mapper fixes for ncpu, debug is broken atm
[fceu.git] / drivers / common / cheat.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "../../driver.h"
24
25 static void GetString(char *s)
26 {
27  int x;
28  fgets(s,256,stdin);
29
30  for(x=0;x<256;x++)
31   if(s[x]=='\n')
32   {
33    s[x]=0;
34    break;
35   }
36 }
37
38 /* Get unsigned 16-bit integer from stdin in hex. */
39 static uint32 GetH16(unsigned int def)
40 {
41  char buf[32];
42
43  fgets(buf,32,stdin);
44  if(buf[0]=='\n')
45   return(def);
46  if(buf[0]=='$')
47   sscanf(buf+1,"%04x",&def);
48  else
49   sscanf(buf,"%04x",&def);
50  return def;
51 }
52
53 /* Get unsigned 8-bit integer from stdin in decimal. */
54 static uint8 Get8(unsigned int def)
55 {
56  char buf[32];
57
58  fgets(buf,32,stdin);
59  if(buf[0]=='\n')
60   return(def);
61  sscanf(buf,"%d",&def);
62  return def;
63 }
64
65 static int GetYN(int def)
66 {
67  char buf[32];
68  printf("(Y/N)[%s]: ",def?"Y":"N");
69  fgets(buf,32,stdin);
70  if(buf[0]=='y' || buf[0]=='Y')
71   return(1);
72  if(buf[0]=='n' || buf[0]=='N')
73   return(0);
74  return(def);
75 }
76
77 /*
78 **      Begin list code.
79 **
80 */
81 static int listcount;
82 static int listids[16];
83 static int listsel;
84 static int mordoe;
85
86 void BeginListShow(void)
87 {
88  listcount=0;
89  listsel=-1;
90  mordoe=0;
91 }
92
93 /* Hmm =0 for in list choices, hmm=1 for end of list choices. */
94 /* Return equals 0 to continue, -1 to stop, otherwise a number. */
95 int ListChoice(int hmm)
96 {
97   char buf[32];
98
99   if(!hmm)
100   {
101    int num=0;
102
103    tryagain:
104    printf(" <'Enter' to continue, (S)top, or enter a number.> ");
105    fgets(buf,32,stdin);
106    if(buf[0]=='s' || buf[0]=='S') return(-1);
107    if(buf[0]=='\n') return(0);
108    if(!sscanf(buf,"%d",&num))
109     return(0);  
110    if(num<1) goto tryagain;
111    return(num);
112   }
113   else
114   {
115    int num=0;
116
117    tryagain2:
118    printf(" <'Enter' to make no selection or enter a number.> ");
119    fgets(buf,32,stdin);
120    if(buf[0]=='\n') return(0);
121    if(!sscanf(buf,"%d",&num))
122     return(0);
123    if(num<1) goto tryagain2;
124    return(num);
125   }
126 }
127
128 int EndListShow(void)
129 {
130   if(mordoe)
131   {
132    int r=ListChoice(1);
133    if(r>0 && r<=listcount)
134     listsel=listids[r-1];
135   }
136   return(listsel);
137 }
138
139 /* Returns 0 to stop listing, 1 to continue. */
140 int AddToList(char *text, uint32 id)
141 {
142  if(listcount==16)
143  {
144   int t=ListChoice(0);
145   mordoe=0;
146   if(t==-1) return(0);  // Stop listing.
147   else if(t>0 && t<17)
148   {
149    listsel=listids[t-1];
150    return(0);
151   }
152   listcount=0;
153  }
154  mordoe=1;
155  listids[listcount]=id;
156  printf("%2d) %s\n",listcount+1,text);
157  listcount++; 
158  return(1);
159 }
160
161 /*
162 **      
163 **      End list code.
164 **/
165
166 typedef struct MENU {
167         char *text;
168         void *action;
169         int type;       // 0 for menu, 1 for function.
170 } MENU;
171
172 static void SetOC(void)
173 {
174  FCEUI_CheatSearchSetCurrentAsOriginal();
175 }
176
177 static void UnhideEx(void)
178 {
179  FCEUI_CheatSearchShowExcluded();
180 }
181
182 static void ToggleCheat(int num)
183 {
184  uint32 A;
185  int s;
186
187  FCEUI_GetCheat(num,0,&A,0,&s);
188  s^=1;
189  FCEUI_SetCheat(num,0,-1,-1,s);
190  printf("Cheat for address $%04x %sabled.\n",(unsigned int)A,s?"en":"dis");
191 }
192
193 static void ModifyCheat(int num)
194 {
195  char *name;
196  char buf[256];
197  uint32 A;
198  uint8 V;
199  int s;
200  int t;
201
202  FCEUI_GetCheat(num, &name, &A, &V, &s);
203
204  printf("Name [%s]: ",name);
205  GetString(buf);
206
207  /* This obviously doesn't allow for cheats with no names.  Bah.  Who wants
208     nameless cheats anyway... 
209  */
210
211  if(buf[0])
212   name=buf;     // Change name when FCEUI_SetCheat() is called.
213  else
214   name=0;       // Don't change name when FCEUI_SetCheat() is called.
215
216  printf("Address [$%04x]: ",(unsigned int)A);
217  A=GetH16(A);
218
219  printf("Value [%03d]: ",(unsigned int)V);
220  V=Get8(V);
221
222  printf("Enable [%s]: ",s?"Y":"N");
223  t=getchar();
224  if(t=='Y' || t=='y') s=1;
225  else if(t=='N' || t=='n') s=0;
226
227  FCEUI_SetCheat(num,name,A,V,s);
228 }
229
230 static void AddCheatParam(uint32 A, uint8 V)
231 {
232  char name[256];
233
234  printf("Name: ");
235  GetString(name);
236  printf("Address [$%04x]: ",(unsigned int)A);
237  A=GetH16(A);
238  printf("Value [%03d]: ",(unsigned int)V);
239  V=Get8(V);
240  printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V);
241  if(GetYN(0))
242  {
243   if(FCEUI_AddCheat(name,A,V))
244    puts("Cheat added.");
245   else
246    puts("Error adding cheat.");
247  }
248 }
249
250 static void AddCheat(void)
251 {
252  AddCheatParam(0,0);
253 }
254
255 static int lid;
256 static int clistcallb(char *name, uint32 a, uint8 v, int s)
257 {
258  char tmp[512];
259  int ret;
260
261  sprintf(tmp,"%s $%04x:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
262  ret=AddToList(tmp,lid);
263  lid++;
264  return(ret);
265 }
266
267 static void ListCheats(void)
268 {
269  int which;
270  lid=0;
271
272  BeginListShow();
273  FCEUI_ListCheats(clistcallb);
274  which=EndListShow();
275  if(which>=0)
276  {
277   char tmp[32];
278   printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
279   fgets(tmp,32,stdin);
280   switch(tolower(tmp[0]))
281   {
282    case 't':ToggleCheat(which);
283             break;
284    case 'd':if(!FCEUI_DelCheat(which))
285              puts("Error deleting cheat!");
286             else 
287              puts("Cheat has been deleted.");
288             break;
289    case 'm':ModifyCheat(which);
290             break;
291   }
292  }
293 }
294
295 static void ResetSearch(void)
296 {
297  FCEUI_CheatSearchBegin();
298  puts("Done.");
299 }
300
301 static int srescallb(uint32 a, uint8 last, uint8 current)
302 {
303  char tmp[13];
304  sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current);
305  return(AddToList(tmp,a));
306 }
307
308 static void ShowRes(void)
309 {
310  int n=FCEUI_CheatSearchGetCount();
311  printf(" %d results:\n",n);
312  if(n)
313  {
314   int which;
315   BeginListShow();
316   FCEUI_CheatSearchGet(srescallb);
317   which=EndListShow();
318   if(which>=0)
319    AddCheatParam(which,0);
320  }
321 }
322
323 static int ShowShortList(char *moe[], int n, int def)
324 {
325  int x,c;
326  unsigned int baa;
327  char tmp[16];
328
329  red:
330  for(x=0;x<n;x++)
331   printf("%d) %s\n",x+1,moe[x]);
332  puts("D) Display List");
333  clo:
334
335  printf("\nSelection [%d]> ",def+1);
336  fgets(tmp,256,stdin);
337  if(tmp[0]=='\n')
338   return def;
339  c=tolower(tmp[0]);
340  baa=c-'1';
341
342  if(baa<n)
343   return baa;
344  else if(c=='d')
345   goto red;
346  else
347  {
348   puts("Invalid selection.");
349   goto clo;
350  }
351 }
352
353 static void DoSearch(void)
354 {
355  static int v1=0,v2=0;
356  static int method=0;
357  char *m[4]={"O==V1 && C==V2","O==V1 && |O-C|==V2","|O-C|==V2","O!=C"};
358  printf("\nSearch Filter:\n");
359
360  method=ShowShortList(m,4,method);
361  if(method<=1)
362  {
363   printf("V1 [%03d]: ",v1);
364   v1=Get8(v1);
365  }
366  if(method<=2)
367  {
368   printf("V2 [%03d]: ",v2);
369   v2=Get8(v2);
370  }
371  FCEUI_CheatSearchEnd(method,v1,v2);
372  puts("Search completed.\n");
373 }
374
375
376 static MENU NewCheatsMenu[7]={
377  {"Add Cheat",AddCheat,1},
378  {"Reset Search",ResetSearch,1},
379  {"Do Search",DoSearch,1},
380  {"Set Original to Current",SetOC,1},
381  {"Unhide Excluded",UnhideEx,1},
382  {"Show Results",ShowRes,1},
383  {0}
384 };
385
386 static MENU MainMenu[3]={
387  {"List Cheats",ListCheats,1},
388  {"New Cheats...",NewCheatsMenu,0},
389  {0}
390 };
391
392 static void DoMenu(MENU *men)
393 {
394  int x=0;
395
396  redisplay:
397  x=0;
398  puts("");
399  while(men[x].text)
400  {
401   printf("%d) %s\n",x+1,men[x].text);
402   x++;
403  }
404  puts("D) Display Menu\nX) Return to Previous\n");
405  {
406   char buf[32];
407   int c;
408
409   recommand:
410   printf("Command> ");
411   fgets(buf,32,stdin);
412   c=tolower(buf[0]);
413   if(c=='\n')
414    goto recommand;
415   else if(c=='d')
416    goto redisplay;
417   else if(c=='x')
418   {
419    return;
420   }
421   else if(sscanf(buf,"%d",&c))
422   {
423    if(c>x) goto invalid;
424    if(men[c-1].type)
425    {
426     void (*func)(void)=men[c-1].action;
427     func();
428    }
429    else
430     DoMenu(men[c-1].action);    /* Mmm...recursivey goodness. */
431    goto redisplay;
432   }
433   else
434   {
435    invalid:
436    puts("Invalid command.\n");
437    goto recommand;
438   }
439
440  }
441 }
442
443 void DoConsoleCheatConfig(void)
444 {
445  MENU *curmenu=MainMenu;
446
447  DoMenu(curmenu);
448 }