/* gameplaySP * * Copyright (C) 2006 Exophase * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" cheat_type cheats[MAX_CHEATS]; u32 num_cheats; void decrypt_gsa_code(u32 *address_ptr, u32 *value_ptr, cheat_variant_enum cheat_variant) { u32 i; u32 address = *address_ptr; u32 value = *value_ptr; u32 r = 0xc6ef3720; u32 seeds_v1[4] = { 0x09f4fbbd, 0x9681884a, 0x352027e9, 0xf3dee5a7 }; u32 seeds_v3[4] = { 0x7aa9648f, 0x7fae6994, 0xc0efaad5, 0x42712c57 }; u32 *seeds; if(cheat_variant == CHEAT_TYPE_GAMESHARK_V1) seeds = seeds_v1; else seeds = seeds_v3; for(i = 0; i < 32; i++) { value -= ((address << 4) + seeds[2]) ^ (address + r) ^ ((address >> 5) + seeds[3]); address -= ((value << 4) + seeds[0]) ^ (value + r) ^ ((value >> 5) + seeds[1]); r -= 0x9e3779b9; } *address_ptr = address; *value_ptr = value; } void add_cheats(char *cheats_filename) { FILE *cheats_file; char current_line[256]; char *name_ptr; u32 *cheat_code_ptr; u32 address, value; u32 num_cheat_lines; u32 cheat_name_length; cheat_variant_enum current_cheat_variant; num_cheats = 0; cheats_file = fopen(cheats_filename, "rb"); if(cheats_file) { while(fgets(current_line, 256, cheats_file)) { // Get the header line first name_ptr = strchr(current_line, ' '); if(name_ptr) { *name_ptr = 0; name_ptr++; } if(!strcasecmp(current_line, "gameshark_v1") || !strcasecmp(current_line, "gameshark_v2") || !strcasecmp(current_line, "PAR_v1") || !strcasecmp(current_line, "PAR_v2")) { current_cheat_variant = CHEAT_TYPE_GAMESHARK_V1; } else if(!strcasecmp(current_line, "gameshark_v3") || !strcasecmp(current_line, "PAR_v3")) { current_cheat_variant = CHEAT_TYPE_GAMESHARK_V3; } else { current_cheat_variant = CHEAT_TYPE_INVALID; } if(current_cheat_variant != CHEAT_TYPE_INVALID) { strncpy(cheats[num_cheats].cheat_name, name_ptr, CHEAT_NAME_LENGTH - 1); cheats[num_cheats].cheat_name[CHEAT_NAME_LENGTH - 1] = 0; cheat_name_length = strlen(cheats[num_cheats].cheat_name); if(cheat_name_length && ((cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\n') || (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r'))) { cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; cheat_name_length--; } if(cheat_name_length && cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r') { cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; } cheats[num_cheats].cheat_variant = current_cheat_variant; cheat_code_ptr = cheats[num_cheats].cheat_codes; num_cheat_lines = 0; while(fgets(current_line, 256, cheats_file)) { if(strlen(current_line) < 3) break; sscanf(current_line, "%08x %08x", &address, &value); decrypt_gsa_code(&address, &value, current_cheat_variant); cheat_code_ptr[0] = address; cheat_code_ptr[1] = value; cheat_code_ptr += 2; num_cheat_lines++; } cheats[num_cheats].num_cheat_lines = num_cheat_lines; num_cheats++; } } fclose(cheats_file); } } void process_cheat_gs1(cheat_type *cheat) { u32 cheat_opcode; u32 *code_ptr = cheat->cheat_codes; u32 address, value; u32 i; for(i = 0; i < cheat->num_cheat_lines; i++) { address = code_ptr[0]; value = code_ptr[1]; code_ptr += 2; cheat_opcode = address >> 28; address &= 0xFFFFFFF; switch(cheat_opcode) { case 0x0: write_memory8(address, value); break; case 0x1: write_memory16(address, value); break; case 0x2: write_memory32(address, value); break; case 0x3: { u32 num_addresses = address & 0xFFFF; u32 address1, address2; u32 i2; for(i2 = 0; i2 < num_addresses; i2++) { address1 = code_ptr[0]; address2 = code_ptr[1]; code_ptr += 2; i++; write_memory32(address1, value); if(address2 != 0) write_memory32(address2, value); } break; } // ROM patch not supported yet case 0x6: break; // GS button down not supported yet case 0x8: break; // Reencryption (DEADFACE) not supported yet case 0xD: if(read_memory16(address) != (value & 0xFFFF)) { code_ptr += 2; i++; } break; case 0xE: if(read_memory16(value & 0xFFFFFFF) != (address & 0xFFFF)) { u32 skip = ((address >> 16) & 0x03); code_ptr += skip * 2; i += skip; } break; // Hook routine not supported yet (not important??) case 0x0F: break; } } } // These are especially incomplete. void process_cheat_gs3(cheat_type *cheat) { u32 cheat_opcode; u32 *code_ptr = cheat->cheat_codes; u32 address, value; u32 i; for(i = 0; i < cheat->num_cheat_lines; i++) { address = code_ptr[0]; value = code_ptr[1]; code_ptr += 2; cheat_opcode = address >> 28; address &= 0xFFFFFFF; switch(cheat_opcode) { case 0x0: cheat_opcode = address >> 24; address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); switch(cheat_opcode) { case 0x0: { u32 iterations = value >> 24; u32 i2; value &= 0xFF; for(i2 = 0; i2 <= iterations; i2++, address++) { write_memory8(address, value); } break; } case 0x2: { u32 iterations = value >> 16; u32 i2; value &= 0xFFFF; for(i2 = 0; i2 <= iterations; i2++, address += 2) { write_memory16(address, value); } break; } case 0x4: write_memory32(address, value); break; } break; case 0x4: cheat_opcode = address >> 24; address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); switch(cheat_opcode) { case 0x0: address = read_memory32(address) + (value >> 24); write_memory8(address, value & 0xFF); break; case 0x2: address = read_memory32(address) + ((value >> 16) * 2); write_memory16(address, value & 0xFFFF); break; case 0x4: address = read_memory32(address); write_memory32(address, value); break; } break; case 0x8: cheat_opcode = address >> 24; address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); switch(cheat_opcode) { case 0x0: value = (value & 0xFF) + read_memory8(address); write_memory8(address, value); break; case 0x2: value = (value & 0xFFFF) + read_memory16(address); write_memory16(address, value); break; case 0x4: value = value + read_memory32(address); write_memory32(address, value); break; } break; case 0xC: cheat_opcode = address >> 24; address = (address & 0xFFFFFF) + 0x4000000; switch(cheat_opcode) { case 0x6: write_memory16(address, value); break; case 0x7: write_memory32(address, value); break; } break; } } } void process_cheats(void) { u32 i; for(i = 0; i < num_cheats; i++) { if(cheats[i].cheat_active) { switch(cheats[i].cheat_variant) { case CHEAT_TYPE_GAMESHARK_V1: process_cheat_gs1(cheats + i); break; case CHEAT_TYPE_GAMESHARK_V3: process_cheat_gs3(cheats + i); break; default: break; } } } }