diff src/gba/GBACheats.cpp @ 19:5e8e5083da94

brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author Robert McIntyre <rlm@mit.edu>
date Sun, 04 Mar 2012 14:33:52 -0600
parents f9f4f1b99eed
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gba/GBACheats.cpp	Sun Mar 04 14:33:52 2012 -0600
     1.3 @@ -0,0 +1,1822 @@
     1.4 +#include <cstdio>
     1.5 +#include <cctype>
     1.6 +#include <cstring>
     1.7 +
     1.8 +#include "../common/System.h"
     1.9 +#include "../common/Util.h"
    1.10 +#include "../NLS.h"
    1.11 +#include "GBACheats.h"
    1.12 +#include "GBA.h"
    1.13 +#include "GBAinline.h"
    1.14 +#include "GBAGlobals.h"
    1.15 +
    1.16 +/**
    1.17 + * Gameshark code types:
    1.18 + *
    1.19 + * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM
    1.20 + * DEADFACE XXXXXXXX - changes decryption seeds
    1.21 + * 0AAAAAAA 000000YY - 8-bit constant write
    1.22 + * 1AAAAAAA 0000YYYY - 16-bit constant write
    1.23 + * 2AAAAAAA YYYYYYYY - 32-bit constant write
    1.24 + * 3AAAAAAA YYYYYYYY - ??
    1.25 + * 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1)
    1.26 + * 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1)
    1.27 + * 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1)
    1.28 + * 8A1AAAAA 000000YY - 8-bit button write
    1.29 + * 8A2AAAAA 0000YYYY - 16-bit button write
    1.30 + * 8A3AAAAA YYYYYYYY - 32-bit button write
    1.31 + * 80F00000 0000YYYY - button slow motion
    1.32 + * DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code
    1.33 + * FAAAAAAA 0000YYYY - Master code function
    1.34 + *
    1.35 + * CodeBreaker codes types:
    1.36 + *
    1.37 + * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI)
    1.38 + * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16)
    1.39 + *                 + 0x08000100))
    1.40 + * 2AAAAAAA YYYY - 16-bit or
    1.41 + * 3AAAAAAA YYYY - 8-bit constant write
    1.42 + * 4AAAAAAA YYYY - Slide code
    1.43 + * XXXXCCCC IIII   (C is count and I is address increment, X is value incr.)
    1.44 + * 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count)
    1.45 + * BBBBBBBB BBBB
    1.46 + * 6AAAAAAA YYYY - 16-bit and
    1.47 + * 7AAAAAAA YYYY - if address contains 16-bit value enable next code
    1.48 + * 8AAAAAAA YYYY - 16-bit constant write
    1.49 + * 9AAAAAAA YYYY - change decryption (when first code only?)
    1.50 + * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code
    1.51 + * BAAAAAAA YYYY - if 16-bit < YYYY
    1.52 + * CAAAAAAA YYYY - if 16-bit > YYYY
    1.53 + * D0000020 YYYY - if button keys equal value enable next code
    1.54 + * EAAAAAAA YYYY - increase value stored in address
    1.55 + */
    1.56 +#define UNKNOWN_CODE           -1
    1.57 +#define INT_8_BIT_WRITE        0
    1.58 +#define INT_16_BIT_WRITE       1
    1.59 +#define INT_32_BIT_WRITE       2
    1.60 +#define GSA_16_BIT_ROM_PATCH   3
    1.61 +#define GSA_8_BIT_GS_WRITE     4
    1.62 +#define GSA_16_BIT_GS_WRITE    5
    1.63 +#define GSA_32_BIT_GS_WRITE    6
    1.64 +#define CBA_IF_KEYS_PRESSED    7
    1.65 +#define CBA_IF_TRUE            8
    1.66 +#define CBA_SLIDE_CODE         9
    1.67 +#define CBA_IF_FALSE           10
    1.68 +#define CBA_AND                11
    1.69 +#define GSA_8_BIT_GS_WRITE2    12
    1.70 +#define GSA_16_BIT_GS_WRITE2   13
    1.71 +#define GSA_32_BIT_GS_WRITE2   14
    1.72 +#define GSA_16_BIT_ROM_PATCH2  15
    1.73 +#define GSA_8_BIT_SLIDE        16
    1.74 +#define GSA_16_BIT_SLIDE       17
    1.75 +#define GSA_32_BIT_SLIDE       18
    1.76 +#define GSA_8_BIT_IF_TRUE      19
    1.77 +#define GSA_32_BIT_IF_TRUE     20
    1.78 +#define GSA_8_BIT_IF_FALSE     21
    1.79 +#define GSA_32_BIT_IF_FALSE    22
    1.80 +#define GSA_8_BIT_FILL         23
    1.81 +#define GSA_16_BIT_FILL        24
    1.82 +#define GSA_8_BIT_IF_TRUE2     25
    1.83 +#define GSA_16_BIT_IF_TRUE2    26
    1.84 +#define GSA_32_BIT_IF_TRUE2    27
    1.85 +#define GSA_8_BIT_IF_FALSE2    28
    1.86 +#define GSA_16_BIT_IF_FALSE2   29
    1.87 +#define GSA_32_BIT_IF_FALSE2   30
    1.88 +#define GSA_SLOWDOWN           31
    1.89 +#define CBA_ADD                32
    1.90 +#define CBA_OR                 33
    1.91 +#define CBA_LT                 34
    1.92 +#define CBA_GT                 35
    1.93 +#define CBA_SUPER              36
    1.94 +
    1.95 +CheatsData cheatsList[100];
    1.96 +int        cheatsNumber = 0;
    1.97 +
    1.98 +u8   cheatsCBASeedBuffer[0x30];
    1.99 +u32  cheatsCBASeed[4];
   1.100 +u32  cheatsCBATemporaryValue = 0;
   1.101 +u16  cheatsCBATable[256];
   1.102 +bool cheatsCBATableGenerated = false;
   1.103 +
   1.104 +u8 cheatsCBACurrentSeed[12] = {
   1.105 +	0x00, 0x00, 0x00, 0x00,
   1.106 +	0x00, 0x00, 0x00, 0x00,
   1.107 +	0x00, 0x00, 0x00, 0x00
   1.108 +};
   1.109 +
   1.110 +#define CHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))
   1.111 +
   1.112 +#define CHEAT_PATCH_ROM_16BIT(a, v) \
   1.113 +    WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v);
   1.114 +
   1.115 +static bool isMultilineWithData(int i)
   1.116 +{
   1.117 +	// we consider it a multiline code if it has more than one line of data
   1.118 +	// otherwise, it can still be considered a single code
   1.119 +	if (i < cheatsNumber && i >= 0)
   1.120 +		switch (cheatsList[i].size)
   1.121 +		{
   1.122 +		case INT_8_BIT_WRITE:
   1.123 +		case INT_16_BIT_WRITE:
   1.124 +		case INT_32_BIT_WRITE:
   1.125 +		case GSA_16_BIT_ROM_PATCH:
   1.126 +		case GSA_8_BIT_GS_WRITE:
   1.127 +		case GSA_16_BIT_GS_WRITE:
   1.128 +		case GSA_32_BIT_GS_WRITE:
   1.129 +		case CBA_AND:
   1.130 +		case CBA_IF_KEYS_PRESSED:
   1.131 +		case CBA_IF_TRUE:
   1.132 +		case CBA_IF_FALSE:
   1.133 +		case GSA_8_BIT_IF_TRUE:
   1.134 +		case GSA_32_BIT_IF_TRUE:
   1.135 +		case GSA_8_BIT_IF_FALSE:
   1.136 +		case GSA_32_BIT_IF_FALSE:
   1.137 +		case GSA_8_BIT_FILL:
   1.138 +		case GSA_16_BIT_FILL:
   1.139 +		case GSA_8_BIT_IF_TRUE2:
   1.140 +		case GSA_16_BIT_IF_TRUE2:
   1.141 +		case GSA_32_BIT_IF_TRUE2:
   1.142 +		case GSA_8_BIT_IF_FALSE2:
   1.143 +		case GSA_16_BIT_IF_FALSE2:
   1.144 +		case GSA_32_BIT_IF_FALSE2:
   1.145 +		case GSA_SLOWDOWN:
   1.146 +		case CBA_ADD:
   1.147 +		case CBA_OR:
   1.148 +			return false;
   1.149 +		// the codes below have two lines of data
   1.150 +		case CBA_SLIDE_CODE:
   1.151 +		case GSA_8_BIT_GS_WRITE2:
   1.152 +		case GSA_16_BIT_GS_WRITE2:
   1.153 +		case GSA_32_BIT_GS_WRITE2:
   1.154 +		case GSA_16_BIT_ROM_PATCH2:
   1.155 +		case GSA_8_BIT_SLIDE:
   1.156 +		case GSA_16_BIT_SLIDE:
   1.157 +		case GSA_32_BIT_SLIDE:
   1.158 +		case CBA_LT:
   1.159 +		case CBA_GT:
   1.160 +		case CBA_SUPER:
   1.161 +			return true;
   1.162 +		}
   1.163 +	return false;
   1.164 +}
   1.165 +
   1.166 +static int getCodeLength(int num)
   1.167 +{
   1.168 +	if (num >= cheatsNumber || num < 0)
   1.169 +		return 1;
   1.170 +
   1.171 +	// this is for all the codes that are true multiline
   1.172 +	switch (cheatsList[num].size)
   1.173 +	{
   1.174 +	case INT_8_BIT_WRITE:
   1.175 +	case INT_16_BIT_WRITE:
   1.176 +	case INT_32_BIT_WRITE:
   1.177 +	case GSA_16_BIT_ROM_PATCH:
   1.178 +	case GSA_8_BIT_GS_WRITE:
   1.179 +	case GSA_16_BIT_GS_WRITE:
   1.180 +	case GSA_32_BIT_GS_WRITE:
   1.181 +	case CBA_AND:
   1.182 +	case GSA_8_BIT_FILL:
   1.183 +	case GSA_16_BIT_FILL:
   1.184 +	case GSA_SLOWDOWN:
   1.185 +	case CBA_ADD:
   1.186 +	case CBA_OR:
   1.187 +		return 1;
   1.188 +	case CBA_IF_KEYS_PRESSED:
   1.189 +	case CBA_IF_TRUE:
   1.190 +	case CBA_IF_FALSE:
   1.191 +	case CBA_SLIDE_CODE:
   1.192 +	case GSA_8_BIT_GS_WRITE2:
   1.193 +	case GSA_16_BIT_GS_WRITE2:
   1.194 +	case GSA_32_BIT_GS_WRITE2:
   1.195 +	case GSA_16_BIT_ROM_PATCH2:
   1.196 +	case GSA_8_BIT_SLIDE:
   1.197 +	case GSA_16_BIT_SLIDE:
   1.198 +	case GSA_32_BIT_SLIDE:
   1.199 +	case GSA_8_BIT_IF_TRUE:
   1.200 +	case GSA_32_BIT_IF_TRUE:
   1.201 +	case GSA_8_BIT_IF_FALSE:
   1.202 +	case GSA_32_BIT_IF_FALSE:
   1.203 +	case CBA_LT:
   1.204 +	case CBA_GT:
   1.205 +		return 2;
   1.206 +	case GSA_8_BIT_IF_TRUE2:
   1.207 +	case GSA_16_BIT_IF_TRUE2:
   1.208 +	case GSA_32_BIT_IF_TRUE2:
   1.209 +	case GSA_8_BIT_IF_FALSE2:
   1.210 +	case GSA_16_BIT_IF_FALSE2:
   1.211 +	case GSA_32_BIT_IF_FALSE2:
   1.212 +		return 3;
   1.213 +	case CBA_SUPER:
   1.214 +		return (cheatsList[num].value+5)/6;
   1.215 +	}
   1.216 +	return 1;
   1.217 +}
   1.218 +
   1.219 +int cheatsCheckKeys(u32 keys, u32 extended)
   1.220 +{
   1.221 +	int ticks = 0;
   1.222 +	for (int i = 0; i < cheatsNumber; i++)
   1.223 +	{
   1.224 +		if (!cheatsList[i].enabled)
   1.225 +		{
   1.226 +			// make sure we skip other lines in this code
   1.227 +			i += getCodeLength(i)-1;
   1.228 +			continue;
   1.229 +		}
   1.230 +		switch (cheatsList[i].size)
   1.231 +		{
   1.232 +		case INT_8_BIT_WRITE:
   1.233 +			CPUWriteByte(cheatsList[i].address, cheatsList[i].value);
   1.234 +			break;
   1.235 +		case INT_16_BIT_WRITE:
   1.236 +			CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);
   1.237 +			break;
   1.238 +		case INT_32_BIT_WRITE:
   1.239 +			CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);
   1.240 +			break;
   1.241 +		case GSA_16_BIT_ROM_PATCH:
   1.242 +			if ((cheatsList[i].status & 1) == 0)
   1.243 +			{
   1.244 +				if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
   1.245 +				{
   1.246 +					cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address);
   1.247 +					cheatsList[i].status  |= 1;
   1.248 +					CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);
   1.249 +				}
   1.250 +			}
   1.251 +			break;
   1.252 +		case GSA_8_BIT_GS_WRITE:
   1.253 +			if (extended & 4)
   1.254 +			{
   1.255 +				CPUWriteByte(cheatsList[i].address, cheatsList[i].value);
   1.256 +			}
   1.257 +			break;
   1.258 +		case GSA_16_BIT_GS_WRITE:
   1.259 +			if (extended & 4)
   1.260 +			{
   1.261 +				CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);
   1.262 +			}
   1.263 +			break;
   1.264 +		case GSA_32_BIT_GS_WRITE:
   1.265 +			if (extended & 4)
   1.266 +			{
   1.267 +				CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);
   1.268 +			}
   1.269 +			break;
   1.270 +		case CBA_IF_KEYS_PRESSED:
   1.271 +		{
   1.272 +			u16 value = cheatsList[i].value;
   1.273 +			u32 addr  = cheatsList[i].address;
   1.274 +			if ((addr & 0x30) == 0x20)
   1.275 +			{
   1.276 +				if ((keys & value) != value)
   1.277 +				{
   1.278 +					i++;
   1.279 +				}
   1.280 +			}
   1.281 +			else if ((addr & 0x30) == 0x10)
   1.282 +			{
   1.283 +				if ((keys & value) == value)
   1.284 +				{
   1.285 +					i++;
   1.286 +				}
   1.287 +			}
   1.288 +			break;
   1.289 +		}
   1.290 +		case CBA_IF_TRUE:
   1.291 +			if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
   1.292 +			{
   1.293 +				i++;
   1.294 +			}
   1.295 +			break;
   1.296 +		case CBA_SLIDE_CODE:
   1.297 +		{
   1.298 +			u32 address = cheatsList[i].address;
   1.299 +			u16 value   = cheatsList[i].value;
   1.300 +			i++;
   1.301 +			if (i < cheatsNumber)
   1.302 +			{
   1.303 +				int count = (cheatsList[i].address & 0xFFFF);
   1.304 +				u16 vinc  = (cheatsList[i].address >> 16) & 0xFFFF;
   1.305 +				int inc   = cheatsList[i].value;
   1.306 +
   1.307 +				for (int x = 0; x < count; x++)
   1.308 +				{
   1.309 +					CPUWriteHalfWord(address, value);
   1.310 +					address += inc;
   1.311 +					value   += vinc;
   1.312 +				}
   1.313 +			}
   1.314 +			break;
   1.315 +		}
   1.316 +		case CBA_IF_FALSE:
   1.317 +			if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)
   1.318 +			{
   1.319 +				i++;
   1.320 +			}
   1.321 +			break;
   1.322 +		case CBA_AND:
   1.323 +			CPUWriteHalfWord(cheatsList[i].address,
   1.324 +			                 CPUReadHalfWord(cheatsList[i].address) &
   1.325 +			                 cheatsList[i].value);
   1.326 +			break;
   1.327 +		case GSA_8_BIT_GS_WRITE2:
   1.328 +			i++;
   1.329 +			if (i < cheatsNumber)
   1.330 +			{
   1.331 +				if (extended & 4)
   1.332 +				{
   1.333 +					CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address);
   1.334 +				}
   1.335 +			}
   1.336 +			break;
   1.337 +		case GSA_16_BIT_GS_WRITE2:
   1.338 +			i++;
   1.339 +			if (i < cheatsNumber)
   1.340 +			{
   1.341 +				if (extended & 4)
   1.342 +				{
   1.343 +					CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address);
   1.344 +				}
   1.345 +			}
   1.346 +			break;
   1.347 +		case GSA_32_BIT_GS_WRITE2:
   1.348 +			i++;
   1.349 +			if (i < cheatsNumber)
   1.350 +			{
   1.351 +				if (extended & 4)
   1.352 +				{
   1.353 +					CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address);
   1.354 +				}
   1.355 +			}
   1.356 +			break;
   1.357 +		case GSA_16_BIT_ROM_PATCH2:
   1.358 +			i++;
   1.359 +			if (i < cheatsNumber)
   1.360 +			{
   1.361 +				if ((cheatsList[i-1].status & 1) == 0)
   1.362 +				{
   1.363 +					u32 addr = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000;
   1.364 +					if (CPUReadHalfWord(addr) != (cheatsList[i].address & 0xFFFF))
   1.365 +					{
   1.366 +						cheatsList[i-1].oldValue = CPUReadHalfWord(addr);
   1.367 +						cheatsList[i-1].status  |= 1;
   1.368 +						CHEAT_PATCH_ROM_16BIT(addr, cheatsList[i].address & 0xFFFF);
   1.369 +					}
   1.370 +				}
   1.371 +			}
   1.372 +			break;
   1.373 +		case GSA_8_BIT_SLIDE:
   1.374 +			i++;
   1.375 +			if (i < cheatsNumber)
   1.376 +			{
   1.377 +				u32 addr  = cheatsList[i-1].value;
   1.378 +				u8  value = cheatsList[i].address;
   1.379 +				int vinc  = (cheatsList[i].value >> 24) & 255;
   1.380 +				int count = (cheatsList[i].value >> 16) & 255;
   1.381 +				int ainc  = (cheatsList[i].value & 0xffff);
   1.382 +				while (count > 0)
   1.383 +				{
   1.384 +					CPUWriteByte(addr, value);
   1.385 +					value += vinc;
   1.386 +					addr  += ainc;
   1.387 +					count--;
   1.388 +				}
   1.389 +			}
   1.390 +			break;
   1.391 +		case GSA_16_BIT_SLIDE:
   1.392 +			i++;
   1.393 +			if (i < cheatsNumber)
   1.394 +			{
   1.395 +				u32 addr  = cheatsList[i-1].value;
   1.396 +				u16 value = cheatsList[i].address;
   1.397 +				int vinc  = (cheatsList[i].value >> 24) & 255;
   1.398 +				int count = (cheatsList[i].value >> 16) & 255;
   1.399 +				int ainc  = (cheatsList[i].value & 0xffff)*2;
   1.400 +				while (count > 0)
   1.401 +				{
   1.402 +					CPUWriteHalfWord(addr, value);
   1.403 +					value += vinc;
   1.404 +					addr  += ainc;
   1.405 +					count--;
   1.406 +				}
   1.407 +			}
   1.408 +			break;
   1.409 +		case GSA_32_BIT_SLIDE:
   1.410 +			i++;
   1.411 +			if (i < cheatsNumber)
   1.412 +			{
   1.413 +				u32 addr  = cheatsList[i-1].value;
   1.414 +				u32 value = cheatsList[i].address;
   1.415 +				int vinc  = (cheatsList[i].value >> 24) & 255;
   1.416 +				int count = (cheatsList[i].value >> 16) & 255;
   1.417 +				int ainc  = (cheatsList[i].value & 0xffff)*4;
   1.418 +				while (count > 0)
   1.419 +				{
   1.420 +					CPUWriteMemory(addr, value);
   1.421 +					value += vinc;
   1.422 +					addr  += ainc;
   1.423 +					count--;
   1.424 +				}
   1.425 +			}
   1.426 +			break;
   1.427 +		case GSA_8_BIT_IF_TRUE:
   1.428 +			if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)
   1.429 +			{
   1.430 +				i++;
   1.431 +			}
   1.432 +			break;
   1.433 +		case GSA_32_BIT_IF_TRUE:
   1.434 +			if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)
   1.435 +			{
   1.436 +				i++;
   1.437 +			}
   1.438 +			break;
   1.439 +		case GSA_8_BIT_IF_FALSE:
   1.440 +			if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)
   1.441 +			{
   1.442 +				i++;
   1.443 +			}
   1.444 +			break;
   1.445 +		case GSA_32_BIT_IF_FALSE:
   1.446 +			if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)
   1.447 +			{
   1.448 +				i++;
   1.449 +			}
   1.450 +			break;
   1.451 +		case GSA_8_BIT_FILL:
   1.452 +		{
   1.453 +			u32 addr = cheatsList[i].address;
   1.454 +			u8  v    = cheatsList[i].value & 0xff;
   1.455 +			u32 end  = addr + (cheatsList[i].value >> 8);
   1.456 +			do
   1.457 +			{
   1.458 +				CPUWriteByte(addr, v);
   1.459 +				addr++;
   1.460 +			}
   1.461 +			while (addr <= end);
   1.462 +			break;
   1.463 +		}
   1.464 +		case GSA_16_BIT_FILL:
   1.465 +		{
   1.466 +			u32 addr = cheatsList[i].address;
   1.467 +			u16 v    = cheatsList[i].value & 0xffff;
   1.468 +			u32 end  = addr + ((cheatsList[i].value >> 16) << 1);
   1.469 +			do
   1.470 +			{
   1.471 +				CPUWriteHalfWord(addr, v);
   1.472 +				addr += 2;
   1.473 +			}
   1.474 +			while (addr <= end);
   1.475 +			break;
   1.476 +		}
   1.477 +		case GSA_8_BIT_IF_TRUE2:
   1.478 +			if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)
   1.479 +			{
   1.480 +				i += 2;
   1.481 +			}
   1.482 +			break;
   1.483 +		case GSA_16_BIT_IF_TRUE2:
   1.484 +			if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
   1.485 +			{
   1.486 +				i += 2;
   1.487 +			}
   1.488 +			break;
   1.489 +		case GSA_32_BIT_IF_TRUE2:
   1.490 +			if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)
   1.491 +			{
   1.492 +				i += 2;
   1.493 +			}
   1.494 +			break;
   1.495 +		case GSA_8_BIT_IF_FALSE2:
   1.496 +			if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)
   1.497 +			{
   1.498 +				i += 2;
   1.499 +			}
   1.500 +			break;
   1.501 +		case GSA_16_BIT_IF_FALSE2:
   1.502 +			if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)
   1.503 +			{
   1.504 +				i += 2;
   1.505 +			}
   1.506 +			break;
   1.507 +		case GSA_32_BIT_IF_FALSE2:
   1.508 +			if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)
   1.509 +			{
   1.510 +				i += 2;
   1.511 +			}
   1.512 +			break;
   1.513 +		case GSA_SLOWDOWN:
   1.514 +			// check if button was pressed and released, if so toggle our state
   1.515 +			if ((cheatsList[i].status & 4) && !(extended & 4))
   1.516 +				cheatsList[i].status ^= 1;
   1.517 +			if (extended & 4)
   1.518 +				cheatsList[i].status |= 4;
   1.519 +			else
   1.520 +				cheatsList[i].status &= ~4;
   1.521 +
   1.522 +			if (cheatsList[i].status & 1)
   1.523 +				ticks += 2*256*((cheatsList[i].value >> 8) & 255);
   1.524 +			break;
   1.525 +		case CBA_ADD:
   1.526 +			CPUWriteHalfWord(cheatsList[i].address,
   1.527 +			                 CPUReadHalfWord(cheatsList[i].address) +
   1.528 +			                 (u16)cheatsList[i].value);
   1.529 +			break;
   1.530 +		case CBA_OR:
   1.531 +			CPUWriteHalfWord(cheatsList[i].address,
   1.532 +			                 CPUReadHalfWord(cheatsList[i].address) |
   1.533 +			                 cheatsList[i].value);
   1.534 +			break;
   1.535 +		case CBA_LT:
   1.536 +			if (CPUReadHalfWord(cheatsList[i].address) >= cheatsList[i].value)
   1.537 +				i++;
   1.538 +			break;
   1.539 +		case CBA_GT:
   1.540 +			if (CPUReadHalfWord(cheatsList[i].address) <= cheatsList[i].value)
   1.541 +				i++;
   1.542 +			break;
   1.543 +		case CBA_SUPER:
   1.544 +		{
   1.545 +			int count   = 2*cheatsList[i].value;
   1.546 +			u32 address = cheatsList[i].address;
   1.547 +			for (int x = 0; x < count; x++)
   1.548 +			{
   1.549 +				u8  b;
   1.550 +				int res = x % 6;
   1.551 +				if (res < 4)
   1.552 +					b = (cheatsList[i].address >> (24-8*res)) & 0xFF;
   1.553 +				else
   1.554 +					b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0x0FF;
   1.555 +				CPUWriteByte(address, b);
   1.556 +				address++;
   1.557 +				if (x && !res)
   1.558 +					i++;
   1.559 +			}
   1.560 +			if (count % 6)
   1.561 +				i++;
   1.562 +			break;
   1.563 +		}
   1.564 +		}
   1.565 +	}
   1.566 +	return ticks;
   1.567 +}
   1.568 +
   1.569 +void cheatsAdd(const char *codeStr,
   1.570 +               const char *desc,
   1.571 +               u32 address,
   1.572 +               u32 value,
   1.573 +               int code,
   1.574 +               int size)
   1.575 +{
   1.576 +	if (cheatsNumber < 100)
   1.577 +	{
   1.578 +		int x = cheatsNumber;
   1.579 +		cheatsList[x].code    = code;
   1.580 +		cheatsList[x].size    = size;
   1.581 +		cheatsList[x].address = address;
   1.582 +		cheatsList[x].value   = value;
   1.583 +		strcpy(cheatsList[x].codestring, codeStr);
   1.584 +		strcpy(cheatsList[x].desc, desc);
   1.585 +		cheatsList[x].enabled = true;
   1.586 +		cheatsList[x].status  = 0;
   1.587 +
   1.588 +		// we only store the old value for this simple codes. ROM patching
   1.589 +		// is taken care when it actually patches the ROM
   1.590 +		switch (cheatsList[x].size)
   1.591 +		{
   1.592 +		case INT_8_BIT_WRITE:
   1.593 +			cheatsList[x].oldValue = CPUReadByte(address);
   1.594 +			break;
   1.595 +		case INT_16_BIT_WRITE:
   1.596 +			cheatsList[x].oldValue = CPUReadHalfWord(address);
   1.597 +			break;
   1.598 +		case INT_32_BIT_WRITE:
   1.599 +			cheatsList[x].oldValue = CPUReadMemory(address);
   1.600 +			break;
   1.601 +		}
   1.602 +		cheatsNumber++;
   1.603 +	}
   1.604 +}
   1.605 +
   1.606 +void cheatsDelete(int number, bool restore)
   1.607 +{
   1.608 +	if (number < cheatsNumber && number >= 0)
   1.609 +	{
   1.610 +		int x = number;
   1.611 +
   1.612 +		if (restore)
   1.613 +		{
   1.614 +			switch (cheatsList[x].size)
   1.615 +			{
   1.616 +			case INT_8_BIT_WRITE:
   1.617 +				CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue);
   1.618 +				break;
   1.619 +			case INT_16_BIT_WRITE:
   1.620 +				CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue);
   1.621 +				break;
   1.622 +			case INT_32_BIT_WRITE:
   1.623 +				CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
   1.624 +				break;
   1.625 +			case GSA_16_BIT_ROM_PATCH:
   1.626 +				if (cheatsList[x].status & 1)
   1.627 +				{
   1.628 +					cheatsList[x].status &= ~1;
   1.629 +					CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,
   1.630 +					                      cheatsList[x].oldValue);
   1.631 +				}
   1.632 +				break;
   1.633 +			case GSA_16_BIT_ROM_PATCH2:
   1.634 +				if (cheatsList[x].status & 1)
   1.635 +				{
   1.636 +					cheatsList[x].status &= ~1;
   1.637 +					CHEAT_PATCH_ROM_16BIT(((cheatsList[x].value & 0x00FFFFFF) << 1)+
   1.638 +					                      0x8000000,
   1.639 +					                      cheatsList[x].oldValue);
   1.640 +				}
   1.641 +				break;
   1.642 +			}
   1.643 +		}
   1.644 +		if ((x+1) <  cheatsNumber)
   1.645 +		{
   1.646 +			memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)*
   1.647 +			       (cheatsNumber-x-1));
   1.648 +		}
   1.649 +		cheatsNumber--;
   1.650 +	}
   1.651 +}
   1.652 +
   1.653 +void cheatsDeleteAll(bool restore)
   1.654 +{
   1.655 +	for (int i = cheatsNumber-1; i >= 0; i--)
   1.656 +	{
   1.657 +		cheatsDelete(i, restore);
   1.658 +	}
   1.659 +}
   1.660 +
   1.661 +void cheatsEnable(int i)
   1.662 +{
   1.663 +	if (i >= 0 && i < cheatsNumber)
   1.664 +	{
   1.665 +		cheatsList[i].enabled = true;
   1.666 +	}
   1.667 +}
   1.668 +
   1.669 +void cheatsDisable(int i)
   1.670 +{
   1.671 +	if (i >= 0 && i < cheatsNumber)
   1.672 +	{
   1.673 +		switch (cheatsList[i].size)
   1.674 +		{
   1.675 +		case GSA_16_BIT_ROM_PATCH:
   1.676 +			if (cheatsList[i].status & 1)
   1.677 +			{
   1.678 +				cheatsList[i].status &= ~1;
   1.679 +				CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,
   1.680 +				                      cheatsList[i].oldValue);
   1.681 +			}
   1.682 +			break;
   1.683 +		case GSA_16_BIT_ROM_PATCH2:
   1.684 +			if (cheatsList[i].status & 1)
   1.685 +			{
   1.686 +				cheatsList[i].status &= ~1;
   1.687 +				CHEAT_PATCH_ROM_16BIT(((cheatsList[i].value & 0x00FFFFFF) << 1)+
   1.688 +				                      0x8000000,
   1.689 +				                      cheatsList[i].oldValue);
   1.690 +			}
   1.691 +			break;
   1.692 +		}
   1.693 +		cheatsList[i].enabled = false;
   1.694 +	}
   1.695 +}
   1.696 +
   1.697 +bool cheatsVerifyCheatCode(const char *code, const char *desc)
   1.698 +{
   1.699 +	int len = strlen(code);
   1.700 +	if (len != 11 && len != 13 && len != 17)
   1.701 +	{
   1.702 +		systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);
   1.703 +		return false;
   1.704 +	}
   1.705 +
   1.706 +	if (code[8] != ':')
   1.707 +	{
   1.708 +		systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);
   1.709 +		return false;
   1.710 +	}
   1.711 +
   1.712 +	int i;
   1.713 +	for (i = 0; i < 8; i++)
   1.714 +	{
   1.715 +		if (!CHEAT_IS_HEX(code[i]))
   1.716 +		{
   1.717 +			// wrong cheat
   1.718 +			systemMessage(MSG_INVALID_CHEAT_CODE,
   1.719 +			              N_("Invalid cheat code '%s'"), code);
   1.720 +			return false;
   1.721 +		}
   1.722 +	}
   1.723 +	for (i = 9; i < len; i++)
   1.724 +	{
   1.725 +		if (!CHEAT_IS_HEX(code[i]))
   1.726 +		{
   1.727 +			// wrong cheat
   1.728 +			systemMessage(MSG_INVALID_CHEAT_CODE,
   1.729 +			              N_("Invalid cheat code '%s'"), code);
   1.730 +			return false;
   1.731 +		}
   1.732 +	}
   1.733 +
   1.734 +	u32 address = 0;
   1.735 +	u32 value   = 0;
   1.736 +
   1.737 +	char buffer[10];
   1.738 +	strncpy(buffer, code, 8);
   1.739 +	buffer[8] = 0;
   1.740 +	sscanf(buffer, "%x", &address);
   1.741 +
   1.742 +	switch (address >> 24)
   1.743 +	{
   1.744 +	case 2:
   1.745 +	case 3:
   1.746 +		break;
   1.747 +	default:
   1.748 +		systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS,
   1.749 +		              N_("Invalid cheat code address: %08x"),
   1.750 +		              address);
   1.751 +		return false;
   1.752 +	}
   1.753 +
   1.754 +	strncpy(buffer, &code[9], 8);
   1.755 +	sscanf(buffer, "%x", &value);
   1.756 +	int type = 0;
   1.757 +	if (len == 13)
   1.758 +		type = 1;
   1.759 +	if (len == 17)
   1.760 +		type = 2;
   1.761 +	cheatsAdd(code, desc, address, value, type, type);
   1.762 +	return true;
   1.763 +}
   1.764 +
   1.765 +void cheatsAddCheatCode(const char *code, const char *desc)
   1.766 +{
   1.767 +	cheatsVerifyCheatCode(code, desc);
   1.768 +}
   1.769 +
   1.770 +void cheatsDecryptGSACode(u32& address, u32& value, bool v3)
   1.771 +{
   1.772 +	u32  rollingseed = 0xC6EF3720;
   1.773 +	u32  seeds_v1[]  =  { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
   1.774 +	u32  seeds_v3[]  = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
   1.775 +	u32 *seeds       = v3 ? seeds_v3 : seeds_v1;
   1.776 +
   1.777 +	int bitsleft = 32;
   1.778 +	while (bitsleft > 0)
   1.779 +	{
   1.780 +		value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^
   1.781 +		          ((address >> 5) + seeds[3]));
   1.782 +		address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^
   1.783 +		            ((value >> 5) + seeds[1]));
   1.784 +		rollingseed -= 0x9E3779B9;
   1.785 +		bitsleft--;
   1.786 +	}
   1.787 +}
   1.788 +
   1.789 +void cheatsAddGSACode(const char *code, const char *desc, bool v3)
   1.790 +{
   1.791 +	if (strlen(code) != 16)
   1.792 +	{
   1.793 +		// wrong cheat
   1.794 +		systemMessage(MSG_INVALID_GSA_CODE,
   1.795 +		              N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));
   1.796 +		return;
   1.797 +	}
   1.798 +
   1.799 +	int i;
   1.800 +	for (i = 0; i < 16; i++)
   1.801 +	{
   1.802 +		if (!CHEAT_IS_HEX(code[i]))
   1.803 +		{
   1.804 +			// wrong cheat
   1.805 +			systemMessage(MSG_INVALID_GSA_CODE,
   1.806 +			              N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));
   1.807 +			return;
   1.808 +		}
   1.809 +	}
   1.810 +
   1.811 +	char buffer[10];
   1.812 +	strncpy(buffer, code, 8);
   1.813 +	buffer[8] = 0;
   1.814 +	u32 address;
   1.815 +	sscanf(buffer, "%x", &address);
   1.816 +	strncpy(buffer, &code[8], 8);
   1.817 +	buffer[8] = 0;
   1.818 +	u32 value;
   1.819 +	sscanf(buffer, "%x", &value);
   1.820 +
   1.821 +	cheatsDecryptGSACode(address, value, v3);
   1.822 +
   1.823 +	if (value == 0x1DC0DE)
   1.824 +	{
   1.825 +		u32 gamecode = READ32LE(((u32 *)&rom[0xac]));
   1.826 +		if (gamecode != address)
   1.827 +		{
   1.828 +			char buffer[5];
   1.829 +			*((u32 *)buffer) = address;
   1.830 +			buffer[4]        = 0;
   1.831 +			char buffer2[5];
   1.832 +			*((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac]));
   1.833 +			buffer2[4]        = 0;
   1.834 +			systemMessage(MSG_GBA_CODE_WARNING,
   1.835 +			              N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."),
   1.836 +			              buffer, buffer2);
   1.837 +		}
   1.838 +		cheatsAdd(code, desc, address & 0x0FFFFFFF, value, v3 ? 257 : 256,
   1.839 +		          UNKNOWN_CODE);
   1.840 +		return;
   1.841 +	}
   1.842 +	if (isMultilineWithData(cheatsNumber-1))
   1.843 +	{
   1.844 +		cheatsAdd(code, desc, address, value, v3 ? 257 : 256, UNKNOWN_CODE);
   1.845 +		return;
   1.846 +	}
   1.847 +	if (v3)
   1.848 +	{
   1.849 +		int type = (address >> 25) & 127;
   1.850 +		u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF);
   1.851 +		switch (type)
   1.852 +		{
   1.853 +		case 0x00:
   1.854 +			if (address == 0)
   1.855 +			{
   1.856 +				type = (value >> 25) & 127;
   1.857 +				addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF);
   1.858 +				switch (type)
   1.859 +				{
   1.860 +				case 0x04:
   1.861 +					cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN);
   1.862 +					break;
   1.863 +				case 0x08:
   1.864 +					cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_GS_WRITE2);
   1.865 +					break;
   1.866 +				case 0x09:
   1.867 +					cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_GS_WRITE2);
   1.868 +					break;
   1.869 +				case 0x0a:
   1.870 +					cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_GS_WRITE2);
   1.871 +					break;
   1.872 +				case 0x0c:
   1.873 +				case 0x0d:
   1.874 +				case 0x0e:
   1.875 +				case 0x0f:
   1.876 +					cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2);
   1.877 +					break;
   1.878 +				case 0x40:
   1.879 +					cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_SLIDE);
   1.880 +					break;
   1.881 +				case 0x41:
   1.882 +					cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_SLIDE);
   1.883 +					break;
   1.884 +				case 0x42:
   1.885 +					cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_SLIDE);
   1.886 +					break;
   1.887 +				default:
   1.888 +					cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);
   1.889 +					break;
   1.890 +				}
   1.891 +			}
   1.892 +			else
   1.893 +				cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_FILL);
   1.894 +			break;
   1.895 +		case 0x01:
   1.896 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_FILL);
   1.897 +			break;
   1.898 +		case 0x02:
   1.899 +			cheatsAdd(code, desc, addr, value, 257, INT_32_BIT_WRITE);
   1.900 +			break;
   1.901 +		case 0x04:
   1.902 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE);
   1.903 +			break;
   1.904 +		case 0x05:
   1.905 +			cheatsAdd(code, desc, addr, value, 257, CBA_IF_TRUE);
   1.906 +			break;
   1.907 +		case 0x06:
   1.908 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE);
   1.909 +			break;
   1.910 +		case 0x08:
   1.911 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE);
   1.912 +			break;
   1.913 +		case 0x09:
   1.914 +			cheatsAdd(code, desc, addr, value, 257, CBA_IF_FALSE);
   1.915 +			break;
   1.916 +		case 0x0a:
   1.917 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE);
   1.918 +			break;
   1.919 +		case 0x24:
   1.920 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE2);
   1.921 +			break;
   1.922 +		case 0x25:
   1.923 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_TRUE2);
   1.924 +			break;
   1.925 +		case 0x26:
   1.926 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE2);
   1.927 +			break;
   1.928 +		case 0x28:
   1.929 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE2);
   1.930 +			break;
   1.931 +		case 0x29:
   1.932 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_FALSE2);
   1.933 +			break;
   1.934 +		case 0x2a:
   1.935 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE2);
   1.936 +			break;
   1.937 +		default:
   1.938 +			cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);
   1.939 +			break;
   1.940 +		}
   1.941 +	}
   1.942 +	else
   1.943 +	{
   1.944 +		int type = (address >> 28) & 15;
   1.945 +		switch (type)
   1.946 +		{
   1.947 +		case 0:
   1.948 +		case 1:
   1.949 +		case 2:
   1.950 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, type);
   1.951 +			break;
   1.952 +		case 6:
   1.953 +			address <<= 1;
   1.954 +			type      = (address >> 28) & 15;
   1.955 +			if (type == 0x0c)
   1.956 +			{
   1.957 +				cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,
   1.958 +				          GSA_16_BIT_ROM_PATCH);
   1.959 +				break;
   1.960 +			}
   1.961 +			// unsupported code
   1.962 +			cheatsAdd(code, desc, address, value, 256,
   1.963 +			          UNKNOWN_CODE);
   1.964 +			break;
   1.965 +		case 8:
   1.966 +			switch ((address >> 20) & 15)
   1.967 +			{
   1.968 +			case 1:
   1.969 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
   1.970 +				          GSA_8_BIT_GS_WRITE);
   1.971 +				break;
   1.972 +			case 2:
   1.973 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
   1.974 +				          GSA_16_BIT_GS_WRITE);
   1.975 +				break;
   1.976 +			case 3:
   1.977 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
   1.978 +				          GSA_32_BIT_GS_WRITE);
   1.979 +			case 15:
   1.980 +				cheatsAdd(code, desc, 0, value & 0xFF00, 256, GSA_SLOWDOWN);
   1.981 +				break;
   1.982 +			default:
   1.983 +				// unsupported code
   1.984 +				cheatsAdd(code, desc, address, value, 256,
   1.985 +				          UNKNOWN_CODE);
   1.986 +				break;
   1.987 +			}
   1.988 +			break;
   1.989 +		case 0x0d:
   1.990 +			if (address != 0xDEADFACE)
   1.991 +			{
   1.992 +				cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,
   1.993 +				          CBA_IF_TRUE);
   1.994 +			}
   1.995 +			else
   1.996 +				cheatsAdd(code, desc, address, value, 256,
   1.997 +				          UNKNOWN_CODE);
   1.998 +			break;
   1.999 +		default:
  1.1000 +			// unsupported code
  1.1001 +			cheatsAdd(code, desc, address, value, 256,
  1.1002 +			          UNKNOWN_CODE);
  1.1003 +			break;
  1.1004 +		}
  1.1005 +	}
  1.1006 +}
  1.1007 +
  1.1008 +bool cheatsImportGSACodeFile(const char *name, int game, bool v3)
  1.1009 +{
  1.1010 +	FILE *f = fopen(name, "rb");
  1.1011 +	if (!f)
  1.1012 +		return false;
  1.1013 +
  1.1014 +	int games = 0;
  1.1015 +	int len   = 0;
  1.1016 +	fseek(f, 0x1e, SEEK_CUR);
  1.1017 +	fread(&games, 1, 4, f);
  1.1018 +	bool found = false;
  1.1019 +	int  g     = 0;
  1.1020 +	while (games > 0)
  1.1021 +	{
  1.1022 +		if (g == game)
  1.1023 +		{
  1.1024 +			found = true;
  1.1025 +			break;
  1.1026 +		}
  1.1027 +		fread(&len, 1, 4, f);
  1.1028 +		fseek(f, len, SEEK_CUR);
  1.1029 +		int codes = 0;
  1.1030 +		fread(&codes, 1, 4, f);
  1.1031 +		while (codes > 0)
  1.1032 +		{
  1.1033 +			fread(&len, 1, 4, f);
  1.1034 +			fseek(f, len, SEEK_CUR);
  1.1035 +			fseek(f, 8, SEEK_CUR);
  1.1036 +			fread(&len, 1, 4, f);
  1.1037 +			fseek(f, len*12, SEEK_CUR);
  1.1038 +			codes--;
  1.1039 +		}
  1.1040 +		games--;
  1.1041 +		g++;
  1.1042 +	}
  1.1043 +	if (found)
  1.1044 +	{
  1.1045 +		char desc[256];
  1.1046 +		char code[17];
  1.1047 +		fread(&len, 1, 4, f);
  1.1048 +		fseek(f, len, SEEK_CUR);
  1.1049 +		int codes = 0;
  1.1050 +		fread(&codes, 1, 4, f);
  1.1051 +		while (codes > 0)
  1.1052 +		{
  1.1053 +			fread(&len, 1, 4, f);
  1.1054 +			fread(desc, 1, len, f);
  1.1055 +			desc[len] = 0;
  1.1056 +			desc[31]  = 0;
  1.1057 +			fread(&len, 1, 4, f);
  1.1058 +			fseek(f, len, SEEK_CUR);
  1.1059 +			fseek(f, 4, SEEK_CUR);
  1.1060 +			fread(&len, 1, 4, f);
  1.1061 +			while (len)
  1.1062 +			{
  1.1063 +				fseek(f, 4, SEEK_CUR);
  1.1064 +				fread(code, 1, 8, f);
  1.1065 +				fseek(f, 4, SEEK_CUR);
  1.1066 +				fread(&code[8], 1, 8, f);
  1.1067 +				code[16] = 0;
  1.1068 +				cheatsAddGSACode(code, desc, v3);
  1.1069 +				len -= 2;
  1.1070 +			}
  1.1071 +			codes--;
  1.1072 +		}
  1.1073 +	}
  1.1074 +	fclose(f);
  1.1075 +	return false;
  1.1076 +}
  1.1077 +
  1.1078 +void cheatsCBAReverseArray(u8 *array, u8 *dest)
  1.1079 +{
  1.1080 +	dest[0] = array[3];
  1.1081 +	dest[1] = array[2];
  1.1082 +	dest[2] = array[1];
  1.1083 +	dest[3] = array[0];
  1.1084 +	dest[4] = array[5];
  1.1085 +	dest[5] = array[4];
  1.1086 +}
  1.1087 +
  1.1088 +void chatsCBAScramble(u8 *array, int count, u8 b)
  1.1089 +{
  1.1090 +	u8 *x  = array + (count >> 3);
  1.1091 +	u8 *y  = array + (b >> 3);
  1.1092 +	u32 z  = *x & (1 << (count & 7));
  1.1093 +	u32 x0 = (*x & (~(1 << (count & 7))));
  1.1094 +	if (z != 0)
  1.1095 +		z = 1;
  1.1096 +	if ((*y & (1 << (b & 7))) != 0)
  1.1097 +		x0 |= (1 << (count & 7));
  1.1098 +	*x = x0;
  1.1099 +	u32 temp = *y & (~(1 << (b & 7)));
  1.1100 +	if (z != 0)
  1.1101 +		temp |= (1 << (b & 7));
  1.1102 +	*y = temp;
  1.1103 +}
  1.1104 +
  1.1105 +u32 cheatsCBAGetValue(u8 *array)
  1.1106 +{
  1.1107 +	return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24;
  1.1108 +}
  1.1109 +
  1.1110 +u16 cheatsCBAGetData(u8 *array)
  1.1111 +{
  1.1112 +	return array[4] | array[5]<<8;
  1.1113 +}
  1.1114 +
  1.1115 +void cheatsCBAArrayToValue(u8 *array, u8 *dest)
  1.1116 +{
  1.1117 +	dest[0] = array[3];
  1.1118 +	dest[1] = array[2];
  1.1119 +	dest[2] = array[1];
  1.1120 +	dest[3] = array[0];
  1.1121 +	dest[4] = array[5];
  1.1122 +	dest[5] = array[4];
  1.1123 +}
  1.1124 +
  1.1125 +void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array)
  1.1126 +{
  1.1127 +	array[0] = 1;
  1.1128 +	array[1] = value & 0xFF;
  1.1129 +	array[2] = (address >> 0x10) & 0xFF;
  1.1130 +	array[3] = (value >> 8) & 0xFF;
  1.1131 +	array[4] = (address >> 0x18) & 0x0F;
  1.1132 +	array[5] = address & 0xFFFF;
  1.1133 +	array[6] = address;
  1.1134 +	array[7] = value;
  1.1135 +}
  1.1136 +
  1.1137 +u32 cheatsCBAEncWorker()
  1.1138 +{
  1.1139 +	u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039;
  1.1140 +	u32 y = (x * 0x41c64e6d) + 0x3039;
  1.1141 +	u32 z = x >> 0x10;
  1.1142 +	x = ((y >> 0x10) & 0x7fff) << 0x0f;
  1.1143 +	z = (z << 0x1e) | x;
  1.1144 +	x = (y * 0x41c64e6d) + 0x3039;
  1.1145 +	cheatsCBATemporaryValue = x;
  1.1146 +	return z | ((x >> 0x10) & 0x7fff);
  1.1147 +}
  1.1148 +
  1.1149 +#define ROR(v, s) \
  1.1150 +    (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
  1.1151 +
  1.1152 +u32 cheatsCBACalcIndex(u32 x, u32 y)
  1.1153 +{
  1.1154 +	if (y != 0)
  1.1155 +	{
  1.1156 +		if (y == 1)
  1.1157 +			x = 0;
  1.1158 +		else if (x == y)
  1.1159 +			x = 0;
  1.1160 +		if (y < 1)
  1.1161 +			return x;
  1.1162 +		else if (x < y)
  1.1163 +			return x;
  1.1164 +		u32 x0 = 1;
  1.1165 +
  1.1166 +		while (y < 0x10000000)
  1.1167 +		{
  1.1168 +			if (y < x)
  1.1169 +			{
  1.1170 +				y  = y << 4;
  1.1171 +				x0 = x0 << 4;
  1.1172 +			}
  1.1173 +			else
  1.1174 +				break;
  1.1175 +		}
  1.1176 +
  1.1177 +		while (y < 0x80000000)
  1.1178 +		{
  1.1179 +			if (y < x)
  1.1180 +			{
  1.1181 +				y  = y << 1;
  1.1182 +				x0 = x0 << 1;
  1.1183 +			}
  1.1184 +			else
  1.1185 +				break;
  1.1186 +		}
  1.1187 +
  1.1188 +loop:
  1.1189 +		u32 z = 0;
  1.1190 +		if (x >= y)
  1.1191 +			x -= y;
  1.1192 +		if (x >= (y >> 1))
  1.1193 +		{
  1.1194 +			x -= (y >> 1);
  1.1195 +			z |= ROR(x0, 1);
  1.1196 +		}
  1.1197 +		if (x >= (y >> 2))
  1.1198 +		{
  1.1199 +			x -= (y >> 2);
  1.1200 +			z |= ROR(x0, 2);
  1.1201 +		}
  1.1202 +		if (x >= (y >> 3))
  1.1203 +		{
  1.1204 +			x -= (y >> 3);
  1.1205 +			z |= ROR(x0, 3);
  1.1206 +		}
  1.1207 +
  1.1208 +		u32 temp = x0;
  1.1209 +
  1.1210 +		if (x != 0)
  1.1211 +		{
  1.1212 +			x0 = x0 >> 4;
  1.1213 +			if (x0 != 0)
  1.1214 +			{
  1.1215 +				y = y >> 4;
  1.1216 +				goto loop;
  1.1217 +			}
  1.1218 +		}
  1.1219 +
  1.1220 +		z = z & 0xe0000000;
  1.1221 +
  1.1222 +		if (z != 0)
  1.1223 +		{
  1.1224 +			if ((temp & 7) == 0)
  1.1225 +				return x;
  1.1226 +		}
  1.1227 +		else
  1.1228 +			return x;
  1.1229 +
  1.1230 +		if ((z & ROR(temp, 3)) != 0)
  1.1231 +			x += y >> 3;
  1.1232 +		if ((z & ROR(temp, 2)) != 0)
  1.1233 +			x += y >> 2;
  1.1234 +		if ((z & ROR(temp, 1)) != 0)
  1.1235 +			x += y >> 1;
  1.1236 +		return x;
  1.1237 +	}
  1.1238 +	else
  1.1239 +	{}
  1.1240 +	// should not happen in the current code
  1.1241 +	return 0;
  1.1242 +}
  1.1243 +
  1.1244 +void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count)
  1.1245 +{
  1.1246 +	int i;
  1.1247 +	for (i = 0; i < count; i++)
  1.1248 +		buffer[i] = i;
  1.1249 +	for (i = 0; (u32)i < a; i++)
  1.1250 +	{
  1.1251 +		u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);
  1.1252 +		u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);
  1.1253 +		u32 t = buffer[a];
  1.1254 +		buffer[a] = buffer[b];
  1.1255 +		buffer[b] = t;
  1.1256 +	}
  1.1257 +}
  1.1258 +
  1.1259 +void cheatsCBAChangeEncryption(u32 *seed)
  1.1260 +{
  1.1261 +	int i;
  1.1262 +
  1.1263 +	cheatsCBATemporaryValue = (seed[1] ^ 0x1111);
  1.1264 +	cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30);
  1.1265 +	cheatsCBATemporaryValue = 0x4efad1c3;
  1.1266 +
  1.1267 +	for (i = 0; (u32)i < seed[4]; i++)
  1.1268 +	{
  1.1269 +		cheatsCBATemporaryValue = cheatsCBAEncWorker();
  1.1270 +	}
  1.1271 +	cheatsCBASeed[2] = cheatsCBAEncWorker();
  1.1272 +	cheatsCBASeed[3] = cheatsCBAEncWorker();
  1.1273 +
  1.1274 +	cheatsCBATemporaryValue = seed[3] ^ 0xf254;
  1.1275 +
  1.1276 +	for (i = 0; (u32)i < seed[3]; i++)
  1.1277 +	{
  1.1278 +		cheatsCBATemporaryValue = cheatsCBAEncWorker();
  1.1279 +	}
  1.1280 +
  1.1281 +	cheatsCBASeed[0] = cheatsCBAEncWorker();
  1.1282 +	cheatsCBASeed[1] = cheatsCBAEncWorker();
  1.1283 +
  1.1284 +	*((u32 *)&cheatsCBACurrentSeed[0]) = seed[6];
  1.1285 +	*((u32 *)&cheatsCBACurrentSeed[4]) = seed[7];
  1.1286 +	*((u32 *)&cheatsCBACurrentSeed[8]) = 0;
  1.1287 +}
  1.1288 +
  1.1289 +u16 cheatsCBAGenValue(u32 x, u32 y, u32 z)
  1.1290 +{
  1.1291 +	y <<= 0x10;
  1.1292 +	z <<= 0x10;
  1.1293 +	x <<= 0x18;
  1.1294 +	u32 x0 = (int)y >> 0x10;
  1.1295 +	z = (int)z >> 0x10;
  1.1296 +	x = (int)x >> 0x10;
  1.1297 +	for (int i = 0; i < 8; i++)
  1.1298 +	{
  1.1299 +		u32 temp = z ^ x;
  1.1300 +		if ((int)temp >= 0)
  1.1301 +		{
  1.1302 +			temp = z << 0x11;
  1.1303 +		}
  1.1304 +		else
  1.1305 +		{
  1.1306 +			temp  = z << 0x01;
  1.1307 +			temp ^= x0;
  1.1308 +			temp  = temp << 0x10;
  1.1309 +		}
  1.1310 +		z    = (int)temp >> 0x10;
  1.1311 +		temp = x << 0x11;
  1.1312 +		x    = (int)temp >> 0x10;
  1.1313 +	}
  1.1314 +	return z & 0xffff;
  1.1315 +}
  1.1316 +
  1.1317 +void cheatsCBAGenTable()
  1.1318 +{
  1.1319 +	for (int i = 0; i < 0x100; i++)
  1.1320 +	{
  1.1321 +		cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0);
  1.1322 +	}
  1.1323 +	cheatsCBATableGenerated = true;
  1.1324 +}
  1.1325 +
  1.1326 +u16 cheatsCBACalcCRC(u8 *rom, int count)
  1.1327 +{
  1.1328 +	u32 crc = 0xffffffff;
  1.1329 +
  1.1330 +	if (count & 3)
  1.1331 +	{
  1.1332 +		// 0x08000EAE
  1.1333 +	}
  1.1334 +	else
  1.1335 +	{
  1.1336 +		count = (count >> 2) - 1;
  1.1337 +		if (count != -1)
  1.1338 +		{
  1.1339 +			while (count != -1)
  1.1340 +			{
  1.1341 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
  1.1342 +				                                       ^ *rom++]) << 0x10) >> 0x10;
  1.1343 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
  1.1344 +				                                       ^ *rom++]) << 0x10) >> 0x10;
  1.1345 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
  1.1346 +				                                       ^ *rom++]) << 0x10) >> 0x10;
  1.1347 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
  1.1348 +				                                       ^ *rom++]) << 0x10) >> 0x10;
  1.1349 +				count--;
  1.1350 +			}
  1.1351 +		}
  1.1352 +	}
  1.1353 +	return crc & 0xffff;
  1.1354 +}
  1.1355 +
  1.1356 +void cheatsCBADecrypt(u8 *decrypt)
  1.1357 +{
  1.1358 +	u8  buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  1.1359 +	u8 *array     = &buffer[1];
  1.1360 +
  1.1361 +	cheatsCBAReverseArray(decrypt, array);
  1.1362 +
  1.1363 +	for (int count = 0x2f; count >= 0; count--)
  1.1364 +	{
  1.1365 +		chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]);
  1.1366 +	}
  1.1367 +	cheatsCBAArrayToValue(array, decrypt);
  1.1368 +	*((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^
  1.1369 +	                    cheatsCBASeed[0];
  1.1370 +	*((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^
  1.1371 +	                         cheatsCBASeed[1]) & 0xffff;
  1.1372 +
  1.1373 +	cheatsCBAReverseArray(decrypt, array);
  1.1374 +
  1.1375 +	u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed);
  1.1376 +	for (int i = 0; i <= 4; i++)
  1.1377 +	{
  1.1378 +		array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ;
  1.1379 +	}
  1.1380 +
  1.1381 +	array[5] = (cs >> 8) ^ array[5];
  1.1382 +
  1.1383 +	for (int j = 5; j >= 0; j--)
  1.1384 +	{
  1.1385 +		array[j] = (cs ^ array[j-1]) ^ array[j];
  1.1386 +	}
  1.1387 +
  1.1388 +	cheatsCBAArrayToValue(array, decrypt);
  1.1389 +
  1.1390 +	*((u32 *)decrypt) = cheatsCBAGetValue(decrypt)
  1.1391 +	                    ^ cheatsCBASeed[2];
  1.1392 +	*((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt)
  1.1393 +	                         ^ cheatsCBASeed[3]) & 0xffff;
  1.1394 +}
  1.1395 +
  1.1396 +int cheatsCBAGetCount()
  1.1397 +{
  1.1398 +	int count = 0;
  1.1399 +	for (int i = 0; i < cheatsNumber; i++)
  1.1400 +	{
  1.1401 +		if (cheatsList[i].code == 512)
  1.1402 +			count++;
  1.1403 +	}
  1.1404 +	return count;
  1.1405 +}
  1.1406 +
  1.1407 +bool cheatsCBAShouldDecrypt()
  1.1408 +{
  1.1409 +	for (int i = 0; i < cheatsNumber; i++)
  1.1410 +	{
  1.1411 +		if (cheatsList[i].code == 512)
  1.1412 +		{
  1.1413 +			return (cheatsList[i].codestring[0] == '9');
  1.1414 +		}
  1.1415 +	}
  1.1416 +	return false;
  1.1417 +}
  1.1418 +
  1.1419 +void cheatsAddCBACode(const char *code, const char *desc)
  1.1420 +{
  1.1421 +	if (strlen(code) != 13)
  1.1422 +	{
  1.1423 +		// wrong cheat
  1.1424 +		systemMessage(MSG_INVALID_CBA_CODE,
  1.1425 +		              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
  1.1426 +		return;
  1.1427 +	}
  1.1428 +
  1.1429 +	int i;
  1.1430 +	for (i = 0; i < 8; i++)
  1.1431 +	{
  1.1432 +		if (!CHEAT_IS_HEX(code[i]))
  1.1433 +		{
  1.1434 +			// wrong cheat
  1.1435 +			systemMessage(MSG_INVALID_CBA_CODE,
  1.1436 +			              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
  1.1437 +			return;
  1.1438 +		}
  1.1439 +	}
  1.1440 +
  1.1441 +	if (code[8] != ' ')
  1.1442 +	{
  1.1443 +		systemMessage(MSG_INVALID_CBA_CODE,
  1.1444 +		              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
  1.1445 +		return;
  1.1446 +	}
  1.1447 +
  1.1448 +	for (i = 9; i < 13; i++)
  1.1449 +	{
  1.1450 +		if (!CHEAT_IS_HEX(code[i]))
  1.1451 +		{
  1.1452 +			// wrong cheat
  1.1453 +			systemMessage(MSG_INVALID_CBA_CODE,
  1.1454 +			              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
  1.1455 +			return;
  1.1456 +		}
  1.1457 +	}
  1.1458 +
  1.1459 +	char buffer[10];
  1.1460 +	strncpy(buffer, code, 8);
  1.1461 +	buffer[8] = 0;
  1.1462 +	u32 address;
  1.1463 +	sscanf(buffer, "%x", &address);
  1.1464 +	strncpy(buffer, &code[9], 4);
  1.1465 +	buffer[4] = 0;
  1.1466 +	u32 value;
  1.1467 +	sscanf(buffer, "%x", &value);
  1.1468 +
  1.1469 +	u8 array[8] = {
  1.1470 +		address &255,
  1.1471 +		(address >> 8) & 255,
  1.1472 +		(address >> 16) & 255,
  1.1473 +		(address >> 24) & 255,
  1.1474 +		(value & 255),
  1.1475 +		(value >> 8) & 255,
  1.1476 +		0,
  1.1477 +		0
  1.1478 +	};
  1.1479 +
  1.1480 +	if (cheatsCBAGetCount() == 0 &&
  1.1481 +	    (address >> 28) == 9)
  1.1482 +	{
  1.1483 +		u32 seed[8];
  1.1484 +		cheatsCBAParseSeedCode(address, value, seed);
  1.1485 +		cheatsCBAChangeEncryption(seed);
  1.1486 +		cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE);
  1.1487 +	}
  1.1488 +	else
  1.1489 +	{
  1.1490 +		if (cheatsCBAShouldDecrypt())
  1.1491 +			cheatsCBADecrypt(array);
  1.1492 +
  1.1493 +		address = READ32LE(((u32 *)array));
  1.1494 +		value   = READ16LE(((u16 *)&array[4]));
  1.1495 +
  1.1496 +		int type = (address >> 28) & 15;
  1.1497 +
  1.1498 +		if (isMultilineWithData(cheatsNumber-1))
  1.1499 +		{
  1.1500 +			cheatsAdd(code, desc, address, value, 512, UNKNOWN_CODE);
  1.1501 +			return;
  1.1502 +		}
  1.1503 +
  1.1504 +		switch (type)
  1.1505 +		{
  1.1506 +		case 0x00:
  1.1507 +		{
  1.1508 +			if (!cheatsCBATableGenerated)
  1.1509 +				cheatsCBAGenTable();
  1.1510 +			u32 crc = cheatsCBACalcCRC(rom, 0x10000);
  1.1511 +			if (crc != address)
  1.1512 +			{
  1.1513 +				systemMessage(MSG_CBA_CODE_WARNING,
  1.1514 +				              N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly."));
  1.1515 +			}
  1.1516 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1517 +			          UNKNOWN_CODE);
  1.1518 +			break;
  1.1519 +		}
  1.1520 +		case 0x02:
  1.1521 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1522 +			          CBA_OR);
  1.1523 +			break;
  1.1524 +		case 0x03:
  1.1525 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1526 +			          INT_8_BIT_WRITE);
  1.1527 +			break;
  1.1528 +		case 0x04:
  1.1529 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1530 +			          CBA_SLIDE_CODE);
  1.1531 +			break;
  1.1532 +		case 0x05:
  1.1533 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1534 +			          CBA_SUPER);
  1.1535 +			break;
  1.1536 +		case 0x06:
  1.1537 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1538 +			          CBA_AND);
  1.1539 +			break;
  1.1540 +		case 0x07:
  1.1541 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1542 +			          CBA_IF_TRUE);
  1.1543 +			break;
  1.1544 +		case 0x08:
  1.1545 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1546 +			          INT_16_BIT_WRITE);
  1.1547 +			break;
  1.1548 +		case 0x0a:
  1.1549 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1550 +			          CBA_IF_FALSE);
  1.1551 +			break;
  1.1552 +		case 0x0b:
  1.1553 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1554 +			          CBA_LT);
  1.1555 +			break;
  1.1556 +		case 0x0c:
  1.1557 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1558 +			          CBA_GT);
  1.1559 +			break;
  1.1560 +		case 0x0d:
  1.1561 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1562 +			          CBA_IF_KEYS_PRESSED);
  1.1563 +			break;
  1.1564 +		case 0x0e:
  1.1565 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
  1.1566 +			          CBA_ADD);
  1.1567 +			break;
  1.1568 +		default:
  1.1569 +			// unsupported code
  1.1570 +			cheatsAdd(code, desc, address & 0xFFFFFFFF, value, 512,
  1.1571 +			          UNKNOWN_CODE);
  1.1572 +			break;
  1.1573 +		}
  1.1574 +	}
  1.1575 +}
  1.1576 +
  1.1577 +void cheatsSaveGame(gzFile file)
  1.1578 +{
  1.1579 +	utilWriteInt(file, cheatsNumber);
  1.1580 +
  1.1581 +	utilGzWrite(file, cheatsList, sizeof(cheatsList));
  1.1582 +}
  1.1583 +
  1.1584 +void cheatsReadGame(gzFile file)
  1.1585 +{
  1.1586 +	cheatsNumber = 0;
  1.1587 +
  1.1588 +	cheatsNumber = utilReadInt(file);
  1.1589 +
  1.1590 +	utilGzRead(file, cheatsList, sizeof(cheatsList));
  1.1591 +
  1.1592 +	bool firstCodeBreaker = true;
  1.1593 +
  1.1594 +	for (int i = 0; i < cheatsNumber; i++)
  1.1595 +	{
  1.1596 +		cheatsList[i].status = 0;
  1.1597 +		if (!cheatsList[i].codestring[0])
  1.1598 +		{
  1.1599 +			switch (cheatsList[i].size)
  1.1600 +			{
  1.1601 +			case 0:
  1.1602 +				sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,
  1.1603 +				        cheatsList[i].value);
  1.1604 +				break;
  1.1605 +			case 1:
  1.1606 +				sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,
  1.1607 +				        cheatsList[i].value);
  1.1608 +				break;
  1.1609 +			case 2:
  1.1610 +				sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,
  1.1611 +				        cheatsList[i].value);
  1.1612 +				break;
  1.1613 +			}
  1.1614 +		}
  1.1615 +
  1.1616 +		if (cheatsList[i].enabled)
  1.1617 +		{
  1.1618 +			cheatsEnable(i);
  1.1619 +		}
  1.1620 +
  1.1621 +		if (cheatsList[i].code == 512 && firstCodeBreaker)
  1.1622 +		{
  1.1623 +			firstCodeBreaker = false;
  1.1624 +			char buffer[10];
  1.1625 +			strncpy(buffer, cheatsList[i].codestring, 8);
  1.1626 +			buffer[8] = 0;
  1.1627 +			u32 address;
  1.1628 +			sscanf(buffer, "%x", &address);
  1.1629 +			if ((address >> 28) == 9)
  1.1630 +			{
  1.1631 +				strncpy(buffer, &cheatsList[i].codestring[9], 4);
  1.1632 +				buffer[4] = 0;
  1.1633 +				u32 value;
  1.1634 +				sscanf(buffer, "%x", &value);
  1.1635 +
  1.1636 +				u32 seed[8];
  1.1637 +				cheatsCBAParseSeedCode(address, value, seed);
  1.1638 +				cheatsCBAChangeEncryption(seed);
  1.1639 +			}
  1.1640 +		}
  1.1641 +	}
  1.1642 +}
  1.1643 +
  1.1644 +void cheatsSaveCheatList(const char *file)
  1.1645 +{
  1.1646 +	if (cheatsNumber == 0)
  1.1647 +		return;
  1.1648 +	FILE *f = fopen(file, "wb");
  1.1649 +	if (f == NULL)
  1.1650 +		return;
  1.1651 +	int version = 1;
  1.1652 +	fwrite(&version, 1, sizeof(version), f);
  1.1653 +	int type = 0;
  1.1654 +	fwrite(&type, 1, sizeof(type), f);
  1.1655 +	fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f);
  1.1656 +	fwrite(cheatsList, 1, sizeof(cheatsList), f);
  1.1657 +	fclose(f);
  1.1658 +}
  1.1659 +
  1.1660 +bool cheatsLoadCheatList(const char *file)
  1.1661 +{
  1.1662 +	cheatsNumber = 0;
  1.1663 +
  1.1664 +	int count = 0;
  1.1665 +
  1.1666 +	FILE *f = fopen(file, "rb");
  1.1667 +
  1.1668 +	if (f == NULL)
  1.1669 +		return false;
  1.1670 +
  1.1671 +	int version = 0;
  1.1672 +
  1.1673 +	if (fread(&version, 1, sizeof(version), f) != sizeof(version))
  1.1674 +	{
  1.1675 +		fclose(f);
  1.1676 +		return false;
  1.1677 +	}
  1.1678 +
  1.1679 +	if (version != 1)
  1.1680 +	{
  1.1681 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
  1.1682 +		              N_("Unsupported cheat list version %d"), version);
  1.1683 +		fclose(f);
  1.1684 +		return false;
  1.1685 +	}
  1.1686 +
  1.1687 +	int type = 0;
  1.1688 +	if (fread(&type, 1, sizeof(type), f) != sizeof(type))
  1.1689 +	{
  1.1690 +		fclose(f);
  1.1691 +		return false;
  1.1692 +	}
  1.1693 +
  1.1694 +	if (type != 0)
  1.1695 +	{
  1.1696 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
  1.1697 +		              N_("Unsupported cheat list type %d"), type);
  1.1698 +		fclose(f);
  1.1699 +		return false;
  1.1700 +	}
  1.1701 +
  1.1702 +	if (fread(&count, 1, sizeof(count), f) != sizeof(count))
  1.1703 +	{
  1.1704 +		fclose(f);
  1.1705 +		return false;
  1.1706 +	}
  1.1707 +
  1.1708 +	if (fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList))
  1.1709 +	{
  1.1710 +		fclose(f);
  1.1711 +		return false;
  1.1712 +	}
  1.1713 +
  1.1714 +	bool firstCodeBreaker = true;
  1.1715 +
  1.1716 +	for (int i = 0; i < count; i++)
  1.1717 +	{
  1.1718 +		cheatsList[i].status = 0; // remove old status as it is not used
  1.1719 +		if (!cheatsList[i].codestring[0])
  1.1720 +		{
  1.1721 +			switch (cheatsList[i].size)
  1.1722 +			{
  1.1723 +			case 0:
  1.1724 +				sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,
  1.1725 +				        cheatsList[i].value);
  1.1726 +				break;
  1.1727 +			case 1:
  1.1728 +				sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,
  1.1729 +				        cheatsList[i].value);
  1.1730 +				break;
  1.1731 +			case 2:
  1.1732 +				sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,
  1.1733 +				        cheatsList[i].value);
  1.1734 +				break;
  1.1735 +			}
  1.1736 +		}
  1.1737 +
  1.1738 +		if (cheatsList[i].code == 512 && firstCodeBreaker)
  1.1739 +		{
  1.1740 +			firstCodeBreaker = false;
  1.1741 +			char buffer[10];
  1.1742 +			strncpy(buffer, cheatsList[i].codestring, 8);
  1.1743 +			buffer[8] = 0;
  1.1744 +			u32 address;
  1.1745 +			sscanf(buffer, "%x", &address);
  1.1746 +			if ((address >> 28) == 9)
  1.1747 +			{
  1.1748 +				strncpy(buffer, &cheatsList[i].codestring[9], 4);
  1.1749 +				buffer[4] = 0;
  1.1750 +				u32 value;
  1.1751 +				sscanf(buffer, "%x", &value);
  1.1752 +
  1.1753 +				u32 seed[8];
  1.1754 +				cheatsCBAParseSeedCode(address, value, seed);
  1.1755 +				cheatsCBAChangeEncryption(seed);
  1.1756 +			}
  1.1757 +		}
  1.1758 +	}
  1.1759 +	cheatsNumber = count;
  1.1760 +	fclose(f);
  1.1761 +	return true;
  1.1762 +}
  1.1763 +
  1.1764 +extern int *extCpuLoopTicks;
  1.1765 +extern int *extClockTicks;
  1.1766 +extern int *extTicks;
  1.1767 +extern int  cpuSavedTicks;
  1.1768 +
  1.1769 +extern void debuggerBreakOnWrite(u32 *, u32, u32, int);
  1.1770 +
  1.1771 +#define CPU_BREAK_LOOP2 \
  1.1772 +    cpuSavedTicks    = cpuSavedTicks - *extCpuLoopTicks; \
  1.1773 +    *extCpuLoopTicks = *extClockTicks; \
  1.1774 +    *extTicks        = *extClockTicks;
  1.1775 +
  1.1776 +void cheatsWriteMemory(u32 *address, u32 value, u32 mask)
  1.1777 +{
  1.1778 +#ifdef BKPT_SUPPORT
  1.1779 +#ifdef SDL
  1.1780 +	if (cheatsNumber == 0)
  1.1781 +	{
  1.1782 +		debuggerBreakOnWrite(address, *address, value, 2);
  1.1783 +		CPU_BREAK_LOOP2;
  1.1784 +		*address = value;
  1.1785 +		return;
  1.1786 +	}
  1.1787 +#endif
  1.1788 +#endif
  1.1789 +}
  1.1790 +
  1.1791 +void cheatsWriteHalfWord(u16 *address, u16 value, u16 mask)
  1.1792 +{
  1.1793 +#ifdef BKPT_SUPPORT
  1.1794 +#ifdef SDL
  1.1795 +	if (cheatsNumber == 0)
  1.1796 +	{
  1.1797 +		debuggerBreakOnWrite((u32 *)address, *address, value, 1);
  1.1798 +		CPU_BREAK_LOOP2;
  1.1799 +		*address = value;
  1.1800 +		return;
  1.1801 +	}
  1.1802 +#endif
  1.1803 +#endif
  1.1804 +}
  1.1805 +
  1.1806 +#if defined BKPT_SUPPORT && defined SDL
  1.1807 +void cheatsWriteByte(u8 *address, u8 value)
  1.1808 +#else
  1.1809 +void cheatsWriteByte(u8 *, u8)
  1.1810 +#endif
  1.1811 +{
  1.1812 +#ifdef BKPT_SUPPORT
  1.1813 +#ifdef SDL
  1.1814 +	if (cheatsNumber == 0)
  1.1815 +	{
  1.1816 +		debuggerBreakOnWrite((u32 *)address, *address, value, 0);
  1.1817 +		CPU_BREAK_LOOP2;
  1.1818 +		*address = value;
  1.1819 +		return;
  1.1820 +	}
  1.1821 +#endif
  1.1822 +#endif
  1.1823 +}
  1.1824 +
  1.1825 +#undef CPU_BREAK_LOOP2