some warnings fixed, nsf fixed, palettes, more code backported
[fceu.git] / drivers / common / cheat.c
... / ...
CommitLineData
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
25static 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. */
39static 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. */
54static 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
65static 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
76static 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*/
92static int listcount;
93static int listids[16];
94static int listsel;
95static int mordoe;
96
97void 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. */
106int 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
139int 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. */
151int 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
177typedef struct MENU {
178 char *text;
179 void *action;
180 int type; // 0 for menu, 1 for function.
181} MENU;
182
183static void SetOC(void)
184{
185 FCEUI_CheatSearchSetCurrentAsOriginal();
186}
187
188static void UnhideEx(void)
189{
190 FCEUI_CheatSearchShowExcluded();
191}
192
193static void ToggleCheat(int num)
194{
195 printf("Cheat %d %sabled.\n",1+num,
196 FCEUI_ToggleCheat(num)?"en":"dis");
197}
198
199static 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
246static 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
288static void AddCheatGG(void)
289{
290 AddCheatGGPAR(0);
291}
292
293static void AddCheatPAR(void)
294{
295 AddCheatGGPAR(1);
296}
297
298static 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
318static void AddCheat(void)
319{
320 AddCheatParam(0,0);
321}
322
323static int lid;
324static 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
340static 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
368static void ResetSearch(void)
369{
370 FCEUI_CheatSearchBegin();
371 puts("Done.");
372}
373
374static 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
381static 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
396static 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
426static 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
449static 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
461static MENU MainMenu[]={
462 {"List Cheats",(void *)ListCheats,1},
463 {"New Cheats...",(void *)NewCheatsMenu,0},
464 {0}
465};
466
467static 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
518void DoConsoleCheatConfig(void)
519{
520 MENU *curmenu=MainMenu;
521
522 DoMenu(curmenu);
523}