1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181 /***********************************************************************************
182 SNES9X for Mac OS (c) Copyright John Stiles
183
184 Snes9x for Mac OS X
185
186 (c) Copyright 2001 - 2011 zones
187 (c) Copyright 2002 - 2005 107
188 (c) Copyright 2002 PB1400c
189 (c) Copyright 2004 Alexander and Sander
190 (c) Copyright 2004 - 2005 Steven Seeger
191 (c) Copyright 2005 Ryan Vogt
192 ***********************************************************************************/
193
194
195 #include "snes9x.h"
196 #include "memmap.h"
197 #include "apu.h"
198 #include "snapshot.h"
199 #include "cheats.h"
200 #include "display.h"
201
202 #include <arpa/inet.h>
203 #include <pthread.h>
204 #include <semaphore.h>
205
206 #include "mac-prefix.h"
207 #include "mac-cart.h"
208 #include "mac-cheatfinder.h"
209 #include "mac-controls.h"
210 #include "mac-dialog.h"
211 #include "mac-file.h"
212 #include "mac-joypad.h"
213 #include "mac-keyboard.h"
214 #include "mac-os.h"
215 #include "mac-snes9x.h"
216 #include "mac-stringtools.h"
217 #include "mac-netplay.h"
218 #include "mac-client.h"
219
220 #ifdef SELF_TEST
221 #include <sys/un.h>
222 #endif
223
224 #define KeyIsPressed(km, k) (1 & (((unsigned char *) km) [(k) >> 3] >> ((k) & 7)))
225
226 enum
227 {
228 kNPCDialogNone,
229 kNPCDialogInit,
230 kNPCDialogConnect,
231 kNPCDialogConnectFailed,
232 kNPCDialogOpenBegin,
233 kNPCDialogOpenEnd,
234 kNPCDialogPrepare,
235 kNPCDialogPrepareFailed,
236 kNPCDialogShowList,
237 kNPCDialogDone,
238 kNPCDialogCancel
239 };
240
241 typedef struct
242 {
243 volatile bool8 padloop;
244 volatile bool8 exitsgn;
245 volatile uint32 phasecount;
246 volatile uint32 phasespan;
247 volatile uint8 header;
248 bool8 online;
249 int socket;
250 int numplayers;
251 char name[256];
252 char serverIP[256];
253
254 int savedDeviceSetting;
255 int savedAutoSaveDelay;
256
257 bool8 configsaved;
258 bool8 dialogcancel;
259 bool8 dialogsheet;
260 int dialogprocess;
261 } clientState;
262
263 typedef struct
264 {
265 bool8 ready;
266 int player;
267 char name[256];
268 } clientsInfo;
269
270 typedef struct
271 {
272 uint32 crc32;
273 int input;
274 int length;
275 char fname[PATH_MAX + 1];
276 } cROMInfo;
277
278 static char n_csememu[] = "/tmp/s9x_c_emu_semaphore",
279 n_csempad[] = "/tmp/s9x_c_pad_semaphore";
280
281 static clientState npclient;
282 static clientsInfo npcinfo[NP_MAX_PLAYERS];
283
284 static cROMInfo nprominfo;
285
286 static uint32 npcactvpad[NP_MAX_PLAYERS][64], // [player number]
287 npcrecvpad[NP_MAX_PLAYERS][64], // [player number]
288 npcsendpad[64],
289 npccachpad[64];
290
291 static WindowRef mRef, sRef;
292 static sem_t *csememu, *csempad;
293 static pthread_t connectthread, preparethread, gamepadthread;
294
295 static int NPClientGetMesFromServer (void);
296 static void NPClientDetachConnectThread (void);
297 static void NPClientDetachPrepareThread (void);
298 static void NPClientBeginPlayerListSheet (void);
299 static void NPClientEndPlayerListSheet (void);
300 static bool8 NPClientConnectToServer (int);
301 static bool8 NPClientSendMesToServer (int);
302 static bool8 NPClientSendNameToServer (void);
303 static bool8 NPClientGetROMInfoFromServer (void);
304 static bool8 NPClientBeginOpenROMImage (WindowRef);
305 static bool8 NPClientEndOpenROMImage (void);
306 static bool8 NPClientROMReadyToServer (void);
307 static bool8 NPClientGetSRAMFromServer (void);
308 static bool8 NPClientGetPlayerListFromServer (void);
309 static bool8 NPClientReplyPhaseSpanTest (void);
310 static void * NPClientConnectThread (void *);
311 static void * NPClientPrepareThread (void *);
312 static void * NPClientNetPlayThread (void *);
313 static pascal void NPClientDialogTimerHandler (EventLoopTimerRef, void *);
314 static pascal OSStatus NPClientDialogEventHandler (EventHandlerCallRef, EventRef, void *);
315 static pascal OSStatus NPClientSheetEventHandler (EventHandlerCallRef, EventRef, void *);
316
317
NPClientDialog(void)318 bool8 NPClientDialog (void)
319 {
320 OSStatus err;
321 IBNibRef nibRef;
322
323 npclient.dialogcancel = true;
324 npclient.dialogsheet = false;
325 npclient.configsaved = false;
326
327 err = CreateNibReference(kMacS9XCFString, &nibRef);
328 if (err == noErr)
329 {
330 err = CreateWindowFromNib(nibRef, CFSTR("Connect"), &mRef);
331 if (err == noErr)
332 {
333 err = CreateWindowFromNib(nibRef, CFSTR("PlayerList"), &sRef);
334 if (err == noErr)
335 {
336 EventHandlerRef eref, seref;
337 EventLoopTimerRef tref;
338 EventHandlerUPP eventUPP, sheetUPP;
339 EventLoopTimerUPP timerUPP;
340 EventTypeSpec windowEvents[] = { { kEventClassCommand, kEventCommandProcess },
341 { kEventClassCommand, kEventCommandUpdateStatus } };
342 CFStringRef ref;
343 HIViewRef ctl, root;
344 HIViewID cid;
345
346 npclient.dialogprocess = kNPCDialogInit;
347
348 eventUPP = NewEventHandlerUPP(NPClientDialogEventHandler);
349 err = InstallWindowEventHandler(mRef, eventUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) mRef, &eref);
350
351 timerUPP = NewEventLoopTimerUPP(NPClientDialogTimerHandler);
352 err = InstallEventLoopTimer(GetCurrentEventLoop(), 0.0f, 0.1f, timerUPP, (void *) mRef, &tref);
353
354 sheetUPP = NewEventHandlerUPP(NPClientSheetEventHandler);
355 err = InstallWindowEventHandler(sRef, sheetUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) sRef, &seref);
356
357 root = HIViewGetRoot(mRef);
358 cid.id = 0;
359
360 cid.signature = 'CHAS';
361 HIViewFindByID(root, cid, &ctl);
362 HIViewSetVisible(ctl, false);
363
364 cid.signature = 'SVIP';
365 HIViewFindByID(root, cid, &ctl);
366 SetEditTextCStr(ctl, npServerIP, false);
367
368 cid.signature = 'CLNM';
369 HIViewFindByID(root, cid, &ctl);
370 ref = CFStringCreateWithCString(kCFAllocatorDefault, npName, kCFStringEncodingUTF8);
371 if (ref)
372 {
373 SetEditTextCFString(ctl, ref, false);
374 CFRelease(ref);
375 }
376 else
377 SetEditTextCFString(ctl, CFSTR("unknown"), false);
378
379 MoveWindowPosition(mRef, kWindowClient, false);
380 ShowWindow(mRef);
381 err = HIViewAdvanceFocus(root, 0);
382 err = RunAppModalLoopForWindow(mRef);
383 HideWindow(mRef);
384 SaveWindowPosition(mRef, kWindowClient);
385
386 err = RemoveEventHandler(seref);
387 DisposeEventHandlerUPP(sheetUPP);
388
389 err = RemoveEventLoopTimer(tref);
390 DisposeEventLoopTimerUPP(timerUPP);
391
392 err = RemoveEventHandler(eref);
393 DisposeEventHandlerUPP(eventUPP);
394
395 CFRelease(sRef);
396 }
397
398 CFRelease(mRef);
399 }
400
401 DisposeNibReference(nibRef);
402 }
403
404 return (!npclient.dialogcancel);
405 }
406
NPClientDialogEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)407 static pascal OSStatus NPClientDialogEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
408 {
409 OSStatus err, result = eventNotHandledErr;
410
411 switch (GetEventClass(inEvent))
412 {
413 case kEventClassCommand:
414 switch (GetEventKind(inEvent))
415 {
416 HICommand tHICommand;
417
418 case kEventCommandUpdateStatus:
419 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
420 if (err == noErr && tHICommand.commandID == 'clos')
421 {
422 UpdateMenuCommandStatus(false);
423 result = noErr;
424 }
425
426 break;
427
428 case kEventCommandProcess:
429 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
430 if (err == noErr)
431 {
432 switch (tHICommand.commandID)
433 {
434 case 'OK__':
435 CFStringRef ref;
436 HIViewRef ctl, root;
437 HIViewID cid;
438
439 root = HIViewGetRoot(mRef);
440 cid.id = 0;
441
442 cid.signature = 'SVIP';
443 HIViewFindByID(root, cid, &ctl);
444 GetEditTextCStr(ctl, npclient.serverIP);
445 DeactivateControl(ctl);
446 if (npclient.serverIP[0] == 0)
447 strcpy(npclient.serverIP, "127.0.0.1");
448 strcpy(npServerIP, npclient.serverIP);
449 printf("%s\n", npServerIP);
450
451 cid.signature = 'CLNM';
452 HIViewFindByID(root, cid, &ctl);
453 CopyEditTextCFString(ctl, &ref);
454 DeactivateControl(ctl);
455 if (ref)
456 {
457 Boolean r;
458
459 r = CFStringGetCString(ref, npclient.name, 256, kCFStringEncodingUTF8);
460 if (!r)
461 strcpy(npclient.name, "unknown");
462 else
463 if (npclient.name[0] == 0)
464 strcpy(npclient.name, "Guest");
465
466 CFRelease(ref);
467 }
468 else
469 strcpy(npclient.name, "unknown");
470 strcpy(npName, npclient.name);
471 printf("%s\n", npName);
472
473 cid.signature = 'OK__';
474 HIViewFindByID(root, cid, &ctl);
475 DeactivateControl(ctl);
476
477 cid.signature = 'NOT_';
478 HIViewFindByID(root, cid, &ctl);
479 DeactivateControl(ctl);
480
481 npclient.dialogcancel = false;
482 npclient.dialogprocess = kNPCDialogConnect;
483
484 result = noErr;
485 break;
486
487 case 'NOT_':
488 npclient.dialogcancel = true;
489 npclient.dialogprocess = kNPCDialogCancel;
490
491 result = noErr;
492 break;
493
494 case 'NvDn':
495 npclient.dialogcancel = false;
496 npclient.dialogprocess = kNPCDialogOpenEnd;
497
498 result = noErr;
499 break;
500 }
501 }
502
503 break;
504 }
505
506 break;
507 }
508
509 return (result);
510 }
511
NPClientDialogTimerHandler(EventLoopTimerRef inTimer,void * userData)512 static pascal void NPClientDialogTimerHandler (EventLoopTimerRef inTimer, void *userData)
513 {
514 WindowRef window = (WindowRef) userData;
515 HIViewRef ctl;
516 HIViewID cid = { 'CHAS', 0 };
517
518 HIViewFindByID(HIViewGetRoot(mRef), cid, &ctl);
519
520 switch (npclient.dialogprocess)
521 {
522 case kNPCDialogNone:
523 break;
524
525 case kNPCDialogCancel:
526 NPNotification(" kNPCDialogCancel", -1);
527 npclient.dialogprocess = kNPCDialogNone;
528 npclient.dialogcancel = true;
529 QuitAppModalLoopForWindow(mRef);
530 break;
531
532 case kNPCDialogInit:
533 NPNotification(" kNPCDialogInit", -1);
534 npclient.dialogprocess = kNPCDialogNone;
535 break;
536
537 case kNPCDialogConnect:
538 NPNotification(" kNPCDialogConnect", -1);
539 npclient.dialogprocess = kNPCDialogNone;
540 HIViewSetVisible(ctl, true);
541 NPClientDetachConnectThread();
542 break;
543
544 case kNPCDialogConnectFailed:
545 NPNotification(" kNPCDialogConnectFailed", -1);
546 npclient.dialogprocess = kNPCDialogNone;
547 npclient.dialogcancel = true;
548 QuitAppModalLoopForWindow(mRef);
549 break;
550
551 case kNPCDialogOpenBegin:
552 NPNotification(" kNPCDialogOpenBegin", -1);
553 npclient.dialogprocess = kNPCDialogNone;
554 HIViewSetVisible(ctl, false);
555 NPClientStoreConfig();
556 if (!NPClientBeginOpenROMImage(window))
557 {
558 NPClientDisconnect();
559 NPClientRestoreConfig();
560 npclient.dialogprocess = kNPCDialogCancel;
561 }
562
563 break;
564
565 case kNPCDialogOpenEnd:
566 NPNotification(" kNPCDialogOpenEnd", -1);
567 npclient.dialogprocess = kNPCDialogNone;
568 if (!NPClientEndOpenROMImage())
569 {
570 NPClientDisconnect();
571 NPClientRestoreConfig();
572 npclient.dialogprocess = kNPCDialogCancel;
573 }
574 else
575 npclient.dialogprocess = kNPCDialogPrepare;
576
577 break;
578
579 case kNPCDialogPrepare:
580 NPNotification(" kNPCDialogPrepare", -1);
581 npclient.dialogprocess = kNPCDialogNone;
582 HIViewSetVisible(ctl, true);
583 NPClientDetachPrepareThread();
584 break;
585
586 case kNPCDialogPrepareFailed:
587 NPNotification(" kNPCDialogPrepareFailed", -1);
588 npclient.dialogprocess = kNPCDialogNone;
589 NPClientRestoreConfig();
590 npclient.dialogcancel = true;
591 QuitAppModalLoopForWindow(mRef);
592 break;
593
594 case kNPCDialogShowList:
595 NPNotification(" kNPCDialogShowList", -1);
596 npclient.dialogprocess = kNPCDialogNone;
597 HIViewSetVisible(ctl, false);
598 npclient.dialogsheet = true;
599 NPClientBeginPlayerListSheet();
600 break;
601
602 case kNPCDialogDone:
603 NPNotification(" kNPCDialogDone", -1);
604 npclient.dialogprocess = kNPCDialogNone;
605 NPClientEndPlayerListSheet();
606 npclient.dialogsheet = false;
607 npclient.dialogcancel = false;
608 QuitAppModalLoopForWindow(mRef);
609 break;
610 }
611 }
612
NPClientDetachConnectThread(void)613 static void NPClientDetachConnectThread (void)
614 {
615 pthread_create(&connectthread, NULL, NPClientConnectThread, NULL);
616 pthread_detach(connectthread);
617 }
618
NPClientConnectThread(void *)619 static void * NPClientConnectThread (void *)
620 {
621 NPNotification("Client: Entered connection thread.", -1);
622
623 if ((NPClientConnectToServer(NP_PORT) == false) ||
624 (NPClientSendNameToServer() == false) ||
625 (NPClientGetROMInfoFromServer() == false))
626 {
627 NPClientDisconnect();
628 npclient.dialogprocess = kNPCDialogConnectFailed;
629 return (NULL);
630 }
631
632 npclient.dialogprocess = kNPCDialogOpenBegin;
633 NPNotification("Client: Exited connection thread.", -1);
634 return (NULL);
635 }
636
NPClientInit(void)637 void NPClientInit (void)
638 {
639 npclient.padloop = false;
640 npclient.exitsgn = false;
641 npclient.phasecount = 0;
642 npclient.phasespan = 0;
643 npclient.header = 0;
644 npclient.online = false;
645 npclient.socket = -1;
646 npclient.numplayers = 0;
647 npclient.name[0] = 0;
648 npclient.serverIP[0] = 0;
649
650 nprominfo.crc32 = 0;
651 nprominfo.input = 0;
652 nprominfo.length = 0;
653 nprominfo.fname[0] = 0;
654
655 for (int i = 0; i < NP_MAX_PLAYERS; i++)
656 {
657 for (int j = 0; j < 64; j++)
658 {
659 npcactvpad[i][j] = 0;
660 npcrecvpad[i][j] = 0;
661 }
662 }
663
664 for (int j = 0; j < 64; j++)
665 {
666 npcsendpad[j] = 0;
667 npccachpad[j] = 0;
668 }
669
670 for (int c = 0; c < NP_MAX_PLAYERS; c++)
671 {
672 npcinfo[c].ready = false;
673 npcinfo[c].player = 0;
674 npcinfo[c].name[0] = 0;
675 }
676 }
677
NPClientConnectToServer(int port)678 static bool8 NPClientConnectToServer (int port)
679 {
680 #ifndef SELF_TEST
681 struct sockaddr_in address;
682 #else
683 struct sockaddr_un address;
684 #endif
685
686 NPNotification("Client: Connecting to server...", -1);
687
688 memset(&address, 0, sizeof(address));
689 #ifndef SELF_TEST
690 address.sin_family = AF_INET;
691 address.sin_addr.s_addr = inet_addr(npclient.serverIP);
692 address.sin_port = htons(port);
693 #else
694 address.sun_family = AF_UNIX;
695 strcpy(address.sun_path, SOCK_NAME);
696 #endif
697
698 #ifndef SELF_TEST
699 if (address.sin_addr.s_addr == INADDR_NONE)
700 {
701 NPError("Client: Server IP is invalid.", 5001);
702 return (false);
703 }
704 #endif
705
706 #ifndef SELF_TEST
707 if ((npclient.socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
708 #else
709 if ((npclient.socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
710 #endif
711 {
712 NPError("Client: Failed to create socket.", 5002);
713 return (false);
714 }
715
716 if (connect(npclient.socket, (struct sockaddr *) &address, sizeof(address)) < 0)
717 {
718 NPError("Client: Failed to connect to server.", 5003);
719 return (false);
720 }
721
722 npclient.online = true;
723
724 NPNotification("Client: Connected to server.", -1);
725 return (true);
726 }
727
NPClientDisconnect(void)728 void NPClientDisconnect (void)
729 {
730 if (npclient.socket != -1)
731 {
732 NPNotification("Client: Disconnecting from server...", -1);
733
734 close(npclient.socket);
735 npclient.socket = -1;
736
737 NPNotification("Client: Disconnected from server.", -1);
738 }
739
740 npclient.online = false;
741 npclient.name[0] = 0;
742 npclient.serverIP[0] = 0;
743 }
744
NPClientSendMesToServer(int num)745 static bool8 NPClientSendMesToServer (int num)
746 {
747 uint8 mes[2];
748
749 mes[0] = NP_CLIENT_MAGIC;
750 mes[1] = num;
751
752 if (socket_write(npclient.socket, mes, 2) != 2)
753 return (false);
754
755 return (true);
756 }
757
NPClientGetMesFromServer(void)758 static int NPClientGetMesFromServer (void)
759 {
760 uint8 mes[2];
761
762 if (socket_read(npclient.socket, mes, 2) != 2)
763 return (-1);
764
765 if (mes[0] != NP_SERVER_MAGIC)
766 return (-1);
767
768 return ((int) mes[1]);
769 }
770
NPClientSendNameToServer(void)771 static bool8 NPClientSendNameToServer (void)
772 {
773 if (!npclient.online)
774 return (false);
775
776 NPNotification("Client: Sending player name to server...", -1);
777
778 if (NPClientGetMesFromServer() != kNPServerNameRequest)
779 {
780 NPError("Client: Failed to receive messsage from server.", 5101);
781 return (false);
782 }
783
784 uint8 mes[4];
785 uint32 l;
786
787 l = strlen(npclient.name);
788 WRITE_LONG(mes + 0, l);
789
790 if (socket_write(npclient.socket, mes, 4) != 4)
791 {
792 NPError("Client: Failed to send name size to server.", 5102);
793 return (false);
794 }
795
796 if (socket_write(npclient.socket, (uint8 *) npclient.name, l) != (int) l)
797 {
798 NPError("Client: Failed to send name to server.", 5103);
799 return (false);
800 }
801
802 if (NPClientGetMesFromServer() != kNPServerNameReceived)
803 {
804 NPError("Client: Failed to receive messsage from server.", 5104);
805 return (false);
806 }
807
808 if (NPClientSendMesToServer(kNPClientNameSent) == false)
809 {
810 NPError("Client: Failed to send messsage to server.", 5105);
811 return (false);
812 }
813
814 NPNotification("Client: Sent player name to server.", -1);
815 return (true);
816 }
817
NPClientGetROMInfoFromServer(void)818 static bool8 NPClientGetROMInfoFromServer (void)
819 {
820 if (!npclient.online)
821 return (false);
822
823 NPNotification("Client: Receiving ROM information from server...", -1);
824
825 if (NPClientGetMesFromServer() != kNPServerROMInfoWillSend)
826 {
827 NPError("Client: Failed to receive messsage from server.", 5201);
828 return (false);
829 }
830
831 if (NPClientSendMesToServer(kNPClientROMInfoWaiting) == false)
832 {
833 NPError("Client: Failed to send messsage to server.", 5202);
834 return (false);
835 }
836
837 uint8 mes[16];
838 uint32 l;
839
840 if (socket_read(npclient.socket, mes, 16) != 16)
841 {
842 NPError("Client: Failed to receive ROM information from server.", 5203);
843 return (false);
844 }
845
846 nprominfo.crc32 = READ_LONG(mes + 0);
847 nprominfo.input = READ_LONG(mes + 4);
848
849 l = READ_LONG(mes + 12);
850
851 if (socket_read(npclient.socket, (uint8 *) nprominfo.fname, l) != (int) l)
852 {
853 NPError("Client: Failed to receive ROM name from server.", 5204);
854 return (false);
855 }
856
857 nprominfo.fname[l] = 0;
858 nprominfo.length = l;
859
860 NPNotification("Client: Received ROM information from server.", -1);
861 return (true);
862 }
863
NPClientStoreConfig(void)864 void NPClientStoreConfig (void)
865 {
866 npclient.savedDeviceSetting = deviceSetting;
867 npclient.savedAutoSaveDelay = Settings.AutoSaveDelay;
868
869 npclient.configsaved = true;
870
871 deviceSetting = nprominfo.input;
872 Settings.AutoSaveDelay = 0;
873
874 ChangeInputDevice();
875 }
876
NPClientRestoreConfig(void)877 void NPClientRestoreConfig (void)
878 {
879 if (npclient.configsaved)
880 {
881 deviceSetting = npclient.savedDeviceSetting;
882 Settings.AutoSaveDelay = npclient.savedAutoSaveDelay;
883
884 npclient.configsaved = false;
885
886 ChangeInputDevice();
887 }
888 }
889
NPClientBeginOpenROMImage(WindowRef window)890 static bool8 NPClientBeginOpenROMImage (WindowRef window)
891 {
892 CFStringRef numRef, romRef, baseRef;
893 CFMutableStringRef mesRef;
894 SInt32 replaceAt;
895 bool8 r;
896
897 DeinitGameWindow();
898
899 if (cartOpen)
900 {
901 SNES9X_SaveSRAM();
902 S9xResetSaveTimer(false);
903 S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
904 }
905
906 cartOpen = false;
907
908 ResetCheatFinder();
909
910 romRef = CFStringCreateWithCString(kCFAllocatorDefault, nprominfo.fname, kCFStringEncodingUTF8);
911 numRef = CFCopyLocalizedString(CFSTR("NPROMNamePos"), "1");
912 baseRef = CFCopyLocalizedString(CFSTR("NPROMNameMes"), "NPROM");
913 mesRef = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, baseRef);
914 replaceAt = CFStringGetIntValue(numRef);
915 CFStringReplace(mesRef, CFRangeMake(replaceAt - 1, 1), romRef);
916
917 r = NavBeginOpenROMImageSheet(window, mesRef);
918
919 CFRelease(mesRef);
920 CFRelease(baseRef);
921 CFRelease(numRef);
922 CFRelease(romRef);
923
924 return (r);
925 }
926
NPClientEndOpenROMImage(void)927 static bool8 NPClientEndOpenROMImage (void)
928 {
929 OSStatus err;
930 FSRef cartRef;
931 char filename[PATH_MAX + 1];
932 bool8 r;
933
934 r = NavEndOpenROMImageSheet(&cartRef);
935 if (!r)
936 {
937 cartOpen = false;
938 return (false);
939 }
940
941 CheckSaveFolder(&cartRef);
942
943 Settings.ForceLoROM = (romDetect == kLoROMForce );
944 Settings.ForceHiROM = (romDetect == kHiROMForce );
945 Settings.ForceHeader = (headerDetect == kHeaderForce );
946 Settings.ForceNoHeader = (headerDetect == kNoHeaderForce );
947 Settings.ForceInterleaved = (interleaveDetect == kInterleaveForce );
948 Settings.ForceInterleaved2 = (interleaveDetect == kInterleave2Force );
949 Settings.ForceInterleaveGD24 = (interleaveDetect == kInterleaveGD24 );
950 Settings.ForceNotInterleaved = (interleaveDetect == kNoInterleaveForce);
951 Settings.ForcePAL = (videoDetect == kPALForce );
952 Settings.ForceNTSC = (videoDetect == kNTSCForce );
953
954 GFX.InfoString = NULL;
955 GFX.InfoStringTimeout = 0;
956
957 S9xResetSaveTimer(true);
958
959 err = FSRefMakePath(&cartRef, (unsigned char *) filename, PATH_MAX);
960
961 SNES9X_InitSound();
962
963 if (Memory.LoadROM(filename) /*&& (Memory.ROMCRC32 == nprominfo.crc32)*/)
964 {
965 ChangeTypeAndCreator(filename, 'CART', '~9X~');
966 cartOpen = true;
967 return (true);
968 }
969 else
970 {
971 cartOpen = false;
972 return (false);
973 }
974 }
975
NPClientDetachPrepareThread(void)976 static void NPClientDetachPrepareThread (void)
977 {
978 pthread_create(&preparethread, NULL, NPClientPrepareThread, NULL);
979 pthread_detach(preparethread);
980 }
981
NPClientPrepareThread(void *)982 static void * NPClientPrepareThread (void *)
983 {
984 NPNotification("Client: Entered preparing thread.", -1);
985
986 if ((NPClientROMReadyToServer() == false) ||
987 (NPClientGetSRAMFromServer() == false) ||
988 (NPClientGetPlayerListFromServer() == false) ||
989 (NPClientReplyPhaseSpanTest() == false))
990 {
991 NPClientDisconnect();
992 npclient.dialogprocess = kNPCDialogPrepareFailed;
993 return (NULL);
994 }
995
996 npclient.dialogprocess = kNPCDialogShowList;
997 NPNotification("Client: Exited preparing thread.", -1);
998 return (NULL);
999 }
1000
NPClientROMReadyToServer(void)1001 static bool8 NPClientROMReadyToServer (void)
1002 {
1003 if (!npclient.online)
1004 return (false);
1005
1006 NPNotification("Client: Sending ROM ready sign to server...", -1);
1007
1008 if (NPClientSendMesToServer(kNPClientROMOpened) == false)
1009 {
1010 NPError("Client: Failed to send messsage to server.", 5401);
1011 return (false);
1012 }
1013
1014 NPNotification("Client: Sent ROM ready sign to server.", -1);
1015 return (true);
1016 }
1017
NPClientGetSRAMFromServer(void)1018 static bool8 NPClientGetSRAMFromServer (void)
1019 {
1020 if (!npclient.online)
1021 return (false);
1022
1023 NPNotification("Client: Receiving SRAM from server...", -1);
1024
1025 if (NPClientGetMesFromServer() != kNPServerSRAMWillSend)
1026 {
1027 NPError("Client: Failed to receive messsage from server.", 5501);
1028 return (false);
1029 }
1030
1031 if (NPClientSendMesToServer(kNPClientSRAMWaiting) == false)
1032 {
1033 NPError("Client: Failed to send messsage to server.", 5502);
1034 return (false);
1035 }
1036
1037 uint8 mes[4];
1038 uint32 sramsize;
1039
1040 if (socket_read(npclient.socket, mes, 4) != 4)
1041 {
1042 NPError("Client: Failed to receive SRAM size from server.", 5503);
1043 return (false);
1044 }
1045
1046 sramsize = READ_LONG(mes + 0);
1047
1048 if (sramsize != (uint32) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0))
1049 {
1050 NPError("Client: SRAM size mismatch.", 5504);
1051 return (false);
1052 }
1053
1054 if (sramsize && (socket_read(npclient.socket, Memory.SRAM, sramsize) != (int) sramsize))
1055 {
1056 NPError("Server: Failed to receive SRAM from server.", 5505);
1057 return (false);
1058 }
1059
1060 if (NPClientSendMesToServer(kNPClientSRAMLoaded) == false)
1061 {
1062 NPError("Client: Failed to send messsage to server.", 5506);
1063 return (false);
1064 }
1065
1066 NPNotification("Client: Received SRAM from server.", -1);
1067 return (true);
1068 }
1069
NPClientGetPlayerListFromServer(void)1070 static bool8 NPClientGetPlayerListFromServer (void)
1071 {
1072 if (!npclient.online)
1073 return (false);
1074
1075 NPNotification("Client: Receiving player list from server...", -1);
1076
1077 if (NPClientGetMesFromServer() != kNPServerPlayerWillSend)
1078 {
1079 NPError("Client: Failed to receive messsage from server.", 5701);
1080 return (false);
1081 }
1082
1083 if (NPClientSendMesToServer(kNPClientPlayerWaiting) == false)
1084 {
1085 NPError("Client: Failed to send messsage to server.", 5702);
1086 return (false);
1087 }
1088
1089 for (int i = 0; i < NP_MAX_PLAYERS; i++)
1090 {
1091 uint8 mes[10];
1092 uint32 l;
1093
1094 if (socket_read(npclient.socket, mes, 10) != 10)
1095 {
1096 NPError("Client: Failed to receive messsage from server.", 5703);
1097 return (false);
1098 }
1099
1100 npcinfo[i].ready = READ_BYTE(mes + 1);
1101 npcinfo[i].player = READ_LONG(mes + 2);
1102
1103 l = READ_LONG(mes + 6);
1104
1105 if (l && (socket_read(npclient.socket, (uint8 *) npcinfo[i].name, l) != (int) l))
1106 {
1107 NPError("Client: Failed to receive messsage from server.", 5704);
1108 return (false);
1109 }
1110
1111 npcinfo[i].name[l] = 0;
1112 }
1113
1114 npclient.numplayers = 0;
1115 for (int i = 0; i < NP_MAX_PLAYERS; i++)
1116 if (npcinfo[i].ready)
1117 npclient.numplayers++;
1118
1119 NPNotification("Client: Received player list from server.", -1);
1120 NPNotification("Client: Number of players: %d", npclient.numplayers);
1121
1122 return (true);
1123 }
1124
NPClientReplyPhaseSpanTest(void)1125 static bool8 NPClientReplyPhaseSpanTest (void)
1126 {
1127 uint8 mes[21];
1128 int l = npclient.numplayers * 4 + 1;
1129
1130 NPNotification("Client: Replying sending / receiving pad states test...", -1);
1131
1132 for (int n = 0; n < 5; n++)
1133 {
1134 if (socket_read(npclient.socket, mes, l) != l)
1135 return (false);
1136
1137 if (socket_write(npclient.socket, mes, 5) != 5)
1138 return (false);
1139 }
1140
1141 NPNotification("Client: Replied sending / receiving pad states test.", -1);
1142
1143 NPNotification("Client: Receiving phase span value from server...", -1);
1144
1145 if (socket_read(npclient.socket, mes, 4) != 4)
1146 return (false);
1147
1148 npclient.phasespan = READ_LONG(mes + 0);
1149
1150 NPNotification(" phase span: %d (frames)", npclient.phasespan);
1151
1152 NPNotification("Client: Received phase span value from server.", -1);
1153
1154 return (true);
1155 }
1156
NPClientBeginPlayerListSheet(void)1157 static void NPClientBeginPlayerListSheet (void)
1158 {
1159 OSStatus err;
1160 CFStringRef ref;
1161 HIViewRef ctl, root;
1162 HIViewID cid;
1163
1164 root = HIViewGetRoot(sRef);
1165 cid.signature = 'PLNM';
1166
1167 for (int i = 0; i < NP_MAX_PLAYERS; i++)
1168 {
1169 if (npcinfo[i].ready)
1170 {
1171 cid.id = npcinfo[i].player;
1172 HIViewFindByID(root, cid, &ctl);
1173 ref = CFStringCreateWithCString(kCFAllocatorDefault, npcinfo[i].name, kCFStringEncodingUTF8);
1174 if (ref)
1175 {
1176 SetStaticTextCFString(ctl, ref, false);
1177 CFRelease(ref);
1178 }
1179 else
1180 SetStaticTextCFString(ctl, CFSTR("unknown"), false);
1181 }
1182 }
1183
1184 err = ShowSheetWindow(sRef, mRef);
1185 }
1186
NPClientEndPlayerListSheet(void)1187 static void NPClientEndPlayerListSheet (void)
1188 {
1189 OSStatus err;
1190
1191 err = HideSheetWindow(sRef);
1192 }
1193
NPClientSheetEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)1194 static pascal OSStatus NPClientSheetEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
1195 {
1196 if (!npclient.dialogsheet)
1197 return (eventNotHandledErr);
1198
1199 OSStatus err, result = eventNotHandledErr;
1200
1201 switch (GetEventClass(inEvent))
1202 {
1203 case kEventClassCommand:
1204 switch (GetEventKind(inEvent))
1205 {
1206 HICommand tHICommand;
1207
1208 case kEventCommandUpdateStatus:
1209 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
1210 if (err == noErr && tHICommand.commandID == 'clos')
1211 {
1212 UpdateMenuCommandStatus(false);
1213 result = noErr;
1214 }
1215
1216 break;
1217
1218 case kEventCommandProcess:
1219 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
1220 if (err == noErr)
1221 {
1222 switch (tHICommand.commandID)
1223 {
1224 case 'ok ':
1225 npclient.dialogprocess = kNPCDialogDone;
1226 result = noErr;
1227 break;
1228 }
1229 }
1230
1231 break;
1232 }
1233
1234 break;
1235 }
1236
1237 return (result);
1238 }
1239
NPClientDetachNetPlayThread(void)1240 void NPClientDetachNetPlayThread (void)
1241 {
1242 NPNotification("Client: Detaching pad thread...", -1);
1243
1244 npclient.padloop = true;
1245 npclient.exitsgn = false;
1246
1247 csememu = sem_open(n_csememu, O_CREAT, 0600, 0);
1248 csempad = sem_open(n_csempad, O_CREAT, 0600, 0);
1249
1250 pthread_create(&gamepadthread, NULL, NPClientNetPlayThread, NULL);
1251 pthread_detach(gamepadthread);
1252
1253 NPNotification("Client: Detached pad thread.", -1);
1254 }
1255
NPClientStopNetPlayThread(void)1256 void NPClientStopNetPlayThread (void)
1257 {
1258 NPNotification("Client: Stopping pad thread...", -1);
1259
1260 npclient.padloop = false;
1261 sem_post(csempad);
1262 sem_post(csememu);
1263
1264 while (!npclient.exitsgn)
1265 sleep(0);
1266
1267 sem_unlink(n_csememu);
1268 sem_unlink(n_csempad);
1269 sem_close(csememu);
1270 sem_close(csempad);
1271
1272 NPNotification("Client: Stopped pad thread.", -1);
1273 }
1274
NPClientNetPlayWaitStart(void)1275 bool8 NPClientNetPlayWaitStart (void)
1276 {
1277 NPNotification("Client: Waiting start flag...", -1);
1278
1279 if (NPClientSendMesToServer(kNPClientStartWait) == false)
1280 {
1281 NPError("Client: Failed to send messsage to server.", 5801);
1282 return (false);
1283 }
1284
1285 if (NPClientGetMesFromServer() != kNPServerStart)
1286 {
1287 NPError("Client: Failed to send messsage to server.", 5802);
1288 return (false);
1289 }
1290
1291 npclient.phasecount = 0;
1292 npclient.header = 0;
1293
1294 sem_post(csempad);
1295
1296 NPNotification("Client: Netplay started.", -1);
1297 return (true);
1298 }
1299
NPClientNetPlayThread(void *)1300 static void * NPClientNetPlayThread (void *)
1301 {
1302 uint8 mes[NP_MAX_PLAYERS * 64 * 4 + 1];
1303 uint8 count = 0;
1304 int l;
1305
1306 NPNotification("Client: Entered pad thread.", -1);
1307
1308 while (npclient.padloop)
1309 {
1310 sem_wait(csempad);
1311
1312 l = npclient.numplayers * npclient.phasespan * 4 + 1;
1313 if (socket_read(npclient.socket, mes, l) != l)
1314 {
1315 npclient.exitsgn = true;
1316 sem_post(csememu);
1317 pthread_exit(NULL);
1318 }
1319
1320 if ((mes[0] & 0xF) != count)
1321 NPNotification("Client: Warning: Failed to synchronize server.", -1);
1322
1323 npclient.header = mes[0] & 0xF0;
1324
1325 for (int i = 0; i < npclient.numplayers; i++)
1326 for (uint32 j = 0; j < npclient.phasespan; j++)
1327 npcrecvpad[i][j] = READ_LONG(mes + (i * npclient.phasespan + j) * 4 + 1);
1328
1329 WRITE_BYTE(mes + 0, count);
1330
1331 for (uint32 j = 0; j < npclient.phasespan; j++)
1332 WRITE_LONG(mes + j * 4 + 1, npcsendpad[j]);
1333
1334 l = npclient.phasespan * 4 + 1;
1335 if (socket_write(npclient.socket, mes, l) != l)
1336 {
1337 npclient.exitsgn = true;
1338 sem_post(csememu);
1339 pthread_exit(NULL);
1340 }
1341
1342 count = (count + 1) & 0xF;
1343
1344 sem_post(csememu);
1345 }
1346
1347 npclient.exitsgn = true;
1348
1349 NPNotification("Client: Exited pad thread.", -1);
1350 return (NULL);
1351 }
1352
NPClientProcessInput(void)1353 void NPClientProcessInput (void)
1354 {
1355 static uint32 pos = 0;
1356 KeyMap myKeys;
1357
1358 if (npclient.exitsgn)
1359 {
1360 if (s9xthreadrunning)
1361 {
1362 if (!eventQueued)
1363 {
1364 PostQueueToSubEventLoop();
1365 eventQueued = true;
1366 }
1367 }
1368 else
1369 running = false;
1370
1371 return;
1372 }
1373
1374 if (npclient.phasecount == 0)
1375 {
1376 sem_wait(csememu);
1377
1378 for (int i = 0; i < npclient.numplayers; i++)
1379 for (uint32 j = 0; j < npclient.phasespan; j++)
1380 npcactvpad[i][j] = npcrecvpad[i][j];
1381
1382 for (uint32 j = 0; j < npclient.phasespan; j++)
1383 npcsendpad[j] = npccachpad[j];
1384
1385 if (npclient.header & 0x80)
1386 {
1387 npcsendpad[npclient.phasespan] = 0;
1388 for (int i = 0; i < npclient.numplayers; i++)
1389 npcactvpad[i][npclient.phasespan] = 0;
1390
1391 npclient.phasespan++;
1392 if (npclient.phasespan > (uint32) Memory.ROMFramesPerSecond)
1393 npclient.phasespan = (uint32) Memory.ROMFramesPerSecond;
1394
1395 char str[256];
1396 sprintf(str, "delay: %d", npclient.phasespan);
1397 S9xMessage(0, 0, str);
1398 }
1399 else
1400 if (npclient.header & 0x40)
1401 {
1402 npclient.phasespan--;
1403 if (npclient.phasespan == 0)
1404 npclient.phasespan = 1;
1405
1406 char str[256];
1407 sprintf(str, "delay: %d", npclient.phasespan);
1408 S9xMessage(0, 0, str);
1409 }
1410
1411 npclient.header = 0;
1412 pos = 0;
1413 }
1414
1415 for (int i = 0; i < npclient.numplayers; i++)
1416 {
1417 controlPad[i] = npcactvpad[i][pos];
1418 ControlPadFlagsToS9xReportButtons(i, controlPad[i]);
1419 }
1420
1421 GetKeys(myKeys);
1422
1423 uint32 pad = 0;
1424
1425 JoypadScanDirection(0, &pad);
1426 if (ISpKeyIsPressed(kISp1PR )) pad |= 0x0010;
1427 if (ISpKeyIsPressed(kISp1PL )) pad |= 0x0020;
1428 if (ISpKeyIsPressed(kISp1PX )) pad |= 0x0040;
1429 if (ISpKeyIsPressed(kISp1PA )) pad |= 0x0080;
1430 if (ISpKeyIsPressed(kISp1PStart )) pad |= 0x1000;
1431 if (ISpKeyIsPressed(kISp1PSelect)) pad |= 0x2000;
1432 if (ISpKeyIsPressed(kISp1PY )) pad |= 0x4000;
1433 if (ISpKeyIsPressed(kISp1PB )) pad |= 0x8000;
1434
1435 if (KeyIsPressed(myKeys, keyCode[k1PR] )) pad |= 0x0010;
1436 if (KeyIsPressed(myKeys, keyCode[k1PL] )) pad |= 0x0020;
1437 if (KeyIsPressed(myKeys, keyCode[k1PX] )) pad |= 0x0040;
1438 if (KeyIsPressed(myKeys, keyCode[k1PA] )) pad |= 0x0080;
1439 if (KeyIsPressed(myKeys, keyCode[k1PRight] )) pad |= 0x0100;
1440 if (KeyIsPressed(myKeys, keyCode[k1PLeft] )) pad |= 0x0200;
1441 if (KeyIsPressed(myKeys, keyCode[k1PDown] )) pad |= 0x0400;
1442 if (KeyIsPressed(myKeys, keyCode[k1PUp] )) pad |= 0x0800;
1443 if (KeyIsPressed(myKeys, keyCode[k1PStart] )) pad |= 0x1000;
1444 if (KeyIsPressed(myKeys, keyCode[k1PSelect])) pad |= 0x2000;
1445 if (KeyIsPressed(myKeys, keyCode[k1PY] )) pad |= 0x4000;
1446 if (KeyIsPressed(myKeys, keyCode[k1PB] )) pad |= 0x8000;
1447
1448 npccachpad[pos] = pad;
1449
1450 if (npclient.phasecount == 0)
1451 {
1452 npclient.phasecount = npclient.phasespan;
1453 sem_post(csempad);
1454 }
1455
1456 npclient.phasecount--;
1457 pos++;
1458 }
1459