e4223bcea20b94a4b3113a97d7f39e14c2ecb73e
[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 "dprintf.h"
35
36 extern INPUTC *FCEU_InitZapper(int w);
37 extern INPUTC *FCEU_InitPowerpad(int w);
38 extern INPUTC *FCEU_InitArkanoid(int w);
39
40 extern INPUTCFC *FCEU_InitArkanoidFC(void);
41 extern INPUTCFC *FCEU_InitSpaceShadow(void);
42 extern INPUTCFC *FCEU_InitFKB(void);
43 static uint8 joy_readbit[2];
44 static uint8 joy[4]={0,0,0,0};
45 static uint8 LastStrobe;
46
47 extern int coinon;
48
49 static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
50 static int JPAttrib[2]={0,0};
51 static int JPType[2]={0,0};
52 static void *InputDataPtr[2];
53
54 static int JPAttribFC=0;
55 static int JPTypeFC=0;
56 static void *InputDataPtrFC;
57
58 void (*InputScanlineHook)(uint8 *buf, int line);
59
60 static INPUTC DummyJPort={0,0,0,0,0};
61 static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
62 static INPUTCFC *FCExp=0;
63
64 static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
65 {
66                 uint8 ret=0;
67
68                 if(joy_readbit[w]>=8)
69                  ret=1;
70                 else
71                 {
72                  ret = ((joy[w]>>(joy_readbit[w]))&1);
73                  joy_readbit[w]++;
74                 }
75                 return ret;
76 }
77
78 static uint8 FP_FASTAPASS(1) ReadGP(int w)
79 {
80                 uint8 ret;
81                 //if(JoyMulti)
82                 //{
83                  //ret = ((joy[w]>>(joy_readbit[w]))&1)|
84                  //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
85                  //if(joy_readbit[w]>8) ret=0;
86                 //}
87                 ret = ((joy[w]>>(joy_readbit[w]))&1);
88                 if(FSDisable)
89                 {
90                  if(joy_readbit[w]>=8) ret|=1;
91                 }
92                 else
93                 {
94                  if(joy_readbit[w]==19-w) ret|=1;
95                 }
96                 joy_readbit[w]++;
97                 return ret;
98 }
99
100 static DECLFR(JPRead)
101 {
102         uint8 ret=0;
103
104         if(JPorts[A&1]->Read)
105          ret|=JPorts[A&1]->Read(A&1);
106
107         if(FCExp)
108          if(FCExp->Read)
109           ret=FCExp->Read(A&1,ret);
110
111         ret|=X.DB&0xC0;
112         dprintf("JPRead %02x", ret);
113         return(ret);
114 }
115
116 static DECLFW(B4016)
117 {
118         if(FCExp)
119          if(FCExp->Write)
120           FCExp->Write(V&7);
121
122         if(JPorts[0]->Write)
123          JPorts[0]->Write(V&1);
124         if(JPorts[1]->Write)
125          JPorts[1]->Write(V&1);
126
127         if((LastStrobe&1) && (!(V&1)))
128         {
129          /* This strobe code is just for convenience.  If it were
130             with the code in input / *.c, it would more accurately represent
131             what's really going on.  But who wants accuracy? ;)
132             Seriously, though, this shouldn't be a problem.
133          */
134          if(JPorts[0]->Strobe)
135           JPorts[0]->Strobe(0);
136          if(JPorts[1]->Strobe)
137           JPorts[1]->Strobe(1);
138          if(FCExp)
139           if(FCExp->Strobe)
140            FCExp->Strobe();
141          }
142          LastStrobe=V&1;
143 }
144
145 static void FP_FASTAPASS(1) StrobeGP(int w)
146 {
147         joy_readbit[w]=0;
148 }
149
150 static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
151 static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
152
153 void DrawInput(uint8 *buf)
154 {
155  int x;
156
157  for(x=0;x<2;x++)
158   if(JPorts[x]->Draw)
159    JPorts[x]->Draw(x,buf,JPAttrib[x]);
160  if(FCExp)
161   if(FCExp->Draw)
162    FCExp->Draw(buf,JPAttribFC);
163 }
164
165 void UpdateInput(void)
166 {
167         int x;
168
169         for(x=0;x<2;x++)
170         {
171          switch(JPType[x])
172          {
173           case SI_GAMEPAD:
174                 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
175                 else joy[1]=*(uint16 *)InputDataPtr[1];
176                 break;
177           default:
178                 if(JPorts[x]->Update)
179                  JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
180                 break;
181          }
182         }
183         if(FCExp)
184          if(FCExp->Update)
185           FCExp->Update(InputDataPtrFC,JPAttribFC);
186
187         if(FCEUGameInfo.type==GIT_VSUNI)
188         {
189          uint16 t=joy[0];
190          joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
191          joy[1]=(joy[1]&0xC)|(t&0xF3);
192          if(coinon) coinon--;
193         }
194         #ifdef NETWORK
195         if(netplay) NetplayUpdate(&joy[0],&joy[1]);
196         #endif
197         if (current < 0) FCEUMOV_AddJoy(joy);
198         FlushCommandQueue();
199 }
200
201 static DECLFR(VSUNIRead0)
202 {
203         uint8 ret=0;
204
205         if(JPorts[0]->Read)
206          ret|=(JPorts[0]->Read(0))&1;
207
208         ret|=(vsdip&3)<<3;
209         if(coinon)
210          ret|=0x4;
211         return ret;
212 }
213
214 static DECLFR(VSUNIRead1)
215 {
216         uint8 ret=0;
217
218         if(JPorts[1]->Read)
219          ret|=(JPorts[1]->Read(1))&1;
220         ret|=vsdip&0xFC;
221         return ret;
222 }
223
224 static void SLHLHook(uint8 *buf, int line)
225 {
226  int x;
227
228  for(x=0;x<2;x++)
229   if(JPorts[x]->SLHook)
230    JPorts[x]->SLHook(x,buf,line);
231  if(FCExp)
232   if(FCExp->SLHook)
233    FCExp->SLHook(buf,line);
234 }
235
236 static void CheckSLHook(void)
237 {
238         InputScanlineHook=0;
239         if(JPorts[0]->SLHook || JPorts[1]->SLHook)
240          InputScanlineHook=SLHLHook;
241         if(FCExp)
242          if(FCExp->SLHook)
243           InputScanlineHook=SLHLHook;
244 }
245
246 static void FASTAPASS(1) SetInputStuff(int x)
247 {
248          switch(JPType[x])
249          {
250           case SI_GAMEPAD:
251            if(FCEUGameInfo.type==GIT_VSUNI)
252             JPorts[x]=&GPCVS;
253            else
254             JPorts[x]=&GPC;
255           break;
256           case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
257           case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
258           case SI_POWERPAD:JPorts[x]=FCEU_InitPowerpad(x);break;
259           case SI_NONE:JPorts[x]=&DummyJPort;break;
260          }
261
262         CheckSLHook();
263 }
264
265 static uint8 F4ReadBit[2];
266 static void StrobeFami4(void)
267 {
268  F4ReadBit[0]=F4ReadBit[1]=0;
269 }
270
271 static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
272 {
273  ret&=1;
274
275  ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
276  if(F4ReadBit[w]>=8) ret|=2;
277  else F4ReadBit[w]++;
278
279  return(ret);
280 }
281
282 static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
283 static void SetInputStuffFC(void)
284 {
285         switch(JPTypeFC)
286         {
287          case SIFC_NONE:FCExp=0;break;
288          case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
289          case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
290          case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
291          case SIFC_FKB:FCExp=FCEU_InitFKB();break;
292         }
293         CheckSLHook();
294 }
295
296 // VS Unisystem code called after SetInputMap() hooks B4016.  Need to
297 // rewrite code to make this more sane?
298
299 void InitializeInput(void)
300 {
301         memset(joy_readbit,0,sizeof(joy_readbit));
302         memset(joy,0,sizeof(joy));
303         LastStrobe=0;
304
305         if(FCEUGameInfo.type==GIT_VSUNI)
306         {
307          SetReadHandler(0x4016,0x4016,VSUNIRead0);
308          SetReadHandler(0x4017,0x4017,VSUNIRead1);
309         }
310         else
311          SetReadHandler(0x4016,0x4017,JPRead);
312         SetWriteHandler(0x4016,0x4016,B4016);
313
314         SetInputStuff(0);
315         SetInputStuff(1);
316         SetInputStuffFC();
317 }
318
319 void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
320 {
321  JPAttrib[port]=attrib;
322  JPType[port]=type;
323  InputDataPtr[port]=ptr;
324  SetInputStuff(port);
325 }
326
327 void FCEUI_DisableFourScore(int s)
328 {
329  FSDisable=s;
330 }
331
332 void FCEUI_SetInputFC(int type, void *ptr, int attrib)
333 {
334  JPAttribFC=attrib;
335  JPTypeFC=type;
336  InputDataPtrFC=ptr;
337  SetInputStuffFC();
338 }
339
340 // quick paste
341 #define FCEUNPCMD_RESET   0x01
342 #define FCEUNPCMD_POWER   0x02
343
344 #define FCEUNPCMD_VSUNICOIN     0x07
345 #define FCEUNPCMD_VSUNIDIP0     0x08
346 #define FCEUNPCMD_FDSINSERT     0x18
347 #define FCEUNPCMD_FDSSELECT     0x1A
348
349
350 void FCEU_DoSimpleCommand(int cmd)
351 {
352  switch(cmd)
353  {
354 //   case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
355 //   case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
356 //   case FCEUNPCMD_FDSEJECT: FCEU_FDSEject();break;
357 //   case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
358 //   case FCEUNPCMD_VSUNIDIP0 ... (FCEUNPCMD_VSUNIDIP0 + 7): FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);break;
359    case FCEUNPCMD_POWER: PowerNES();break;
360    case FCEUNPCMD_RESET: ResetNES();break;
361    default: printf("FCEU_DoSimpleCommand: can't handle cmd %i\n", cmd); break;
362  }
363 }
364
365
366 SFORMAT FCEUCTRL_STATEINFO[]={
367  { joy_readbit, 2, "JYRB"},
368  { joy, 4, "JOYS"},
369  { &LastStrobe, 1, "LSTS"},
370  { 0 }
371 };
372
373