wannabe optimizations
[fceu.git] / 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 <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
34 static uint8 *CheatRPtrs[64];
35
36 void FCEU_CheatResetRAM(void)
37 {
38  int x;
39
40  for(x=0;x<64;x++) 
41   CheatRPtrs[x]=0;
42 }
43
44 void 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
54 struct CHEATF {
55            struct CHEATF *next;
56            char *name;
57            uint16 addr;
58            uint8 val;
59            int status;
60 };
61
62 struct CHEATF *cheats=0,*cheatsl=0;
63
64
65 #define CHEATC_NONE     0x8000
66 #define CHEATC_EXCLUDED 0x4000
67 #define CHEATC_NOSHOW   0xC000
68
69 static uint16 *CheatComp=0;
70 static int savecheats;
71
72 static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status);
73
74 static 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" */
80 static 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
106 void 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
162 void 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
218 int 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
237 int 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
281 void 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
299 void 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
310 int 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
339 int 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
376 static 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
392 void 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
405 void FCEUI_CheatSearchShowExcluded(void)
406 {
407  uint32 x;
408
409  for(x=0x000;x<0x10000;x++)
410   CheatComp[x]&=~CHEATC_EXCLUDED;
411 }
412
413
414 int32 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
429 void 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
446 void 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
469 void 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
491 static int INLINE CAbs(int x)
492 {
493  if(x<0)
494   return(0-x);
495  return x;
496 }
497
498 void 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 }