451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - cheat.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2009 Richard Goedeken * |
5 | * Copyright (C) 2008 Okaygo * |
6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * |
9 | * the Free Software Foundation; either version 2 of the License, or * |
10 | * (at your option) any later version. * |
11 | * * |
12 | * This program is distributed in the hope that it will be useful, * |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
15 | * GNU General Public License for more details. * |
16 | * * |
17 | * You should have received a copy of the GNU General Public License * |
18 | * along with this program; if not, write to the * |
19 | * Free Software Foundation, Inc., * |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
22 | |
23 | // gameshark and xploder64 reference: http://doc.kodewerx.net/hacking_n64.html |
24 | |
25 | #include <SDL.h> |
26 | #include <SDL_thread.h> |
27 | |
28 | #include "api/m64p_types.h" |
29 | #include "api/callbacks.h" |
30 | #include "api/config.h" |
31 | |
32 | #include "memory/memory.h" |
33 | #include "osal/preproc.h" |
34 | #include "cheat.h" |
35 | #include "main.h" |
36 | #include "rom.h" |
37 | #include "eventloop.h" |
38 | #include "list.h" |
39 | |
40 | #include <stdio.h> |
41 | #include <string.h> |
42 | |
43 | // local definitions |
44 | #define CHEAT_CODE_MAGIC_VALUE 0xDEAD0000 |
45 | |
46 | typedef struct cheat_code { |
47 | unsigned int address; |
48 | int value; |
49 | int old_value; |
50 | struct list_head list; |
51 | } cheat_code_t; |
52 | |
53 | typedef struct cheat { |
54 | char *name; |
55 | int enabled; |
56 | int was_enabled; |
57 | struct list_head cheat_codes; |
58 | struct list_head list; |
59 | } cheat_t; |
60 | |
61 | // local variables |
62 | static LIST_HEAD(active_cheats); |
63 | static SDL_mutex *cheat_mutex = NULL; |
64 | |
65 | // private functions |
66 | static unsigned short read_address_16bit(unsigned int address) |
67 | { |
68 | return *(unsigned short *)((rdramb + ((address & 0xFFFFFF)^S16))); |
69 | } |
70 | |
71 | static unsigned char read_address_8bit(unsigned int address) |
72 | { |
73 | return *(unsigned char *)((rdramb + ((address & 0xFFFFFF)^S8))); |
74 | } |
75 | |
76 | static void update_address_16bit(unsigned int address, unsigned short new_value) |
77 | { |
78 | *(unsigned short *)((rdramb + ((address & 0xFFFFFF)^S16))) = new_value; |
79 | } |
80 | |
81 | static void update_address_8bit(unsigned int address, unsigned char new_value) |
82 | { |
83 | *(unsigned char *)((rdramb + ((address & 0xFFFFFF)^S8))) = new_value; |
84 | } |
85 | |
86 | static int address_equal_to_8bit(unsigned int address, unsigned char value) |
87 | { |
88 | unsigned char value_read; |
89 | value_read = *(unsigned char *)((rdramb + ((address & 0xFFFFFF)^S8))); |
90 | return value_read == value; |
91 | } |
92 | |
93 | static int address_equal_to_16bit(unsigned int address, unsigned short value) |
94 | { |
95 | unsigned short value_read; |
96 | value_read = *(unsigned short *)((rdramb + ((address & 0xFFFFFF)^S16))); |
97 | return value_read == value; |
98 | } |
99 | |
100 | // individual application - returns 0 if we are supposed to skip the next cheat |
101 | // (only really used on conditional codes) |
102 | static int execute_cheat(unsigned int address, unsigned short value, int *old_value) |
103 | { |
104 | switch (address & 0xFF000000) |
105 | { |
106 | case 0x80000000: |
107 | case 0x88000000: |
108 | case 0xA0000000: |
109 | case 0xA8000000: |
110 | case 0xF0000000: |
111 | // if pointer to old value is valid and uninitialized, write current value to it |
112 | if(old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) |
113 | *old_value = (int) read_address_8bit(address); |
114 | update_address_8bit(address,(unsigned char) value); |
115 | return 1; |
116 | case 0x81000000: |
117 | case 0x89000000: |
118 | case 0xA1000000: |
119 | case 0xA9000000: |
120 | case 0xF1000000: |
121 | // if pointer to old value is valid and uninitialized, write current value to it |
122 | if(old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) |
123 | *old_value = (int) read_address_16bit(address); |
124 | update_address_16bit(address,value); |
125 | return 1; |
126 | case 0xD0000000: |
127 | case 0xD8000000: |
128 | return address_equal_to_8bit(address,(unsigned char) value); |
129 | case 0xD1000000: |
130 | case 0xD9000000: |
131 | return address_equal_to_16bit(address,value); |
132 | case 0xD2000000: |
133 | case 0xDB000000: |
134 | return !(address_equal_to_8bit(address,(unsigned char) value)); |
135 | case 0xD3000000: |
136 | case 0xDA000000: |
137 | return !(address_equal_to_16bit(address,value)); |
138 | case 0xEE000000: |
139 | // most likely, this doesnt do anything. |
140 | execute_cheat(0xF1000318, 0x0040, NULL); |
141 | execute_cheat(0xF100031A, 0x0000, NULL); |
142 | return 1; |
143 | default: |
144 | return 1; |
145 | } |
146 | } |
147 | |
148 | static cheat_t *find_or_create_cheat(const char *name) |
149 | { |
150 | cheat_t *cheat; |
151 | int found = 0; |
152 | |
153 | list_for_each_entry(cheat, &active_cheats, cheat_t, list) { |
154 | if (strcmp(cheat->name, name) == 0) { |
155 | found = 1; |
156 | break; |
157 | } |
158 | } |
159 | |
160 | if (found) |
161 | { |
162 | /* delete any pre-existing cheat codes */ |
163 | cheat_code_t *code, *safe; |
164 | |
165 | list_for_each_entry_safe(code, safe, &cheat->cheat_codes, cheat_code_t, list) { |
166 | list_del(&code->list); |
167 | free(code); |
168 | } |
169 | |
170 | cheat->enabled = 0; |
171 | cheat->was_enabled = 0; |
172 | } |
173 | else |
174 | { |
175 | cheat = malloc(sizeof(*cheat)); |
176 | cheat->name = strdup(name); |
177 | cheat->enabled = 0; |
178 | cheat->was_enabled = 0; |
179 | INIT_LIST_HEAD(&cheat->cheat_codes); |
180 | list_add_tail(&cheat->list, &active_cheats); |
181 | } |
182 | |
183 | return cheat; |
184 | } |
185 | |
186 | |
187 | // public functions |
188 | void cheat_init(void) |
189 | { |
190 | cheat_mutex = SDL_CreateMutex(); |
191 | } |
192 | |
193 | void cheat_uninit(void) |
194 | { |
195 | if (cheat_mutex != NULL) |
196 | SDL_DestroyMutex(cheat_mutex); |
197 | cheat_mutex = NULL; |
198 | } |
199 | |
200 | void cheat_apply_cheats(int entry) |
201 | { |
202 | cheat_t *cheat; |
203 | cheat_code_t *code; |
204 | int skip; |
205 | int execute_next; |
206 | |
207 | // If game is Zelda OOT, apply subscreen delay fix |
208 | if (strncmp((char *)ROM_HEADER.Name, "THE LEGEND OF ZELDA", 19) == 0 && entry == ENTRY_VI) { |
209 | if (sl(ROM_HEADER.CRC1) == 0xEC7011B7 && sl(ROM_HEADER.CRC2) == 0x7616D72B) { |
210 | // Legend of Zelda, The - Ocarina of Time (U) + (J) (V1.0) |
211 | execute_cheat(0x801DA5CB, 0x0002, NULL); |
212 | } else if (sl(ROM_HEADER.CRC1) == 0xD43DA81F && sl(ROM_HEADER.CRC2) == 0x021E1E19) { |
213 | // Legend of Zelda, The - Ocarina of Time (U) + (J) (V1.1) |
214 | execute_cheat(0x801DA78B, 0x0002, NULL); |
215 | } else if (sl(ROM_HEADER.CRC1) == 0x693BA2AE && sl(ROM_HEADER.CRC2) == 0xB7F14E9F) { |
216 | // Legend of Zelda, The - Ocarina of Time (U) + (J) (V1.2) |
217 | execute_cheat(0x801DAE8B, 0x0002, NULL); |
218 | } else if (sl(ROM_HEADER.CRC1) == 0xB044B569 && sl(ROM_HEADER.CRC2) == 0x373C1985) { |
219 | // Legend of Zelda, The - Ocarina of Time (E) (V1.0) |
220 | execute_cheat(0x801D860B, 0x0002, NULL); |
221 | } else if (sl(ROM_HEADER.CRC1) == 0xB2055FBD && sl(ROM_HEADER.CRC2) == 0x0BAB4E0C) { |
222 | // Legend of Zelda, The - Ocarina of Time (E) (V1.1) |
223 | execute_cheat(0x801D864B, 0x0002, NULL); |
224 | } else { |
225 | // Legend of Zelda, The - Ocarina of Time Master Quest |
226 | execute_cheat(0x801D8F4B, 0x0002, NULL); |
227 | } |
228 | } |
229 | |
230 | if (list_empty(&active_cheats)) |
231 | return; |
232 | |
233 | if (cheat_mutex == NULL || SDL_LockMutex(cheat_mutex) != 0) |
234 | { |
235 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_apply_cheats()"); |
236 | return; |
237 | } |
238 | |
239 | list_for_each_entry(cheat, &active_cheats, cheat_t, list) { |
240 | if (cheat->enabled) |
241 | { |
242 | cheat->was_enabled = 1; |
243 | switch(entry) |
244 | { |
245 | case ENTRY_BOOT: |
246 | list_for_each_entry(code, &cheat->cheat_codes, cheat_code_t, list) { |
247 | // code should only be written once at boot time |
248 | if((code->address & 0xF0000000) == 0xF0000000) |
249 | execute_cheat(code->address, code->value, &code->old_value); |
250 | } |
251 | break; |
252 | case ENTRY_VI: |
253 | skip = 0; |
254 | execute_next = 0; |
255 | list_for_each_entry(code, &cheat->cheat_codes, cheat_code_t, list) { |
256 | if (skip) { |
257 | skip = 0; |
258 | continue; |
259 | } |
260 | if (execute_next) { |
261 | execute_next = 0; |
262 | |
263 | // if code needs GS button pressed, don't save old value |
264 | if(((code->address & 0xFF000000) == 0xD8000000 || |
265 | (code->address & 0xFF000000) == 0xD9000000 || |
266 | (code->address & 0xFF000000) == 0xDA000000 || |
267 | (code->address & 0xFF000000) == 0xDB000000)) |
268 | execute_cheat(code->address, code->value, NULL); |
269 | else |
270 | execute_cheat(code->address, code->value, &code->old_value); |
271 | |
272 | continue; |
273 | } |
274 | // conditional cheat codes |
275 | if((code->address & 0xF0000000) == 0xD0000000) |
276 | { |
277 | // if code needs GS button pressed and it's not, skip it |
278 | if(((code->address & 0xFF000000) == 0xD8000000 || |
279 | (code->address & 0xFF000000) == 0xD9000000 || |
280 | (code->address & 0xFF000000) == 0xDA000000 || |
281 | (code->address & 0xFF000000) == 0xDB000000) && |
282 | !event_gameshark_active()) |
283 | { |
284 | // skip next code |
285 | skip = 1; |
286 | continue; |
287 | } |
288 | |
289 | if (execute_cheat(code->address, code->value, NULL)) { |
290 | // if condition true, execute next cheat code |
291 | execute_next = 1; |
292 | } else { |
293 | // if condition false, skip next code |
294 | skip = 1; |
295 | continue; |
296 | } |
297 | } |
298 | // GS button triggers cheat code |
299 | else if((code->address & 0xFF000000) == 0x88000000 || |
300 | (code->address & 0xFF000000) == 0x89000000 || |
301 | (code->address & 0xFF000000) == 0xA8000000 || |
302 | (code->address & 0xFF000000) == 0xA9000000) |
303 | { |
304 | if(event_gameshark_active()) |
305 | execute_cheat(code->address, code->value, NULL); |
306 | } |
307 | // normal cheat code |
308 | else |
309 | { |
310 | // exclude boot-time cheat codes |
311 | if((code->address & 0xF0000000) != 0xF0000000) |
312 | execute_cheat(code->address, code->value, &code->old_value); |
313 | } |
314 | } |
315 | break; |
316 | default: |
317 | break; |
318 | } |
319 | } |
320 | // if cheat was enabled, but is now disabled, restore old memory values |
321 | else if (cheat->was_enabled) |
322 | { |
323 | cheat->was_enabled = 0; |
324 | switch(entry) |
325 | { |
326 | case ENTRY_VI: |
327 | list_for_each_entry(code, &cheat->cheat_codes, cheat_code_t, list) { |
328 | // set memory back to old value and clear saved copy of old value |
329 | if(code->old_value != CHEAT_CODE_MAGIC_VALUE) |
330 | { |
331 | execute_cheat(code->address, code->old_value, NULL); |
332 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
333 | } |
334 | } |
335 | break; |
336 | default: |
337 | break; |
338 | } |
339 | } |
340 | } |
341 | |
342 | SDL_UnlockMutex(cheat_mutex); |
343 | } |
344 | |
345 | |
346 | void cheat_delete_all(void) |
347 | { |
348 | cheat_t *cheat, *safe_cheat; |
349 | cheat_code_t *code, *safe_code; |
350 | |
351 | if (list_empty(&active_cheats)) |
352 | return; |
353 | |
354 | if (cheat_mutex == NULL || SDL_LockMutex(cheat_mutex) != 0) |
355 | { |
356 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_delete_all()"); |
357 | return; |
358 | } |
359 | |
360 | list_for_each_entry_safe(cheat, safe_cheat, &active_cheats, cheat_t, list) { |
361 | free(cheat->name); |
362 | |
363 | list_for_each_entry_safe(code, safe_code, &cheat->cheat_codes, cheat_code_t, list) { |
364 | list_del(&code->list); |
365 | free(code); |
366 | } |
367 | list_del(&cheat->list); |
368 | free(cheat); |
369 | } |
370 | |
371 | SDL_UnlockMutex(cheat_mutex); |
372 | } |
373 | |
374 | int cheat_set_enabled(const char *name, int enabled) |
375 | { |
376 | cheat_t *cheat = NULL; |
377 | |
378 | if (list_empty(&active_cheats)) |
379 | return 0; |
380 | |
381 | if (cheat_mutex == NULL || SDL_LockMutex(cheat_mutex) != 0) |
382 | { |
383 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_set_enabled()"); |
384 | return 0; |
385 | } |
386 | |
387 | list_for_each_entry(cheat, &active_cheats, cheat_t, list) { |
388 | if (strcmp(name, cheat->name) == 0) |
389 | { |
390 | cheat->enabled = enabled; |
391 | SDL_UnlockMutex(cheat_mutex); |
392 | return 1; |
393 | } |
394 | } |
395 | |
396 | SDL_UnlockMutex(cheat_mutex); |
397 | return 0; |
398 | } |
399 | |
400 | int cheat_add_new(const char *name, m64p_cheat_code *code_list, int num_codes) |
401 | { |
402 | cheat_t *cheat; |
403 | int i, j; |
404 | |
405 | if (cheat_mutex == NULL || SDL_LockMutex(cheat_mutex) != 0) |
406 | { |
407 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_add_new()"); |
408 | return 0; |
409 | } |
410 | |
411 | /* create a new cheat function or erase the codes in an existing cheat function */ |
412 | cheat = find_or_create_cheat(name); |
413 | if (cheat == NULL) |
414 | { |
415 | SDL_UnlockMutex(cheat_mutex); |
416 | return 0; |
417 | } |
418 | |
419 | cheat->enabled = 1; /* default for new cheats is enabled */ |
420 | |
421 | for (i = 0; i < num_codes; i++) |
422 | { |
423 | /* if this is a 'patch' code, convert it and dump out all of the individual codes */ |
424 | if ((code_list[i].address & 0xFFFF0000) == 0x50000000 && i < num_codes - 1) |
425 | { |
426 | int code_count = ((code_list[i].address & 0xFF00) >> 8); |
427 | int incr_addr = code_list[i].address & 0xFF; |
428 | int incr_value = code_list[i].value; |
429 | int cur_addr = code_list[i+1].address; |
430 | int cur_value = code_list[i+1].value; |
431 | i += 1; |
432 | for (j = 0; j < code_count; j++) |
433 | { |
434 | cheat_code_t *code = malloc(sizeof(*code)); |
435 | code->address = cur_addr; |
436 | code->value = cur_value; |
437 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
438 | list_add_tail(&code->list, &cheat->cheat_codes); |
439 | cur_addr += incr_addr; |
440 | cur_value += incr_value; |
441 | } |
442 | } |
443 | else |
444 | { /* just a normal code */ |
445 | cheat_code_t *code = malloc(sizeof(*code)); |
446 | code->address = code_list[i].address; |
447 | code->value = code_list[i].value; |
448 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
449 | list_add_tail(&code->list, &cheat->cheat_codes); |
450 | } |
451 | } |
452 | |
453 | SDL_UnlockMutex(cheat_mutex); |
454 | return 1; |
455 | } |
456 | |
457 | |