Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ============================================================
- ================== SABERSENSE™ PROP FILE ===================
- ============================================================
- Built on SA22C programming by Matthew McGeary.
- Modified by Chris Carter with help and contributions
- from Brian Connor and Fredrik Hubinette.
- November 2024.
- Version 55.
- ============================================================
- ========= BUTTON SYSTEM PRINCIPLES AND LOGIC NOTES =========
- The Sabersense™ button prop file has been engineered for
- simplicity and usability. Complex gesture controls and
- features like Battle Mode have been removed.
- The Sabersense™ button prop features harmonized controls
- between one-button and two-button operation without
- compromising the greater usability of two-button operation.
- Where practicable, the same controls apply to both states,
- with two-button operation benefitting from some extra
- features. Where possible without causing conflicts, some
- one-button controls also appear in two-button mode,
- despite two-button having its own controls for the same feature.
- The overall intention is that users need only remember a
- minimum set of control principles in order to access
- all functions. As such, the logic is that the same button
- presses do the same thing within the various states,
- subject to inevitable and obvious variants.
- Hence:
- ONE AND TWO BUTTON:
- Single click MAIN always lights the blade...
- Short click lights blade with sound
- Long click lights blade mute
- Double click MAIN always plays a sound file...
- Character Quote or Music track with blade OFF
- Character Quote or Force Effect with blade ON
- Holding down MAIN (1-button) or AUX (2-button)
- and waiting with blade OFF always skips to specific preset...
- Hilt pointing up - first preset
- Hilt horizontal - middle preset
- Hilt pointing down - last preset
- Triple-clicking MAIN always enters a control menu
- Colour change with blade ON
- BladeID with blade OFF
- TWO BUTTON ONLY:
- Short clicking AUX with blade OFF always moves to a different preset,
- forward with hilt pointing up, backwards with hilt pointing down...
- Single short click - one preset
- Double short click - five presets
- Triple short click - ten presets
- Holding MAIN and short clicking AUX always enters a control menu...
- Colour change with blade ON
- Volume menu with blade OFF
- ==========================================================
- =================== 1 BUTTON CONTROLS ====================
- MAIN FUNCTIONS
- Activate blade Short click while OFF. *
- Activate blade mute Long click while OFF (hold for one second then release).
- Deactivate blade Hold and wait until blade is off while ON.
- FUNCTIONS WITH BLADE OFF
- Next preset Double click and hold while OFF pointing blade tip up.
- Previous preset Double click and hold while OFF pointing blade tip down.
- Skip to first preset Press and hold until it switches, hilt pointing upwards.
- Skip to middle preset Press and hold until it switches, hilt horizontal.
- Skip to last preset Press and hold until it switches, hilt pointing downwards.
- Play Character Quote Fast double-click, hilt pointing up. Quotes play sequentially. **
- To reset sequential quotes, change font or run BladeID.
- Play Music Track Fast double-click, hilt pointing down. **
- Speak battery voltage Fast four clicks while OFF.
- Run BladeID/Array Select Fast triple-click while OFF. (Applicable installs only).
- Enter/Exit VOLUME MENU Hold and clash while OFF.
- Volume up Click while in VOLUME MENU, hilt pointing up.
- Volume down Click while in VOLUME MENU, hilt pointing down.
- Volume adjusts in increments per click.
- You must exit VOLUME MENU to resume using lightsaber normally.
- FUNCTIONS WITH BLADE ON
- Blade lockup Hold and hit clash while ON.
- Blade tip drag Hold and hit clash while ON pointing the blade tip down.
- Force Effect Fast double-click, hilt pointing down.
- Plays random Force effect (often character quote).
- Character Quote Fast double-click, hilt pointing up.
- Plays sequential character quote.
- Lightning block Double click and hold while ON.
- Melt Hold and thrust forward clash while ON. (Selected fonts only).
- Blaster blocks Short click/double click/triple click while ON.
- Enter multi-blast mode Hold while swinging for one second and release.
- To trigger blaster block, swing saber while in multi-blast mode.
- To exit, hold while swinging for one second and release.
- COLOUR CHANGE FUNCTIONS WITH BLADE ON
- Enter COLOUR MENU Fast triple-click while ON.
- Announcement confirms you are in the COLOUR MENU.
- Cycle to next colour Rotate hilt whilst in COLOUR MENU until desired colour is reached.
- Exit COLOUR MENU Fast triple-click OR hold and wait.
- Announcement confirms you are exiting COLOUR MENU.
- You must exit COLOUR MENU to resume using lightsaber normally.
- ============================================================
- ===================== 2 BUTTON CONTROLS ====================
- MAIN FUNCTIONS
- Activate blade Short click MAIN. *
- Activate blade mute Long click MAIN (hold for one second then release).
- Deactivate blade Press and hold MAIN and wait until blade is off.
- FUNCTIONS WITH BLADE OFF
- Next preset Short click AUX, hilt pointing upwards.
- Previous preset Short click AUX, hilt pointing downwards.
- Previous preset Hold AUX and short click MAIN.
- (Duplicate legacy command).
- Skip to first preset Press and hold any button until it switches, hilt upwards.
- Skip to middle preset Press and hold any button until it switches, hilt horizontal.
- Skip to last preset Press and hold any button until it switches, hilt downwards.
- Skip forward 5 presets Fast double-click AUX, hilt pointing upwards.
- Skip back 5 presets Fast double-click AUX, hilt pointing downwards.
- Skip forward 10 presets Fast triple-click AUX, hilt pointing upwards.
- Skip back 10 presets Fast triple-click AUX, hilt pointing downwards.
- Play Character Quote Fast double-click MAIN, pointing up. Quotes play sequentially. **
- To reset sequential quotes, change font or run BladeID.
- Play Music Track Fast double-click MAIN, pointing down. **
- Speak battery voltage Fast four clicks MAIN or hold hold AUX for one second and let go.
- Run BladeID/Array Select Fast triple-click while OFF. (Applicable installs only).
- Enter/Exit VOLUME MENU Hold MAIN then quickly click AUX and release both simultaneously.
- Volume up Click MAIN while in VOLUME MENU, hilt pointing up.
- Volume down Click MAIN while in VOLUME MENU, hilt pointing down, OR click
- AUX while in VOLUME MENU.
- Volume adjusts in increments per click.
- You must exit VOLUME MENU to resume using saber normally.
- FUNCTIONS WITH BLADE ON
- Blade lockup Press and hold AUX.
- Blade tip drag Press and hold AUX while blade is pointing down.
- Force Effect Fast double-click MAIN, hilt pointing down.
- Plays random Force effect (often character quote).
- Play Character Quote Fast double-click MAIN, hilt pointing up.
- Plays sequential character quote.
- Lightning block Double-click MAIN and hold.
- Melt Hold MAIN and push blade tip against wall (stab).
- Blaster blocks Short click AUX.
- Enter multi-blast mode Hold MAIN while swinging for one second and release.
- Saber will play two quick blasts confirming mode.
- Swing blade to trigger blaster block.
- To exit multi-blast mode, fast single click AUX.
- COLOUR CHANGE FUNCTIONS WITH BLADE ON
- Enter/Exit COLOUR MENU Hold MAIN then quickly click AUX and release both
- buttons simultaneously. Or fast triple-click MAIN.
- Announcement confirms you are in the COLOUR MENU.
- Cycle to next colour Rotate hilt whilst in COLOUR MENU until desired colour is reached.
- Most Sabersense presets have 12 colour options.
- Alt Exit COLOUR MENU Hold MAIN and wait.
- Announcement confirms you are exiting COLOUR MENU.
- You must exit COLOUR MENU to resume using lightsaber normally.
- * = Gesture ignitions also available via defines.
- ** = Audio player orientations can be reversed using SABERSENSE_FLIP_AUDIO_PLAYERS define.
- ===========================================================
- ========================= DEFINES =========================
- #define SABERSENSE_ARRAY_SELECTOR
- Replaces regular BladeID and allows cycling between different
- blade/preset arrays regardless of actual BladeID status.
- #define SABERSENSE_NUM_ARRAYS
- Required when using SABERSENSE_ARRAY_SELECTOR to tell the
- system how many blade arrays there are.
- #define SABERSENSE_FLIP_AUDIO_PLAYERS
- Reverses UP/DOWN orientation for playing FORCE, QUOTE and
- MUSIC TRACK audio files. Default (no define) is UP for
- sequential QUOTE with blade ON and OFF, and DOWN for random
- FORCE effect (ON) and music TRACK (OFF). Define acts on
- both ON and OFF states for consistency.
- #define SABERSENSE_OS7_LEGACY_SUPPORT
- Required when using this prop file with ProffieOS 7.x.
- Must NOT be used with ProffieOS 8.x or later.
- #define SABERSENSE_NO_LOCKUP_HOLD
- Applicable to two-button mode only, reverts to lockup being
- triggered by clash while holding aux.
- GESTURE CONTROLS
- There are four gesture types: Twist, Stab, Swing and Thrust.
- Gesture controls bypass all preon effects.
- Below are the options to add to the config to enable the various gestures. MM.
- #define SABERSENSE_TWIST_ON
- #define SABERSENSE_TWIST_OFF
- #define SABERSENSE_STAB_ON
- #define SABERSENSE_SWING_ON
- #define SABERSENSE_THRUST_ON
- ============================================================
- ============================================================
- */
- #ifndef PROPS_SABER_SABERSENSE_BUTTONS_H
- #define PROPS_SABER_SABERSENSE_BUTTONS_H
- #ifdef SABERSENSE_ARRAY_SELECTOR
- #ifndef SABERSENSE_NUM_ARRAYS // No default number of arrays - must be defined in config.
- #error "SABERSENSE_NUM_ARRAYS must be defined in the config file."
- #endif
- // Function to play the corresponding sound.
- void PlaySound(const char* sound) {
- RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
- if (player) {
- if (!player->PlayInCurrentDir(sound)) {
- player->Play(sound);
- }
- }
- }
- struct SabersenseArraySelector {
- static int return_value; // Tracks the current array index.
- static const int sabersense_num_arrays = SABERSENSE_NUM_ARRAYS;
- static bool shouldPlaySound; // Flag to control if sound should be played.
- static unsigned long lastSwitchTime; // Track time of the last array switch.
- static const unsigned long soundDelay = 200; // Delay in ms before playing sound after switch.
- static bool isSwitchingInProgress; // Flag to indicate if array switch is in progress.
- float id() {
- return return_value;
- }
- // Forward cycle through arrays...
- static void cycleForward() {
- isSwitchingInProgress = true; // Mark that the switch is in progress.
- return_value = (return_value + 1) % sabersense_num_arrays;
- shouldPlaySound = true;
- lastSwitchTime = millis();
- isSwitchingInProgress = false; // Mark that the switch is complete.
- }
- // Backward cycle through arrays.
- static void cycleBackward() {
- isSwitchingInProgress = true; // Mark that the switch is in progress
- return_value = (return_value - 1 + sabersense_num_arrays) % sabersense_num_arrays; // Ensures wrap.
- shouldPlaySound = true;
- lastSwitchTime = millis();
- isSwitchingInProgress = false; // Mark that the switch is complete.
- }
- // Function to play corresponding sound file based on array index.
- static void playArraySound(int arrayIndex) {
- const char* soundFile = nullptr;
- switch (arrayIndex) {
- // Maximum of eight arrays possible.
- case 0: soundFile = "array1.wav"; break;
- case 1: soundFile = "array2.wav"; break;
- case 2: soundFile = "array3.wav"; break;
- case 3: soundFile = "array4.wav"; break;
- case 4: soundFile = "array5.wav"; break;
- case 5: soundFile = "array6.wav"; break;
- case 6: soundFile = "array7.wav"; break;
- case 7: soundFile = "array8.wav"; break;
- default: return; // No sound for invalid array index.
- }
- PlaySound(soundFile); // Calls custom PlaySound function.
- }
- // Function to check enough time has passed to play the sound.
- static void checkAndPlaySound() {
- if (shouldPlaySound && !isSwitchingInProgress && (millis() - lastSwitchTime >= soundDelay)) {
- playArraySound(return_value); // Play sound for the current array.
- shouldPlaySound = false; // Reset flag after sound is played.
- }
- }
- // Loop function, needs to be called periodically.
- static void loop() {
- checkAndPlaySound(); // Check if sound should be played after switching arrays.
- }
- };
- // Static member initialization
- int SabersenseArraySelector::return_value = 0; // Start with the first array (index 0).
- bool SabersenseArraySelector::shouldPlaySound = false; // Flag to control sound playback.
- unsigned long SabersenseArraySelector::lastSwitchTime = 0; // Track time of array switch.
- bool SabersenseArraySelector::isSwitchingInProgress = false; // Flag for switch status.
- #undef BLADE_ID_CLASS_INTERNAL
- #define BLADE_ID_CLASS_INTERNAL SabersenseArraySelector
- #undef BLADE_ID_CLASS
- #define BLADE_ID_CLASS SabersenseArraySelector
- #endif
- #include "prop_base.h"
- #include "../sound/hybrid_font.h"
- #undef PROP_TYPE
- #define PROP_TYPE SabersenseButtons
- #ifndef MOTION_TIMEOUT
- #define MOTION_TIMEOUT 60 * 15 * 1000
- #endif
- #ifndef SABERSENSE_SWING_ON_SPEED
- #define SABERSENSE_SWING_ON_SPEED 250
- #endif
- #ifndef SABERSENSE_LOCKUP_DELAY
- #define SABERSENSE_LOCKUP_DELAY 200
- #endif
- #ifndef SABERSENSE_FORCE_PUSH_LENGTH
- #define SABERSENSE_FORCE_PUSH_LENGTH 5
- #endif
- #ifndef BUTTON_DOUBLE_CLICK_TIMEOUT
- #define BUTTON_DOUBLE_CLICK_TIMEOUT 300
- #endif
- #ifndef BUTTON_SHORT_CLICK_TIMEOUT
- #define BUTTON_SHORT_CLICK_TIMEOUT 300
- #endif
- #ifndef BUTTON_HELD_TIMEOUT
- #define BUTTON_HELD_TIMEOUT 300
- #endif
- #ifndef BUTTON_HELD_MEDIUM_TIMEOUT
- #define BUTTON_HELD_MEDIUM_TIMEOUT 1000
- #endif
- #ifndef BUTTON_HELD_LONG_TIMEOUT
- #define BUTTON_HELD_LONG_TIMEOUT 2000
- #endif
- #ifdef SABERSENSE_SWING_ON
- #define SABERSENSE_SWING_GESTURE
- #endif
- #ifdef SABERSENSE_STAB_ON
- #define SABERSENSE_STAB_GESTURE
- #endif
- #ifdef SABERSENSE_TWIST_ON
- #define SABERSENSE_TWIST_GESTURE
- #endif
- #ifdef SABERSENSE_THRUST_ON
- #define SABERSENSE_THRUST_GESTURE
- #endif
- EFFECT(dim); // for EFFECT_POWERSAVE
- EFFECT(battery); // for EFFECT_BATTERY_LEVEL
- EFFECT(vmbegin); // for Begin Volume Menu
- EFFECT(vmend); // for End Volume Menu
- EFFECT(volup); // for increse volume
- EFFECT(voldown); // for decrease volume
- EFFECT(volmin); // for minimum volume reached
- EFFECT(volmax); // for maximum volume reached
- EFFECT(faston); // for EFFECT_FAST_ON
- EFFECT(blstbgn); // for Begin Multi-Blast
- EFFECT(blstend); // for End Multi-Blast
- #ifdef SABERSENSE_OS7_LEGACY_SUPPORT
- EFFECT(quote); // for playing quotes. Required for ProffieOS 7.x.
- #endif
- // The Saber class implements the basic states and actions
- // for the saber.
- class SabersenseButtons : public PROP_INHERIT_PREFIX PropBase {
- public:
- SabersenseButtons() : PropBase() {}
- const char* name() override { return "SabersenseButtons"; }
- void Loop() override {
- PropBase::Loop();
- DetectTwist();
- Vec3 mss = fusor.mss();
- if (SaberBase::IsOn()) {
- DetectSwing();
- if (auto_lockup_on_ &&
- !swinging_ &&
- fusor.swing_speed() > 120 &&
- millis() - clash_impact_millis_ > SABERSENSE_LOCKUP_DELAY &&
- SaberBase::Lockup()) {
- SaberBase::DoEndLockup();
- SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
- auto_lockup_on_ = false;
- }
- if (auto_melt_on_ &&
- !swinging_ &&
- fusor.swing_speed() > 60 &&
- millis() - clash_impact_millis_ > SABERSENSE_LOCKUP_DELAY &&
- SaberBase::Lockup()) {
- SaberBase::DoEndLockup();
- SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
- auto_melt_on_ = false;
- }
- // EVENT_PUSH
- if (fabs(mss.x) < 3.0 &&
- mss.y * mss.y + mss.z * mss.z > 70 &&
- fusor.swing_speed() < 30 &&
- fabs(fusor.gyro().x) < 10) {
- if (millis() - push_begin_millis_ > SABERSENSE_FORCE_PUSH_LENGTH) {
- Event(BUTTON_NONE, EVENT_PUSH);
- push_begin_millis_ = millis();
- }
- } else {
- push_begin_millis_ = millis();
- }
- } else {
- // EVENT_SWING - Swing On gesture control to allow fine tuning of speed needed to ignite
- if (millis() - saber_off_time_ < MOTION_TIMEOUT) {
- SaberBase::RequestMotion();
- if (swinging_ && fusor.swing_speed() < 90) {
- swinging_ = false;
- }
- if (!swinging_ && fusor.swing_speed() > SABERSENSE_SWING_ON_SPEED) {
- swinging_ = true;
- Event(BUTTON_NONE, EVENT_SWING);
- }
- }
- // EVENT_THRUST
- if (mss.y * mss.y + mss.z * mss.z < 16.0 &&
- mss.x > 14 &&
- fusor.swing_speed() < 150) {
- if (millis() - thrust_begin_millis_ > 15) {
- Event(BUTTON_NONE, EVENT_THRUST);
- thrust_begin_millis_ = millis();
- }
- } else {
- thrust_begin_millis_ = millis();
- }
- }
- }
- // Volume Menu
- void VolumeUp() {
- STDOUT.println("Volume up");
- if (dynamic_mixer.get_volume() < VOLUME) {
- dynamic_mixer.set_volume(std::min<int>(VOLUME + VOLUME * 0.1,
- dynamic_mixer.get_volume() + VOLUME * 0.10));
- if (SFX_volup) {
- hybrid_font.PlayCommon(&SFX_volup);
- } else {
- beeper.Beep(0.5, 2000);
- }
- STDOUT.print("Volume Up - Current Volume: ");
- STDOUT.println(dynamic_mixer.get_volume());
- } else {
- // Cycle through ends of Volume Menu option
- #ifdef VOLUME_MENU_CYCLE
- if (!max_vol_reached_) {
- if (SFX_volmax) {
- hybrid_font.PlayCommon(&SFX_volmax);
- } else {
- beeper.Beep(0.5, 3000);
- }
- STDOUT.print("Maximum Volume: ");
- max_vol_reached_ = true;
- } else {
- dynamic_mixer.set_volume(std::max<int>(VOLUME * 0.1,
- dynamic_mixer.get_volume() - VOLUME * 0.90));
- if (SFX_volmin) {
- hybrid_font.PlayCommon(&SFX_volmin);
- } else {
- beeper.Beep(0.5, 1000);
- }
- STDOUT.print("Minimum Volume: ");
- max_vol_reached_ = false;
- }
- #else
- if (SFX_volmax) {
- hybrid_font.PlayCommon(&SFX_volmax);
- } else {
- beeper.Beep(0.5, 3000);
- }
- STDOUT.print("Maximum Volume: ");
- #endif
- }
- }
- void VolumeDown() {
- STDOUT.println("Volume Down");
- if (dynamic_mixer.get_volume() > (0.10 * VOLUME)) {
- dynamic_mixer.set_volume(std::max<int>(VOLUME * 0.1,
- dynamic_mixer.get_volume() - VOLUME * 0.10));
- if (SFX_voldown) {
- hybrid_font.PlayCommon(&SFX_voldown);
- } else {
- beeper.Beep(0.5, 2000);
- }
- STDOUT.print("Volume Down - Current Volume: ");
- STDOUT.println(dynamic_mixer.get_volume());
- } else {
- #ifdef VOLUME_MENU_CYCLE
- if (!min_vol_reached_) {
- if (SFX_volmin) {
- hybrid_font.PlayCommon(&SFX_volmin);
- } else {
- beeper.Beep(0.5, 1000);
- }
- STDOUT.print("Minimum Volume: ");
- min_vol_reached_ = true;
- } else {
- dynamic_mixer.set_volume(VOLUME);
- if (SFX_volmax) {
- hybrid_font.PlayCommon(&SFX_volmax);
- } else {
- beeper.Beep(0.5, 3000);
- }
- STDOUT.print("Maximum Volume: ");
- min_vol_reached_ = false;
- }
- #else
- if (SFX_volmin) {
- hybrid_font.PlayCommon(&SFX_volmin);
- } else {
- beeper.Beep(0.5, 1000);
- }
- STDOUT.print("Minimum Volume: ");
- #endif
- }
- }
- // Button Clicker to play press/release wav files when buttons are pressed.
- // Intended for Scavenger hilt where wheel makes tactile feel difficult.
- // Requires press.wav and release.wav files to work.
- void PlaySound(const char* sound) {
- RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
- if (player) {
- if (!player->PlayInCurrentDir(sound)) player->Play(sound);
- }
- }
- bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override {
- switch (EVENTID(button, event, modifiers)) {
- case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
- case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
- case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
- case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
- SaberBase::RequestMotion();
- PlaySound("press.wav");
- return false;
- case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
- case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
- case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
- case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
- PlaySound("release.wav");
- if (SaberBase::Lockup()) {
- SaberBase::DoEndLockup();
- SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
- return true;
- } else {
- return false;
- }
- case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ON):
- case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_ON):
- if (accel_.x < -0.15) {
- pointing_down_ = true;
- } else {
- pointing_down_ = false;
- }
- return true;
- // Gesture Controls
- #ifdef SABERSENSE_SWING_ON
- case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_OFF):
- // Due to motion chip startup on boot creating false ignition we delay Swing On at boot for 3000ms
- if (millis() > 3000) {
- FastOn();
- }
- return true;
- #endif
- #ifdef SABERSENSE_TWIST_ON
- case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_OFF):
- // Delay twist events to prevent false trigger from over twisting
- if (millis() - last_twist_ > 2000 &&
- millis() - saber_off_time_ > 1000) {
- FastOn();
- last_twist_ = millis();
- }
- return true;
- #endif
- #ifdef SABERSENSE_TWIST_OFF
- case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_ON):
- // Delay twist events to prevent false trigger from over twisting
- if (millis() - last_twist_ > 3000) {
- Off();
- last_twist_ = millis();
- saber_off_time_ = millis();
- }
- return true;
- #endif
- #ifdef SABERSENSE_STAB_ON
- case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_OFF):
- if (millis() - saber_off_time_ > 1000) {
- FastOn();
- }
- return true;
- #endif
- #ifdef SABERSENSE_THRUST_ON
- case EVENTID(BUTTON_NONE, EVENT_THRUST, MODE_OFF):
- if (millis() - saber_off_time_ > 1000) {
- FastOn();
- }
- return true;
- #endif
- // Multiple Skips only available with 2 button installs.
- // Skips forward five fonts if pointing up, skips back five fonts if pointing down.
- case EVENTID(BUTTON_AUX, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF):
- // backwards if pointing down
- SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -5 : 5), true);
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- // Skips forward ten fonts if pointing up, skips back ten fonts if pointing down.
- case EVENTID(BUTTON_AUX, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
- // backwards if pointing down
- SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -10 : 10), true);
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- // Saber ON AND Volume Adjust.
- case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_OFF):
- IgnoreClash(50); // Hopefully prevents false clashes due to 'clicky' button.
- // Low threshold so as not to conflict with 1-button lockup or volume menu.
- if (!mode_volume_) {
- On();
- } else {
- if (fusor.angle1() > 0) {
- VolumeUp();
- } else {
- VolumeDown();
- }
- }
- return true;
- // Modified 2 button 'next/previous preset' AND volume down,
- // to align with multiple skips above.
- // Forward one font pointing up, back one font pointing down.
- case EVENTID(BUTTON_AUX, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_OFF):
- // backwards if pointing down
- if (!mode_volume_) {
- SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -1 : 1), true);
- } else {
- VolumeDown();
- }
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- // 1 button 'next/previous preset' command.
- // Forward one font pointing up, back one font pointing down.
- #if NUM_BUTTONS == 1
- case EVENTID(BUTTON_POWER, EVENT_SECOND_HELD, MODE_OFF):
- // backwards if pointing down
- if (!mode_volume_) {
- SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -1 : 1), true);
- } else {
- VolumeDown();
- }
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- #endif
- // 1 Button skips to first preset (up) or last preset (down)
- // or middle preset if horizontal:
- #if NUM_BUTTONS == 2
- case EVENTID(BUTTON_AUX, EVENT_FIRST_HELD_LONG, MODE_OFF):
- #endif
- case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_LONG, MODE_OFF):
- #define DEGREES_TO_RADIANS (M_PI / 180)
- if (fusor.angle1() > 45 * DEGREES_TO_RADIANS) {
- // If pointing up
- SetPreset(0, true);
- } else if (fusor.angle1() < -45 * DEGREES_TO_RADIANS) {
- // If pointing down
- SetPreset(-1, true);
- } else {
- // If horizontal
- CurrentPreset tmp;
- tmp.SetPreset(-1);
- SetPreset(tmp.preset_num / 2, true);
- }
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- // 1 and 2 button: Previous Preset, retained legacy control.
- #if NUM_BUTTONS == 2
- case EVENTID(BUTTON_POWER, EVENT_CLICK_SHORT, MODE_OFF | BUTTON_AUX):
- #endif
- if (!mode_volume_) {
- previous_preset();
- }
- return true;
- // Skips to first preset (up) or last (battery or charge) preset (down)
- // or middle preset if horizontal:
- #if NUM_BUTTONS == 2
- // 2 button: First Preset
- case EVENTID(BUTTON_AUX, EVENT_HELD_LONG, MODE_OFF):
- #endif
- #define DEGREES_TO_RADIANS (M_PI / 180)
- if (fusor.angle1() > 45 * DEGREES_TO_RADIANS) {
- // If pointing up
- SetPreset(0, true);
- } else if (fusor.angle1() < -45 * DEGREES_TO_RADIANS) {
- // If pointing down
- SetPreset(-1, true);
- } else {
- // If horizontal
- CurrentPreset tmp;
- tmp.SetPreset(-1);
- SetPreset(tmp.preset_num / 2, true);
- }
- #ifdef SAVE_PRESET
- SaveState(current_preset_.preset_num);
- #endif
- return true;
- // BladeID and manual blade array selector.
- case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
- #ifdef SABERSENSE_ARRAY_SELECTOR
- // Cycles through blade arrays regardless of BladeID status.
- if (fusor.angle1() > 0) {
- // Cycles forward...
- SabersenseArraySelector::cycleForward();
- } else {
- // Cycles backward.
- SabersenseArraySelector::cycleBackward();
- }
- FindBladeAgain();
- SabersenseArraySelector::checkAndPlaySound();
- return true;
- #else
- // Runs BladeID manually to actually check BladeID status.
- // Won't change arrays unless status tells it to (i.e. Data/Neg resistance changes).
- FindBladeAgain();
- SabersenseArraySelector::checkAndPlaySound();
- return true;
- #endif
- // Activate Muted
- case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_OFF):
- if (SetMute(true)) {
- unmute_on_deactivation_ = true;
- On();
- }
- return true;
- // Turn Blade OFF
- #if NUM_BUTTONS > 1
- // 2 button
- case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_MEDIUM, MODE_ON):
- #else
- // 1 button
- case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_LONG, MODE_ON):
- #endif
- if (!SaberBase::Lockup()) {
- #ifndef DISABLE_COLOR_CHANGE
- if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) {
- // Just exit color change mode.
- // Don't turn saber off.
- ToggleColorChangeMode();
- } else {
- Off();
- }
- }
- saber_off_time_ = millis();
- swing_blast_ = false;
- return true;
- #endif
- // Character Quote and Force Effect, Blade ON.
- // Hilt pointed UP for Character Quote, plays sequentially,
- // Hilt pointed DOWN for Force Effect, plays randomly.
- case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_ON):
- #ifndef SABERSENSE_FLIP_AUDIO_PLAYERS
- // Define reverses UP/DOWN options for QUOTE/FORCE/TRACK audio player.
- // Quote player points upwards.
- if (SFX_quote) {
- if (fusor.angle1() > 0) {
- SFX_quote.SelectNext();
- SaberBase::DoEffect(EFFECT_QUOTE, 0);
- } else {
- SaberBase::DoForce(); // Force effect for hilt pointed DOWN.
- }
- } else {
- SaberBase::DoForce(); // Fallback: play force effect if no quotes are available.
- }
- return true;
- #else
- // Quote player points downwards.
- if (SFX_quote) {
- if (fusor.angle1() < 0) {
- SFX_quote.SelectNext();
- SaberBase::DoEffect(EFFECT_QUOTE, 0);
- } else {
- SaberBase::DoForce(); // Force effect for hilt pointed DOWN.
- }
- } else {
- SaberBase::DoForce(); // Fallback: play force effect if no quotes are available.
- }
- return true;
- #endif
- // Character Quote and Music Track, Blade OFF.
- // Play sequential quote pointing up, play music track pointing down.
- case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF):
- #ifndef SABERSENSE_FLIP_AUDIO_PLAYERS
- // Define reverses UP/DOWN options for QUOTE/FORCE/TRACK audio players.
- // Quote player points upwards.
- if (SFX_quote) {
- if (fusor.angle1() > 0) {
- SFX_quote.SelectNext();
- SaberBase::DoEffect(EFFECT_QUOTE, 0);
- } else {
- StartOrStopTrack(); // Play track for hilt pointed DOWN.
- }
- } else {
- StartOrStopTrack(); // Fallback: play track if no quotes are available.
- }
- return true;
- #else
- // Quote player points downwards.
- if (SFX_quote) {
- if (fusor.angle1() < 0) {
- SFX_quote.SelectNext();
- SaberBase::DoEffect(EFFECT_QUOTE, 0);
- } else {
- StartOrStopTrack(); // Play track for hilt pointed DOWN.
- }
- } else {
- StartOrStopTrack(); // Fallback: play track if no quotes are available.
- }
- return true;
- #endif
- // Colour Change.
- // 1 and 2 button modes.
- #ifndef DISABLE_COLOR_CHANGE
- case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_ON):
- ToggleColorChangeMode();
- return true;
- // 2 button mode only.
- #if NUM_BUTTONS == 2
- case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_ON | BUTTON_POWER):
- ToggleColorChangeMode();
- return true;
- #endif
- #endif
- // Blaster Deflection
- #if NUM_BUTTONS == 1
- // 1 button
- case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
- #else
- // 2 button
- case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_ON):
- case EVENTID(BUTTON_AUX, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
- #endif
- swing_blast_ = false;
- SaberBase::DoBlast();
- return true;
- // Multi-Blaster Deflection mode
- case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_ON | BUTTON_POWER):
- swing_blast_ = !swing_blast_;
- if (swing_blast_) {
- if (SFX_blstbgn) {
- hybrid_font.PlayCommon(&SFX_blstbgn);
- } else {
- hybrid_font.SB_Effect(EFFECT_BLAST, 0);
- }
- } else {
- if (SFX_blstend) {
- hybrid_font.PlayCommon(&SFX_blstend);
- } else {
- hybrid_font.SB_Effect(EFFECT_BLAST, 0);
- }
- }
- return true;
- case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_ON):
- if (swing_blast_) {
- SaberBase::DoBlast();
- }
- return true;
- // Lockup
- #if NUM_BUTTONS == 1
- // 1 button lockup
- case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_POWER):
- #else
- #ifndef SABERSENSE_NO_LOCKUP_HOLD
- // 2 button lockup
- case EVENTID(BUTTON_AUX, EVENT_FIRST_HELD, MODE_ON):
- #else
- case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_AUX):
- #endif
- #endif
- if (accel_.x < -0.15) {
- SaberBase::SetLockup(SaberBase::LOCKUP_DRAG);
- } else {
- SaberBase::SetLockup(SaberBase::LOCKUP_NORMAL);
- }
- swing_blast_ = false;
- SaberBase::DoBeginLockup();
- return true;
- break;
- // Lightning Block, 1 and 2 button.
- case EVENTID(BUTTON_POWER, EVENT_SECOND_HELD, MODE_ON):
- SaberBase::SetLockup(SaberBase::LOCKUP_LIGHTNING_BLOCK);
- swing_blast_ = false;
- SaberBase::DoBeginLockup();
- return true;
- break;
- // Melt
- case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_ON | BUTTON_POWER):
- SaberBase::SetLockup(SaberBase::LOCKUP_MELT);
- swing_blast_ = false;
- SaberBase::DoBeginLockup();
- return true;
- break;
- case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_OFF):
- SaberBase::RequestMotion();
- return true;
- // Enter Volume MENU
- #if NUM_BUTTONS == 1
- // 1 button
- case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_OFF | BUTTON_POWER):
- #else
- // 2 button
- case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_OFF | BUTTON_POWER):
- #endif
- if (!mode_volume_) {
- mode_volume_ = true;
- if (SFX_vmbegin) {
- hybrid_font.PlayCommon(&SFX_vmbegin);
- } else {
- beeper.Beep(0.5, 3000);
- }
- STDOUT.println("Enter Volume Menu");
- } else {
- mode_volume_ = false;
- if (SFX_vmend) {
- hybrid_font.PlayCommon(&SFX_vmend);
- } else {
- beeper.Beep(0.5, 3000);
- }
- STDOUT.println("Exit Volume Menu");
- }
- return true;
- // Battery level
- case EVENTID(BUTTON_POWER, EVENT_FOURTH_SAVED_CLICK_SHORT, MODE_OFF):
- #if NUM_BUTTONS == 2
- case EVENTID(BUTTON_AUX, EVENT_FIRST_CLICK_LONG, MODE_OFF):
- #endif
- talkie.SayDigit((int)floorf(battery_monitor.battery()));
- talkie.Say(spPOINT);
- talkie.SayDigit(((int)floorf(battery_monitor.battery() * 10)) % 10);
- talkie.SayDigit(((int)floorf(battery_monitor.battery() * 100)) % 10);
- talkie.Say(spVOLTS);
- SaberBase::DoEffect(EFFECT_BATTERY_LEVEL, 0);
- return true;
- #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.
- 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.
- blade_detected_ = false;
- FindBladeAgain();
- SaberBase::DoBladeDetect(false);
- return true;
- #endif
- // Events that needs to be handled regardless of what other buttons are pressed.
- case EVENTID(BUTTON_AUX2, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
- if (SaberBase::Lockup()) {
- SaberBase::DoEndLockup();
- SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
- return true;
- }
- }
- return false;
- }
- #ifdef SABERSENSE_OS7_LEGACY_SUPPORT
- void SB_Effect(EffectType effect, float location) override { // Required for ProffieOS 7.x.
- #else
- void SB_Effect(EffectType effect, EffectLocation location) override { // Required for ProffieOS 8.x.
- #endif
- switch (effect) {
- case EFFECT_QUOTE: hybrid_font.PlayCommon(&SFX_quote); return;
- case EFFECT_POWERSAVE:
- if (SFX_dim) {
- hybrid_font.PlayCommon(&SFX_dim);
- } else {
- beeper.Beep(0.5, 3000);
- }
- return;
- case EFFECT_BATTERY_LEVEL:
- if (SFX_battery) {
- hybrid_font.PlayCommon(&SFX_battery);
- } else {
- beeper.Beep(0.5, 3000);
- }
- return;
- case EFFECT_FAST_ON:
- if (SFX_faston) {
- hybrid_font.PlayCommon(&SFX_faston);
- }
- return;
- default: break; // avoids compiler warning
- }
- }
- private:
- bool pointing_down_ = false;
- bool swing_blast_ = false;
- bool mode_volume_ = false;
- bool auto_lockup_on_ = false;
- bool auto_melt_on_ = false;
- bool max_vol_reached_ = false;
- bool min_vol_reached_ = false;
- uint32_t thrust_begin_millis_ = millis();
- uint32_t push_begin_millis_ = millis();
- uint32_t clash_impact_millis_ = millis();
- uint32_t last_twist_ = millis();
- uint32_t last_push_ = millis();
- uint32_t saber_off_time_ = millis();
- };
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement