From 1843390189c497157b21522b641a6771ce945ead Mon Sep 17 00:00:00 2001 From: Adam Days <14880329+adays1234@users.noreply.github.com> Date: Fri, 20 Dec 2019 17:26:15 -0800 Subject: [PATCH] Immediate on when kill key / switch is enabled to on. Finite blaster shots implemented. Corrected hum start. New button names, reload and clipin clipout implemented (#30) Lots of blaster prop updates. --- blades/abstract_blade.h | 43 ++++++++++ blades/blade_base.h | 15 ++++ common/events.h | 10 ++- common/saber_base.h | 17 +++- config/blaster_v3_config.h | 11 ++- props/blaster.h | 166 ++++++++++++++++++++++++------------- props/prop_base.h | 2 +- sound/effect.h | 2 +- sound/hybrid_font.h | 23 +++++ 9 files changed, 221 insertions(+), 68 deletions(-) diff --git a/blades/abstract_blade.h b/blades/abstract_blade.h index b4b63bee6..1ad223d53 100644 --- a/blades/abstract_blade.h +++ b/blades/abstract_blade.h @@ -56,6 +56,7 @@ class AbstractBlade : public BladeBase, public SaberBase { num_effects_ = std::min(num_effects_ + 1, NELEM(effects_)); } + // Saber Effects void SB_Clash() override { addEffect(EFFECT_CLASH, (200 + random(700)) / 1000.0f); } @@ -69,6 +70,7 @@ class AbstractBlade : public BladeBase, public SaberBase { addEffect(EFFECT_FORCE, 1.0f); } + // Shared Effects void SB_On() override { addEffect(EFFECT_IGNITION, 0); } @@ -109,6 +111,47 @@ class AbstractBlade : public BladeBase, public SaberBase { return GetPrimaryBlade() == this; } + // Blaster Effects + void SB_Stun() override { + addEffect(EFFECT_STUN, 0); + } + void SB_Fire() override { + addEffect(EFFECT_FIRE, 0); + } + void SB_ClipIn() override { + addEffect(EFFECT_CLIP_IN, 0); + } + void SB_ClipOut() override { + addEffect(EFFECT_CLIP_OUT, 0); + } + void SB_Reload() override { + addEffect(EFFECT_RELOAD, 0); + } + void SB_Mode() override { + addEffect(EFFECT_MODE, 0); + } + void SB_Range() override { + addEffect(EFFECT_RANGE, 0); + } + void SB_Empty() override { + addEffect(EFFECT_EMPTY, 0); + } + void SB_Full() override { + addEffect(EFFECT_FULL, 0); + } + void SB_Jam() override { + addEffect(EFFECT_JAM, 0); + } + void SB_UnJam() override { + addEffect(EFFECT_UNJAM, 0); + } + void SB_PLIOn() override { + addEffect(EFFECT_PLI_ON, 0); + } + void SB_PLIOff() override { + addEffect(EFFECT_PLI_OFF, 0); + } + protected: BladeStyle *current_style_ = nullptr; private: diff --git a/blades/blade_base.h b/blades/blade_base.h index 09fab8cc9..7557bcd00 100644 --- a/blades/blade_base.h +++ b/blades/blade_base.h @@ -16,6 +16,21 @@ enum BladeEffectType { EFFECT_IGNITION = 1 << 9, EFFECT_RETRACTION = 1 << 10, EFFECT_CHANGE = 1 << 11, // used for click to change + + // Blaster Effect Types + EFFECT_STUN = 1 << 12, // used to pass STUN to allow alternate colors for stun type blasts + EFFECT_FIRE = 1 << 13, + EFFECT_CLIP_IN = 1 << 14, + EFFECT_CLIP_OUT = 1 << 15, + EFFECT_RELOAD = 1 << 16, + EFFECT_MODE = 1 << 17, + EFFECT_RANGE = 1 << 18, + EFFECT_EMPTY = 1 << 19, + EFFECT_FULL = 1 << 20, + EFFECT_JAM = 1 << 21, + EFFECT_UNJAM = 1 << 22, + EFFECT_PLI_ON = 1 << 23, + EFFECT_PLI_OFF = 1 << 24, }; #include "../styles/blade_style.h" diff --git a/common/events.h b/common/events.h index ce2ed2212..929cd3c04 100644 --- a/common/events.h +++ b/common/events.h @@ -10,14 +10,16 @@ enum BUTTON : uint32_t { BUTTON_DOWN = 16, BUTTON_LEFT = 32, BUTTON_RIGHT = 64, + BUTTON_SELECT = 128, - // D-pad and FIRE/RELOAD/CLIP_DETECT have the same numbers, + // D-pad and FIRE//MODE_SELECT/CLIP_DETECT/RELOAD and RANGE have the same numbers, // so you can't have a D-pad in a blaster. BUTTON_FIRE = 8, - BUTTON_RELOAD = 16, + BUTTON_MODE_SELECT = 16, BUTTON_CLIP_DETECT = 32, - - BUTTON_SELECT = 128, + BUTTON_RELOAD = 64, + BUTTON_RANGE = 128, + BUTTON_BLADE_DETECT = 256, MODE_ANY_BUTTON = 512, MODE_ON = 1024, diff --git a/common/saber_base.h b/common/saber_base.h index f1c883e5e..e86787cab 100644 --- a/common/saber_base.h +++ b/common/saber_base.h @@ -119,8 +119,21 @@ public: \ SABERFUN(Top, (), ()); \ SABERFUN(Relax, (), ()); \ SABERFUN(IsOn, (bool* on), (on)); \ - SABERFUN(Message, (const char* msg), (msg)); - + SABERFUN(Message, (const char* msg), (msg)); \ + \ + SABERFUN(Stun, (), ()); \ + SABERFUN(Fire, (), ()); \ + SABERFUN(ClipIn, (), ()); \ + SABERFUN(ClipOut, (), ()); \ + SABERFUN(Reload, (), ()); \ + SABERFUN(Mode, (), ()); \ + SABERFUN(Range, (), ()); \ + SABERFUN(Empty, (), ()); \ + SABERFUN(Full, (), ()); \ + SABERFUN(Jam, (), ()); \ + SABERFUN(UnJam, (), ()); \ + SABERFUN(PLIOn, (), ()); \ + SABERFUN(PLIOff, (), ()); SABERBASEFUNCTIONS(); #undef SABERFUN diff --git a/config/blaster_v3_config.h b/config/blaster_v3_config.h index 699e1095f..443a9f436 100644 --- a/config/blaster_v3_config.h +++ b/config/blaster_v3_config.h @@ -6,9 +6,12 @@ const unsigned int maxLedsPerStrip = 144; #define CLASH_THRESHOLD_G 1.0 #define ENABLE_AUDIO +#define ENABLE_MOTION #define ENABLE_WS2811 #define ENABLE_SD #define ENABLE_BLASTER_AUTO +#define BLASTER_SHOTS_UNTIL_EMPTY 30 +#define BLASTER_JAM_PERCENTAGE 3 #endif #ifdef CONFIG_PROP @@ -19,8 +22,8 @@ const unsigned int maxLedsPerStrip = 144; Preset presets[] = { // Default basic blast color with red audio flicker on blast { "_blstr1", "tracks/mars.wav", - StylePtr>,AudioFlicker>>(), - StylePtr>,AudioFlicker>>() }, + StylePtr,250,EFFECT_FIRE>,AudioFlicker,1500,EFFECT_STUN>,AudioFlicker>>(), + StylePtr,250,EFFECT_FIRE>,AudioFlicker,1500,EFFECT_STUN>,AudioFlicker>>() } }; BladeConfig blades[] = { @@ -32,6 +35,6 @@ BladeConfig blades[] = { #endif #ifdef CONFIG_BUTTONS -Button PowerButton(BUTTON_POWER, powerButtonPin, "pow"); -Button AuxButton(BUTTON_AUX, auxPin, "aux"); +Button FireButton(BUTTON_FIRE, powerButtonPin, "fire"); +Button ModeButton(BUTTON_MODE_SELECT, auxPin, "modeselect"); #endif diff --git a/props/blaster.h b/props/blaster.h index 303661089..0bb0ddd10 100644 --- a/props/blaster.h +++ b/props/blaster.h @@ -10,16 +10,6 @@ class Blaster : public PropBase { Blaster() : PropBase() {} const char* name() override { return "Blaster"; } -/* -#ifdef DELAYED_OFF - bool powered_ = false; - void SetPower(bool on) { powered_ = on; } -#else - constexpr bool powered_ = true; - void SetPower(bool on) {} -#endif -*/ - // Mode states to handle kill vs stun effects enum BlasterMode { MODE_STUN, @@ -32,13 +22,7 @@ class Blaster : public PropBase { virtual void SetBlasterMode(BlasterMode to_mode) { if (!auto_firing_) { blaster_mode = to_mode; - -#ifdef ENABLE_AUDIO - // Initiate mode change effect - if (SFX_mode.files_found()) { - hybrid_font.PlayCommon(&SFX_mode); - } -#endif + SaberBase::DoMode(); } } @@ -61,23 +45,93 @@ class Blaster : public PropBase { } bool auto_firing_ = false; + int shots_fired_ = 0; + bool is_jammed_ = false; + +#ifdef BLASTER_SHOTS_UNTIL_EMPTY + const int max_shots_ = BLASTER_SHOTS_UNTIL_EMPTY; +#else + const int max_shots_ = -1; +#endif + + virtual bool CheckJam(int percent) { + int random = rand() % 100; + return random <= percent ? true : false; + } virtual void Fire() { - if (!SaberBase::IsOn()) return; // Don't allow firing when off. +#ifdef ENABLE_MOTION +#ifdef BLASTER_JAM_PERCENTAGE + // If we're already jammed then we don't need to recheck. If we're not jammed then check if we just jammed. + is_jammed_ = is_jammed_ ? true : CheckJam(BLASTER_JAM_PERCENTAGE); + + if (is_jammed_) { + SaberBase::DoJam(); + return; + } +#endif +#endif + + if (max_shots_ != -1) { + if (shots_fired_ >= max_shots_) { + SaberBase::DoEmpty(); + return; + } + } if (blaster_mode == MODE_AUTO) { + SelectAutoFirePair(); // Set up the autofire pairing if the font suits it. SaberBase::SetLockup(LOCKUP_AUTOFIRE); SaberBase::DoBeginLockup(); auto_firing_ = true; } else { - SaberBase::DoBlast(); -#ifdef ENABLE_AUDIO if (blaster_mode == MODE_STUN) { - hybrid_font.PlayCommon(&SFX_stun); + SaberBase::DoStun(); } else { - hybrid_font.PlayCommon(&SFX_blast); + SaberBase::DoFire(); + } + + shots_fired_++; + } + } + + virtual void SelectAutoFirePair() { + if (!SFX_auto.files_found() || !SFX_blast.files_found()) return; + + int autoCount = SFX_auto.files_found(); + int blastCount = SFX_blast.files_found(); + int pairSelection; + + // If we don't have a matched pair of autos and blasts, then don't override the sequence to get a matched pair. + if (autoCount == blastCount) { + pairSelection = rand() % autoCount; + SFX_auto.Select(pairSelection); + SFX_blast.Select(pairSelection); + } + } + + virtual void Reload() { + shots_fired_ = 0; + SaberBase::DoReload(); + } + + virtual void ClipOut() { + if (max_shots_ != -1) shots_fired_ = max_shots_; + SaberBase::DoClipOut(); + } + + virtual void ClipIn() { + SaberBase::DoClipIn(); + } + + // Pull in parent's SetPreset, but turn the blaster on. + virtual void SetPreset(int preset_num, bool announce) override { + PropBase::SetPreset(preset_num, announce); + + if (!SFX_poweron) { + if (!SaberBase::IsOn()) { + On(); } -#endif } } @@ -152,51 +206,42 @@ class Blaster : public PropBase { PollNextAction(); } - // Make clash do nothing - void Clash(bool stab) override {} + // Make clash do nothing except unjam if jammed. + void Clash(bool stab) override { + if (is_jammed_) { + is_jammed_ = false; + SaberBase::DoUnJam(); + } + } // Make swings do nothing void DoMotion(const Vec3& motion, bool clear) override {} bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override { switch (EVENTID(button, event, modifiers)) { - case EVENTID(BUTTON_POWER, EVENT_LATCH_ON, MODE_OFF): - case EVENTID(BUTTON_AUX, EVENT_LATCH_ON, MODE_OFF): - case EVENTID(BUTTON_AUX2, EVENT_LATCH_ON, MODE_OFF): - case EVENTID(BUTTON_POWER, EVENT_CLICK_SHORT, MODE_OFF): - armed_ = false; -#ifdef ENABLE_AUDIO - hybrid_font.PlayCommon(&SFX_unjam); -#endif - On(); - return true; - case EVENTID(BUTTON_POWER, EVENT_LATCH_OFF, MODE_ON): - case EVENTID(BUTTON_POWER, EVENT_LATCH_OFF, MODE_OFF): - case EVENTID(BUTTON_POWER, EVENT_CLICK_LONG, MODE_ON): -#ifdef ENABLE_AUDIO - hybrid_font.PlayCommon(&SFX_jam); -#endif - Off(); + case EVENTID(BUTTON_MODE_SELECT, EVENT_PRESSED, MODE_ON): + NextBlasterMode(); return true; - case EVENTID(BUTTON_AUX, EVENT_DOUBLE_CLICK, MODE_OFF): + case EVENTID(BUTTON_MODE_SELECT, EVENT_DOUBLE_CLICK, MODE_ON): next_preset(); return true; - case EVENTID(BUTTON_POWER, EVENT_DOUBLE_CLICK, MODE_ON): - StartOrStopTrack(); + case EVENTID(BUTTON_RELOAD, EVENT_PRESSED, MODE_ON): + case EVENTID(BUTTON_MODE_SELECT, EVENT_HELD_MEDIUM, MODE_ON): + Reload(); return true; - case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ON): - NextBlasterMode(); + case EVENTID(BUTTON_MODE_SELECT, EVENT_HELD_LONG, MODE_ON): + StartOrStopTrack(); return true; - case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ON): + case EVENTID(BUTTON_FIRE, EVENT_PRESSED, MODE_ON): Fire(); return true; - case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ON): + case EVENTID(BUTTON_FIRE, EVENT_RELEASED, MODE_ON): if (blaster_mode == MODE_AUTO) { if (SaberBase::Lockup()) { SaberBase::DoEndLockup(); @@ -206,15 +251,24 @@ class Blaster : public PropBase { } return true; - case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_ON): - beginArm(); - break; + case EVENTID(BUTTON_CLIP_DETECT, EVENT_PRESSED, MODE_ON): + case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_ON, MODE_ON): + ClipIn(); + return true; + + case EVENTID(BUTTON_CLIP_DETECT, EVENT_RELEASED, MODE_ON): + case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_OFF, MODE_ON): + ClipOut(); + return true; - case EVENTID(BUTTON_AUX2, EVENT_RELEASED, MODE_ON): - selfDestruct(); - return armed_; + // In the event of the presence of a power button, let it control the power on events. + case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_OFF): + On(); + return true; - // TODO: Long click when off? + case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ON): + Off(); + return true; } return false; } diff --git a/props/prop_base.h b/props/prop_base.h index 9a3a7a5fb..71d20dbfc 100644 --- a/props/prop_base.h +++ b/props/prop_base.h @@ -246,7 +246,7 @@ class PropBase : CommandParser, Looper, protected SaberBase { } // Select preset (font/style) - void SetPreset(int preset_num, bool announce) { + virtual void SetPreset(int preset_num, bool announce) { #ifdef IDLE_OFF_TIME last_on_time_ = millis(); #endif diff --git a/sound/effect.h b/sound/effect.h index 88049e094..e1de8672f 100644 --- a/sound/effect.h +++ b/sound/effect.h @@ -470,7 +470,7 @@ EFFECT(ccchange); // Blaster effects // hum, boot and font are reused from sabers and already defined. EFFECT(bgnauto); // Doesn't exist in fonts, but I expect there may be use for autofire transitions -EFFECT2(auto,auto); // HACK to work around autoN.wav +EFFECT2(auto,auto); EFFECT(endauto); // Doesn't exist in fonts, but I expect there may be use for autofire transitions EFFECT(blast); // Not to be confused with "blst" and "blaster" as blocking sounds in sabers diff --git a/sound/hybrid_font.h b/sound/hybrid_font.h index d0b37eb58..463baf510 100644 --- a/sound/hybrid_font.h +++ b/sound/hybrid_font.h @@ -300,6 +300,29 @@ class HybridFont : public SaberBase { void SB_Force() override { PlayCommon(&SFX_force); } void SB_Blast() override { Play(&SFX_blaster, &SFX_blst); } void SB_Boot() override { PlayPolyphonic(&SFX_boot); } + + // Blaster effects, auto fire is handled by begin/end lockup + void SB_Stun() override { PlayCommon(&SFX_stun); } + void SB_Fire() override { PlayCommon(&SFX_blast); } + void SB_ClipIn() override { PlayCommon(&SFX_clipin); } + void SB_ClipOut() override { PlayCommon(&SFX_clipout); } + void SB_Reload() override { PlayCommon(&SFX_reload); } + void SB_Mode() override { + if (SFX_mode) { + PlayCommon(&SFX_mode); + return; + } + // TODO: would rather do a Talkie to speak the mode we're in after mode sound + beeper.Beep(0.05, 2000.0); + } + void SB_Range() override { PlayCommon(&SFX_range); } + void SB_Empty() override { PlayCommon(&SFX_empty); } + void SB_Full() override { PlayCommon(&SFX_full); } + void SB_Jam() override { PlayCommon(&SFX_jam); } + void SB_UnJam() override { PlayCommon(&SFX_unjam); } + void SB_PLIOn() override { PlayCommon(&SFX_plion); } + void SB_PLIOff() override { PlayCommon(&SFX_plioff); } + void SB_BladeDetect(bool detected) { Effect &X(detected ? SFX_bladein : SFX_bladeout); if (X) {