X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=fceu.git;a=blobdiff_plain;f=cheat.c;h=2fba4f44e1b8b55e341f6cb180e589134fd76153;hp=d789d74465bf8c0c50a42a56293c52289a724cc3;hb=92764e6252a3691033d6044b466bf716c96b62d5;hpb=ea80a45b1dbd9f2c46567e18a2e18fcbb6e55c8d diff --git a/cheat.c b/cheat.c index d789d74..2fba4f4 100644 --- a/cheat.c +++ b/cheat.c @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2002 Ben Parnell + * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,23 +21,26 @@ #include #include #include +#include #include "types.h" #include "x6502.h" #include "cheat.h" #include "fce.h" -#include "svga.h" #include "general.h" #include "cart.h" #include "memory.h" +#include "file.h" +#include "svga.h" + static uint8 *CheatRPtrs[64]; void FCEU_CheatResetRAM(void) { int x; - for(x=0;x<64;x++) + for(x=0;x<64;x++) CheatRPtrs[x]=0; } @@ -56,9 +59,21 @@ struct CHEATF { char *name; uint16 addr; uint8 val; + int compare; /* -1 for no compare. */ + int type; /* 0 for replace, 1 for substitute(GG). */ int status; }; +typedef struct { + uint16 addr; + uint8 val; + int compare; + readfunc PrevRead; +} CHEATF_SUBFAST; + + +static CHEATF_SUBFAST SubCheats[256]; +static int numsubcheats=0; struct CHEATF *cheats=0,*cheatsl=0; @@ -69,18 +84,79 @@ struct CHEATF *cheats=0,*cheatsl=0; static uint16 *CheatComp=0; static int savecheats; -static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status); +static DECLFR(SubCheatsRead) +{ + CHEATF_SUBFAST *s=SubCheats; + int x=numsubcheats; + + do + { + if(s->addr==A) + { + if(s->compare>=0) + { + uint8 pv=s->PrevRead(A); + + if(pv==s->compare) + return(s->val); + else return(pv); + } + else return(s->val); + } + s++; + } while(--x); + return(0); /* We should never get here. */ +} + +void RebuildSubCheats(void) +{ + int x; + struct CHEATF *c=cheats; + + for(x=0;xtype==1 && c->status) + { + if(GetReadHandler(c->addr)==SubCheatsRead) + { + /* Prevent a catastrophe by this check. */ + //FCEU_DispMessage("oops"); + } + else + { + SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr); + SubCheats[numsubcheats].addr=c->addr; + SubCheats[numsubcheats].val=c->val; + SubCheats[numsubcheats].compare=c->compare; + SetReadHandler(c->addr,c->addr,SubCheatsRead); + numsubcheats++; + } + } + c=c->next; + } +} +void FCEU_PowerCheats() +{ + numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */ + RebuildSubCheats(); +} + +static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type); static void CheatMemErr(void) { FCEUD_PrintError("Error allocating memory for cheat data."); } /* This function doesn't allocate any memory for "name" */ -static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status) +static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type) { struct CHEATF *temp; - if(!(temp=malloc(sizeof(struct CHEATF)))) + if(!(temp=(struct CHEATF *)malloc(sizeof(struct CHEATF)))) { CheatMemErr(); return(0); @@ -89,7 +165,8 @@ static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status) temp->addr=addr; temp->val=val; temp->status=status; - + temp->compare=compare; + temp->type=type; temp->next=0; if(cheats) @@ -103,80 +180,113 @@ static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status) return(1); } -void LoadGameCheats(void) +void FCEU_LoadGameCheats(FILE *override) { FILE *fp; - char *name=0; unsigned int addr; unsigned int val; unsigned int status; + unsigned int type; + unsigned int compare; int x; - 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 */ - char namebuf[257]; + char linebuf[2048]; + char *namebuf; int tc=0; + char *fn; + + numsubcheats=savecheats=0; + + if(override) + fp = override; + else + { + fn=FCEU_MakeFName(FCEUMKF_CHEAT,0,0); + fp=FCEUD_UTF8fopen(fn,"rb"); + free(fn); + if(!fp) return; + } - savecheats=0; - if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"rb"))) - return; - - while(fgets(linebuf,256+4+2+2+1+1,fp)>0) - { - addr=val=status=0; - namebuf[0]=0; // If the cheat doesn't have a name... - if(linebuf[0]==':') + while(fgets(linebuf,2048,fp)>0) + { + char *tbuf=linebuf; + int doc=0; + + addr=val=compare=status=type=0; + + if(tbuf[0]=='S') { - strncpy(namebuf,&linebuf[1+4+2+2],257); - if(sscanf(&linebuf[1],"%04x%*[:]%02x",&addr,&val)!=2) - continue; + tbuf++; + type=1; + } + else type=0; + + if(tbuf[0]=='C') + { + tbuf++; + doc=1; + } + + if(tbuf[0]==':') + { + tbuf++; status=0; } + else status=1; + + if(doc) + { + char *neo=&tbuf[4+2+2+1+1+1]; + if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3) + continue; + namebuf=malloc(strlen(neo)+1); + strcpy(namebuf,neo); + } else { - strncpy(namebuf,&linebuf[4+2+2],257); - if(sscanf(linebuf,"%04x%*[:]%02x",&addr,&val)!=2) continue; - status=1; + char *neo=&tbuf[4+2+1+1]; + if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2) + continue; + namebuf=malloc(strlen(neo)+1); + strcpy(namebuf,neo); } - for(x=0;x<257;x++) + + for(x=0;xnext; - free(cheats->name); - free(cheats); + free(last->name); + free(last); if(!next) break; } cheats=cheatsl=0; @@ -184,53 +294,80 @@ void FlushGameCheats(void) } else { + char *fn = 0; + + if(!override) + fn = FCEU_MakeFName(FCEUMKF_CHEAT,0,0); + if(cheats) { struct CHEATF *next=cheats; FILE *fp; - if((fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"wb"))) + + if(override) + fp = override; + else + fp=FCEUD_UTF8fopen(fn,"wb"); + + if(fp) { for(;;) { struct CHEATF *t; - if(next->status) - fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name); + if(next->type) + fputc('S',fp); + if(next->compare>=0) + fputc('C',fp); + + if(!next->status) + fputc(':',fp); + + if(next->compare>=0) + fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name); else - fprintf(fp,":%04x:%02x:%s\n",next->addr,next->val,next->name); + fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name); + free(next->name); t=next; next=next->next; free(t); if(!next) break; } - fclose(fp); + if(!override) + fclose(fp); } else FCEUD_PrintError("Error saving cheats."); cheats=cheatsl=0; } - else - remove(FCEU_MakeFName(FCEUMKF_CHEAT,0,0)); + else if(!override) + remove(fn); + if(!override) + free(fn); } + + RebuildSubCheats(); /* Remove memory handlers. */ + } -int FCEUI_AddCheat(char *name, uint32 addr, uint8 val) +int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) { char *t; - if(!(t=malloc(strlen(name)+1))) + if(!(t=(char *)malloc(strlen(name)+1))) { CheatMemErr(); return(0); } strcpy(t,name); - if(!AddCheatEntry(t,addr,val,1)) + if(!AddCheatEntry(t,addr,val,compare,1,type)) { free(t); return(0); } savecheats=1; + RebuildSubCheats(); return(1); } @@ -262,7 +399,7 @@ int FCEUI_DelCheat(uint32 which) cheats=cheatsl=0; // No (more) cheats. } free(cur->name); // Now that all references to this cheat are removed, - free(cur); // free the memory. + free(cur); // free the memory. break; } // *END REMOVE THIS CHEAT* @@ -275,17 +412,19 @@ int FCEUI_DelCheat(uint32 which) } savecheats=1; + RebuildSubCheats(); + return(1); } -void ApplyPeriodicCheats(void) +void FCEU_ApplyPeriodicCheats(void) { struct CHEATF *cur=cheats; if(!cur) return; for(;;) { - if(cur->status) + if(cur->status && !(cur->type)) if(CheatRPtrs[cur->addr>>10]) CheatRPtrs[cur->addr>>10][cur->addr]=cur->val; if(cur->next) @@ -296,18 +435,18 @@ void ApplyPeriodicCheats(void) } -void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s)) +void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data) { struct CHEATF *next=cheats; while(next) { - if(!callb(next->name,next->addr,next->val,next->status)) break; + if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break; next=next->next; } } -int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s) +int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type) { struct CHEATF *next=cheats; uint32 x=0; @@ -319,12 +458,15 @@ int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s) if(name) *name=next->name; if(a) - *a=next->addr; + *a=next->addr; if(v) *v=next->val; if(s) *s=next->status; - + if(compare) + *compare=next->compare; + if(type) + *type=next->type; return(1); } next=next->next; @@ -333,10 +475,116 @@ int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s) return(0); } +static int GGtobin(char c) +{ + static char lets[16]={'A','P','Z','L','G','I','T','Y','E','O','X','U','K','S','V','N'}; + int x; + + for(x=0;x<16;x++) + if(lets[x] == toupper(c)) return(x); + return(0); +} + +/* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */ +int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c) +{ + uint16 A; + uint8 V,C; + uint8 t; + int s; + + A=0x8000; + V=0; + C=0; + + s=strlen(str); + if(s!=6 && s!=8) return(0); + + t=GGtobin(*str++); + V|=(t&0x07); + V|=(t&0x08)<<4; + + t=GGtobin(*str++); + V|=(t&0x07)<<4; + A|=(t&0x08)<<4; + + t=GGtobin(*str++); + A|=(t&0x07)<<4; + //if(t&0x08) return(0); /* 8-character code?! */ + + t=GGtobin(*str++); + A|=(t&0x07)<<12; + A|=(t&0x08); + + t=GGtobin(*str++); + A|=(t&0x07); + A|=(t&0x08)<<8; + + if(s==6) + { + t=GGtobin(*str++); + A|=(t&0x07)<<8; + V|=(t&0x08); + + *a=A; + *v=V; + *c=-1; + return(1); + } + else + { + t=GGtobin(*str++); + A|=(t&0x07)<<8; + C|=(t&0x08); + + t=GGtobin(*str++); + C|=(t&0x07); + C|=(t&0x08)<<4; + + t=GGtobin(*str++); + C|=(t&0x07)<<4; + V|=(t&0x08); + *a=A; + *v=V; + *c=C; + return(1); + } + return(0); +} + +int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type) +{ + int boo[4]; + if(strlen(str)!=8) return(0); + + sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3); + + *c=-1; + + if(1) + { + *a=(boo[3]<<8)|(boo[2]+0x7F); + *v=0; + } + else + { + *v=boo[3]; + *a=boo[2]|(boo[1]<<8); + } + /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so + we must do the old hacky method of RAM cheats. + */ + if(*a<0x0100) + *type=0; + else + *type=1; + return(1); +} + /* name can be NULL if the name isn't going to be changed. */ /* same goes for a, v, and s(except the values of each one must be <0) */ -int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s) +int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type) { struct CHEATF *next=cheats; uint32 x=0; @@ -349,7 +597,7 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s) { char *t; - if((t=realloc(next->name,strlen(name+1)))) + if((t=(char *)realloc(next->name,strlen(name+1)))) { next->name=t; strcpy(next->name,name); @@ -363,7 +611,12 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s) next->val=v; if(s>=0) next->status=s; + next->compare=compare; + next->type=type; + savecheats=1; + RebuildSubCheats(); + return(1); } next=next->next; @@ -372,12 +625,33 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s) return(0); } +/* Convenience function. */ +int FCEUI_ToggleCheat(uint32 which) +{ + struct CHEATF *next=cheats; + uint32 x=0; + + while(next) + { + if(x==which) + { + next->status=!next->status; + savecheats=1; + RebuildSubCheats(); + return(next->status); + } + next=next->next; + x++; + } + + return(-1); +} static int InitCheatComp(void) { uint32 x; - CheatComp=malloc(65536*sizeof(uint16)); + CheatComp=(uint16*)malloc(65536*sizeof(uint16)); if(!CheatComp) { CheatMemErr(); @@ -385,7 +659,7 @@ static int InitCheatComp(void) } for(x=0;x<65536;x++) CheatComp[x]=CHEATC_NONE; - + return(1); } @@ -426,7 +700,7 @@ int32 FCEUI_CheatSearchGetCount(void) } /* This function will give the initial value of the search and the current value at a location. */ -void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current)) +void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data),void *data) { uint32 x; @@ -439,7 +713,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current)) for(x=0;x<0x10000;x++) if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) - if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) + if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x],data)) break; } @@ -550,7 +824,7 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) } else if(type==3) // Any change. { - for(x=0x000;x<0x10000;x++) + for(x=0;x<0x10000;x++) if(!(CheatComp[x]&CHEATC_NOSHOW)) { if(CheatComp[x]!=CheatRPtrs[x>>10][x]) @@ -560,6 +834,25 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) else CheatComp[x]|=CHEATC_EXCLUDED; } - } + else if(type==4) // Value decreased. + { + for(x=0;x<0x10000;x++) + if(!(CheatComp[x]&CHEATC_NOSHOW)) + { + if(!(CheatRPtrs[x>>10][x]>10][x]>CheatComp[x])) + CheatComp[x]|=CHEATC_EXCLUDED; + } + } + if(type>4) + FCEUI_CheatSearchSetCurrentAsOriginal(); }