cheat.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #include <../base.hpp>
  2. Cheat cheat;
  3. Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
  4. enabled = source.enabled;
  5. code = source.code;
  6. desc = source.desc;
  7. count = source.count;
  8. addr.reset();
  9. data.reset();
  10. for(unsigned n = 0; n < count; n++) {
  11. addr[n] = source.addr[n];
  12. data[n] = source.data[n];
  13. }
  14. return *this;
  15. }
  16. //used to sort cheat code list by description
  17. bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
  18. return strcmp(desc, source.desc) < 0;
  19. }
  20. //parse item ("0123-4567+89AB-CDEF"), return cheat_t item
  21. //return true if code is valid, false otherwise
  22. bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
  23. item.enabled = false;
  24. item.count = 0;
  25. lstring list;
  26. list.split("+", s);
  27. for(unsigned n = 0; n < list.size(); n++) {
  28. unsigned addr;
  29. uint8_t data;
  30. type_t type;
  31. if(decode(list[n], addr, data, type) == false) return false;
  32. item.addr[item.count] = addr;
  33. item.data[item.count] = data;
  34. item.count++;
  35. }
  36. return true;
  37. }
  38. //read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
  39. //returns true if cheat code was found, false if it was not.
  40. //when true, cheat code substitution value is stored in data.
  41. bool Cheat::read(unsigned addr, uint8_t &data) const {
  42. addr = mirror_address(addr);
  43. for(unsigned i = 0; i < code.size(); i++) {
  44. if(enabled(i) == false) continue;
  45. for(unsigned n = 0; n < code[i].count; n++) {
  46. if(addr == mirror_address(code[i].addr[n])) {
  47. data = code[i].data[n];
  48. return true;
  49. }
  50. }
  51. }
  52. //code not found, or code is disabled
  53. return false;
  54. }
  55. //==============
  56. //master control
  57. //==============
  58. //global cheat system enable/disable:
  59. //if disabled, *all* cheat codes are disabled;
  60. //otherwise only individually disabled codes are.
  61. bool Cheat::enabled() const {
  62. return cheat_system_enabled;
  63. }
  64. void Cheat::enable() {
  65. cheat_system_enabled = true;
  66. cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
  67. }
  68. void Cheat::disable() {
  69. cheat_system_enabled = false;
  70. cheat_enabled = false;
  71. }
  72. //================================
  73. //cheat list manipulation routines
  74. //================================
  75. bool Cheat::add(bool enable, const char *code_, const char *desc_) {
  76. cheat_t item;
  77. if(decode(code_, item) == false) return false;
  78. unsigned i = code.size();
  79. code[i] = item;
  80. code[i].enabled = enable;
  81. code[i].desc = desc_;
  82. code[i].code = code_;
  83. encode_description(code[i].desc);
  84. update(code[i]);
  85. update_cheat_status();
  86. return true;
  87. }
  88. bool Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
  89. cheat_t item;
  90. if(decode(code_, item) == false) return false;
  91. //disable current code and clear from code lookup table
  92. code[i].enabled = false;
  93. update(code[i]);
  94. code[i] = item;
  95. code[i].enabled = enable;
  96. code[i].desc = desc_;
  97. code[i].code = code_;
  98. encode_description(code[i].desc);
  99. update(code[i]);
  100. update_cheat_status();
  101. return true;
  102. }
  103. bool Cheat::remove(unsigned i) {
  104. unsigned size = code.size();
  105. if(i >= size) return false; //also verifies size cannot be < 1
  106. for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
  107. code.resize(size - 1);
  108. update_cheat_status();
  109. return true;
  110. }
  111. bool Cheat::get(unsigned i, cheat_t &item) const {
  112. if(i >= code.size()) return false;
  113. item = code[i];
  114. decode_description(item.desc);
  115. return true;
  116. }
  117. //==============================
  118. //cheat status modifier routines
  119. //==============================
  120. bool Cheat::enabled(unsigned i) const {
  121. return (i < code.size() ? code[i].enabled : false);
  122. }
  123. void Cheat::enable(unsigned i) {
  124. if(i >= code.size()) return;
  125. code[i].enabled = true;
  126. update(code[i]);
  127. update_cheat_status();
  128. }
  129. void Cheat::disable(unsigned i) {
  130. if(i >= code.size()) return;
  131. code[i].enabled = false;
  132. update(code[i]);
  133. update_cheat_status();
  134. }
  135. //===============================
  136. //cheat file load / save routines
  137. //
  138. //file format:
  139. //"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
  140. //...
  141. //===============================
  142. bool Cheat::load(const char *fn) {
  143. string data;
  144. if(!data.readfile(fn)) return false;
  145. data.replace("\r\n", "\n");
  146. data.qreplace(" ", "");
  147. lstring line;
  148. line.split("\n", data);
  149. for(unsigned i = 0; i < line.size(); i++) {
  150. lstring part;
  151. part.qsplit(",", line[i]);
  152. if(part.size() != 3) continue;
  153. trim(part[0], "\"");
  154. add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]);
  155. }
  156. return true;
  157. }
  158. bool Cheat::save(const char *fn) const {
  159. file fp;
  160. if(!fp.open(fn, file::mode_write)) return false;
  161. for(unsigned i = 0; i < code.size(); i++) {
  162. fp.print(string()
  163. << "\"" << code[i].desc << "\", "
  164. << (code[i].enabled ? "enabled, " : "disabled, ")
  165. << code[i].code << "\r\n");
  166. }
  167. fp.close();
  168. return true;
  169. }
  170. void Cheat::clear() {
  171. cheat_enabled_code_exists = false;
  172. memset(mask, 0, 0x200000);
  173. code.reset();
  174. }
  175. Cheat::Cheat() : cheat_system_enabled(true) {
  176. clear();
  177. }
  178. //==================
  179. //internal functions
  180. //==================
  181. //string <> binary code translation routines
  182. //decode() "7e123456" -> 0x7e123456
  183. //encode() 0x7e123456 -> "7e123456"
  184. bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
  185. string t = s;
  186. strlower(t);
  187. #define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f'))
  188. if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
  189. //strip ':'
  190. if(strlen(t) == 9 && t[6] == ':') t = string() << substr(t, 0, 6) << substr(t, 7);
  191. //validate input
  192. for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
  193. type = ProActionReplay;
  194. unsigned r = strhex((const char*)t);
  195. addr = r >> 8;
  196. data = r & 0xff;
  197. return true;
  198. } else if(strlen(t) == 9 && t[4] == '-') {
  199. //strip '-'
  200. t = string() << substr(t, 0, 4) << substr(t, 5);
  201. //validate input
  202. for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
  203. type = GameGenie;
  204. strtr(t, "df4709156bc8a23e", "0123456789abcdef");
  205. unsigned r = strhex((const char*)t);
  206. //8421 8421 8421 8421 8421 8421
  207. //abcd efgh ijkl mnop qrst uvwx
  208. //ijkl qrst opab cduv wxef ghmn
  209. addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22)
  210. | (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20)
  211. | (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18)
  212. | (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16)
  213. | (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14)
  214. | (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12)
  215. | (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10)
  216. | (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8)
  217. | (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6)
  218. | (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4)
  219. | (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2)
  220. | (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
  221. data = r >> 24;
  222. return true;
  223. } else {
  224. return false;
  225. }
  226. }
  227. bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
  228. char t[16];
  229. if(type == ProActionReplay) {
  230. sprintf(t, "%.6x%.2x", addr, data);
  231. s = t;
  232. return true;
  233. } else if(type == GameGenie) {
  234. unsigned r = addr;
  235. addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22)
  236. | (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20)
  237. | (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18)
  238. | (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16)
  239. | (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14)
  240. | (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12)
  241. | (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10)
  242. | (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8)
  243. | (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6)
  244. | (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4)
  245. | (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2)
  246. | (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
  247. sprintf(t, "%.2x%.2x-%.4x", data, addr >> 16, addr & 0xffff);
  248. strtr(t, "0123456789abcdef", "df4709156bc8a23e");
  249. s = t;
  250. return true;
  251. } else {
  252. return false;
  253. }
  254. }
  255. //speed up S-CPU memory reads by disabling cheat code lookup when either:
  256. //a) cheat system is disabled by user, or b) no enabled cheat codes exist
  257. void Cheat::update_cheat_status() {
  258. for(unsigned i = 0; i < code.size(); i++) {
  259. if(code[i].enabled) {
  260. cheat_enabled_code_exists = true;
  261. cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
  262. return;
  263. }
  264. }
  265. cheat_enabled_code_exists = false;
  266. cheat_enabled = false;
  267. }
  268. //address lookup table manipulation and mirroring
  269. //mirror_address() 0x000000 -> 0x7e0000
  270. //set() enable specified address, mirror accordingly
  271. //clear() disable specified address, mirror accordingly
  272. unsigned Cheat::mirror_address(unsigned addr) const {
  273. if((addr & 0x40e000) != 0x0000) return addr;
  274. //8k WRAM mirror
  275. //$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
  276. return (0x7e0000 + (addr & 0x1fff));
  277. }
  278. //updates mask[] table enabled bits;
  279. //must be called after modifying item.enabled state.
  280. void Cheat::update(const cheat_t &item) {
  281. for(unsigned n = 0; n < item.count; n++) {
  282. (item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
  283. }
  284. }
  285. void Cheat::set(unsigned addr) {
  286. addr = mirror_address(addr);
  287. mask[addr >> 3] |= 1 << (addr & 7);
  288. if((addr & 0xffe000) == 0x7e0000) {
  289. //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
  290. unsigned mirror;
  291. for(unsigned x = 0; x <= 0x3f; x++) {
  292. mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
  293. mask[mirror >> 3] |= 1 << (mirror & 7);
  294. mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
  295. mask[mirror >> 3] |= 1 << (mirror & 7);
  296. }
  297. }
  298. }
  299. void Cheat::clear(unsigned addr) {
  300. addr = mirror_address(addr);
  301. //if there is more than one cheat code using the same address,
  302. //(eg with a different override value) then do not clear code
  303. //lookup table entry.
  304. uint8_t r;
  305. if(read(addr, r) == true) return;
  306. mask[addr >> 3] &= ~(1 << (addr & 7));
  307. if((addr & 0xffe000) == 0x7e0000) {
  308. //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
  309. unsigned mirror;
  310. for(unsigned x = 0; x <= 0x3f; x++) {
  311. mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
  312. mask[mirror >> 3] &= ~(1 << (mirror & 7));
  313. mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
  314. mask[mirror >> 3] &= ~(1 << (mirror & 7));
  315. }
  316. }
  317. }
  318. //these two functions are used to safely store description text inside .cfg file format.
  319. string& Cheat::encode_description(string &desc) const {
  320. desc.replace("\"", "\\q");
  321. desc.replace("\n", "\\n");
  322. return desc;
  323. }
  324. string& Cheat::decode_description(string &desc) const {
  325. desc.replace("\\q", "\"");
  326. desc.replace("\\n", "\n");
  327. return desc;
  328. }