1 /*
2 * Nestopia UE
3 *
4 * Copyright (C) 2012-2018 R. Danbrook
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 *
21 */
22
23 #include <cstdlib>
24 #include <iostream>
25 #include <fstream>
26
27 #include "cheats.h"
28
29 static Xml savexml;
30 static Xml::Node saveroot;
31
32 std::vector<NstCheat> chtlist;
33
34 extern Emulator emulator;
35
nst_cheats_init(const char * cheatpath)36 void nst_cheats_init(const char *cheatpath) {
37 // Initialize cheat engine
38 Cheats cheats(emulator);
39 Xml xml;
40
41 cheats.ClearCodes();
42
43 std::ifstream cheatfile(cheatpath, std::ifstream::in|std::ifstream::binary);
44
45 if (cheatfile.is_open()) {
46 xml.Read(cheatfile);
47
48 if (xml.GetRoot().IsType(L"cheats")) {
49
50 Xml::Node root(xml.GetRoot());
51 Xml::Node node(root.GetFirstChild());
52
53 for (int i = 0; i < root.NumChildren(L"cheat"); i++) {
54
55 if (node.GetAttribute(L"enabled").IsValue(L"1")) {
56
57 if (node.GetChild(L"genie")) { // Game Genie
58 nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue());
59 }
60
61 else if (node.GetChild(L"rocky")) { // Pro Action Rocky
62 nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue());
63 }
64
65 else if (node.GetChild(L"address")) { // Raw
66 Cheats::Code code;
67 code.useCompare = false;
68
69 code.address = node.GetChild(L"address").GetUnsignedValue();
70 if (node.GetChild(L"value")) {
71 code.value = node.GetChild(L"value").GetUnsignedValue();
72 }
73 if (node.GetChild(L"compare")) {
74 code.compare = node.GetChild(L"compare").GetUnsignedValue();
75 code.useCompare = true;
76 }
77 cheats.SetCode(code);
78 }
79
80 //fprintf(stderr, "Cheat: %ls\n", node.GetChild(L"description").GetValue());
81 }
82 NstCheat cht = {
83 node.GetAttribute(L"enabled").IsValue(L"1"),
84 node.GetChild(L"genie").GetValue(),
85 node.GetChild(L"rocky").GetValue(),
86 node.GetChild(L"address").GetUnsignedValue(),
87 node.GetChild(L"value").GetUnsignedValue(),
88 node.GetChild(L"compare").GetUnsignedValue(),
89 node.GetChild(L"description").GetValue()
90 };
91 chtlist.push_back(cht);
92 node = node.GetNextSibling();
93 }
94 }
95 cheatfile.close();
96 }
97 }
98
nst_cheats_save(const char * cheatpath)99 void nst_cheats_save(const char *cheatpath) {
100 // Save the cheat list
101 std::ofstream cheatfile(cheatpath, std::ifstream::out|std::ifstream::binary);
102
103 if (cheatfile.is_open()) {
104 saveroot = (savexml.GetRoot());
105
106 saveroot = savexml.Create( L"cheats" );
107 saveroot.AddAttribute( L"version", L"1.0" );
108
109 char buf[9];
110 wchar_t wbuf[9];
111
112 for (int i = 0; i < chtlist.size(); i++) {
113 Xml::Node node(saveroot.AddChild(L"cheat"));
114 node.AddAttribute(L"enabled", chtlist[i].enabled ? L"1" : L"0");
115
116 if (chtlist[i].gg.size() > 0) {
117 node.AddChild(L"genie", chtlist[i].gg.c_str());
118 }
119
120 if (chtlist[i].par.size() > 0) {
121 node.AddChild(L"rocky", chtlist[i].par.c_str());
122 }
123
124 if (chtlist[i].address != 0) {
125 snprintf(buf, sizeof(buf), "0x%04X", chtlist[i].address);
126 mbstowcs(wbuf, buf, 9);
127 node.AddChild(L"address", wbuf);
128
129 snprintf(buf, sizeof(buf), "0x%02x", chtlist[i].value);
130 mbstowcs(wbuf, buf, 9);
131 node.AddChild(L"value", wbuf);
132
133 snprintf(buf, sizeof(buf), "0x%02x", chtlist[i].compare);
134 mbstowcs(wbuf, buf, 9);
135 node.AddChild(L"compare", wbuf);
136 }
137
138 if (chtlist[i].description.size() > 0) {
139 node.AddChild(L"description", chtlist[i].description.c_str());
140 }
141 }
142
143 savexml.Write(saveroot, cheatfile);
144 cheatfile.close();
145 }
146 }
147
nst_cheats_code_gg_add(const std::wstring data)148 void nst_cheats_code_gg_add(const std::wstring data) {
149 // Add a Game Genie code
150 Cheats cheats(emulator);
151 Cheats::Code code;
152
153 char gg[9];
154 snprintf(gg, sizeof(gg), "%ls", data.c_str());
155
156 cheats.GameGenieDecode(gg, code);
157 cheats.SetCode(code);
158 }
159
nst_cheats_code_par_add(const std::wstring data)160 void nst_cheats_code_par_add(const std::wstring data) {
161 // Add a Pro Action Rocky code
162 Cheats cheats(emulator);
163 Cheats::Code code;
164
165 char par[9];
166 snprintf(par, sizeof(par), "%ls", data.c_str());
167
168 cheats.ProActionRockyDecode(par, code);
169 cheats.SetCode(code);
170 }
171
nst_cheats_refresh()172 void nst_cheats_refresh() {
173 Cheats cheats(emulator);
174 cheats.ClearCodes();
175
176 for (int i = 0; i < chtlist.size(); i++) {
177 if (chtlist[i].enabled) {
178 if (chtlist[i].gg.size()) {
179 nst_cheats_code_gg_add(chtlist[i].gg);
180 }
181 else if (chtlist[i].par.size()) {
182 nst_cheats_code_par_add(chtlist[i].par);
183 }
184 else if (chtlist[i].address) {
185 Cheats::Code code;
186 code.useCompare = false;
187 code.address = chtlist[i].address;
188 code.value = chtlist[i].value;
189 code.compare = chtlist[i].compare;
190 code.useCompare = code.compare != 0;
191 cheats.SetCode(code);
192 }
193 }
194 }
195 }
196
197 // DIP Switches
nst_dip_handle(const char * dippath)198 void nst_dip_handle(const char *dippath) {
199 // Handle the DIP switch file
200 DipSwitches dipswitches(emulator);
201 Xml xml;
202
203 std::ifstream dipfile(dippath, std::ifstream::in|std::ifstream::binary);
204
205 if (dipfile.is_open()) {
206 xml.Read(dipfile);
207
208 if (xml.GetRoot().IsType(L"dipswitches")) {
209 Xml::Node root(xml.GetRoot());
210 Xml::Node node(root.GetFirstChild());
211
212 for (int i = 0; i < root.NumChildren(L"dip"); i++) {
213
214 if (node.GetChild(L"value")) {
215 dipswitches.SetValue(i, node.GetChild(L"value").GetUnsignedValue());
216 }
217 node = node.GetNextSibling();
218 }
219 }
220 dipfile.close();
221 }
222 else {
223 Xml::Node root(xml.GetRoot());
224
225 root = xml.Create(L"dipswitches");
226 root.AddAttribute(L"version", L"1.0");
227
228 wchar_t wbuf[32];
229 char buf[32];
230
231 int numdips = dipswitches.NumDips();
232
233 if (numdips > 0) {
234 for (int i = 0; i < numdips; i++) {
235 Xml::Node node(root.AddChild(L"dip"));
236
237 snprintf(buf, sizeof(buf), "%s", dipswitches.GetDipName(i));
238 mbstowcs(wbuf, buf, sizeof(buf));
239 node.AddChild(L"description", wbuf);
240
241 snprintf(buf, sizeof(buf), "%d", dipswitches.GetValue(i));
242 mbstowcs(wbuf, buf, sizeof(buf));
243 node.AddChild(L"value", wbuf);
244 }
245 }
246
247 std::ofstream dipout(dippath, std::ifstream::out|std::ifstream::binary);
248
249 if (dipout.is_open()) {
250 xml.Write(root, dipout);
251 }
252
253 dipout.close();
254 }
255 }
256