diff --git a/Makefile b/Makefile index b3db89bd..67ce3a77 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,6 @@ SRCS = \ menu/actions.c \ menu/bookkeeping.c \ menu/cart_load.c \ - menu/cheat_load.c \ menu/disk_info.c \ menu/fonts.c \ menu/hdmi.c \ diff --git a/README.md b/README.md index 85d80f97..ef70d344 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ This menu aims to support as many N64 flashcarts as possible. The current state * N64 ROM autoload. * ROM information descriptions. * ROM history and favorites (pre-release only). -* ROM cheat file support (pre-release only). ## Documentation diff --git a/docs/00_index.md b/docs/00_index.md index 37b68a80..668784c3 100644 --- a/docs/00_index.md +++ b/docs/00_index.md @@ -5,7 +5,7 @@ - [Initial Setup of an SD Card](./10_getting_started_sd.md) - [Basic Controls](./11_menu_controls.md) - [ROM Configuration](./12_rom_configuration.md) - +- [Cheats (Gameshark, etc.)](./13_datel_cheats.md) - [ROM Patches (Hacks, Fan Translations, etc.)](./14_rom_patches.md) - [Controller PAKs](./15_controller_paks.md) - [Background Images](./16_background_images.md) diff --git a/docs/13_datel_cheats.md b/docs/13_datel_cheats.md index d60f03f4..08ac1612 100644 --- a/docs/13_datel_cheats.md +++ b/docs/13_datel_cheats.md @@ -1,8 +1,6 @@ [Return to the index](./00_index.md) ## Cheats (Gameshark, etc.) -**THIS FEATURE IS EXPERIMENTAL** - The N64FlashcartMenu supports the cheat code types made popular by the peripherals: - GameShark - Action Replay @@ -12,41 +10,39 @@ Another product by Blaze, called the Xploder64/Xplorer64 also existed in some re **WARNING**: It is not advised to connect a physical cheat cartridge in conjunction with most flashcarts. -The N64FlashcartMenu can only support cheat codes based on Datel carts when **also** using an Expansion Pak. +The N64FlashcartMenu can only support cheat codes based on Datel carts when also using an Expansion Pak. Caveats: - Something about cheats and expansion paks. + +The current code types are supported: +- 80 (description here) +- D0 (description here) +- Fx (description here) +- ... + +The codes XX are not supported, because... - e.g. they rely on the button. -### File parsing support -If a file named the same as the selected rom with the extension `.cht` is found, it will attempt to parse the file for cheat codes and place them in `menu->boot_params->cheat_list` per the cheat backend API. - -The parser ignores lines that start with a `#` or `$`, are under 12 characters or over 15 characters. Every other line needs to be a valid cheat code input with the code on the left, and the value on the right separated by a space. - -Cheat files should be formatted this way: ``` -# Super mario 64 infinite lives -8033B21D 0064 - -# 120 stars -80207723 0001 -8020770B 00C7 -50001101 0000 -8020770C 00FF +// Example cheat codes for the game "Majoras Mask USA" +uint32_t cheats[] = { + // Enable code + 0xF1096820, + 0x2400, + 0xFF000220, + 0x0000, + // Inventory Editor (assigned to L) + 0xD01F9B91, + 0x0020, + 0x803FDA3F, + 0x0002, + // Last 2 entries must be 0 + 0, + 0, +}; ``` -Another example: -``` -# Example cheat codes for the game "Majoras Mask USA" -# Enable code -F1096820 2400 -FF000220 0000 -# Inventory Editor (assigned to L) -D01F9B91 0020 -803FDA3F 0002 -``` - -The cheat file needs to be enabled for the specific game (press `R` within the Rom Info). - +And pass this array as a boot parameter: `menu->boot_params->cheat_list = cheats;` Check the [Pull Requests](https://github.com/Polprzewodnikowy/N64FlashcartMenu/pulls) for work towards GUI editor support. diff --git a/docs/65_experimental.md b/docs/65_experimental.md index 3349791a..f5e6ad07 100644 --- a/docs/65_experimental.md +++ b/docs/65_experimental.md @@ -1,9 +1,6 @@ [Return to the index](./00_index.md) ## Experimental Features (Subject to change) -### Cheats -See: [Cheats (Gameshark, etc.)](./13_datel_cheats.md) - ### ROM info descriptions (pre-release only) To show a ROM description in the N64 ROM information screen, add a `.ini` file next to the game ROM file with the same name and the following content: ```ini @@ -18,3 +15,4 @@ Add a `font64` file to the `sd:/menu/` directory called `custom.font64`. You can build a font64 file with `Mkfont`, one of `libdragon`'s tools. At the time of writing, you will need to obtain `libdragon`'s [preview branch artifacts](https://github.com/DragonMinded/libdragon/actions/workflows/build-tool-windows.yml) to find out a copy of the prebuilt Windows executable. [Read its related Wiki page](https://github.com/DragonMinded/libdragon/wiki/Mkfont) for usage information. + diff --git a/src/menu/cart_load.c b/src/menu/cart_load.c index 70796bb8..fa72f09c 100644 --- a/src/menu/cart_load.c +++ b/src/menu/cart_load.c @@ -6,7 +6,6 @@ #include "path.h" #include "utils/fs.h" #include "utils/utils.h" -#include "cheat_load.h" #ifndef SAVES_SUBDIRECTORY #define SAVES_SUBDIRECTORY "saves" diff --git a/src/menu/cheat_load.c b/src/menu/cheat_load.c deleted file mode 100644 index baabff9c..00000000 --- a/src/menu/cheat_load.c +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @brief Cheat file support - * - * @authors Mena and XLuma - */ - -#include "cheat_load.h" -#include "../utils/fs.h" - -#include -#include -#include -#include -#include "views/views.h" - - -char *cheat_load_convert_error_message (cheat_load_err_t err) { - switch (err) { - case CHEAT_LOAD_OK: return "Cheats loaded OK"; - case CHEAT_LOAD_ERR_NO_CHEAT_FILE: return "No cheat file found"; - case CHEAT_LOAD_ERR_SIZE_FAILED: return "Error occured acquiring cheat size"; - case CHEAT_LOAD_ERR_CHEAT_EMPTY: return "Cheat file is empty"; - case CHEAT_LOAD_ERR_CHEAT_TOO_LARGE: return "Cheat file is too large (over 128KiB)"; - case CHEAT_LOAD_ERR_MALLOC_FAILED: return "Error occured allocating memory for file"; - case CHEAT_LOAD_ERR_READ_FAILED: return "Error occured during file read"; - case CHEAT_LOAD_ERR_CLOSE_FAILED: return "Error occured during file close"; - default: return "Unknown error [CHEAT_LOAD]"; - } -} - -static int find_str (char const *s, char c) { - int i; - int nb_str; - - i = 0; - nb_str = 0; - if (!s[0]) { - return (0); - } - while (s[i] && s[i] == c) { - i++; - } - while (s[i]) { - if (s[i] == c) { - nb_str++; - while (s[i] && s[i] == c) { - i++; - } - continue; - } - i++; - } - if (s[i - 1] != c) { - nb_str++; - } - return (nb_str); -} - -static void get_next_str (char **next_str, size_t *next_strlen, char c) { - size_t i; - - *next_str += *next_strlen; - *next_strlen = 0; - i = 0; - while (**next_str && **next_str == c) { - (*next_str)++; - } - while ((*next_str)[i]) { - if ((*next_str)[i] == c) { - return; - } - (*next_strlen)++; - i++; - } -} - -static char **free_tab (char **tab) { - int i; - - i = 0; - while (tab[i]) { - free(tab[i]); - i++; - } - free(tab); - return (NULL); -} - -char **ft_split (char const *s, char c) { - char **tab; - char *next_str; - size_t next_strlen; - int i; - - i = -1; - if (!s) { - return (NULL); - } - tab = malloc(sizeof(char *) * (find_str(s, c) + 1)); - if (!tab) { - return (NULL); - } - next_str = (char *)s; - next_strlen = 0; - while (++i < find_str(s, c)) { - get_next_str(&next_str, &next_strlen, c); - tab[i] = (char *)malloc(sizeof(char) * (next_strlen + 1)); - if (!tab[i]) { - return (free_tab(tab)); - } - strlcpy(tab[i], next_str, next_strlen + 1); - } - tab[i] = NULL; - return (tab); -} - -cheat_load_err_t load_cheats (menu_t *menu) { - FILE *cheatsFile; - struct stat st; - size_t cheatsLength; - path_t *path = path_clone(menu->load.rom_path); - - // Parse cheats from file - path_ext_replace(path, "cht"); - if((cheatsFile = fopen(path_get(path), "rb")) == NULL) { - path_free(path); - return CHEAT_LOAD_OK; // no file is not an error. - } - - if (fstat(fileno(cheatsFile), &st)){ - path_free(path); - return CHEAT_LOAD_ERR_SIZE_FAILED; - } - - cheatsLength = st.st_size; - if (cheatsLength <= 0) { - path_free(path); - return CHEAT_LOAD_ERR_CHEAT_EMPTY; - } - if (cheatsLength > KiB(128)) { - path_free(path); - return CHEAT_LOAD_ERR_CHEAT_TOO_LARGE; - } - - char *cheatsContent = NULL; - if((cheatsContent = malloc((cheatsLength + 1) * sizeof(char))) == NULL) { - path_free(path); - return CHEAT_LOAD_ERR_MALLOC_FAILED; - } - if(fread(cheatsContent, cheatsLength, 1, cheatsFile) != 1) { - path_free(path); - return CHEAT_LOAD_ERR_READ_FAILED; - } - - cheatsContent[cheatsLength] = '\0'; - if(fclose(cheatsFile) != 0){ - path_free(path); - return CHEAT_LOAD_ERR_CLOSE_FAILED; - } - cheatsFile = NULL; - - char **tab = ft_split(cheatsContent, '\n'); - size_t lines = 1; - for (size_t i = 0; tab[i] != NULL; i++) { - lines++; - } - - free(cheatsContent); - - uint32_t *cheats = (uint32_t*)malloc(((lines * sizeof(uint32_t)) * 2) + 2); - memset(cheats, 0, ((lines * sizeof(uint32_t)) * 2) + 2); - size_t cheatIndex = 0; - for(size_t i = 0; tab[i] != NULL; i++) { - // ignore titles - if (tab[i][0] == '#' || tab[i][0] == '$') { - continue; - } - // ignore empty, too small or too big lines - if (strlen(tab[i]) < 12 || strlen(tab[i]) > 15) { - continue; - } - char **splitCheat = ft_split(tab[i], ' '); - uint32_t cheatValue1 = strtoul(splitCheat[0], NULL, 16); - uint32_t cheatValue2 = strtoul(splitCheat[1], NULL, 16); - cheats[cheatIndex] = cheatValue1; - cheats[cheatIndex + 1] = cheatValue2; - free_tab(splitCheat); - cheatIndex += 2; - } - free_tab(tab); - - cheats[cheatIndex] = 0; - cheats[cheatIndex + 1] = 0; - menu->boot_params->cheat_list = cheats; - - return CHEAT_LOAD_OK; -} diff --git a/src/menu/cheat_load.h b/src/menu/cheat_load.h deleted file mode 100644 index 5d44daf9..00000000 --- a/src/menu/cheat_load.h +++ /dev/null @@ -1,26 +0,0 @@ -/*** - * @file cheat_load.h - * @brief Cheat loading functions - */ - -#include "path.h" -#include "utils/fs.h" -#include "utils/utils.h" -#include "menu_state.h" - -/** @brief Cheat code loading enum */ - -typedef enum { - CHEAT_LOAD_OK, - CHEAT_LOAD_ERR_NO_CHEAT_FILE, - CHEAT_LOAD_ERR_SIZE_FAILED, - CHEAT_LOAD_ERR_CHEAT_EMPTY, - CHEAT_LOAD_ERR_CHEAT_TOO_LARGE, - CHEAT_LOAD_ERR_MALLOC_FAILED, - CHEAT_LOAD_ERR_READ_FAILED, - CHEAT_LOAD_ERR_CLOSE_FAILED, - CHEAT_LOAD_ERR_UNKNOWN_ERROR -} cheat_load_err_t; - -cheat_load_err_t load_cheats (menu_t *menu); -char *cheat_load_convert_error_message (cheat_load_err_t err); diff --git a/src/menu/rom_info.c b/src/menu/rom_info.c index c20946ae..fc2d5bfd 100644 --- a/src/menu/rom_info.c +++ b/src/menu/rom_info.c @@ -857,8 +857,6 @@ static rom_err_t save_override (path_t *path, const char *id, int value, int def if (value == default_value) { mini_err = mini_delete_value(rom_info_ini, "custom_boot", id); - } else if (strncmp(id, "cheat_codes", strlen("cheat_codes"))) { - mini_err = mini_set_bool(rom_info_ini, NULL, id, value); } else { mini_err = mini_set_int(rom_info_ini, "custom_boot", id, value); } @@ -964,11 +962,6 @@ rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_ return save_override(path, "tv_type", rom_info->boot_override.tv_type, ROM_TV_TYPE_AUTOMATIC); } -rom_err_t rom_setting_set_cheats (path_t *path, rom_info_t *rom_info, bool enabled) { - rom_info->settings.cheats_enabled = enabled; - return save_override(path, "cheat_codes", enabled, false); -} - rom_err_t rom_info_load (path_t *path, rom_info_t *rom_info) { FILE *f; rom_header_t rom_header; diff --git a/src/menu/rom_info.h b/src/menu/rom_info.h index b20d87f9..26779429 100644 --- a/src/menu/rom_info.h +++ b/src/menu/rom_info.h @@ -247,6 +247,4 @@ rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_s rom_tv_type_t rom_info_get_tv_type (rom_info_t *rom_info); rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_type_t tv_type); -rom_err_t rom_setting_set_cheats (path_t *path, rom_info_t *rom_info, bool enabled); - #endif diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c index 1b18909f..1a979426 100644 --- a/src/menu/views/file_info.c +++ b/src/menu/views/file_info.c @@ -15,7 +15,6 @@ static const char *image_extensions[] = { "png", "jpg", "gif", NULL }; static const char *music_extensions[] = { "mp3", "wav", "ogg", "wma", "flac", NULL }; static const char *controller_pak_extensions[] = { "mpk", "pak", NULL }; static const char *emulator_extensions[] = { "nes", "smc", "gb", "gbc", "sms", "gg", "chf", NULL }; -static const char *cheat_extensions[] = {"cht", NULL}; static struct stat st; @@ -45,9 +44,6 @@ static char *format_file_type (char *name, bool is_directory) { } else if (file_has_extensions(name, emulator_extensions)) { return " Type: Emulator ROM file\n"; } - else if (file_has_extensions(name, cheat_extensions)) { - return " Type: Cheats\n"; - } return " Type: Unknown file\n"; } diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index fc18a104..9fb97458 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -6,7 +6,6 @@ #include #include "utils/fs.h" #include "../bookkeeping.h" -#include "../cheat_load.h" static bool show_extra_info_message = false; static component_boxart_t *boxart; @@ -167,23 +166,6 @@ static void add_favorite (menu_t *menu, void *arg) { bookkeeping_favorite_add(&menu->bookkeeping, menu->load.rom_path, NULL, BOOKKEEPING_TYPE_ROM); } -static void set_cheat_option(menu_t *menu, void *arg) { - bool enabled = (bool)arg; - if (enabled == true) { - cheat_load_err_t err = load_cheats(menu); - if (err != CHEAT_LOAD_OK) { - menu_show_error(menu, cheat_load_convert_error_message(err)); - } - } - if (enabled == false) { - if (menu->boot_params->cheat_list != NULL) { - free(menu->boot_params->cheat_list); - } - } - rom_setting_set_cheats(menu->load.rom_path, &menu->load.rom_info, enabled); - menu->browser.reload = true; -} - static component_context_menu_t set_cic_type_context_menu = { .list = { {.text = "Automatic", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_AUTOMATIC) }, {.text = "CIC-6101", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_6101) }, @@ -222,17 +204,10 @@ static component_context_menu_t set_tv_type_context_menu = { .list = { COMPONENT_CONTEXT_MENU_LIST_END, }}; -static component_context_menu_t set_cheat_options_menu = { .list = { - { .text = "Enable", .action = set_cheat_option, .arg = (void *) (true)}, - { .text = "Disable", .action = set_cheat_option, .arg = (void *) (false)}, - COMPONENT_CONTEXT_MENU_LIST_END, -}}; - static component_context_menu_t options_context_menu = { .list = { { .text = "Set CIC Type", .submenu = &set_cic_type_context_menu }, { .text = "Set Save Type", .submenu = &set_save_type_context_menu }, { .text = "Set TV Type", .submenu = &set_tv_type_context_menu }, - { .text = "Set Cheats", .submenu = &set_cheat_options_menu }, { .text = "Set ROM to autoload", .action = set_autoload_type }, { .text = "Add to favorites", .action = add_favorite }, COMPONENT_CONTEXT_MENU_LIST_END, @@ -392,6 +367,7 @@ static void load (menu_t *menu) { case ROM_TV_TYPE_MPAL: menu->boot_params->tv_type = BOOT_TV_TYPE_MPAL; break; default: menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; break; } + menu->boot_params->cheat_list = NULL; } static void deinit (void) {