Blaster - make autofire count bullets

Well, I took a crack at this, but I’m stuck at the moment.
The primary goal is to increment the shots_fired_ during a lockup.
Secondarily, it would be ideal to count each shot based on the sound’s duration, but I don’t think we can get the length of the looped auto.wav during lockup, so might need to choose a fixed duration of each shot instead of incrementing after each actual shot sound plays.
But the way I have things coded currently, even using a set time for each shot, it’s getting stuck because we’re in a ‘while (auto_firing)’ loop and this causes all remaining shots to fire until empty even if the trigger is released.

So I guess the next thing is choose a different way to cause the shots_fired_ to increment while continuing to listen for button events.

  virtual void CheckEmpty() {
    if (max_shots_ != -1) {
      if (shots_fired_ >= max_shots_) {
        empty_ = true;
        SaberBase::DoEffect(EFFECT_EMPTY, 0);
        return;
      }
    }
  }

  uint32_t auto_time_;
  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_ && !empty_) {
      // Don't jam if empty
        SaberBase::DoEffect(EFFECT_JAM, 0);
      return;
    }
#endif
#endif
    CheckEmpty();
    if (empty_) 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;
      auto_time_ = millis();
      while (auto_firing_) {
        if (millis() - auto_time_ > 250) {
          shots_fired_++;
          auto_time_ = millis();
STDOUT << "**************** millis() - auto_time_ " << millis() - auto_time_ << "\n";
STDOUT << " --------------- time elapsed exceeded 250, incrementing shots with shots-fired_++. Resetting timer.";
          STDOUT << "AUTOFIRING - counting shots. Remaining = " << GetBulletCount() << "\n";
          CheckEmpty();
          if (empty_) {
            SaberBase::DoEndLockup();
            SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
            auto_firing_ = false;
            return;
          }
        } else {
STDOUT << "---------------- time elapsed NOT greater than 250, bullet count should be same = " << GetBulletCount() << "\n";
STDOUT << "**************** millis() - auto_time_ " << millis() - auto_time_ << "\n";

        }
      }
    } else {
      if (blaster_mode == MODE_STUN) {
        SaberBase::DoEffect(EFFECT_STUN, 0);
      } else {
        SaberBase::DoEffect(EFFECT_FIRE, 0);
        STDOUT << "FIRE - counting shots. Remaining shots = " << GetBulletCount() << "\n";
      }
      shots_fired_++;
    }
  }

This does not work.
All ProffieOS coding has to be done in a “non-blocking” style. That means that the code cannot wait, stop or loop until something happens. Instead it must return and then check if that something has happened next time the code is called.

Some of the ProffieOS code uses a trick using switch() which lets you jump out of the code, and then jump back next time. This ends up kind of like threads, but it’s not really. Such code will be inside a function that has BEGIN_STATE_MACHINE / END_STATE_MACHINE in it, and it’s possible to do loops, because each YIELD() call actually jumps out of the function, does other stuff and then comes back later.

Thanks Professor.
Some brain racking with that info and now this is working!
Very cool. Was stuck because I didn’t see there’s already a Loop in the prop, so it didn’t like a second one,
so I moved the new counting bit to Loop() inside a STATE_MACHINE.
Finally, figured out I needed to add StateMachine to the class


  void Loop() override {
    PropBase::Loop();
    PollNextAction();
    sound_library_.Poll(wav_player);
    if (wav_player && !wav_player->isPlaying()) wav_player.Free();

    STATE_MACHINE_BEGIN();
    while (true) {
      while (!auto_firing_) YIELD();
      if (millis() - auto_time_ > 250) {
        shots_fired_++;
        auto_time_ = millis();
        STDOUT << "AUTOFIRING - counting shots. Remaining = " << GetBulletCount() << "\n";
        CheckEmpty();
        if (empty_) {
          SaberBase::DoEndLockup();
          SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
          auto_firing_ = false;
          return;
        }
      }
    YIELD();
    }
    STATE_MACHINE_END();
  }

This is overkill, and basically the same as writing:

if (auto_firing && millis() - auto_time_ > 250) {

Right, thanks.

3 Likes

Wow thanx for the tip.
Do you think it might also be that when break cleaner evaporates it cools rapidly causing the internal stresses in extruded polycarbonate to be releaced?

lol is that a nod to my use of “take a crack at this”?

@MTMiller if you’re feeling adventurous, here’s what I plan to submit for a custom blaster prop file.

2 Likes

Ooh! Self Destruct! That goes in the blade style code, right? Or in this case, blaster code. As soon as I try out the rapid fire bullet count fix, I might give that a go as well. I have another suggestion for the OLED display. Since we’re not at a place where we can decrease the font size for the bullet counter easily, can we instead make it so that the bullet count display goes away after, say, one second? The reticle animation then comes back on the OLED until the fire button gets activated again, displaying the bullet count once again. Do-able?

I must have a bug in my code🤣 that reply was not supposed to be in this thread.

Won’t compile. Ironically, it’s the self destruct part that is causing the error.

props\blaster_bc_buttons.h:351:29: error: ‘EFFECT_DESTRUCT’ was not declared in this scope; did you mean ‘EFFECT_STUN’?

Do I have to include the EFFECT_DESTRUCT in the blaster styles, whether I use it or not?

ah. yeah, my personal version I made it EFFECT_DESTRUCT specifically instead of an existing generic EFFECT_USER1.

If you add

DEFINE_EFFECT(DESTRUCT)                      \

to the list in common/saber_base.h you should be good.

that’s funny

Bullet count on autofire appears to be working, as it is working on all modes now. Thank you!

2 Likes