mapper fixes for ncpu, debug is broken atm
[fceu.git] / drivers / common / cheat.c
CommitLineData
c62d2810 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
25static 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. */
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,"%d",&def);
62 return def;
63}
64
65static 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*/
81static int listcount;
82static int listids[16];
83static int listsel;
84static int mordoe;
85
86void 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. */
95int 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
128int 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. */
140int 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
166typedef struct MENU {
167 char *text;
168 void *action;
169 int type; // 0 for menu, 1 for function.
170} MENU;
171
172static void SetOC(void)
173{
174 FCEUI_CheatSearchSetCurrentAsOriginal();
175}
176
177static void UnhideEx(void)
178{
179 FCEUI_CheatSearchShowExcluded();
180}
181
182static 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
193static 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
230static 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
250static void AddCheat(void)
251{
252 AddCheatParam(0,0);
253}
254
255static int lid;
256static 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
267static 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
295static void ResetSearch(void)
296{
297 FCEUI_CheatSearchBegin();
298 puts("Done.");
299}
300
301static 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
308static 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
323static 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
353static 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
376static 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
386static MENU MainMenu[3]={
387 {"List Cheats",ListCheats,1},
388 {"New Cheats...",NewCheatsMenu,0},
389 {0}
390};
391
392static 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
443void DoConsoleCheatConfig(void)
444{
445 MENU *curmenu=MainMenu;
446
447 DoMenu(curmenu);
448}