Mercurial > vba-clojure
view src/gb/gbCheats.cpp @ 378:5c4a30521d09
created efficient frame-metronome program
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Wed, 11 Apr 2012 11:43:51 -0500 |
parents | 5e8e5083da94 |
children |
line wrap: on
line source
1 #include <cstdio>2 #include <cstdlib>3 #include <cctype>4 #include <cstring>6 #include "../NLS.h"7 #include "../common/System.h"8 #include "../common/Util.h"10 #include "gbCheats.h"11 #include "gbGlobals.h"13 gbCheat gbCheatList[100];14 int gbCheatNumber = 0;15 bool gbCheatMap[0x10000];17 extern bool8 cheatsEnabled;19 #define GBCHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))20 #define GBCHEAT_HEX_VALUE(a) ((a) >= 'A' ? (a) - 'A' + 10 : (a) - '0')22 void gbCheatUpdateMap()23 {24 memset(gbCheatMap, 0, 0x10000);26 for (int i = 0; i < gbCheatNumber; i++)27 {28 if (gbCheatList[i].enabled)29 gbCheatMap[gbCheatList[i].address] = true;30 }31 }33 void gbCheatsSaveGame(gzFile gzFile)34 {35 utilWriteInt(gzFile, gbCheatNumber);36 if (gbCheatNumber)37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);38 }40 void gbCheatsReadGame(gzFile gzFile, int version)41 {42 if (version <= 8)43 {44 int gbGgOn = utilReadInt(gzFile);46 if (gbGgOn)47 {48 int n = utilReadInt(gzFile);49 gbXxCheat tmpCheat;50 for (int i = 0; i < n; i++)51 {52 utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));53 gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);54 }55 }57 int gbGsOn = utilReadInt(gzFile);59 if (gbGsOn)60 {61 int n = utilReadInt(gzFile);62 gbXxCheat tmpCheat;63 for (int i = 0; i < n; i++)64 {65 utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));66 gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);67 }68 }69 }70 else71 {72 gbCheatNumber = utilReadInt(gzFile);74 if (gbCheatNumber)75 {76 utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);77 }78 }80 gbCheatUpdateMap();81 }83 void gbCheatsSaveCheatList(const char *file)84 {85 if (gbCheatNumber == 0)86 return;87 FILE *f = fopen(file, "wb");88 if (f == NULL)89 return;90 int version = 1;91 fwrite(&version, 1, sizeof(version), f);92 int type = 1;93 fwrite(&type, 1, sizeof(type), f);94 fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);95 fwrite(gbCheatList, 1, sizeof(gbCheatList), f);96 fclose(f);97 }99 bool gbCheatsLoadCheatList(const char *file)100 {101 gbCheatNumber = 0;103 gbCheatUpdateMap();105 int count = 0;107 FILE *f = fopen(file, "rb");109 if (f == NULL)110 return false;112 int version = 0;114 if (fread(&version, 1, sizeof(version), f) != sizeof(version))115 {116 fclose(f);117 return false;118 }120 if (version != 1)121 {122 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,123 N_("Unsupported cheat list version %d"), version);124 fclose(f);125 return false;126 }128 int type = 0;129 if (fread(&type, 1, sizeof(type), f) != sizeof(type))130 {131 fclose(f);132 return false;133 }135 if (type != 1)136 {137 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,138 N_("Unsupported cheat list type %d"), type);139 fclose(f);140 return false;141 }143 if (fread(&count, 1, sizeof(count), f) != sizeof(count))144 {145 fclose(f);146 return false;147 }149 if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))150 {151 fclose(f);152 return false;153 }155 fclose(f);156 gbCheatNumber = count;157 gbCheatUpdateMap();159 return true;160 }162 bool gbVerifyGsCode(const char *code)163 {164 int len = strlen(code);166 if (len == 0)167 return true;169 if (len != 8)170 return false;172 for (int i = 0; i < 8; i++)173 if (!GBCHEAT_IS_HEX(code[i]))174 return false;176 int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |177 GBCHEAT_HEX_VALUE(code[7]) << 8 |178 GBCHEAT_HEX_VALUE(code[4]) << 4 |179 GBCHEAT_HEX_VALUE(code[5]);181 if (address < 0xa000 ||182 address > 0xdfff)183 return false;185 return true;186 }188 void gbAddGsCheat(const char *code, const char *desc)189 {190 if (gbCheatNumber > 99)191 {192 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,193 N_("Maximum number of cheats reached."));194 return;195 }197 if (!gbVerifyGsCode(code))198 {199 systemMessage(MSG_INVALID_GAMESHARK_CODE,200 N_("Invalid GameShark code: %s"), code);201 return;202 }204 int i = gbCheatNumber;206 strcpy(gbCheatList[i].cheatCode, code);207 strcpy(gbCheatList[i].cheatDesc, desc);209 gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |210 GBCHEAT_HEX_VALUE(code[1]);212 gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |213 GBCHEAT_HEX_VALUE(code[3]);215 gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |216 GBCHEAT_HEX_VALUE(code[7]) << 8 |217 GBCHEAT_HEX_VALUE(code[4]) << 4 |218 GBCHEAT_HEX_VALUE(code[5]);220 gbCheatList[i].compare = 0;222 gbCheatList[i].enabled = true;224 gbCheatMap[gbCheatList[i].address] = true;226 gbCheatNumber++;227 }229 bool gbVerifyGgCode(const char *code)230 {231 int len = strlen(code);233 if (len != 11 &&234 len != 7 &&235 len != 6 &&236 len != 0)237 return false;239 if (len == 0)240 return true;242 if (!GBCHEAT_IS_HEX(code[0]))243 return false;244 if (!GBCHEAT_IS_HEX(code[1]))245 return false;246 if (!GBCHEAT_IS_HEX(code[2]))247 return false;248 if (code[3] != '-')249 return false;250 if (!GBCHEAT_IS_HEX(code[4]))251 return false;252 if (!GBCHEAT_IS_HEX(code[5]))253 return false;254 if (!GBCHEAT_IS_HEX(code[6]))255 return false;256 if (code[7] != 0)257 {258 if (code[7] != '-')259 return false;260 if (code[8] != 0)261 {262 if (!GBCHEAT_IS_HEX(code[8]))263 return false;264 if (!GBCHEAT_IS_HEX(code[9]))265 return false;266 if (!GBCHEAT_IS_HEX(code[10]))267 return false;268 }269 }271 // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +272 // GBCHEAT_HEX_VALUE(code[1]);274 int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +275 (GBCHEAT_HEX_VALUE(code[4]) << 4) +276 (GBCHEAT_HEX_VALUE(code[5])) +277 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);279 if (address >= 0x8000 && address <= 0x9fff)280 return false;282 if (address >= 0xc000)283 return false;285 if (code[7] == 0 || code[8] == '0')286 return true;288 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +289 (GBCHEAT_HEX_VALUE(code[10]));290 compare = compare ^ 0xff;291 compare = (compare >> 2) | ((compare << 6) & 0xc0);292 compare ^= 0x45;294 int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));296 if (cloak >= 1 && cloak <= 7)297 return false;299 return true;300 }302 void gbAddGgCheat(const char *code, const char *desc)303 {304 if (gbCheatNumber > 99)305 {306 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,307 N_("Maximum number of cheats reached."));308 return;309 }311 if (!gbVerifyGgCode(code))312 {313 systemMessage(MSG_INVALID_GAMEGENIE_CODE,314 N_("Invalid GameGenie code: %s"), code);315 return;316 }318 int i = gbCheatNumber;320 int len = strlen(code);322 strcpy(gbCheatList[i].cheatCode, code);323 strcpy(gbCheatList[i].cheatDesc, desc);325 gbCheatList[i].code = 1;326 gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +327 GBCHEAT_HEX_VALUE(code[1]);329 gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +330 (GBCHEAT_HEX_VALUE(code[4]) << 4) +331 (GBCHEAT_HEX_VALUE(code[5])) +332 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);334 gbCheatList[i].compare = 0;336 if (len != 7 && len != 8)337 {338 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +339 (GBCHEAT_HEX_VALUE(code[10]));340 compare = compare ^ 0xff;341 compare = (compare >> 2) | ((compare << 6) & 0xc0);342 compare ^= 0x45;344 gbCheatList[i].compare = compare;345 gbCheatList[i].code = 0;346 }348 gbCheatList[i].enabled = true;350 gbCheatMap[gbCheatList[i].address] = true;352 gbCheatNumber++;353 }355 void gbCheatRemove(int i)356 {357 if (i < 0 || i >= gbCheatNumber)358 {359 systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,360 N_("Invalid cheat to remove %d"), i);361 return;362 }364 if ((i+1) < gbCheatNumber)365 {366 memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*367 (gbCheatNumber-i-1));368 }370 gbCheatNumber--;372 gbCheatUpdateMap();373 }375 void gbCheatRemoveAll()376 {377 gbCheatNumber = 0;378 gbCheatUpdateMap();379 }381 void gbCheatEnable(int i)382 {383 if (i >= 0 && i < gbCheatNumber)384 {385 if (!gbCheatList[i].enabled)386 {387 gbCheatList[i].enabled = true;388 gbCheatUpdateMap();389 }390 }391 }393 void gbCheatDisable(int i)394 {395 if (i >= 0 && i < gbCheatNumber)396 {397 if (gbCheatList[i].enabled)398 {399 gbCheatList[i].enabled = false;400 gbCheatUpdateMap();401 }402 }403 }405 bool gbCheatReadGSCodeFile(const char *fileName)406 {407 FILE *file = fopen(fileName, "rb");409 if (!file)410 return false;412 fseek(file, 0x18, SEEK_SET);413 int count = 0;414 fread(&count, 1, 2, file);415 int dummy = 0;416 gbCheatRemoveAll();417 char desc[13];418 char code[9];419 int i;420 for (i = 0; i < count; i++)421 {422 fread(&dummy, 1, 2, file);423 fread(desc, 1, 12, file);424 desc[12] = 0;425 fread(code, 1, 8, file);426 code[8] = 0;427 gbAddGsCheat(code, desc);428 }430 for (i = 0; i < gbCheatNumber; i++)431 gbCheatDisable(i);433 fclose(file);434 return true;435 }437 u8 gbCheatRead(u16 address)438 {439 if (!cheatsEnabled)440 return gbReadMemoryQuick(address);442 for (int i = 0; i < gbCheatNumber; i++)443 {444 if (gbCheatList[i].enabled && gbCheatList[i].address == address)445 {446 switch (gbCheatList[i].code)447 {448 case 0x100: // GameGenie support449 if (gbReadMemoryQuick(address) == gbCheatList[i].compare)450 return gbCheatList[i].value;451 break;452 case 0x00:453 case 0x01:454 case 0x80:455 return gbCheatList[i].value;456 case 0x90:457 case 0x91:458 case 0x92:459 case 0x93:460 case 0x94:461 case 0x95:462 case 0x96:463 case 0x97:464 if (address >= 0xd000 && address < 0xe000)465 {466 if (((gbMemoryMap[0x0d] - gbWram)/0x1000) ==467 (gbCheatList[i].code - 0x90))468 return gbCheatList[i].value;469 }470 else471 return gbCheatList[i].value;472 }473 }474 }475 return gbReadMemoryQuick(address);476 }