Add copyright message to gles_video
[gpsp.git] / cheats.c
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;
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(char *cheats_filename)
62 {
63   FILE *cheats_file;
64   char current_line[256];
65   char *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         default:
387           break;
388       }
389     }
390   }
391 }