some warnings fixed, nsf fixed, palettes, more code backported
[fceu.git] / drivers / common / cheat.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel
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, int max)
26 {
27  int x;
28  fgets(s,max,stdin);
29
30  for(x=0;x<max;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,"%u",&def);
62  return def;
63 }
64
65 static int GetI(int def)
66 {
67  char buf[32];
68
69  fgets(buf,32,stdin);
70  if(buf[0]=='\n')
71   return(def);
72  sscanf(buf,"%d",&def);
73  return def;
74 }
75
76 static int GetYN(int def)
77 {
78  char buf[32];
79  printf("(Y/N)[%s]: ",def?"Y":"N");
80  fgets(buf,32,stdin);
81  if(buf[0]=='y' || buf[0]=='Y')
82   return(1);
83  if(buf[0]=='n' || buf[0]=='N')
84   return(0);
85  return(def);
86 }
87
88 /*
89 **      Begin list code.
90 **
91 */
92 static int listcount;
93 static int listids[16];
94 static int listsel;
95 static int mordoe;
96
97 void BeginListShow(void)
98 {
99  listcount=0;
100  listsel=-1;
101  mordoe=0;
102 }
103
104 /* Hmm =0 for in list choices, hmm=1 for end of list choices. */
105 /* Return equals 0 to continue, -1 to stop, otherwise a number. */
106 int ListChoice(int hmm)
107 {
108   char buf[32];
109
110   if(!hmm)
111   {
112    int num=0;
113
114    tryagain:
115    printf(" <'Enter' to continue, (S)top, or enter a number.> ");
116    fgets(buf,32,stdin);
117    if(buf[0]=='s' || buf[0]=='S') return(-1);
118    if(buf[0]=='\n') return(0);
119    if(!sscanf(buf,"%d",&num))
120     return(0);
121    if(num<1) goto tryagain;
122    return(num);
123   }
124   else
125   {
126    int num=0;
127
128    tryagain2:
129    printf(" <'Enter' to make no selection or enter a number.> ");
130    fgets(buf,32,stdin);
131    if(buf[0]=='\n') return(0);
132    if(!sscanf(buf,"%d",&num))
133     return(0);
134    if(num<1) goto tryagain2;
135    return(num);
136   }
137 }
138
139 int EndListShow(void)
140 {
141   if(mordoe)
142   {
143    int r=ListChoice(1);
144    if(r>0 && r<=listcount)
145     listsel=listids[r-1];
146   }
147   return(listsel);
148 }
149
150 /* Returns 0 to stop listing, 1 to continue. */
151 int AddToList(char *text, uint32 id)
152 {
153  if(listcount==16)
154  {
155   int t=ListChoice(0);
156   mordoe=0;
157   if(t==-1) return(0);  // Stop listing.
158   else if(t>0 && t<17)
159   {
160    listsel=listids[t-1];
161    return(0);
162   }
163   listcount=0;
164  }
165  mordoe=1;
166  listids[listcount]=id;
167  printf("%2d) %s\n",listcount+1,text);
168  listcount++;
169  return(1);
170 }
171
172 /*
173 **
174 **      End list code.
175 **/
176
177 typedef struct MENU {
178         char *text;
179         void *action;
180         int type;       // 0 for menu, 1 for function.
181 } MENU;
182
183 static void SetOC(void)
184 {
185  FCEUI_CheatSearchSetCurrentAsOriginal();
186 }
187
188 static void UnhideEx(void)
189 {
190  FCEUI_CheatSearchShowExcluded();
191 }
192
193 static void ToggleCheat(int num)
194 {
195  printf("Cheat %d %sabled.\n",1+num,
196   FCEUI_ToggleCheat(num)?"en":"dis");
197 }
198
199 static void ModifyCheat(int num)
200 {
201  char *name;
202  char buf[256];
203  uint32 A;
204  uint8 V;
205  int compare;
206  int type;
207
208  int s;
209  int t;
210
211  FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type);
212
213  printf("Name [%s]: ",name);
214  GetString(buf,256);
215
216  /* This obviously doesn't allow for cheats with no names.  Bah.  Who wants
217     nameless cheats anyway...
218  */
219
220  if(buf[0])
221   name=buf;     // Change name when FCEUI_SetCheat() is called.
222  else
223   name=0;       // Don't change name when FCEUI_SetCheat() is called.
224
225  printf("Address [$%04x]: ",(unsigned int)A);
226  A=GetH16(A);
227
228  printf("Value [%03d]: ",(unsigned int)V);
229  V=Get8(V);
230
231  printf("Compare [%3d]: ",compare);
232  compare=GetI(compare);
233
234  printf("Type(0=Old Style, 1=Read Substitute) [%1d]: ",type);
235  type=GetI(type)?1:0;
236
237  printf("Enable [%s]: ",s?"Y":"N");
238  t=getchar();
239  if(t=='Y' || t=='y') s=1;
240  else if(t=='N' || t=='n') s=0;
241
242  FCEUI_SetCheat(num,name,A,V,compare,s,type);
243 }
244
245
246 static void AddCheatGGPAR(int which)
247 {
248  uint16 A;
249  uint8 V;
250  int C;
251  int type;
252  char name[256],code[256];
253
254  printf("Name: ");
255  GetString(name,256);
256
257  printf("Code: ");
258  GetString(code,256);
259
260  printf("Add cheat \"%s\" for code \"%s\"?",name,code);
261  if(GetYN(0))
262  {
263   if(which)
264   {
265    if(!FCEUI_DecodePAR(code,&A,&V,&C,&type))
266    {
267     puts("Invalid Game Genie code.");
268     return;
269    }
270   }
271   else
272   {
273    if(!FCEUI_DecodeGG(code,&A,&V,&C))
274    {
275     puts("Invalid Game Genie code.");
276     return;
277    }
278    type=1;
279   }
280
281   if(FCEUI_AddCheat(name,A,V,C,type))
282    puts("Cheat added.");
283   else
284    puts("Error adding cheat.");
285  }
286 }
287
288 static void AddCheatGG(void)
289 {
290  AddCheatGGPAR(0);
291 }
292
293 static void AddCheatPAR(void)
294 {
295  AddCheatGGPAR(1);
296 }
297
298 static void AddCheatParam(uint32 A, uint8 V)
299 {
300  char name[256];
301
302  printf("Name: ");
303  GetString(name,256);
304  printf("Address [$%04x]: ",(unsigned int)A);
305  A=GetH16(A);
306  printf("Value [%03d]: ",(unsigned int)V);
307  V=Get8(V);
308  printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V);
309  if(GetYN(0))
310  {
311   if(FCEUI_AddCheat(name,A,V,-1,0))
312    puts("Cheat added.");
313   else
314    puts("Error adding cheat.");
315  }
316 }
317
318 static void AddCheat(void)
319 {
320  AddCheatParam(0,0);
321 }
322
323 static int lid;
324 static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
325 {
326  char tmp[512];
327  int ret;
328
329  if(compare>=0)
330   sprintf(tmp,"%s   $%04x:%03d:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name);
331  else
332   sprintf(tmp,"%s   $%04x:%03d     - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
333  if(type==1)
334   tmp[2]='S';
335  ret=AddToList(tmp,lid);
336  lid++;
337  return(ret);
338 }
339
340 static void ListCheats(void)
341 {
342  int which;
343  lid=0;
344
345  BeginListShow();
346  FCEUI_ListCheats(clistcallb,0);
347  which=EndListShow();
348  if(which>=0)
349  {
350   char tmp[32];
351   printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
352   fgets(tmp,32,stdin);
353   switch(tolower(tmp[0]))
354   {
355    case 't':ToggleCheat(which);
356             break;
357    case 'd':if(!FCEUI_DelCheat(which))
358              puts("Error deleting cheat!");
359             else
360              puts("Cheat has been deleted.");
361             break;
362    case 'm':ModifyCheat(which);
363             break;
364   }
365  }
366 }
367
368 static void ResetSearch(void)
369 {
370  FCEUI_CheatSearchBegin();
371  puts("Done.");
372 }
373
374 static int srescallb(uint32 a, uint8 last, uint8 current, void *data)
375 {
376  char tmp[13];
377  sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current);
378  return(AddToList(tmp,a));
379 }
380
381 static void ShowRes(void)
382 {
383  int n=FCEUI_CheatSearchGetCount();
384  printf(" %d results:\n",n);
385  if(n)
386  {
387   int which;
388   BeginListShow();
389   FCEUI_CheatSearchGet(srescallb,0);
390   which=EndListShow();
391   if(which>=0)
392    AddCheatParam(which,0);
393  }
394 }
395
396 static int ShowShortList(char *moe[], int n, int def)
397 {
398  int x,c;
399  unsigned int baa;
400  char tmp[16];
401
402  red:
403  for(x=0;x<n;x++)
404   printf("%d) %s\n",x+1,moe[x]);
405  puts("D) Display List");
406  clo:
407
408  printf("\nSelection [%d]> ",def+1);
409  fgets(tmp,256,stdin);
410  if(tmp[0]=='\n')
411   return def;
412  c=tolower(tmp[0]);
413  baa=c-'1';
414
415  if(baa<n)
416   return baa;
417  else if(c=='d')
418   goto red;
419  else
420  {
421   puts("Invalid selection.");
422   goto clo;
423  }
424 }
425
426 static void DoSearch(void)
427 {
428  static int v1=0,v2=0;
429  static int method=0;
430  char *m[6]={"O==V1 && C==V2","O==V1 && |O-C|==V2","|O-C|==V2","O!=C","Value decreased","Value increased"};
431  printf("\nSearch Filter:\n");
432
433  method=ShowShortList(m,6,method);
434  if(method<=1)
435  {
436   printf("V1 [%03d]: ",v1);
437   v1=Get8(v1);
438  }
439  if(method<=2)
440  {
441   printf("V2 [%03d]: ",v2);
442   v2=Get8(v2);
443  }
444  FCEUI_CheatSearchEnd(method,v1,v2);
445  puts("Search completed.\n");
446 }
447
448
449 static MENU NewCheatsMenu[]={
450  {"Add Cheat",(void *)AddCheat,1},
451  {"Reset Search",(void *)ResetSearch,1},
452  {"Do Search",(void *)DoSearch,1},
453  {"Set Original to Current",(void *)SetOC,1},
454  {"Unhide Excluded",(void *)UnhideEx,1},
455  {"Show Results",(void *)ShowRes,1},
456  {"Add Game Genie Cheat",(void *)AddCheatGG,1},
457  {"Add PAR Cheat",(void *)AddCheatPAR,1},
458  {0}
459 };
460
461 static MENU MainMenu[]={
462  {"List Cheats",(void *)ListCheats,1},
463  {"New Cheats...",(void *)NewCheatsMenu,0},
464  {0}
465 };
466
467 static void DoMenu(MENU *men)
468 {
469  int x=0;
470
471  redisplay:
472  x=0;
473  puts("");
474  while(men[x].text)
475  {
476   printf("%d) %s\n",x+1,men[x].text);
477   x++;
478  }
479  puts("D) Display Menu\nX) Return to Previous\n");
480  {
481   char buf[32];
482   int c;
483
484   recommand:
485   printf("Command> ");
486   fgets(buf,32,stdin);
487   c=tolower(buf[0]);
488   if(c=='\n')
489    goto recommand;
490   else if(c=='d')
491    goto redisplay;
492   else if(c=='x')
493   {
494    return;
495   }
496   else if(sscanf(buf,"%d",&c))
497   {
498    if(c>x) goto invalid;
499    if(men[c-1].type)
500    {
501     void (*func)(void)=(void(*)())men[c-1].action;
502     func();
503    }
504    else
505     DoMenu((MENU*)men[c-1].action);     /* Mmm...recursivey goodness. */
506    goto redisplay;
507   }
508   else
509   {
510    invalid:
511    puts("Invalid command.\n");
512    goto recommand;
513   }
514
515  }
516 }
517
518 void DoConsoleCheatConfig(void)
519 {
520  MENU *curmenu=MainMenu;
521
522  DoMenu(curmenu);
523 }