X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Ffront-end%2Fsrc%2Fcheat.c;fp=source%2Ffront-end%2Fsrc%2Fcheat.c;h=d491cbf0a832dbc5ec738ea478c661dc10092f03;hb=5288f5429f38c99c73856e285d35e7d0c4c779d0;hp=0000000000000000000000000000000000000000;hpb=48d77f736bea02afeb362cff05c81375752b3015;p=mupen64plus-pandora.git diff --git a/source/front-end/src/cheat.c b/source/front-end/src/cheat.c new file mode 100644 index 0000000..d491cbf --- /dev/null +++ b/source/front-end/src/cheat.c @@ -0,0 +1,458 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cheat.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009-2010 Richard Goedeken * + * Copyright (C) 2010 Rhett Osborne (spinout) * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include "m64p_types.h" + +#include "main.h" +#include "cheat.h" +#include "core_interface.h" + +/* local definitions */ +#define CHEAT_FILE "mupencheat.txt" + +typedef struct { + int address; + int *variables; + char **variable_names; + int var_to_use; + int var_count; +} cheat_code; + +typedef struct _sCheatInfo { + int Number; + int Count; + int VariableLine; + const char *Name; + const char *Description; + cheat_code *Codes; + struct _sCheatInfo *Next; + } sCheatInfo; + +/* local variables */ +static m64p_rom_header l_RomHeader; +static char *l_IniText = NULL; +static char *l_CheatGameName = NULL; +static sCheatInfo *l_CheatList = NULL; +static int l_CheatCodesFound = 0; +static int l_RomFound = 0; + +/********************************************************************************************************* + * Static (Local) functions + */ + +static int isSpace(char ch) +{ + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); +} + +/* Find cheat code */ +static sCheatInfo *CheatFindCode(int Number) +{ + sCheatInfo *pCur = l_CheatList; + while (pCur != NULL) + { + if (pCur->Number == Number) break; + pCur = pCur->Next; + } + return pCur; +} + + +/* Activate a code */ +static void CheatActivate(sCheatInfo *pCheat) +{ + int i; + + /* Get a m64p_cheat_code object */ + m64p_cheat_code * code = (m64p_cheat_code*) calloc(pCheat->Count, sizeof(m64p_cheat_code)); + if (code == NULL) + { + DebugMessage(M64MSG_WARNING, "could not allocate memory for code '%s'", pCheat->Name); + return; + } + /* Fill in members */ + for (i = 0; i < pCheat->Count; i++) + { + code[i].address = pCheat->Codes[i].address; + code[i].value = pCheat->Codes[i].variables[pCheat->Codes[i].var_to_use]; + } + /* Enable cheat */ + if (CoreAddCheat(pCheat->Name, code, pCheat->Count) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_WARNING, "CoreAddCheat() failed for cheat code %i (%s)", pCheat->Number, pCheat->Name); + free(code); + return; + } + + free(code); + DebugMessage(M64MSG_STATUS, "activated cheat code %i: %s", pCheat->Number, pCheat->Name); +} + +static void CheatFreeAll(void) +{ + if (l_IniText != NULL) + free(l_IniText); + l_IniText = NULL; + + sCheatInfo *pCur = l_CheatList; + while (pCur != NULL) + { + sCheatInfo *pNext = pCur->Next; + if (pCur->Codes != NULL) + { + int i; + for (i=0; i < pCur->Count; i++) + { + if (pCur->Codes[i].variables != NULL) + free(pCur->Codes[i].variables); + if (pCur->Codes[i].variable_names != NULL) + free(pCur->Codes[i].variable_names); + } + free(pCur->Codes); + } + free(pCur); + pCur = pNext; + } + + l_CheatList = NULL; +} + +/* Append new code */ +static sCheatInfo * NewCode(char *CheatName, int CheatNum) +{ + /* allocate memory for a new sCheatInfo struct */ + sCheatInfo *pNew = (sCheatInfo *) malloc(sizeof(sCheatInfo)); + if (pNew == NULL) return NULL; + + /* fill in the data members */ + pNew->Number = CheatNum; + pNew->Count = 0; + pNew->VariableLine = -1; + pNew->Name = CheatName; + pNew->Description = NULL; + pNew->Codes = NULL; + pNew->Next = NULL; + + l_CheatCodesFound++; + + /* stick it at the end of the list */ + if (l_CheatList == NULL) + { + l_CheatList = pNew; + return pNew; + } + sCheatInfo *pLast = l_CheatList; + while (pLast->Next != NULL) pLast = pLast->Next; + pLast->Next = pNew; + return pNew; +} + +static void CheatAddVariables(cheat_code * Code, char *varlist) +{ + /* needs to be more verbose? */ + Code->variables = NULL; + Code->variable_names = NULL; + Code->var_count = 0; + while (*varlist != 0) + { + if ((Code->variables = (int*) realloc(Code->variables, sizeof(int) * (Code->var_count + 1))) == NULL) + return; + if ((Code->variable_names = (char**) realloc(Code->variable_names, sizeof(char*) * (Code->var_count + 1))) == NULL) + return; + if (sscanf(varlist, "%04X", &Code->variables[Code->var_count]) != 1) + Code->variables[Code->var_count] = 0; + if (strchr(varlist, '"') == NULL) + return; + Code->variable_names[Code->var_count] = strchr(varlist, '"') + 1; + if ((varlist = strchr(Code->variable_names[Code->var_count], '"')) == NULL) + return; + *varlist++ = 0; + if (*varlist == ',') + varlist++; + Code->var_count++; + } +} + +/********************************************************************************************************* +* global functions +*/ + +static void ReadCheats(char *RomSection) +{ + sCheatInfo *curr_code = NULL; + const char *romdbpath = ConfigGetSharedDataFilepath(CHEAT_FILE); + if (romdbpath == NULL) + { + DebugMessage(M64MSG_WARNING, "cheat code database file '%s' not found.", CHEAT_FILE); + return; + } + + /* read the INI file into a new buffer */ + FILE *fPtr = NULL; + fPtr = fopen(romdbpath, "rb"); + if (fPtr == NULL) + { + DebugMessage(M64MSG_WARNING, "Couldn't open cheat code database file '%s'.", romdbpath); + return; + } + fseek(fPtr, 0L, SEEK_END); + long IniLength = ftell(fPtr); + fseek(fPtr, 0L, SEEK_SET); + l_IniText = (char *) malloc(IniLength + 1); + if (l_IniText == NULL) + { + DebugMessage(M64MSG_WARNING, "Couldn't allocate %li bytes of memory to read cheat file.", IniLength); + fclose(fPtr); + return; + } + if (fread(l_IniText, 1, IniLength, fPtr) != IniLength) + { + DebugMessage(M64MSG_WARNING, "Couldn't read %li bytes from cheat file.", IniLength); + free(l_IniText); + l_IniText = NULL; + fclose(fPtr); + return; + } + fclose(fPtr); + l_IniText[IniLength] = 0; /* null-terminate the text data */ + + /* parse lines from cheat database */ + char *curline = NULL; + char *nextline = l_IniText; + + while(nextline != NULL && *nextline != 0) + { + curline = nextline; + /* get pointer to next line and NULL-terminate the current line */ + nextline = strchr(curline, '\n'); + if (nextline != NULL) + { + *nextline = 0; + nextline++; + } + + /* remove leading and trailing white space */ + while(isSpace(*curline)) curline++; + char *endptr = curline + strlen(curline) - 1; + while(isSpace(*endptr)) *endptr-- = 0; + + /* ignore line if comment or empty */ + if (*curline == '#' || strncmp(curline, "//", 2) == 0 || *curline == 0) + continue; + + /* handle beginning of new rom section */ + if (strncmp(curline, "crc ", 4) == 0) + { + /* if we have already found cheats for the given ROM file, then exit upon encountering a new ROM section */ + if (l_RomFound && (l_CheatGameName != NULL || l_CheatList != NULL)) + return; + /* else see if this Rom Section matches */ + if (strcmp(curline+4, RomSection) == 0) + l_RomFound = 1; + continue; + } + + /* if we haven't found the specified ROM section, then continue looking */ + if (!l_RomFound) + continue; + + /* Game name */ + if (strncmp(curline, "gn ", 3) == 0) + { + l_CheatGameName = curline+3; + continue; + } + + /* code name */ + if (strncmp(curline, "cn ", 3) == 0) + { + curr_code = NewCode(curline + 3, l_CheatCodesFound); + if (curr_code == NULL) + DebugMessage(M64MSG_WARNING, "error getting new code (%s)", curline+3); + continue; + } + + /* if curr_code is NULL, don't do these checks */ + if (curr_code == NULL) + continue; + + /* code description */ + if (strncmp(curline, "cd ", 3) == 0) + { + curr_code->Description = curline+3; + continue; + } + + /* code line */ + int address; + if (sscanf(curline, "%8X %*s", &address) == 1) + { + curr_code->Codes = (cheat_code*) realloc(curr_code->Codes, sizeof(cheat_code) * (curr_code->Count + 1)); + if (strncmp(curline+9, "????", 4) == 0) + { + curr_code->Codes[curr_code->Count].var_count = 0; + CheatAddVariables(&curr_code->Codes[curr_code->Count], curline+14); + curr_code->VariableLine = curr_code->Count; + } + else + { + int var; + curr_code->Codes[curr_code->Count].var_count = 1; + curr_code->Codes[curr_code->Count].variables = (int*) malloc(sizeof(int)); + if(curr_code->Codes[curr_code->Count].variables == NULL) + { + DebugMessage(M64MSG_WARNING, "couldn't allocate memory; ignoring line: '%s'", curline); + continue; + } + if (sscanf(curline+9, "%04X", &var) != 1) + var = 0; + curr_code->Codes[curr_code->Count].variables[0] = var; + curr_code->Codes[curr_code->Count].variable_names = NULL; + } + curr_code->Codes[curr_code->Count].var_to_use = 0; + curr_code->Codes[curr_code->Count].address = address; + curr_code->Count++; + continue; + } + + /* otherwise we don't know what this line is */ + DebugMessage(M64MSG_WARNING, "unrecognized line in cheat file: '%s'", curline); + } + +} + +void CheatStart(eCheatMode CheatMode, char *CheatNumList) +{ + /* if cheat codes are disabled, then we don't have to do anything */ + if (CheatMode == CHEAT_DISABLE || (CheatMode == CHEAT_LIST && strlen(CheatNumList) == 0)) + { + DebugMessage(M64MSG_STATUS, "Cheat codes disabled."); + return; + } + + /* get the ROM header for the currently loaded ROM image from the core */ + if ((*CoreDoCommand)(M64CMD_ROM_GET_HEADER, sizeof(l_RomHeader), &l_RomHeader) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_WARNING, "couldn't get ROM header information from core library"); + return; + } + + /* generate section name from ROM's CRC and country code */ + char RomSection[24]; + sprintf(RomSection, "%08X-%08X-C:%X", sl(l_RomHeader.CRC1), sl(l_RomHeader.CRC2), l_RomHeader.Country_code & 0xff); + + /* parse through the cheat INI file and load up any cheat codes found for this ROM */ + ReadCheats(RomSection); + if (!l_RomFound || l_CheatCodesFound == 0) + { + DebugMessage(M64MSG_WARNING, "no cheat codes found for ROM image '%.20s'", l_RomHeader.Name); + CheatFreeAll(); + return; + } + + /* handle the list command */ + if (CheatMode == CHEAT_SHOW_LIST) + { + DebugMessage(M64MSG_INFO, "%i cheat code(s) found for ROM '%s'", l_CheatCodesFound, l_CheatGameName); + sCheatInfo *pCur = l_CheatList; + while (pCur != NULL) + { + if (pCur->Description == NULL) + DebugMessage(M64MSG_INFO, " %i: %s", pCur->Number, pCur->Name); + else + DebugMessage(M64MSG_INFO, " %i: %s (%s)", pCur->Number, pCur->Name, pCur->Description); + if(pCur->VariableLine != -1) + { + int i; + for (i = 0; i < pCur->Codes[pCur->VariableLine].var_count; i++) + DebugMessage(M64MSG_INFO, " %i: %s", i, pCur->Codes[pCur->VariableLine].variable_names[i]); + } + pCur = pCur->Next; + } + CheatFreeAll(); + return; + } + + /* handle all cheats enabled mode */ + if (CheatMode == CHEAT_ALL) + { + sCheatInfo *pCur = l_CheatList; + while (pCur != NULL) + { + CheatActivate(pCur); + pCur = pCur->Next; + } + CheatFreeAll(); + return; + } + + /* handle list of cheats enabled mode */ + if (CheatMode == CHEAT_LIST) + { + int option, number; + char *cheat_next; + sCheatInfo *pCheat; + while(CheatNumList != NULL && *CheatNumList) + { + if ((cheat_next = strchr(CheatNumList, ',')) != NULL) + { + *cheat_next = 0; + cheat_next ++; + } + + if (strchr(CheatNumList, '-') != NULL) + { + sscanf(CheatNumList, "%i-%i", &number, &option); /* option */ + } + else + { + option=0; + sscanf(CheatNumList, "%i", &number); + } + + pCheat = CheatFindCode(number); + if (pCheat == NULL) + DebugMessage(M64MSG_WARNING, "invalid cheat code number %i", number); + else + { + if (pCheat->VariableLine != -1 && pCheat->Count > pCheat->VariableLine && option < pCheat->Codes[pCheat->VariableLine].var_count) + pCheat->Codes[pCheat->VariableLine].var_to_use = option; + CheatActivate(pCheat); + } + + CheatNumList = cheat_next; + } + CheatFreeAll(); + + return; + } + + /* otherwise the mode is invalid */ + DebugMessage(M64MSG_WARNING, "internal error; invalid CheatMode in CheatStart()"); + + return; +} +