Advertisement
Sabersense

Sabersense Prop WiP

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