-
Notifications
You must be signed in to change notification settings - Fork 75
/
saber_BC_buttons.h
1031 lines (967 loc) · 37 KB
/
saber_BC_buttons.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
saber_BC_buttons.h
http://fredrik.hubbe.net/lightsaber/proffieos.html
Copyright (c) 2016-2019 Fredrik Hubinette
Copyright (c) 2021 Brian Conner with contributions by:
Fredrik Hubinette, Fernando DeRosa, and Matthew McGeary.
Distributed under the terms of the GNU General Public License v3.
http://www.gnu.org/licenses/
Includes 1 and 2 button controls.
Incorporates an intuitive control scheme so button actions are consistant
whether blade is on or off.
Includes:
sa22c's multi-blast, Battle Mode and gesture ignitions from fett263,
enhanced sa22c's on-the-fly volume controls with custom prompts and sounds
via the following wav files:
vmbegin.wav
vmend.wav
volchangedown.wav
volchangeup.wav
volmax.wav
volmin.wav
To use a female voice version of the battery level spoken digits, use:
#define FEMALE_TALKIE_VOICE
EFFECT_USER1 - use as a standalone trigger for EffectSequence<>,
- ie:EffectSequence<EFFECT_USER1, item1, item2...>
- Custom swap.wav files can be used as a sound effect,
otherwise ccchange.wavs get used.
EFFECT_USER2 - for blade effects with sounds that might work better without hum
(think seismic charge silence, iceblade etc...)
- monosfx.wav files are used. It can be just the sound, or a
blade effect too by using EFFECT_USER2 in a TransitionEffectL.
Added quote sound so force.wavs can remain as force.
-Add quote.wav files to font to use.
Added Play / Stop track control while blade is on.
Added Prev/Next preset control while blade is on.
Force Push is always available, not just in Battle Mode.
Melt is always available as no button, with pull-away or button to end
Drag is always clash with button pressed while pointing down.
Optional #defines:
#define ENABLE_AUTO_SWING_BLAST - Multi-blast initiated by simply swinging
within 1 second of last blast.
Exit by not swinging for 1 second.
#define VOLUME_MENU_CYCLE - This allows the Volume menu to loop through from
maximum back to minimum and vice versa.
On-Demand battery level - A layer built into the blade styles.
- This example style reacts as the battery gets weaker by pulsing quicker,
the blade length shortens, and color changes from Green to Red:
AlphaL<TransitionEffectL<TrConcat<TrSmoothFade<500>,AlphaL<PulsingX<Mix<
BatteryLevel,Red,Green>,Black,Scale<BatteryLevel,Int<200>,Int<4000>>>,
SmoothStep<Scale<BatteryLevel,Int<0>,Int<35000>>,Int<-1>>>,
TrSmoothFade<2000>>,EFFECT_BATTERY_LEVEL>,Ifon<Int<0>,Int<32768>>>
------------------------------------------------------------------------------
Gesture Controls:
There are four gesture types: swing, stab, thrust and twist.
For simplicity, using gesture ignition will automatically skip the preon effect.
Below are the options to add to the config to enable the various gestures:
#define BC_SWING_ON
#define BC_STAB_ON
#define BC_THRUST_ON
#define BC_TWIST_ON
#define BC_TWIST_OFF
Force Push:
This mode plays a force sound (or force push sound if the font contains it) with
a controlled pushing gesture, and is always available, not just in Battle Mode.
To enable this feature, add this define:
#define BC_FORCE_PUSH
#define BC_FORCE_PUSH_LENGTH
Used for adjustment to the Push gesture length in millis needed to trigger
Force Push. Recommended range 1 ~ 10,
1 = shortest, easiest to trigger, 10 = longest. Default value is 5.
If you want the gesture ignition to ALSO enter battle mode automatically
on ignition, add this define:
#define BC_GESTURE_AUTO_BATTLE_MODE
Battle mode by fett263, BC modified version:
Once you enter battle mode, buttons are not used for lockup.
Clashing the blade against something will automatically do lockup and then end
when you pull away.
Automatic lockup and grazing clash (swinging through) detection works
by measuring delay of the saber blade pulling back from the clash.
If you clash the blade and it does not pull back during the delay period,
it is assumed to be a lockup and the lockup effect will show on the blade.
If you clash the blade and pull away, only the bgn/end lockup effects will show.
You can adjust the threshold of this detection by using
#define BC_LOCKUP_DELAY (insert number here)
Default value is 200.
If you don't rebound off the object (opponent's blade) but instead clash while
swinging through, clash will automatically trigger.
To manually override the auto-lockup temporarily and get a regular clash,
hold any button while clashing.
Automatic clash/lockup uses the pre and post lockup effects
so your blade style and font MUST have those capabilities to support
battle mode.
Melt will automatically trigger with no buttons when you physically
stab something, and end when you pull away or push any button.
Stab will trigger either with no buttons and thrusting forward,
or with any button and physically stabbing something.
Tightened click timings.
The timeouts for short and double click detection are shortened
from the stock 500ms to 300ms to feel more responsive but still give enough
timeout to ensure all button actions can be achieved consistently.
All button timings are included below so they can be easily tweaked to suit
individual tastes.
====================== 1 BUTTON CONTROLS ========================
| Sorted by ON or OFF state: (what it's like while using saber) |
=================================================================
************* WHILE SABER BLADE IS OFF ***************
Play/Stop Track - 4x click POW
Next Preset - Long click and release POW
Prev Preset - Double click and hold POW, release after a second
(click then long click)
Volume Menu:
Enter/Exit - Hold POW + Clash
Volume UP - Long click and release POW while in Volume Menu
Volume DOWN - Double click and hold POW while in Volume Menu
Spoken Battery Level - Triple click POW
On-Demand Batt Level - Double click POW
(requires EFFECT_BATTERY_LEVEL to be in blade style)
Turn blade ON - Short click POW (or gestures if defined)
Turn blade ON Muted - Triple click and hold POW
************* WHILE SABER BLADE IS ON ****************
Play/Stop Track - 4x click POW
Next Preset - Long click and release POW while pointing up
Prev Preset - Double click and release POW after a second
(click then long click) while pointing up
Clash - No buttons, just hit the blade against something
- In Battle Mode, Hold POW and Clash to temporarily
override the auto-lockup and do regular Clash.
Stab - Either no button and just Thrust forward,
or Hold any button and physically stab something.
- works in Battle Mode!
Blaster Blocks - Click or Double click POW
Multi-Blast mode - sa22c mode
- To enter, hold POW then release while swinging
- To trigger Blaster Block, swing saber while in
Multi-Blast mode
- To exit, hold AUX then release while swinging
Auto Swing Blast - Timed. To use, #define AUTO_SWING_BLAST
- To enter, swing within 1 second of doing
button activated Blaster Block
- To trigger auto blaster blocks, swing saber
within 1 second of last Swing Blast block
- To exit, stop swinging for 1 second
Lockup - Hold POW + Clash
- in Battle Mode, just Clash and stay there,
pull away or press POW to end lockup.
Drag - Hold POW + Clash while pointing down
- in Battle Mode also
Melt - No button, just stab something. pull away or
press POW to end.
- in Battle Mode also
Lightning Block - Double click and hold POW
Battle Mode - Triple click and hold POW to enter and exit.
Power OFF disabled, YOU MUST EXIT WITH THIS COMBO.
Force Effect - Hold POW + Twist (while NOT pointing up or down)
Monophonic Force - Hold POW + Twist (while pointing up)
Color Change Mode - Hold POW + Twist the hilt (while pointing down),
- Rotate hilt to cycle through all available colors, or
- click POW to change if ColorChange<> used in blade style,
- click + hold POW to save color selection and exit.
- Triple click POW to exit without changing color.
ColorChange explained:
If the style uses ColorChange<>, when you activate color change mode,
there will be up to 12 steps per rotation with a little sound at each step.
If it does not use ColorChange<>, the color wheel will be activated,
which has 32768 steps per rotation.
COLOR_CHANGE_DIRECT makes it so that IF the style uses ColorChange<>,
when you activate color change mode, it will immediately go to the
next color and exit color change mode. If the style does not use
ColorChange<>, it has no effect.
Quote Player - Triple click POW
Force Push - Push hilt perpendicularly from a stop.
Swap (EffectSequence) - 4x click and hold POW medium (while NOT pointing up)
Power Save Dim Blade - 4x click and hold POW medium (while pointing up)
(To use Power Save requires AlphaL based EffectSequence in style)
Turn off blade - Hold and wait until blade is off
or use #define BC_TWIST_OFF gesture
====================== 2 BUTTON CONTROLS ========================
| Sorted by ON or OFF state: (what it's like while using saber) |
=================================================================
************* WHILE SABER BLADE IS OFF ***************
Play/Stop Track - Hold AUX + Double click POW
Next Preset - Long click and release POW
Prev Preset - Double click and hold POW, release after a second
(click then long click)
Volume Menu:
Enter/Exit - Long click and release AUX
Volume UP - Long click and release POW while in Volume Menu
Volume DOWN - Double click and hold POW, release after a second
(click then long click) while in Volume Menu
Spoken Battery Level - Hold AUX until it talks
On-Demand Batt Level - Double click POW
(requires EFFECT_BATTERY_LEVEL to be in blade style)
Activate - Short click POW (or gestures if defined)
Activate Muted - Triple click and hold POW
************* WHILE SABER BLADE IS ON ****************
Play/Stop Track - Hold AUX + Double click POW
Next Preset - Hold AUX + Long click and release POW while pointing up
Prev Preset - Hold AUX + Double click and hold POW for a second
(click then long click) while pointing up
Clash - No buttons, just hit the blade against something
- In Battle Mode, Hold any button and Clash to
temporarily override the auto-lockup and do regular Clash
Stab - Either no button and just Thrust forward, or
Hold any button and physically stab something.
- works in Battle Mode!
Blaster Blocks - Click or Double click POW
Multi-Blast mode - sa22c's version
- To enter, hold POW then release while swinging
- To trigger Blaster Block, swing saber while in
Multi-Blast mode
- To exit, hold AUX then release while swinging
Auto Swing Blast - Timed. To use, #define AUTO_SWING_BLAST
- To enter, swing within 1 second of doing
button activated Blaster Block
- To trigger auto blaster blocks, swing saber
within 1 second of last Swing Blast block
- To exit, stop swinging for 1 second
Lockup - Hold AUX + Clash
- in Battle Mode, just Clash and stay there,
pull away or press any button to end lockup.
Drag - Hold AUX + Clash while pointing down
- in Battle Mode also
Melt - No button, just stab something,
pull away or press any button to end
- in Battle Mode also
Lightning Block - Double click and hold POW
Battle Mode - Hold POW + Click AUX -
Power OFF disabled, YOU MUST EXIT WITH THIS COMBO
Force Effect - Hold POW + Twist (while NOT pointing up or down)
Monophonic Force - Hold POW + Twist (while pointing up)
Color Change Mode - Hold POW + Twist the hilt (while pointing down),
- Rotate hilt to cycle through all available colors, or
- click AUX to change if ColorChange<> used in blade style,
- click + hold POW to save color selection and exit
- Triple click POW to exit without changing color
ColorChange explained:
If the style uses ColorChange<>, when you activate color change mode,
there will be up to 12 steps per rotation with a little sound at each step.
If it does not use ColorChange<>, the color wheel will be activated,
which has 32768 steps per rotation.
COLOR_CHANGE_DIRECT makes it so that IF the style uses ColorChange<>,
when you activate color change mode, it will immediately go to the
next color and exit color change mode. If the style does not use
ColorChange<>, it has no effect.
Quote Player - Triple click POW
Force Push - Push hilt perpendicularly from a stop.
Swap (EffectSequence) - Hold AUX + Twist (while NOT pointing up)
Power Save Dim Blade - Hold AUX + Twist (while pointing up)
(To use Power Save requires AlphaL based
EffectSequence in blade style)
Turn off blade - Hold POW and wait until blade is off
or use #define BC_TWIST_OFF gesture
*/
#ifndef PROPS_SABER_BC_BUTTONS_H
#define PROPS_SABER_BC_BUTTONS_H
#include "prop_base.h"
#include "../sound/hybrid_font.h"
#undef PROP_TYPE
#define PROP_TYPE SaberBCButtons
#ifndef MOTION_TIMEOUT
#define MOTION_TIMEOUT 60 * 15 * 1000
#endif
#ifndef BC_SWING_ON_SPEED
#define BC_SWING_ON_SPEED 250
#endif
#ifndef BC_LOCKUP_DELAY
#define BC_LOCKUP_DELAY 200
#endif
#ifndef BC_FORCE_PUSH_LENGTH
#define BC_FORCE_PUSH_LENGTH 4
#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 1500
#endif
#ifndef BUTTON_HELD_LONG_TIMEOUT
#define BUTTON_HELD_LONG_TIMEOUT 2000
#endif
#ifdef BC_SWING_ON
#define SWING_GESTURE
#endif
#ifdef BC_STAB_ON
#define STAB_GESTURE
#endif
#ifdef BC_TWIST_ON
#define TWIST_GESTURE
#endif
#ifdef BC_THRUST_ON
#define THRUST_GESTURE
#endif
EFFECT(dim); // for EFFECT_POWERSAVE
EFFECT(battery); // for EFFECT_BATTERY_LEVEL
EFFECT(bmbegin); // for Begin Battle Mode
EFFECT(bmend); // for End Battle Mode
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
EFFECT(push); // for Force Push gesture
EFFECT(quote); // for playing quotes
EFFECT(monosfx); // for Monophonically played sounds (iceblade, seismic charge etc...)
EFFECT(swap); // for standalone triggering EffectSequence<>
EFFECT(battlevel); // for Spoken Battery Level
EFFECT(point); // for Spoken Battery Level
EFFECT(volts); // for Spoken Battery Level
// The Saber class implements the basic states and actions
// for the saber.
class SaberBCButtons : public PropBase {
public:
SaberBCButtons() : PropBase() {}
const char* name() override { return "SaberBCButtons"; }
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_ > BC_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_ > BC_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_ > BC_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() > BC_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();
}
}
// Revert colorchange witout saving (reset to Variation == 0)
void ResetColorChangeMode() {
if (!current_style()) return;
STDOUT << "Reset Color Variation" << "\n";
SetVariation(0);
STDOUT << "Color change mode done, variation = " << SaberBase::GetCurrentVariation() << "\n";
SaberBase::SetColorChangeMode(SaberBase::COLOR_CHANGE_MODE_NONE);
}
// Fast On Gesture Ignition
virtual void FastOn() {
if (IsOn()) return;
if (current_style() && current_style()->NoOnOff())
return;
activated_ = millis();
STDOUT.println("Ignition.");
MountSDCard();
EnableAmplifier();
SaberBase::RequestMotion();
// Avoid clashes a little bit while turning on.
// It might be a "clicky" power button...
IgnoreClash(500);
SaberBase::TurnOn();
// Optional effects
SaberBase::DoEffect(EFFECT_FAST_ON, 0);
}
// SA22C Volume Menu
void VolumeUp() {
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 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 \n");
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 \n");
max_vol_reached_ = false;
}
#else
if (SFX_volmax) {
hybrid_font.PlayCommon(&SFX_volmax);
} else {
beeper.Beep(0.5, 3000);
}
STDOUT.print("Maximum Volume \n");
#endif
}
}
void VolumeDown() {
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 \n");
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 \n");
min_vol_reached_ = false;
}
#else
if (SFX_volmin) {
hybrid_font.PlayCommon(&SFX_volmin);
} else {
beeper.Beep(0.5, 1000);
}
STDOUT.print("Minimum Volume \n");
#endif
}
}
bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override {
switch (EVENTID(button, event, modifiers)) {
case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ON):
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 Ignition Controls
#ifdef BC_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();
#ifdef BC_GESTURE_AUTO_BATTLE_MODE
STDOUT.println("Entering Battle Mode");
battle_mode_ = true;
#endif
}
return true;
#endif // BC_SWING_ON
#ifdef BC_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();
#ifdef BC_GESTURE_AUTO_BATTLE_MODE
STDOUT.println("Entering Battle Mode");
battle_mode_ = true;
#endif
last_twist_ = millis();
}
return true;
#endif // BC_TWIST_ON
#ifdef BC_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();
battle_mode_ = false;
}
return true;
#endif // BC_TWIST_OFF
#ifdef BC_STAB_ON
case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_OFF):
// Delay Stab On at boot
if (millis() - saber_off_time_ > 1000) {
FastOn();
#ifdef BC_GESTURE_AUTO_BATTLE_MODE
STDOUT.println("Entering Battle Mode");
battle_mode_ = true;
#endif
}
return true;
#endif // BC_STAB_ON
#ifdef BC_THRUST_ON
case EVENTID(BUTTON_NONE, EVENT_THRUST, MODE_OFF):
// Delay Thrust On at boot
if (millis() - saber_off_time_ > 1000) {
FastOn();
#ifdef BC_GESTURE_AUTO_BATTLE_MODE
STDOUT.println("Entering Battle Mode");
battle_mode_ = true;
#endif
}
return true;
#endif // BC_THRUST_ON
#ifdef BC_FORCE_PUSH
case EVENTID(BUTTON_NONE, EVENT_PUSH, MODE_ON):
// Delay Force Push from previous Push
if (millis() - last_push_ > 2000) {
if (SFX_push) {
hybrid_font.PlayCommon(&SFX_push);
} else {
hybrid_font.DoEffect(EFFECT_FORCE, 0);
}
last_push_ = millis();
}
return true;
#endif // BC_FORCE_PUSH
// Start or Stop Track
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_FOURTH_SAVED_CLICK_SHORT, MODE_OFF):
case EVENTID(BUTTON_POWER, EVENT_FOURTH_SAVED_CLICK_SHORT, MODE_ON):
#else
// 2 or 3 button
case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_ON | BUTTON_AUX):
case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF | BUTTON_AUX):
#endif
if (!mode_volume_) {
StartOrStopTrack();
}
return true;
// Next Preset AND Volume Up
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_ON):
#else
// 2 button
case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_ON | BUTTON_AUX):
#endif
if (fusor.angle1() > M_PI / 3) {
//Don't change preset if in colorchange mode
if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) return false;
next_preset();
}
return true;
case EVENTID(BUTTON_POWER, EVENT_FIRST_CLICK_LONG, MODE_OFF):
if (!mode_volume_) {
next_preset();
} else {
VolumeUp();
}
return true;
// Previous Preset AND Volume Down
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_SECOND_CLICK_LONG, MODE_ON):
#else
// 2 button
case EVENTID(BUTTON_POWER, EVENT_SECOND_CLICK_LONG, MODE_ON | BUTTON_AUX):
#endif
if (fusor.angle1() > M_PI / 3) {
//Don't change preset if in colorchange mode
if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) return false;
previous_preset();
}
return true;
case EVENTID(BUTTON_POWER, EVENT_SECOND_CLICK_LONG, MODE_OFF):
if (!mode_volume_) {
previous_preset();
} else {
VolumeDown();
}
return true;
// Enter / Exit Volume MENU
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_OFF | BUTTON_POWER):
#else
// 2 button
case EVENTID(BUTTON_AUX, EVENT_FIRST_CLICK_LONG, MODE_OFF):
#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;
// Spoken Battery Level
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
#else
// 2 and 3 button
case EVENTID(BUTTON_AUX, EVENT_FIRST_HELD_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);
return true;
// On Demand Battery Level
case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_OFF):
if (!mode_volume_) {
SaberBase::DoEffect(EFFECT_BATTERY_LEVEL, 0);
}
return true;
// Turns Saber ON
case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_OFF):
// No power on without exiting Vol Menu first
if (!mode_volume_) {
On();
}
return true;
// Activate Muted
case EVENTID(BUTTON_POWER, EVENT_THIRD_HELD, MODE_OFF):
if (!mode_volume_) {
if (SetMute(true)) {
unmute_on_deactivation_ = true;
On();
}
}
return true;
// Stab
case EVENTID(BUTTON_NONE, EVENT_THRUST, MODE_ON):
SaberBase::DoStab();
return true;
// Blaster Deflection
// original sa22c mode if ENABLE_AUTO_SWING_BLAST is not defined
#ifndef ENABLE_AUTO_SWING_BLAST
case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_ON):
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);
STDOUT.println("Entering Swing Blast mode");
} else {
hybrid_font.SB_Effect(EFFECT_BLAST, 0);
}
} else {
if (SFX_blstend) {
hybrid_font.PlayCommon(&SFX_blstend);
STDOUT.println("Exiting Swing Blast mode");
} 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;
#else
// AUTO_SWING_BLAST if swing within 1 second
case EVENTID(BUTTON_POWER, EVENT_FIRST_SAVED_CLICK_SHORT, MODE_ON):
case EVENTID(BUTTON_POWER, EVENT_SECOND_SAVED_CLICK_SHORT, MODE_ON):
//Don't blast if in colorchange mode
if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) return false;
SaberBase::DoBlast();
last_blast_ = millis();
return true;
case EVENTID(BUTTON_NONE, EVENT_SWING, MODE_ON):
if (millis() - last_blast_ < 1000) {
SaberBase::DoBlast();
last_blast_ = millis();
STDOUT.println("Auto Swing Blast mode");
}
break;
#endif // ENABLE_AUTO_SWING_BLAST
// Lockup
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_POWER):
#else
// 2 button
case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON | BUTTON_AUX):
#endif
if (!SaberBase::Lockup()) {
if (pointing_down_) {
SaberBase::SetLockup(SaberBase::LOCKUP_DRAG);
} else {
if (!battle_mode_) {
SaberBase::SetLockup(SaberBase::LOCKUP_NORMAL);
} else {
break; // Overrides Auto-lockup if holding Button during clash, NOT pointing down
}
}
swing_blast_ = false;
SaberBase::DoBeginLockup();
return true;
}
break;
// Melt
case EVENTID(BUTTON_NONE, EVENT_STAB, MODE_ON):
clash_impact_millis_ = millis();
swing_blast_ = false;
if (!swinging_) {
SaberBase::SetLockup(SaberBase::LOCKUP_MELT);
auto_melt_on_ = true;
SaberBase::DoBeginLockup();
}
return true;
// Lightning Block
case EVENTID(BUTTON_POWER, EVENT_SECOND_HELD_MEDIUM, MODE_ON):
SaberBase::SetLockup(SaberBase::LOCKUP_LIGHTNING_BLOCK);
swing_blast_ = false;
SaberBase::DoBeginLockup();
return true;
// Battle Mode
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_THIRD_HELD, MODE_ON):
#else
// 2 button
case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_ON | BUTTON_POWER):
#endif
if (!battle_mode_) {
STDOUT.println("Entering Battle Mode");
battle_mode_ = true;
if (SFX_bmbegin) {
hybrid_font.PlayCommon(&SFX_bmbegin);
STDOUT.println("-----------------playing bmbegin.wav");
} else {
hybrid_font.DoEffect(EFFECT_FORCE, 0);
STDOUT.println("-----------------playing forcexx.wav");
}
} else {
STDOUT.println("Exiting Battle Mode");
battle_mode_ = false;
if (SFX_bmend) {
hybrid_font.PlayCommon(&SFX_bmend);
STDOUT.println("-----------------playing bmend.wav");
} else {
beeper.Beep(0.5, 3000);
}
}
return true;
// Auto Lockup Mode
case EVENTID(BUTTON_NONE, EVENT_CLASH, MODE_ON):
if (!battle_mode_) return false;
clash_impact_millis_ = millis();
swing_blast_ = false;
if (swinging_) return false;
SaberBase::SetLockup(SaberBase::LOCKUP_NORMAL);
auto_lockup_on_ = true;
SaberBase::DoBeginLockup();
return true;
// Color Change - pointing up
// MonoForce - pointing down
// Force - NOT pointing up or down
case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_ON | BUTTON_POWER):
if (fusor.angle1() < - M_PI / 4) { // pointing down
ToggleColorChangeMode();
return true;
}
if (fusor.angle1() > M_PI / 3) { // pointing up
hybrid_font.DoEffect(EFFECT_USER2, 0);
} else {
SaberBase::DoForce(); // NOT pointing up or down
}
return true;
// Quote
// Revert colorchange witout saving (reset to Variation == 0)
case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_ON):
if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) {
ResetColorChangeMode();
return true;
} else {
hybrid_font.PlayCommon(&SFX_quote);
}
return true;
// Power Save blade dimming - pointing up
// Swap effect - NOT pointing up
#if NUM_BUTTONS == 1
case EVENTID(BUTTON_POWER, EVENT_FOURTH_HELD_MEDIUM, MODE_ON):
#else
case EVENTID(BUTTON_NONE, EVENT_TWIST, MODE_ON | BUTTON_AUX):
#endif
if (fusor.angle1() > M_PI / 3) { // pointing up
SaberBase::DoEffect(EFFECT_POWERSAVE, 0);
return true;
} else {
hybrid_font.DoEffect(EFFECT_USER1, 0);
}
return true;
// Turn Blade OFF
case EVENTID(BUTTON_POWER, EVENT_FIRST_HELD_MEDIUM, MODE_ON):
if (!SaberBase::Lockup()) {
if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) {
// Just exit color change mode.
// Don't turn saber off.
ToggleColorChangeMode();
return true;
}
if (!battle_mode_) {
Off();
}
}
saber_off_time_ = millis();
swing_blast_ = false;
return true;
// Blade Detect
#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_POWER, EVENT_PRESSED, MODE_OFF):
case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_OFF):
case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_OFF):
SaberBase::RequestMotion();
return true;
case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
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;
}
void SB_Effect(EffectType effect, float location) override {
switch (effect) {
case EFFECT_POWERSAVE: // Dim
if (SFX_dim) {
hybrid_font.PlayCommon(&SFX_dim);
} else {
beeper.Beep(0.5, 3000);
}
return;
case EFFECT_BATTERY_LEVEL: // On-Demand Battery Level
if (SFX_battery) {
hybrid_font.PlayCommon(&SFX_battery);
} else {
beeper.Beep(0.5, 3000);
}
return;
case EFFECT_FAST_ON: // Gesture on, bybass preon
if (SFX_faston) {
hybrid_font.PlayCommon(&SFX_faston);
}
return;
case EFFECT_USER1: // Swap
if (SFX_swap) {
hybrid_font.PlayCommon(&SFX_swap);
} else {
hybrid_font.PlayCommon(&SFX_ccchange);