Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/controls.cpp
28515 views
1
/***********************************************************************************
2
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4
(c) Copyright 1996 - 2002 Gary Henderson ([email protected]),
5
Jerremy Koot ([email protected])
6
7
(c) Copyright 2002 - 2004 Matthew Kendora
8
9
(c) Copyright 2002 - 2005 Peter Bortas ([email protected])
10
11
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13
(c) Copyright 2001 - 2006 John Weidman ([email protected])
14
15
(c) Copyright 2002 - 2006 funkyass ([email protected]),
16
Kris Bleakley ([email protected])
17
18
(c) Copyright 2002 - 2010 Brad Jorsch ([email protected]),
19
Nach ([email protected]),
20
21
(c) Copyright 2002 - 2011 zones ([email protected])
22
23
(c) Copyright 2006 - 2007 nitsuja
24
25
(c) Copyright 2009 - 2011 BearOso,
26
OV2
27
28
29
BS-X C emulator code
30
(c) Copyright 2005 - 2006 Dreamer Nom,
31
zones
32
33
C4 x86 assembler and some C emulation code
34
(c) Copyright 2000 - 2003 _Demo_ ([email protected]),
35
Nach,
36
zsKnight ([email protected])
37
38
C4 C++ code
39
(c) Copyright 2003 - 2006 Brad Jorsch,
40
Nach
41
42
DSP-1 emulator code
43
(c) Copyright 1998 - 2006 _Demo_,
44
Andreas Naive ([email protected]),
45
Gary Henderson,
46
Ivar ([email protected]),
47
John Weidman,
48
Kris Bleakley,
49
Matthew Kendora,
50
Nach,
51
neviksti ([email protected])
52
53
DSP-2 emulator code
54
(c) Copyright 2003 John Weidman,
55
Kris Bleakley,
56
Lord Nightmare ([email protected]),
57
Matthew Kendora,
58
neviksti
59
60
DSP-3 emulator code
61
(c) Copyright 2003 - 2006 John Weidman,
62
Kris Bleakley,
63
Lancer,
64
z80 gaiden
65
66
DSP-4 emulator code
67
(c) Copyright 2004 - 2006 Dreamer Nom,
68
John Weidman,
69
Kris Bleakley,
70
Nach,
71
z80 gaiden
72
73
OBC1 emulator code
74
(c) Copyright 2001 - 2004 zsKnight,
75
pagefault ([email protected]),
76
Kris Bleakley
77
Ported from x86 assembler to C by sanmaiwashi
78
79
SPC7110 and RTC C++ emulator code used in 1.39-1.51
80
(c) Copyright 2002 Matthew Kendora with research by
81
zsKnight,
82
John Weidman,
83
Dark Force
84
85
SPC7110 and RTC C++ emulator code used in 1.52+
86
(c) Copyright 2009 byuu,
87
neviksti
88
89
S-DD1 C emulator code
90
(c) Copyright 2003 Brad Jorsch with research by
91
Andreas Naive,
92
John Weidman
93
94
S-RTC C emulator code
95
(c) Copyright 2001 - 2006 byuu,
96
John Weidman
97
98
ST010 C++ emulator code
99
(c) Copyright 2003 Feather,
100
John Weidman,
101
Kris Bleakley,
102
Matthew Kendora
103
104
Super FX x86 assembler emulator code
105
(c) Copyright 1998 - 2003 _Demo_,
106
pagefault,
107
zsKnight
108
109
Super FX C emulator code
110
(c) Copyright 1997 - 1999 Ivar,
111
Gary Henderson,
112
John Weidman
113
114
Sound emulator code used in 1.5-1.51
115
(c) Copyright 1998 - 2003 Brad Martin
116
(c) Copyright 1998 - 2006 Charles Bilyue'
117
118
Sound emulator code used in 1.52+
119
(c) Copyright 2004 - 2007 Shay Green ([email protected])
120
121
SH assembler code partly based on x86 assembler code
122
(c) Copyright 2002 - 2004 Marcus Comstedt ([email protected])
123
124
2xSaI filter
125
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
126
127
HQ2x, HQ3x, HQ4x filters
128
(c) Copyright 2003 Maxim Stepin ([email protected])
129
130
NTSC filter
131
(c) Copyright 2006 - 2007 Shay Green
132
133
GTK+ GUI code
134
(c) Copyright 2004 - 2011 BearOso
135
136
Win32 GUI code
137
(c) Copyright 2003 - 2006 blip,
138
funkyass,
139
Matthew Kendora,
140
Nach,
141
nitsuja
142
(c) Copyright 2009 - 2011 OV2
143
144
Mac OS GUI code
145
(c) Copyright 1998 - 2001 John Stiles
146
(c) Copyright 2001 - 2011 zones
147
148
149
Specific ports contains the works of other authors. See headers in
150
individual files.
151
152
153
Snes9x homepage: http://www.snes9x.com/
154
155
Permission to use, copy, modify and/or distribute Snes9x in both binary
156
and source form, for non-commercial purposes, is hereby granted without
157
fee, providing that this license information and copyright notice appear
158
with all copies and any derived work.
159
160
This software is provided 'as-is', without any express or implied
161
warranty. In no event shall the authors be held liable for any damages
162
arising from the use of this software or it's derivatives.
163
164
Snes9x is freeware for PERSONAL USE only. Commercial users should
165
seek permission of the copyright holders first. Commercial use includes,
166
but is not limited to, charging money for Snes9x or software derived from
167
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
168
using Snes9x as a promotion for your commercial product.
169
170
The copyright holders request that bug fixes and improvements to the code
171
should be forwarded to them so everyone can benefit from the modifications
172
in future versions.
173
174
Super NES and Super Nintendo Entertainment System are trademarks of
175
Nintendo Co., Limited and its subsidiary companies.
176
***********************************************************************************/
177
178
179
#include <map>
180
#include <set>
181
#include <vector>
182
#include <string>
183
#include <algorithm>
184
#include <assert.h>
185
#include <ctype.h>
186
187
#include "snes9x.h"
188
#include "memmap.h"
189
#include "apu/apu.h"
190
#ifdef FANCY
191
#include "snapshot.h"
192
#include "movie.h"
193
#else
194
#define S9xMoviePlaying() FALSE
195
#define S9xMovieActive() FALSE
196
#endif
197
#include "controls.h"
198
#ifdef FANCY
199
#include "crosshairs.h"
200
#endif
201
#include "display.h"
202
#ifdef NETPLAY_SUPPORT
203
#include "netplay.h"
204
#endif
205
206
using namespace std;
207
208
#define NONE (-2)
209
#define MP5 (-1)
210
#define JOYPAD0 0
211
#define JOYPAD1 1
212
#define JOYPAD2 2
213
#define JOYPAD3 3
214
#define JOYPAD4 4
215
#define JOYPAD5 5
216
#define JOYPAD6 6
217
#define JOYPAD7 7
218
#define MOUSE0 8
219
#define MOUSE1 9
220
#define SUPERSCOPE 10
221
#define ONE_JUSTIFIER 11
222
#define TWO_JUSTIFIERS 12
223
#define NUMCTLS 13 // This must be LAST
224
225
#define POLL_ALL NUMCTLS
226
227
#define SUPERSCOPE_FIRE 0x80
228
#define SUPERSCOPE_CURSOR 0x40
229
#define SUPERSCOPE_TURBO 0x20
230
#define SUPERSCOPE_PAUSE 0x10
231
#define SUPERSCOPE_OFFSCREEN 0x02
232
233
#define JUSTIFIER_TRIGGER 0x80
234
#define JUSTIFIER_START 0x20
235
#define JUSTIFIER_SELECT 0x08
236
237
#define MAP_UNKNOWN (-1)
238
#define MAP_NONE 0
239
#define MAP_BUTTON 1
240
#define MAP_AXIS 2
241
#define MAP_POINTER 3
242
243
#define FLAG_IOBIT0 (Memory.FillRAM[0x4213] & 0x40)
244
#define FLAG_IOBIT1 (Memory.FillRAM[0x4213] & 0x80)
245
#define FLAG_IOBIT(n) ((n) ? (FLAG_IOBIT1) : (FLAG_IOBIT0))
246
247
bool8 pad_read = 0, pad_read_last = 0;
248
uint8 read_idx[2 /* ports */][2 /* per port */];
249
250
struct exemulti
251
{
252
int32 pos;
253
bool8 data1;
254
s9xcommand_t *script;
255
};
256
257
struct crosshair
258
{
259
uint8 set;
260
uint8 img;
261
uint8 fg, bg;
262
};
263
264
static struct
265
{
266
int16 x, y;
267
int16 V_adj;
268
bool8 V_var;
269
int16 H_adj;
270
bool8 H_var;
271
bool8 mapped;
272
} pseudopointer[8];
273
274
static struct
275
{
276
uint16 buttons;
277
uint16 turbos;
278
uint16 toggleturbo;
279
uint16 togglestick;
280
uint8 turbo_ct;
281
} joypad[8];
282
283
static struct
284
{
285
uint8 delta_x, delta_y;
286
int16 old_x, old_y;
287
int16 cur_x, cur_y;
288
uint8 buttons;
289
uint32 ID;
290
struct crosshair crosshair;
291
} mouse[2];
292
293
static struct
294
{
295
int16 x, y;
296
uint8 phys_buttons;
297
uint8 next_buttons;
298
uint8 read_buttons;
299
uint32 ID;
300
struct crosshair crosshair;
301
} superscope;
302
303
static struct
304
{
305
int16 x[2], y[2];
306
uint8 buttons;
307
bool8 offscreen[2];
308
uint32 ID[2];
309
struct crosshair crosshair[2];
310
} justifier;
311
312
static struct
313
{
314
int8 pads[4];
315
} mp5[2];
316
317
static set<struct exemulti *> exemultis;
318
static set<uint32> pollmap[NUMCTLS + 1];
319
static map<uint32, s9xcommand_t> keymap;
320
static vector<s9xcommand_t *> multis;
321
static uint8 turbo_time;
322
static uint8 pseudobuttons[256];
323
static bool8 FLAG_LATCH = FALSE;
324
static int32 curcontrollers[2] = { NONE, NONE };
325
static int32 newcontrollers[2] = { JOYPAD0, NONE };
326
static char buf[256];
327
328
#ifdef FANCY
329
static const char *color_names[32] =
330
{
331
"Trans",
332
"Black",
333
"25Grey",
334
"50Grey",
335
"75Grey",
336
"White",
337
"Red",
338
"Orange",
339
"Yellow",
340
"Green",
341
"Cyan",
342
"Sky",
343
"Blue",
344
"Violet",
345
"MagicPink",
346
"Purple",
347
NULL,
348
"tBlack",
349
"t25Grey",
350
"t50Grey",
351
"t75Grey",
352
"tWhite",
353
"tRed",
354
"tOrange",
355
"tYellow",
356
"tGreen",
357
"tCyan",
358
"tSky",
359
"tBlue",
360
"tViolet",
361
"tMagicPink",
362
"tPurple"
363
};
364
#endif
365
366
static const char *speed_names[4] =
367
{
368
"Var",
369
"Slow",
370
"Med",
371
"Fast"
372
};
373
374
static const int ptrspeeds[4] = { 1, 1, 4, 8 };
375
376
// Note: these should be in asciibetical order!
377
#define THE_COMMANDS \
378
S(BeginRecordingMovie), \
379
S(ClipWindows), \
380
S(Debugger), \
381
S(DecEmuTurbo), \
382
S(DecFrameRate), \
383
S(DecFrameTime), \
384
S(DecTurboSpeed), \
385
S(EmuTurbo), \
386
S(EndRecordingMovie), \
387
S(ExitEmu), \
388
S(IncEmuTurbo), \
389
S(IncFrameRate), \
390
S(IncFrameTime), \
391
S(IncTurboSpeed), \
392
S(LoadFreezeFile), \
393
S(LoadMovie), \
394
S(LoadOopsFile), \
395
S(Pause), \
396
S(QuickLoad000), \
397
S(QuickLoad001), \
398
S(QuickLoad002), \
399
S(QuickLoad003), \
400
S(QuickLoad004), \
401
S(QuickLoad005), \
402
S(QuickLoad006), \
403
S(QuickLoad007), \
404
S(QuickLoad008), \
405
S(QuickLoad009), \
406
S(QuickLoad010), \
407
S(QuickSave000), \
408
S(QuickSave001), \
409
S(QuickSave002), \
410
S(QuickSave003), \
411
S(QuickSave004), \
412
S(QuickSave005), \
413
S(QuickSave006), \
414
S(QuickSave007), \
415
S(QuickSave008), \
416
S(QuickSave009), \
417
S(QuickSave010), \
418
S(Reset), \
419
S(SaveFreezeFile), \
420
S(SaveSPC), \
421
S(Screenshot), \
422
S(SeekToFrame), \
423
S(SoftReset), \
424
S(SoundChannel0), \
425
S(SoundChannel1), \
426
S(SoundChannel2), \
427
S(SoundChannel3), \
428
S(SoundChannel4), \
429
S(SoundChannel5), \
430
S(SoundChannel6), \
431
S(SoundChannel7), \
432
S(SoundChannelsOn), \
433
S(SwapJoypads), \
434
S(ToggleBG0), \
435
S(ToggleBG1), \
436
S(ToggleBG2), \
437
S(ToggleBG3), \
438
S(ToggleEmuTurbo), \
439
S(ToggleSprites), \
440
S(ToggleTransparency) \
441
442
#define S(x) x
443
444
enum command_numbers
445
{
446
THE_COMMANDS,
447
LAST_COMMAND
448
};
449
450
#undef S
451
#define S(x) #x
452
453
static const char *command_names[LAST_COMMAND + 1] =
454
{
455
THE_COMMANDS,
456
NULL
457
};
458
459
#undef S
460
#undef THE_COMMANDS
461
462
static void DisplayStateChange (const char *, bool8);
463
static void DoGunLatch (int, int);
464
static int maptype (int);
465
static bool strless (const char *, const char *);
466
static int findstr (const char *, const char **, int);
467
static int get_threshold (const char **);
468
static const char * maptypename (int);
469
static int32 ApplyMulti (s9xcommand_t *, int32, int16);
470
static void do_polling (int);
471
static void UpdatePolledMouse (int);
472
473
474
static string& operator += (string &s, int i)
475
{
476
snprintf(buf, sizeof(buf), "%d", i);
477
s.append(buf);
478
return (s);
479
}
480
481
static string& operator += (string &s, double d)
482
{
483
snprintf(buf, sizeof(buf), "%g", d);
484
s.append(buf);
485
return (s);
486
}
487
488
static void DisplayStateChange (const char *str, bool8 on)
489
{
490
snprintf(buf, sizeof(buf), "%s: %s", str, on ? "on":"off");
491
S9xSetInfoString(buf);
492
}
493
494
static void DoGunLatch (int x, int y)
495
{
496
x += 40;
497
498
if (x > 295)
499
x = 295;
500
else
501
if (x < 40)
502
x = 40;
503
504
if (y > PPU.ScreenHeight - 1)
505
y = PPU.ScreenHeight - 1;
506
else
507
if (y < 0)
508
y = 0;
509
510
PPU.GunVLatch = (uint16) (y + 1);
511
PPU.GunHLatch = (uint16) x;
512
}
513
514
static int maptype (int t)
515
{
516
switch (t)
517
{
518
case S9xNoMapping:
519
return (MAP_NONE);
520
521
case S9xButtonJoypad:
522
case S9xButtonMouse:
523
case S9xButtonSuperscope:
524
case S9xButtonJustifier:
525
case S9xButtonCommand:
526
case S9xButtonPseudopointer:
527
case S9xButtonPort:
528
case S9xButtonMulti:
529
return (MAP_BUTTON);
530
531
case S9xAxisJoypad:
532
case S9xAxisPseudopointer:
533
case S9xAxisPseudobuttons:
534
case S9xAxisPort:
535
return (MAP_AXIS);
536
537
case S9xPointer:
538
case S9xPointerPort:
539
return (MAP_POINTER);
540
541
default:
542
return (MAP_UNKNOWN);
543
}
544
}
545
546
void S9xControlsReset (void)
547
{
548
S9xControlsSoftReset();
549
mouse[0].buttons &= ~0x30;
550
mouse[1].buttons &= ~0x30;
551
justifier.buttons &= ~JUSTIFIER_SELECT;
552
}
553
554
void S9xControlsSoftReset (void)
555
{
556
for (set<struct exemulti *>::iterator it = exemultis.begin(); it != exemultis.end(); it++)
557
delete *it;
558
exemultis.clear();
559
560
for (int i = 0; i < 2; i++)
561
for (int j = 0; j < 2; j++)
562
read_idx[i][j]=0;
563
564
FLAG_LATCH = FALSE;
565
}
566
567
void S9xUnmapAllControls (void)
568
{
569
S9xControlsReset();
570
571
keymap.clear();
572
573
for (int i = 0; i < (int) multis.size(); i++)
574
free(multis[i]);
575
multis.clear();
576
577
for (int i = 0; i < NUMCTLS + 1; i++)
578
pollmap[i].clear();
579
580
for (int i = 0; i < 8; i++)
581
{
582
pseudopointer[i].x = 0;
583
pseudopointer[i].y = 0;
584
pseudopointer[i].H_adj = 0;
585
pseudopointer[i].V_adj = 0;
586
pseudopointer[i].H_var = 0;
587
pseudopointer[i].V_var = 0;
588
pseudopointer[i].mapped = false;
589
590
joypad[i].buttons = 0;
591
joypad[i].turbos = 0;
592
joypad[i].turbo_ct = 0;
593
}
594
595
for (int i = 0; i < 2; i++)
596
{
597
mouse[i].old_x = mouse[i].old_y = 0;
598
mouse[i].cur_x = mouse[i].cur_y = 0;
599
mouse[i].buttons = 1;
600
mouse[i].ID = InvalidControlID;
601
602
if (!(mouse[i].crosshair.set & 1))
603
mouse[i].crosshair.img = 0; // no image for mouse because its only logical position is game-specific, not known by the emulator
604
if (!(mouse[i].crosshair.set & 2))
605
mouse[i].crosshair.fg = 5;
606
if (!(mouse[i].crosshair.set & 4))
607
mouse[i].crosshair.bg = 1;
608
609
justifier.x[i] = justifier.y[i] = 0;
610
justifier.offscreen[i] = 0;
611
justifier.ID[i] = InvalidControlID;
612
613
if (!(justifier.crosshair[i].set & 1))
614
justifier.crosshair[i].img = 4;
615
if (!(justifier.crosshair[i].set & 2))
616
justifier.crosshair[i].fg = i ? 14 : 12;
617
if (!(justifier.crosshair[i].set & 4))
618
justifier.crosshair[i].bg = 1;
619
}
620
621
justifier.buttons = 0;
622
623
superscope.x = superscope.y = 0;
624
superscope.phys_buttons = 0;
625
superscope.next_buttons = 0;
626
superscope.read_buttons = 0;
627
superscope.ID = InvalidControlID;
628
629
if (!(superscope.crosshair.set & 1))
630
superscope.crosshair.img = 2;
631
if (!(superscope.crosshair.set & 2))
632
superscope.crosshair.fg = 5;
633
if (!(superscope.crosshair.set & 4))
634
superscope.crosshair.bg = 1;
635
636
ZeroMemory(pseudobuttons, sizeof(pseudobuttons));
637
638
turbo_time = 1;
639
}
640
641
void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4)
642
{
643
if (port < 0 || port > 1)
644
return;
645
646
switch (controller)
647
{
648
case CTL_NONE:
649
break;
650
651
case CTL_JOYPAD:
652
if (id1 < 0 || id1 > 7)
653
break;
654
655
newcontrollers[port] = JOYPAD0 + id1;
656
return;
657
658
case CTL_MOUSE:
659
if (id1 < 0 || id1 > 1)
660
break;
661
if (!Settings.MouseMaster)
662
{
663
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled");
664
break;
665
}
666
667
newcontrollers[port] = MOUSE0 + id1;
668
return;
669
670
case CTL_SUPERSCOPE:
671
if (!Settings.SuperScopeMaster)
672
{
673
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled");
674
break;
675
}
676
677
newcontrollers[port] = SUPERSCOPE;
678
return;
679
680
case CTL_JUSTIFIER:
681
if (id1 < 0 || id1 > 1)
682
break;
683
if (!Settings.JustifierMaster)
684
{
685
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled");
686
break;
687
}
688
689
newcontrollers[port] = ONE_JUSTIFIER + id1;
690
return;
691
692
case CTL_MP5:
693
if (id1 < -1 || id1 > 7)
694
break;
695
if (id2 < -1 || id2 > 7)
696
break;
697
if (id3 < -1 || id3 > 7)
698
break;
699
if (id4 < -1 || id4 > 7)
700
break;
701
if (!Settings.MultiPlayer5Master)
702
{
703
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled");
704
break;
705
}
706
707
newcontrollers[port] = MP5;
708
mp5[port].pads[0] = (id1 < 0) ? NONE : JOYPAD0 + id1;
709
mp5[port].pads[1] = (id2 < 0) ? NONE : JOYPAD0 + id2;
710
mp5[port].pads[2] = (id3 < 0) ? NONE : JOYPAD0 + id3;
711
mp5[port].pads[3] = (id4 < 0) ? NONE : JOYPAD0 + id4;
712
return;
713
714
default:
715
fprintf(stderr, "Unknown controller type %d\n", controller);
716
break;
717
}
718
719
newcontrollers[port] = NONE;
720
}
721
722
bool S9xVerifyControllers (void)
723
{
724
bool ret = false;
725
int port, i, used[NUMCTLS];
726
727
for (i = 0; i < NUMCTLS; used[i++] = 0) ;
728
729
for (port = 0; port < 2; port++)
730
{
731
switch (i = newcontrollers[port])
732
{
733
case MOUSE0:
734
case MOUSE1:
735
if (!Settings.MouseMaster)
736
{
737
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled");
738
newcontrollers[port] = NONE;
739
ret = true;
740
break;
741
}
742
743
if (used[i]++ > 0)
744
{
745
snprintf(buf, sizeof(buf), "Mouse%d used more than once! Disabling extra instances", i - MOUSE0 + 1);
746
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
747
newcontrollers[port] = NONE;
748
ret = true;
749
break;
750
}
751
752
break;
753
754
case SUPERSCOPE:
755
if (!Settings.SuperScopeMaster)
756
{
757
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled");
758
newcontrollers[port] = NONE;
759
ret = true;
760
break;
761
}
762
763
if (used[i]++ > 0)
764
{
765
snprintf(buf, sizeof(buf), "Superscope used more than once! Disabling extra instances");
766
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
767
newcontrollers[port] = NONE;
768
ret = true;
769
break;
770
}
771
772
break;
773
774
case ONE_JUSTIFIER:
775
case TWO_JUSTIFIERS:
776
if (!Settings.JustifierMaster)
777
{
778
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled");
779
newcontrollers[port] = NONE;
780
ret = true;
781
break;
782
}
783
784
if (used[ONE_JUSTIFIER]++ > 0)
785
{
786
snprintf(buf, sizeof(buf), "Justifier used more than once! Disabling extra instances");
787
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
788
newcontrollers[port] = NONE;
789
ret = true;
790
break;
791
}
792
793
break;
794
795
case MP5:
796
if (!Settings.MultiPlayer5Master)
797
{
798
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled");
799
newcontrollers[port] = NONE;
800
ret = true;
801
break;
802
}
803
804
for (i = 0; i < 4; i++)
805
{
806
if (mp5[port].pads[i] != NONE)
807
{
808
if (used[mp5[port].pads[i] - JOYPAD0]++ > 0)
809
{
810
snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", mp5[port].pads[i] - JOYPAD0 + 1);
811
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
812
mp5[port].pads[i] = NONE;
813
ret = true;
814
break;
815
}
816
}
817
}
818
819
break;
820
821
case JOYPAD0:
822
case JOYPAD1:
823
case JOYPAD2:
824
case JOYPAD3:
825
case JOYPAD4:
826
case JOYPAD5:
827
case JOYPAD6:
828
case JOYPAD7:
829
if (used[i - JOYPAD0]++ > 0)
830
{
831
snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", i - JOYPAD0 + 1);
832
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
833
newcontrollers[port] = NONE;
834
ret = true;
835
break;
836
}
837
838
break;
839
840
default:
841
break;
842
}
843
}
844
845
return (ret);
846
}
847
848
void S9xGetController (int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4)
849
{
850
int i;
851
852
*controller = CTL_NONE;
853
*id1 = *id2 = *id3 = *id4 = -1;
854
855
if (port < 0 || port > 1)
856
return;
857
858
switch (i = newcontrollers[port])
859
{
860
case MP5:
861
*controller = CTL_MP5;
862
*id1 = (mp5[port].pads[0] == NONE) ? -1 : mp5[port].pads[0] - JOYPAD0;
863
*id2 = (mp5[port].pads[1] == NONE) ? -1 : mp5[port].pads[1] - JOYPAD0;
864
*id3 = (mp5[port].pads[2] == NONE) ? -1 : mp5[port].pads[2] - JOYPAD0;
865
*id4 = (mp5[port].pads[3] == NONE) ? -1 : mp5[port].pads[3] - JOYPAD0;
866
return;
867
868
case JOYPAD0:
869
case JOYPAD1:
870
case JOYPAD2:
871
case JOYPAD3:
872
case JOYPAD4:
873
case JOYPAD5:
874
case JOYPAD6:
875
case JOYPAD7:
876
*controller = CTL_JOYPAD;
877
*id1 = i - JOYPAD0;
878
return;
879
880
case MOUSE0:
881
case MOUSE1:
882
*controller = CTL_MOUSE;
883
*id1 = i - MOUSE0;
884
return;
885
886
case SUPERSCOPE:
887
*controller = CTL_SUPERSCOPE;
888
*id1 = 1;
889
return;
890
891
case ONE_JUSTIFIER:
892
case TWO_JUSTIFIERS:
893
*controller = CTL_JUSTIFIER;
894
*id1 = i - ONE_JUSTIFIER;
895
return;
896
}
897
}
898
899
void S9xReportControllers (void)
900
{
901
static char mes[128];
902
char *c = mes;
903
904
S9xVerifyControllers();
905
906
for (int port = 0; port < 2; port++)
907
{
908
c += sprintf(c, "Port %d: ", port + 1);
909
910
switch (newcontrollers[port])
911
{
912
case NONE:
913
c += sprintf(c, "<none>. ");
914
break;
915
916
case MP5:
917
c += sprintf(c, "MP5 with pads");
918
for (int i = 0; i < 4; i++)
919
{
920
if (mp5[port].pads[i] == NONE)
921
c += sprintf(c, " <none>. ");
922
else
923
c += sprintf(c, " #%d. ", mp5[port].pads[i] + 1 - JOYPAD0);
924
}
925
926
break;
927
928
case JOYPAD0:
929
case JOYPAD1:
930
case JOYPAD2:
931
case JOYPAD3:
932
case JOYPAD4:
933
case JOYPAD5:
934
case JOYPAD6:
935
case JOYPAD7:
936
c += sprintf(c, "Pad #%d. ", (int) (newcontrollers[port] - JOYPAD0 + 1));
937
break;
938
939
case MOUSE0:
940
case MOUSE1:
941
c += sprintf(c, "Mouse #%d. ", (int) (newcontrollers[port] - MOUSE0 + 1));
942
break;
943
944
case SUPERSCOPE:
945
if (port == 0)
946
c += sprintf(c, "Superscope (cannot fire). ");
947
else
948
c += sprintf(c, "Superscope. ");
949
break;
950
951
case ONE_JUSTIFIER:
952
if (port == 0)
953
c += sprintf(c, "Blue Justifier (cannot fire). ");
954
else
955
c += sprintf(c, "Blue Justifier. ");
956
break;
957
958
case TWO_JUSTIFIERS:
959
if (port == 0)
960
c += sprintf(c, "Blue and Pink Justifiers (cannot fire). ");
961
else
962
c += sprintf(c, "Blue and Pink Justifiers. ");
963
break;
964
}
965
}
966
967
S9xMessage(S9X_INFO, S9X_CONFIG_INFO, mes);
968
}
969
970
char * S9xGetCommandName (s9xcommand_t command)
971
{
972
string s;
973
char c;
974
975
switch (command.type)
976
{
977
case S9xButtonJoypad:
978
if (command.input.button.joypad.buttons == 0)
979
return (strdup("None"));
980
if (command.input.button.joypad.buttons & 0x000f)
981
return (strdup("None"));
982
983
s = "Joypad";
984
s += command.input.button.joypad.idx + 1;
985
986
c = ' ';
987
if (command.input.button.joypad.toggle) { if (c) s += c; s += "Toggle"; c = 0; }
988
if (command.input.button.joypad.sticky) { if (c) s += c; s += "Sticky"; c = 0; }
989
if (command.input.button.joypad.turbo ) { if (c) s += c; s += "Turbo"; c = 0; }
990
991
c = ' ';
992
if (command.input.button.joypad.buttons & SNES_UP_MASK ) { s += c; s += "Up"; c = '+'; }
993
if (command.input.button.joypad.buttons & SNES_DOWN_MASK ) { s += c; s += "Down"; c = '+'; }
994
if (command.input.button.joypad.buttons & SNES_LEFT_MASK ) { s += c; s += "Left"; c = '+'; }
995
if (command.input.button.joypad.buttons & SNES_RIGHT_MASK ) { s += c; s += "Right"; c = '+'; }
996
if (command.input.button.joypad.buttons & SNES_A_MASK ) { s += c; s += "A"; c = '+'; }
997
if (command.input.button.joypad.buttons & SNES_B_MASK ) { s += c; s += "B"; c = '+'; }
998
if (command.input.button.joypad.buttons & SNES_X_MASK ) { s += c; s += "X"; c = '+'; }
999
if (command.input.button.joypad.buttons & SNES_Y_MASK ) { s += c; s += "Y"; c = '+'; }
1000
if (command.input.button.joypad.buttons & SNES_TL_MASK ) { s += c; s += "L"; c = '+'; }
1001
if (command.input.button.joypad.buttons & SNES_TR_MASK ) { s += c; s += "R"; c = '+'; }
1002
if (command.input.button.joypad.buttons & SNES_START_MASK ) { s += c; s += "Start"; c = '+'; }
1003
if (command.input.button.joypad.buttons & SNES_SELECT_MASK) { s += c; s += "Select"; c = '+'; }
1004
1005
break;
1006
1007
case S9xButtonMouse:
1008
if (!command.input.button.mouse.left && !command.input.button.mouse.right)
1009
return (strdup("None"));
1010
1011
s = "Mouse";
1012
s += command.input.button.mouse.idx + 1;
1013
s += " ";
1014
1015
if (command.input.button.mouse.left ) s += "L";
1016
if (command.input.button.mouse.right) s += "R";
1017
1018
break;
1019
1020
case S9xButtonSuperscope:
1021
if (!command.input.button.scope.fire && !command.input.button.scope.cursor && !command.input.button.scope.turbo && !command.input.button.scope.pause && !command.input.button.scope.aim_offscreen)
1022
return (strdup("None"));
1023
1024
s = "Superscope";
1025
1026
if (command.input.button.scope.aim_offscreen) s += " AimOffscreen";
1027
1028
c = ' ';
1029
if (command.input.button.scope.fire ) { s += c; s += "Fire"; c = '+'; }
1030
if (command.input.button.scope.cursor) { s += c; s += "Cursor"; c = '+'; }
1031
if (command.input.button.scope.turbo ) { s += c; s += "ToggleTurbo"; c = '+'; }
1032
if (command.input.button.scope.pause ) { s += c; s += "Pause"; c = '+'; }
1033
1034
break;
1035
1036
case S9xButtonJustifier:
1037
if (!command.input.button.justifier.trigger && !command.input.button.justifier.start && !command.input.button.justifier.aim_offscreen)
1038
return (strdup("None"));
1039
1040
s = "Justifier";
1041
s += command.input.button.justifier.idx + 1;
1042
1043
if (command.input.button.justifier.aim_offscreen) s += " AimOffscreen";
1044
1045
c = ' ';
1046
if (command.input.button.justifier.trigger) { s += c; s += "Trigger"; c = '+'; }
1047
if (command.input.button.justifier.start ) { s += c; s += "Start"; c = '+'; }
1048
1049
break;
1050
1051
case S9xButtonCommand:
1052
if (command.input.button.command >= LAST_COMMAND)
1053
return (strdup("None"));
1054
1055
return (strdup(command_names[command.input.button.command]));
1056
1057
case S9xPointer:
1058
if (!command.input.pointer.aim_mouse0 && !command.input.pointer.aim_mouse1 && !command.input.pointer.aim_scope && !command.input.pointer.aim_justifier0 && !command.input.pointer.aim_justifier1)
1059
return (strdup("None"));
1060
1061
s = "Pointer";
1062
1063
c = ' ';
1064
if (command.input.pointer.aim_mouse0 ) { s += c; s += "Mouse1"; c = '+'; }
1065
if (command.input.pointer.aim_mouse1 ) { s += c; s += "Mouse2"; c = '+'; }
1066
if (command.input.pointer.aim_scope ) { s += c; s += "Superscope"; c = '+'; }
1067
if (command.input.pointer.aim_justifier0) { s += c; s += "Justifier1"; c = '+'; }
1068
if (command.input.pointer.aim_justifier1) { s += c; s += "Justifier2"; c = '+'; }
1069
1070
break;
1071
1072
case S9xButtonPseudopointer:
1073
if (!command.input.button.pointer.UD && !command.input.button.pointer.LR)
1074
return (strdup("None"));
1075
if (command.input.button.pointer.UD == -2 || command.input.button.pointer.LR == -2)
1076
return (strdup("None"));
1077
1078
s = "ButtonToPointer ";
1079
s += command.input.button.pointer.idx + 1;
1080
1081
if (command.input.button.pointer.UD) s += (command.input.button.pointer.UD == 1) ? 'd' : 'u';
1082
if (command.input.button.pointer.LR) s += (command.input.button.pointer.LR == 1) ? 'r' : 'l';
1083
1084
s += " ";
1085
s += speed_names[command.input.button.pointer.speed_type];
1086
1087
break;
1088
1089
case S9xAxisJoypad:
1090
s = "Joypad";
1091
s += command.input.axis.joypad.idx + 1;
1092
s += " Axis ";
1093
1094
switch (command.input.axis.joypad.axis)
1095
{
1096
case 0: s += (command.input.axis.joypad.invert ? "Right/Left" : "Left/Right"); break;
1097
case 1: s += (command.input.axis.joypad.invert ? "Down/Up" : "Up/Down" ); break;
1098
case 2: s += (command.input.axis.joypad.invert ? "A/Y" : "Y/A" ); break;
1099
case 3: s += (command.input.axis.joypad.invert ? "B/X" : "X/B" ); break;
1100
case 4: s += (command.input.axis.joypad.invert ? "R/L" : "L/R" ); break;
1101
default: return (strdup("None"));
1102
}
1103
1104
s += " T=";
1105
s += int((command.input.axis.joypad.threshold + 1) * 1000 / 256) / 10.0;
1106
s += "%";
1107
1108
break;
1109
1110
case S9xAxisPseudopointer:
1111
s = "AxisToPointer ";
1112
s += command.input.axis.pointer.idx + 1;
1113
s += command.input.axis.pointer.HV ? 'v' : 'h';
1114
s += " ";
1115
1116
if (command.input.axis.pointer.invert) s += "-";
1117
1118
s += speed_names[command.input.axis.pointer.speed_type];
1119
1120
break;
1121
1122
case S9xAxisPseudobuttons:
1123
s = "AxisToButtons ";
1124
s += command.input.axis.button.negbutton;
1125
s += "/";
1126
s += command.input.axis.button.posbutton;
1127
s += " T=";
1128
s += int((command.input.axis.button.threshold + 1) * 1000 / 256) / 10.0;
1129
s += "%";
1130
1131
break;
1132
1133
case S9xButtonPort:
1134
case S9xAxisPort:
1135
case S9xPointerPort:
1136
return (strdup("BUG: Port should have handled this instead of calling S9xGetCommandName()"));
1137
1138
case S9xNoMapping:
1139
return (strdup("None"));
1140
1141
case S9xButtonMulti:
1142
{
1143
if (command.input.button.multi_idx >= (int) multis.size())
1144
return (strdup("None"));
1145
1146
s = "{";
1147
if (multis[command.input.button.multi_idx]->multi_press) s = "+{";
1148
1149
bool sep = false;
1150
1151
for (s9xcommand_t *m = multis[command.input.button.multi_idx]; m->multi_press != 3; m++)
1152
{
1153
if (m->type == S9xNoMapping)
1154
{
1155
s += ";";
1156
sep = false;
1157
}
1158
else
1159
{
1160
if (sep) s += ",";
1161
if (m->multi_press == 1) s += "+";
1162
if (m->multi_press == 2) s += "-";
1163
1164
s += S9xGetCommandName(*m);
1165
sep = true;
1166
}
1167
}
1168
1169
s += "}";
1170
1171
break;
1172
}
1173
1174
default:
1175
return (strdup("BUG: Unknown command type"));
1176
}
1177
1178
return (strdup(s.c_str()));
1179
}
1180
1181
static bool strless (const char *a, const char *b)
1182
{
1183
return (strcmp(a, b) < 0);
1184
}
1185
1186
static int findstr (const char *needle, const char **haystack, int numstr)
1187
{
1188
const char **r;
1189
1190
r = lower_bound(haystack, haystack + numstr, needle, strless);
1191
if (r >= haystack + numstr || strcmp(needle, *r))
1192
return (-1);
1193
1194
return (r - haystack);
1195
}
1196
1197
static int get_threshold (const char **ss)
1198
{
1199
const char *s = *ss;
1200
int i;
1201
1202
if (s[0] != 'T' || s[1] != '=')
1203
return (-1);
1204
1205
s += 2;
1206
i = 0;
1207
1208
if (s[0] == '0')
1209
{
1210
if (s[1] != '.')
1211
return (-1);
1212
1213
s++;
1214
}
1215
else
1216
{
1217
do
1218
{
1219
if (*s < '0' || *s > '9')
1220
return (-1);
1221
1222
i = i * 10 + 10 * (*s - '0');
1223
if (i > 1000)
1224
return (-1);
1225
1226
s++;
1227
}
1228
while (*s != '.' && *s != '%');
1229
}
1230
1231
if (*s == '.')
1232
{
1233
if (s[1] < '0' || s[1] > '9' || s[2] != '%')
1234
return (-1);
1235
1236
i += s[1] - '0';
1237
}
1238
1239
if (i > 1000)
1240
return (-1);
1241
1242
*ss = s;
1243
1244
return (i);
1245
}
1246
1247
s9xcommand_t S9xGetCommandT (const char *name)
1248
{
1249
s9xcommand_t cmd;
1250
int i, j;
1251
const char *s;
1252
1253
ZeroMemory(&cmd, sizeof(cmd));
1254
cmd.type = S9xBadMapping;
1255
cmd.multi_press = 0;
1256
cmd.button_norpt = 0;
1257
1258
if (!strcmp(name, "None"))
1259
cmd.type = S9xNoMapping;
1260
else
1261
if (!strncmp(name, "Joypad", 6))
1262
{
1263
if (name[6] < '1' || name[6] > '8' || name[7] != ' ')
1264
return (cmd);
1265
1266
if (!strncmp(name + 8, "Axis ", 5))
1267
{
1268
cmd.input.axis.joypad.idx = name[6] - '1';
1269
s = name + 13;
1270
1271
if (!strncmp(s, "Left/Right ", 11)) { j = 0; i = 0; s += 11; }
1272
else
1273
if (!strncmp(s, "Right/Left ", 11)) { j = 0; i = 1; s += 11; }
1274
else
1275
if (!strncmp(s, "Up/Down ", 8)) { j = 1; i = 0; s += 8; }
1276
else
1277
if (!strncmp(s, "Down/Up ", 8)) { j = 1; i = 1; s += 8; }
1278
else
1279
if (!strncmp(s, "Y/A ", 4)) { j = 2; i = 0; s += 4; }
1280
else
1281
if (!strncmp(s, "A/Y ", 4)) { j = 2; i = 1; s += 4; }
1282
else
1283
if (!strncmp(s, "X/B ", 4)) { j = 3; i = 0; s += 4; }
1284
else
1285
if (!strncmp(s, "B/X ", 4)) { j = 3; i = 1; s += 4; }
1286
else
1287
if (!strncmp(s, "L/R ", 4)) { j = 4; i = 0; s += 4; }
1288
else
1289
if (!strncmp(s, "R/L ", 4)) { j = 4; i = 1; s += 4; }
1290
else
1291
return (cmd);
1292
1293
cmd.input.axis.joypad.axis = j;
1294
cmd.input.axis.joypad.invert = i;
1295
i = get_threshold(&s);
1296
if (i < 0)
1297
return (cmd);
1298
cmd.input.axis.joypad.threshold = (i - 1) * 256 / 1000;
1299
1300
cmd.type = S9xAxisJoypad;
1301
}
1302
else
1303
{
1304
cmd.input.button.joypad.idx = name[6] - '1';
1305
s = name + 8;
1306
i = 0;
1307
1308
if ((cmd.input.button.joypad.toggle = strncmp(s, "Toggle", 6) ? 0 : 1)) s += i = 6;
1309
if ((cmd.input.button.joypad.sticky = strncmp(s, "Sticky", 6) ? 0 : 1)) s += i = 6;
1310
if ((cmd.input.button.joypad.turbo = strncmp(s, "Turbo", 5) ? 0 : 1)) s += i = 5;
1311
1312
if (cmd.input.button.joypad.toggle && !(cmd.input.button.joypad.sticky || cmd.input.button.joypad.turbo))
1313
return (cmd);
1314
1315
if (i)
1316
{
1317
if (*s != ' ')
1318
return (cmd);
1319
s++;
1320
}
1321
1322
i = 0;
1323
1324
if (!strncmp(s, "Up", 2)) { i |= SNES_UP_MASK; s += 2; if (*s == '+') s++; }
1325
if (!strncmp(s, "Down", 4)) { i |= SNES_DOWN_MASK; s += 4; if (*s == '+') s++; }
1326
if (!strncmp(s, "Left", 4)) { i |= SNES_LEFT_MASK; s += 4; if (*s == '+') s++; }
1327
if (!strncmp(s, "Right", 5)) { i |= SNES_RIGHT_MASK; s += 5; if (*s == '+') s++; }
1328
1329
if (*s == 'A') { i |= SNES_A_MASK; s++; if (*s == '+') s++; }
1330
if (*s == 'B') { i |= SNES_B_MASK; s++; if (*s == '+') s++; }
1331
if (*s == 'X') { i |= SNES_X_MASK; s++; if (*s == '+') s++; }
1332
if (*s == 'Y') { i |= SNES_Y_MASK; s++; if (*s == '+') s++; }
1333
if (*s == 'L') { i |= SNES_TL_MASK; s++; if (*s == '+') s++; }
1334
if (*s == 'R') { i |= SNES_TR_MASK; s++; if (*s == '+') s++; }
1335
1336
if (!strncmp(s, "Start", 5)) { i |= SNES_START_MASK; s += 5; if (*s == '+') s++; }
1337
if (!strncmp(s, "Select", 6)) { i |= SNES_SELECT_MASK; s += 6; }
1338
1339
if (i == 0 || *s != 0 || *(s - 1) == '+')
1340
return (cmd);
1341
1342
cmd.input.button.joypad.buttons = i;
1343
1344
cmd.type = S9xButtonJoypad;
1345
}
1346
}
1347
else
1348
if (!strncmp(name, "Mouse", 5))
1349
{
1350
if (name[5] < '1' || name[5] > '2' || name[6] != ' ')
1351
return (cmd);
1352
1353
cmd.input.button.mouse.idx = name[5] - '1';
1354
s = name + 7;
1355
i = 0;
1356
1357
if ((cmd.input.button.mouse.left = (*s == 'L'))) s += i = 1;
1358
if ((cmd.input.button.mouse.right = (*s == 'R'))) s += i = 1;
1359
1360
if (i == 0 || *s != 0)
1361
return (cmd);
1362
1363
cmd.type = S9xButtonMouse;
1364
}
1365
else
1366
if (!strncmp(name, "Superscope ", 11))
1367
{
1368
s = name + 11;
1369
i = 0;
1370
1371
if ((cmd.input.button.scope.aim_offscreen = strncmp(s, "AimOffscreen", 12) ? 0 : 1)) { s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); }
1372
if ((cmd.input.button.scope.fire = strncmp(s, "Fire", 4) ? 0 : 1)) { s += i = 4; if (*s == '+') s++; }
1373
if ((cmd.input.button.scope.cursor = strncmp(s, "Cursor", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; }
1374
if ((cmd.input.button.scope.turbo = strncmp(s, "ToggleTurbo", 11) ? 0 : 1)) { s += i = 11; if (*s == '+') s++; }
1375
if ((cmd.input.button.scope.pause = strncmp(s, "Pause", 5) ? 0 : 1)) { s += i = 5; }
1376
1377
if (i == 0 || *s != 0 || *(s - 1) == '+')
1378
return (cmd);
1379
1380
cmd.type = S9xButtonSuperscope;
1381
}
1382
else
1383
if (!strncmp(name, "Justifier", 9))
1384
{
1385
if (name[9] < '1' || name[9] > '2' || name[10] != ' ')
1386
return (cmd);
1387
1388
cmd.input.button.justifier.idx = name[9] - '1';
1389
s = name + 11;
1390
i = 0;
1391
1392
if ((cmd.input.button.justifier.aim_offscreen = strncmp(s, "AimOffscreen", 12) ? 0 : 1)) { s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); }
1393
if ((cmd.input.button.justifier.trigger = strncmp(s, "Trigger", 7) ? 0 : 1)) { s += i = 7; if (*s == '+') s++; }
1394
if ((cmd.input.button.justifier.start = strncmp(s, "Start", 5) ? 0 : 1)) { s += i = 5; }
1395
1396
if (i == 0 || *s != 0 || *(s - 1) == '+')
1397
return (cmd);
1398
1399
cmd.type = S9xButtonJustifier;
1400
}
1401
else
1402
if (!strncmp(name, "Pointer ", 8))
1403
{
1404
s = name + 8;
1405
i = 0;
1406
1407
if ((cmd.input.pointer.aim_mouse0 = strncmp(s, "Mouse1", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; }
1408
if ((cmd.input.pointer.aim_mouse1 = strncmp(s, "Mouse2", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; }
1409
if ((cmd.input.pointer.aim_scope = strncmp(s, "Superscope", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; }
1410
if ((cmd.input.pointer.aim_justifier0 = strncmp(s, "Justifier1", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; }
1411
if ((cmd.input.pointer.aim_justifier1 = strncmp(s, "Justifier2", 10) ? 0 : 1)) { s += i = 10; }
1412
1413
if (i == 0 || *s != 0 || *(s - 1) == '+')
1414
return (cmd);
1415
1416
cmd.type = S9xPointer;
1417
}
1418
else
1419
if (!strncmp(name, "ButtonToPointer ", 16))
1420
{
1421
if (name[16] < '1' || name[16] > '8')
1422
return (cmd);
1423
1424
cmd.input.button.pointer.idx = name[16] - '1';
1425
s = name + 17;
1426
i = 0;
1427
1428
if ((cmd.input.button.pointer.UD = (*s == 'u' ? -1 : (*s == 'd' ? 1 : 0)))) s += i = 1;
1429
if ((cmd.input.button.pointer.LR = (*s == 'l' ? -1 : (*s == 'r' ? 1 : 0)))) s += i = 1;
1430
1431
if (i == 0 || *(s++) != ' ')
1432
return (cmd);
1433
1434
for (i = 0; i < 4; i++)
1435
if (!strcmp(s, speed_names[i]))
1436
break;
1437
if (i > 3)
1438
return (cmd);
1439
1440
cmd.input.button.pointer.speed_type = i;
1441
1442
cmd.type = S9xButtonPseudopointer;
1443
}
1444
else
1445
if (!strncmp(name, "AxisToPointer ", 14))
1446
{
1447
if (name[14] < '1' || name[14] > '8')
1448
return (cmd);
1449
1450
cmd.input.axis.pointer.idx = name[14] - '1';
1451
s= name + 15;
1452
i = 0;
1453
1454
if (*s == 'h')
1455
cmd.input.axis.pointer.HV = 0;
1456
else
1457
if (*s == 'v')
1458
cmd.input.axis.pointer.HV = 1;
1459
else
1460
return (cmd);
1461
1462
if (s[1] != ' ')
1463
return (cmd);
1464
1465
s += 2;
1466
if ((cmd.input.axis.pointer.invert = *s == '-'))
1467
s++;
1468
1469
for (i = 0; i < 4; i++)
1470
if (!strcmp(s, speed_names[i]))
1471
break;
1472
if (i > 3)
1473
return (cmd);
1474
1475
cmd.input.axis.pointer.speed_type = i;
1476
1477
cmd.type = S9xAxisPseudopointer;
1478
}
1479
else
1480
if (!strncmp(name, "AxisToButtons ", 14))
1481
{
1482
s = name + 14;
1483
1484
if (s[0] == '0')
1485
{
1486
if (s[1] != '/')
1487
return (cmd);
1488
1489
cmd.input.axis.button.negbutton = 0;
1490
s += 2;
1491
}
1492
else
1493
{
1494
i = 0;
1495
do
1496
{
1497
if (*s < '0' || *s > '9')
1498
return (cmd);
1499
1500
i = i * 10 + *s - '0';
1501
if (i > 255)
1502
return (cmd);
1503
}
1504
while (*++s != '/');
1505
1506
cmd.input.axis.button.negbutton = i;
1507
s++;
1508
}
1509
1510
if (s[0] == '0')
1511
{
1512
if (s[1] != ' ')
1513
return (cmd);
1514
1515
cmd.input.axis.button.posbutton = 0;
1516
s += 2;
1517
}
1518
else
1519
{
1520
i = 0;
1521
do
1522
{
1523
if (*s < '0' || *s > '9')
1524
return (cmd);
1525
1526
i = i * 10 + *s - '0';
1527
if (i > 255)
1528
return (cmd);
1529
}
1530
while (*++s != ' ');
1531
1532
cmd.input.axis.button.posbutton = i;
1533
s++;
1534
}
1535
1536
i = get_threshold(&s);
1537
if (i < 0)
1538
return (cmd);
1539
cmd.input.axis.button.threshold = (i - 1) * 256 / 1000;
1540
1541
cmd.type = S9xAxisPseudobuttons;
1542
}
1543
else
1544
if (!strncmp(name, "MULTI#", 6))
1545
{
1546
i = strtol(name + 6, (char **) &s, 10);
1547
if (s != NULL && *s != '\0')
1548
return (cmd);
1549
if (i >= (int) multis.size())
1550
return (cmd);
1551
1552
cmd.input.button.multi_idx = i;
1553
cmd.type = S9xButtonMulti;
1554
}
1555
else
1556
if (((name[0] == '+' && name[1] == '{') || name[0] == '{') && name[strlen(name) - 1] == '}')
1557
{
1558
if (multis.size() > 2147483640)
1559
{
1560
fprintf(stderr, "Too many multis!");
1561
return (cmd);
1562
}
1563
1564
string x;
1565
int n;
1566
1567
j = 2;
1568
for (i = (name[0] == '+') ? 2 : 1; name[i] != '\0'; i++)
1569
{
1570
if (name[i] == ',' || name[i] == ';')
1571
{
1572
if (name[i] == ';')
1573
j++;
1574
if (++j > 2147483640)
1575
{
1576
fprintf(stderr, "Multi too long!");
1577
return (cmd);
1578
}
1579
}
1580
1581
if (name[i] == '{')
1582
return (cmd);
1583
}
1584
1585
s9xcommand_t *c = (s9xcommand_t *) calloc(j, sizeof(s9xcommand_t));
1586
if (c == NULL)
1587
{
1588
perror("malloc error while parsing multi");
1589
return (cmd);
1590
}
1591
1592
n = 0;
1593
i = (name[0] == '+') ? 2 : 1;
1594
1595
do
1596
{
1597
if (name[i] == ';')
1598
{
1599
c[n].type = S9xNoMapping;
1600
c[n].multi_press = 0;
1601
c[n].button_norpt = 0;
1602
1603
j = i;
1604
}
1605
else
1606
if (name[i] == ',')
1607
{
1608
free(c);
1609
return (cmd);
1610
}
1611
else
1612
{
1613
uint8 press = 0;
1614
1615
if (name[0] == '+')
1616
{
1617
if (name[i] == '+')
1618
press = 1;
1619
else
1620
if (name[i] == '-')
1621
press = 2;
1622
else
1623
{
1624
free(c);
1625
return (cmd);
1626
}
1627
1628
i++;
1629
}
1630
1631
for (j = i; name[j] != ';' && name[j] != ',' && name[j] != '}'; j++) ;
1632
1633
x.assign(name + i, j - i);
1634
c[n] = S9xGetCommandT(x.c_str());
1635
c[n].multi_press = press;
1636
1637
if (maptype(c[n].type) != MAP_BUTTON)
1638
{
1639
free(c);
1640
return (cmd);
1641
}
1642
1643
if (name[j] == ';')
1644
j--;
1645
}
1646
1647
i = j + 1;
1648
n++;
1649
}
1650
while (name[i] != '\0');
1651
1652
c[n].type = S9xNoMapping;
1653
c[n].multi_press = 3;
1654
1655
multis.push_back(c);
1656
1657
cmd.input.button.multi_idx = multis.size() - 1;
1658
cmd.type = S9xButtonMulti;
1659
}
1660
else
1661
{
1662
i = findstr(name, command_names, LAST_COMMAND);
1663
if (i < 0)
1664
return (cmd);
1665
1666
cmd.type = S9xButtonCommand;
1667
cmd.input.button.command = i;
1668
}
1669
1670
return (cmd);
1671
}
1672
1673
const char ** S9xGetAllSnes9xCommands (void)
1674
{
1675
return (command_names);
1676
}
1677
1678
s9xcommand_t S9xGetMapping (uint32 id)
1679
{
1680
if (keymap.count(id) == 0)
1681
{
1682
s9xcommand_t cmd;
1683
cmd.type = S9xNoMapping;
1684
return (cmd);
1685
}
1686
else
1687
return (keymap[id]);
1688
}
1689
1690
static const char * maptypename (int t)
1691
{
1692
switch (t)
1693
{
1694
case MAP_NONE: return ("unmapped");
1695
case MAP_BUTTON: return ("button");
1696
case MAP_AXIS: return ("axis");
1697
case MAP_POINTER: return ("pointer");
1698
default: return ("unknown");
1699
}
1700
}
1701
1702
void S9xUnmapID (uint32 id)
1703
{
1704
for (int i = 0; i < NUMCTLS + 1; i++)
1705
pollmap[i].erase(id);
1706
1707
if (mouse[0].ID == id) mouse[0].ID = InvalidControlID;
1708
if (mouse[1].ID == id) mouse[1].ID = InvalidControlID;
1709
if (superscope.ID == id) superscope.ID = InvalidControlID;
1710
if (justifier.ID[0] == id) justifier.ID[0] = InvalidControlID;
1711
if (justifier.ID[1] == id) justifier.ID[1] = InvalidControlID;
1712
1713
if (id >= PseudoPointerBase)
1714
pseudopointer[id - PseudoPointerBase].mapped = false;
1715
1716
keymap.erase(id);
1717
}
1718
1719
bool S9xMapButton (uint32 id, s9xcommand_t mapping, bool poll)
1720
{
1721
int t;
1722
1723
if (id == InvalidControlID)
1724
{
1725
fprintf(stderr, "Cannot map InvalidControlID\n");
1726
return (false);
1727
}
1728
1729
t = maptype(mapping.type);
1730
1731
if (t == MAP_NONE)
1732
{
1733
S9xUnmapID(id);
1734
return (true);
1735
}
1736
1737
if (t != MAP_BUTTON)
1738
return (false);
1739
1740
t = maptype(S9xGetMapping(id).type);
1741
1742
if (t != MAP_NONE && t != MAP_BUTTON)
1743
fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to button\n", id, maptypename(t));
1744
1745
if (id >= PseudoPointerBase)
1746
{
1747
fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as a button\n", id - PseudoPointerBase);
1748
return (false);
1749
}
1750
1751
t = -1;
1752
1753
if (poll)
1754
{
1755
if (id >= PseudoButtonBase)
1756
fprintf(stderr, "INFO: Ignoring attempt to set pseudo-button #%d to polling\n", id - PseudoButtonBase);
1757
else
1758
{
1759
switch (mapping.type)
1760
{
1761
case S9xButtonJoypad:
1762
t = JOYPAD0 + mapping.input.button.joypad.idx;
1763
break;
1764
1765
case S9xButtonMouse:
1766
t = MOUSE0 + mapping.input.button.mouse.idx;
1767
break;
1768
1769
case S9xButtonSuperscope:
1770
t = SUPERSCOPE;
1771
break;
1772
1773
case S9xButtonJustifier:
1774
t = ONE_JUSTIFIER + mapping.input.button.justifier.idx;
1775
break;
1776
1777
case S9xButtonCommand:
1778
case S9xButtonPseudopointer:
1779
case S9xButtonPort:
1780
case S9xButtonMulti:
1781
t = POLL_ALL;
1782
break;
1783
}
1784
}
1785
}
1786
1787
S9xUnmapID(id);
1788
1789
keymap[id] = mapping;
1790
1791
if (t >= 0)
1792
pollmap[t].insert(id);
1793
1794
return (true);
1795
}
1796
1797
void S9xReportButton (uint32 id, bool pressed)
1798
{
1799
if (keymap.count(id) == 0)
1800
return;
1801
1802
if (keymap[id].type == S9xNoMapping)
1803
return;
1804
1805
if (maptype(keymap[id].type) != MAP_BUTTON)
1806
{
1807
fprintf(stderr, "ERROR: S9xReportButton called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
1808
return;
1809
}
1810
1811
if (keymap[id].type == S9xButtonCommand) // skips the "already-pressed check" unless it's a command, as a hack to work around the following problem:
1812
if (keymap[id].button_norpt == pressed) // FIXME: this makes the controls "stick" after loading a savestate while recording a movie and holding any button
1813
return;
1814
1815
keymap[id].button_norpt = pressed;
1816
1817
S9xApplyCommand(keymap[id], pressed, 0);
1818
}
1819
1820
bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll)
1821
{
1822
int t;
1823
1824
if (id == InvalidControlID)
1825
{
1826
fprintf(stderr, "Cannot map InvalidControlID\n");
1827
return (false);
1828
}
1829
1830
t = maptype(mapping.type);
1831
1832
if (t == MAP_NONE)
1833
{
1834
S9xUnmapID(id);
1835
return (true);
1836
}
1837
1838
if (t != MAP_POINTER)
1839
return (false);
1840
1841
t = maptype(S9xGetMapping(id).type);
1842
1843
if (t != MAP_NONE && t != MAP_POINTER)
1844
fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to pointer\n", id, maptypename(t));
1845
1846
if (id < PseudoPointerBase && id >= PseudoButtonBase)
1847
{
1848
fprintf(stderr, "ERROR: Refusing to map pseudo-button #%d as a pointer\n", id - PseudoButtonBase);
1849
return (false);
1850
}
1851
1852
if (mapping.type == S9xPointer)
1853
{
1854
if (mapping.input.pointer.aim_mouse0 && mouse[0].ID != InvalidControlID && mouse[0].ID != id)
1855
{
1856
fprintf(stderr, "ERROR: Rejecting attempt to control Mouse1 with two pointers\n");
1857
return (false);
1858
}
1859
1860
if (mapping.input.pointer.aim_mouse1 && mouse[1].ID != InvalidControlID && mouse[1].ID != id)
1861
{
1862
fprintf(stderr, "ERROR: Rejecting attempt to control Mouse2 with two pointers\n");
1863
return (false);
1864
}
1865
1866
if (mapping.input.pointer.aim_scope && superscope.ID != InvalidControlID && superscope.ID != id)
1867
{
1868
fprintf(stderr, "ERROR: Rejecting attempt to control SuperScope with two pointers\n");
1869
return (false);
1870
}
1871
1872
if (mapping.input.pointer.aim_justifier0 && justifier.ID[0] != InvalidControlID && justifier.ID[0] != id)
1873
{
1874
fprintf(stderr, "ERROR: Rejecting attempt to control Justifier1 with two pointers\n");
1875
return (false);
1876
}
1877
1878
if (mapping.input.pointer.aim_justifier1 && justifier.ID[1] != InvalidControlID && justifier.ID[1] != id)
1879
{
1880
fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n");
1881
return (false);
1882
}
1883
}
1884
1885
S9xUnmapID(id);
1886
1887
if (poll)
1888
{
1889
if (id >= PseudoPointerBase)
1890
fprintf(stderr, "INFO: Ignoring attempt to set pseudo-pointer #%d to polling\n", id - PseudoPointerBase);
1891
else
1892
{
1893
switch (mapping.type)
1894
{
1895
case S9xPointer:
1896
if (mapping.input.pointer.aim_mouse0 ) pollmap[MOUSE0 ].insert(id);
1897
if (mapping.input.pointer.aim_mouse1 ) pollmap[MOUSE1 ].insert(id);
1898
if (mapping.input.pointer.aim_scope ) pollmap[SUPERSCOPE ].insert(id);
1899
if (mapping.input.pointer.aim_justifier0) pollmap[ONE_JUSTIFIER ].insert(id);
1900
if (mapping.input.pointer.aim_justifier1) pollmap[TWO_JUSTIFIERS].insert(id);
1901
break;
1902
1903
case S9xPointerPort:
1904
pollmap[POLL_ALL].insert(id);
1905
break;
1906
}
1907
}
1908
}
1909
1910
if (id >= PseudoPointerBase)
1911
pseudopointer[id - PseudoPointerBase].mapped = true;
1912
1913
keymap[id] = mapping;
1914
1915
if (mapping.input.pointer.aim_mouse0 ) mouse[0].ID = id;
1916
if (mapping.input.pointer.aim_mouse1 ) mouse[1].ID = id;
1917
if (mapping.input.pointer.aim_scope ) superscope.ID = id;
1918
if (mapping.input.pointer.aim_justifier0) justifier.ID[0] = id;
1919
if (mapping.input.pointer.aim_justifier1) justifier.ID[1] = id;
1920
1921
return (true);
1922
}
1923
1924
void S9xReportPointer (uint32 id, int16 x, int16 y)
1925
{
1926
if (keymap.count(id) == 0)
1927
return;
1928
1929
if (keymap[id].type == S9xNoMapping)
1930
return;
1931
1932
if (maptype(keymap[id].type) != MAP_POINTER)
1933
{
1934
fprintf(stderr, "ERROR: S9xReportPointer called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
1935
return;
1936
}
1937
1938
S9xApplyCommand(keymap[id], x, y);
1939
}
1940
1941
bool S9xMapAxis (uint32 id, s9xcommand_t mapping, bool poll)
1942
{
1943
int t;
1944
1945
if (id == InvalidControlID)
1946
{
1947
fprintf(stderr, "Cannot map InvalidControlID\n");
1948
return (false);
1949
}
1950
1951
t = maptype(mapping.type);
1952
1953
if (t == MAP_NONE)
1954
{
1955
S9xUnmapID(id);
1956
return (true);
1957
}
1958
1959
if (t != MAP_AXIS)
1960
return (false);
1961
1962
t = maptype(S9xGetMapping(id).type);
1963
1964
if (t != MAP_NONE && t != MAP_AXIS)
1965
fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to axis\n", id, maptypename(t));
1966
1967
if (id >= PseudoPointerBase)
1968
{
1969
fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as an axis\n", id - PseudoPointerBase);
1970
return (false);
1971
}
1972
1973
t = -1;
1974
1975
if (poll)
1976
{
1977
switch (mapping.type)
1978
{
1979
case S9xAxisJoypad:
1980
t = JOYPAD0 + mapping.input.axis.joypad.idx;
1981
break;
1982
1983
case S9xAxisPseudopointer:
1984
case S9xAxisPseudobuttons:
1985
case S9xAxisPort:
1986
t=POLL_ALL;
1987
break;
1988
}
1989
}
1990
1991
S9xUnmapID(id);
1992
1993
keymap[id] = mapping;
1994
1995
if (t >= 0)
1996
pollmap[t].insert(id);
1997
1998
return (true);
1999
}
2000
2001
void S9xReportAxis (uint32 id, int16 value)
2002
{
2003
if (keymap.count(id) == 0)
2004
return;
2005
2006
if (keymap[id].type == S9xNoMapping)
2007
return;
2008
2009
if (maptype(keymap[id].type) != MAP_AXIS)
2010
{
2011
fprintf(stderr, "ERROR: S9xReportAxis called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
2012
return;
2013
}
2014
2015
S9xApplyCommand(keymap[id], value, 0);
2016
}
2017
2018
static int32 ApplyMulti (s9xcommand_t *multi, int32 pos, int16 data1)
2019
{
2020
while (1)
2021
{
2022
if (multi[pos].multi_press == 3)
2023
return (-1);
2024
2025
if (multi[pos].type == S9xNoMapping)
2026
break;
2027
2028
if (multi[pos].multi_press)
2029
S9xApplyCommand(multi[pos], multi[pos].multi_press == 1, 0);
2030
else
2031
S9xApplyCommand(multi[pos], data1, 0);
2032
2033
pos++;
2034
}
2035
2036
return (pos + 1);
2037
}
2038
2039
void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
2040
{
2041
int i;
2042
2043
switch (cmd.type)
2044
{
2045
case S9xNoMapping:
2046
return;
2047
2048
case S9xButtonJoypad:
2049
if (cmd.input.button.joypad.toggle)
2050
{
2051
if (!data1)
2052
return;
2053
2054
uint16 r = cmd.input.button.joypad.buttons;
2055
2056
if (cmd.input.button.joypad.turbo) joypad[cmd.input.button.joypad.idx].toggleturbo ^= r;
2057
if (cmd.input.button.joypad.sticky) joypad[cmd.input.button.joypad.idx].togglestick ^= r;
2058
}
2059
else
2060
{
2061
uint16 r, s, t, st;
2062
2063
s = t = st = 0;
2064
r = cmd.input.button.joypad.buttons;
2065
st = r & joypad[cmd.input.button.joypad.idx].togglestick & joypad[cmd.input.button.joypad.idx].toggleturbo;
2066
r ^= st;
2067
t = r & joypad[cmd.input.button.joypad.idx].toggleturbo;
2068
r ^= t;
2069
s = r & joypad[cmd.input.button.joypad.idx].togglestick;
2070
r ^= s;
2071
2072
if (cmd.input.button.joypad.turbo && cmd.input.button.joypad.sticky)
2073
{
2074
uint16 x = r; r = st; st = x;
2075
x = s; s = t; t = x;
2076
}
2077
else
2078
if (cmd.input.button.joypad.turbo)
2079
{
2080
uint16 x = r; r = t; t = x;
2081
x = s; s = st; st = x;
2082
}
2083
else
2084
if (cmd.input.button.joypad.sticky)
2085
{
2086
uint16 x = r; r = s; s = x;
2087
x = t; t = st; st = x;
2088
}
2089
2090
if (data1)
2091
{
2092
if (!Settings.UpAndDown && !S9xMoviePlaying()) // if up+down isn't allowed AND we are NOT playing a movie,
2093
{
2094
if (cmd.input.button.joypad.buttons & (SNES_LEFT_MASK | SNES_RIGHT_MASK))
2095
{
2096
// if we're pressing left or right, then unpress and unturbo them both first
2097
// so we don't end up hittnig left AND right accidentally.
2098
// Note though that the user can still do it on purpose, if Settings.UpAndDown = true.
2099
// This is a feature, look up glitches in tLoZ:aLttP to find out why.
2100
joypad[cmd.input.button.joypad.idx].buttons &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
2101
joypad[cmd.input.button.joypad.idx].turbos &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
2102
}
2103
2104
if (cmd.input.button.joypad.buttons & (SNES_UP_MASK | SNES_DOWN_MASK))
2105
{
2106
// and ditto for up/down
2107
joypad[cmd.input.button.joypad.idx].buttons &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
2108
joypad[cmd.input.button.joypad.idx].turbos &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
2109
}
2110
}
2111
2112
joypad[cmd.input.button.joypad.idx].buttons |= r;
2113
joypad[cmd.input.button.joypad.idx].turbos |= t;
2114
joypad[cmd.input.button.joypad.idx].buttons ^= s;
2115
joypad[cmd.input.button.joypad.idx].buttons &= ~(joypad[cmd.input.button.joypad.idx].turbos & st);
2116
joypad[cmd.input.button.joypad.idx].turbos ^= st;
2117
}
2118
else
2119
{
2120
joypad[cmd.input.button.joypad.idx].buttons &= ~r;
2121
joypad[cmd.input.button.joypad.idx].buttons &= ~(joypad[cmd.input.button.joypad.idx].turbos & t);
2122
joypad[cmd.input.button.joypad.idx].turbos &= ~t;
2123
}
2124
}
2125
2126
return;
2127
2128
case S9xButtonMouse:
2129
i = 0;
2130
if (cmd.input.button.mouse.left ) i |= 0x40;
2131
if (cmd.input.button.mouse.right) i |= 0x80;
2132
2133
if (data1)
2134
mouse[cmd.input.button.mouse.idx].buttons |= i;
2135
else
2136
mouse[cmd.input.button.mouse.idx].buttons &= ~i;
2137
2138
return;
2139
2140
case S9xButtonSuperscope:
2141
i = 0;
2142
if (cmd.input.button.scope.fire ) i |= SUPERSCOPE_FIRE;
2143
if (cmd.input.button.scope.cursor ) i |= SUPERSCOPE_CURSOR;
2144
if (cmd.input.button.scope.pause ) i |= SUPERSCOPE_PAUSE;
2145
if (cmd.input.button.scope.aim_offscreen) i |= SUPERSCOPE_OFFSCREEN;
2146
2147
if (data1)
2148
{
2149
superscope.phys_buttons |= i;
2150
2151
if (cmd.input.button.scope.turbo)
2152
{
2153
superscope.phys_buttons ^= SUPERSCOPE_TURBO;
2154
2155
if (superscope.phys_buttons & SUPERSCOPE_TURBO)
2156
superscope.next_buttons |= superscope.phys_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
2157
else
2158
superscope.next_buttons &= ~(SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
2159
}
2160
2161
superscope.next_buttons |= i & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR | SUPERSCOPE_PAUSE);
2162
2163
if (!S9xMovieActive()) // PPU modification during non-recordable command screws up movie synchronization
2164
if ((superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) && curcontrollers[1] == SUPERSCOPE && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN))
2165
DoGunLatch(superscope.x, superscope.y);
2166
}
2167
else
2168
{
2169
superscope.phys_buttons &= ~i;
2170
superscope.next_buttons &= SUPERSCOPE_OFFSCREEN | ~i;
2171
}
2172
2173
return;
2174
2175
case S9xButtonJustifier:
2176
i = 0;
2177
if (cmd.input.button.justifier.trigger) i |= JUSTIFIER_TRIGGER;
2178
if (cmd.input.button.justifier.start ) i |= JUSTIFIER_START;
2179
if (cmd.input.button.justifier.aim_offscreen) justifier.offscreen[cmd.input.button.justifier.idx] = data1 ? 1 : 0;
2180
i >>= cmd.input.button.justifier.idx;
2181
2182
if (data1)
2183
justifier.buttons |= i;
2184
else
2185
justifier.buttons &= ~i;
2186
2187
return;
2188
2189
case S9xButtonCommand:
2190
if (((enum command_numbers) cmd.input.button.command) >= LAST_COMMAND)
2191
{
2192
fprintf(stderr, "Unknown command %04x\n", cmd.input.button.command);
2193
return;
2194
}
2195
2196
if (!data1)
2197
{
2198
switch (i = cmd.input.button.command)
2199
{
2200
case EmuTurbo:
2201
Settings.TurboMode = FALSE;
2202
break;
2203
}
2204
}
2205
else
2206
{
2207
switch ((enum command_numbers) (i = cmd.input.button.command))
2208
{
2209
case ExitEmu:
2210
S9xExit();
2211
break;
2212
2213
case Reset:
2214
S9xReset();
2215
break;
2216
2217
case SoftReset:
2218
#ifdef FANCY
2219
S9xMovieUpdateOnReset();
2220
if (S9xMoviePlaying())
2221
S9xMovieStop(TRUE);
2222
#endif
2223
S9xSoftReset();
2224
break;
2225
2226
case EmuTurbo:
2227
Settings.TurboMode = TRUE;
2228
break;
2229
2230
case ToggleEmuTurbo:
2231
Settings.TurboMode = !Settings.TurboMode;
2232
DisplayStateChange("Turbo mode", Settings.TurboMode);
2233
break;
2234
2235
case ClipWindows:
2236
Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows;
2237
DisplayStateChange("Graphic clip windows", !Settings.DisableGraphicWindows);
2238
break;
2239
2240
case Debugger:
2241
#ifdef DEBUGGER
2242
CPU.Flags |= DEBUG_MODE_FLAG;
2243
#endif
2244
break;
2245
2246
case IncFrameRate:
2247
if (Settings.SkipFrames == AUTO_FRAMERATE)
2248
Settings.SkipFrames = 1;
2249
else
2250
if (Settings.SkipFrames < 10)
2251
Settings.SkipFrames++;
2252
2253
if (Settings.SkipFrames == AUTO_FRAMERATE)
2254
S9xSetInfoString("Auto frame skip");
2255
else
2256
{
2257
sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
2258
S9xSetInfoString(buf);
2259
}
2260
2261
break;
2262
2263
case DecFrameRate:
2264
if (Settings.SkipFrames <= 1)
2265
Settings.SkipFrames = AUTO_FRAMERATE;
2266
else
2267
if (Settings.SkipFrames != AUTO_FRAMERATE)
2268
Settings.SkipFrames--;
2269
2270
if (Settings.SkipFrames == AUTO_FRAMERATE)
2271
S9xSetInfoString("Auto frame skip");
2272
else
2273
{
2274
sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
2275
S9xSetInfoString(buf);
2276
}
2277
2278
break;
2279
2280
case IncEmuTurbo:
2281
if (Settings.TurboSkipFrames < 20)
2282
Settings.TurboSkipFrames += 1;
2283
else
2284
if (Settings.TurboSkipFrames < 200)
2285
Settings.TurboSkipFrames += 5;
2286
sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
2287
S9xSetInfoString(buf);
2288
break;
2289
2290
case DecEmuTurbo:
2291
if (Settings.TurboSkipFrames > 20)
2292
Settings.TurboSkipFrames -= 5;
2293
else
2294
if (Settings.TurboSkipFrames > 0)
2295
Settings.TurboSkipFrames -= 1;
2296
sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
2297
S9xSetInfoString(buf);
2298
break;
2299
2300
case IncFrameTime: // Increase emulated frame time by 1ms
2301
Settings.FrameTime += 1000;
2302
sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
2303
S9xSetInfoString(buf);
2304
break;
2305
2306
case DecFrameTime: // Decrease emulated frame time by 1ms
2307
if (Settings.FrameTime >= 1000)
2308
Settings.FrameTime -= 1000;
2309
sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
2310
S9xSetInfoString(buf);
2311
break;
2312
2313
case IncTurboSpeed:
2314
if (turbo_time >= 120)
2315
break;
2316
turbo_time++;
2317
sprintf(buf, "Turbo speed: %d", turbo_time);
2318
S9xSetInfoString(buf);
2319
break;
2320
2321
case DecTurboSpeed:
2322
if (turbo_time <= 1)
2323
break;
2324
turbo_time--;
2325
sprintf(buf, "Turbo speed: %d", turbo_time);
2326
S9xSetInfoString(buf);
2327
break;
2328
2329
case LoadFreezeFile:
2330
#ifdef FANCY
2331
S9xUnfreezeGame(S9xChooseFilename(TRUE));
2332
#endif
2333
break;
2334
2335
case SaveFreezeFile:
2336
#ifdef FANCY
2337
S9xFreezeGame(S9xChooseFilename(FALSE));
2338
#endif
2339
break;
2340
2341
case LoadOopsFile:
2342
#ifdef FANCY
2343
{
2344
char filename[PATH_MAX + 1];
2345
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2346
2347
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2348
snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
2349
2350
if (S9xUnfreezeGame(filename))
2351
{
2352
sprintf(buf, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops");
2353
S9xSetInfoString (buf);
2354
}
2355
else
2356
S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Oops file not found");
2357
2358
break;
2359
}
2360
#else
2361
break;
2362
#endif
2363
case Pause:
2364
Settings.Paused = !Settings.Paused;
2365
DisplayStateChange("Pause", Settings.Paused);
2366
#if defined(NETPLAY_SUPPORT) && !defined(__WIN32__)
2367
S9xNPSendPause(Settings.Paused);
2368
#endif
2369
break;
2370
2371
case QuickLoad000:
2372
case QuickLoad001:
2373
case QuickLoad002:
2374
case QuickLoad003:
2375
case QuickLoad004:
2376
case QuickLoad005:
2377
case QuickLoad006:
2378
case QuickLoad007:
2379
case QuickLoad008:
2380
case QuickLoad009:
2381
case QuickLoad010:
2382
#ifdef FANCY
2383
{
2384
char filename[PATH_MAX + 1];
2385
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2386
2387
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2388
snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickLoad000);
2389
2390
if (S9xUnfreezeGame(filename))
2391
{
2392
sprintf(buf, "%s.%03d loaded", def, i - QuickLoad000);
2393
S9xSetInfoString(buf);
2394
}
2395
else
2396
S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Freeze file not found");
2397
2398
break;
2399
}
2400
#endif
2401
2402
case QuickSave000:
2403
case QuickSave001:
2404
case QuickSave002:
2405
case QuickSave003:
2406
case QuickSave004:
2407
case QuickSave005:
2408
case QuickSave006:
2409
case QuickSave007:
2410
case QuickSave008:
2411
case QuickSave009:
2412
case QuickSave010:
2413
#ifdef FANCY
2414
{
2415
char filename[PATH_MAX + 1];
2416
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2417
2418
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2419
snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000);
2420
2421
sprintf(buf, "%s.%03d saved", def, i - QuickSave000);
2422
S9xSetInfoString(buf);
2423
2424
S9xFreezeGame(filename);
2425
break;
2426
}
2427
#else
2428
break;
2429
#endif
2430
case SaveSPC:
2431
#ifdef FANCY
2432
S9xDumpSPCSnapshot();
2433
#endif
2434
break;
2435
2436
case Screenshot:
2437
#ifdef FANCY
2438
Settings.TakeScreenshot = TRUE;
2439
#endif
2440
break;
2441
2442
case SoundChannel0:
2443
case SoundChannel1:
2444
case SoundChannel2:
2445
case SoundChannel3:
2446
case SoundChannel4:
2447
case SoundChannel5:
2448
case SoundChannel6:
2449
case SoundChannel7:
2450
S9xToggleSoundChannel(i - SoundChannel0);
2451
sprintf(buf, "Sound channel %d toggled", i - SoundChannel0);
2452
S9xSetInfoString(buf);
2453
break;
2454
2455
case SoundChannelsOn:
2456
S9xToggleSoundChannel(8);
2457
S9xSetInfoString("All sound channels on");
2458
break;
2459
2460
case ToggleBG0:
2461
Settings.BG_Forced ^= 1;
2462
DisplayStateChange("BG#0", !(Settings.BG_Forced & 1));
2463
break;
2464
2465
case ToggleBG1:
2466
Settings.BG_Forced ^= 2;
2467
DisplayStateChange("BG#1", !(Settings.BG_Forced & 2));
2468
break;
2469
2470
case ToggleBG2:
2471
Settings.BG_Forced ^= 4;
2472
DisplayStateChange("BG#2", !(Settings.BG_Forced & 4));
2473
break;
2474
2475
case ToggleBG3:
2476
Settings.BG_Forced ^= 8;
2477
DisplayStateChange("BG#3", !(Settings.BG_Forced & 8));
2478
break;
2479
2480
case ToggleSprites:
2481
Settings.BG_Forced ^= 16;
2482
DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
2483
break;
2484
2485
case ToggleTransparency:
2486
Settings.Transparency = !Settings.Transparency;
2487
DisplayStateChange("Transparency effects", Settings.Transparency);
2488
break;
2489
2490
case BeginRecordingMovie:
2491
#ifdef FANCY
2492
if (S9xMovieActive())
2493
S9xMovieStop(FALSE);
2494
S9xMovieCreate(S9xChooseMovieFilename(FALSE), 0xFF, MOVIE_OPT_FROM_RESET, NULL, 0);
2495
#endif
2496
break;
2497
2498
case LoadMovie:
2499
#ifdef FANCY
2500
if (S9xMovieActive())
2501
S9xMovieStop(FALSE);
2502
S9xMovieOpen(S9xChooseMovieFilename(TRUE), FALSE);
2503
#endif
2504
break;
2505
2506
case EndRecordingMovie:
2507
#ifdef FANCY
2508
if (S9xMovieActive())
2509
S9xMovieStop(FALSE);
2510
break;
2511
#endif
2512
case SwapJoypads:
2513
if ((curcontrollers[0] != NONE && !(curcontrollers[0] >= JOYPAD0 && curcontrollers[0] <= JOYPAD7)))
2514
{
2515
S9xSetInfoString("Cannot swap pads: port 1 is not a joypad");
2516
break;
2517
}
2518
2519
if ((curcontrollers[1] != NONE && !(curcontrollers[1] >= JOYPAD0 && curcontrollers[1] <= JOYPAD7)))
2520
{
2521
S9xSetInfoString("Cannot swap pads: port 2 is not a joypad");
2522
break;
2523
}
2524
2525
newcontrollers[1] = curcontrollers[0];
2526
newcontrollers[0] = curcontrollers[1];
2527
2528
strcpy(buf, "Swap pads: P1=");
2529
i = 14;
2530
if (newcontrollers[0] == NONE)
2531
{
2532
strcpy(buf + i, "<none>");
2533
i += 6;
2534
}
2535
else
2536
{
2537
sprintf(buf + i, "Joypad%d", newcontrollers[0] - JOYPAD0 + 1);
2538
i += 7;
2539
}
2540
2541
strcpy(buf + i, " P2=");
2542
i += 4;
2543
if (newcontrollers[1] == NONE)
2544
strcpy(buf + i, "<none>");
2545
else
2546
sprintf(buf + i, "Joypad%d", newcontrollers[1] - JOYPAD0 + 1);
2547
2548
S9xSetInfoString(buf);
2549
break;
2550
2551
case SeekToFrame:
2552
#ifdef FANCY
2553
if (S9xMovieActive())
2554
{
2555
sprintf(buf, "Select frame number (current: %d)", S9xMovieGetFrameCounter());
2556
const char *frameno = S9xStringInput(buf);
2557
if (!frameno)
2558
return;
2559
2560
int frameDest = atoi(frameno);
2561
if (frameDest > 0 && frameDest > (int) S9xMovieGetFrameCounter())
2562
{
2563
int distance = frameDest - S9xMovieGetFrameCounter();
2564
Settings.HighSpeedSeek = distance;
2565
}
2566
}
2567
#endif
2568
break;
2569
2570
case LAST_COMMAND:
2571
break;
2572
}
2573
}
2574
2575
return;
2576
2577
case S9xPointer:
2578
if (cmd.input.pointer.aim_mouse0)
2579
{
2580
mouse[0].cur_x = data1;
2581
mouse[0].cur_y = data2;
2582
}
2583
2584
if (cmd.input.pointer.aim_mouse1)
2585
{
2586
mouse[1].cur_x = data1;
2587
mouse[1].cur_y = data2;
2588
}
2589
2590
if (cmd.input.pointer.aim_scope)
2591
{
2592
superscope.x = data1;
2593
superscope.y = data2;
2594
}
2595
2596
if (cmd.input.pointer.aim_justifier0)
2597
{
2598
justifier.x[0] = data1;
2599
justifier.y[0] = data2;
2600
}
2601
2602
if (cmd.input.pointer.aim_justifier1)
2603
{
2604
justifier.x[1] = data1;
2605
justifier.y[1] = data2;
2606
}
2607
2608
return;
2609
2610
case S9xButtonPseudopointer:
2611
if (data1)
2612
{
2613
if (cmd.input.button.pointer.UD)
2614
{
2615
if (!pseudopointer[cmd.input.button.pointer.idx].V_adj)
2616
pseudopointer[cmd.input.button.pointer.idx].V_adj = cmd.input.button.pointer.UD * ptrspeeds[cmd.input.button.pointer.speed_type];
2617
pseudopointer[cmd.input.button.pointer.idx].V_var = (cmd.input.button.pointer.speed_type == 0);
2618
}
2619
2620
if (cmd.input.button.pointer.LR)
2621
{
2622
if (!pseudopointer[cmd.input.button.pointer.idx].H_adj)
2623
pseudopointer[cmd.input.button.pointer.idx].H_adj = cmd.input.button.pointer.LR * ptrspeeds[cmd.input.button.pointer.speed_type];
2624
pseudopointer[cmd.input.button.pointer.idx].H_var = (cmd.input.button.pointer.speed_type == 0);
2625
}
2626
}
2627
else
2628
{
2629
if (cmd.input.button.pointer.UD)
2630
{
2631
pseudopointer[cmd.input.button.pointer.idx].V_adj = 0;
2632
pseudopointer[cmd.input.button.pointer.idx].V_var = false;
2633
}
2634
2635
if (cmd.input.button.pointer.LR)
2636
{
2637
pseudopointer[cmd.input.button.pointer.idx].H_adj = 0;
2638
pseudopointer[cmd.input.button.pointer.idx].H_var = false;
2639
}
2640
}
2641
2642
return;
2643
2644
case S9xAxisJoypad:
2645
{
2646
uint16 pos, neg;
2647
2648
switch (cmd.input.axis.joypad.axis)
2649
{
2650
case 0: neg = SNES_LEFT_MASK; pos = SNES_RIGHT_MASK; break;
2651
case 1: neg = SNES_UP_MASK; pos = SNES_DOWN_MASK; break;
2652
case 2: neg = SNES_Y_MASK; pos = SNES_A_MASK; break;
2653
case 3: neg = SNES_X_MASK; pos = SNES_B_MASK; break;
2654
case 4: neg = SNES_TL_MASK; pos = SNES_TR_MASK; break;
2655
default: return;
2656
}
2657
2658
if (cmd.input.axis.joypad.invert)
2659
data1 = -data1;
2660
2661
uint16 p, r;
2662
2663
p = r = 0;
2664
if (data1 > ((cmd.input.axis.joypad.threshold + 1) * 127))
2665
p |= pos;
2666
else
2667
r |= pos;
2668
2669
if (data1 <= ((cmd.input.axis.joypad.threshold + 1) * -127))
2670
p |= neg;
2671
else
2672
r |= neg;
2673
2674
joypad[cmd.input.axis.joypad.idx].buttons |= p;
2675
joypad[cmd.input.axis.joypad.idx].buttons &= ~r;
2676
joypad[cmd.input.axis.joypad.idx].turbos &= ~(p | r);
2677
2678
return;
2679
}
2680
2681
case S9xAxisPseudopointer:
2682
if (data1 == 0)
2683
{
2684
if (cmd.input.axis.pointer.HV)
2685
{
2686
pseudopointer[cmd.input.axis.pointer.idx].V_adj = 0;
2687
pseudopointer[cmd.input.axis.pointer.idx].V_var = false;
2688
}
2689
else
2690
{
2691
pseudopointer[cmd.input.axis.pointer.idx].H_adj = 0;
2692
pseudopointer[cmd.input.axis.pointer.idx].H_var = false;
2693
}
2694
}
2695
else
2696
{
2697
if (cmd.input.axis.pointer.invert)
2698
data1 = -data1;
2699
2700
if (cmd.input.axis.pointer.HV)
2701
{
2702
if (!pseudopointer[cmd.input.axis.pointer.idx].V_adj)
2703
pseudopointer[cmd.input.axis.pointer.idx].V_adj = (int16) ((int32) data1 * ptrspeeds[cmd.input.axis.pointer.speed_type] / 32767);
2704
pseudopointer[cmd.input.axis.pointer.idx].V_var = (cmd.input.axis.pointer.speed_type == 0);
2705
}
2706
else
2707
{
2708
if (!pseudopointer[cmd.input.axis.pointer.idx].H_adj)
2709
pseudopointer[cmd.input.axis.pointer.idx].H_adj = (int16) ((int32) data1 * ptrspeeds[cmd.input.axis.pointer.speed_type] / 32767);
2710
pseudopointer[cmd.input.axis.pointer.idx].H_var = (cmd.input.axis.pointer.speed_type == 0);
2711
}
2712
}
2713
2714
return;
2715
2716
case S9xAxisPseudobuttons:
2717
if (data1 > ((cmd.input.axis.button.threshold + 1) * 127))
2718
{
2719
if (!pseudobuttons[cmd.input.axis.button.posbutton])
2720
{
2721
pseudobuttons[cmd.input.axis.button.posbutton] = 1;
2722
S9xReportButton(PseudoButtonBase + cmd.input.axis.button.posbutton, true);
2723
}
2724
}
2725
else
2726
{
2727
if (pseudobuttons[cmd.input.axis.button.posbutton])
2728
{
2729
pseudobuttons[cmd.input.axis.button.posbutton] = 0;
2730
S9xReportButton(PseudoButtonBase + cmd.input.axis.button.posbutton, false);
2731
}
2732
}
2733
2734
if (data1 <= ((cmd.input.axis.button.threshold + 1) * -127))
2735
{
2736
if (!pseudobuttons[cmd.input.axis.button.negbutton])
2737
{
2738
pseudobuttons[cmd.input.axis.button.negbutton] = 1;
2739
S9xReportButton(PseudoButtonBase + cmd.input.axis.button.negbutton, true);
2740
}
2741
}
2742
else
2743
{
2744
if (pseudobuttons[cmd.input.axis.button.negbutton])
2745
{
2746
pseudobuttons[cmd.input.axis.button.negbutton] = 0;
2747
S9xReportButton(PseudoButtonBase + cmd.input.axis.button.negbutton, false);
2748
}
2749
}
2750
2751
return;
2752
2753
case S9xButtonPort:
2754
case S9xAxisPort:
2755
case S9xPointerPort:
2756
S9xHandlePortCommand(cmd, data1, data2);
2757
return;
2758
2759
case S9xButtonMulti:
2760
if (cmd.input.button.multi_idx >= (int) multis.size())
2761
return;
2762
2763
if (multis[cmd.input.button.multi_idx]->multi_press && !data1)
2764
return;
2765
2766
i = ApplyMulti(multis[cmd.input.button.multi_idx], 0, data1);
2767
if (i >= 0)
2768
{
2769
struct exemulti *e = new struct exemulti;
2770
e->pos = i;
2771
e->data1 = data1 != 0;
2772
e->script = multis[cmd.input.button.multi_idx];
2773
exemultis.insert(e);
2774
}
2775
2776
return;
2777
2778
default:
2779
fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type);
2780
return;
2781
}
2782
}
2783
2784
static void do_polling (int mp)
2785
{
2786
set<uint32>::iterator itr;
2787
#ifdef FANCY
2788
if (S9xMoviePlaying())
2789
return;
2790
#endif
2791
if (pollmap[mp].empty())
2792
return;
2793
2794
for (itr = pollmap[mp].begin(); itr != pollmap[mp].end(); itr++)
2795
{
2796
switch (maptype(keymap[*itr].type))
2797
{
2798
case MAP_BUTTON:
2799
{
2800
bool pressed;
2801
if (S9xPollButton(*itr, &pressed))
2802
S9xReportButton(*itr, pressed);
2803
break;
2804
}
2805
2806
case MAP_AXIS:
2807
{
2808
int16 value;
2809
if (S9xPollAxis(*itr, &value))
2810
S9xReportAxis(*itr, value);
2811
break;
2812
}
2813
2814
case MAP_POINTER:
2815
{
2816
int16 x, y;
2817
if (S9xPollPointer(*itr, &x, &y))
2818
S9xReportPointer(*itr, x, y);
2819
break;
2820
}
2821
2822
default:
2823
break;
2824
}
2825
}
2826
}
2827
2828
static void UpdatePolledMouse (int i)
2829
{
2830
int16 j;
2831
2832
j = mouse[i - MOUSE0].cur_x - mouse[i - MOUSE0].old_x;
2833
2834
if (j < -127)
2835
{
2836
mouse[i - MOUSE0].delta_x = 0xff;
2837
mouse[i - MOUSE0].old_x -= 127;
2838
}
2839
else
2840
if (j < 0)
2841
{
2842
mouse[i - MOUSE0].delta_x = 0x80 | -j;
2843
mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x;
2844
}
2845
else
2846
if (j > 127)
2847
{
2848
mouse[i - MOUSE0].delta_x = 0x7f;
2849
mouse[i - MOUSE0].old_x += 127;
2850
}
2851
else
2852
{
2853
mouse[i - MOUSE0].delta_x = (uint8) j;
2854
mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x;
2855
}
2856
2857
j = mouse[i - MOUSE0].cur_y - mouse[i - MOUSE0].old_y;
2858
2859
if (j < -127)
2860
{
2861
mouse[i - MOUSE0].delta_y = 0xff;
2862
mouse[i - MOUSE0].old_y -= 127;
2863
}
2864
else
2865
if (j < 0)
2866
{
2867
mouse[i - MOUSE0].delta_y = 0x80 | -j;
2868
mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y;
2869
}
2870
else
2871
if (j > 127)
2872
{
2873
mouse[i - MOUSE0].delta_y = 0x7f;
2874
mouse[i - MOUSE0].old_y += 127;
2875
}
2876
else
2877
{
2878
mouse[i - MOUSE0].delta_y = (uint8) j;
2879
mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y;
2880
}
2881
}
2882
2883
void S9xSetJoypadLatch (bool latch)
2884
{
2885
if (!latch && FLAG_LATCH)
2886
{
2887
// 1 written, 'plug in' new controllers now
2888
curcontrollers[0] = newcontrollers[0];
2889
curcontrollers[1] = newcontrollers[1];
2890
}
2891
2892
if (latch && !FLAG_LATCH)
2893
{
2894
int i;
2895
2896
for (int n = 0; n < 2; n++)
2897
{
2898
for (int j = 0; j < 2; j++)
2899
read_idx[n][j] = 0;
2900
2901
switch (i = curcontrollers[n])
2902
{
2903
case MP5:
2904
for (int j = 0, k = mp5[n].pads[j]; j < 4; k = mp5[n].pads[++j])
2905
{
2906
if (k == NONE)
2907
continue;
2908
do_polling(k);
2909
}
2910
2911
break;
2912
2913
case JOYPAD0:
2914
case JOYPAD1:
2915
case JOYPAD2:
2916
case JOYPAD3:
2917
case JOYPAD4:
2918
case JOYPAD5:
2919
case JOYPAD6:
2920
case JOYPAD7:
2921
do_polling(i);
2922
break;
2923
2924
case MOUSE0:
2925
case MOUSE1:
2926
do_polling(i);
2927
if (!S9xMoviePlaying())
2928
UpdatePolledMouse(i);
2929
break;
2930
2931
case SUPERSCOPE:
2932
if (superscope.next_buttons & SUPERSCOPE_FIRE)
2933
{
2934
superscope.next_buttons &= ~SUPERSCOPE_TURBO;
2935
superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_TURBO;
2936
}
2937
2938
if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR))
2939
{
2940
superscope.next_buttons &= ~SUPERSCOPE_OFFSCREEN;
2941
superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_OFFSCREEN;
2942
}
2943
2944
superscope.read_buttons = superscope.next_buttons;
2945
2946
superscope.next_buttons &= ~SUPERSCOPE_PAUSE;
2947
if (!(superscope.phys_buttons & SUPERSCOPE_TURBO))
2948
superscope.next_buttons &= ~(SUPERSCOPE_CURSOR | SUPERSCOPE_FIRE);
2949
2950
do_polling(i);
2951
break;
2952
2953
case TWO_JUSTIFIERS:
2954
do_polling(TWO_JUSTIFIERS);
2955
// fall through
2956
2957
case ONE_JUSTIFIER:
2958
justifier.buttons ^= JUSTIFIER_SELECT;
2959
do_polling(ONE_JUSTIFIER);
2960
break;
2961
2962
default:
2963
break;
2964
}
2965
}
2966
}
2967
2968
FLAG_LATCH = latch;
2969
}
2970
2971
uint8 S9xReadJOYSERn (int n)
2972
{
2973
int i, j, r;
2974
2975
if (n > 1)
2976
n -= 0x4016;
2977
assert(n == 0 || n == 1);
2978
2979
uint8 bits = (OpenBus & ~3) | ((n == 1) ? 0x1c : 0);
2980
2981
if (FLAG_LATCH)
2982
{
2983
switch (i = curcontrollers[n])
2984
{
2985
case MP5:
2986
return (bits | 2);
2987
2988
case JOYPAD0:
2989
case JOYPAD1:
2990
case JOYPAD2:
2991
case JOYPAD3:
2992
case JOYPAD4:
2993
case JOYPAD5:
2994
case JOYPAD6:
2995
case JOYPAD7:
2996
return (bits | ((joypad[i - JOYPAD0].buttons & 0x8000) ? 1 : 0));
2997
2998
case MOUSE0:
2999
case MOUSE1:
3000
mouse[i - MOUSE0].buttons += 0x10;
3001
if ((mouse[i - MOUSE0].buttons & 0x30) == 0x30)
3002
mouse[i - MOUSE0].buttons &= 0xcf;
3003
return (bits);
3004
3005
case SUPERSCOPE:
3006
return (bits | ((superscope.read_buttons & 0x80) ? 1 : 0));
3007
3008
case ONE_JUSTIFIER:
3009
case TWO_JUSTIFIERS:
3010
return (bits);
3011
3012
default:
3013
return (bits);
3014
}
3015
}
3016
else
3017
{
3018
switch (i = curcontrollers[n])
3019
{
3020
case MP5:
3021
r = read_idx[n][FLAG_IOBIT(n) ? 0 : 1]++;
3022
j = FLAG_IOBIT(n) ? 0 : 2;
3023
3024
for (i = 0; i < 2; i++, j++)
3025
{
3026
if (mp5[n].pads[j] == NONE)
3027
continue;
3028
if (r >= 16)
3029
bits |= 1 << i;
3030
else
3031
bits |= ((joypad[mp5[n].pads[j] - JOYPAD0].buttons & (0x8000 >> r)) ? 1 : 0) << i;
3032
}
3033
3034
return (bits);
3035
3036
case JOYPAD0:
3037
case JOYPAD1:
3038
case JOYPAD2:
3039
case JOYPAD3:
3040
case JOYPAD4:
3041
case JOYPAD5:
3042
case JOYPAD6:
3043
case JOYPAD7:
3044
if (read_idx[n][0] >= 16)
3045
{
3046
read_idx[n][0]++;
3047
return (bits | 1);
3048
}
3049
else
3050
return (bits | ((joypad[i - JOYPAD0].buttons & (0x8000 >> read_idx[n][0]++)) ? 1 : 0));
3051
3052
case MOUSE0:
3053
case MOUSE1:
3054
if (read_idx[n][0] < 8)
3055
{
3056
read_idx[n][0]++;
3057
return (bits);
3058
}
3059
else
3060
if (read_idx[n][0] < 16)
3061
return (bits | ((mouse[i - MOUSE0].buttons & (0x8000 >> read_idx[n][0]++)) ? 1 : 0));
3062
else
3063
if (read_idx[n][0] < 24)
3064
return (bits | ((mouse[i - MOUSE0].delta_y & (0x800000 >> read_idx[n][0]++)) ? 1 : 0));
3065
else
3066
if (read_idx[n][0] < 32)
3067
return (bits | ((mouse[i - MOUSE0].delta_x & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0));
3068
else
3069
{
3070
read_idx[n][0]++;
3071
return (bits | 1);
3072
}
3073
3074
case SUPERSCOPE:
3075
if (read_idx[n][0] < 8)
3076
return (bits | ((superscope.read_buttons & (0x80 >> read_idx[n][0]++)) ? 1 : 0));
3077
else
3078
{
3079
read_idx[n][0]++;
3080
return (bits | 1);
3081
}
3082
3083
case ONE_JUSTIFIER:
3084
if (read_idx[n][0] < 24)
3085
return (bits | ((0xaa7000 >> read_idx[n][0]++) & 1));
3086
else
3087
if (read_idx[n][0] < 32)
3088
return (bits | ((justifier.buttons & (JUSTIFIER_TRIGGER | JUSTIFIER_START | JUSTIFIER_SELECT) & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0));
3089
else
3090
{
3091
read_idx[n][0]++;
3092
return (bits | 1);
3093
}
3094
3095
case TWO_JUSTIFIERS:
3096
if (read_idx[n][0] < 24)
3097
return (bits | ((0xaa7000 >> read_idx[n][0]++) & 1));
3098
else
3099
if (read_idx[n][0] < 32)
3100
return (bits | ((justifier.buttons & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0));
3101
else
3102
{
3103
read_idx[n][0]++;
3104
return (bits | 1);
3105
}
3106
3107
default:
3108
read_idx[n][0]++;
3109
return (bits);
3110
}
3111
}
3112
}
3113
3114
void S9xDoAutoJoypad (void)
3115
{
3116
int i, j;
3117
3118
S9xSetJoypadLatch(1);
3119
S9xSetJoypadLatch(0);
3120
#ifdef FANCY
3121
S9xMovieUpdate(false);
3122
#endif
3123
for (int n = 0; n < 2; n++)
3124
{
3125
switch (i = curcontrollers[n])
3126
{
3127
case MP5:
3128
j = FLAG_IOBIT(n) ? 0 : 2;
3129
for (i = 0; i < 2; i++, j++)
3130
{
3131
if (mp5[n].pads[j] == NONE)
3132
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, 0);
3133
else
3134
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, joypad[mp5[n].pads[j] - JOYPAD0].buttons);
3135
}
3136
3137
read_idx[n][FLAG_IOBIT(n) ? 0 : 1] = 16;
3138
break;
3139
3140
case JOYPAD0:
3141
case JOYPAD1:
3142
case JOYPAD2:
3143
case JOYPAD3:
3144
case JOYPAD4:
3145
case JOYPAD5:
3146
case JOYPAD6:
3147
case JOYPAD7:
3148
read_idx[n][0] = 16;
3149
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, joypad[i - JOYPAD0].buttons);
3150
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3151
break;
3152
3153
case MOUSE0:
3154
case MOUSE1:
3155
read_idx[n][0] = 16;
3156
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, mouse[i - MOUSE0].buttons);
3157
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3158
break;
3159
3160
case SUPERSCOPE:
3161
read_idx[n][0] = 16;
3162
Memory.FillRAM[0x4218 + n * 2] = 0xff;
3163
Memory.FillRAM[0x4219 + n * 2] = superscope.read_buttons;
3164
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3165
break;
3166
3167
case ONE_JUSTIFIER:
3168
case TWO_JUSTIFIERS:
3169
read_idx[n][0] = 16;
3170
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0x000e);
3171
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3172
break;
3173
3174
default:
3175
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0);
3176
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3177
break;
3178
}
3179
}
3180
}
3181
3182
void S9xControlEOF (void)
3183
{
3184
#ifdef FANCY
3185
struct crosshair *c;
3186
#endif
3187
int i, j;
3188
3189
PPU.GunVLatch = 1000; // i.e., never latch
3190
PPU.GunHLatch = 0;
3191
3192
for (int n = 0; n < 2; n++)
3193
{
3194
switch (i = curcontrollers[n])
3195
{
3196
case MP5:
3197
for (j = 0, i = mp5[n].pads[j]; j < 4; i = mp5[n].pads[++j])
3198
{
3199
if (i == NONE)
3200
continue;
3201
3202
if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time)
3203
{
3204
joypad[i - JOYPAD0].turbo_ct = 0;
3205
joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos;
3206
}
3207
}
3208
3209
break;
3210
3211
case JOYPAD0:
3212
case JOYPAD1:
3213
case JOYPAD2:
3214
case JOYPAD3:
3215
case JOYPAD4:
3216
case JOYPAD5:
3217
case JOYPAD6:
3218
case JOYPAD7:
3219
if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time)
3220
{
3221
joypad[i - JOYPAD0].turbo_ct = 0;
3222
joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos;
3223
}
3224
3225
break;
3226
#ifdef FANCY
3227
case MOUSE0:
3228
case MOUSE1:
3229
c = &mouse[i - MOUSE0].crosshair;
3230
if (IPPU.RenderThisFrame)
3231
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, mouse[i - MOUSE0].cur_x, mouse[i - MOUSE0].cur_y);
3232
break;
3233
3234
case SUPERSCOPE:
3235
if (n == 1 && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN))
3236
{
3237
if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR))
3238
DoGunLatch(superscope.x, superscope.y);
3239
3240
c = &superscope.crosshair;
3241
if (IPPU.RenderThisFrame)
3242
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, superscope.x, superscope.y);
3243
}
3244
3245
break;
3246
3247
case TWO_JUSTIFIERS:
3248
if (n == 1 && !justifier.offscreen[1])
3249
{
3250
c = &justifier.crosshair[1];
3251
if (IPPU.RenderThisFrame)
3252
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[1], justifier.y[1]);
3253
}
3254
3255
i = (justifier.buttons & JUSTIFIER_SELECT) ? 1 : 0;
3256
goto do_justifier;
3257
3258
case ONE_JUSTIFIER:
3259
i = (justifier.buttons & JUSTIFIER_SELECT) ? -1 : 0;
3260
3261
do_justifier:
3262
if (n == 1)
3263
{
3264
if (i >= 0 && !justifier.offscreen[i])
3265
DoGunLatch(justifier.x[i], justifier.y[i]);
3266
3267
if (!justifier.offscreen[0])
3268
{
3269
c = &justifier.crosshair[0];
3270
if (IPPU.RenderThisFrame)
3271
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[0], justifier.y[0]);
3272
}
3273
}
3274
3275
break;
3276
#endif
3277
default:
3278
break;
3279
}
3280
}
3281
3282
for (int n = 0; n < 8; n++)
3283
{
3284
if (!pseudopointer[n].mapped)
3285
continue;
3286
3287
if (pseudopointer[n].H_adj)
3288
{
3289
pseudopointer[n].x += pseudopointer[n].H_adj;
3290
if (pseudopointer[n].x < 0)
3291
pseudopointer[n].x = 0;
3292
else
3293
if (pseudopointer[n].x > 255)
3294
pseudopointer[n].x = 255;
3295
3296
if (pseudopointer[n].H_var)
3297
{
3298
if (pseudopointer[n].H_adj < 0)
3299
{
3300
if (pseudopointer[n].H_adj > -ptrspeeds[3])
3301
pseudopointer[n].H_adj--;
3302
}
3303
else
3304
{
3305
if (pseudopointer[n].H_adj < ptrspeeds[3])
3306
pseudopointer[n].H_adj++;
3307
}
3308
}
3309
}
3310
3311
if (pseudopointer[n].V_adj)
3312
{
3313
pseudopointer[n].y += pseudopointer[n].V_adj;
3314
if (pseudopointer[n].y < 0)
3315
pseudopointer[n].y = 0;
3316
else
3317
if (pseudopointer[n].y > PPU.ScreenHeight - 1)
3318
pseudopointer[n].y = PPU.ScreenHeight - 1;
3319
3320
if (pseudopointer[n].V_var)
3321
{
3322
if (pseudopointer[n].V_adj < 0)
3323
{
3324
if (pseudopointer[n].V_adj > -ptrspeeds[3])
3325
pseudopointer[n].V_adj--;
3326
}
3327
else
3328
{
3329
if (pseudopointer[n].V_adj < ptrspeeds[3])
3330
pseudopointer[n].V_adj++;
3331
}
3332
}
3333
}
3334
3335
S9xReportPointer(PseudoPointerBase + n, pseudopointer[n].x, pseudopointer[n].y);
3336
}
3337
3338
set<struct exemulti *>::iterator it, jt;
3339
3340
for (it = exemultis.begin(); it != exemultis.end(); it++)
3341
{
3342
i = ApplyMulti((*it)->script, (*it)->pos, (*it)->data1);
3343
3344
if (i >= 0)
3345
(*it)->pos = i;
3346
else
3347
{
3348
jt = it;
3349
it--;
3350
delete *jt;
3351
exemultis.erase(jt);
3352
}
3353
}
3354
3355
do_polling(POLL_ALL);
3356
#ifdef FANCY
3357
S9xMovieUpdate();
3358
#endif
3359
pad_read_last = pad_read;
3360
pad_read = false;
3361
}
3362
#ifdef FANCY
3363
void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg, const char *bg)
3364
{
3365
struct crosshair *c;
3366
int8 fgcolor = -1, bgcolor = -1;
3367
int i, j;
3368
3369
if (idx < -1 || idx > 31)
3370
{
3371
fprintf(stderr, "S9xSetControllerCrosshair() called with invalid index\n");
3372
return;
3373
}
3374
3375
switch (ctl)
3376
{
3377
case X_MOUSE1: c = &mouse[0].crosshair; break;
3378
case X_MOUSE2: c = &mouse[1].crosshair; break;
3379
case X_SUPERSCOPE: c = &superscope.crosshair; break;
3380
case X_JUSTIFIER1: c = &justifier.crosshair[0]; break;
3381
case X_JUSTIFIER2: c = &justifier.crosshair[1]; break;
3382
default:
3383
fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
3384
return;
3385
}
3386
3387
if (fg)
3388
{
3389
fgcolor = 0;
3390
if (*fg == 't')
3391
{
3392
fg++;
3393
fgcolor = 16;
3394
}
3395
3396
for (i = 0; i < 16; i++)
3397
{
3398
for (j = 0; color_names[i][j] && fg[j] == color_names[i][j]; j++) ;
3399
if (isalnum(fg[j]))
3400
continue;
3401
3402
if (!color_names[i][j])
3403
break;
3404
}
3405
3406
fgcolor |= i;
3407
if (i > 15 || fgcolor == 16)
3408
{
3409
fprintf(stderr, "S9xSetControllerCrosshair() called with invalid fgcolor\n");
3410
return;
3411
}
3412
}
3413
3414
if (bg)
3415
{
3416
bgcolor = 0;
3417
if (*bg == 't')
3418
{
3419
bg++;
3420
bgcolor = 16;
3421
}
3422
3423
for (i = 0; i < 16; i++)
3424
{
3425
for (j = 0; color_names[i][j] && bg[j] == color_names[i][j]; j++) ;
3426
if (isalnum(bg[j]))
3427
continue;
3428
3429
if (!color_names[i][j])
3430
break;
3431
}
3432
3433
bgcolor |= i;
3434
if (i > 15 || bgcolor == 16)
3435
{
3436
fprintf(stderr, "S9xSetControllerCrosshair() called with invalid bgcolor\n");
3437
return;
3438
}
3439
}
3440
3441
if (idx != -1)
3442
{
3443
c->set |= 1;
3444
c->img = idx;
3445
}
3446
3447
if (fgcolor != -1)
3448
{
3449
c->set |= 2;
3450
c->fg = fgcolor;
3451
}
3452
3453
if (bgcolor != -1)
3454
{
3455
c->set |= 4;
3456
c->bg = bgcolor;
3457
}
3458
}
3459
3460
void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg)
3461
{
3462
struct crosshair *c;
3463
3464
switch (ctl)
3465
{
3466
case X_MOUSE1: c = &mouse[0].crosshair; break;
3467
case X_MOUSE2: c = &mouse[1].crosshair; break;
3468
case X_SUPERSCOPE: c = &superscope.crosshair; break;
3469
case X_JUSTIFIER1: c = &justifier.crosshair[0]; break;
3470
case X_JUSTIFIER2: c = &justifier.crosshair[1]; break;
3471
default:
3472
fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
3473
return;
3474
}
3475
3476
if (idx)
3477
*idx = c->img;
3478
3479
if (fg)
3480
*fg = color_names[c->fg];
3481
3482
if (bg)
3483
*bg = color_names[c->bg];
3484
}
3485
#endif
3486
void S9xControlPreSaveState (struct SControlSnapshot *s)
3487
{
3488
ZeroMemory(s, sizeof(*s));
3489
s->ver = 3;
3490
3491
for (int j = 0; j < 2; j++)
3492
{
3493
s->port1_read_idx[j] = read_idx[0][j];
3494
s->port2_read_idx[j] = read_idx[1][j];
3495
}
3496
3497
for (int j = 0; j < 2; j++)
3498
s->mouse_speed[j] = (mouse[j].buttons & 0x30) >> 4;
3499
3500
s->justifier_select = ((justifier.buttons & JUSTIFIER_SELECT) ? 1 : 0);
3501
3502
#define COPY(x) { memcpy((char *) s->internal + i, &(x), sizeof(x)); i += sizeof(x); }
3503
3504
int i = 0;
3505
3506
for (int j = 0; j < 8; j++)
3507
COPY(joypad[j].buttons);
3508
3509
for (int j = 0; j < 2; j++)
3510
{
3511
COPY(mouse[j].delta_x);
3512
COPY(mouse[j].delta_y);
3513
COPY(mouse[j].old_x);
3514
COPY(mouse[j].old_y);
3515
COPY(mouse[j].cur_x);
3516
COPY(mouse[j].cur_y);
3517
COPY(mouse[j].buttons);
3518
}
3519
3520
COPY(superscope.x);
3521
COPY(superscope.y);
3522
COPY(superscope.phys_buttons);
3523
COPY(superscope.next_buttons);
3524
COPY(superscope.read_buttons);
3525
3526
for (int j = 0; j < 2; j++)
3527
COPY(justifier.x[j]);
3528
for (int j = 0; j < 2; j++)
3529
COPY(justifier.y[j]);
3530
COPY(justifier.buttons);
3531
for (int j = 0; j < 2; j++)
3532
COPY(justifier.offscreen[j]);
3533
3534
for (int j = 0; j < 2; j++)
3535
for (int k = 0; k < 2; k++)
3536
COPY(mp5[j].pads[k]);
3537
3538
assert(i == sizeof(s->internal));
3539
3540
#undef COPY
3541
3542
s->pad_read = pad_read;
3543
s->pad_read_last = pad_read_last;
3544
}
3545
3546
void S9xControlPostLoadState (struct SControlSnapshot *s)
3547
{
3548
if (curcontrollers[0] == MP5 && s->ver < 1)
3549
{
3550
// Crap. Old snes9x didn't support this.
3551
S9xMessage(S9X_WARNING, S9X_FREEZE_FILE_INFO, "Old savestate has no support for MP5 in port 1.");
3552
newcontrollers[0] = curcontrollers[0];
3553
curcontrollers[0] = mp5[0].pads[0];
3554
}
3555
3556
for (int j = 0; j < 2; j++)
3557
{
3558
read_idx[0][j] = s->port1_read_idx[j];
3559
read_idx[1][j] = s->port2_read_idx[j];
3560
}
3561
3562
for (int j = 0; j < 2; j++)
3563
mouse[j].buttons |= (s->mouse_speed[j] & 3) << 4;
3564
3565
if (s->justifier_select & 1)
3566
justifier.buttons |= JUSTIFIER_SELECT;
3567
else
3568
justifier.buttons &= ~JUSTIFIER_SELECT;
3569
3570
FLAG_LATCH = (Memory.FillRAM[0x4016] & 1) == 1;
3571
3572
if (s->ver > 1)
3573
{
3574
#define COPY(x) { memcpy(&(x), (char *) s->internal + i, sizeof(x)); i += sizeof(x); }
3575
3576
int i = 0;
3577
3578
for (int j = 0; j < 8; j++)
3579
COPY(joypad[j].buttons);
3580
3581
for (int j = 0; j < 2; j++)
3582
{
3583
COPY(mouse[j].delta_x);
3584
COPY(mouse[j].delta_y);
3585
COPY(mouse[j].old_x);
3586
COPY(mouse[j].old_y);
3587
COPY(mouse[j].cur_x);
3588
COPY(mouse[j].cur_y);
3589
COPY(mouse[j].buttons);
3590
}
3591
3592
COPY(superscope.x);
3593
COPY(superscope.y);
3594
COPY(superscope.phys_buttons);
3595
COPY(superscope.next_buttons);
3596
COPY(superscope.read_buttons);
3597
3598
for (int j = 0; j < 2; j++)
3599
COPY(justifier.x[j]);
3600
for (int j = 0; j < 2; j++)
3601
COPY(justifier.y[j]);
3602
COPY(justifier.buttons);
3603
for (int j = 0; j < 2; j++)
3604
COPY(justifier.offscreen[j]);
3605
for (int j = 0; j < 2; j++)
3606
for (int k = 0; k < 2; k++)
3607
COPY(mp5[j].pads[k]);
3608
3609
assert(i == sizeof(s->internal));
3610
3611
#undef COPY
3612
}
3613
3614
if (s->ver > 2)
3615
{
3616
pad_read = s->pad_read;
3617
pad_read_last = s->pad_read_last;
3618
}
3619
}
3620
#ifdef FANCY
3621
uint16 MovieGetJoypad (int i)
3622
{
3623
if (i < 0 || i > 7)
3624
return (0);
3625
3626
return (joypad[i].buttons);
3627
}
3628
3629
void MovieSetJoypad (int i, uint16 buttons)
3630
{
3631
if (i < 0 || i > 7)
3632
return;
3633
3634
joypad[i].buttons = buttons;
3635
}
3636
3637
bool MovieGetMouse (int i, uint8 out[5])
3638
{
3639
if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1))
3640
return (false);
3641
3642
int n = curcontrollers[i] - MOUSE0;
3643
uint8 *ptr = out;
3644
3645
WRITE_WORD(ptr, mouse[n].cur_x); ptr += 2;
3646
WRITE_WORD(ptr, mouse[n].cur_y); ptr += 2;
3647
*ptr = mouse[n].buttons;
3648
3649
return (true);
3650
}
3651
3652
void MovieSetMouse (int i, uint8 in[5], bool inPolling)
3653
{
3654
if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1))
3655
return;
3656
3657
int n = curcontrollers[i] - MOUSE0;
3658
uint8 *ptr = in;
3659
3660
mouse[n].cur_x = READ_WORD(ptr); ptr += 2;
3661
mouse[n].cur_y = READ_WORD(ptr); ptr += 2;
3662
mouse[n].buttons = *ptr;
3663
3664
if (inPolling)
3665
UpdatePolledMouse(curcontrollers[i]);
3666
}
3667
3668
bool MovieGetScope (int i, uint8 out[6])
3669
{
3670
if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE)
3671
return (false);
3672
3673
uint8 *ptr = out;
3674
3675
WRITE_WORD(ptr, superscope.x); ptr += 2;
3676
WRITE_WORD(ptr, superscope.y); ptr += 2;
3677
*ptr++ = superscope.phys_buttons;
3678
*ptr = superscope.next_buttons;
3679
3680
return (true);
3681
}
3682
3683
void MovieSetScope (int i, uint8 in[6])
3684
{
3685
if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE)
3686
return;
3687
3688
uint8 *ptr = in;
3689
3690
superscope.x = READ_WORD(ptr); ptr += 2;
3691
superscope.y = READ_WORD(ptr); ptr += 2;
3692
superscope.phys_buttons = *ptr++;
3693
superscope.next_buttons = *ptr;
3694
}
3695
3696
bool MovieGetJustifier (int i, uint8 out[11])
3697
{
3698
if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS))
3699
return (false);
3700
3701
uint8 *ptr = out;
3702
3703
WRITE_WORD(ptr, justifier.x[0]); ptr += 2;
3704
WRITE_WORD(ptr, justifier.x[1]); ptr += 2;
3705
WRITE_WORD(ptr, justifier.y[0]); ptr += 2;
3706
WRITE_WORD(ptr, justifier.y[1]); ptr += 2;
3707
*ptr++ = justifier.buttons;
3708
*ptr++ = justifier.offscreen[0];
3709
*ptr = justifier.offscreen[1];
3710
3711
return (true);
3712
}
3713
3714
void MovieSetJustifier (int i, uint8 in[11])
3715
{
3716
if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS))
3717
return;
3718
3719
uint8 *ptr = in;
3720
3721
justifier.x[0] = READ_WORD(ptr); ptr += 2;
3722
justifier.x[1] = READ_WORD(ptr); ptr += 2;
3723
justifier.y[0] = READ_WORD(ptr); ptr += 2;
3724
justifier.y[1] = READ_WORD(ptr); ptr += 2;
3725
justifier.buttons = *ptr++;
3726
justifier.offscreen[0] = *ptr++;
3727
justifier.offscreen[1] = *ptr;
3728
}
3729
#endif
3730
3731