1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - cheat.c *
3 * Mupen64Plus homepage: https://mupen64plus.org/ *
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#define __STDC_FORMAT_MACROS
29#include <inttypes.h>
30
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include "cheat.h"
37#include "eventloop.h"
38#include "list.h"
39
40#include "api/callbacks.h"
41#include "api/m64p_types.h"
42#include "device/r4300/r4300_core.h"
43#include "device/rdram/rdram.h"
44#include "osal/preproc.h"
45
46/* local definitions */
47#define CHEAT_CODE_MAGIC_VALUE UINT32_C(0xDEAD0000)
48
49typedef struct cheat_code {
50 uint32_t address;
51 uint32_t value;
52 uint32_t old_value;
53 struct list_head list;
54} cheat_code_t;
55
56typedef struct cheat {
57 char *name;
58 int enabled;
59 int was_enabled;
60 struct list_head cheat_codes;
61 struct list_head list;
62} cheat_t;
63
64/* private functions */
65static uint16_t read_address_16bit(struct r4300_core* r4300, uint32_t address)
66{
67 return *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16)));
68}
69
70static uint8_t read_address_8bit(struct r4300_core* r4300, uint32_t address)
71{
72 return *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8)));
73}
74
75static void update_address_16bit(struct r4300_core* r4300, uint32_t address, uint16_t new_value)
76{
77 *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))) = new_value;
78 /* mask out bit 24 which is used by GS codes to specify 8/16 bits */
79 address &= 0xfeffffff;
80 invalidate_r4300_cached_code(r4300, address, 2);
81}
82
83static void update_address_8bit(struct r4300_core* r4300, uint32_t address, uint8_t new_value)
84{
85 *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))) = new_value;
86 invalidate_r4300_cached_code(r4300, address, 1);
87}
88
89static int address_equal_to_8bit(struct r4300_core* r4300, uint32_t address, uint8_t value)
90{
91 uint8_t value_read;
92 value_read = *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8)));
93 return value_read == value;
94}
95
96static int address_equal_to_16bit(struct r4300_core* r4300, uint32_t address, uint16_t value)
97{
98 uint16_t value_read;
99 value_read = *(unsigned short *)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16)));
100 return value_read == value;
101}
102
103/* individual application - returns 0 if we are supposed to skip the next cheat
104 * (only really used on conditional codes)
105 */
106static int execute_cheat(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t* old_value)
107{
108 switch (address & 0xFF000000)
109 {
110 case 0x80000000:
111 case 0x88000000:
112 case 0xA0000000:
113 case 0xA8000000:
114 case 0xF0000000:
115 /* if pointer to old value is valid and uninitialized, write current value to it */
116 if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) {
117 *old_value = read_address_8bit(r4300, address);
118 }
119 update_address_8bit(r4300, address, (uint8_t)value);
120 return 1;
121 case 0x81000000:
122 case 0x89000000:
123 case 0xA1000000:
124 case 0xA9000000:
125 case 0xF1000000:
126 /* if pointer to old value is valid and uninitialized, write current value to it */
127 if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) {
128 *old_value = read_address_16bit(r4300, address);
129 }
130 update_address_16bit(r4300, address, (uint16_t)value);
131 return 1;
132 case 0xD0000000:
133 case 0xD8000000:
134 return address_equal_to_8bit(r4300, address, (uint8_t)value);
135 case 0xD1000000:
136 case 0xD9000000:
137 return address_equal_to_16bit(r4300, address, (uint16_t)value);
138 case 0xD2000000:
139 case 0xDB000000:
140 return !(address_equal_to_8bit(r4300, address, (uint8_t)value));
141 case 0xD3000000:
142 case 0xDA000000:
143 return !(address_equal_to_16bit(r4300, address, (uint16_t)value));
144 case 0xEE000000:
145 /* most likely, this doesnt do anything. */
146 execute_cheat(r4300, 0xF1000318, 0x0040, NULL);
147 execute_cheat(r4300, 0xF100031A, 0x0000, NULL);
148 return 1;
149 default:
150 return 1;
151 }
152}
153
154static cheat_t *find_or_create_cheat(struct cheat_ctx* ctx, const char *name)
155{
156 cheat_t *cheat;
157 int found = 0;
158
159 list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) {
160 if (strcmp(cheat->name, name) == 0) {
161 found = 1;
162 break;
163 }
164 }
165
166 if (found)
167 {
168 /* delete any pre-existing cheat codes */
169 cheat_code_t *code, *safe;
170
171 list_for_each_entry_safe_t(code, safe, &cheat->cheat_codes, cheat_code_t, list) {
172 list_del(&code->list);
173 free(code);
174 }
175
176 cheat->enabled = 0;
177 cheat->was_enabled = 0;
178 }
179 else
180 {
181 cheat = malloc(sizeof(*cheat));
182 cheat->name = strdup(name);
183 cheat->enabled = 0;
184 cheat->was_enabled = 0;
185 INIT_LIST_HEAD(&cheat->cheat_codes);
186 list_add_tail(&cheat->list, &ctx->active_cheats);
187 }
188
189 return cheat;
190}
191
192
193/* public functions */
194void cheat_init(struct cheat_ctx* ctx)
195{
196 ctx->mutex = SDL_CreateMutex();
197 INIT_LIST_HEAD(&ctx->active_cheats);
198}
199
200void cheat_uninit(struct cheat_ctx* ctx)
201{
202 if (ctx->mutex != NULL) {
203 SDL_DestroyMutex(ctx->mutex);
204 }
205 ctx->mutex = NULL;
206}
207
208void cheat_apply_cheats(struct cheat_ctx* ctx, struct r4300_core* r4300, int entry)
209{
210 cheat_t *cheat;
211 cheat_code_t *code;
212 int cond_failed;
213
214 if (list_empty(&ctx->active_cheats))
215 return;
216
217 if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0)
218 {
219 DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_apply_cheats()");
220 return;
221 }
222
223 list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) {
224 if (cheat->enabled)
225 {
226 cheat->was_enabled = 1;
227 switch(entry)
228 {
229 case ENTRY_BOOT:
230 list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) {
231 /* code should only be written once at boot time */
232 if ((code->address & 0xF0000000) == 0xF0000000) {
233 execute_cheat(r4300, code->address, code->value, &code->old_value);
234 }
235 }
236 break;
237 case ENTRY_VI:
238 /* a cheat starts without failed preconditions */
239 cond_failed = 0;
240
241 list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) {
242 /* conditional cheat codes */
243 if ((code->address & 0xF0000000) == 0xD0000000)
244 {
245 /* if code needs GS button pressed and it's not, skip it */
246 if (((code->address & 0xFF000000) == 0xD8000000 ||
247 (code->address & 0xFF000000) == 0xD9000000 ||
248 (code->address & 0xFF000000) == 0xDA000000 ||
249 (code->address & 0xFF000000) == 0xDB000000) &&
250 !event_gameshark_active()) {
251 /* if condition false, skip next code non-test code */
252 cond_failed = 1;
253 }
254
255 /* if condition false, skip next code non-test code */
256 if (!execute_cheat(r4300, code->address, code->value, NULL)) {
257 cond_failed = 1;
258 }
259 }
260 else {
261 /* preconditions were false for this non-test code
262 * reset the condition state and skip the cheat
263 */
264 if (cond_failed) {
265 cond_failed = 0;
266 continue;
267 }
268
269 switch (code->address & 0xFF000000) {
270 /* GS button triggers cheat code */
271 case 0x88000000:
272 case 0x89000000:
273 case 0xA8000000:
274 case 0xA9000000:
275 if (event_gameshark_active()) {
276 execute_cheat(r4300, code->address, code->value, NULL);
277 }
278 break;
279 /* normal cheat code */
280 default:
281 /* exclude boot-time cheat codes */
282 if ((code->address & 0xF0000000) != 0xF0000000) {
283 execute_cheat(r4300, code->address, code->value, &code->old_value);
284 }
285 break;
286 }
287 }
288 }
289 break;
290 default:
291 break;
292 }
293 }
294 /* if cheat was enabled, but is now disabled, restore old memory values */
295 else if (cheat->was_enabled)
296 {
297 cheat->was_enabled = 0;
298 switch(entry)
299 {
300 case ENTRY_VI:
301 list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) {
302 /* set memory back to old value and clear saved copy of old value */
303 if(code->old_value != CHEAT_CODE_MAGIC_VALUE)
304 {
305 execute_cheat(r4300, code->address, code->old_value, NULL);
306 code->old_value = CHEAT_CODE_MAGIC_VALUE;
307 }
308 }
309 break;
310 default:
311 break;
312 }
313 }
314 }
315
316 SDL_UnlockMutex(ctx->mutex);
317}
318
319
320void cheat_delete_all(struct cheat_ctx* ctx)
321{
322 cheat_t *cheat, *safe_cheat;
323 cheat_code_t *code, *safe_code;
324
325 if (list_empty(&ctx->active_cheats))
326 return;
327
328 if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0)
329 {
330 DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_delete_all()");
331 return;
332 }
333
334 list_for_each_entry_safe_t(cheat, safe_cheat, &ctx->active_cheats, cheat_t, list) {
335 free(cheat->name);
336
337 list_for_each_entry_safe_t(code, safe_code, &cheat->cheat_codes, cheat_code_t, list) {
338 list_del(&code->list);
339 free(code);
340 }
341 list_del(&cheat->list);
342 free(cheat);
343 }
344
345 SDL_UnlockMutex(ctx->mutex);
346}
347
348int cheat_set_enabled(struct cheat_ctx* ctx, const char* name, int enabled)
349{
350 cheat_t *cheat = NULL;
351
352 if (list_empty(&ctx->active_cheats))
353 return 0;
354
355 if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0)
356 {
357 DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_set_enabled()");
358 return 0;
359 }
360
361 list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) {
362 if (strcmp(name, cheat->name) == 0)
363 {
364 cheat->enabled = enabled;
365 SDL_UnlockMutex(ctx->mutex);
366 return 1;
367 }
368 }
369
370 SDL_UnlockMutex(ctx->mutex);
371 return 0;
372}
373
374int cheat_add_new(struct cheat_ctx* ctx, const char* name, m64p_cheat_code* code_list, int num_codes)
375{
376 cheat_t *cheat;
377 int i, j;
378
379 if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0)
380 {
381 DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_add_new()");
382 return 0;
383 }
384
385 /* create a new cheat function or erase the codes in an existing cheat function */
386 cheat = find_or_create_cheat(ctx, name);
387 if (cheat == NULL)
388 {
389 SDL_UnlockMutex(ctx->mutex);
390 return 0;
391 }
392
393 /* default for new cheats is enabled */
394 cheat->enabled = 1;
395
396 for (i = 0; i < num_codes; i++)
397 {
398 /* if this is a 'patch' code, convert it and dump out all of the individual codes */
399 if ((code_list[i].address & 0xFFFF0000) == 0x50000000 && i < num_codes - 1)
400 {
401 int code_count = ((code_list[i].address & 0xFF00) >> 8);
402 int incr_addr = code_list[i].address & 0xFF;
403 int incr_value = code_list[i].value;
404 int cur_addr = code_list[i+1].address;
405 int cur_value = code_list[i+1].value;
406 i += 1;
407 for (j = 0; j < code_count; j++)
408 {
409 cheat_code_t *code = malloc(sizeof(*code));
410 code->address = cur_addr;
411 code->value = cur_value;
412 code->old_value = CHEAT_CODE_MAGIC_VALUE;
413 list_add_tail(&code->list, &cheat->cheat_codes);
414 cur_addr += incr_addr;
415 cur_value += incr_value;
416 }
417 }
418 else
419 {
420 /* just a normal code */
421 cheat_code_t *code = malloc(sizeof(*code));
422 code->address = code_list[i].address;
423 code->value = code_list[i].value;
424 code->old_value = CHEAT_CODE_MAGIC_VALUE;
425 list_add_tail(&code->list, &cheat->cheat_codes);
426 }
427 }
428
429 SDL_UnlockMutex(ctx->mutex);
430 return 1;
431}
432
433static char *strtok_compat(char *str, const char *delim, char **saveptr)
434{
435 char *p;
436
437 if (str == NULL)
438 str = *saveptr;
439
440 if (str == NULL)
441 return NULL;
442
443 str += strspn(str, delim);
444 if ((p = strpbrk(str, delim)) != NULL) {
445 *saveptr = p + 1;
446 *p = '\0';
447 } else {
448 *saveptr = NULL;
449 }
450 return str;
451}
452
453static int cheat_parse_hacks_code(char *code, m64p_cheat_code **hack)
454{
455 char *saveptr = NULL;
456 char *input, *token;
457 int num_codes;
458 m64p_cheat_code *hackbuf;
459 int ret;
460
461 *hack = NULL;
462
463 /* count number of possible cheatcodes */
464 input = code;
465 num_codes = 0;
466 while ((strchr(input, ','))) {
467 input++;
468 num_codes++;
469 }
470 num_codes++;
471
472 /* allocate buffer */
473 hackbuf = malloc(sizeof(*hackbuf) * num_codes);
474 if (!hackbuf)
475 return 0;
476
477 /* parse cheatcodes */
478 input = code;
479 num_codes = 0;
480 while ((token = strtok_compat(input, ",", &saveptr))) {
481 input = NULL;
482
483 ret = sscanf(token, "%08" SCNx32 " %04X", &hackbuf[num_codes].address,
484 (unsigned int*)&hackbuf[num_codes].value);
485 if (ret == 2)
486 num_codes++;
487 }
488
489 if (num_codes == 0)
490 free(hackbuf);
491 else
492 *hack = hackbuf;
493
494 return num_codes;
495}
496
497int cheat_add_hacks(struct cheat_ctx* ctx, const char* rom_cheats)
498{
499 char *cheat_raw = NULL;
500 char *saveptr = NULL;
501 char *input, *token;
502 unsigned int i = 0;
503 int num_codes;
504 char cheatname[32];
505 m64p_cheat_code *hack;
506
507 if (!rom_cheats)
508 return 0;
509
510 /* copy ini entry for tokenizing */
511 cheat_raw = strdup(rom_cheats);
512 if (!cheat_raw)
513 goto out;
514
515 /* split into cheats for the cheat engine */
516 input = cheat_raw;
517 while ((token = strtok_compat(input, ";", &saveptr))) {
518 input = NULL;
519
520 snprintf(cheatname, sizeof(cheatname), "HACK%u", i);
521 cheatname[sizeof(cheatname) - 1] = '\0';
522
523 /* parse and add cheat */
524 num_codes = cheat_parse_hacks_code(token, &hack);
525 if (num_codes <= 0)
526 continue;
527
528 cheat_add_new(ctx, cheatname, hack, num_codes);
529 free(hack);
530 i++;
531 }
532
533out:
534 free(cheat_raw);
535 return 0;
536}
537