original source from gpsp09-2xb_src.tar.bz2
[gpsp.git] / cheats.c
CommitLineData
2823a4c8 1/* gameplaySP
2 *
3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include "common.h"
21
22cheat_type cheats[MAX_CHEATS];
23u32 num_cheats;
24
25void decrypt_gsa_code(u32 *address_ptr, u32 *value_ptr, cheat_variant_enum
26 cheat_variant)
27{
28 u32 i, i2, code_position;
29 u32 address = *address_ptr;
30 u32 value = *value_ptr;
31 u32 r = 0xc6ef3720;
32
33 u32 seeds_v1[4] =
34 {
35 0x09f4fbbd, 0x9681884a, 0x352027e9, 0xf3dee5a7
36 };
37 u32 seeds_v3[4] =
38 {
39 0x7aa9648f, 0x7fae6994, 0xc0efaad5, 0x42712c57
40 };
41 u32 *seeds;
42
43 if(cheat_variant == CHEAT_TYPE_GAMESHARK_V1)
44 seeds = seeds_v1;
45 else
46 seeds = seeds_v3;
47
48 for(i = 0; i < 32; i++)
49 {
50 value -= ((address << 4) + seeds[2]) ^ (address + r) ^
51 ((address >> 5) + seeds[3]);
52 address -= ((value << 4) + seeds[0]) ^ (value + r) ^
53 ((value >> 5) + seeds[1]);
54 r -= 0x9e3779b9;
55 }
56
57 *address_ptr = address;
58 *value_ptr = value;
59}
60
61void add_cheats(u8 *cheats_filename)
62{
63 FILE *cheats_file;
64 u8 current_line[256];
65 u8 *name_ptr;
66 u32 *cheat_code_ptr;
67 u32 address, value;
68 u32 num_cheat_lines;
69 u32 cheat_name_length;
70 cheat_variant_enum current_cheat_variant;
71
72 num_cheats = 0;
73
74 cheats_file = fopen(cheats_filename, "rb");
75
76 if(cheats_file)
77 {
78 while(fgets(current_line, 256, cheats_file))
79 {
80 // Get the header line first
81 name_ptr = strchr(current_line, ' ');
82 if(name_ptr)
83 {
84 *name_ptr = 0;
85 name_ptr++;
86 }
87
88 if(!strcasecmp(current_line, "gameshark_v1") ||
89 !strcasecmp(current_line, "gameshark_v2") ||
90 !strcasecmp(current_line, "PAR_v1") ||
91 !strcasecmp(current_line, "PAR_v2"))
92 {
93 current_cheat_variant = CHEAT_TYPE_GAMESHARK_V1;
94 }
95 else
96
97 if(!strcasecmp(current_line, "gameshark_v3") ||
98 !strcasecmp(current_line, "PAR_v3"))
99 {
100 current_cheat_variant = CHEAT_TYPE_GAMESHARK_V3;
101 }
102 else
103 {
104 current_cheat_variant = CHEAT_TYPE_INVALID;
105 }
106
107 if(current_cheat_variant != CHEAT_TYPE_INVALID)
108 {
109 strncpy(cheats[num_cheats].cheat_name, name_ptr, CHEAT_NAME_LENGTH - 1);
110 cheats[num_cheats].cheat_name[CHEAT_NAME_LENGTH - 1] = 0;
111 cheat_name_length = strlen(cheats[num_cheats].cheat_name);
112 if(cheat_name_length &&
113 (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\n') ||
114 (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r'))
115 {
116 cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0;
117 cheat_name_length--;
118 }
119
120 if(cheat_name_length &&
121 cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r')
122 {
123 cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0;
124 }
125
126 cheats[num_cheats].cheat_variant = current_cheat_variant;
127 cheat_code_ptr = cheats[num_cheats].cheat_codes;
128 num_cheat_lines = 0;
129
130 while(fgets(current_line, 256, cheats_file))
131 {
132 if(strlen(current_line) < 3)
133 break;
134
135 sscanf(current_line, "%08x %08x", &address, &value);
136
137 decrypt_gsa_code(&address, &value, current_cheat_variant);
138
139 cheat_code_ptr[0] = address;
140 cheat_code_ptr[1] = value;
141
142 cheat_code_ptr += 2;
143 num_cheat_lines++;
144 }
145
146 cheats[num_cheats].num_cheat_lines = num_cheat_lines;
147
148 num_cheats++;
149 }
150 }
151
152 fclose(cheats_file);
153 }
154}
155
156void process_cheat_gs1(cheat_type *cheat)
157{
158 u32 cheat_opcode;
159 u32 *code_ptr = cheat->cheat_codes;
160 u32 address, value;
161 u32 i;
162
163 for(i = 0; i < cheat->num_cheat_lines; i++)
164 {
165 address = code_ptr[0];
166 value = code_ptr[1];
167
168 code_ptr += 2;
169
170 cheat_opcode = address >> 28;
171 address &= 0xFFFFFFF;
172
173 switch(cheat_opcode)
174 {
175 case 0x0:
176 write_memory8(address, value);
177 break;
178
179 case 0x1:
180 write_memory16(address, value);
181 break;
182
183 case 0x2:
184 write_memory32(address, value);
185 break;
186
187 case 0x3:
188 {
189 u32 num_addresses = address & 0xFFFF;
190 u32 address1, address2;
191 u32 i2;
192
193 for(i2 = 0; i2 < num_addresses; i2++)
194 {
195 address1 = code_ptr[0];
196 address2 = code_ptr[1];
197 code_ptr += 2;
198 i++;
199
200 write_memory32(address1, value);
201 if(address2 != 0)
202 write_memory32(address2, value);
203 }
204 break;
205 }
206
207 // ROM patch not supported yet
208 case 0x6:
209 break;
210
211 // GS button down not supported yet
212 case 0x8:
213 break;
214
215 // Reencryption (DEADFACE) not supported yet
216 case 0xD:
217 if(read_memory16(address) != (value & 0xFFFF))
218 {
219 code_ptr += 2;
220 i++;
221 }
222 break;
223
224 case 0xE:
225 if(read_memory16(value & 0xFFFFFFF) != (address & 0xFFFF))
226 {
227 u32 skip = ((address >> 16) & 0x03);
228 code_ptr += skip * 2;
229 i += skip;
230 }
231 break;
232
233 // Hook routine not supported yet (not important??)
234 case 0x0F:
235 break;
236 }
237 }
238}
239
240// These are especially incomplete.
241
242void process_cheat_gs3(cheat_type *cheat)
243{
244 u32 cheat_opcode;
245 u32 *code_ptr = cheat->cheat_codes;
246 u32 address, value;
247 u32 i;
248
249 for(i = 0; i < cheat->num_cheat_lines; i++)
250 {
251 address = code_ptr[0];
252 value = code_ptr[1];
253
254 code_ptr += 2;
255
256 cheat_opcode = address >> 28;
257 address &= 0xFFFFFFF;
258
259 switch(cheat_opcode)
260 {
261 case 0x0:
262 cheat_opcode = address >> 24;
263 address = (address & 0xFFFFF) + ((address << 4) & 0xF000000);
264
265 switch(cheat_opcode)
266 {
267 case 0x0:
268 {
269 u32 iterations = value >> 24;
270 u32 i2;
271
272 value &= 0xFF;
273
274 for(i2 = 0; i2 <= iterations; i2++, address++)
275 {
276 write_memory8(address, value);
277 }
278 break;
279 }
280
281 case 0x2:
282 {
283 u32 iterations = value >> 16;
284 u32 i2;
285
286 value &= 0xFFFF;
287
288 for(i2 = 0; i2 <= iterations; i2++, address += 2)
289 {
290 write_memory16(address, value);
291 }
292 break;
293 }
294
295 case 0x4:
296 write_memory32(address, value);
297 break;
298 }
299 break;
300
301 case 0x4:
302 cheat_opcode = address >> 24;
303 address = (address & 0xFFFFF) + ((address << 4) & 0xF000000);
304
305 switch(cheat_opcode)
306 {
307 case 0x0:
308 address = read_memory32(address) + (value >> 24);
309 write_memory8(address, value & 0xFF);
310 break;
311
312 case 0x2:
313 address = read_memory32(address) + ((value >> 16) * 2);
314 write_memory16(address, value & 0xFFFF);
315 break;
316
317 case 0x4:
318 address = read_memory32(address);
319 write_memory32(address, value);
320 break;
321
322 }
323 break;
324
325 case 0x8:
326 cheat_opcode = address >> 24;
327 address = (address & 0xFFFFF) + ((address << 4) & 0xF000000);
328
329 switch(cheat_opcode)
330 {
331 case 0x0:
332 value = (value & 0xFF) + read_memory8(address);
333 write_memory8(address, value);
334 break;
335
336 case 0x2:
337 value = (value & 0xFFFF) + read_memory16(address);
338 write_memory16(address, value);
339 break;
340
341 case 0x4:
342 value = value + read_memory32(address);
343 write_memory32(address, value);
344 break;
345 }
346 break;
347
348 case 0xC:
349 cheat_opcode = address >> 24;
350 address = (address & 0xFFFFFF) + 0x4000000;
351
352 switch(cheat_opcode)
353 {
354 case 0x6:
355 write_memory16(address, value);
356 break;
357
358 case 0x7:
359 write_memory32(address, value);
360 break;
361 }
362 break;
363 }
364 }
365}
366
367
368void process_cheats()
369{
370 u32 i;
371
372 for(i = 0; i < num_cheats; i++)
373 {
374 if(cheats[i].cheat_active)
375 {
376 switch(cheats[i].cheat_variant)
377 {
378 case CHEAT_TYPE_GAMESHARK_V1:
379 process_cheat_gs1(cheats + i);
380 break;
381
382 case CHEAT_TYPE_GAMESHARK_V3:
383 process_cheat_gs3(cheats + i);
384 break;
385 }
386 }
387 }
388}