annotate src/gb/gbCheats.cpp @ 523:d00096b6bf17

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