aboutsummaryrefslogtreecommitdiff
path: root/source/nds/gcheat.c
diff options
context:
space:
mode:
authorNebuleon Fumika2012-12-22 22:16:55 -0500
committerNebuleon Fumika2012-12-22 22:16:55 -0500
commita194b850037c03f5fb3ac1ecc9f7a99f73b84104 (patch)
treee741bc4898e81b568552a8ae91867fd6a2ed3523 /source/nds/gcheat.c
parente7f7d0282a7126f9e1095481b39c43e3e24909bf (diff)
downloadsnes9x2005-a194b850037c03f5fb3ac1ecc9f7a99f73b84104.tar.gz
snes9x2005-a194b850037c03f5fb3ac1ecc9f7a99f73b84104.tar.bz2
snes9x2005-a194b850037c03f5fb3ac1ecc9f7a99f73b84104.zip
Preliminary Snes9x-based cheat code support. Not tested, because the file selection interface freezes when it gets to the folder containing Mightymo's cheat files, whereas it did not do this before with the converted Mightymo cheats. (335 files -> 679, though.)
Diffstat (limited to 'source/nds/gcheat.c')
-rw-r--r--source/nds/gcheat.c574
1 files changed, 87 insertions, 487 deletions
diff --git a/source/nds/gcheat.c b/source/nds/gcheat.c
index 062ce9d..648bfda 100644
--- a/source/nds/gcheat.c
+++ b/source/nds/gcheat.c
@@ -1,9 +1,9 @@
/* gcheat.c
*
- * Copyright (C) 2010 dking <dking024@gmail.com>
+ * Copyright (C) 2012 GBAtemp user Nebuleon.
*
* This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licens e as
+ * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
@@ -17,511 +17,111 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "port.h"
#include "string.h"
#include "fs_api.h"
#include "ds2_malloc.h"
#include "gcheat.h"
#include "charsets.h"
+#include "cheats.h"
-#define MAX_SFCCHEAT_NAME 24
+extern struct SCheatData Cheat;
-
-//GCHEAT_STRUCT gcheat[MAX_CHEATS];
-unsigned int g_cheat_cell_num;
-unsigned int g_cheat_num;
-
-#define SKIP_SPACE(pt) while(' ' == *pt) pt++
-
-static unsigned char* check_is_cht(unsigned char *str)
-{
- unsigned char *pt, *pt1;
-
- if(*str == '\0') return NULL;
-
- pt = str;
- while(*pt == ' ') pt++; //Skip leading space
- if(*pt != '[') return NULL; //valid entry should be:[string]
-
- pt1 = strrchr(str, ']');
- if(pt1 == NULL) return NULL;
-
- while(*(--pt1) == ' ');
- *(pt1+1) = '\0'; //Cut trailing space between string and ']'
-
- while(*(++pt) == ' '); //Cut space between '[' and string
-
- return pt;
-}
-
-static unsigned int sscanf_hex_value(unsigned char* str, unsigned int *value)
-{
- unsigned char *pt;
- unsigned int tmp;
- unsigned char ch;
- unsigned int len;
-
- pt = str;
- len = 0;
- tmp = 0;
- while(*pt && len < 8)
- {
- ch = *pt;
- if(ch >= 'a' && ch <= 'f') ch = ch - 'a' + 0xa;
- else if(ch >= 'A' && ch <= 'F') ch = ch - 'A' + 0xa;
- else if(ch >= '0' && ch <= '9') ch = ch - '0';
- else if(ch == ' ') continue;
- else break;
-
- tmp = (tmp << 4) | ch;
- pt++;
- len += 1;
- }
-
- *value = tmp;
- return len;
-}
-
-/*
-* Convert the src string to UTF8 coding dst string, and cut to length
-*/
-int string2utf8(unsigned char *src, unsigned char* dst, unsigned int length)
+// Reads a cheat text file in BSNES's format.
+int NDSSFCLoadCheatFile(const char* filename)
{
- unsigned char *pt;
- unsigned char ch;
- unsigned short ucode;
- unsigned int type;
- unsigned int len;
+ FILE* fp = fopen(filename, "r");
+ if (fp == NULL)
+ return -1;
- len = 0;
- type = 0;
- pt = src;
- while(*pt)
+ S9xDeleteCheats();
+
+ // The construction is "a","b","c" <newline>.
+ // a is ignored. In BSNES, it decides whether the code is enabled.
+ // b is a series of codes separated by +. Each of the codes is in the form
+ // accepted by the Game Genie, Pro Action Replay, or the GoldFinger.
+ // c is the cheat's description.
+ char line[256], code[24];
+ char *description, *codes_ptr;
+ uint32 address;
+ uint8 byte;
+ uint8 bytes [3];
+ bool8 sram;
+ uint8 num_bytes;
+
+ while (fgets(line, sizeof(line), fp))
{
- pt = utf8decode(pt, &ucode);
- if(ucode < 0x4e00) {
- if(ucode == 0 || ucode > 0x7F) {
- type = 1;
- break;
- }
- } else if(ucode > 0x9FCF) {
- type = 1;
- break;
+ char* ptr = &line[0];
+ // Ignore a.
+ while (*ptr && *ptr != ',')
+ ptr++;
+ // If there was no comma, declare a bad file.
+ if (*ptr == '\0') {
+ fclose(fp);
+ return -2;
}
- else
- len++;
-
- if(len >= 3) break; //There is enough UTF8, so it is, to save time(>_*)
- }
+ *ptr++; // Past the comma
+
+ if (*ptr && *ptr == '"')
+ ptr++; // Starting quote of b.
+ codes_ptr = ptr; // Save this for later.
+ while (*ptr && *ptr != ',')
+ ptr++;
+ // If there was no comma, declare a bad file.
+ if (*ptr == '\0') {
+ fclose(fp);
+ return -2;
+ }
+ *ptr++; // Past the comma
+ *(ptr - 1) = '\0'; // End the codes there
+
+ uint32 i = 0;
+ description = ptr; // Skip starting " in description
+ while (*description && *description == '"')
+ description++;
+ ptr = description;
+ while (*ptr && !(*ptr == '\r' || *ptr == '\n' || *ptr == '"') && i < MAX_SFCCHEAT_NAME - 1) {
+ ptr++; // Remove trailing newline/quote in description
+ i++; // Clip the cheat name to MAX_SFCCHEAT_NAME chars
+ }
+ *ptr = '\0';
- if(type == 0) //UTF8
- {
- while(*src)
- {
- ch = *src++;
- *dst++ = ch;
+ uint32 n = 0, c;
+ // n is the number of cheat codes. Beware of MAX_CHEATS_T.
- if(ch < 0x80) {
- if(length > 1) length -= 1;
- else break;
- } else if (ch < 0xe0) { /* U-00000080 - U-000007FF, 2 bytes */
- if(length > 2) length -= 2;
- else break;
- *dst++ = *src++;
- } else if (ch < 0xf0) { /* U-00000800 - U-0000FFFF, 3 bytes */
- if(length > 3) length -= 3;
- else break;
- *dst++ = *src++;
- *dst++ = *src++;
- } else if (ch < 0xf5) { /* U-00010000 - U-001FFFFF, 4 bytes */
- if(length > 4) length -= 4;
- else break;
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = *src++;
- } else {
- break;
+ // List of cheat codes having the same description.
+ ptr = codes_ptr;
+ while (*ptr && !(*ptr == ',' || *ptr == '"')) {
+ if (n >= MAX_CHEATS_T) {
+ fclose(fp);
+ return 0;
}
- }
- *dst = '\0';
- }
- else //assume it is GBK code
- {
- //GBK to UTF8
- while(*src)
- {
- ch = *src;
- if(ch < 0x80)
- {
- if(length > 1) length -= 1;
- else break;
-
- *dst++= ch;
- src ++;
+ i = 0;
+ while (*ptr && *ptr != '+' && i < sizeof(code) - 1)
+ code[i++] = *ptr++;
+ code[i] = '\0';
+ if (!S9xGameGenieToRaw (code, &address, &byte)) {
+ S9xAddCheat (FALSE, TRUE, address, byte);
+ strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, MAX_SFCCHEAT_NAME);
+ }
+ else if (!S9xProActionReplayToRaw (code, &address, &byte)) {
+ S9xAddCheat (FALSE, TRUE, address, byte);
+ strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, MAX_SFCCHEAT_NAME);
}
- else
+ else if (!S9xGoldFingerToRaw (code, &address, &sram, &num_bytes, bytes))
{
- ucode = charsets_gbk_to_ucs(src);
-
- if (ucode < 0x800) //2 bytes
- {
- if(length > 2) length -= 2;
- else break;
-
- *dst++ = 0xC0 | ((ucode >> 6) & 0x1F);
- *dst++ = 0x80 | (ucode & 0x3F);
- }
- else //3 bytes
- {
- if(length > 3) length -= 3;
- else break;
-
- *dst++ = 0xE0 | (ucode >> 12);
- *dst++ = 0x80 | ((ucode >>6) & 0x3F);
- *dst++ = 0x80 | (ucode & 0x3F);
+ for (c = 0; c < num_bytes; c++) {
+ S9xAddCheat (FALSE, TRUE, address + c, bytes[c]);
+ strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, 22);
}
-
- src += 2;
}
- }
- *dst = '\0';
- }
-
- return 0;
-}
-
-int load_cheatname(const char* filename, unsigned int string_num, unsigned int string_len, MSG_TABLE* mssg_table)
-{
- FILE *fp;
- unsigned char current_line[256];
- unsigned char current_line_tmp[256];
- int len, m;
- unsigned char** indexp;
- unsigned char* msg;
- unsigned char* pt;
-
- mssg_table->msg_index = (unsigned char**)malloc(string_num*4);
- if(NULL == mssg_table->msg_index)
- return -1;
-
- string_len = string_len + string_len/2;
- mssg_table->msg_pool = (unsigned char*)malloc((string_len+31)&(~31));
- if(NULL == mssg_table->msg_pool) {
- free((void*)mssg_table->msg_index);
- return -1;
- }
-
- fp = fopen(filename, "r");
- if(fp == NULL) {
- free((void*)mssg_table->msg_index);
- free((void*)mssg_table->msg_pool);
- return -1;
- }
-
- len = 0;
- m= 0;
- indexp = mssg_table->msg_index;
- msg = mssg_table->msg_pool;
- while(fgets(current_line, 256, fp))
- {
- unsigned int str_len;
-
- if((pt = check_is_cht(current_line)) != NULL)
- {
- if(!strcasecmp(pt, "gameinfo"))
- continue;
-
- string2utf8(pt, current_line_tmp, 255);
-
- str_len = strlen(current_line_tmp);
- strncpy(msg+len, current_line_tmp, str_len);
-
- indexp[m++] = msg+len;
- len += str_len;
- msg[len] = '\0';
- len += 1;
-
- if(len >= string_len) break;
- if(m >= string_num) break;
-
- while(fgets(current_line, 256, fp))
- {
- str_len = strlen(current_line);
- if(str_len < 4) break;
-
- if((pt = strchr(current_line, '=')) == NULL) //valid cheat item
- break;
-
- *pt = '\0';
- pt = current_line;
-
- string2utf8(pt, current_line_tmp, 255);
-
- str_len = strlen(current_line_tmp);
- strncpy(msg+len, current_line_tmp, str_len);
-
- indexp[m++] = msg+len;
- len += str_len;
- msg[len] = '\0';
- len += 1;
-
- if(len >= string_len) break;
- if(m >= string_num) break;
+ else {
+ fclose(fp);
+ return -3; // Bad cheat format
}
-
- if(len >= string_len) break;
- if(m >= string_num) break;
- }
- }
-
- mssg_table -> msg_num = m;
- fclose(fp);
-
-#if 0
-cprintf("string_len %d; len %d\n", string_len, len);
-for(m= 0; m<mssg_table -> msg_num; m++)
-{
-cprintf("msg%d:%s\n", m, indexp[m]);
-}
-#endif
-
- return 0;
-}
-
-#define MAX_CHEAT_DATE_LEN (MAX_SFCCHEAT_NAME/2) //other part hold the saved data
-
-/*
-* Load cheat file
-*/
-int load_cheatfile(const char* filename, unsigned int *string_num, unsigned int *string_len,
- GCHEAT_STRUCT *gcheat)
-{
- FILE *cheats_file;
- unsigned char current_line[256];
- unsigned char current_line_tmp[256];
- unsigned int current_line_len;
- unsigned char *pt;
- int gcheat_num;
-
- unsigned int str_num;
- unsigned int str_len;
- unsigned int cheat_cell_num;
- int flag;
-
- cheats_file = fopen(filename, "r");
- if(NULL == cheats_file)
- return -1;
- g_cheat_cell_num = 0;
- g_cheat_num = 0;
- cheat_cell_num = 0;
- gcheat_num = 0;
- str_num = 0;
- str_len = 0;
- flag = 0;
-
- while(fgets(current_line, 256, cheats_file))
- {
- if((pt = check_is_cht(current_line)) == NULL) //Check valid cht cheat
- continue;
-
- if(!strcasecmp(pt, "gameinfo")) //maybe file end
- continue;
-
- gcheat[gcheat_num].name_id = str_num;
- gcheat[gcheat_num].item_id = cheat_cell_num;
- gcheat[gcheat_num].item_num = 0;
-
- string2utf8(pt, current_line_tmp, CHEAT_NAME_LENGTH);
- strcpy(gcheat[gcheat_num].name_shot, current_line_tmp); //store a cut name shot
- //Initialize other parameter of gcheat
- gcheat[gcheat_num].active = 0;
- gcheat[gcheat_num].sub_active = 0;
-
- current_line_len = strlen(pt);
- str_len += current_line_len +1;
- str_num++;
-
- //Cheat items
- while(fgets(current_line, 256, cheats_file) != NULL)
- {
- if(strlen(current_line) < 4)
- break;
-
- if((pt = strchr(current_line, '=')) == NULL) //No valid content
- break;
-
- //one sub item each pass
- unsigned int first_part; //first part of a cheat item
- unsigned int first_part_id;
- unsigned int sub_part_id;
- unsigned int hex_len;
-
- unsigned int cheat_addr;
- unsigned char cheat_dat[MAX_CHEAT_DATE_LEN];
- unsigned int cheat_dat_len;
- unsigned int str_num_saved;
-
- str_num_saved = str_num;
- str_len += pt - current_line +1;
- str_num++;
-
- first_part = 1;
- first_part_id = cheat_cell_num;
- sub_part_id = 0;
-
- //skip name part
- pt += 1;
- current_line_len = strlen(pt);
-
- //data part
- while(1)
- {
- //fill current_line buffer as full as possible
- if(current_line_len < (MAX_CHEAT_DATE_LEN*3+8))
- { //the data length can fill a cheat cell
- if(NULL == strchr(pt, 0x0A)) { //this line not end
- memmove(current_line, pt, current_line_len+1);
- fgets(current_line+current_line_len, 256-current_line_len, cheats_file);
- pt = current_line;
- current_line_len = strlen(pt);
- }
- }
-#if 0
-cprintf("------\n");
-cprintf("new %d:[%s]\n", current_line_len, pt);
-dump_mem(pt, strlen(pt));
-cprintf("\n------\n");
-#endif
- //get address
- if(first_part)
- {
- hex_len = sscanf_hex_value(pt, &cheat_addr);
- if(0 == hex_len) {
- goto load_cheatfile_error;
- }
-
- pt += hex_len;
- current_line_len -= hex_len +1;
- // strict to follow the formate
- if(',' != *pt++ || '\0' == *pt || 0x0D == *pt || 0x0A == *pt) {
- goto load_cheatfile_error;
- }
-
- if(cheat_addr < 0x10000)
- cheat_addr |= 0x7e0000;
- else {
- cheat_addr &= 0xffff;
- cheat_addr |= 0x7f0000;
- }
- }
-
- //get data
- unsigned int tmp, m;
-
- m = 0;
- cheat_dat_len = 0;
- while(m++ < MAX_CHEAT_DATE_LEN)
- {
- hex_len = sscanf_hex_value(pt, &tmp);
- if(0 == hex_len) break;
-
- cheat_dat[cheat_dat_len++] = (unsigned char)tmp;
-
- pt += hex_len;
- current_line_len -= hex_len +1;
- if(',' == *pt) pt++;
- }
-
- //In first part, get data error
- if(0 == cheat_dat_len) {
- if(0 == sub_part_id)
- goto load_cheatfile_error;
- }
- else {
- //record data
- flag = S9xAddCheat_ex(cheat_addr, cheat_dat, cheat_dat_len, cheat_cell_num++, sub_part_id++, str_num_saved);
- if(0 != flag) {
- cheat_cell_num -= sub_part_id;
- break;
- }
- }
-
- if(0 == *pt || 0x0D == *pt || 0x0A == *pt) break; //a line over
-
- first_part = 0;
- if(';' == *pt) first_part = 1, pt += 1; //other address of the cheat cell
- else cheat_addr += cheat_dat_len; //more data
- } //data part
-
- //have no enough cheat_cell struct to store cheat
- if(0 != flag) break;
-
- S9xAddCheat_ov(first_part_id, sub_part_id);
- gcheat[gcheat_num].item_num += 1;
- } //Cheat items
-
- if(0 != flag) break;
-
- gcheat_num += 1;
- if(gcheat_num >= MAX_CHEATS)
- break;
- }
-
- g_cheat_cell_num = cheat_cell_num;
- g_cheat_num = gcheat_num;
- *string_num = str_num;
- *string_len = str_len;
- fclose(cheats_file);
-
-#if 0
-cprintf("g_cheat_num %d; g_cheat_cell_num %d\n", g_cheat_num, g_cheat_cell_num);
-
-int i;
-for(i= 0; i < g_cheat_cell_num; i++)
-S9x_dumpcheat(i);
-
-for(i= 0; i < g_cheat_num; i++)
-{
- cprintf("cheat %d\n", i);
- cprintf("item num %d; item id %d\n", gcheat[i].item_num, gcheat[i].item_id);
-}
-#endif
-
- return 0;
-
-load_cheatfile_error:
- fclose(cheats_file);
- return -1;
-}
-
-void gcheat_Managment(GCHEAT_STRUCT *gcheat)
-{
- unsigned int i, enable, m, en_flag;
- unsigned int active, item_id, sub_active, item_num;
-
- //no cheat
- if(0 == g_cheat_num || 0 == g_cheat_cell_num) {
- S9xCheat_Disable();
- return;
- }
-
- enable = 0;
- for(i = 0; i < g_cheat_num; i++)
- {
- active = gcheat[i].active & 0x1;
- item_id = gcheat[i].item_id;
- item_num = gcheat[i].item_num;
- sub_active = gcheat[i].sub_active;
-
- for(m = 0; m < item_num; m++)
- {
- en_flag = sub_active == m ? active : 0;
- S9xCheat_switch(item_id, m, en_flag);
}
-
- if(active) enable = 1;
}
- if(enable)
- S9xCheat_Enable();
+ fclose(fp);
+ return 0;
}
-