1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
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.
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.
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
37 static uint8 *CheatRPtrs[64];
39 void FCEU_CheatResetRAM(void)
47 void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
62 int compare; /* -1 for no compare. */
63 int type; /* 0 for replace, 1 for substitute(GG). */
75 static CHEATF_SUBFAST SubCheats[256];
76 static int numsubcheats=0;
77 struct CHEATF *cheats=0,*cheatsl=0;
80 #define CHEATC_NONE 0x8000
81 #define CHEATC_EXCLUDED 0x4000
82 #define CHEATC_NOSHOW 0xC000
84 static uint16 *CheatComp=0;
85 static int savecheats;
87 static DECLFR(SubCheatsRead)
89 CHEATF_SUBFAST *s=SubCheats;
98 uint8 pv=s->PrevRead(A);
108 return(0); /* We should never get here. */
111 void RebuildSubCheats(void)
114 struct CHEATF *c=cheats;
116 for(x=0;x<numsubcheats;x++)
117 SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead);
122 if(c->type==1 && c->status)
124 if(GetReadHandler(c->addr)==SubCheatsRead)
126 /* Prevent a catastrophe by this check. */
127 //FCEU_DispMessage("oops");
131 SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr);
132 SubCheats[numsubcheats].addr=c->addr;
133 SubCheats[numsubcheats].val=c->val;
134 SubCheats[numsubcheats].compare=c->compare;
135 SetReadHandler(c->addr,c->addr,SubCheatsRead);
143 void FCEU_PowerCheats()
145 numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */
149 static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
150 static void CheatMemErr(void)
152 FCEUD_PrintError("Error allocating memory for cheat data.");
155 /* This function doesn't allocate any memory for "name" */
156 static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
159 if(!(temp=(struct CHEATF *)malloc(sizeof(struct CHEATF))))
168 temp->compare=compare;
183 void FCEU_LoadGameCheats(FILE *override)
190 unsigned int compare;
198 numsubcheats=savecheats=0;
204 fn=FCEU_MakeFName(FCEUMKF_CHEAT,0,0);
205 fp=FCEUD_UTF8fopen(fn,"rb");
210 while(fgets(linebuf,2048,fp)>0)
215 addr=val=compare=status=type=0;
239 char *neo=&tbuf[4+2+2+1+1+1];
240 if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3)
242 namebuf=malloc(strlen(neo)+1);
247 char *neo=&tbuf[4+2+1+1];
248 if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2)
250 namebuf=malloc(strlen(neo)+1);
254 for(x=0;x<strlen(namebuf);x++)
256 if(namebuf[x]==10 || namebuf[x]==13)
261 else if(namebuf[x]<0x20) namebuf[x]=' ';
264 AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);
272 void FCEU_FlushGameCheats(FILE *override, int nosave)
279 if((!savecheats || nosave) && !override) /* Always save cheats if we're being overridden. */
283 struct CHEATF *next=cheats;
286 struct CHEATF *last=next;
300 fn = FCEU_MakeFName(FCEUMKF_CHEAT,0,0);
304 struct CHEATF *next=cheats;
310 fp=FCEUD_UTF8fopen(fn,"wb");
326 fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name);
328 fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
340 FCEUD_PrintError("Error saving cheats.");
349 RebuildSubCheats(); /* Remove memory handlers. */
354 int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
358 if(!(t=(char *)malloc(strlen(name)+1)))
364 if(!AddCheatEntry(t,addr,val,compare,1,type))
374 int FCEUI_DelCheat(uint32 which)
380 for(prev=0,cur=cheats;;)
382 if(x==which) // Remove this cheat.
384 if(prev) // Update pointer to this cheat.
386 if(cur->next) // More cheats.
387 prev->next=cur->next;
391 cheatsl=prev; // Set the previous cheat as the last cheat.
394 else // This is the first cheat.
396 if(cur->next) // More cheats
399 cheats=cheatsl=0; // No (more) cheats.
401 free(cur->name); // Now that all references to this cheat are removed,
402 free(cur); // free the memory.
404 } // *END REMOVE THIS CHEAT*
407 if(!cur->next) // No more cheats to go through(this shouldn't ever happen...)
420 void FCEU_ApplyPeriodicCheats(void)
422 struct CHEATF *cur=cheats;
427 if(cur->status && !(cur->type))
428 if(CheatRPtrs[cur->addr>>10])
429 CheatRPtrs[cur->addr>>10][cur->addr]=cur->val;
438 void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
440 struct CHEATF *next=cheats;
444 if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
449 int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
451 struct CHEATF *next=cheats;
467 *compare=next->compare;
478 static int GGtobin(char c)
480 static char lets[16]={'A','P','Z','L','G','I','T','Y','E','O','X','U','K','S','V','N'};
484 if(lets[x] == toupper(c)) return(x);
488 /* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */
489 int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c)
501 if(s!=6 && s!=8) return(0);
513 //if(t&0x08) return(0); /* 8-character code?! */
555 int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type)
558 if(strlen(str)!=8) return(0);
560 sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3);
566 *a=(boo[3]<<8)|(boo[2]+0x7F);
572 *a=boo[2]|(boo[1]<<8);
574 /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so
575 we must do the old hacky method of RAM cheats.
584 /* name can be NULL if the name isn't going to be changed. */
585 /* same goes for a, v, and s(except the values of each one must be <0) */
587 int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type)
589 struct CHEATF *next=cheats;
600 if((t=(char *)realloc(next->name,strlen(name+1))))
603 strcpy(next->name,name);
614 next->compare=compare;
628 /* Convenience function. */
629 int FCEUI_ToggleCheat(uint32 which)
631 struct CHEATF *next=cheats;
638 next->status=!next->status;
641 return(next->status);
650 static int InitCheatComp(void)
654 CheatComp=(uint16*)malloc(65536*sizeof(uint16));
661 CheatComp[x]=CHEATC_NONE;
666 void FCEUI_CheatSearchSetCurrentAsOriginal(void)
669 for(x=0x000;x<0x10000;x++)
670 if(!(CheatComp[x]&CHEATC_NOSHOW))
672 if(CheatRPtrs[x>>10])
673 CheatComp[x]=CheatRPtrs[x>>10][x];
675 CheatComp[x]|=CHEATC_NONE;
679 void FCEUI_CheatSearchShowExcluded(void)
683 for(x=0x000;x<0x10000;x++)
684 CheatComp[x]&=~CHEATC_EXCLUDED;
688 int32 FCEUI_CheatSearchGetCount(void)
694 for(x=0x0000;x<0x10000;x++)
695 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
701 /* This function will give the initial value of the search and the current value at a location. */
703 void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data),void *data)
714 for(x=0;x<0x10000;x++)
715 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
716 if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x],data))
720 void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
732 for(x=0;x<0x10000;x++)
733 if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
736 if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
743 void FCEUI_CheatSearchBegin(void)
755 for(x=0;x<0x10000;x++)
757 if(CheatRPtrs[x>>10])
758 CheatComp[x]=CheatRPtrs[x>>10][x];
760 CheatComp[x]=CHEATC_NONE;
765 static int INLINE CAbs(int x)
772 void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
786 if(!type) // Change to a specific value.
788 for(x=0;x<0x10000;x++)
789 if(!(CheatComp[x]&CHEATC_NOSHOW))
791 if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
796 CheatComp[x]|=CHEATC_EXCLUDED;
799 else if(type==1) // Search for relative change(between values).
801 for(x=0;x<0x10000;x++)
802 if(!(CheatComp[x]&CHEATC_NOSHOW))
804 if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
809 CheatComp[x]|=CHEATC_EXCLUDED;
812 else if(type==2) // Purely relative change.
814 for(x=0x000;x<0x10000;x++)
815 if(!(CheatComp[x]&CHEATC_NOSHOW))
817 if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
822 CheatComp[x]|=CHEATC_EXCLUDED;
825 else if(type==3) // Any change.
827 for(x=0;x<0x10000;x++)
828 if(!(CheatComp[x]&CHEATC_NOSHOW))
830 if(CheatComp[x]!=CheatRPtrs[x>>10][x])
835 CheatComp[x]|=CHEATC_EXCLUDED;
838 else if(type==4) // Value decreased.
840 for(x=0;x<0x10000;x++)
841 if(!(CheatComp[x]&CHEATC_NOSHOW))
843 if(!(CheatRPtrs[x>>10][x]<CheatComp[x]))
844 CheatComp[x]|=CHEATC_EXCLUDED;
847 else if(type==5) // Value increased.
849 for(x=0;x<0x10000;x++)
850 if(!(CheatComp[x]&CHEATC_NOSHOW))
852 if(!(CheatRPtrs[x>>10][x]>CheatComp[x]))
853 CheatComp[x]|=CHEATC_EXCLUDED;
857 FCEUI_CheatSearchSetCurrentAsOriginal();