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 | |
22 | cheat_type cheats[MAX_CHEATS]; |
23 | u32 num_cheats; |
24 | |
25 | void 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 | |
61 | void 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 | |
156 | void 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 | |
242 | void 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 | |
368 | void 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 | } |