098 video fix, 098 sound integrated
[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_InitPowerpadA(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 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 *bg, uint8 *spr, uint32 linets, int final);
59
60 static INPUTC DummyJPort={0,0,0,0,0};
61 static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
62 static INPUTCFC *FCExp=0;
63
64 /* This function is a quick hack to get the NSF player to use emulated gamepad
65    input.
66 */
67 uint8 FCEU_GetJoyJoy(void)
68 {
69  return(joy[0]|joy[1]|joy[2]|joy[3]);
70 }
71
72 static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
73 {
74                 uint8 ret=0;
75
76                 if(joy_readbit[w]>=8)
77                  ret=1;
78                 else
79                 {
80                  ret = ((joy[w]>>(joy_readbit[w]))&1);
81                  joy_readbit[w]++;
82                 }
83                 return ret;
84 }
85
86 static uint8 FP_FASTAPASS(1) ReadGP(int w)
87 {
88                 uint8 ret;
89                 //if(JoyMulti)
90                 //{
91                  //ret = ((joy[w]>>(joy_readbit[w]))&1)|
92                  //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
93                  //if(joy_readbit[w]>8) ret=0;
94                 //}
95                 ret = ((joy[w]>>(joy_readbit[w]))&1);
96                 if(FSDisable)
97                 {
98                  if(joy_readbit[w]>=8) ret|=1;
99                 }
100                 else
101                 {
102                  if(joy_readbit[w]==19-w) ret|=1;
103                 }
104                 joy_readbit[w]++;
105                 return ret;
106 }
107
108 static DECLFR(JPRead)
109 {
110         uint8 ret=0;
111
112         if(JPorts[A&1]->Read)
113          ret|=JPorts[A&1]->Read(A&1);
114
115         if(FCExp)
116          if(FCExp->Read)
117           ret=FCExp->Read(A&1,ret);
118
119         ret|=X.DB&0xC0;
120         dprintf("JPRead %i %02x", A&1, ret);
121         return(ret);
122 }
123
124 static DECLFW(B4016)
125 {
126         if(FCExp)
127          if(FCExp->Write)
128           FCExp->Write(V&7);
129
130         if(JPorts[0]->Write)
131          JPorts[0]->Write(V&1);
132         if(JPorts[1]->Write)
133          JPorts[1]->Write(V&1);
134
135         if((LastStrobe&1) && (!(V&1)))
136         {
137          /* This strobe code is just for convenience.  If it were
138             with the code in input / *.c, it would more accurately represent
139             what's really going on.  But who wants accuracy? ;)
140             Seriously, though, this shouldn't be a problem.
141          */
142          if(JPorts[0]->Strobe)
143           JPorts[0]->Strobe(0);
144          if(JPorts[1]->Strobe)
145           JPorts[1]->Strobe(1);
146          if(FCExp)
147           if(FCExp->Strobe)
148            FCExp->Strobe();
149          }
150          LastStrobe=V&1;
151 }
152
153 static void FP_FASTAPASS(1) StrobeGP(int w)
154 {
155         joy_readbit[w]=0;
156 }
157
158 static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
159 static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
160
161 void DrawInput(uint8 *buf)
162 {
163  int x;
164
165  for(x=0;x<2;x++)
166   if(JPorts[x]->Draw)
167    JPorts[x]->Draw(x,buf,JPAttrib[x]);
168  if(FCExp)
169   if(FCExp->Draw)
170    FCExp->Draw(buf,JPAttribFC);
171 }
172
173 void UpdateInput(void)
174 {
175         int x;
176
177         for(x=0;x<2;x++)
178         {
179          switch(JPType[x])
180          {
181           case SI_GAMEPAD:
182                 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
183                 else joy[1]=*(uint16 *)InputDataPtr[1];
184                 break;
185           default:
186                 if(JPorts[x]->Update)
187                  JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
188                 break;
189          }
190         }
191         if(FCExp)
192          if(FCExp->Update)
193           FCExp->Update(InputDataPtrFC,JPAttribFC);
194
195         if(FCEUGameInfo.type==GIT_VSUNI)
196         {
197          uint16 t=joy[0];
198          joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
199          joy[1]=(joy[1]&0xC)|(t&0xF3);
200          if(coinon) coinon--;
201         }
202         #ifdef NETWORK
203         if(netplay) NetplayUpdate(&joy[0],&joy[1]);
204         #endif
205         if (current < 0) FCEUMOV_AddJoy(joy);
206         else framecount++; // for debug
207         //FlushCommandQueue();
208 }
209
210 static DECLFR(VSUNIRead0)
211 {
212         uint8 ret=0;
213
214         if(JPorts[0]->Read)
215          ret|=(JPorts[0]->Read(0))&1;
216
217         ret|=(vsdip&3)<<3;
218         if(coinon)
219          ret|=0x4;
220         return ret;
221 }
222
223 static DECLFR(VSUNIRead1)
224 {
225         uint8 ret=0;
226
227         if(JPorts[1]->Read)
228          ret|=(JPorts[1]->Read(1))&1;
229         ret|=vsdip&0xFC;
230         return ret;
231 }
232
233 static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final)
234 {
235  int x;
236
237  for(x=0;x<2;x++)
238   if(JPorts[x]->SLHook)
239    JPorts[x]->SLHook(x,bg,spr,linets,final);
240  if(FCExp)
241   if(FCExp->SLHook)
242    FCExp->SLHook(bg,spr,linets,final);
243 }
244
245 static void CheckSLHook(void)
246 {
247         InputScanlineHook=0;
248         if(JPorts[0]->SLHook || JPorts[1]->SLHook)
249          InputScanlineHook=SLHLHook;
250         if(FCExp)
251          if(FCExp->SLHook)
252           InputScanlineHook=SLHLHook;
253 }
254
255 static void FASTAPASS(1) SetInputStuff(int x)
256 {
257          switch(JPType[x])
258          {
259           case SI_GAMEPAD:
260            if(FCEUGameInfo.type==GIT_VSUNI)
261             JPorts[x]=&GPCVS;
262            else
263             JPorts[x]=&GPC;
264           break;
265           case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
266           case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
267           case SI_POWERPADA:JPorts[x]=FCEU_InitPowerpadA(x);break;
268           case SI_NONE:JPorts[x]=&DummyJPort;break;
269          }
270
271         CheckSLHook();
272 }
273
274 static uint8 F4ReadBit[2];
275 static void StrobeFami4(void)
276 {
277  F4ReadBit[0]=F4ReadBit[1]=0;
278 }
279
280 static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
281 {
282  ret&=1;
283
284  ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
285  if(F4ReadBit[w]>=8) ret|=2;
286  else F4ReadBit[w]++;
287
288  return(ret);
289 }
290
291 static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
292 static void SetInputStuffFC(void)
293 {
294         switch(JPTypeFC)
295         {
296          case SIFC_NONE:FCExp=0;break;
297          case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
298          case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
299          case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
300          case SIFC_FKB:FCExp=FCEU_InitFKB();break;
301         }
302         CheckSLHook();
303 }
304
305 // VS Unisystem code called after SetInputMap() hooks B4016.  Need to
306 // rewrite code to make this more sane?
307
308 void InitializeInput(void)
309 {
310         memset(joy_readbit,0,sizeof(joy_readbit));
311         memset(joy,0,sizeof(joy));
312         LastStrobe=0;
313
314         if(FCEUGameInfo.type==GIT_VSUNI)
315         {
316          SetReadHandler(0x4016,0x4016,VSUNIRead0);
317          SetReadHandler(0x4017,0x4017,VSUNIRead1);
318         }
319         else
320          SetReadHandler(0x4016,0x4017,JPRead);
321         SetWriteHandler(0x4016,0x4016,B4016);
322
323         SetInputStuff(0);
324         SetInputStuff(1);
325         SetInputStuffFC();
326 }
327
328 void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
329 {
330  JPAttrib[port]=attrib;
331  JPType[port]=type;
332  InputDataPtr[port]=ptr;
333  SetInputStuff(port);
334 }
335
336 void FCEUI_DisableFourScore(int s)
337 {
338  FSDisable=s;
339 }
340
341 void FCEUI_SetInputFC(int type, void *ptr, int attrib)
342 {
343  JPAttribFC=attrib;
344  JPTypeFC=type;
345  InputDataPtrFC=ptr;
346  SetInputStuffFC();
347 }
348
349 void FCEU_DoSimpleCommand(int cmd)
350 {
351    printf("FCEU_DoSimpleCommand: %i\n", cmd);
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 void FCEU_QSimpleCommand(int cmd)
366 {
367 // if(FCEUnetplay)
368 //  FCEUNET_SendCommand(cmd, 0);
369 // else
370  {
371   // totally wrong:
372 //  if(!FCEUMOV_IsPlaying())
373 //   FCEU_DoSimpleCommand(cmd);
374 //  else
375 //   FCEUMOV_AddCommand(cmd);
376
377   FCEU_DoSimpleCommand(cmd);
378 //  if(FCEUMOV_IsRecording())
379 //   FCEUMOV_AddCommand(cmd);
380  }
381 }
382
383 void FCEUI_FDSSelect(void)
384 {
385  FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
386 }
387
388 int FCEUI_FDSInsert(void)
389 {
390  FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
391  return(1);
392 }
393
394 /*
395 int FCEUI_FDSEject(void)
396 {
397     FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
398     return(1);
399 }
400 */
401 void FCEUI_VSUniToggleDIP(int w)
402 {
403  FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
404 }
405
406 void FCEUI_VSUniCoin(void)
407 {
408  FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
409 }
410
411 void FCEUI_ResetNES(void)
412 {
413         FCEU_QSimpleCommand(FCEUNPCMD_RESET);
414 }
415
416 void FCEUI_PowerNES(void)
417 {
418         FCEU_QSimpleCommand(FCEUNPCMD_POWER);
419 }
420
421
422
423 SFORMAT FCEUCTRL_STATEINFO[]={
424  { joy_readbit, 2, "JYRB"},
425  { joy, 4, "JOYS"},
426  { &LastStrobe, 1, "LSTS"},
427  { 0 }
428 };
429
430