some refactoring, no change in performance seen
[fceu.git] / 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 <stdlib.h>
22#include <string.h>
23#include <stdio.h>
24
25#include "types.h"
26#include "x6502.h"
27#include "cheat.h"
28#include "fce.h"
29#include "svga.h"
30#include "general.h"
31#include "cart.h"
32#include "memory.h"
33
34static uint8 *CheatRPtrs[64];
35
36void FCEU_CheatResetRAM(void)
37{
38 int x;
39
40 for(x=0;x<64;x++)
41 CheatRPtrs[x]=0;
42}
43
44void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
45{
46 uint32 AB=A>>10;
47 int x;
48
49 for(x=s-1;x>=0;x--)
50 CheatRPtrs[AB+x]=p-A;
51}
52
53
54struct CHEATF {
55 struct CHEATF *next;
56 char *name;
57 uint16 addr;
58 uint8 val;
59 int status;
60};
61
62struct CHEATF *cheats=0,*cheatsl=0;
63
64
65#define CHEATC_NONE 0x8000
66#define CHEATC_EXCLUDED 0x4000
67#define CHEATC_NOSHOW 0xC000
68
69static uint16 *CheatComp=0;
70static int savecheats;
71
72static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status);
73
74static void CheatMemErr(void)
75{
76 FCEUD_PrintError("Error allocating memory for cheat data.");
77}
78
79/* This function doesn't allocate any memory for "name" */
80static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status)
81{
82 struct CHEATF *temp;
83 if(!(temp=malloc(sizeof(struct CHEATF))))
84 {
85 CheatMemErr();
86 return(0);
87 }
88 temp->name=name;
89 temp->addr=addr;
90 temp->val=val;
91 temp->status=status;
92
93 temp->next=0;
94
95 if(cheats)
96 {
97 cheatsl->next=temp;
98 cheatsl=temp;
99 }
100 else
101 cheats=cheatsl=temp;
102
103 return(1);
104}
105
106void LoadGameCheats(void)
107{
108 FILE *fp;
109 char *name=0;
110 unsigned int addr;
111 unsigned int val;
112 unsigned int status;
113 int x;
114
115 char linebuf[256+4+2+2+1+1]; /* 256 for name, 4 for address, 2 for value, 2 for semicolons, 1 for status, 1 for null */
116 char namebuf[257];
117 int tc=0;
118
119 savecheats=0;
120 if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"rb")))
121 return;
122
123 while(fgets(linebuf,256+4+2+2+1+1,fp)>0)
124 {
125 addr=val=status=0;
126 namebuf[0]=0; // If the cheat doesn't have a name...
127 if(linebuf[0]==':')
128 {
129 strncpy(namebuf,&linebuf[1+4+2+2],257);
130 if(sscanf(&linebuf[1],"%04x%*[:]%02x",&addr,&val)!=2)
131 continue;
132 status=0;
133 }
134 else
135 {
136 strncpy(namebuf,&linebuf[4+2+2],257);
137 if(sscanf(linebuf,"%04x%*[:]%02x",&addr,&val)!=2) continue;
138 status=1;
139 }
140 for(x=0;x<257;x++)
141 {
142 if(namebuf[x]==10 || namebuf[x]==13)
143 {
144 namebuf[x]=0;
145 break;
146 }
147 }
148 namebuf[256]=0;
149 if(!(name=malloc(strlen(namebuf)+1)))
150 CheatMemErr();
151 else
152 {
153 strcpy(name,namebuf);
154 AddCheatEntry(name,addr,val,status);
155 tc++;
156 }
157 }
158 fclose(fp);
159}
160
161
162void FlushGameCheats(void)
163{
164 if(CheatComp)
165 {
166 free(CheatComp);
167 CheatComp=0;
168 }
169
170 if(!savecheats)
171 {
172 if(cheats)
173 {
174 struct CHEATF *next=cheats;
175 for(;;)
176 {
177 next=next->next;
178 free(cheats->name);
179 free(cheats);
180 if(!next) break;
181 }
182 cheats=cheatsl=0;
183 }
184 }
185 else
186 {
187 if(cheats)
188 {
189 struct CHEATF *next=cheats;
190 FILE *fp;
191 if((fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"wb")))
192 {
193 for(;;)
194 {
195 struct CHEATF *t;
196 if(next->status)
197 fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
198 else
199 fprintf(fp,":%04x:%02x:%s\n",next->addr,next->val,next->name);
200 free(next->name);
201 t=next;
202 next=next->next;
203 free(t);
204 if(!next) break;
205 }
206 fclose(fp);
207 }
208 else
209 FCEUD_PrintError("Error saving cheats.");
210 cheats=cheatsl=0;
211 }
212 else
213 remove(FCEU_MakeFName(FCEUMKF_CHEAT,0,0));
214 }
215}
216
217
218int FCEUI_AddCheat(char *name, uint32 addr, uint8 val)
219{
220 char *t;
221
222 if(!(t=malloc(strlen(name)+1)))
223 {
224 CheatMemErr();
225 return(0);
226 }
227 strcpy(t,name);
228 if(!AddCheatEntry(t,addr,val,1))
229 {
230 free(t);
231 return(0);
232 }
233 savecheats=1;
234 return(1);
235}
236
237int FCEUI_DelCheat(uint32 which)
238{
239 struct CHEATF *prev;
240 struct CHEATF *cur;
241 uint32 x=0;
242
243 for(prev=0,cur=cheats;;)
244 {
245 if(x==which) // Remove this cheat.
246 {
247 if(prev) // Update pointer to this cheat.
248 {
249 if(cur->next) // More cheats.
250 prev->next=cur->next;
251 else // No more.
252 {
253 prev->next=0;
254 cheatsl=prev; // Set the previous cheat as the last cheat.
255 }
256 }
257 else // This is the first cheat.
258 {
259 if(cur->next) // More cheats
260 cheats=cur->next;
261 else
262 cheats=cheatsl=0; // No (more) cheats.
263 }
264 free(cur->name); // Now that all references to this cheat are removed,
265 free(cur); // free the memory.
266 break;
267 } // *END REMOVE THIS CHEAT*
268
269
270 if(!cur->next) // No more cheats to go through(this shouldn't ever happen...)
271 return(0);
272 prev=cur;
273 cur=prev->next;
274 x++;
275 }
276
277 savecheats=1;
278 return(1);
279}
280
281void ApplyPeriodicCheats(void)
282{
283 struct CHEATF *cur=cheats;
284 if(!cur) return;
285
286 for(;;)
287 {
288 if(cur->status)
289 if(CheatRPtrs[cur->addr>>10])
290 CheatRPtrs[cur->addr>>10][cur->addr]=cur->val;
291 if(cur->next)
292 cur=cur->next;
293 else
294 break;
295 }
296}
297
298
299void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s))
300{
301 struct CHEATF *next=cheats;
302
303 while(next)
304 {
305 if(!callb(next->name,next->addr,next->val,next->status)) break;
306 next=next->next;
307 }
308}
309
310int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s)
311{
312 struct CHEATF *next=cheats;
313 uint32 x=0;
314
315 while(next)
316 {
317 if(x==which)
318 {
319 if(name)
320 *name=next->name;
321 if(a)
322 *a=next->addr;
323 if(v)
324 *v=next->val;
325 if(s)
326 *s=next->status;
327
328 return(1);
329 }
330 next=next->next;
331 x++;
332 }
333 return(0);
334}
335
336/* name can be NULL if the name isn't going to be changed. */
337/* same goes for a, v, and s(except the values of each one must be <0) */
338
339int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s)
340{
341 struct CHEATF *next=cheats;
342 uint32 x=0;
343
344 while(next)
345 {
346 if(x==which)
347 {
348 if(name)
349 {
350 char *t;
351
352 if((t=realloc(next->name,strlen(name+1))))
353 {
354 next->name=t;
355 strcpy(next->name,name);
356 }
357 else
358 return(0);
359 }
360 if(a>=0)
361 next->addr=a;
362 if(v>=0)
363 next->val=v;
364 if(s>=0)
365 next->status=s;
366 savecheats=1;
367 return(1);
368 }
369 next=next->next;
370 x++;
371 }
372 return(0);
373}
374
375
376static int InitCheatComp(void)
377{
378 uint32 x;
379
380 CheatComp=malloc(65536*sizeof(uint16));
381 if(!CheatComp)
382 {
383 CheatMemErr();
384 return(0);
385 }
386 for(x=0;x<65536;x++)
387 CheatComp[x]=CHEATC_NONE;
388
389 return(1);
390}
391
392void FCEUI_CheatSearchSetCurrentAsOriginal(void)
393{
394 uint32 x;
395 for(x=0x000;x<0x10000;x++)
396 if(!(CheatComp[x]&CHEATC_NOSHOW))
397 {
398 if(CheatRPtrs[x>>10])
399 CheatComp[x]=CheatRPtrs[x>>10][x];
400 else
401 CheatComp[x]|=CHEATC_NONE;
402 }
403}
404
405void FCEUI_CheatSearchShowExcluded(void)
406{
407 uint32 x;
408
409 for(x=0x000;x<0x10000;x++)
410 CheatComp[x]&=~CHEATC_EXCLUDED;
411}
412
413
414int32 FCEUI_CheatSearchGetCount(void)
415{
416 uint32 x,c=0;
417
418 if(CheatComp)
419 {
420 for(x=0x0000;x<0x10000;x++)
421 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
422 c++;
423 }
424
425 return c;
426}
427/* This function will give the initial value of the search and the current value at a location. */
428
429void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current))
430{
431 uint32 x;
432
433 if(!CheatComp)
434 {
435 if(!InitCheatComp())
436 CheatMemErr();
437 return;
438 }
439
440 for(x=0;x<0x10000;x++)
441 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
442 if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
443 break;
444}
445
446void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
447{
448 uint32 x;
449 uint32 in=0;
450
451 if(!CheatComp)
452 {
453 if(!InitCheatComp())
454 CheatMemErr();
455 return;
456 }
457
458 for(x=0;x<0x10000;x++)
459 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
460 {
461 if(in>=first)
462 if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
463 break;
464 in++;
465 if(in>last) return;
466 }
467}
468
469void FCEUI_CheatSearchBegin(void)
470{
471 uint32 x;
472
473 if(!CheatComp)
474 {
475 if(!InitCheatComp())
476 {
477 CheatMemErr();
478 return;
479 }
480 }
481 for(x=0;x<0x10000;x++)
482 {
483 if(CheatRPtrs[x>>10])
484 CheatComp[x]=CheatRPtrs[x>>10][x];
485 else
486 CheatComp[x]=CHEATC_NONE;
487 }
488}
489
490
491static int INLINE CAbs(int x)
492{
493 if(x<0)
494 return(0-x);
495 return x;
496}
497
498void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
499{
500 uint32 x;
501
502 if(!CheatComp)
503 {
504 if(!InitCheatComp())
505 {
506 CheatMemErr();
507 return;
508 }
509 }
510
511
512 if(!type) // Change to a specific value.
513 {
514 for(x=0;x<0x10000;x++)
515 if(!(CheatComp[x]&CHEATC_NOSHOW))
516 {
517 if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
518 {
519
520 }
521 else
522 CheatComp[x]|=CHEATC_EXCLUDED;
523 }
524 }
525 else if(type==1) // Search for relative change(between values).
526 {
527 for(x=0;x<0x10000;x++)
528 if(!(CheatComp[x]&CHEATC_NOSHOW))
529 {
530 if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
531 {
532
533 }
534 else
535 CheatComp[x]|=CHEATC_EXCLUDED;
536 }
537 }
538 else if(type==2) // Purely relative change.
539 {
540 for(x=0x000;x<0x10000;x++)
541 if(!(CheatComp[x]&CHEATC_NOSHOW))
542 {
543 if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
544 {
545
546 }
547 else
548 CheatComp[x]|=CHEATC_EXCLUDED;
549 }
550 }
551 else if(type==3) // Any change.
552 {
553 for(x=0x000;x<0x10000;x++)
554 if(!(CheatComp[x]&CHEATC_NOSHOW))
555 {
556 if(CheatComp[x]!=CheatRPtrs[x>>10][x])
557 {
558
559 }
560 else
561 CheatComp[x]|=CHEATC_EXCLUDED;
562 }
563
564 }
565}