-
Notifications
You must be signed in to change notification settings - Fork 10
/
PinMameExceptions.ino
1492 lines (1446 loc) · 102 KB
/
PinMameExceptions.ino
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
#define SoundCommandCh1 0
#define SoundCommandCh2 1
#define SwitchActCommand 2
#define SwitchRelCommand 3
#define SolenoidActCommand 4
#define SolenoidRelCommand 5
#define LampOnCommand 6
#define LampOffCommand 7
#define WriteToDisplay0 8
#define WriteToDisplay1 9
#define WriteToDisplay2 10
#define WriteToDisplay3 11
#define WriteToDisplay4 12
#define USB_BallSave 5 // optional ball saver
#define USB_BallSaveTime 6 // activation time for the optional ball saver
#define USB_BGmusic 7 // to select an own BG music
#define SwOuthole 0 // number of the outhole switch
#define SwTrunk1 1 // number of the 1st trunk switch (active if one ball is in the trunk) - set to 0 if machine has only one ball (-> no trunk)
#define SwTrunk2 2 // number of the 2nd trunk switch (active if a second ball is in the trunk)
#define SwTrunk3 3 // number of the 3rd trunk switch (active if a third ball is in the trunk) - set to 0 if machine has only two balls
#define SwTrunk4 4 // number of the 4th trunk switch (active if a fourth ball is in the trunk) - set to 0 if machine has only three balls
#define SwLeftOutlane 5 // number of the left outlane switch
#define SwRightOutlane 6 // number of the right outlane switch
#define SolACrelay 7 // number of the AC relay solenoid (set to 0 if machine has no AC relay)
#define SolLeftKickback 8 // number of the left kickback solenoid (set to 0 if machine has no left kickback)
#define SolRightKickback 9 // number of the right kickback solenoid (set to 0 if machine has no right kickback)
#define SolOuthole 10 // number of the outhole kicker solenoid
#define SolShooterLn 11 // number of the shooter lane feeder solenoid (set to 0 if machine has no shooter lane feeder (only one ball)
#define LampExBall 12 // number of the extra ball lamp (on the playfield) which is supposed to blink when ball saver is active
const byte EX_SpaceStationProperties[13] = { // machine properties for ball saver
10, // number of the outhole switch
11, // number of the 1st trunk switch (active if one ball is in the trunk) - set to 0 if machine has only one ball (-> no trunk)
12, // number of the 2nd trunk switch (active if a second ball is in the trunk)
13, // number of the 3rd trunk switch (active if a third ball is in the trunk) - set to 0 if machine has only two balls
0, // number of the 4th trunk switch (active if a fourth ball is in the trunk) - set to 0 if machine has only three balls
17, // number of the left outlane switch
32, // number of the right outlane switch
12, // number of the AC relay solenoid (set to 0 if machine has no AC relay)
13, // number of the left kickback solenoid (set to 0 if machine has no left kickback)
0, // number of the right kickback solenoid (set to 0 if machine has no right kickback)
1, // number of the outhole kicker solenoid
2, // number of the shooter lane feeder solenoid (set to 0 if machine has no shooter lane feeder (only one ball)
42}; // number of the extra ball lamp (on the playfield) which is supposed to blink when ball saver is active
const byte EX_AlienPokerProperties[13] = {
9, 0, 0, 0, 0, 11, 32, 0, 0, 0, 1, 0, 1};
const byte EX_BarracoraProperties[13] = {
12, 15, 14, 13, 0, 23, 24, 0, 0, 0, 11, 12, 26};
const byte EX_BlackKnightProperties[13] = {
20, 17, 18, 19, 0, 11, 12, 0, 0, 0, 1, 6, 47};
const byte EX_CometProperties[13] = {
45, 0, 0, 0, 0, 32, 31, 0, 0, 0, 1, 0, 60};
const byte EX_DiscoFeverProperties[13] = {
22, 0, 0, 0, 0, 25, 19, 0, 0, 0, 1, 0, 33};
const byte EX_FirepowerProperties[13] = {
9, 57, 58, 51, 0, 10, 44, 0, 7, 0, 1, 8, 1};
const byte EX_FlashProperties[13] = {
48, 0, 0, 0, 0, 43, 46, 0, 0, 0, 1, 0, 16};
const byte EX_F14Properties[13] = {
10, 11, 12, 13, 14, 61, 62, 14, 13, 0, 1, 2, 16};
const byte EX_HighSpeedProperties[13] = {
9, 12, 11, 10, 0, 31, 32, 0, 14, 0, 1, 2, 3};
const byte EX_JungleLordProperties[13] = {
42, 43, 9, 10, 0, 22, 23, 0, 0, 0, 1, 2, 27};
const byte EX_PharaohProperties[13] = {
36, 39, 38, 0, 0, 15, 16, 0, 0, 0, 1, 2, 8};
const byte EX_PinbotProperties[13] = {
16, 17, 18, 0, 0, 12, 15, 14, 0, 0, 1, 2, 33};
const byte EX_RollerGamesProperties[13] = {
9, 13, 12, 11, 0, 40, 19, 12, 20, 0, 1, 2, 21};
const byte EX_TimeWarpProperties[13] = {
9, 0, 0, 0, 0, 40, 39, 0, 0, 0, 1, 0, 38};
const byte *EX_Machine; // machine specific settings (optional)
byte USB_SerialBuffer[128]; // received command arguments
char USB_RepeatSound[13]; // name of the sound file to be repeated
byte EX_EjectSolenoid; // eject coil for improved ball release
byte EX_CountBallsInTrunk() {
byte Count = 0;
for (byte i=0; i<4; i++) {
if (EX_Machine[SwTrunk1+i] && QuerySwitch(EX_Machine[SwTrunk1+i])) {
Count++;}}
return(Count);}
byte EX_BallSaver(byte Type, byte Command){
static byte EX_IgnoreOuthole = 0; // to ignore the outhole switch while the ball is being kicked out
static bool EX_BallSaveActive = 0; // hide switches from PinMame while active
static byte EX_BallSaveTimer = 0; // Timer used by the ball saver
static bool EX_BallSaveMonitor = false; // monitor AC relay while ball saver is operating the coils
static bool EX_BallSaveExBallLamp = false; // PinMame state of the extra ball lamp
static bool EX_BallSaveACstate; // store the state of the AC relay while ball saver is operating the coils
static byte BallsInTrunk;
switch(Type){
case SwitchActCommand: // activated switches
if (EX_BallSaveMonitor) {
if (Command == EX_Machine[SwTrunk1] || Command == EX_Machine[SwTrunk2] || Command == EX_Machine[SwTrunk3]) { // hide trunk switches while ball saver is active
return (1);}}
if (EX_BallSaveActive) { // hide switches from PinMame
if (Command == EX_Machine[SwLeftOutlane] || Command == EX_Machine[SwRightOutlane]) { // We hide the switches of the outlanes and trunk
if (EX_Machine[SolLeftKickback] && Command == EX_Machine[SwLeftOutlane]) { // use the left kickback if present
ActivateSolenoid(40, EX_Machine[SolLeftKickback]);}
else if (EX_Machine[SolRightKickback] && Command == EX_Machine[SwRightOutlane]) { // use the right kickback if present
ActivateSolenoid(40, EX_Machine[SolRightKickback]);}
return(1);} // hide these switches from PinMame
else if (Command == EX_Machine[SwOuthole]) { // Outhole switch : the ball is in the outhole.
AppByte = 0; // reset outhole kicks
if (!EX_IgnoreOuthole) {
if (EX_BallSaveTimer) { // timer still running?
KillTimer(EX_BallSaveTimer); // stop it
EX_BallSaveTimer = 0;}
EX_BallSaveMonitor = true;
EX_IgnoreOuthole = true; // ignore switch bouncing when the ball is kicked out
if (!EX_Machine[SolACrelay] || !QuerySolenoid(EX_Machine[SolACrelay])) { // AC present or not active?
EX_BallSaveACstate = false;
ActivateTimer(1000, 46, EX_BallSaver2);}
else { // AC needs to be switched
EX_BallSaveACstate = true;
if (!SolBuffer[0]) { // none of solenoids 1 - 8 active?
EX_BallSaver(45, 0);}
else {
SolBuffer[0] = 0; // quick way to release
ReleaseSolenoid(1); // solenoids 1 - 8
ActivateTimer(40, 45, EX_BallSaver2);}}}
return(1);}} // hide this switch from PinMame
return(0); // report switch to PinMame
case SwitchRelCommand:
if (EX_BallSaveMonitor) {
if (Command == EX_Machine[SwTrunk1] || Command == EX_Machine[SwTrunk2] || Command == EX_Machine[SwTrunk3]) { // hide trunk switches while ball saver is active
return (1);}}
if (EX_BallSaveActive) { // hide switches from PinMame
if (Command == EX_Machine[SwLeftOutlane] || Command == EX_Machine[SwRightOutlane]) { // We hide the switches of the outlanes and trunk
return(1);}} // hide these switches from PinMame
return(0);
case SolenoidActCommand:
if (((EX_Machine[SolShooterLn] && Command == EX_Machine[SolShooterLn]) || (!EX_Machine[SolShooterLn] && Command == EX_Machine[SolOuthole])) && QuerySolenoid(24)) { // Use the shooter lane coil to start ball saver. If none present use outhole coil.
if (!EX_Machine[SolACrelay] || !QuerySolenoid(EX_Machine[SolACrelay])) {
if (EX_BallSaveTimer) { // Activate the timer
KillTimer(EX_BallSaveTimer);}
EX_BallSaveActive = true;
AddBlinkLamp(EX_Machine[LampExBall], 150); // start blinking of Shoot again lamps (Shoot again on backglass, Drive again on playfield)
EX_BallSaveTimer = ActivateTimer(game_settings[USB_BallSaveTime] * 1000, 50, EX_BallSaver2);}}
else if (EX_Machine[SolACrelay]) { // machine has an AC relay?
if (Command == EX_Machine[SolACrelay] && EX_BallSaveMonitor) { // AC relay
EX_BallSaveACstate = true;
return(1);}
if (Command < 9 && EX_BallSaveACstate) { // PinMame requesting the AC relay to be set
return(1);}} // ignore the solenoid command
return(0);
case SolenoidRelCommand: // released switches
if(EX_Machine[SolACrelay] && Command == EX_Machine[SolACrelay] && EX_BallSaveMonitor) {
EX_BallSaveACstate = false;
return(1);} // hide these switches from PinMame
else if (Command == 25) { // disable ball saver when game is over (flipper relay turned off)
if (EX_BallSaveTimer) { // timer still running?
KillTimer(EX_BallSaveTimer);} // stop it
EX_BallSaver(50, 0);}
return(0);
case LampOnCommand:
if (Command == EX_Machine[LampExBall]) {
EX_BallSaveExBallLamp = true;
if (EX_BallSaveActive) {
return(1);}}
return(0);
case LampOffCommand:
if (Command == EX_Machine[LampExBall]) {
EX_BallSaveExBallLamp = false;
if (EX_BallSaveActive) {
return(1);}}
return(0);
case 45: // Turn Off AC relay
ReleaseSolenoid(EX_Machine[SolACrelay]);
ActivateTimer(1000, 46, EX_BallSaver2);
return(1);
case 46:
if (QuerySwitch(EX_Machine[SwOuthole])) { // ball still in outhole?
if (EX_Machine[SwTrunk1]) { // does machine have more than one ball?
BallsInTrunk = EX_CountBallsInTrunk();
AppByte = 0;
ActivateTimer(1500, 47, EX_BallSaver2);}
else {
ActivateTimer(200, 50, EX_BallSaver2);}
ActivateSolenoid(40, EX_Machine[SolOuthole]);} // kick ball into trunk (solenoid 1 outhole)
else { // ball not in outhole
if (AppByte < 10) { // already tried 10 times?
AppByte++;
ActivateTimer(300, 46, EX_BallSaver2);}
else { // something's wrong
if (EX_BallSaveTimer) { // timer still running?
KillTimer(EX_BallSaveTimer);} // stop it
EX_BallSaver(50, 0);}} // end ball saver cycle
return(1);
case 47: // timer after ball has been kicked to trunk run out
{byte CountTrunk = EX_CountBallsInTrunk();
if (CountTrunk == BallsInTrunk + 1) { // ball in the trunk?
ActivateSolenoid(30, EX_Machine[SolShooterLn]); // kick ball into shooter lane
if (!EX_BallSaveACstate) { // correct AC state?
ActivateTimer(40, 50, EX_BallSaver2);} // end cycle
else {
ActivateTimer(40, 48, EX_BallSaver2);}} // switch on AC relay
else { // wrong number of balls in trunk
if (AppByte) { // additional waiting time has already passed
if (CountTrunk < BallsInTrunk + 1) { // less balls in trunk than expected
if (QuerySwitch(EX_Machine[SwOuthole])) { // ball still in outhole?
AppByte = 0;
ActivateTimer(100, 46, EX_BallSaver2);}} // try again
else { // more balls in trunk than expected
USB_SwitchHandler(EX_Machine[SwTrunk1 + BallsInTrunk]); // report one drained ball to PinMame
BallsInTrunk++;
ActivateTimer(1000, 47, EX_BallSaver2);}} // come back to handle second ball
else { // wait and try again
AppByte = 1;
ActivateTimer(1000, 47, EX_BallSaver2);}} // come back in 1s
return(1);}
case 48: // fix state of AC relay
if (EX_BallSaveACstate) {
ActivateSolenoid(0, EX_Machine[SolACrelay]);} // turn on AC relay
ActivateTimer(40, 50, EX_BallSaver2);
return(1);
case 50: // Stop the timer of Shoot Again after 20 seconds
EX_BallSaveTimer = 0;
EX_IgnoreOuthole = false;
EX_BallSaveMonitor = false;
EX_BallSaveACstate = false; // stop fumbling with the AC relay
RemoveBlinkLamp(EX_Machine[LampExBall]); // stop blinking the extra ball lamps
if (EX_BallSaveExBallLamp) { // restore the state of the Extra Ball lamps
TurnOnLamp(EX_Machine[LampExBall]);} // Activate lamps Shoot Again (backglass) and Drive Again (playfield)
else {
TurnOffLamp(EX_Machine[LampExBall]);}
EX_BallSaveActive = 0;
return(1);
default: // use default treatment for undefined types
return(0);}} // no exception rule found for this type so proceed as normal
void EX_BallSaver2(byte Selector) { // to be called by timer from EX_BallSaver
EX_BallSaver(Selector, 0);}
void EX_BallRelease(byte State) { // repeat ball eject in case the ball got stuck
static byte Timer; // stores the timer number
switch (State) { // determines what to do
case 0: // kill the timer
if (Timer) { // if a timer is active
KillTimer(Timer); // kill it
Timer = 0;} // and set Timer = 0 to indicate that no timer is active
break;
case 1: // start a timer
if (!Timer) { // if no timer is active
Timer = ActivateTimer(3000, 2, EX_BallRelease);} // start one for 3s with 2 as the argument
break;
case 2: // timer has run out
ActivateSolenoid(40, EX_EjectSolenoid); // activate the shooter lane feeder again
Timer = ActivateTimer(3000, 2, EX_BallRelease);}} // and restart the timer
void EX_StepperMotor(byte State) { // control stepper motor
static byte MainTimer = 0; // number of the main timer
static unsigned int RefTime; // stores the start value of the main timer
static unsigned int PWMtime; // stores the PWM time for the active cycle
switch(State) { // state machine
case 0: // procedure is called from solenoid exception
if (!MainTimer) { // initial call, stepper motor not yet running
RefTime = 60; // set timeout to 60ms
MainTimer = ActivateTimer(RefTime, 1, EX_StepperMotor);} // start main timer
else { // not the first solenoid call from PinMame as main timer is already running
PWMtime = RefTime - TimerValue[MainTimer]; // calculate time difference between PinMame's solenoid pulses
KillTimer(MainTimer); // cancel timeout
RefTime = PWMtime + 10; // set new timeout value based on last PWM cycle time
MainTimer = ActivateTimer(RefTime, 1, EX_StepperMotor); // restart main timer
ActivateSolenoid(PWMtime/2, 14); // generate PWM pulse on first solenoid
ActivateTimer(PWMtime/4, 2, EX_StepperMotor);} // come back to generate pulse on second solenoid
break;
case 1: // timeout has occurred as no pulses from PinMame have been detected recently
MainTimer = 0; // indicate that main timer is not active
ActivateSolenoid(PWMtime/2, 14); // generate last step on the solenoids anyway
ActivateTimer(PWMtime/4, 2, EX_StepperMotor);
break;
case 2: // generate pulse on second solenoid
ActivateSolenoid(PWMtime/2, 15);
break;}}
void EX_FakeSwitchSequence(byte State) { // sends a sequence of fake switches to PinMame
switch (State) {
case 1:
USB_SwitchHandler(3); // report switch 3 activated
ActivateTimer(100, 2, EX_FakeSwitchSequence); // wait 100ms and come back
break;
case 2:
USB_ReleasedSwitches(3); // report switch 3 released
ActivateTimer(1000, 3, EX_FakeSwitchSequence);
break;
case 3:
break;}}
byte EX_FakeSwitches(byte Type, byte Command){ // use this to start sending fake switches to PinMame
switch (Type) {
// case SoundCommandCh1: // sound commands for channel 1
// char FileName[9] = "0_00.snd"; // handle standard sound
// if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
// PlaySound(51, (char*) FileName);}
// return(0); // return number not relevant for sounds
// case SoundCommandCh2: // sound commands for channel 2
// char FileName[9] = "1_00.snd"; // handle standard music
// if (USB_GenerateFilename(2, Command, FileName)) { // create filename and check whether file is present
// PlayMusic(51, (char*) FileName);}
// return(0); // return number not relevant for sounds
case SwitchActCommand: // activated switches
Serial.print("Sw "); // report their activation
Serial.println(Command);
if (Command == 65) { // start sequence with special solenoid switch 1
EX_FakeSwitchSequence(1); // start fake sequence
return(1);} // but don't tell PinMame
return(0); // all other switches are reported
case SolenoidActCommand: // activate solenoids
if (Command != 14 && Command != 15){ // for all solenoids except for 14 and 15
Serial.print("Sol "); // report their activation
Serial.println(Command); } // works only when debug mode is enabled
return(0); // solenoid will be activated
default:
return(0);}}
// game specific exceptions
byte EX_DummyProcess(byte Type, byte Command) { // plays just the standard sounds
if (Type == SoundCommandCh1) { // sound commands for channel 1
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
else if (Type == SoundCommandCh2) { // sound commands for channel 2
char FileName[9] = "1_00.snd"; // handle standard music
if (USB_GenerateFilename(2, Command, FileName)) { // create filename and check whether file is present
PlayMusic(51, (char*) FileName);}}
return(0);} // no exception rule found for this type so proceed as normal
byte EX_DiscoFever(byte Type, byte Command){
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SolenoidActCommand:
if (Command == 2) { // ball release
ActivateSolenoid(80, 2); // FEV drop target reset
return(1);}
else if (Command == 3) { // ER drop target reset
ActivateSolenoid(60, 3); // Fix to increase the strength of the ball release
return(1);}
return(0);
case SolenoidRelCommand:
if (Command == 2 || Command == 3) { // ignore turn-off commands for drop target solenoids
return(1);} // ignore it
return(0);
default:
return(0);}}
byte EX_Flash(byte Type, byte Command){
static byte SoundSeries[3]; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SolenoidActCommand:
if (Command == 1) { // ball release
ActivateSolenoid(40, 1); // Fix to increase the strength of the ball release
return(1);}
else if (Command == 3) { // reset of the lower two of the five drop targets
ActivateSolenoid(40, 3); // Fix to increase the strength of the ball release
return(1);}
return(0);
case SolenoidRelCommand:
if (Command == 1 || Command == 3) { // ball release or the reset of the lower two of the five drop targets
return(1);} // ignore it
return(0);
case SoundCommandCh1: // sound commands for channel 1
if (Command == 31) { } // ignore sound command 0x1f - audio bus init - not relevant for APC sound / also ignore 0xff whatever it is
else if (Command == 12) { // sound command 0x0c - stop sound
AfterSound = 0;
SoundSeries[0] = 0;
SoundSeries[1] = 0; // reset the multiball start sound
SoundSeries[2] = 0; // Reset BG sound
StopPlayingSound();
StopPlayingMusic();}
else if (Command == 10){ // sound command 0x0a - sound series
if (SoundSeries[0] < 80) { // this sound has 80 pitches
SoundSeries[0]++;} // every call of this sound proceeds with next pitch
char FileName[13] = "0_0a_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[0] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[0] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 11) { // sound command 0x0b - sound series
if (SoundSeries[1] < 200) { // this sound has 200 pitches
SoundSeries[1]++;}
char FileName[13] = "0_0b_000.snd";
FileName[7] = 48 + (SoundSeries[1] % 10);
FileName[6] = 48 + (SoundSeries[1] % 100) / 10;
FileName[5] = 48 + (SoundSeries[1] / 100); // the same with the 5th character
PlaySound(51, (char*) FileName);}
else if (Command == 13) { // sound command 0x0d - background sound - sound series
SoundSeries[0] = 0;
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[2]) { // ignore the pitches
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[2] = 1;}}
else {
if (SoundSeries[2] < 25) { // this sound has 25 pitches
SoundSeries[2]++;}
char FileName[13] = "0_0e_000.snd";
FileName[7] = 48 + (SoundSeries[2] % 10);
FileName[6] = 48 + (SoundSeries[2] % 100) / 10;
for (byte i=0; i<12; i++) { // prepare the filename
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}}
else if (Command == 14) { // sound command 0x0e - background sound - sound series
SoundSeries[2] = 0;
char FileName[13] = "0_0e_001.snd";
for (byte i=0; i<12; i++) { // prepare the filename
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}
else if (Command == 15) { // sound command 0x0f - start game
char FileName[13] = "0_0f_000.snd"; // generate base filename
FileName[7] = 48 + random(8) + 1; // change the counter according to random number
PlaySound(51, (char*) FileName);} // play the corresponding sound file
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
default:
return(0);}}
byte EX_TimeWarp(byte Type, byte Command){
static byte SoundSeries; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 31) { } // ignore sound command 0x1f - audio bus init - not relevant for APC sound / also ignore 0xff whatever it is
else if (Command == 12) { // sound command 0x0c - stop sound
AfterSound = 0;
SoundSeries = 0; // Reset BG sound
StopPlayingMusic();
StopPlayingSound();}
else if (Command == 13) { // sound command 0x0d - increase pitch of background sound
if (!game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (SoundSeries < 25 ) // this sound has 31 pitches
SoundSeries++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0e_000.snd";
FileName[7] = 48 + (SoundSeries % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // prepare the filename
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}}
else if (Command == 14) { // sound command 0x0e - background sound - sound series
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd");} // and loop it
else {
SoundSeries = 1;
PlaySound(51, "0_0e_001.snd"); // play BG sound
QueueNextSound("0_0e_001.snd");}} // select this sound to be repeated
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
case SolenoidActCommand:
if (Command == 6) { // the 5 bank bottom drop target reset solenoid needs to be stronger
ActivateSolenoid(80, 6); // drop target reset
return(1);}
return(0);
case SolenoidRelCommand:
if (Command == 6) { // ignore turn-off commands for drop target solenoids
return(1);} // ignore it
return(0);
default:
return(0);}}
byte EX_Firepower(byte Type, byte Command){ // thanks to Matiou for sending me this code
static byte SoundSeries[5] = {0, 0, 0, 0, 0}; // buffer to handle pre system11 sound series
static byte PlayingMultiballSound = 0;
const byte PlayCombinedSoundForMultiball = 1; // 1-> play one sound "1, 2, 3". 2-> play 3 sounds "1", "2", "3".
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 31) { } // ignore sound command 0x1f
else if (Command == 12) { // sound command 0x0c - stop all sounds and reset series
AfterSound = 0;
SoundSeries[0] = 0;
SoundSeries[1] = 0;
SoundSeries[2] = 0;
SoundSeries[3] = 0;
SoundSeries[4] = 0;
StopPlayingSound();
StopPlayingMusic();}
else {
if (Command == 4){ // 0x04 End game - random speech
char FileName[13] = "0_04_000.snd"; // generate base filename
FileName[7] = 48 + random(9) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 7){ // 0x07 Fire one/two/three series (multiball!)
// code for individual sounds
if (PlayCombinedSoundForMultiball == 0) {
PlayingMultiballSound = 1; // remember we're in a multiball start session
if (SoundSeries[0] < 3) // this sound has 3 pitches
SoundSeries[0]++; // every call of this sound proceeds with next pitch
else //
SoundSeries[0] = 1; // start all over again
char FileName[13] = "0_07_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[0] % 10); // change the 7th character of filename according to current pitch
PlaySound(51, (char*) FileName);} // play the sound
else { // code for combined sounds (not standard but works better)
if (PlayingMultiballSound == 0) {
PlayingMultiballSound = 1;
char FileName[13] = "0_07_004.snd"; // this wav is combined version from 67_001 to 67_003
PlaySound(51, (char*) FileName);}}}
else if (Command == 9){ // 0x09 Bonus
if (SoundSeries[1] < 146) // this sound has 146 pitches
SoundSeries[1]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_09_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[1] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[1] % 100) / 10; // the same with the 6th character
FileName[5] = 48 + (SoundSeries[1] / 100); // the same with the 5th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 10) { // 0x0a Whirling background
if (SoundSeries[2] < 29 ) // this sound has 29 pitches
SoundSeries[2]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0a_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[2] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[2] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 13) { // 0x0d Spinner
if (SoundSeries[3] < 31 ) // this sound has 31 pitches
SoundSeries[3]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0d_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[3] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[3] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 14) { // 0x0e Background // repeated
PlayingMultiballSound = 0; // if the background plays, we're not in a multiball start session
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[4]) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[4] = 1;}}
else { // normal BG sound
if (SoundSeries[4] < 31 ) // this sound has 31 pitches
SoundSeries[4]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0e_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[4] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[4] % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // store the name of this sound
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}} // play the sound
else if ((Command == 8 || Command == 11) // ignore these sounds at beginning of multiball
&& PlayingMultiballSound == 1) { }
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}}
return(0); // return number not relevant for sounds
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_AlienPoker(byte Type, byte Command){
static byte SoundSeries[3] = {0, 0, 0}; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 31) { } // ignore sound command 0x1f
else if (Command == 12) { // sound command 0x0c - stop all sounds and reset series
AfterSound = 0;
SoundSeries[0] = 0;
SoundSeries[1] = 0;
SoundSeries[2] = 0;
StopPlayingSound();
StopPlayingMusic();}
else if (Command == 10) { // sound series
if (SoundSeries[0] < 29 ) // this sound has 29 pitches
SoundSeries[0]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0a_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[0] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[0] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 13) { // sound series
if (SoundSeries[1] < 31 ) // this sound has 31 pitches
SoundSeries[1]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0d_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[1] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[1] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else if (Command == 14) { // 0x0e Background sound series - repeated
SoundSeries[0] = 0;
SoundSeries[1] = 0;
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[2]) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[2] = 1;}}
else {
if (SoundSeries[2] < 36 ) // this sound has 36 pitches
SoundSeries[2]++; // every call of this sound proceeds with next pitch
char FileName[13] = "0_0e_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[2] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[2] % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // store the name of this sound
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}} // play the sound
else if (Command == 23){ // sound command 0x17 - game over random phrase
char FileName[13] = "0_17_000.snd"; // generate base filename
FileName[7] = 48 + random(6) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_JungleLord(byte Type, byte Command){
static byte SoundSeries[2]; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 127) { } // ignore sound command 0x7f - audio bus init - not relevant for APC sound
else if (Command == 38){ // sound command 0x26 - start game
char FileName[13] = "0_26_000.snd"; // generate base filename
FileName[7] = 48 + random(4) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 42){ // sound command 0x2a - background sound - sound series
SoundSeries[1] = 0; // reset the multiball start sound
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[0]) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[0] = 1;}}
else {
if (SoundSeries[0] < 29) // BG sound has 29 pitches
SoundSeries[0]++; // every call of this sound proceeds with the next pitch
char FileName[13] = "0_2a_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[0] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[0] % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // store the name of this sound
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // select this sound to be repeated
PlaySound(51, (char*) FileName);}} // play the sound
else if (Command == 44) { // sound command 0x2c - stop sound
AfterSound = 0;
SoundSeries[0] = 0; // Reset BG sound
SoundSeries[1] = 0; // reset the multiball start sound
StopPlayingSound();
StopPlayingMusic();}
else if (Command == 45){ // sound command 0x2d - multiball start - sound series
if (SoundSeries[1] < 31) // this sound has 31 pitches
SoundSeries[1]++; // every call of this sound proceeds with next pitch
else
SoundSeries[1] = 1; // start all over again
char FileName[13] = "0_2d_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[1] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[1] % 100) / 10; // the same with the 6th character
PlaySound(51, (char*) FileName);} // play the sound
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
case SwitchActCommand: // activated switches
if (Command == 43) { // ball successfully ejected
EX_BallRelease(0);} // stop ball release timer
else if (Command == 49) { // right magnet button
if (QueryLamp(8) && QueryLamp(2)) { // right magnet and ball in play lamp lit?
ActivateSolenoid(0, 22);}} // activate right magnet
else if (Command == 50) { // left magnet button
if (QueryLamp(39) && QueryLamp(2)) { // left magnet and ball in play lamp lit?
ActivateSolenoid(0, 21);}} // activate left magnet
return(0); // all switches are reported to PinMame
case SwitchRelCommand: // deactivated switches
if (Command == 49){ // right magnet button
ReleaseSolenoid(22);} // turn off right magnet
else if (Command == 50) { // left magnet button
ReleaseSolenoid(21);} // turn off left magnet
return(0); // all switches are reported to PinMame
case SolenoidActCommand: // activated solenoids
if (Command == EX_EjectSolenoid){ // ball eject coil
if (QueryLamp(2)) { // ball in play lamp lit?
EX_BallRelease(1);}} // start ball release timer
return(0); // solenoid will be activated
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_Pharaoh(byte Type, byte Command){ // thanks to Grangeomatic for sending me this code
static byte SoundSeries; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 127) { } // ignore sound command 0x7f - audio bus init - not relevant for APC sound
else if (Command == 37) { // sound command 0x25 - random speech
char FileName[13] = "0_25_000.snd"; // generate base filename
FileName[7] = 48 + random(4) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 42) { // sound command 0x2a - random speech
char FileName[13] = "0_2a_000.snd"; // generate base filename
FileName[7] = 48 + random(2) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 44) { // sound command 0x2c - stop sound
AfterSound = 0; // disable auto restart of BG sound
SoundSeries = 0; // Reset BG sound
StopPlayingMusic();
StopPlayingSound();}
else if (Command == 45) { // sound command 0x2d - background sound - sound series
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries = 1;}}
else {
if (SoundSeries < 32) // sound series has 32 different pitches
SoundSeries++; // switch to the next pitch when sound command is called again
char FileName[13] = "0_2d_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // store filename to be repeated
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // set this filename to be started by PlayNextSound
PlaySound(51, (char*) FileName);}}
else if (Command == 48) { // sound command 0x30 - random speech
char FileName[13] = "0_30_000.snd"; // generate base filename
FileName[7] = 48 + random(2) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 49) { // sound command 0x31 - random speech
char FileName[13] = "0_31_000.snd"; // generate base filename
FileName[7] = 48 + random(2) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 55) { // sound command 0x37 - random speech
char FileName[13] = "0_37_000.snd"; // generate base filename
FileName[7] = 48 + random(2) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 58) { // sound command 0x3a - random speech
char FileName[13] = "0_3a_000.snd"; // generate base filename
FileName[7] = 48 + random(4) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_Barracora(byte Type, byte Command){
static byte SoundSeries[2]; // buffer to handle pre system11 sound series
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 127) { } // ignore sound command 0x7f - audio bus init - not relevant for APC sound
else if (Command == 44) { // sound command 0x2c - stop sound
AfterSound = 0;
SoundSeries[0] = 0; // Reset BG sound
SoundSeries[1] = 0; // reset the multiball start sound
StopPlayingSound();
StopPlayingMusic();}
else if (Command == 45){ // sound command 0x2d - sound series
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[0]) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[0] = 1;}}
else {
if (SoundSeries[0] < 32) { // this sound has 32 pitches
SoundSeries[0]++;} // every call of this sound proceeds with next pitch
char FileName[13] = "0_2d_000.snd"; // generate base filename
FileName[7] = 48 + (SoundSeries[0] % 10); // change the 7th character of filename according to current pitch
FileName[6] = 48 + (SoundSeries[0] % 100) / 10; // the same with the 6th character
for (byte i=0; i<12; i++) { // prepare the filename
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // sound is being auto repeated
PlaySound(51, (char*) FileName);}} // play the sound
else if (Command == 46) { // sound command 0x2e - background sound - sound series
SoundSeries[0] = 0;
if (SoundSeries[1] < 30) { // this sound has 30 pitches
SoundSeries[1]++;}
char FileName[13] = "0_2e_000.snd";
FileName[7] = 48 + (SoundSeries[1] % 10);
FileName[6] = 48 + (SoundSeries[1] % 100) / 10;
for (byte i=0; i<12; i++) { // prepare the filename
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound); // sound is being auto repeated
PlaySound(51, (char*) FileName);}
else { // standard sound
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
case SwitchActCommand: // activated switches
if (Command == 16) { // ball successfully ejected
EX_BallRelease(0);} // stop ball release timer
return(0); // all switches are reported to PinMame
case SolenoidActCommand: // activated solenoids
if (Command == EX_EjectSolenoid){ // ball eject coil
if (QueryLamp(2)) { // ball in play lamp lit?
EX_BallRelease(1);}} // start ball release timer
return(0); // solenoid will be activated
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_BlackKnight(byte Type, byte Command){
static byte SoundSeries[3]; // buffer to handle pre system11 sound series
static byte LastCh1Sound; // preSys11: stores the number of the last sound that has been played on Ch1
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (Command == 127) { } // ignore sound command 0x7f - audio bus init - not relevant for APC sound
else if (Command == 48) { // sound command 0x30
if (QuerySolenoid(11)) { // GI off?
PlaySound(152, "0_30_001.snd");}} // play multiball ball release sequence
else if (Command == 56) { // sound command 0x38
if (QuerySolenoid(11)) { // GI off?
if (LastCh1Sound != 56) { // ignore all subsequent 0x38 commands
AfterSound = 0;
LastCh1Sound = Command; // buffer sound number
PlaySound(51, "0_38_001.snd");}}} // play multiball start sequence
else if (Command == 43) { // sound command 0x2b - start game
char FileName[13] = "0_2b_000.snd"; // generate base filename
FileName[7] = 48 + random(5) + 1; // change the counter according to random number
PlaySound(52, (char*) FileName);} // play the corresponding sound file
else if (Command == 45) { // sound command 0x2d - activated spinner - sound series
if (SoundSeries[0] != 45) {
SoundSeries[0] = 45;
SoundSeries[1] = 0;}
SoundSeries[1]++;
char FileName[13] = "0_2d_000.snd";
FileName[7] = 48 + (SoundSeries[1] % 10);
FileName[6] = 48 + (SoundSeries[1] % 100) / 10;
FileName[5] = 48 + SoundSeries[1] / 100;
LastCh1Sound = Command; // buffer sound number
PlaySound(51, (char*) FileName);}
else if (Command == 44) { // sound command 0x2c - stop sound
AfterSound = 0;
SoundSeries[0] = 0; // Reset last sound series number
SoundSeries[1] = 0; // reset the multiball start sound
SoundSeries[2] = 0; // Reset BG sound
StopPlayingSound();
StopPlayingMusic();}
else if (Command == 46) { // sound command 0x2e - background sound - sound series
SoundSeries[0] = 0;
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
if (!SoundSeries[2]) { // don't restart if next pitch is requested
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd"); // and loop it
SoundSeries[2] = 1;}}
else {
if (SoundSeries[2] < 29)
SoundSeries[2]++;
char FileName[13] = "0_2e_000.snd";
FileName[7] = 48 + (SoundSeries[2] % 10);
FileName[6] = 48 + (SoundSeries[2] % 100) / 10;
FileName[5] = 48 + SoundSeries[2] / 100;
for (byte i=0; i<12; i++) {
USB_RepeatSound[i] = FileName[i];}
QueueNextSound(USB_RepeatSound);
LastCh1Sound = Command; // buffer sound number
PlaySound(51, (char*) FileName);}}
else if (Command == 52) { // sound command 0x34 - bonus count
AfterSound = 0;
if (!QueryLamp(49) && !QueryLamp(57) && !QueryLamp(61)) { // only bonus lamp 1 lit?
PlaySound(51, "0_34_002.snd");}
else if (LastCh1Sound != 52) {
LastCh1Sound = Command; // buffer sound number
SoundSeries[2] = 0; // Reset BG sound
PlaySound(51, "0_34_001.snd");}}
else if (Command == 58) { // sound command 0x3a
PlaySound(152, "0_3a.snd");} // play multiball ball release sequence
else { // standard sound
LastCh1Sound = Command; // buffer sound number
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0);
case SwitchActCommand: // activated switches
if (Command == 45) { // ball successfully ejected
EX_BallRelease(0);} // stop ball release timer
else if (Command == 9) { // right magnet button
if (QueryLamp(9) && QueryLamp(2)) { // right magnet and ball in play lamp lit?
ActivateSolenoid(0, 9);}} // activate right magnet
else if (Command == 10) { // left magnet button
if (QueryLamp(10) && QueryLamp(2)) { // left magnet and ball in play lamp lit?
ActivateSolenoid(0, 10);}} // activate left magnet
return(0); // all switches are reported to PinMame
case SolenoidActCommand: // activated solenoids
if (Command == EX_EjectSolenoid){ // ball eject coil
if (QueryLamp(2)) { // ball in play lamp lit?
EX_BallRelease(1);}} // start ball release timer
return(0); // return number not relevant for sounds
default:
return(0);}}
byte EX_Comet(byte Type, byte Command) {
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (!Command || Command > 254) { // sound command 0x00 and 0xff -> stop sound
AfterMusic = 0;
StopPlayingMusic();
StopPlayingSound();}
else if (Command == 11 || Command == 254) { } // ignore sound commands 0x0b and 0xfe
else if (Command == 47) { // play BG music
if (game_settings[USB_BGmusic]) { // use MUSIC.SND instead of BG sound
PlayMusic(50, "MUSIC.snd"); // play music track
QueueNextMusic("MUSIC.snd");} // and loop it
else {
PlayMusic(50, "0_2f.snd");
QueueNextMusic("0_2f.snd");}} // track is looping so queue it also
else { // handle standard sound
if (Command == 9) {
MusicVolume = 4;} // reduce music volume
if (Command == 241) { // sound 0xf1
RestoreMusicVolumeAfterSound(25);} // and restore it
char FileName[9] = "0_00.snd";
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
return(0); // return number not relevant for sounds
default:
return(0);}} // no exception rule found for this type so proceed as normal
byte EX_HighSpeed(byte Type, byte Command) { // plays just the standard sounds
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
if (Type == SoundCommandCh1) { // sound commands for channel 1
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
PlaySound(51, (char*) FileName);}}
else if (Type == SoundCommandCh2) { // sound commands for channel 2
char FileName[9] = "1_00.snd"; // handle standard music
if (USB_GenerateFilename(2, Command, FileName)) { // create filename and check whether file is present
PlayMusic(51, (char*) FileName);}}
return(0);} // no exception rule found for this type so proceed as normal
byte EX_Pinbot(byte Type, byte Command){
if (game_settings[USB_BallSave]) { // ball saver set to active?
if (EX_BallSaver(Type, Command)) { // include ball saver
return(1);}} // omit command if ball saver says so
switch(Type){
case SoundCommandCh1: // sound commands for channel 1
if (!Command){ // sound command 0x00 - stop sound
AfterSound = 0;
StopPlayingSound();}
else if (Command == 85) { } // ignore sound command 0x55
else if (Command == 105) { } // ignore strange misplaced sound during multiball
else if (Command == 170) { } // ignore sound command 0xaa
else if (Command == 255) { } // ignore sound command 0xff
else { // proceed with standard sound handling
char FileName[9] = "0_00.snd"; // handle standard sound
if (USB_GenerateFilename(1, Command, FileName)) { // create filename and check whether file is present
if (Command < 128) { // play speech with a higher priority
PlaySound(50, (char*) FileName);}
else {
PlaySound(51, (char*) FileName);}}}
return(0); // return number not relevant for sounds
case SoundCommandCh2: // sound commands for channel 2
if (!Command) { // sound command 0x00 - stop music
AfterMusic = 0;
StopPlayingMusic();}
else if (Command == 127) { // sound command 0x7f - stop sound
AfterSound = 0;
StopPlayingSound();}