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