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