/* Returns 0 to stop listing, 1 to continue. */ int AddToList(const char *text, uint32 id, const char* second_text = NULL) { if(listcount==10) { int t=ListChoice(0); mordoe=0; if(t==-1) return(0); // Stop listing. else if(t>0 && t<11) { listsel=listids[t-1]; return(0); } listcount=0; } mordoe = 1; listids[listcount] = id; CHEAT_printf("%2d) %s",listcount+1,text); if(second_text != NULL) CHEAT_printf(" %s", second_text); listcount++; return(1); }
static int ShowShortList(const char *moe[], unsigned int n, int def) { unsigned int x; int c; unsigned int baa; char tmp[256]; red: for(x=0;x<n;x++) CHEAT_printf("%d) %s",x+1,moe[x]); CHEAT_puts("D) Display List"); clo: CHEAT_puts(""); CHEAT_printf("Selection [%d]> ",def+1); CHEAT_gets(tmp,256); if(!tmp[0]) return def; c=tolower(tmp[0]); baa=c-'1'; if(baa<n) return baa; else if(c=='d') goto red; else { CHEAT_puts("Invalid selection."); goto clo; } }
/* Return equals 0 to continue, -1 to stop, otherwise a number. */ int ListChoice(int hmm) { char buf[32]; if(!hmm) { int num=0; tryagain: CHEAT_printf(" <'Enter' to continue, (S)top, or #> "); CHEAT_gets(buf,32); if(buf[0]=='s' || buf[0]=='S') return(-1); if(!buf[0]) return(0); if(!trio_sscanf(buf,"%d",&num)) return(0); if(num<1) goto tryagain; return(num); } else { int num=0; tryagain2: CHEAT_printf(" <'Enter' to make no selection, or #> "); CHEAT_gets(buf,32); if(!buf[0]) return(0); if(!trio_sscanf(buf,"%d",&num)) return(0); if(num<1) goto tryagain2; return(num); } }
static void AddCheatParam(uint32 A, uint64 V, unsigned int bytelen, bool bigendian) { MemoryPatch patch; patch.addr = A; patch.val = V; patch.length = bytelen; patch.bigendian = bigendian; patch.type = 'R'; patch.status = true; patch = GetCheatFields(patch); CHEAT_printf("Add cheat \"%s\" for address $%08x with value %llu?", patch.name.c_str(), (unsigned int)patch.addr, (unsigned long long)patch.val); if(GetYN(true)) { try { MDFNI_AddCheat(patch); } catch(std::exception &e) { CHEAT_printf("Error adding cheat: %s", e.what()); return; } CHEAT_puts("Cheat added."); } }
static void DoMenu(const std::vector<MENU>& men, bool topmost = 0) { bool MenuLoop = TRUE; while(MenuLoop) { int x; CHEAT_puts(""); for(x = 0; x < (int)men.size(); x++) CHEAT_printf("%d) %s", x + 1, men[x].text.c_str()); CHEAT_puts("D) Display Menu"); if(!topmost) CHEAT_puts("X) Return to Previous"); bool CommandLoop = TRUE; while(CommandLoop) { char buf[32]; int c, c_numeral; CHEAT_printf("Command> "); CHEAT_gets(buf,32); c = tolower(buf[0]); if(c == 0) continue; else if(c == 'd') { CommandLoop = FALSE; } else if(c == 'x' && !topmost) { CommandLoop = FALSE; MenuLoop = FALSE; } else if(trio_sscanf(buf, "%d", &c_numeral) == 1 && c_numeral <= x && c_numeral >= 1) { assert(!(men[c_numeral - 1].func_action && men[c_numeral - 1].menu_action)); if(men[c_numeral - 1].func_action) men[c_numeral - 1].func_action(men[c_numeral - 1].data); else if(men[c_numeral - 1].menu_action) DoMenu(*men[c_numeral - 1].menu_action); /* Mmm...recursivey goodness. */ CommandLoop = FALSE; } else { CHEAT_puts("Invalid command."); } } // while(CommandLoop) } // while(MenuLoop) }
static void DoMenu(MENU *men, bool topmost = 0) { int x=0; redisplay: x=0; CHEAT_puts(""); while(men[x].text) { CHEAT_printf("%d) %s",x+1,men[x].text); x++; } CHEAT_puts("D) Display Menu"); if(!topmost) CHEAT_puts("X) Return to Previous"); { char buf[32]; int c; recommand: CHEAT_printf("Command> "); CHEAT_gets(buf,32); c=tolower(buf[0]); if(c == 0) goto recommand; else if(c=='d') goto redisplay; else if(c=='x' && !topmost) { return; } else if(trio_sscanf(buf,"%d",&c)) { if(c>x) goto invalid; if(men[c-1].type) { void (*func)(void)=(void(*)())men[c-1].action; func(); } else DoMenu((MENU*)men[c-1].action); /* Mmm...recursivey goodness. */ goto redisplay; } else { invalid: CHEAT_puts("Invalid command."); goto recommand; } } }
static void AddCheatGGPAR(int which) { uint32 A; uint8 V; uint8 C; char type; char name[256],code[256]; CHEAT_printf("Name: "); GetString(name,256); CHEAT_printf("Code: "); GetString(code,256); CHEAT_printf("Add cheat \"%s\" for code \"%s\"?",name,code); if(GetYN(0)) { if(which) { if(!MDFNI_DecodePAR(code,&A,&V,&C,&type)) { CHEAT_puts("Invalid Game Genie code."); return; } } else { if(!strcmp(CurGame->shortname, "gb")) { if(!MDFNI_DecodeGBGG(code, &A, &V, &C, &type)) { CHEAT_puts("Invalid Game Genie code."); return; } } else { if(!MDFNI_DecodeGG(code,&A,&V,&C, &type)) { CHEAT_puts("Invalid Game Genie code."); return; } } } if(MDFNI_AddCheat(name,A,V,C,type, 1, 0)) CHEAT_puts("Cheat added."); else CHEAT_puts("Error adding cheat."); } }
static void ListCheats(void) { int which; lid=0; BeginListShow(); MDFNI_ListCheats(clistcallb,0); which=EndListShow(); if(which>=0) { char tmp[32]; CHEAT_printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> "); CHEAT_gets(tmp,32); switch(tolower(tmp[0])) { case 't':ToggleCheat(which); break; case 'd':if(!MDFNI_DelCheat(which)) CHEAT_puts("Error deleting cheat!"); else CHEAT_puts("Cheat has been deleted."); break; case 'm':ModifyCheat(which); break; } } }
static int GetYN(int def) { char buf[32]; CHEAT_printf("(Y/N)[%s]: ",def?"Y":"N"); CHEAT_gets(buf,32); if(buf[0]=='y' || buf[0]=='Y') return(1); if(buf[0]=='n' || buf[0]=='N') return(0); return(def); }
static void AddCheatParam(uint32 A, uint64 V, unsigned int bytelen, bool bigendian) { char name[256]; CHEAT_printf("Name: "); GetString(name,256); CHEAT_printf("Address [$%08x]: ", A); A=GetUI(A); CHEAT_printf("Byte length [%d]: ", bytelen); bytelen = GetUI(bytelen); if(bytelen > 1) { CHEAT_printf("Big endian? [%c]: ", bigendian ? 'Y' : 'N'); bigendian = GetYN(bigendian); } else bigendian = 0; CHEAT_printf("Value [%llu]: ", V); V=GetUI(V); CHEAT_printf("Add cheat \"%s\" for address $%08x with value %llu?",name,(unsigned int)A,(unsigned long long)V); if(GetYN(0)) { if(MDFNI_AddCheat(name,A,V,0, 'R', bytelen, bigendian)) CHEAT_puts("Cheat added."); else CHEAT_puts("Error adding cheat."); } }
static void ShowRes(void* data) { int n=MDFNI_CheatSearchGetCount(); CHEAT_printf(" %d results:",n); if(n) { int which; BeginListShow(); MDFNI_CheatSearchGet(srescallb, 0); which=EndListShow(); if(which>=0) AddCheatParam(which,0, searchbytelen, searchbigendian); } }
static void DoSearch(void* data) { static int v1=0,v2=0; static int method=0; const char *m[6]={"O==V1 && C==V2","O==V1 && |O-C|==V2","|O-C|==V2","O!=C","Value decreased","Value increased"}; CHEAT_puts(""); CHEAT_printf("Search Filter:"); method = ShowShortList(m,6,method); if(method<=1) { CHEAT_printf("V1 [%03d]: ",v1); v1=GetUI(v1); } if(method<=2) { CHEAT_printf("V2 [%03d]: ",v2); v2=GetUI(v2); } CHEAT_printf("Byte length(1-8)[%1d]: ", searchbytelen); searchbytelen = GetUI(searchbytelen); if(searchbytelen > 1) { CHEAT_printf("Big endian? [%c]: ", searchbigendian ? 'Y' : 'N'); searchbigendian = GetYN(searchbigendian); } else searchbigendian = 0; MDFNI_CheatSearchEnd(method, v1, v2, searchbytelen, searchbigendian); CHEAT_puts("Search completed."); }
static int clistcallb(const MemoryPatch& patch, void *data) { char tmp[512]; int ret; if(!lid) { CHEAT_printf(" /---------------------------------------\\"); CHEAT_printf(" | Type | Affected Addr Range | Name \\"); CHEAT_printf(" |-----------------------------------------\\"); } if(patch.type == 'C' || patch.type == 'S') { trio_snprintf(tmp, 512, "%c %c | $%08x | %s", patch.status ? '*' : ' ', patch.type, patch.addr, patch.name.c_str()); //trio_snprintf(tmp, 512, "%s %c $%08x:%lld:%lld - %s", patch.status ? "*" : " ", patch.type, patch.addr, patch.val, patch.compare, patch.name.c_str()); } else { uint32 sa = patch.addr; uint32 ea = patch.addr + ((patch.mltpl_count - 1) * patch.mltpl_addr_inc) + (patch.length - 1); if(patch.mltpl_count == 0 || patch.length == 0) trio_snprintf(tmp, 512, "%c %c%s | | %s", patch.status ? '*' : ' ', patch.type, patch.conditions.size() ? "+CC" : " ", patch.name.c_str()); else { if(sa == ea) trio_snprintf(tmp, 512, "%c %c%s | $%08x | %s", patch.status ? '*' : ' ', patch.type, patch.conditions.size() ? "+CC" : " ", sa, patch.name.c_str()); else trio_snprintf(tmp, 512, "%c %c%s | $%08x-$%08x | %s", patch.status ? '*' : ' ', patch.type, patch.conditions.size() ? "+CC" : " ", sa, ea, patch.name.c_str()); } } ret = AddToList(tmp, lid); lid++; return(ret); }
static void ListCheats(void* data) { int which; lid=0; BeginListShow(); MDFNI_ListCheats(clistcallb,0); which=EndListShow(); if(which>=0) { char tmp[32]; CHEAT_printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> "); CHEAT_gets(tmp,32); switch(tolower(tmp[0])) { case 't':ToggleCheat(which); break; case 'd': try { MDFNI_DelCheat(which); } catch(std::exception &e) { CHEAT_printf("Error deleting cheat: %s", e.what()); break; } CHEAT_puts("Cheat has been deleted."); break; case 'm':ModifyCheat(which); break; } } }
static MemoryPatch GetCheatFields(const MemoryPatch &pin) { MemoryPatch patch = pin; char buf[256]; const bool support_read_subst = CurGame->InstallReadPatch && CurGame->RemoveReadPatches; CHEAT_printf("Name [%s]: ", patch.name.c_str()); GetString(buf, 256); if(buf[0] != 0) patch.name = std::string(buf); CHEAT_printf("Available types:"); CHEAT_printf(" R - Replace/RAM write(high-level)."); CHEAT_printf(" A - Addition/RAM read->add->write(high-level)."); CHEAT_printf(" T - Transfer/RAM copy(high-level)."); if(support_read_subst) { CHEAT_printf(" S - Subsitute on reads."); CHEAT_printf(" C - Substitute on reads, with compare."); } for(;;) { CHEAT_printf("Type [%c]: ", patch.type); patch.type = toupper(CHEAT_getchar(patch.type)); if(patch.type == 'R' || patch.type == 'A' || patch.type == 'T') break; if(support_read_subst && (patch.type == 'S' || patch.type == 'C')) break; } if(patch.type == 'T') { CHEAT_printf("Source address [$%08x]: ", (unsigned int)patch.copy_src_addr); patch.copy_src_addr = GetUI(patch.copy_src_addr); CHEAT_printf("Source address inc [%u]: ", patch.copy_src_addr_inc); patch.copy_src_addr_inc = GetUI(patch.copy_src_addr_inc); CHEAT_printf("Dest address [$%08x]: ", (unsigned int)patch.addr); patch.addr = GetUI(patch.addr); CHEAT_printf("Dest address inc [%u]: ", patch.mltpl_addr_inc); patch.mltpl_addr_inc = GetUI(patch.mltpl_addr_inc); CHEAT_printf("Count [%u]: ", patch.mltpl_count); patch.mltpl_count = GetUI(patch.mltpl_count); } else { CHEAT_printf("Address [$%08x]: ", (unsigned int)patch.addr); patch.addr = GetUI(patch.addr); } if(patch.type == 'S' || patch.type == 'C') patch.length = 1; // TODO in the future for GBA: support lengths other than 1 in core. else { do { if(patch.type == 'T') { //if(patch.length == 1 && patch.copy_src_addr_inc == 1 && patch.mltpl_addr_inc == 1) // break; //if((patch.copy_src_addr_inc == patch.mltpl_addr_inc) && patch.copy_src_addr_inc >= 1 && patch.copy_src_addr_inc <= 8) // CHEAT_printf("Transfer unit byte length should probably be \"%u\".", patch.copy_src_addr_inc); CHEAT_printf("Transfer unit byte length(1-8) [%u]: ", patch.length); } else CHEAT_printf("Byte length(1-8) [%u]: ", patch.length); patch.length = GetUI(patch.length); } while(patch.length < 1 || patch.length > 8); } if(patch.length > 1 && (patch.type != 'S' && patch.type != 'C')) { CHEAT_printf("Big endian? [%c]: ", patch.bigendian ? 'Y' : 'N'); patch.bigendian = GetYN(patch.bigendian); } else patch.bigendian = false; if(patch.type != 'T') { CHEAT_printf("Value [%03llu]: ", (unsigned long long)patch.val); patch.val = GetUI(patch.val); } // T type loop stuff is handled up above. if((patch.type != 'C' && patch.type != 'S' && patch.type != 'T') && patch.mltpl_count != 1) { CHEAT_printf("Loop count [%u]: ", patch.mltpl_count); patch.mltpl_count = GetUI(patch.mltpl_count); CHEAT_printf("Loop address inc [%u]: ", patch.mltpl_addr_inc); patch.mltpl_addr_inc = GetUI(patch.mltpl_addr_inc); CHEAT_printf("Loop value inc [%u]: ", patch.mltpl_val_inc); patch.mltpl_val_inc = GetUI(patch.mltpl_val_inc); } if(patch.type == 'C') { CHEAT_printf("Compare [%03lld]: ", patch.compare); patch.compare = GetUI(patch.compare); } if((patch.type != 'C' && patch.type != 'S') && patch.conditions.size()) { CHEAT_printf("Conditions: %s", patch.conditions.c_str()); // Just informational for now. //CHEAT_printf("Conditions [%s]: ", ); //patch.conditions = GetString(); } CHEAT_printf("Enable? "); patch.status = GetYN(patch.status); return(patch); }
static void ToggleCheat(int num) { CHEAT_printf("Cheat %d %sabled.",1+num, MDFNI_ToggleCheat(num)?"en":"dis"); }
static void AddCodeCheat(void* data) { const CheatFormatStruct* cf = (CheatFormatStruct*)data; char name[256],code[256]; MemoryPatch patch; unsigned iter = 0; while(1) { if(iter == 0) CHEAT_printf("%s Code: ", cf->FullName); else CHEAT_printf("%s Code(part %u): ", cf->FullName, iter + 1); GetString(code, 256); if(code[0] == 0) { CHEAT_printf("Aborted."); return; } try { if(!cf->DecodeCheat(std::string(code), &patch)) break; iter++; } catch(std::exception &e) { CHEAT_printf("Decode error: %s", e.what()); } } if(patch.name.size() == 0) patch.name = std::string(code); CHEAT_printf("Name[%s]: ", patch.name.c_str()); GetString(name, 256); if(name[0] != 0) patch.name = std::string(name); patch.status = true; CHEAT_printf("Add cheat?"); if(GetYN(true)) { try { MDFNI_AddCheat(patch); } catch(std::exception &e) { CHEAT_printf("Error adding cheat: %s", e.what()); return; } CHEAT_puts("Cheat added."); } }
static void ModifyCheat(int num) { char *name; char buf[256]; uint32 A; uint64 V; uint64 compare; char type; int status; unsigned int bytelen; bool bigendian; MDFNI_GetCheat(num, &name, &A, &V, &compare, &status, &type, &bytelen, &bigendian); CHEAT_printf("Name [%s]: ",name); GetString(buf,256); /* This obviously doesn't allow for cheats with no names. Bah. Who wants nameless cheats anyway... */ if(buf[0]) name=buf; // Change name when MDFNI_SetCheat() is called. else name=0; // Don't change name when MDFNI_SetCheat() is called. CHEAT_printf("Address [$%08x]: ",(unsigned int)A); A=GetUI(A); CHEAT_printf("Byte length [%d]: ", bytelen); bytelen = GetUI(bytelen); if(bytelen > 1) { CHEAT_printf("Big endian? [%c]: ", bigendian ? 'Y' : 'N'); bigendian = GetYN(bigendian); } else bigendian = 0; CHEAT_printf("Value [%03lld]: ",(unsigned int)V); V=GetUI(V); do { CHEAT_printf("Type('R'=replace,'S'=Read Substitute(or 'C' with compare)) [%c]: ",type); type = toupper(CHEAT_getchar(type)); } while(type != 'R' && type !='S' && type !='C'); if(type == 'C') { CHEAT_printf("Compare [%03lld]: ",compare); compare = GetUI(compare); } CHEAT_printf("Enable? "); status = GetYN(status); MDFNI_SetCheat(num, name, A, V, compare, status, type, bytelen, bigendian); }