Request for new blaster effects and features

I want to finish the out the blaster prop caiblites by adding 3 new effects modes and then to the config on the SD card(so it can know what blaster modes to use and change number of shots to reload). I have been reworking the buttons file to make the actions make more sense to me.

New effect modes requests:

  1. Charge shot - hold the trigger to increase the power of the shot and release to fire. depending how long you hold it. you get a normal shot or the max energy shot.

  2. recharge shot - fire a powerful shot that requires a recharge time before it fires again.

  3. burst burst - like auto mode but only fires a 3 rounds. or other number number of shots.

Now for the sd card config file it would be nice to edit the file on the sd card to activate modes or deactivate. number of shots to reload, number of shots in the burst, jam rate…

also I dont know if clip in or out have been added.

but blaster prop needs some love. I cant do it by myself… I have some coding experience but I lack the knowledge and skill.

ALso here is where I stopped with my b
Propfile.

blaster_Teas_buttons.h (27.4 KB)

how do you post code in the window here?

3 backticks (```) , newline, then paste code, newline, 3 backticks

like this

The easiest way to activate a feature or not might just be to have the sound for it or not.
I just got my blaster prop merged , take a look at the Github master if anything in there helps.

The current blaster.h was really written to be simple and use existing fonts.
It’s not clear if it’s better to add features to it, or to just create a new includes-all-features blaster/phaser/gun prop.

The features you are talking about are interesting, are they based on any particular type of blaster, or is just something you would like to have because it would be fun?

Do you already have sounds for these things? (If so where did you get them from? Did you make them?)

They have.

I was investigating that when IRL took all my time and focus. Burst mode was kinda doable (you can get out of the auto after a seteable amount of shots). The other is more difficult because you need a time based accumulator. This brought two problems:

  1. The button events are designed for a set amount of time for short, normal and long pulls (still doable).
  2. For an overheating or slow recharging gun, you’d need to keep a rate of charge or radiating, plus a rate of charge or heating. I didn’t found the way to count milliseconds and sleep (t_miliseconds) to add that functionality.

Well that file I uploaded is a new prop file… It’s somewhat based on bc buttons. I just adjusted some things that make better sense to me. It has jam and clip in… And everything.

What these ideas are from is video games real life. And scifi… Like in the the Mandalorian. Nando’s rifle over heats.

If it is any help, this is what I was working on:

/*
  blaster_BC_buttons.h prop file.
  http://fredrik.hubbe.net/lightsaber/proffieos.html
  Copyright (c) 2016-2023 Fredrik Hubinette
  Fredrik Hubinette, Fernando da Rosa, Brian Conner, Matthew McGeary,
  Scott Weber and Alejandro Belluscio.
  Distributed under the terms of the GNU General Public License v3.
  http://www.gnu.org/licenses/

  This prop file makes full use soundfont and display specification, while keeping features to a minimum

TODO:
-Do Range change the fire sound.
-Add ammo limitation to auto.
-Teach prop about OLED: PLI, Shot counter, battery, etc.

Functionality:
-------------------------------------------------------------------------------
* PROP DEFINES *
Optional #defines that customize the blaster's behavior.
-------------------------------------------------------------------------------

General Defines:
  #define PROFFIEOS_VERBOSITY 2         - 0-5 range. Sets the output verbosity.
                                          0: no printouts
                                          1: essential printouts
                                          2: good-to-know printouts
                                          3: debug printouts
                                          4: verbose printouts
                                          5: spammy printouts 

Optional defines:
  #define ENABLE_BLASTER_AUTO           - DEPRECATED. Enable Autofire/rapid fire mode. Please replace with BLASTER_ENABLE_AUTO.
  #define BLASTER_ENABLE_AUTO           - Enable Autofire/rapid fire mode.
  #define BLASTER_DEFAULT_MODE			- Sets the mode at startup MODE_STUN|MODE_KILL|MODE_AUTO.
  #define BLASTER_DEFAULT_POWER_STATE	- Sets the state at startup as ON|OFF|SOUNDFONT (dependent on poweron.wav presence). Defaults to SOUNDFONT.
  #define BLASTER_RANGE_LEVELS			- Sets the steps of Range/Power levels, also used to define PLI steps. Should be 1 to 99. Defaults to 6.
  #define BLASTER_RANGE_LEVELS_BY_FONT  - Sets the steps of Range/Power levels according to each fonts number of rangexx.wavs.
  #define BLASTER_SHOTS_UNTIL_EMPTY 15  - Whatever number, not defined = unlimited shots.
  #define BLASTER_AUTO_LIMITED_ROUNDS	- When enabled, AUTO mode respects the round limit set by BLASTER_SHOTS_UNTIL_EMPTY.
  #define BLASTER_JAM_PERCENTAGE        - Range 0-100 percent. If this is not defined, random from 0-100%.
  #define BLASTER_SINGLE_POWER_BUTTON   - Only Power Button will turn on/off the blaster.
  #define BLASTER_SINGLE_RELOAD_BUTTON  - Only Reload Button will reload the blaster. Mutually exclusive with BLASTER_RELOAD_THROUGH_CLIP.
  #define BLASTER_RELOAD_THROUGH_CLIP   - Only Clip Out then Clip In will reload the blaster. Mutually exclusive BLASTER_SINGLE_RELOAD_BUTTON.
  #define BLASTER_CLIP_OUT_BLOCK        - Clip Out will block blaster even without BLASTER_SHOTS_UNTIL_EMPTY.

-------------------------------------------------------------------------------
* PROP BUTTONS *
This prop manages up to six different buttons.
-------------------------------------------------------------------------------

*Single Button Mode*
 -Buttons: FIRE
  This case quite limited since you can only fire and reload. Weapon will always
  be on the default mode (STUN is the defined in the prop, if you wish another
  you will have to define BLASTER_DEFAULT_MODE). Blaster can be turned on or off.
  And can be reloaded, which takes precedence over turning it on/off.
  
  Default Mode: Fire or Stun
    Fire 			- Click FIRE.
	Power On / Off	- Hold FIRE.
	Reload			- Hold FIRE until Reloaded. Takes priority over power on/off.
    Unjam			- Bang the blaster.
  
  Default Mode: Auto *This mode is not compatible with clip capacity and really needs
                      an on/off switch on the power line.
    Fire (Semi)     - Click FIRE.
    Fire (Auto)     - Hold FIRE.
    Power On        - Hold FIRE. You can't power off.
    Unjam           - Bang the blaster.

*Dual Buttons Mode*
 -Buttons: FIRE and MODE
  This is the "stock" configuration.
  -Weapon will always start on the default mode (define with BLASTER_DEFAULT_MODE,
  STUN is default).
  Default is to powered on if it finds poweron.wav file present or off otherwise.
  Use BLASTER_DEFAULT_POWERON_STATE to define a different behavior.
  
    Fire 				- Click FIRE.
    Cycle Modes			- Click MODE.
    Next Preset			- Long click and release MODE.
    Previous Preset		- Double click and hold MODE, release after a second.
    Reload				- Hold MODE until Reloaded.
    Start/Stop Track	- Double click MODE.
    Unjam				- Bang the blaster.

*Extra Buttons*
-Button: POWER
	Power On / Off	- Click POWER.

-Button: RELOAD
  You can make this the only button to reload by defining BLASTER_SINGLE_RELOAD_BUTTON.
	Reload			- Hold RELOAD until Reloaded.
	
-Button: CLIP
  You can make that shooting will be blocked when the clip is out by defining
  define BLASTER_CLIP_OUT_BLOCK.
  You can make that you only reload through the clip by defining
  BLASTER_RELOAD_THROUGH_CLIP (takes precedence over BLASTER_SINGLE_RELOAD_BUTTON).
	Clip In			- Latch CLIP
	Clip Out		- Unlatch CLIP

-Button: RANGE
  You have to define the number of levels by 
	Increase Range	- Click RANGE.
	Decrease Range	- Long click RANGE.
	
-------------------------------------------------------------------------------
* PROP SOUNDS *
This prop manages the following sounds.
-------------------------------------------------------------------------------

bgnauto 	Played when auto fire starts.
auto 		Played while auto fire is going.
endauto 	Played when auto fire ends.
blast 		Is the semi-automatic fire sound. You can have as many as you want.
boot 		Played when ProffieOS boots up.
clipin 		Sound made when inserting a clip.
clipout 	Sound made when dropping a clip.
empty 		Sound when the weapon is out of rounds.
font 		Name of the preset.
full 		Sound made when the weapon is full of ammo.
hum 		Constant sound looping while not firing.
jam 		Sound made when the weapon jamed.
unjam 		Sound made when unjamming the blaster.
mode 		Sound made when switching mode (if mdkill, mdstun and/or mdauto not present).
plioff 		Played while retracting the PLI bargraph.
plion 		Played while extending the PLI bargraph.
poweron 	If this file is present, the blaster will start once it is turned on. If not, you will need a Power button to power it on.
range 		Sounds of increasing weapon range/power.
stun 		Firing sound for stun mode.
reload		Reloading sound.
mdkill		Sound made when switching to KILL mode
mdstun		Sound made when switching to STUN mode
mdauto		Sound made when switching to AUTO mode

-------------------------------------------------------------------------------
* PROP EFFECTS *
This prop enables the following EFFECTs for use in styles
-------------------------------------------------------------------------------
EFFECT_RANGE_MAXIMUM
EFFECT_RANGE_MINIMUM
EFFECT_RANGE_UP
EFFECT_RANGE_DOWN

Already defined in SaberBase
EFFECT_CLIP_IN
EFFECT_CLIP_OUT
EFFECT_RELOAD
EFFECT_JAM
EFFECT_UNJAM
EFFECT_NONE
EFFECT_BLAST
EFFECT_BOOT
EFFECT_LOCKUP_BEGIN
EFFECT_LOCKUP_END
EFFECT_PREON
EFFECT_POSTOFF
EFFECT_ON
EFFECT_FAST_ON
EFFECT_OFF
EFFECT_FAST_OFF


*/

#ifndef PROPS_BLASTER_BALDUSI_H
#define PROPS_BLASTER_BALDUSI_H

#ifndef PROFFIEOS_VERBOSITY
 #define PROFFIEOS_VERBOSITY 2  /* range 0 - 5 */
#endif

#ifndef BLASTER_DEFAULT_MODE
#define BLASTER_DEFAULT_MODE MODE_STUN
#endif

#ifndef BLASTER_DEFAULT_POWER_STATE
#define BLASTER_DEFAULT_POWER_STATE SOUNDFONT
#endif

#ifndef BLASTER_RANGE_LEVELS
#define BLASTER_RANGE_LEVELS 6
#endif

#if NUM_BUTTONS < 1
#error /props/blaster_baldusi.h requires 1 or more Buttons for operation
#endif

#include "prop_base.h"
#include "../sound/sound_library.h"

#define PROP_TYPE Blaster_Baldusi
#define PROP_HAS_BULLET_COUNT

EFFECT(clipin);
EFFECT(clipins);    // s for stun mode
EFFECT(clipout);
EFFECT(clipouts);   // s for stun mode
EFFECT(empty);
EFFECT(full);
EFFECT(jam);
EFFECT(mode);
EFFECT(plioff);
EFFECT(plion);
EFFECT(range);
EFFECT(rangemax);
EFFECT(rangemin);
EFFECT(rangeup);
EFFECT(rangedwn);
EFFECT(reload);
EFFECT(reloads);    // s for stun mode
EFFECT(stun);
EFFECT(unjam);
EFFECT(mdstun);
EFFECT(mdkill);
EFFECT(mdauto);

//Effects defined in SaberBase
//EFFECT(bgnauto)
//EFFECT(auto)
//EFFECT(endauto)
//EFFECT(hum)
//EFFECT()
//EFFECT()
//EFFECT()
//EFFECT()
//EFFECT()


/* Blaster effects defined in SaberBase
DEFINE_EFFECT(STUN)
DEFINE_EFFECT(FIRE)
DEFINE_EFFECT(CLIP_IN)
DEFINE_EFFECT(CLIP_OUT)
DEFINE_EFFECT(RELOAD)
DEFINE_EFFECT(MODE)
DEFINE_EFFECT(RANGE)
DEFINE_EFFECT(EMPTY)
DEFINE_EFFECT(FULL)
DEFINE_EFFECT(JAM)
DEFINE_EFFECT(UNJAM)
DEFINE_EFFECT(PLI_ON)
DEFINE_EFFECT(PLI_OFF)
*/

//EFFECT_RANGE_MAX
//EFFECT_RANGE_MIN
//EFFECT_RANGE_INCREASE
//EFFECT_RANGE_DECREASE

class Blaster_Baldusi : public PROP_INHERIT_PREFIX PropBase {
public:
  Blaster_Baldusi() : PropBase() {}
  const char* name() override { return "Blaster_Baldusi"; }

  // Mode states to handle kill vs stun effects
  enum BlasterMode {
    MODE_STUN = 0,
    MODE_KILL = 1,
    MODE_AUTO = 2
  };

  // Set default power state.
  enum BlasterInitialPowerState {
      ON = 0,
      OFF = 1,
      SOUNDFONT=2
  };

  #if defined (BLASTER_SINGLE_RELOAD_BUTTON) && defined (BLASTER_RELOAD_THROUGH_CLIP)
    #error "BLASTER_SINGLE_RELOAD_BUTTON and BLASTER_RELOAD_THROUGH_CLIP are mutually exclusive."
  #endif

  #if NUM_BUTTONS == 1 && !(defined (ENABLE_BLASTER_AUTO) || defined (BLASTER_ENABLE_AUTO))
  static_assert(BLASTER_DEFAULT_MODE != MODE_AUTO,
    "BLASTER_DEFAULT_MODE cannot be MODE_AUTO without BLASTER_ENABLE_AUTO in Single Button configuration.");
  #endif

  #if NUM_BUTTONS == 1 && (defined (BLASTER_ENABLE_AUTO) || defined (ENABLE_BLASTER_AUTO))
  static_assert(BLASTER_DEFAULT_MODE == MODE_AUTO,
    "Single Button Auto mode requires BLASTER_DEFAULT_MODE = MODE_AUTO");
  #endif

  BlasterMode blaster_mode = BLASTER_DEFAULT_MODE;
  BlasterInitialPowerState initial_power_state = BLASTER_DEFAULT_POWER_STATE;
  
  int shots_fired_ = 0;
  bool auto_firing_ = false;
  bool is_jammed_ = false;
  bool empty_ = false;
  bool clip_present_ = true;
  int previous_range_ = 1;
  int current_range_ = 1;
  int maximum_range_ = BLASTER_RANGE_LEVELS;
  bool stun_mode_ = true;
#ifdef BLASTER_SHOTS_UNTIL_EMPTY
  const int max_shots_ = BLASTER_SHOTS_UNTIL_EMPTY;
#else
  const int max_shots_ = -1;
#endif
 

 
  virtual void SetBlasterMode(BlasterMode to_mode) {
    if (!auto_firing_) {
      blaster_mode = to_mode;
      SaberBase::DoEffect(EFFECT_MODE, 0);
    }
  }

  virtual void NextBlasterMode() {
    switch(blaster_mode) {
      case MODE_STUN:
	    stun_mode_ = false;
        SetBlasterMode(MODE_KILL);
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Mode set to: MODE_KILL");
        #endif
        return;
      case MODE_KILL:
      #if defined (ENABLE_BLASTER_AUTO) || defined (BLASTER_ENABLE_AUTO)
 	    stun_mode_ = false;
        SetBlasterMode(MODE_AUTO);
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Mode set to: MODE_AUTO");
        #endif
      #else
	    stun_mode_ = true;
        SetBlasterMode(MODE_STUN);
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Mode set to: MODE_STUN");
        #endif
      #endif
        return;
      case MODE_AUTO:
	    stun_mode_ = true;
        SetBlasterMode(MODE_STUN);
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Mode set to: MODE_STUN");
        #endif
        return;
    }
  }
  

  virtual int GetBulletCount() {
    return max_shots_ - shots_fired_;
  }

  virtual bool CheckJam(int percent) {
    int random = rand() % 100;
    if (random < percent) {
      #if PROFFIEOS_VERBOSITY - 0 >= 3
        STDOUT.println("Effect: JAM");
      #endif
      return 1;
    }
    return 0;
    //return random < percent;
  }

  virtual void Fire() {
#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_) {
      #if PROFFIEOS_VERBOSITY - 0 >= 3
        STDOUT.println("Effect: JAMMED");
      #endif
      SaberBase::DoEffect(EFFECT_JAM, 0);
      return;
    }
#endif
#endif

#ifdef BLASTER_CLIP_OUT_BLOCK 
    if ((max_shots_ != -1 && shots_fired_ >= max_shots_)|| clip_present_ == false ) {
      #if PROFFIEOS_VERBOSITY - 0 >= 3
        STDOUT.println("Effect: EMPTY or CLIP OUT");
      #endif
#else
    if (max_shots_ != -1 && shots_fired_ >= max_shots_) {
      #if PROFFIEOS_VERBOSITY - 0 >= 3
        STDOUT.println("Effect: EMPTY");
      #endif
#endif
      SaberBase::DoEffect(EFFECT_EMPTY, 0);
      return;
    }

    if (blaster_mode == MODE_AUTO) {
	// !!!!!It would be desirable to have the option to limit the amount of total shots, even in auto!!!
      SelectAutoFirePair(); // Set up the autofire pairing if the font suits it.
      SaberBase::SetLockup(LOCKUP_AUTOFIRE);
      #if PROFFIEOS_VERBOSITY - 0 >= 4
        STDOUT.println("Action: AUTO Fire");
      #endif
      SaberBase::DoBeginLockup();
      auto_firing_ = true;
    } else {
      if (blaster_mode == MODE_STUN) {
        #if PROFFIEOS_VERBOSITY - 0 >= 4
          STDOUT.println("Action: STUN");
        #endif
        SaberBase::DoEffect(EFFECT_STUN, 0);
      } else {
        #if PROFFIEOS_VERBOSITY - 0 >= 4
          STDOUT.println("Action: FIRE");
        #endif
        SaberBase::DoEffect(EFFECT_FIRE, 0);
      }
      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;
    #if PROFFIEOS_VERBOSITY - 0 >= 3
      STDOUT.println("Action: RELOAD");
    #endif
    SaberBase::DoEffect(EFFECT_RELOAD, 0);
    SaberBase::DoEffect(EFFECT_FULL, 0);
  }

// !!! Should clip out prevent firing even when infinite rounds? I think yes.
  virtual void ClipOut() {
    #if PROFFIEOS_VERBOSITY - 0 >= 3
      STDOUT.println("Action: CLIP_OUT");
    #endif
    if (max_shots_ != -1) shots_fired_ = max_shots_;
	clip_present_ = false;
    SaberBase::DoEffect(EFFECT_CLIP_OUT, 0);
  }

  virtual void ClipIn() {
    #if PROFFIEOS_VERBOSITY - 0 >= 3
      STDOUT.println("Action: CLIP_IN");
    #endif
	clip_present_ = true;
    SaberBase::DoEffect(EFFECT_CLIP_IN, 0);
    #if defined (BLASTER_RELOAD_THROUGH_CLIP)
    if (max_shots_ != -1) shots_fired_ = 0;
    SaberBase::DoEffect(EFFECT_FULL, 0);   
    #endif
  }


  virtual void IncreaseRange() {
    #if PROFFIEOS_VERBOSITY - 0 >= 3
      STDOUT.println("Action: Increase RANGE");
    #endif
    previous_range_ = current_range_;
	if (current_range_ < maximum_range_ ) {
	  current_range_++;
	}
    SaberBase::DoEffect(EFFECT_RANGE, 0);
  }

  virtual void DecreaseRange() {
    #if PROFFIEOS_VERBOSITY - 0 >= 3
      STDOUT.println("Action: Decrease RANGE");
    #endif
    previous_range_ = current_range_;
	if (current_range_ > 1) {
	  current_range_--;
	}
    SaberBase::DoEffect(EFFECT_RANGE, 0);
  }


  // Pull in parent's SetPreset, but turn the blaster on.
  // Still keeping it to default off.
  void SetPreset(int preset_num, bool announce) override {
    PropBase::SetPreset(preset_num, announce);
      #ifdef BLASTER_RANGE_LEVELS_BY_FONT
        if (SFX_range) {
          maximum_range_ = SFX_range.files_found();
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.print("Action: range.wav found. Setting MAX_RANGE as:");
            STDOUT.println(maximum_range_);
          #endif
       } else {
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: range.wav not found. Setting MAX_RANGE as 1");
          #endif
          maximum_range_ = 1;
        }
      #endif
      
      switch (initial_power_state) {
          case ON:
            if (!SaberBase::IsOn()) {
              #if PROFFIEOS_VERBOSITY - 0 >= 3
                STDOUT.println("Action: Blaster ON.");
              #endif
              On();
            }
          case OFF:
            if (SaberBase::IsOn()) {
              #if PROFFIEOS_VERBOSITY - 0 >= 3
                STDOUT.println("Action: Blaster OFF.");
              #endif
              Off();
            }
          case SOUNDFONT:
             if (!SFX_poweron) {
              if (!SaberBase::IsOn()) {
              #if PROFFIEOS_VERBOSITY - 0 >= 3
                STDOUT.println("Action: poweron.wav found. Setting Blaster ON.");
              #endif
             On();
              } 
           }
      }
/*	  #if (defined BLASTER_DEFAULT_POWER && BLASTER_DEFAULT_POWER_STATE == ON)
	    if (!SaberBase::IsOn()) {
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: Blaster ON.");
          #endif
          On();
        }
	  #elif (defined BLASTER_DEFAULT_POWER && BLASTER_DEFAULT_POWER_STATE == OFF)
        if (SaberBase::IsOn()) {
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: Blaster OFF.");
          #endif
          Off();
        }
      #else
        if (!SFX_poweron) {
          if (!SaberBase::IsOn()) {
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: poweron.wav found. Setting Blaster ON.");
          #endif
         On();
        } 
	  #endif */
  }

  void LowBatteryOff() override {
    if (SFX_poweron) {
      PropBase::LowBatteryOff();
    }
  }

  // Make clash do nothing except unjam if jammed.
  void Clash(bool stab, float strength) override {
    if (is_jammed_) {
      #if PROFFIEOS_VERBOSITY - 0 >= 3
        STDOUT.println("Action: UNJAM\n");
      #endif
      is_jammed_ = false;
      SaberBase::DoEffect(EFFECT_UNJAM, 0);
    }
  }

  // Make swings do nothing
  void DoMotion(const Vec3& motion, bool clear) override {
    PropBase::DoMotion(Vec3(0), clear);
  }

  bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override {
    switch (EVENTID(button, event, modifiers)) {
    
	//-------------------------------------------------------------------------
	// #### SINGLE BUTTON (FIRE) CASE
	//-------------------------------------------------------------------------
      #if NUM_BUTTONS == 1 && (defined (BLASTER_ENABLE_AUTO) || defined (ENABLE_BLASTER_AUTO))
        case EVENTID(BUTTON_FIRE, EVENT_PRESSED, MODE_OFF):
          On();
          return true;
        case EVENTID(BUTTON_FIRE, EVENT_PRESSED, MODE_ON):
  	      Fire();
          return true;
        case EVENTID(BUTTON_FIRE, EVENT_RELEASED, MODE_ON):
          if (blaster_mode == MODE_AUTO) {
            if (SaberBase::Lockup()) {
              SaberBase::DoEndLockup();
              SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
              auto_firing_ = false;
            }
          }
          return true;  
    
    #elif (NUM_BUTTONS == 1)
        case EVENTID(BUTTON_FIRE, EVENT_CLICK_SHORT, MODE_ON):
          Fire();
          return true;
        case EVENTID(BUTTON_FIRE, EVENT_HELD, MODE_ON):
  	    if(max_shots_ != -1 && shots_fired_ >= max_shots_) {
  		  Reload();
  		} else {
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: Power OFF");
          #endif
  		  Off();
  		};
          return true;
        case EVENTID(BUTTON_FIRE, EVENT_HELD, MODE_OFF):
          #if PROFFIEOS_VERBOSITY - 0 >= 3
            STDOUT.println("Action: Power ON");
          #endif
         On();
          return true;

	//-------------------------------------------------------------------------
	// #### MULTI BUTTON CASE
	//-------------------------------------------------------------------------
    #else
      case EVENTID(BUTTON_MODE_SELECT, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
        NextBlasterMode();
        return true;

      case EVENTID(BUTTON_MODE_SELECT, EVENT_FIRST_CLICK_LONG, MODE_ON):
        next_preset();
        return true;

      case EVENTID(BUTTON_MODE_SELECT, EVENT_SECOND_CLICK_LONG, MODE_ON):
        previous_preset();
        return true;
      
      #ifndef BLASTER_RELOAD_THROUGH_CLIP
      case EVENTID(BUTTON_RELOAD, EVENT_PRESSED, MODE_ON):
	  #ifndef BLASTER_SINGLE_RELOAD_BUTTON
      case EVENTID(BUTTON_MODE_SELECT, EVENT_HELD_MEDIUM, MODE_ON):
	  #endif
        Reload();
        return true;
      #endif

      case EVENTID(BUTTON_MODE_SELECT, EVENT_DOUBLE_CLICK, MODE_ON):
        StartOrStopTrack();
        return true;

      case EVENTID(BUTTON_FIRE, EVENT_CLICK_SHORT, MODE_ON):
	    Fire();
        return true;

      case EVENTID(BUTTON_FIRE, EVENT_HELD, MODE_ON):
	    Fire();
        return true;
      case EVENTID(BUTTON_FIRE, EVENT_RELEASED, MODE_ON):
        if (blaster_mode == MODE_AUTO) {
          if (SaberBase::Lockup()) {
            SaberBase::DoEndLockup();
            SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
            auto_firing_ = false;
          }
        }
        return true;
	  

	  //-----------------------------------------------------------------------
	  //POWER Button 
	  //-----------------------------------------------------------------------
      // 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):
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Action: Power ON");
        #endif
        On();
        return true;

      case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ON):
        #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Action: Power OFF");
        #endif
        Off();
        return true;

      //-----------------------------------------------------------------------
	  //CLIP_DETECT Button
	  //-----------------------------------------------------------------------
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_PRESSED, MODE_ON):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_PRESSED, MODE_OFF):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_ON, MODE_ON):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_ON, MODE_OFF):
        ClipIn();
        return true;

      case EVENTID(BUTTON_CLIP_DETECT, EVENT_RELEASED, MODE_ON):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_RELEASED, MODE_OFF):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_OFF, MODE_ON):
      case EVENTID(BUTTON_CLIP_DETECT, EVENT_LATCH_OFF, MODE_OFF):
        ClipOut();
        return true;

      //-----------------------------------------------------------------------
	  //RANGE Button 
	  //-----------------------------------------------------------------------
      // In the event of the presence of a power button, let it control the power on events.
      case EVENTID(BUTTON_RANGE, EVENT_CLICK_SHORT, MODE_ON):
        IncreaseRange();
        return true;

      case EVENTID(BUTTON_RANGE, EVENT_CLICK_LONG, MODE_ON):
        DecreaseRange();
        return true;
	
    #endif	
		    
  #ifdef BLADE_DETECT_PIN
    case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_ON):
    case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_OFF):
      // Might need to do something cleaner, but let's try this for now.
      #if PROFFIEOS_VERBOSITY - 0 >= 3
         STDOUT.println("Event: Blade DETECT");
      #endif
     blade_detected_ = true;
      FindBladeAgain();
      SaberBase::DoBladeDetect(true);
      return true;

    case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_ON):
    case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_OFF):
      // Might need to do something cleaner, but let's try this for now.
      #if PROFFIEOS_VERBOSITY - 0 >= 3
          STDOUT.println("Event: NO Blade");
      #endif
     blade_detected_ = false;
      FindBladeAgain();
      SaberBase::DoBladeDetect(false);
      return true;
  #endif
    }
    return false;
  }

   // Blaster effects, auto fire is handled by begin/end lockup
  void SB_Effect(EffectType effect, float location) override {
    switch (effect) {
      default: return;
      case EFFECT_STUN: hybrid_font.PlayCommon(&SFX_stun); return;
      case EFFECT_FIRE: hybrid_font.PlayCommon(&SFX_blast); return;
      case EFFECT_CLIP_IN: 
        if (stun_mode_ && SFX_clipins) {
          hybrid_font.PlayCommon(&SFX_clipins); return;
        } else {
          hybrid_font.PlayCommon(&SFX_clipin); return;
        }
      case EFFECT_CLIP_OUT: 
        if (stun_mode_ && SFX_clipouts) {
          hybrid_font.PlayCommon(&SFX_clipouts); return;
        } else { 
          hybrid_font.PlayCommon(&SFX_clipout); return;
        }
      case EFFECT_RELOAD:
        if (stun_mode_ && SFX_reloads) {
          hybrid_font.PlayCommon(&SFX_reloads); return;
        } else {
          hybrid_font.PlayCommon(&SFX_reload); return;
        }
      case EFFECT_MODE: SayMode(); return;
      case EFFECT_RANGE: SayRange(); return;
      case EFFECT_EMPTY: hybrid_font.PlayCommon(&SFX_empty); return;
      case EFFECT_FULL: hybrid_font.PlayCommon(&SFX_full); return;
      case EFFECT_JAM: hybrid_font.PlayCommon(&SFX_jam); return;
      case EFFECT_UNJAM: hybrid_font.PlayCommon(&SFX_unjam); return;
      case EFFECT_PLI_ON: hybrid_font.PlayCommon(&SFX_plion); return;
      case EFFECT_PLI_OFF: hybrid_font.PlayCommon(&SFX_plioff); return;
      case EFFECT_RANGE_MAXIMUM: hybrid_font.PlayCommon(&SFX_rangemax); return;
      case EFFECT_RANGE_MINIMUM: hybrid_font.PlayCommon(&SFX_rangemin); return;
      case EFFECT_RANGE_UP: hybrid_font.PlayCommon(&SFX_rangeup); return;
      case EFFECT_RANGE_DOWN: hybrid_font.PlayCommon(&SFX_rangedwn); return;
    }
  }

  void SayMode() {
    switch (blaster_mode) {
      case MODE_STUN:
        if (SFX_mdstun) {
          hybrid_font.PlayCommon(&SFX_mdstun);
        } else if (SFX_mode) {
          hybrid_font.PlayCommon(&SFX_mode);
        } else {
          talkie.Say(spSTUN);
        }
      break;
      case MODE_KILL:
        if (SFX_mdkill) {
          hybrid_font.PlayCommon(&SFX_mdkill);
        } else if (SFX_mode) {
          hybrid_font.PlayCommon(&SFX_mode);
        } else {
          talkie.Say(spKILL);      
        }
      break;
      case MODE_AUTO:
        if (SFX_mdauto) {
          hybrid_font.PlayCommon(&SFX_mdauto);
        } else if (SFX_mode) {
          hybrid_font.PlayCommon(&SFX_mode);
        } else {
          talkie.Say(spAUTOFIRE);       
        }
      break;
    }
  }
  
  void SayRange() {
     if (SFX_range || SFX_range.files_found() >= maximum_range_) {
      SFX_range.Select(current_range_ - 1);
      hybrid_font.PlayCommon(&SFX_range);
    } else if ( SFX_rangemax && SFX_rangemin && SFX_rangeup && SFX_rangedwn) {
      if (current_range_ == maximum_range_) {
        hybrid_font.PlayCommon(&SFX_rangemax);
      } else if (current_range_ == 1) {
        hybrid_font.PlayCommon(&SFX_rangemin);
      } else if (previous_range_<current_range_) {
        hybrid_font.PlayCommon(&SFX_rangeup);
      } else {
        hybrid_font.PlayCommon(&SFX_rangedwn);
      }
    } else {
      talkie.Say(spRANGE);
      talkie.SayNumber(current_range_);
    }
  };
};

#endif

1 Like