cleanup
[fceu.git] / input.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Ben Parnell
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include <string.h>
22 #include "types.h"
23 #include "x6502.h"
24
25 #include "fce.h"
26 #include "sound.h"
27 #include "netplay.h"
28 #include "svga.h"
29
30 #include "input.h"
31 #include "state.h"
32 #include "movie.h"
33
34 #include "fds.h"
35 #include "vsuni.h"
36 #include "dprintf.h"
37
38 extern INPUTC *FCEU_InitZapper(int w);
39 extern INPUTC *FCEU_InitPowerpad(int w);
40 extern INPUTC *FCEU_InitArkanoid(int w);
41
42 extern INPUTCFC *FCEU_InitArkanoidFC(void);
43 extern INPUTCFC *FCEU_InitSpaceShadow(void);
44 extern INPUTCFC *FCEU_InitFKB(void);
45 static uint8 joy_readbit[2];
46 static uint8 joy[4]={0,0,0,0};
47 static uint8 LastStrobe;
48
49 extern int coinon;
50
51 static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
52 static int JPAttrib[2]={0,0};
53 static int JPType[2]={0,0};
54 static void *InputDataPtr[2];
55
56 static int JPAttribFC=0;
57 static int JPTypeFC=0;
58 static void *InputDataPtrFC;
59
60 void (*InputScanlineHook)(uint8 *buf, int line);
61
62 static INPUTC DummyJPort={0,0,0,0,0};
63 static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
64 static INPUTCFC *FCExp=0;
65
66 /* This function is a quick hack to get the NSF player to use emulated gamepad
67    input.
68 */
69 uint8 FCEU_GetJoyJoy(void)
70 {
71  return(joy[0]|joy[1]|joy[2]|joy[3]);
72 }
73
74 static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
75 {
76                 uint8 ret=0;
77
78                 if(joy_readbit[w]>=8)
79                  ret=1;
80                 else
81                 {
82                  ret = ((joy[w]>>(joy_readbit[w]))&1);
83                  joy_readbit[w]++;
84                 }
85                 return ret;
86 }
87
88 static uint8 FP_FASTAPASS(1) ReadGP(int w)
89 {
90                 uint8 ret;
91                 //if(JoyMulti)
92                 //{
93                  //ret = ((joy[w]>>(joy_readbit[w]))&1)|
94                  //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
95                  //if(joy_readbit[w]>8) ret=0;
96                 //}
97                 ret = ((joy[w]>>(joy_readbit[w]))&1);
98                 if(FSDisable)
99                 {
100                  if(joy_readbit[w]>=8) ret|=1;
101                 }
102                 else
103                 {
104                  if(joy_readbit[w]==19-w) ret|=1;
105                 }
106                 joy_readbit[w]++;
107                 return ret;
108 }
109
110 static DECLFR(JPRead)
111 {
112         uint8 ret=0;
113
114         if(JPorts[A&1]->Read)
115          ret|=JPorts[A&1]->Read(A&1);
116
117         if(FCExp)
118          if(FCExp->Read)
119           ret=FCExp->Read(A&1,ret);
120
121         ret|=X.DB&0xC0;
122         dprintf("JPRead %02x", ret);
123         return(ret);
124 }
125
126 static DECLFW(B4016)
127 {
128         if(FCExp)
129          if(FCExp->Write)
130           FCExp->Write(V&7);
131
132         if(JPorts[0]->Write)
133          JPorts[0]->Write(V&1);
134         if(JPorts[1]->Write)
135          JPorts[1]->Write(V&1);
136
137         if((LastStrobe&1) && (!(V&1)))
138         {
139          /* This strobe code is just for convenience.  If it were
140             with the code in input / *.c, it would more accurately represent
141             what's really going on.  But who wants accuracy? ;)
142             Seriously, though, this shouldn't be a problem.
143          */
144          if(JPorts[0]->Strobe)
145           JPorts[0]->Strobe(0);
146          if(JPorts[1]->Strobe)
147           JPorts[1]->Strobe(1);
148          if(FCExp)
149           if(FCExp->Strobe)
150            FCExp->Strobe();
151          }
152          LastStrobe=V&1;
153 }
154
155 static void FP_FASTAPASS(1) StrobeGP(int w)
156 {
157         joy_readbit[w]=0;
158 }
159
160 static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
161 static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
162
163 void DrawInput(uint8 *buf)
164 {
165  int x;
166
167  for(x=0;x<2;x++)
168   if(JPorts[x]->Draw)
169    JPorts[x]->Draw(x,buf,JPAttrib[x]);
170  if(FCExp)
171   if(FCExp->Draw)
172    FCExp->Draw(buf,JPAttribFC);
173 }
174
175 void UpdateInput(void)
176 {
177         int x;
178
179         for(x=0;x<2;x++)
180         {
181          switch(JPType[x])
182          {
183           case SI_GAMEPAD:
184                 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
185                 else joy[1]=*(uint16 *)InputDataPtr[1];
186                 break;
187           default:
188                 if(JPorts[x]->Update)
189                  JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
190                 break;
191          }
192         }
193         if(FCExp)
194          if(FCExp->Update)
195           FCExp->Update(InputDataPtrFC,JPAttribFC);
196
197         if(FCEUGameInfo.type==GIT_VSUNI)
198         {
199          uint16 t=joy[0];
200          joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
201          joy[1]=(joy[1]&0xC)|(t&0xF3);
202          if(coinon) coinon--;
203         }
204         #ifdef NETWORK
205         if(netplay) NetplayUpdate(&joy[0],&joy[1]);
206         #endif
207         if (current < 0) FCEUMOV_AddJoy(joy);
208         //FlushCommandQueue();
209 }
210
211 static DECLFR(VSUNIRead0)
212 {
213         uint8 ret=0;
214
215         if(JPorts[0]->Read)
216          ret|=(JPorts[0]->Read(0))&1;
217
218         ret|=(vsdip&3)<<3;
219         if(coinon)
220          ret|=0x4;
221         return ret;
222 }
223
224 static DECLFR(VSUNIRead1)
225 {
226         uint8 ret=0;
227
228         if(JPorts[1]->Read)
229          ret|=(JPorts[1]->Read(1))&1;
230         ret|=vsdip&0xFC;
231         return ret;
232 }
233
234 static void SLHLHook(uint8 *buf, int line)
235 {
236  int x;
237
238  for(x=0;x<2;x++)
239   if(JPorts[x]->SLHook)
240    JPorts[x]->SLHook(x,buf,line);
241  if(FCExp)
242   if(FCExp->SLHook)
243    FCExp->SLHook(buf,line);
244 }
245
246 static void CheckSLHook(void)
247 {
248         InputScanlineHook=0;
249         if(JPorts[0]->SLHook || JPorts[1]->SLHook)
250          InputScanlineHook=SLHLHook;
251         if(FCExp)
252          if(FCExp->SLHook)
253           InputScanlineHook=SLHLHook;
254 }
255
256 static void FASTAPASS(1) SetInputStuff(int x)
257 {
258          switch(JPType[x])
259          {
260           case SI_GAMEPAD:
261            if(FCEUGameInfo.type==GIT_VSUNI)
262             JPorts[x]=&GPCVS;
263            else
264             JPorts[x]=&GPC;
265           break;
266           case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
267           case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
268           case SI_POWERPADA:JPorts[x]=FCEU_InitPowerpad(x);break;
269           case SI_NONE:JPorts[x]=&DummyJPort;break;
270          }
271
272         CheckSLHook();
273 }
274
275 static uint8 F4ReadBit[2];
276 static void StrobeFami4(void)
277 {
278  F4ReadBit[0]=F4ReadBit[1]=0;
279 }
280
281 static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
282 {
283  ret&=1;
284
285  ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
286  if(F4ReadBit[w]>=8) ret|=2;
287  else F4ReadBit[w]++;
288
289  return(ret);
290 }
291
292 static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
293 static void SetInputStuffFC(void)
294 {
295         switch(JPTypeFC)
296         {
297          case SIFC_NONE:FCExp=0;break;
298          case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
299          case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
300          case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
301          case SIFC_FKB:FCExp=FCEU_InitFKB();break;
302         }
303         CheckSLHook();
304 }
305
306 // VS Unisystem code called after SetInputMap() hooks B4016.  Need to
307 // rewrite code to make this more sane?
308
309 void InitializeInput(void)
310 {
311         memset(joy_readbit,0,sizeof(joy_readbit));
312         memset(joy,0,sizeof(joy));
313         LastStrobe=0;
314
315         if(FCEUGameInfo.type==GIT_VSUNI)
316         {
317          SetReadHandler(0x4016,0x4016,VSUNIRead0);
318          SetReadHandler(0x4017,0x4017,VSUNIRead1);
319         }
320         else
321          SetReadHandler(0x4016,0x4017,JPRead);
322         SetWriteHandler(0x4016,0x4016,B4016);
323
324         SetInputStuff(0);
325         SetInputStuff(1);
326         SetInputStuffFC();
327 }
328
329 void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
330 {
331  JPAttrib[port]=attrib;
332  JPType[port]=type;
333  InputDataPtr[port]=ptr;
334  SetInputStuff(port);
335 }
336
337 void FCEUI_DisableFourScore(int s)
338 {
339  FSDisable=s;
340 }
341
342 void FCEUI_SetInputFC(int type, void *ptr, int attrib)
343 {
344  JPAttribFC=attrib;
345  JPTypeFC=type;
346  InputDataPtrFC=ptr;
347  SetInputStuffFC();
348 }
349
350 // quick paste
351 #define FCEUNPCMD_RESET   0x01
352 #define FCEUNPCMD_POWER   0x02
353
354 #define FCEUNPCMD_VSUNICOIN     0x07
355 #define FCEUNPCMD_VSUNIDIP0     0x08
356 #define FCEUNPCMD_FDSINSERT     0x18
357 #define FCEUNPCMD_FDSSELECT     0x1A
358
359
360 void FCEU_DoSimpleCommand(int cmd)
361 {
362  switch(cmd)
363  {
364    case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
365    case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
366 //   case FCEUNPCMD_FDSEJECT: FCEU_FDSEject();break;
367    case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
368    case FCEUNPCMD_VSUNIDIP0 ... (FCEUNPCMD_VSUNIDIP0 + 7): FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);break;
369    case FCEUNPCMD_POWER: PowerNES();break;
370    case FCEUNPCMD_RESET: ResetNES();break;
371    default: printf("FCEU_DoSimpleCommand: can't handle cmd %i\n", cmd); break;
372  }
373 }
374
375 void FCEU_QSimpleCommand(int cmd)
376 {
377 // if(FCEUnetplay)
378 //  FCEUNET_SendCommand(cmd, 0);
379 // else
380  {
381   // totally wrong:
382 //  if(!FCEUMOV_IsPlaying())
383 //   FCEU_DoSimpleCommand(cmd);
384 //  else
385 //   FCEUMOV_AddCommand(cmd);
386
387   FCEU_DoSimpleCommand(cmd);
388 //  if(FCEUMOV_IsRecording())
389 //   FCEUMOV_AddCommand(cmd);
390  }
391 }
392
393 void FCEUI_FDSSelect(void)
394 {
395  FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
396 }
397
398 int FCEUI_FDSInsert(void)
399 {
400  FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
401  return(1);
402 }
403
404 /*
405 int FCEUI_FDSEject(void)
406 {
407     FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
408     return(1);
409 }
410 */
411 void FCEUI_VSUniToggleDIP(int w)
412 {
413  FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
414 }
415
416 void FCEUI_VSUniCoin(void)
417 {
418  FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
419 }
420
421 void FCEUI_ResetNES(void)
422 {
423         FCEU_QSimpleCommand(FCEUNPCMD_RESET);
424 }
425
426 void FCEUI_PowerNES(void)
427 {
428         FCEU_QSimpleCommand(FCEUNPCMD_POWER);
429 }
430
431
432
433 SFORMAT FCEUCTRL_STATEINFO[]={
434  { joy_readbit, 2, "JYRB"},
435  { joy, 4, "JOYS"},
436  { &LastStrobe, 1, "LSTS"},
437  { 0 }
438 };
439
440