src/gba/cheats/codebreaker.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "gba/cheats.h"
7
8#include "gba/cheats/cheats-private.h"
9#include "gba/gba.h"
10#include "gba/io.h"
11#include "util/string.h"
12
13bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
14 char line[14] = "XXXXXXXX XXXX";
15 snprintf(line, sizeof(line), "%08X %04X", op1, op2);
16 GBACheatRegisterLine(cheats, line);
17
18 enum GBACodeBreakerType type = op1 >> 28;
19 struct GBACheat* cheat = 0;
20
21 if (cheats->incompleteCheat) {
22 cheats->incompleteCheat->repeat = op1 & 0xFFFF;
23 cheats->incompleteCheat->addressOffset = op2;
24 cheats->incompleteCheat->operandOffset = 0;
25 cheats->incompleteCheat = 0;
26 return true;
27 }
28
29 switch (type) {
30 case CB_GAME_ID:
31 // TODO: Run checksum
32 return true;
33 case CB_HOOK:
34 if (cheats->hook) {
35 return false;
36 }
37 cheats->hook = malloc(sizeof(*cheats->hook));
38 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
39 cheats->hook->mode = MODE_THUMB;
40 cheats->hook->refs = 1;
41 cheats->hook->reentries = 0;
42 return true;
43 case CB_OR_2:
44 cheat = GBACheatListAppend(&cheats->list);
45 cheat->type = CHEAT_OR;
46 cheat->width = 2;
47 break;
48 case CB_ASSIGN_1:
49 cheat = GBACheatListAppend(&cheats->list);
50 cheat->type = CHEAT_ASSIGN;
51 cheat->width = 1;
52 break;
53 case CB_FILL:
54 cheat = GBACheatListAppend(&cheats->list);
55 cheat->type = CHEAT_ASSIGN;
56 cheat->width = 2;
57 cheats->incompleteCheat = cheat;
58 break;
59 case CB_FILL_8:
60 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
61 return false;
62 case CB_AND_2:
63 cheat = GBACheatListAppend(&cheats->list);
64 cheat->type = CHEAT_AND;
65 cheat->width = 2;
66 break;
67 case CB_IF_EQ:
68 cheat = GBACheatListAppend(&cheats->list);
69 cheat->type = CHEAT_IF_EQ;
70 cheat->width = 2;
71 break;
72 case CB_ASSIGN_2:
73 cheat = GBACheatListAppend(&cheats->list);
74 cheat->type = CHEAT_ASSIGN;
75 cheat->width = 2;
76 break;
77 case CB_ENCRYPT:
78 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
79 return false;
80 case CB_IF_NE:
81 cheat = GBACheatListAppend(&cheats->list);
82 cheat->type = CHEAT_IF_NE;
83 cheat->width = 2;
84 break;
85 case CB_IF_GT:
86 cheat = GBACheatListAppend(&cheats->list);
87 cheat->type = CHEAT_IF_GT;
88 cheat->width = 2;
89 break;
90 case CB_IF_LT:
91 cheat = GBACheatListAppend(&cheats->list);
92 cheat->type = CHEAT_IF_LT;
93 cheat->width = 2;
94 break;
95 case CB_IF_SPECIAL:
96 switch (op1 & 0x0FFFFFFF) {
97 case 0x20:
98 cheat = GBACheatListAppend(&cheats->list);
99 cheat->type = CHEAT_IF_AND;
100 cheat->width = 2;
101 cheat->address = BASE_IO | REG_JOYSTAT;
102 cheat->operand = op2;
103 cheat->repeat = 1;
104 return true;
105 default:
106 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
107 return false;
108 }
109 case CB_ADD_2:
110 cheat = GBACheatListAppend(&cheats->list);
111 cheat->type = CHEAT_ADD;
112 cheat->width = 2;
113 break;
114 case CB_IF_AND:
115 cheat = GBACheatListAppend(&cheats->list);
116 cheat->type = CHEAT_IF_AND;
117 cheat->width = 2;
118 break;
119 }
120
121 cheat->address = op1 & 0x0FFFFFFF;
122 cheat->operand = op2;
123 cheat->repeat = 1;
124 cheat->negativeRepeat = 0;
125 return true;
126}
127
128bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
129 uint32_t op1;
130 uint16_t op2;
131 line = hex32(line, &op1);
132 if (!line) {
133 return false;
134 }
135 while (*line == ' ') {
136 ++line;
137 }
138 line = hex16(line, &op2);
139 if (!line) {
140 return false;
141 }
142 return GBACheatAddCodeBreaker(cheats, op1, op2);
143}