Advertisement
Sabersense

My Modest Masterpiece

Dec 11th, 2024
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 43.70 KB | None | 0 0
  1. /*
  2. ============================================================
  3. ================== SABERSENSE™ PROP FILE ===================
  4. ============================================================
  5.  
  6. Built on SA22C programming by Matthew McGeary.
  7. Modified by Chris Carter with substantial help and
  8. contributions from Brian Connor and Fredrik Hubinette.
  9. Version 89.
  10.  
  11. This prop file references certain custom sound files
  12. to aid in saber function navigation. These sound files
  13. are available as a free download from:
  14. https://sabersense.square.site/downloads
  15.  
  16.  
  17. ============================================================
  18. ========= BUTTON SYSTEM PRINCIPLES AND LOGIC NOTES =========
  19.  
  20. The Sabersense™ button control system has been engineered
  21. for simplicity and usability. Complex gesture controls and
  22. features like Battle Mode are NOT included.
  23.  
  24. By default, the Sabersense™ button prop features harmonized
  25. controls between one-button and two-button operation without
  26. compromising the greater usability of two-button systems.
  27.  
  28. Where practicable, the same controls apply to both one-button
  29. and two-button systems, with two-button operation benefitting
  30. from some extra features.
  31.  
  32. Where possible without causing conflicts, some one-button
  33. controls also appear in two-button mode, despite two-button
  34. having its own controls for the same feature.
  35.  
  36. The overall intention is that by default, users need only
  37. remember a minimum set of control principles in order to
  38. access all functions. As such, the logic is that the
  39. same button presses do the same thing within the various
  40. states, subject to inevitable and obvious variants.
  41.  
  42. Hence:
  43. ONE AND TWO BUTTON:
  44. Single click MAIN always lights the blade...
  45. Short click lights blade with sound
  46. Long click lights blade mute
  47.  
  48. Double click MAIN always plays a sound file...
  49. Character Quote or Music track with blade OFF
  50. Character Quote or Force Effect with blade ON
  51. Battery level announcement if held down on second click
  52.  
  53. Holding down MAIN (1-button) or AUX (2-button)
  54. and waiting with blade OFF always skips to specific preset...
  55. Hilt pointing up - first preset
  56. Hilt horizontal - middle preset
  57. Hilt pointing down - last preset
  58.  
  59. Triple-clicking MAIN is always a saber management feature
  60. Colour change with blade ON
  61. BladeID/Array Switch with blade OFF
  62.  
  63. TWO BUTTON ONLY:
  64. Short clicking AUX with blade OFF always moves to a different preset,
  65. forward with hilt pointing up, backwards with hilt pointing down...
  66. Single short click - one preset
  67. Double short click - five presets
  68. Triple short click - ten presets
  69.  
  70. Holding MAIN and short clicking AUX always enters a control menu...
  71. Colour change with blade ON
  72. Volume menu with blade OFF
  73.  
  74.  
  75. ==========================================================
  76. =================== 1 BUTTON CONTROLS ====================
  77.  
  78. MAIN FUNCTIONS
  79. Activate blade Short click while OFF. *
  80. Activate blade mute Long click while OFF, hilt horizontal.
  81. (Hold for one second then release).
  82. Deactivate blade Hold and wait until blade is off while ON.
  83.  
  84. FUNCTIONS WITH BLADE OFF
  85. Next preset Long click while OFF, hilt pointing up.
  86. (Hold for one second then release).
  87. Previous preset Long click while OFF, hilt pointing down.
  88. (Hold for one second then release).
  89. Skip to first preset Press and hold until it switches, hilt pointing upwards.
  90. Skip to middle preset Press and hold until it switches, hilt horizontal.
  91. Skip to last preset Press and hold until it switches, hilt pointing downwards.
  92. Play Character Quote Fast double-click, hilt pointing up. Quotes play sequentially. **
  93. To reset sequential quotes, change font or run BladeID.
  94. Play Music Track Fast double-click, hilt pointing down. **
  95. Speak battery voltage Fast double-click-and-hold while OFF.
  96. Run BladeID/Array Select Fast triple-click while OFF. (Applicable installs only).
  97. Restore Factory Defaults Fast four-clicks while OFF, hold on last click. (If enabled).
  98. Release once announcement starts.
  99. Enter/Exit VOLUME MENU Hold and clash while OFF.
  100. Volume up Click while in VOLUME MENU, hilt pointing up.
  101. Volume down Click while in VOLUME MENU, hilt pointing down.
  102. Volume adjusts in increments per click.
  103. You must exit VOLUME MENU to resume using lightsaber normally.
  104.  
  105. FUNCTIONS WITH BLADE ON
  106. Blade lockup Hold and hit clash while ON.
  107. Blade tip drag Hold and hit clash while ON pointing the blade tip down.
  108. Force Effect Fast double-click, hilt pointing down.
  109. Plays random Force effect (often character quote).
  110. Character Quote Fast double-click, hilt pointing up.
  111. Plays sequential character quote.
  112. Lightning block Double click and hold while ON.
  113. Melt Hold and thrust forward clash while ON. (Selected fonts only).
  114. Blaster blocks Short click/double click/triple click while ON.
  115. Enter multi-blast mode Hold while swinging for one second and release.
  116. To trigger blaster block, swing saber while in multi-blast mode.
  117. To exit, hold while swinging for one second and release.
  118.  
  119. COLOUR CHANGE FUNCTIONS WITH BLADE ON
  120. Enter COLOUR MENU Fast triple-click while ON.
  121. Announcement confirms you are in the COLOUR MENU.
  122. Cycle to next colour Rotate hilt whilst in COLOUR MENU until desired colour is reached.
  123. Exit COLOUR MENU Short click saves new colour and exits.
  124. Fast-double-click exits and reverts to original colour.
  125. Announcement confirms you are exiting COLOUR MENU.
  126. You must exit COLOUR MENU to resume using lightsaber normally.
  127.  
  128. * = Gesture ignitions also available via defines.
  129. ** = Audio player orientations can be reversed using SABERSENSE_FLIP_AUDIO_PLAYERS define.
  130.  
  131.  
  132. ============================================================
  133. ===================== 2 BUTTON CONTROLS ====================
  134.  
  135. MAIN FUNCTIONS
  136. Activate blade Short click MAIN. *
  137. Activate blade mute Long click MAIN (hold for one second then release).
  138. Deactivate blade Press and hold MAIN and wait until blade is off.
  139.  
  140. FUNCTIONS WITH BLADE OFF
  141. Next preset Short click AUX, hilt pointing upwards.
  142. Previous preset Short click AUX, hilt pointing downwards.
  143. Previous preset Hold AUX and short click MAIN.
  144. (Duplicate legacy command).
  145. Skip to first preset Press and hold any button until it switches, hilt upwards.
  146. Skip to middle preset Press and hold any button until it switches, hilt horizontal.
  147. Skip to last preset Press and hold any button until it switches, hilt downwards.
  148. Skip forward 5 presets Fast double-click AUX, hilt pointing upwards.
  149. Skip back 5 presets Fast double-click AUX, hilt pointing downwards.
  150. Skip forward 10 presets Fast triple-click AUX, hilt pointing upwards.
  151. Skip back 10 presets Fast triple-click AUX, hilt pointing downwards.
  152. Play Character Quote Fast double-click MAIN, pointing up. Quotes play sequentially. **
  153. To reset sequential quotes, change font or run BladeID.
  154. Play Music Track Fast double-click MAIN, pointing down. **
  155. Speak battery voltage Fast double-click-and-hold while OFF or hold hold AUX for one second and let go.
  156. Run BladeID/Array Select Fast triple-click while OFF. (Applicable installs only).
  157. Restore Factory Defaults Fast four-clicks MAIN, hold on last click. (If enabled).
  158. Release once announcement starts.
  159. Enter/Exit VOLUME MENU Hold MAIN then quickly click AUX and release both simultaneously.
  160. Volume up Click MAIN while in VOLUME MENU, hilt pointing up.
  161. Volume down Click MAIN while in VOLUME MENU, hilt pointing down, OR click
  162. AUX while in VOLUME MENU.
  163. Volume adjusts in increments per click.
  164. You must exit VOLUME MENU to resume using saber normally.
  165.  
  166. FUNCTIONS WITH BLADE ON
  167. Blade lockup Press and hold AUX.
  168. Blade tip drag Press and hold AUX while blade is pointing down.
  169. Force Effect Fast double-click MAIN, hilt pointing down.
  170. Plays random Force effect (often character quote).
  171. Play Character Quote Fast double-click MAIN, hilt pointing up.
  172. Plays sequential character quote.
  173. Lightning block Double-click MAIN and hold.
  174. Melt Hold MAIN and push blade tip against wall (stab).
  175. Blaster blocks Short click AUX. (Add Short click MAIN using define).
  176. Enter multi-blast mode Hold MAIN while swinging for one second and release.
  177. Saber will play two quick blasts confirming mode.
  178. Swing blade to trigger blaster block.
  179. To exit multi-blast mode, fast single click AUX.
  180.  
  181. COLOUR CHANGE FUNCTIONS WITH BLADE ON
  182. Enter COLOUR MENU Hold MAIN then quickly click AUX and release both
  183. buttons simultaneously. Or fast triple-click MAIN.
  184. Announcement confirms you are in the COLOUR MENU.
  185. Cycle to next colour Rotate hilt whilst in COLOUR MENU until desired colour is reached.
  186. Most Sabersense presets have 12 colour options.
  187. Exit COLOUR MENU Short click saves new colour and exits.
  188. Fast-double-click exits and reverts to original colour.
  189. Announcement confirms you are exiting COLOUR MENU.
  190. You must exit COLOUR MENU to resume using lightsaber normally.
  191.  
  192. * = Gesture ignitions also available via defines.
  193. ** = Audio player orientations can be reversed using SABERSENSE_FLIP_AUDIO_PLAYERS define.
  194.  
  195.  
  196. ===========================================================
  197. =================== SABERSENSE™ DEFINES ===================
  198.  
  199. #define SABERSENSE_BLADE_ID
  200. Replaces regular BladeID with Sabersense version to play
  201. arrayX.wav files with BladeID-derived array switching.
  202.  
  203. #define SABERSENSE_ARRAY_SELECTOR
  204. Replaces regular BladeID and allows cycling between different
  205. blade/preset arrays regardless of actual BladeID status.
  206.  
  207. #define SABERSENSE_ENABLE_ARRAY_FONT_IDENT
  208. Plays font ident after array ident when switching arrays.
  209. Works with both SABERSENSE_BLADE_ID and
  210. SABERSENSE_ARRAY_SELECTOR.
  211.  
  212. #define SABERSENSE_FLIP_AUDIO_PLAYERS
  213. Reverses UP/DOWN orientation for playing FORCE, QUOTE and
  214. MUSIC TRACK audio files. Default (no define) is UP for
  215. sequential QUOTE with blade ON and OFF, and DOWN for random
  216. FORCE effect (ON) and music TRACK (OFF). Define acts on
  217. both ON and OFF states for consistency.
  218.  
  219. #define SABERSENSE_BLAST_MAIN_AND_AUX
  220. Adds blaster block button to MAIN as well as AUX in
  221. 2-button mode. Improves 1 and 2-button harmonization,
  222. but makes accidental blasts more likely when double-clicking
  223. for Quotes or Force Effect.
  224.  
  225. #define SABERSENSE_BUTTON_CLICKER
  226. Button Clicker to play press/release wav files when
  227. buttons are pressed. Intended for Scavenger hilt
  228. where wheel makes tactile feel difficult.
  229. Requires press.wav and release.wav files to work.
  230.  
  231. #define SABERSENSE_ENABLE_RESET
  232. Enables system to be completely reset to 'factory defaults',
  233. i.e. original config, using button press to delete
  234. all save files.
  235.  
  236. #define SABERSENSE_OS7_LEGACY_SUPPORT
  237. Required when using this prop file with ProffieOS 7.x.
  238. Must NOT be used with ProffieOS 8.x or later.
  239.  
  240. #define SABERSENSE_NO_LOCKUP_HOLD
  241. Applicable to two-button mode only, reverts to lockup being
  242. triggered by clash while holding aux.
  243.  
  244. GESTURE CONTROLS
  245. There are four gesture types: Twist, Stab, Swing and Thrust.
  246. Gesture controls bypass all preon effects.
  247. #define SABERSENSE_TWIST_ON
  248. #define SABERSENSE_TWIST_OFF
  249. #define SABERSENSE_STAB_ON
  250. #define SABERSENSE_SWING_ON
  251. #define SABERSENSE_THRUST_ON
  252.  
  253. ============================================================
  254. ============================================================
  255. */
  256. #ifndef PROPS_SABER_SABERSENSE_BUTTONS_H
  257. #define PROPS_SABER_SABERSENSE_BUTTONS_H
  258.  
  259.  
  260. #include "prop_base.h"
  261. #include "../sound/hybrid_font.h"
  262.  
  263. #undef PROP_TYPE
  264. #define PROP_TYPE SabersenseButtons
  265.  
  266. #ifndef MOTION_TIMEOUT
  267. #define MOTION_TIMEOUT 60 * 15 * 1000
  268. #endif
  269.  
  270. #ifndef SABERSENSE_SWING_ON_SPEED
  271. #define SABERSENSE_SWING_ON_SPEED 250
  272. #endif
  273.  
  274. #ifndef SABERSENSE_LOCKUP_DELAY
  275. #define SABERSENSE_LOCKUP_DELAY 200
  276. #endif
  277.  
  278. #ifndef SABERSENSE_FORCE_PUSH_LENGTH
  279. #define SABERSENSE_FORCE_PUSH_LENGTH 5
  280. #endif
  281.  
  282. #ifndef BUTTON_DOUBLE_CLICK_TIMEOUT
  283. #define BUTTON_DOUBLE_CLICK_TIMEOUT 300
  284. #endif
  285.  
  286. #ifndef BUTTON_SHORT_CLICK_TIMEOUT
  287. #define BUTTON_SHORT_CLICK_TIMEOUT 300
  288. #endif
  289.  
  290. #ifndef BUTTON_HELD_TIMEOUT
  291. #define BUTTON_HELD_TIMEOUT 300
  292. #endif
  293.  
  294. #ifndef BUTTON_HELD_MEDIUM_TIMEOUT
  295. #define BUTTON_HELD_MEDIUM_TIMEOUT 1000
  296. #endif
  297.  
  298. #ifndef BUTTON_HELD_LONG_TIMEOUT
  299. #define BUTTON_HELD_LONG_TIMEOUT 2000
  300. #endif
  301.  
  302. #ifdef SABERSENSE_SWING_ON
  303. #define SABERSENSE_SWING_GESTURE
  304. #endif
  305.  
  306. #ifdef SABERSENSE_STAB_ON
  307. #define SABERSENSE_STAB_GESTURE
  308. #endif
  309.  
  310. #ifdef SABERSENSE_TWIST_ON
  311. #define SABERSENSE_TWIST_GESTURE
  312. #endif
  313.  
  314. #ifdef SABERSENSE_THRUST_ON
  315. #define SABERSENSE_THRUST_GESTURE
  316. #endif
  317.  
  318. EFFECT(dim); // for EFFECT_POWERSAVE
  319. EFFECT(battery); // for EFFECT_BATTERY_LEVEL
  320. EFFECT(vmbegin); // for Begin Volume Menu
  321. EFFECT(vmend); // for End Volume Menu
  322. EFFECT(volup); // for increse volume
  323. EFFECT(voldown); // for decrease volume
  324. EFFECT(volmin); // for minimum volume reached
  325. EFFECT(volmax); // for maximum volume reached
  326. EFFECT(faston); // for EFFECT_FAST_ON
  327. EFFECT(blstbgn); // for Begin Multi-Blast
  328. EFFECT(blstend); // for End Multi-Blast
  329. EFFECT(array); // for playing array idents
  330. EFFECT(bladeid); // for playing bladeid idents
  331. EFFECT(reset); // for playing factory default reset completed
  332. #ifdef SABERSENSE_OS7_LEGACY_SUPPORT
  333. EFFECT(quote); // for playing quotes. Required for ProffieOS 7.x.
  334. #endif
  335.  
  336.  
  337. // The Saber class implements the basic states and actions
  338. // for the saber.
  339. class SabersenseButtons : public PROP_INHERIT_PREFIX PropBase {
  340. public:
  341. SabersenseButtons() : PropBase() {}
  342. const char* name() override { return "SabersenseButtons"; }
  343.  
  344.  
  345. // RESET FACTORY DEFAULTS (Delete Save Files).
  346. // Script to determine if sound effect has finished.
  347. bool IsResetSoundPlaying() {
  348. return !!GetWavPlayerPlaying(&SFX_reset);
  349. }
  350.  
  351.  
  352. // BLADE ID OPTIONS
  353. // Primary code courtesy Brian Conner.
  354. // True BladeID, runs scan on demand with unique 'bladeid' ident effect.
  355. #ifdef SABERSENSE_BLADE_ID
  356. #ifdef SABERSENSE_ARRAY_SELECTOR // Only one Sabersense BladeID standard permitted.
  357. #error "SABERSENSE_ARRAY_SELECTOR and SABERSENSE_BLADE_ID cannot be defined at the same time."
  358. #endif
  359. // Script to determine if sound effect has finished.
  360. bool IsBladeidSoundPlaying() {
  361. return !!GetWavPlayerPlaying(&SFX_bladeid);
  362. }
  363. #ifdef SABERSENSE_ENABLE_ARRAY_FONT_IDENT // Plays 'bladeid' sound AND 'font' sound.
  364. void TriggerBladeID() {
  365. FindBladeAgain();
  366. SFX_bladeid.Select(current_config - blades);
  367. hybrid_font.PlayCommon(&SFX_bladeid);
  368. while(IsBladeidSoundPlaying()); // Wait for 'bladeid' sound file to finish...
  369. SaberBase::DoNewFont(); // ...then play font ident.
  370. }
  371. #else
  372. // Plays 'bladeid' sound only, or 'font' sound if no 'bladeid' sound available.
  373. void TriggerBladeID() {
  374. FindBladeAgain();
  375. if (SFX_bladeid) {
  376. SFX_bladeid.Select(current_config - blades);
  377. hybrid_font.PlayCommon(&SFX_bladeid); // Play 'bladeid' sound file if available.
  378. } else {
  379. SaberBase::DoNewFont(); // Play font ident if 'bladeid' sound file missing.
  380. }
  381. #endif
  382. #endif
  383.  
  384.  
  385. // Manual Blade Array cycling regardless of BladeID status.
  386. #ifdef SABERSENSE_ARRAY_SELECTOR
  387. // Script to determine if sound effect has finished.
  388. bool IsArraySoundPlaying() {
  389. return !!GetWavPlayerPlaying(&SFX_array);
  390. }
  391. #ifdef SABERSENSE_ENABLE_ARRAY_FONT_IDENT // Plays 'array' sound AND 'font' sound.
  392. void NextBladeArray() {
  393. FakeFindBladeAgain();
  394. SFX_array.Select(current_config - blades);
  395. hybrid_font.PlayCommon(&SFX_array);
  396. while(IsArraySoundPlaying()); // Wait for 'array' sound file to finish...
  397. SaberBase::DoNewFont(); // ...then play font ident.
  398. }
  399. #else
  400. // Plays 'array' sound only, or 'font' sound if no 'array' sound available.
  401. void NextBladeArray() {
  402. FakeFindBladeAgain();
  403. if (SFX_array) {
  404. SFX_array.Select(current_config - blades);
  405. hybrid_font.PlayCommon(&SFX_array); // Play 'array' sound file if available.
  406. } else {
  407. SaberBase::DoNewFont(); // Play font ident if 'array' sound file missing.
  408. }
  409. #endif
  410.  
  411. // Manual Blade Array Selection version of FindBladeAgain()
  412. #ifdef SABERSENSE_OS7_LEGACY_SUPPORT
  413. #undef ACTIVATE
  414. #define ACTIVATE(N) do { \
  415. if (!current_config->blade##N) { \
  416. goto bad_blade; \
  417. } \
  418. current_config->blade##N->Activate(); \
  419. } while(0);
  420. #endif
  421.  
  422. void FakeFindBladeAgain() {
  423. // Reverse everything FindBladeAgain does, except for recalculating best_config
  424. ONCEPERBLADE(UNSET_BLADE_STYLE)
  425.  
  426. #undef DEACTIVATE
  427. #define DEACTIVATE(N) do { \
  428. if (current_config->blade##N) \
  429. current_config->blade##N->Deactivate(); \
  430. } while(0);
  431.  
  432. ONCEPERBLADE(DEACTIVATE);
  433. SaveVolumeIfNeeded();
  434. if (fusor.angle1() > 0) {
  435. // Cycle forwards (next array) if hilt pointing up...
  436. current_config = blades + (current_config - blades + 1) % NELEM(blades);
  437. } else {
  438. // Cycle backwards (previous array) if hilt pointing down.
  439. current_config = blades + (current_config - blades - 1) % NELEM(blades);
  440. }
  441.  
  442. #ifndef SABERSENSE_OS7_LEGACY_SUPPORT
  443. #undef ACTIVATE
  444. #define ACTIVATE(N) do { \
  445. if (!current_config->blade##N) { \
  446. goto bad_blade; \
  447. } \
  448. current_config->blade##N->Activate(N); \
  449. } while(0);
  450. #endif
  451.  
  452. ONCEPERBLADE(ACTIVATE);
  453. RestoreGlobalState();
  454.  
  455. #ifdef SAVE_PRESET
  456. ResumePreset();
  457. #else
  458. SetPreset(0, false);
  459. #endif // SAVE_PRESET
  460. // PVLOG_NORMAL << "** FakeFindBladeAgain() Completed\n";
  461. return;
  462.  
  463. #if NUM_BLADES != 0
  464. bad_blade:
  465. ProffieOSErrors::error_in_blade_array();
  466. #endif
  467. }
  468. #endif
  469.  
  470.  
  471. void Loop() override {
  472. PropBase::Loop();
  473. DetectTwist();
  474. Vec3 mss = fusor.mss();
  475. if (SaberBase::IsOn()) {
  476. DetectSwing();
  477. if (auto_lockup_on_ &&
  478. !swinging_ &&
  479. fusor.swing_speed() > 120 &&
  480. millis() - clash_impact_millis_ > SABERSENSE_LOCKUP_DELAY &&
  481. SaberBase::Lockup()) {
  482. SaberBase::DoEndLockup();
  483. SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
  484. auto_lockup_on_ = false;
  485. }
  486. if (auto_melt_on_ &&
  487. !swinging_ &&
  488. fusor.swing_speed() > 60 &&
  489. millis() - clash_impact_millis_ > SABERSENSE_LOCKUP_DELAY &&
  490. SaberBase::Lockup()) {
  491. SaberBase::DoEndLockup();
  492. SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
  493. auto_melt_on_ = false;
  494. }
  495.  
  496. // EVENT_PUSH
  497. if (fabs(mss.x) < 3.0 &&
  498. mss.y * mss.y + mss.z * mss.z > 70 &&
  499. fusor.swing_speed() < 30 &&
  500. fabs(fusor.gyro().x) < 10) {
  501. if (millis() - push_begin_millis_ > SABERSENSE_FORCE_PUSH_LENGTH) {
  502. Event(BUTTON_NONE, EVENT_PUSH);
  503. push_begin_millis_ = millis();
  504. }
  505. } else {
  506. push_begin_millis_ = millis();
  507. }
  508. } else {
  509. // EVENT_SWING - Swing On gesture control to allow fine tuning of speed needed to ignite
  510. if (millis() - saber_off_time_ < MOTION_TIMEOUT) {
  511. SaberBase::RequestMotion();
  512. if (swinging_ && fusor.swing_speed() < 90) {
  513. swinging_ = false;
  514. }
  515. if (!swinging_ && fusor.swing_speed() > SABERSENSE_SWING_ON_SPEED) {
  516. swinging_ = true;
  517. Event(BUTTON_NONE, EVENT_SWING);
  518. }
  519. }
  520. // EVENT_THRUST
  521. if (mss.y * mss.y + mss.z * mss.z < 16.0 &&
  522. mss.x > 14 &&
  523. fusor.swing_speed() < 150) {
  524. if (millis() - thrust_begin_millis_ > 15) {
  525. Event(BUTTON_NONE, EVENT_THRUST);
  526. thrust_begin_millis_ = millis();
  527. }
  528. } else {
  529. thrust_begin_millis_ = millis();
  530. }
  531. }
  532. }
  533.  
  534.  
  535. // VOLUME MENU
  536. void VolumeUp() {
  537. STDOUT.println("Volume up");
  538. if (dynamic_mixer.get_volume() < VOLUME) {
  539. dynamic_mixer.set_volume(std::min<int>(VOLUME + VOLUME * 0.1,
  540. dynamic_mixer.get_volume() + VOLUME * 0.10));
  541. if (SFX_volup) {
  542. hybrid_font.PlayCommon(&SFX_volup);
  543. } else {
  544. beeper.Beep(0.5, 2000);
  545. }
  546. STDOUT.print("Volume Up - Current Volume: ");
  547. STDOUT.println(dynamic_mixer.get_volume());
  548. } else {
  549. // Cycle through ends of Volume Menu option
  550. #ifdef VOLUME_MENU_CYCLE
  551. if (!max_vol_reached_) {
  552. if (SFX_volmax) {
  553. hybrid_font.PlayCommon(&SFX_volmax);
  554. } else {
  555. beeper.Beep(0.5, 3000);
  556. }
  557. STDOUT.print("Maximum Volume: ");
  558. max_vol_reached_ = true;
  559. } else {
  560. dynamic_mixer.set_volume(std::max<int>(VOLUME * 0.1,
  561. dynamic_mixer.get_volume() - VOLUME * 0.90));
  562. if (SFX_volmin) {
  563. hybrid_font.PlayCommon(&SFX_volmin);
  564. } else {
  565. beeper.Beep(0.5, 1000);
  566. }
  567. STDOUT.print("Minimum Volume: ");
  568. max_vol_reached_ = false;
  569. }
  570. #else
  571. if (SFX_volmax) {
  572. hybrid_font.PlayCommon(&SFX_volmax);
  573. } else {
  574. beeper.Beep(0.5, 3000);
  575. }
  576. STDOUT.print("Maximum Volume: ");
  577. #endif
  578. }
  579. }
  580.  
  581. void VolumeDown() {
  582. STDOUT.println("Volume Down");
  583. if (dynamic_mixer.get_volume() > (0.10 * VOLUME)) {
  584. dynamic_mixer.set_volume(std::max<int>(VOLUME * 0.1,
  585. dynamic_mixer.get_volume() - VOLUME * 0.10));
  586. if (SFX_voldown) {
  587. hybrid_font.PlayCommon(&SFX_voldown);
  588. } else {
  589. beeper.Beep(0.5, 2000);
  590. }
  591. STDOUT.print("Volume Down - Current Volume: ");
  592. STDOUT.println(dynamic_mixer.get_volume());
  593. } else {
  594. #ifdef VOLUME_MENU_CYCLE
  595. if (!min_vol_reached_) {
  596. if (SFX_volmin) {
  597. hybrid_font.PlayCommon(&SFX_volmin);
  598. } else {
  599. beeper.Beep(0.5, 1000);
  600. }
  601. STDOUT.print("Minimum Volume: ");
  602. min_vol_reached_ = true;
  603. } else {
  604. dynamic_mixer.set_volume(VOLUME);
  605. if (SFX_volmax) {
  606. hybrid_font.PlayCommon(&SFX_volmax);
  607. } else {
  608. beeper.Beep(0.5, 3000);
  609. }
  610. STDOUT.print("Maximum Volume: ");
  611. min_vol_reached_ = false;
  612. }
  613. #else
  614. if (SFX_volmin) {
  615. hybrid_font.PlayCommon(&SFX_volmin);
  616. } else {
  617. beeper.Beep(0.5, 1000);
  618. }
  619. STDOUT.print("Minimum Volume: ");
  620. #endif
  621.  
  622. }
  623. }
  624.  
  625.  
  626. // CLICK PLAYER FOR BUTTON PRESSES.
  627. void PlaySound(const char* sound) {
  628. RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
  629. if (player) {
  630. if (!player->PlayInCurrentDir(sound)) player->Play(sound);
  631. }
  632. }
  633.  
  634. bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override {
  635. switch (EVENTID(button, event, modifiers)) {
  636. case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
  637. case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
  638. case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
  639. case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
  640. SaberBase::RequestMotion();
  641. #ifdef SABERSENSE_BUTTON_CLICKER
  642. // Intended for Scavenger hilt where wheel makes tactile feel difficult.
  643. PlaySound("press.wav"); // Requires press.wav file to work.
  644. #endif
  645. return false;
  646. case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
  647. case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
  648. case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
  649. case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
  650. #ifdef SABERSENSE_BUTTON_CLICKER
  651. // Intended for Scavenger hilt where wheel makes tactile feel difficult.
  652. PlaySound("release.wav"); // Requires release.wav file to work.
  653. #endif
  654. if (SaberBase::Lockup()) {
  655. SaberBase::DoEndLockup();
  656. SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
  657. return true;
  658. } else {
  659. return false;
  660. }
  661.  
  662. case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ON):
  663. case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_ON):
  664. if (accel_.x < -0.15) {
  665. pointing_down_ = true;
  666. } else {
  667. pointing_down_ = false;
  668. }
  669. return true;
  670.  
  671.  
  672. // GESTURE CONTROLS
  673. #ifdef SABERSENSE_SWING_ON
  674. case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_OFF):
  675. // Due to motion chip startup on boot creating false ignition we delay Swing On at boot for 3000ms
  676. if (millis() > 3000) {
  677. FastOn();
  678. }
  679. return true;
  680. #endif
  681.  
  682. #ifdef SABERSENSE_TWIST_ON
  683. case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_OFF):
  684. // Delay twist events to prevent false trigger from over twisting
  685. if (millis() - last_twist_ > 2000 &&
  686. millis() - saber_off_time_ > 1000) {
  687. FastOn();
  688. last_twist_ = millis();
  689. }
  690. return true;
  691. #endif
  692.  
  693. #ifdef SABERSENSE_TWIST_OFF
  694. case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_ON):
  695. // Delay twist events to prevent false trigger from over twisting
  696. if (millis() - last_twist_ > 3000) {
  697. Off();
  698. last_twist_ = millis();
  699. saber_off_time_ = millis();
  700. }
  701. return true;
  702. #endif
  703.  
  704. #ifdef SABERSENSE_STAB_ON
  705. case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_OFF):
  706. if (millis() - saber_off_time_ > 1000) {
  707. FastOn();
  708. }
  709. return true;
  710. #endif
  711.  
  712. #ifdef SABERSENSE_THRUST_ON
  713. case EVENTID(BUTTON_NONE, EVENT_THRUST, MODE_OFF):
  714. if (millis() - saber_off_time_ > 1000) {
  715. FastOn();
  716. }
  717. return true;
  718. #endif
  719.  
  720.  
  721. // ACTIVATION
  722. // Saber ON AND Volume Adjust.
  723. case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_OFF):
  724. IgnoreClash(100); // Hopefully prevents false clashes due to 'clicky' button.
  725. // Low threshold so as not to conflict with 1-button volume menu access.
  726. if (!mode_volume_) {
  727. On();
  728. } else {
  729. if (fusor.angle1() > 0) {
  730. VolumeUp();
  731. } else {
  732. VolumeDown();
  733. }
  734. }
  735. return true;
  736.  
  737.  
  738. // 1 Button Activate Muted, forward one preset, back one preset.
  739. #if NUM_BUTTONS == 1
  740. case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_OFF):
  741. IgnoreClash(100); // Hopefully prevents false clashes due to 'clicky' button.
  742. // Low threshold so as not to conflict with 1-button volume menu access.
  743. #define DEGREES_TO_RADIANS (M_PI / 180)
  744. if (fusor.angle1() > 45 * DEGREES_TO_RADIANS) {
  745. // If pointing up
  746. next_preset();
  747. } else if (fusor.angle1() < -45 * DEGREES_TO_RADIANS) {
  748. // If pointing down
  749. previous_preset();
  750. } else {
  751. // If horizontal
  752. if (SetMute(true)) {
  753. unmute_on_deactivation_ = true;
  754. On();
  755. }
  756. }
  757. #ifdef SAVE_PRESET
  758. SaveState(current_preset_.preset_num);
  759. #endif
  760. return true;
  761. #endif
  762.  
  763.  
  764. // 2 Button Activate Muted
  765. #if NUM_BUTTONS == 2
  766. case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_OFF):
  767. if (SetMute(true)) {
  768. unmute_on_deactivation_ = true;
  769. On();
  770. }
  771. return true;
  772. #endif
  773.  
  774.  
  775. // Turn Blade OFF
  776. case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_MEDIUM, MODE_ON):
  777. if (!SaberBase::Lockup()) {
  778. #ifndef DISABLE_COLOR_CHANGE
  779. if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) {
  780. // Just exit color change mode.
  781. // Don't turn saber off.
  782. ToggleColorChangeMode();
  783. } else {
  784. Off();
  785. }
  786. }
  787. saber_off_time_ = millis();
  788. swing_blast_ = false;
  789. return true;
  790. #endif
  791.  
  792.  
  793. // FONT NAVIGATION
  794. // Multiple preset skips - only available with 2 button sabers.
  795. #if NUM_BUTTONS == 2
  796. // Skips forward five fonts if pointing up, skips back five fonts if pointing down.
  797. case EVENTID(BUTTON_AUX, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF):
  798. // backwards if pointing down
  799. SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -5 : 5), true);
  800. #ifdef SAVE_PRESET
  801. SaveState(current_preset_.preset_num);
  802. #endif
  803. return true;
  804.  
  805. // Skips forward ten fonts if pointing up, skips back ten fonts if pointing down.
  806. case EVENTID(BUTTON_AUX, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
  807. // backwards if pointing down
  808. SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -10 : 10), true);
  809. #ifdef SAVE_PRESET
  810. SaveState(current_preset_.preset_num);
  811. #endif
  812. return true;
  813. #endif
  814.  
  815.  
  816. // Skips to first preset (up) or last preset (down)
  817. // or middle preset if horizontal:
  818. #if NUM_BUTTONS == 2
  819. case EVENTID(BUTTON_AUX, EVENT_FIRST_HELD_LONG, MODE_OFF):
  820. #endif
  821. case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_LONG, MODE_OFF):
  822. #define DEGREES_TO_RADIANS (M_PI / 180)
  823. if (fusor.angle1() > 45 * DEGREES_TO_RADIANS) {
  824. // If pointing up
  825. SetPreset(0, true);
  826. } else if (fusor.angle1() < -45 * DEGREES_TO_RADIANS) {
  827. // If pointing down
  828. SetPreset(-1, true);
  829. } else {
  830. // If horizontal
  831. CurrentPreset tmp;
  832. tmp.SetPreset(-1);
  833. SetPreset(tmp.preset_num / 2, true);
  834. }
  835. #ifdef SAVE_PRESET
  836. SaveState(current_preset_.preset_num);
  837. #endif
  838. return true;
  839.  
  840.  
  841. // Modified 2 button 'next/previous preset' AND volume down,
  842. // to align with multiple skips above.
  843. // Forward one font pointing up, back one font pointing down.
  844. #if NUM_BUTTONS == 2
  845. case EVENTID(BUTTON_AUX, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_OFF):
  846. // backwards if pointing down
  847. if (!mode_volume_) {
  848. SetPreset(current_preset_.preset_num + (fusor.angle1() < -M_PI / 4 ? -1 : 1), true);
  849. } else {
  850. VolumeDown();
  851. }
  852. #ifdef SAVE_PRESET
  853. SaveState(current_preset_.preset_num);
  854. #endif
  855. return true;
  856. #endif
  857.  
  858.  
  859. // 2 button: Previous Preset, retained legacy control.
  860. #if NUM_BUTTONS == 2
  861. case EVENTID(BUTTON_POWER, EVENT_CLICK_SHORT, MODE_OFF | BUTTON_AUX):
  862. if (!mode_volume_) {
  863. previous_preset();
  864. }
  865. return true;
  866. #endif
  867.  
  868.  
  869. // BLADE ID OPTIONS
  870. // True Blade ID with bladeid audio idents.
  871. #ifdef SABERSENSE_BLADE_ID
  872. case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
  873. TriggerBladeID();
  874. return true;
  875. #endif
  876.  
  877.  
  878. // Manual Array Selector with array audio idents.
  879. // Cycles through blade arrays regardless of BladeID status.
  880. // Hilt pointing up cycles forward, pointing down cycles back (handled in main code).
  881. #ifdef SABERSENSE_ARRAY_SELECTOR
  882. case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
  883. NextBladeArray();
  884. return true;
  885. #endif
  886.  
  887.  
  888. // SOUND EFFECTS PLAYERS
  889. // Character Quote and Force Effect, Blade ON.
  890. // Hilt pointed UP for Character Quote, plays sequentially,
  891. // Hilt pointed DOWN for Force Effect, plays randomly.
  892. case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_ON):
  893. #ifndef SABERSENSE_FLIP_AUDIO_PLAYERS
  894. // Define reverses UP/DOWN options for QUOTE/FORCE/TRACK audio player.
  895. // Quote player points upwards.
  896. if (SFX_quote) {
  897. if (fusor.angle1() > 0) {
  898. SFX_quote.SelectNext();
  899. SaberBase::DoEffect(EFFECT_QUOTE, 0);
  900. } else {
  901. SaberBase::DoForce(); // Force effect for hilt pointed DOWN.
  902. }
  903. } else {
  904. SaberBase::DoForce(); // Fallback: play force effect if no quotes are available.
  905. }
  906. return true;
  907. #else
  908. // Quote player points downwards.
  909. if (SFX_quote) {
  910. if (fusor.angle1() < 0) {
  911. SFX_quote.SelectNext();
  912. SaberBase::DoEffect(EFFECT_QUOTE, 0);
  913. } else {
  914. SaberBase::DoForce(); // Force effect for hilt pointed DOWN.
  915. }
  916. } else {
  917. SaberBase::DoForce(); // Fallback: play force effect if no quotes are available.
  918. }
  919. return true;
  920. #endif
  921.  
  922.  
  923. // Character Quote and Music Track, Blade OFF.
  924. // Play sequential quote pointing up, play music track pointing down.
  925. case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF):
  926. #ifndef SABERSENSE_FLIP_AUDIO_PLAYERS
  927. // Define reverses UP/DOWN options for QUOTE/FORCE/TRACK audio players.
  928. // Quote player points upwards.
  929. if (SFX_quote) {
  930. if (fusor.angle1() > 0) {
  931. SFX_quote.SelectNext();
  932. SaberBase::DoEffect(EFFECT_QUOTE, 0);
  933. } else {
  934. StartOrStopTrack(); // Play track for hilt pointed DOWN.
  935. }
  936. } else {
  937. StartOrStopTrack(); // Fallback: play track if no quotes are available.
  938. }
  939. return true;
  940. #else
  941. // Quote player points downwards.
  942. if (SFX_quote) {
  943. if (fusor.angle1() < 0) {
  944. SFX_quote.SelectNext();
  945. SaberBase::DoEffect(EFFECT_QUOTE, 0);
  946. } else {
  947. StartOrStopTrack(); // Play track for hilt pointed DOWN.
  948. }
  949. } else {
  950. StartOrStopTrack(); // Fallback: play track if no quotes are available.
  951. }
  952. return true;
  953. #endif
  954.  
  955.  
  956. // BLASTER DEFLECTION
  957. #if NUM_BUTTONS == 1
  958. // 1 button
  959. case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
  960. swing_blast_ = false;
  961. SaberBase::DoBlast();
  962. return true;
  963. #endif
  964.  
  965. #if NUM_BUTTONS == 2
  966. // 2 button
  967. case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_ON):
  968. #ifdef SABERSENSE_BLAST_MAIN_AND_AUX
  969. case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
  970. #endif
  971. swing_blast_ = false;
  972. SaberBase::DoBlast();
  973. return true;
  974. #endif
  975.  
  976. // Multi-Blaster Deflection mode
  977. case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_ON | BUTTON_POWER):
  978. swing_blast_ = !swing_blast_;
  979. if (swing_blast_) {
  980. if (SFX_blstbgn) {
  981. hybrid_font.PlayCommon(&SFX_blstbgn);
  982. } else {
  983. hybrid_font.SB_Effect(EFFECT_BLAST, 0);
  984. }
  985. } else {
  986. if (SFX_blstend) {
  987. hybrid_font.PlayCommon(&SFX_blstend);
  988. } else {
  989. hybrid_font.SB_Effect(EFFECT_BLAST, 0);
  990. }
  991. }
  992. return true;
  993.  
  994. case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_ON):
  995. if (swing_blast_) {
  996. SaberBase::DoBlast();
  997. }
  998. return true;
  999.  
  1000.  
  1001. // LOCKUP
  1002. #if NUM_BUTTONS == 1
  1003. // 1 button lockup
  1004. case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_POWER):
  1005. #else
  1006. #ifndef SABERSENSE_NO_LOCKUP_HOLD
  1007. // 2 button lockup
  1008. case EVENTID(BUTTON_AUX, EVENT_FIRST_HELD, MODE_ON):
  1009. #else
  1010. case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_AUX):
  1011. #endif
  1012. #endif
  1013. if (accel_.x < -0.15) {
  1014. SaberBase::SetLockup(SaberBase::LOCKUP_DRAG);
  1015. } else {
  1016. SaberBase::SetLockup(SaberBase::LOCKUP_NORMAL);
  1017. }
  1018. swing_blast_ = false;
  1019. SaberBase::DoBeginLockup();
  1020. return true;
  1021. break;
  1022.  
  1023. // Lightning Block, 1 and 2 button.
  1024. case EVENTID(BUTTON_POWER, EVENT_SECOND_HELD, MODE_ON):
  1025. SaberBase::SetLockup(SaberBase::LOCKUP_LIGHTNING_BLOCK);
  1026. swing_blast_ = false;
  1027. SaberBase::DoBeginLockup();
  1028. return true;
  1029. break;
  1030.  
  1031. // Melt
  1032. case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_ON | BUTTON_POWER):
  1033. SaberBase::SetLockup(SaberBase::LOCKUP_MELT);
  1034. swing_blast_ = false;
  1035. SaberBase::DoBeginLockup();
  1036. return true;
  1037. break;
  1038.  
  1039. case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_OFF):
  1040. SaberBase::RequestMotion();
  1041. return true;
  1042.  
  1043.  
  1044. // ENTER VOLUME MENU
  1045. #if NUM_BUTTONS == 1
  1046. // 1 button
  1047. case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_OFF | BUTTON_POWER):
  1048. #else
  1049. // 2 button
  1050. case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_OFF | BUTTON_POWER):
  1051. #endif
  1052. if (!mode_volume_) {
  1053. mode_volume_ = true;
  1054. if (SFX_vmbegin) {
  1055. hybrid_font.PlayCommon(&SFX_vmbegin);
  1056. } else {
  1057. beeper.Beep(0.5, 3000);
  1058. }
  1059. STDOUT.println("Enter Volume Menu");
  1060. } else {
  1061. mode_volume_ = false;
  1062. if (SFX_vmend) {
  1063. hybrid_font.PlayCommon(&SFX_vmend);
  1064. } else {
  1065. beeper.Beep(0.5, 3000);
  1066. }
  1067. STDOUT.println("Exit Volume Menu");
  1068. }
  1069. return true;
  1070.  
  1071.  
  1072. // RESTORE FACTORY DEFAULTS
  1073. // Restores system to 'factory defaults' by deleting all
  1074. // save files in root and first level directories.
  1075. #ifdef SABERSENSE_ENABLE_RESET
  1076. case EVENTID(BUTTON_POWER, EVENT_FOURTH_HELD, MODE_OFF): {
  1077. // Lock the SD card to prevent other operations during deletion.
  1078. LOCK_SD(true);
  1079. const char* filesToDelete[] = {
  1080. "curstate.ini",
  1081. "curstate.tmp",
  1082. "preset.ini",
  1083. "preset.tmp",
  1084. "global.ini",
  1085. "global.tmp"
  1086. };
  1087. // Delete files from the root directory.
  1088. for (const char* targetFile : filesToDelete) {
  1089. if (LSFS::Exists(targetFile)) {
  1090. LSFS::Remove(targetFile);
  1091. Serial.print("Deleted from root: ");
  1092. Serial.println(targetFile);
  1093. }
  1094. }
  1095. // Find all immediate subdirectories of the root and delete files
  1096. LSFS::Iterator dirIterator("/"); // Iterator for the root directory
  1097. while (dirIterator) {
  1098. const char* subdirName = dirIterator.name();
  1099. if (dirIterator.isdir()) {
  1100. // Construct the full path to the subdirectory
  1101. PathHelper subdirPath("/");
  1102. subdirPath.Append(subdirName);
  1103. // Iterate over the files to delete in this subdirectory
  1104. for (const char* targetFile : filesToDelete) {
  1105. PathHelper filePath(subdirPath);
  1106. filePath.Append(targetFile);
  1107. // If the file exists in this subdirectory, delete it
  1108. if (LSFS::Exists(filePath)) {
  1109. LSFS::Remove(filePath);
  1110. Serial.print("Deleted from ");
  1111. Serial.print(subdirPath);
  1112. Serial.print(": ");
  1113. Serial.println(targetFile);
  1114. }
  1115. }
  1116. }
  1117. ++dirIterator; // Move to the next entry in the root directory.
  1118. }
  1119. // Unlock SD card after deletion is complete.
  1120. LOCK_SD(false);
  1121.  
  1122. if (SFX_reset) { // Optional confirmation sound file 'reset'.
  1123. hybrid_font.PlayCommon(&SFX_reset);
  1124. while(IsResetSoundPlaying()); // Wait for sound file to finish...
  1125. STM32.reset(); // ...then reboot saber.
  1126. } else {
  1127. STM32.reset(); // Immediate reboot if 'reset' sound file is missing.
  1128. }
  1129. break;
  1130. }
  1131. #endif
  1132.  
  1133.  
  1134. // BATTERY LEVEL
  1135. case EVENTID(BUTTON_POWER, EVENT_SECOND_HELD_MEDIUM, MODE_OFF):
  1136. talkie.SayDigit((int)floorf(battery_monitor.battery()));
  1137. talkie.Say(spPOINT);
  1138. talkie.SayDigit(((int)floorf(battery_monitor.battery() * 10)) % 10);
  1139. talkie.SayDigit(((int)floorf(battery_monitor.battery() * 100)) % 10);
  1140. talkie.Say(spVOLTS);
  1141. SaberBase::DoEffect(EFFECT_BATTERY_LEVEL, 0);
  1142. return true;
  1143.  
  1144.  
  1145. #ifdef BLADE_DETECT_PIN
  1146. case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_ON):
  1147. case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_OFF):
  1148. // Might need to do something cleaner, but let's try this for now.
  1149. blade_detected_ = true;
  1150. FindBladeAgain();
  1151. SaberBase::DoBladeDetect(true);
  1152. return true;
  1153.  
  1154. case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_ON):
  1155. case EVENTID(BUTTON_BLADE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_OFF):
  1156. // Might need to do something cleaner, but let's try this for now.
  1157. blade_detected_ = false;
  1158. FindBladeAgain();
  1159. SaberBase::DoBladeDetect(false);
  1160. return true;
  1161. #endif
  1162.  
  1163.  
  1164. // Events that needs to be handled regardless of what other buttons are pressed.
  1165. case EVENTID(BUTTON_AUX2, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
  1166. if (SaberBase::Lockup()) {
  1167. SaberBase::DoEndLockup();
  1168. SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
  1169. return true;
  1170. }
  1171. }
  1172. return false;
  1173. }
  1174.  
  1175. #ifdef SABERSENSE_OS7_LEGACY_SUPPORT
  1176. void SB_Effect(EffectType effect, float location) override { // Required for ProffieOS 7.x.
  1177. switch (effect) {
  1178. case EFFECT_QUOTE: hybrid_font.PlayCommon(&SFX_quote); return;
  1179. #else
  1180. void SB_Effect(EffectType effect, EffectLocation location) override { // Required for ProffieOS 8.x.
  1181. switch (effect) {
  1182. #endif
  1183. case EFFECT_POWERSAVE:
  1184. if (SFX_dim) {
  1185. hybrid_font.PlayCommon(&SFX_dim);
  1186. } else {
  1187. beeper.Beep(0.5, 3000);
  1188. }
  1189. return;
  1190. case EFFECT_BATTERY_LEVEL:
  1191. if (SFX_battery) {
  1192. hybrid_font.PlayCommon(&SFX_battery);
  1193. } else {
  1194. beeper.Beep(0.5, 3000);
  1195. }
  1196. return;
  1197. case EFFECT_FAST_ON:
  1198. if (SFX_faston) {
  1199. hybrid_font.PlayCommon(&SFX_faston);
  1200. }
  1201. return;
  1202.  
  1203. default: break; // avoids compiler warning
  1204. }
  1205. }
  1206.  
  1207.  
  1208. private:
  1209. bool pointing_down_ = false;
  1210. bool swing_blast_ = false;
  1211. bool mode_volume_ = false;
  1212. bool auto_lockup_on_ = false;
  1213. bool auto_melt_on_ = false;
  1214. bool max_vol_reached_ = false;
  1215. bool min_vol_reached_ = false;
  1216. uint32_t thrust_begin_millis_ = millis();
  1217. uint32_t push_begin_millis_ = millis();
  1218. uint32_t clash_impact_millis_ = millis();
  1219. uint32_t last_twist_ = millis();
  1220. uint32_t last_push_ = millis();
  1221. uint32_t saber_off_time_ = millis();
  1222. };
  1223.  
  1224. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement