annotate src/gb/gbCheats.cpp @ 17:75e5bb1e0aa1

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