diff options
Diffstat (limited to 'source/nds/gcheat.c')
-rw-r--r-- | source/nds/gcheat.c | 576 |
1 files changed, 89 insertions, 487 deletions
diff --git a/source/nds/gcheat.c b/source/nds/gcheat.c index 062ce9d..d0ada43 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,113 @@ * 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 = '\0'; // End the codes there + *ptr++; // Past the comma + + 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 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 (Cheat.num_cheats >= 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 == '+' || *ptr == ',' || *ptr == '"') && i < sizeof(code) - 1) + code[i++] = *ptr++; + if (*ptr) + ptr++; // Go past the + , or " + code[i] = '\0'; + if (!S9xGameGenieToRaw (code, &address, &byte)) { + S9xAddCheat (FALSE, FALSE, address, byte); + strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, MAX_SFCCHEAT_NAME); + } + else if (!S9xProActionReplayToRaw (code, &address, &byte)) { + S9xAddCheat (FALSE, FALSE, 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, FALSE, address + c, bytes[c]); + strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, MAX_SFCCHEAT_NAME); } - - 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; } - |