Merge branch 'develop' into ed64-basic

This commit is contained in:
Robin Jones 2024-08-04 21:05:47 +01:00 committed by GitHub
commit 8ced9660d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 716 additions and 561 deletions

View File

@ -98,7 +98,7 @@ FILESYSTEM = \
$(MINIZ_OBJS): N64_CFLAGS+=-DMINIZ_NO_TIME -fcompare-debug-second $(MINIZ_OBJS): N64_CFLAGS+=-DMINIZ_NO_TIME -fcompare-debug-second
$(SPNG_OBJS): N64_CFLAGS+=-isystem $(SOURCE_DIR)/libs/miniz -DSPNG_USE_MINIZ -fcompare-debug-second $(SPNG_OBJS): N64_CFLAGS+=-isystem $(SOURCE_DIR)/libs/miniz -DSPNG_USE_MINIZ -fcompare-debug-second
$(FILESYSTEM_DIR)/FiraMonoBold.font64: MKFONT_FLAGS+=-c 1 --size 16 -r 20-1FF -r 2026-2026 --ellipsis 2026,1 $(FILESYSTEM_DIR)/FiraMonoBold.font64: MKFONT_FLAGS+=-c 1 --size 16 -r 20-7F -r 80-1FF -r 2026-2026 --ellipsis 2026,1
$(FILESYSTEM_DIR)/%.wav64: AUDIOCONV_FLAGS=--wav-compress 1 $(FILESYSTEM_DIR)/%.wav64: AUDIOCONV_FLAGS=--wav-compress 1

View File

@ -68,10 +68,9 @@ A known set of PNG files using 2 letter ID's can be downloaded [here](https://me
Emulators should be added to the `/menu/emulators` directory on the SD card. Emulators should be added to the `/menu/emulators` directory on the SD card.
Menu currently supports the following emulators and associated ROM file names: Menu currently supports the following emulators and associated ROM file names:
- **NES**: [neon64v2](https://github.com/hcs64/neon64v2) by *hcs64* - `neon64bu.rom` - **NES**: [neon64v2](https://github.com/hcs64/neon64v2/releases) by *hcs64* - `neon64bu.rom`
- **SNES**: [sodium64](https://github.com/Hydr8gon/sodium64) by *Hydr8gon* - `sodium64.z64` - **SNES**: [sodium64](https://github.com/Hydr8gon/sodium64/releases) by *Hydr8gon* - `sodium64.z64`
- **Game Boy** / **GB Color**: [gb64](https://lambertjamesd.github.io/gb64/romwrapper/romwrapper.html) by *lambertjamesd* - `gb.v64` / `gbc.v64` - **Game Boy** / **GB Color**: [gb64](https://lambertjamesd.github.io/gb64/romwrapper/romwrapper.html) by *lambertjamesd* - `gb.v64` / `gbc.v64` ("Download Emulator" button)
- **Sega Master System** / **Sega Game Gear** / **Sg1000**: [TotalSMS](https://github.com/ITotalJustice/TotalSMS) - `TotalSMS.z64` (Currently broken)
### Menu Settings ### Menu Settings
The Menu creates a `config.ini` file in `sd:/menu/` which contains various settings that are used by the menu. The Menu creates a `config.ini` file in `sd:/menu/` which contains various settings that are used by the menu.

@ -1 +1 @@
Subproject commit af650428e9615f4e08d8e7eae187929a90c15ccc Subproject commit e2e2dc063add29e9d11f55ae3fbeccc189fb2ad6

View File

@ -170,7 +170,7 @@ static flashcart_err_t d64_load_save (char *save_path) {
size_t save_size = f_size(&fil); size_t save_size = f_size(&fil);
bool is_eeprom_save = (current_save_type == SAVE_TYPE_EEPROM_4K || current_save_type == SAVE_TYPE_EEPROM_16K); bool is_eeprom_save = (current_save_type == SAVE_TYPE_EEPROM_4KBIT || current_save_type == SAVE_TYPE_EEPROM_16KBIT);
void *address = (void *) (SAVE_ADDRESS_DEV_B); void *address = (void *) (SAVE_ADDRESS_DEV_B);
if (is_eeprom_save) { if (is_eeprom_save) {
@ -212,27 +212,27 @@ static flashcart_err_t d64_set_save_type (flashcart_save_type_t save_type) {
case FLASHCART_SAVE_TYPE_NONE: case FLASHCART_SAVE_TYPE_NONE:
type = SAVE_TYPE_NONE; type = SAVE_TYPE_NONE;
break; break;
case FLASHCART_SAVE_TYPE_EEPROM_4K: case FLASHCART_SAVE_TYPE_EEPROM_4KBIT:
type = SAVE_TYPE_EEPROM_4K; type = SAVE_TYPE_EEPROM_4KBIT;
break; break;
case FLASHCART_SAVE_TYPE_EEPROM_16K: case FLASHCART_SAVE_TYPE_EEPROM_16KBIT:
type = SAVE_TYPE_EEPROM_16K; type = SAVE_TYPE_EEPROM_16KBIT;
break; break;
case FLASHCART_SAVE_TYPE_SRAM: case FLASHCART_SAVE_TYPE_SRAM_256KBIT:
type = SAVE_TYPE_SRAM; type = SAVE_TYPE_SRAM_256KBIT;
break; break;
case FLASHCART_SAVE_TYPE_SRAM_BANKED: case FLASHCART_SAVE_TYPE_SRAM_BANKED:
type = SAVE_TYPE_SRAM_BANKED; type = SAVE_TYPE_SRAM_BANKED;
break; break;
case FLASHCART_SAVE_TYPE_SRAM_128K: case FLASHCART_SAVE_TYPE_SRAM_1MBIT:
// NOTE: 64drive doesn't support 128 kiB SRAM save type, fallback to 32 kiB SRAM save type // NOTE: 64drive doesn't support 128 kiB SRAM save type, fallback to 32 kiB SRAM save type
type = SAVE_TYPE_SRAM; type = SAVE_TYPE_SRAM_256KBIT;
break; break;
case FLASHCART_SAVE_TYPE_FLASHRAM: case FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT:
type = SAVE_TYPE_FLASHRAM; type = SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2: case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2:
type = (device_variant == DEVICE_VARIANT_A) ? SAVE_TYPE_FLASHRAM_PKST2 : SAVE_TYPE_FLASHRAM; type = (device_variant == DEVICE_VARIANT_A) ? SAVE_TYPE_FLASHRAM_PKST2 : SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
default: default:
return FLASHCART_ERR_ARGS; return FLASHCART_ERR_ARGS;

View File

@ -79,10 +79,10 @@ typedef enum {
/** @brief Save Type Enumeration. */ /** @brief Save Type Enumeration. */
typedef enum { typedef enum {
SAVE_TYPE_NONE, SAVE_TYPE_NONE,
SAVE_TYPE_EEPROM_4K, SAVE_TYPE_EEPROM_4KBIT,
SAVE_TYPE_EEPROM_16K, SAVE_TYPE_EEPROM_16KBIT,
SAVE_TYPE_SRAM, SAVE_TYPE_SRAM_256KBIT,
SAVE_TYPE_FLASHRAM, SAVE_TYPE_FLASHRAM_1MBIT,
SAVE_TYPE_SRAM_BANKED, SAVE_TYPE_SRAM_BANKED,
SAVE_TYPE_FLASHRAM_PKST2, SAVE_TYPE_FLASHRAM_PKST2,
} d64_save_type_t; } d64_save_type_t;

View File

@ -34,12 +34,12 @@ typedef enum {
/** @brief Flashcart save type enumeration */ /** @brief Flashcart save type enumeration */
typedef enum { typedef enum {
FLASHCART_SAVE_TYPE_NONE, FLASHCART_SAVE_TYPE_NONE,
FLASHCART_SAVE_TYPE_EEPROM_4K, FLASHCART_SAVE_TYPE_EEPROM_4KBIT,
FLASHCART_SAVE_TYPE_EEPROM_16K, FLASHCART_SAVE_TYPE_EEPROM_16KBIT,
FLASHCART_SAVE_TYPE_SRAM, FLASHCART_SAVE_TYPE_SRAM_256KBIT,
FLASHCART_SAVE_TYPE_SRAM_BANKED, FLASHCART_SAVE_TYPE_SRAM_BANKED,
FLASHCART_SAVE_TYPE_SRAM_128K, FLASHCART_SAVE_TYPE_SRAM_1MBIT,
FLASHCART_SAVE_TYPE_FLASHRAM, FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT,
FLASHCART_SAVE_TYPE_FLASHRAM_PKST2, FLASHCART_SAVE_TYPE_FLASHRAM_PKST2,
__FLASHCART_SAVE_TYPE_END __FLASHCART_SAVE_TYPE_END
} flashcart_save_type_t; } flashcart_save_type_t;

View File

@ -388,12 +388,12 @@ static flashcart_err_t sc64_load_save (char *save_path) {
sc64_save_type_t type = (sc64_save_type_t) (value); sc64_save_type_t type = (sc64_save_type_t) (value);
switch (type) { switch (type) {
case SAVE_TYPE_EEPROM_4K: case SAVE_TYPE_EEPROM_4KBIT:
case SAVE_TYPE_EEPROM_16K: case SAVE_TYPE_EEPROM_16KBIT:
address = (void *) (EEPROM_ADDRESS); address = (void *) (EEPROM_ADDRESS);
break; break;
case SAVE_TYPE_SRAM: case SAVE_TYPE_SRAM_256KBIT:
case SAVE_TYPE_FLASHRAM: case SAVE_TYPE_FLASHRAM_1MBIT:
case SAVE_TYPE_SRAM_BANKED: case SAVE_TYPE_SRAM_BANKED:
address = (void *) (SRAM_FLASHRAM_ADDRESS); address = (void *) (SRAM_FLASHRAM_ADDRESS);
break; break;
@ -515,26 +515,26 @@ static flashcart_err_t sc64_set_save_type (flashcart_save_type_t save_type) {
case FLASHCART_SAVE_TYPE_NONE: case FLASHCART_SAVE_TYPE_NONE:
type = SAVE_TYPE_NONE; type = SAVE_TYPE_NONE;
break; break;
case FLASHCART_SAVE_TYPE_EEPROM_4K: case FLASHCART_SAVE_TYPE_EEPROM_4KBIT:
type = SAVE_TYPE_EEPROM_4K; type = SAVE_TYPE_EEPROM_4KBIT;
break; break;
case FLASHCART_SAVE_TYPE_EEPROM_16K: case FLASHCART_SAVE_TYPE_EEPROM_16KBIT:
type = SAVE_TYPE_EEPROM_16K; type = SAVE_TYPE_EEPROM_16KBIT;
break; break;
case FLASHCART_SAVE_TYPE_SRAM: case FLASHCART_SAVE_TYPE_SRAM_256KBIT:
type = SAVE_TYPE_SRAM; type = SAVE_TYPE_SRAM_256KBIT;
break; break;
case FLASHCART_SAVE_TYPE_SRAM_BANKED: case FLASHCART_SAVE_TYPE_SRAM_BANKED:
type = SAVE_TYPE_SRAM_BANKED; type = SAVE_TYPE_SRAM_BANKED;
break; break;
case FLASHCART_SAVE_TYPE_SRAM_128K: case FLASHCART_SAVE_TYPE_SRAM_1MBIT:
type = SAVE_TYPE_SRAM_128K; type = SAVE_TYPE_SRAM_1MBIT;
break; break;
case FLASHCART_SAVE_TYPE_FLASHRAM: case FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT:
type = SAVE_TYPE_FLASHRAM; type = SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2: case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2:
type = SAVE_TYPE_FLASHRAM; type = SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
default: default:
return FLASHCART_ERR_ARGS; return FLASHCART_ERR_ARGS;

View File

@ -76,12 +76,12 @@ typedef enum {
/** @brief The SC64 Save Type Enumeration. */ /** @brief The SC64 Save Type Enumeration. */
typedef enum { typedef enum {
SAVE_TYPE_NONE, SAVE_TYPE_NONE,
SAVE_TYPE_EEPROM_4K, SAVE_TYPE_EEPROM_4KBIT,
SAVE_TYPE_EEPROM_16K, SAVE_TYPE_EEPROM_16KBIT,
SAVE_TYPE_SRAM, SAVE_TYPE_SRAM_256KBIT,
SAVE_TYPE_FLASHRAM, SAVE_TYPE_FLASHRAM_1MBIT,
SAVE_TYPE_SRAM_BANKED, SAVE_TYPE_SRAM_BANKED,
SAVE_TYPE_SRAM_128K, SAVE_TYPE_SRAM_1MBIT,
} sc64_save_type_t; } sc64_save_type_t;
typedef enum { typedef enum {

View File

@ -21,6 +21,7 @@ static void actions_clear (menu_t *menu) {
menu->actions.back = false; menu->actions.back = false;
menu->actions.options = false; menu->actions.options = false;
menu->actions.settings = false; menu->actions.settings = false;
menu->actions.lz_context = false;
} }
static void actions_update_direction (menu_t *menu) { static void actions_update_direction (menu_t *menu) {
@ -91,6 +92,8 @@ static void actions_update_buttons (menu_t *menu) {
menu->actions.options = true; menu->actions.options = true;
} else if (pressed.start) { } else if (pressed.start) {
menu->actions.settings = true; menu->actions.settings = true;
} else if (pressed.l || pressed.z) {
menu->actions.lz_context = true;
} }
} }

View File

@ -35,12 +35,12 @@ static bool create_saves_subdirectory (path_t *path) {
static flashcart_save_type_t convert_save_type (rom_save_type_t save_type) { static flashcart_save_type_t convert_save_type (rom_save_type_t save_type) {
switch (save_type) { switch (save_type) {
case SAVE_TYPE_EEPROM_4K: return FLASHCART_SAVE_TYPE_EEPROM_4K; case SAVE_TYPE_EEPROM_4KBIT: return FLASHCART_SAVE_TYPE_EEPROM_4KBIT;
case SAVE_TYPE_EEPROM_16K: return FLASHCART_SAVE_TYPE_EEPROM_16K; case SAVE_TYPE_EEPROM_16KBIT: return FLASHCART_SAVE_TYPE_EEPROM_16KBIT;
case SAVE_TYPE_SRAM: return FLASHCART_SAVE_TYPE_SRAM; case SAVE_TYPE_SRAM_256KBIT: return FLASHCART_SAVE_TYPE_SRAM_256KBIT;
case SAVE_TYPE_SRAM_BANKED: return FLASHCART_SAVE_TYPE_SRAM_BANKED; case SAVE_TYPE_SRAM_BANKED: return FLASHCART_SAVE_TYPE_SRAM_BANKED;
case SAVE_TYPE_SRAM_128K: return FLASHCART_SAVE_TYPE_SRAM_128K; case SAVE_TYPE_SRAM_1MBIT: return FLASHCART_SAVE_TYPE_SRAM_1MBIT;
case SAVE_TYPE_FLASHRAM: return FLASHCART_SAVE_TYPE_FLASHRAM; case SAVE_TYPE_FLASHRAM_1MBIT: return FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
case SAVE_TYPE_FLASHRAM_PKST2: return FLASHCART_SAVE_TYPE_FLASHRAM_PKST2; case SAVE_TYPE_FLASHRAM_PKST2: return FLASHCART_SAVE_TYPE_FLASHRAM_PKST2;
default: return FLASHCART_SAVE_TYPE_NONE; default: return FLASHCART_SAVE_TYPE_NONE;
} }
@ -166,19 +166,19 @@ cart_load_err_t cart_load_emulator (menu_t *menu, cart_load_emu_type_t emu_type,
break; break;
case CART_LOAD_EMU_TYPE_SNES: case CART_LOAD_EMU_TYPE_SNES:
path_push(path, "sodium64.z64"); path_push(path, "sodium64.z64");
save_type = FLASHCART_SAVE_TYPE_SRAM; save_type = FLASHCART_SAVE_TYPE_SRAM_256KBIT;
break; break;
case CART_LOAD_EMU_TYPE_GAMEBOY: case CART_LOAD_EMU_TYPE_GAMEBOY:
path_push(path, "gb.v64"); path_push(path, "gb.v64");
save_type = FLASHCART_SAVE_TYPE_FLASHRAM; save_type = FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
case CART_LOAD_EMU_TYPE_GAMEBOY_COLOR: case CART_LOAD_EMU_TYPE_GAMEBOY_COLOR:
path_push(path, "gbc.v64"); path_push(path, "gbc.v64");
save_type = FLASHCART_SAVE_TYPE_FLASHRAM; save_type = FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
break; break;
case CART_LOAD_EMU_TYPE_SEGA_GENERIC_8BIT: case CART_LOAD_EMU_TYPE_SEGA_GENERIC_8BIT:
path_push(path, "TotalSMS.z64"); path_push(path, "TotalSMS.z64");
save_type = FLASHCART_SAVE_TYPE_SRAM; save_type = FLASHCART_SAVE_TYPE_SRAM_256KBIT;
break; break;
} }

View File

@ -67,6 +67,10 @@ static void menu_init (boot_params_t *boot_params) {
sound_init_default(); sound_init_default();
JOYPAD_PORT_FOREACH (port) {
joypad_set_rumble_active(port, false);
}
menu = calloc(1, sizeof(menu_t)); menu = calloc(1, sizeof(menu_t));
assert(menu != NULL); assert(menu != NULL);
@ -115,8 +119,9 @@ static void menu_init (boot_params_t *boot_params) {
__boot_tvtype = TV_NTSC; __boot_tvtype = TV_NTSC;
} }
if (menu->settings.sound_enabled) {
sound_init_sfx(); sound_init_sfx();
if (menu->settings.sound_enabled) {
sound_use_sfx(true);
} }
display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, FILTERS_DISABLED); display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, FILTERS_DISABLED);

View File

@ -85,6 +85,7 @@ typedef struct {
bool back; bool back;
bool options; bool options;
bool settings; bool settings;
bool lz_context;
} actions; } actions;
struct { struct {

View File

@ -147,234 +147,234 @@ typedef struct {
static const match_t database[] = { static const match_t database[] = {
MATCH_HOMEBREW_HEADER("ED"), // Homebrew header (ED) MATCH_HOMEBREW_HEADER("ED"), // Homebrew header (ED)
MATCH_CHECK_CODE(0x000000004CBC3B56, SAVE_TYPE_SRAM, FEAT_EXP_PAK_REQUIRED | FEAT_64DD_CONVERSION), // DMTJ 64DD cartridge conversion MATCH_CHECK_CODE(0x000000004CBC3B56, SAVE_TYPE_SRAM_256KBIT, FEAT_EXP_PAK_REQUIRED | FEAT_64DD_CONVERSION), // DMTJ 64DD cartridge conversion
MATCH_CHECK_CODE(0x0DD4ABABB5A2A91E, SAVE_TYPE_EEPROM_16K, FEAT_EXP_PAK_REQUIRED), // DK Retail kiosk demo MATCH_CHECK_CODE(0x0DD4ABABB5A2A91E, SAVE_TYPE_EEPROM_16KBIT, FEAT_EXP_PAK_REQUIRED), // DK Retail kiosk demo
MATCH_CHECK_CODE(0xEB85EBC9596682AF, SAVE_TYPE_FLASHRAM, FEAT_NONE), // Doubutsu Banchou MATCH_CHECK_CODE(0xEB85EBC9596682AF, SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Doubutsu Banchou
MATCH_CHECK_CODE(0x9A746EBF2802EA99, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Toon panic MATCH_CHECK_CODE(0x9A746EBF2802EA99, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Toon panic
MATCH_CHECK_CODE(0x21548CA921548CA9, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Mini racers MATCH_CHECK_CODE(0x21548CA921548CA9, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Mini racers
MATCH_CHECK_CODE(0xBC9B2CC34ED04DA5, SAVE_TYPE_FLASHRAM, FEAT_NONE), // Starcraft 64 [Prototype 2000] MATCH_CHECK_CODE(0xBC9B2CC34ED04DA5, SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Starcraft 64 [Prototype 2000]
MATCH_CHECK_CODE(0x5D40ED2C10D6ABCF, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Viewpoint 2064 MATCH_CHECK_CODE(0x5D40ED2C10D6ABCF, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Viewpoint 2064
MATCH_CHECK_CODE(0x7280E03F497689BA, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Viewpoint 2064 [ENG patch] MATCH_CHECK_CODE(0x7280E03F497689BA, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Viewpoint 2064 [ENG patch]
MATCH_CHECK_CODE(0xCDB8B4D08832352D, SAVE_TYPE_SRAM, FEAT_RPAK), // Jet Force Gemini [USA CRACK] MATCH_CHECK_CODE(0xCDB8B4D08832352D, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Jet Force Gemini [USA CRACK]
MATCH_CHECK_CODE(0xB66E0F7C2709C22F, SAVE_TYPE_SRAM, FEAT_RPAK), // Jet Force Gemini [PAL CRACK] MATCH_CHECK_CODE(0xB66E0F7C2709C22F, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Jet Force Gemini [PAL CRACK]
MATCH_CHECK_CODE(0xCE84793D27ECC1AD, SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey kong 64 [USA CRACK] MATCH_CHECK_CODE(0xCE84793D27ECC1AD, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey kong 64 [USA CRACK]
MATCH_CHECK_CODE(0x1F95CAAA047FC22A, SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey kong 64 [PAL CRACK] MATCH_CHECK_CODE(0x1F95CAAA047FC22A, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey kong 64 [PAL CRACK]
MATCH_CHECK_CODE(0xE3FF09DFCAE4B0ED, SAVE_TYPE_SRAM, FEAT_RPAK), // Banjo tooie [USA CRACK] MATCH_CHECK_CODE(0xE3FF09DFCAE4B0ED, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Banjo tooie [USA CRACK]
MATCH_ID_REGION_VERSION("NK4J", 0, SAVE_TYPE_SRAM, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)] MATCH_ID_REGION_VERSION("NK4J", 0, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)]
MATCH_ID_REGION_VERSION("NK4J", 1, SAVE_TYPE_SRAM, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)] MATCH_ID_REGION_VERSION("NK4J", 1, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)]
MATCH_ID("NK4", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)] MATCH_ID("NK4", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Kirby 64: The Crystal Shards [Hoshi no Kirby 64 (J)]
MATCH_ID_REGION_VERSION("NSMJ", 3, SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Super Mario 64 Shindou Edition MATCH_ID_REGION_VERSION("NSMJ", 3, SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Super Mario 64 Shindou Edition
MATCH_ID("NSM", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Super Mario 64 MATCH_ID("NSM", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Super Mario 64
MATCH_ID_REGION_VERSION("NWRJ", 2, SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Wave Race 64 Shindou Edition MATCH_ID_REGION_VERSION("NWRJ", 2, SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Wave Race 64 Shindou Edition
MATCH_ID("NWR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Wave Race 64 MATCH_ID("NWR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Wave Race 64
MATCH_ID_REGION("N3HJ", SAVE_TYPE_SRAM, FEAT_NONE), // Ganbare! Nippon! Olympics 2000 MATCH_ID_REGION("N3HJ", SAVE_TYPE_SRAM_256KBIT, FEAT_NONE), // Ganbare! Nippon! Olympics 2000
MATCH_ID("N3H", SAVE_TYPE_NONE, FEAT_CPAK), // International Track & Field 2000 MATCH_ID("N3H", SAVE_TYPE_NONE, FEAT_CPAK), // International Track & Field 2000
MATCH_ID_REGION("ND3J", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Akumajou Dracula Mokushiroku (J) MATCH_ID_REGION("ND3J", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Akumajou Dracula Mokushiroku (J)
MATCH_ID("ND3", SAVE_TYPE_NONE, FEAT_CPAK), // Castlevania MATCH_ID("ND3", SAVE_TYPE_NONE, FEAT_CPAK), // Castlevania
MATCH_ID_REGION("ND4J", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Akumajou Dracula Mokushiroku Gaiden: Legend of Cornell (J) MATCH_ID_REGION("ND4J", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Akumajou Dracula Mokushiroku Gaiden: Legend of Cornell (J)
MATCH_ID("ND4", SAVE_TYPE_NONE, FEAT_CPAK), // Castlevania - Legacy of Darkness MATCH_ID("ND4", SAVE_TYPE_NONE, FEAT_CPAK), // Castlevania - Legacy of Darkness
MATCH_ID_REGION("NDKJ", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Dark Rift [Space Dynamites (J)] MATCH_ID_REGION("NDKJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Dark Rift [Space Dynamites (J)]
MATCH_ID_REGION("NSVE", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Space Station Silicon Valley MATCH_ID_REGION("NSVE", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Space Station Silicon Valley
MATCH_ID("NSV", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_EXP_PAK_BROKEN), // Space Station Silicon Valley MATCH_ID("NSV", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_EXP_PAK_BROKEN), // Space Station Silicon Valley
MATCH_ID_REGION("NWTJ", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Wetrix MATCH_ID_REGION("NWTJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Wetrix
MATCH_ID("NWT", SAVE_TYPE_NONE, FEAT_CPAK), // Wetrix MATCH_ID("NWT", SAVE_TYPE_NONE, FEAT_CPAK), // Wetrix
// EEPROM 4K // EEPROM 4K
MATCH_ID("CLB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_64DD_ENHANCED), // Mario Party (NTSC) MATCH_ID("CLB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_64DD_ENHANCED), // Mario Party (NTSC)
MATCH_ID("NAB", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Air Boarder 64 MATCH_ID("NAB", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Air Boarder 64
MATCH_ID("NAD", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Worms Armageddon (U) MATCH_ID("NAD", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Worms Armageddon (U)
MATCH_ID("NAG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // AeroGauge MATCH_ID("NAG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // AeroGauge
MATCH_ID("NB6", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_TPAK), // Super B-Daman: Battle Phoenix 64 MATCH_ID("NB6", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_TPAK), // Super B-Daman: Battle Phoenix 64
MATCH_ID("NBC", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Blast Corps MATCH_ID("NBC", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Blast Corps
MATCH_ID("NBD", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Bomberman Hero [Mirian Ojo o Sukue! (J)] MATCH_ID("NBD", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Bomberman Hero [Mirian Ojo o Sukue! (J)]
MATCH_ID("NBH", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Body Harvest MATCH_ID("NBH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Body Harvest
MATCH_ID("NBK", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Banjo-Kazooie [Banjo to Kazooie no Daiboken (J)] MATCH_ID("NBK", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Banjo-Kazooie [Banjo to Kazooie no Daiboken (J)]
MATCH_ID("NBM", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Bomberman 64 [Baku Bomberman (J)] MATCH_ID("NBM", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bomberman 64 [Baku Bomberman (J)]
MATCH_ID("NBN", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Bakuretsu Muteki Bangaioh MATCH_ID("NBN", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bakuretsu Muteki Bangaioh
MATCH_ID("NBV", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Bomberman 64: The Second Attack! [Baku Bomberman 2 (J)] MATCH_ID("NBV", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Bomberman 64: The Second Attack! [Baku Bomberman 2 (J)]
MATCH_ID("NCG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Choro Q 64 II - Hacha Mecha Grand Prix Race (J) MATCH_ID("NCG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Choro Q 64 II - Hacha Mecha Grand Prix Race (J)
MATCH_ID("NCH", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Chopper Attack MATCH_ID("NCH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Chopper Attack
MATCH_ID("NCR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Penny Racers [Choro Q 64 (J)] MATCH_ID("NCR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Penny Racers [Choro Q 64 (J)]
MATCH_ID("NCT", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Chameleon Twist MATCH_ID("NCT", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Chameleon Twist
MATCH_ID("NCU", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Cruis'n USA MATCH_ID("NCU", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Cruis'n USA
MATCH_ID("NCX", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Custom Robo MATCH_ID("NCX", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Custom Robo
MATCH_ID("NDQ", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Disney's Donald Duck - Goin' Quackers [Quack Attack (E)] MATCH_ID("NDQ", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Disney's Donald Duck - Goin' Quackers [Quack Attack (E)]
MATCH_ID("NDR", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Doraemon: Nobita to 3tsu no Seireiseki MATCH_ID("NDR", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Doraemon: Nobita to 3tsu no Seireiseki
MATCH_ID("NDU", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Duck Dodgers starring Daffy Duck MATCH_ID("NDU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Duck Dodgers starring Daffy Duck
MATCH_ID("NDY", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Diddy Kong Racing MATCH_ID("NDY", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Diddy Kong Racing
MATCH_ID("NEA", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // PGA European Tour MATCH_ID("NEA", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // PGA European Tour
MATCH_ID("NER", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Aero Fighters Assault [Sonic Wings Assault (J)] MATCH_ID("NER", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Aero Fighters Assault [Sonic Wings Assault (J)]
MATCH_ID("NF2", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // F-1 World Grand Prix II MATCH_ID("NF2", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // F-1 World Grand Prix II
MATCH_ID("NFG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Fighter Destiny 2 MATCH_ID("NFG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Fighter Destiny 2
MATCH_ID("NFH", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // In-Fisherman Bass Hunter 64 MATCH_ID("NFH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // In-Fisherman Bass Hunter 64
MATCH_ID("NFW", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // F-1 World Grand Prix MATCH_ID("NFW", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // F-1 World Grand Prix
MATCH_ID("NFX", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Fox 64 [Lylat Wars (E)] MATCH_ID("NFX", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Fox 64 [Lylat Wars (E)]
MATCH_ID("NFY", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Kakutou Denshou: F-Cup Maniax MATCH_ID("NFY", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Kakutou Denshou: F-Cup Maniax
MATCH_ID("NGE", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // GoldenEye 007 MATCH_ID("NGE", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // GoldenEye 007
MATCH_ID("NGL", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Getter Love!! MATCH_ID("NGL", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Getter Love!!
MATCH_ID("NGU", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Tsumi to Batsu: Hoshi no Keishousha (Sin and Punishment) MATCH_ID("NGU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Tsumi to Batsu: Hoshi no Keishousha (Sin and Punishment)
MATCH_ID("NGV", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Glover MATCH_ID("NGV", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Glover
MATCH_ID("NHA", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Bomberman 64: Arcade Edition (J) MATCH_ID("NHA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bomberman 64: Arcade Edition (J)
MATCH_ID("NHF", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // 64 Hanafuda: Tenshi no Yakusoku MATCH_ID("NHF", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // 64 Hanafuda: Tenshi no Yakusoku
MATCH_ID("NHP", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Heiwa Pachinko World 64 MATCH_ID("NHP", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Heiwa Pachinko World 64
MATCH_ID("NIC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Indy Racing 2000 MATCH_ID("NIC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Indy Racing 2000
MATCH_ID("NIJ", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // Indiana Jones and the Infernal Machine MATCH_ID("NIJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // Indiana Jones and the Infernal Machine
MATCH_ID("NIR", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Utchan Nanchan no Hono no Challenger: Denryuu Ira Ira Bou MATCH_ID("NIR", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Utchan Nanchan no Hono no Challenger: Denryuu Ira Ira Bou
MATCH_ID("NJM", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Earthworm Jim 3D MATCH_ID("NJM", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Earthworm Jim 3D
MATCH_ID("NK2", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Snowboard Kids 2 [Chou Snobow Kids (J)] MATCH_ID("NK2", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Snowboard Kids 2 [Chou Snobow Kids (J)]
MATCH_ID("NKA", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Fighters Destiny [Fighting Cup (J)] MATCH_ID("NKA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Fighters Destiny [Fighting Cup (J)]
MATCH_ID("NKI", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Killer Instinct Gold MATCH_ID("NKI", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Killer Instinct Gold
MATCH_ID("NKT", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Mario Kart 64 MATCH_ID("NKT", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Mario Kart 64
MATCH_ID("NLB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Mario Party (PAL) MATCH_ID("NLB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mario Party (PAL)
MATCH_ID("NLL", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Last Legion UX MATCH_ID("NLL", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Last Legion UX
MATCH_ID("NLR", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Lode Runner 3-D MATCH_ID("NLR", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Lode Runner 3-D
MATCH_ID("NMG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Monaco Grand Prix [Racing Simulation 2 (G)] MATCH_ID("NMG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Monaco Grand Prix [Racing Simulation 2 (G)]
MATCH_ID("NMI", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Mission: Impossible MATCH_ID("NMI", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mission: Impossible
MATCH_ID("NML", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_TPAK), // Mickey's Speedway USA [Mickey no Racing Challenge USA (J)] MATCH_ID("NML", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_TPAK), // Mickey's Speedway USA [Mickey no Racing Challenge USA (J)]
MATCH_ID("NMO", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Monopoly MATCH_ID("NMO", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Monopoly
MATCH_ID("NMR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Multi-Racing Championship MATCH_ID("NMR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Multi-Racing Championship
MATCH_ID("NMS", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Morita Shougi 64 MATCH_ID("NMS", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Morita Shougi 64
MATCH_ID("NMU", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Big Mountain 2000 MATCH_ID("NMU", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Big Mountain 2000
MATCH_ID("NMW", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Mario Party 2 MATCH_ID("NMW", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mario Party 2
MATCH_ID("NMZ", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Zool - Majou Tsukai Densetsu (J) MATCH_ID("NMZ", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Zool - Majou Tsukai Densetsu (J)
MATCH_ID("NN6", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Dr. Mario 64 MATCH_ID("NN6", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Dr. Mario 64
MATCH_ID("NNA", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Wars Episode I: Battle for Naboo MATCH_ID("NNA", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Wars Episode I: Battle for Naboo
MATCH_ID("NOS", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // 64 Oozumou MATCH_ID("NOS", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // 64 Oozumou
MATCH_ID("NP2", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Chou Kuukan Night Pro Yakyuu King 2 (J) MATCH_ID("NP2", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Chou Kuukan Night Pro Yakyuu King 2 (J)
MATCH_ID("NPG", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_VRU), // Hey You, Pikachu! [Pikachu Genki Dechu (J)] MATCH_ID("NPG", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_VRU), // Hey You, Pikachu! [Pikachu Genki Dechu (J)]
MATCH_ID("NPT", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_TPAK), // Puyo Puyon Party MATCH_ID("NPT", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_TPAK), // Puyo Puyon Party
MATCH_ID("NPW", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Pilotwings 64 MATCH_ID("NPW", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Pilotwings 64
MATCH_ID("NPY", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Puyo Puyo Sun 64 MATCH_ID("NPY", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Puyo Puyo Sun 64
MATCH_ID("NRA", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Rally '99 (J) MATCH_ID("NRA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Rally '99 (J)
MATCH_ID("NRC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Top Gear Overdrive MATCH_ID("NRC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Top Gear Overdrive
MATCH_ID("NRS", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Wars: Rogue Squadron [Shutsugeki! Rogue Chuutai (J)] MATCH_ID("NRS", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Wars: Rogue Squadron [Shutsugeki! Rogue Chuutai (J)]
MATCH_ID("NS3", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // AI Shougi 3 MATCH_ID("NS3", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // AI Shougi 3
MATCH_ID("NS6", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Soldier: Vanishing Earth MATCH_ID("NS6", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Soldier: Vanishing Earth
MATCH_ID("NSA", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Sonic Wings Assault (J) MATCH_ID("NSA", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Sonic Wings Assault (J)
MATCH_ID("NSC", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Starshot: Space Circus Fever MATCH_ID("NSC", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Starshot: Space Circus Fever
MATCH_ID("NSN", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Snow Speeder (J) MATCH_ID("NSN", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Snow Speeder (J)
MATCH_ID("NSS", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Super Robot Spirits MATCH_ID("NSS", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Super Robot Spirits
MATCH_ID("NSU", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Rocket: Robot on Wheels MATCH_ID("NSU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Rocket: Robot on Wheels
MATCH_ID("NSW", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Star Wars: Shadows of the Empire [Teikoku no Kage (J)] MATCH_ID("NSW", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Star Wars: Shadows of the Empire [Teikoku no Kage (J)]
MATCH_ID("NT6", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Tetris 64 MATCH_ID("NT6", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Tetris 64
MATCH_ID("NTB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Transformers: Beast Wars Metals 64 (J) MATCH_ID("NTB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Transformers: Beast Wars Metals 64 (J)
MATCH_ID("NTC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // 64 Trump Collection MATCH_ID("NTC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // 64 Trump Collection
MATCH_ID("NTJ", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Tom & Jerry in Fists of Fury MATCH_ID("NTJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Tom & Jerry in Fists of Fury
MATCH_ID("NTM", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Mischief Makers [Yuke Yuke!! Trouble Makers (J)] MATCH_ID("NTM", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Mischief Makers [Yuke Yuke!! Trouble Makers (J)]
MATCH_ID("NTN", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // All Star Tennis '99 MATCH_ID("NTN", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // All Star Tennis '99
MATCH_ID("NTP", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Tetrisphere MATCH_ID("NTP", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Tetrisphere
MATCH_ID("NTR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Top Gear Rally (J + E) MATCH_ID("NTR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Top Gear Rally (J + E)
MATCH_ID("NTW", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // 64 de Hakken!! Tamagotchi MATCH_ID("NTW", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // 64 de Hakken!! Tamagotchi
MATCH_ID("NTX", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Taz Express MATCH_ID("NTX", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Taz Express
MATCH_ID("NVL", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // V-Rally Edition '99 MATCH_ID("NVL", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // V-Rally Edition '99
MATCH_ID("NVY", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // V-Rally Edition '99 (J) MATCH_ID("NVY", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // V-Rally Edition '99 (J)
MATCH_ID("NWC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Wild Choppers MATCH_ID("NWC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Wild Choppers
MATCH_ID("NWQ", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Rally Challenge 2000 MATCH_ID("NWQ", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Rally Challenge 2000
MATCH_ID("NWU", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Worms Armageddon (E) MATCH_ID("NWU", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Worms Armageddon (E)
MATCH_ID("NXO", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Cruis'n Exotica MATCH_ID("NXO", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Cruis'n Exotica
MATCH_ID("NYK", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Yakouchuu II: Satsujin Kouro MATCH_ID("NYK", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Yakouchuu II: Satsujin Kouro
// EEPROM 16K // EEPROM 16K
MATCH_ID("N3D", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Doraemon 3: Nobita no Machi SOS! MATCH_ID("N3D", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Doraemon 3: Nobita no Machi SOS!
MATCH_ID("NB7", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Banjo-Tooie [Banjo to Kazooie no Daiboken 2 (J)] MATCH_ID("NB7", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Banjo-Tooie [Banjo to Kazooie no Daiboken 2 (J)]
MATCH_ID("NCW", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Cruis'n World MATCH_ID("NCW", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Cruis'n World
MATCH_ID("NCZ", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Custom Robo V2 MATCH_ID("NCZ", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Custom Robo V2
MATCH_ID("ND2", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Doraemon 2: Nobita to Hikari no Shinden MATCH_ID("ND2", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Doraemon 2: Nobita to Hikari no Shinden
MATCH_ID("ND6", SAVE_TYPE_EEPROM_16K, FEAT_RPAK | FEAT_VRU), // Densha de Go! 64 MATCH_ID("ND6", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_VRU), // Densha de Go! 64
MATCH_ID("NDO", SAVE_TYPE_EEPROM_16K, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey Kong 64 MATCH_ID("NDO", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey Kong 64
MATCH_ID("NEP", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Star Wars Episode I: Racer MATCH_ID("NEP", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Star Wars Episode I: Racer
MATCH_ID("NEV", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Neon Genesis Evangelion MATCH_ID("NEV", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Neon Genesis Evangelion
MATCH_ID("NFU", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Conker's Bad Fur Day MATCH_ID("NFU", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Conker's Bad Fur Day
MATCH_ID("NGC", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK), // GT 64: Championship Edition MATCH_ID("NGC", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // GT 64: Championship Edition
MATCH_ID("NGT", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK), // City Tour GrandPrix - Zen Nihon GT Senshuken MATCH_ID("NGT", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // City Tour GrandPrix - Zen Nihon GT Senshuken
MATCH_ID("NIM", SAVE_TYPE_EEPROM_16K, FEAT_NONE), // Ide Yosuke no Mahjong Juku MATCH_ID("NIM", SAVE_TYPE_EEPROM_16KBIT, FEAT_NONE), // Ide Yosuke no Mahjong Juku
MATCH_ID("NM8", SAVE_TYPE_EEPROM_16K, FEAT_RPAK | FEAT_TPAK), // Mario Tennis MATCH_ID("NM8", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_TPAK), // Mario Tennis
MATCH_ID("NMV", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Mario Party 3 MATCH_ID("NMV", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Mario Party 3
MATCH_ID("NMX", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK), // Excitebike 64 MATCH_ID("NMX", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Excitebike 64
MATCH_ID("NNB", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK), // Kobe Bryant in NBA Courtside MATCH_ID("NNB", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Kobe Bryant in NBA Courtside
MATCH_ID("NPD", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK | FEAT_EXP_PAK_RECOMMENDED), // Perfect Dark MATCH_ID("NPD", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK | FEAT_EXP_PAK_RECOMMENDED), // Perfect Dark
MATCH_ID("NPP", SAVE_TYPE_EEPROM_16K, FEAT_CPAK), // Parlor! Pro 64: Pachinko Jikki Simulation Game MATCH_ID("NPP", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK), // Parlor! Pro 64: Pachinko Jikki Simulation Game
MATCH_ID("NR7", SAVE_TYPE_EEPROM_16K, FEAT_TPAK), // Robot Poncots 64: 7tsu no Umi no Caramel MATCH_ID("NR7", SAVE_TYPE_EEPROM_16KBIT, FEAT_TPAK), // Robot Poncots 64: 7tsu no Umi no Caramel
MATCH_ID("NRZ", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Ridge Racer 64 MATCH_ID("NRZ", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Ridge Racer 64
MATCH_ID("NUB", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_TPAK), // PD Ultraman Battle Collection 64 MATCH_ID("NUB", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_TPAK), // PD Ultraman Battle Collection 64
MATCH_ID("NYS", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Yoshi's Story MATCH_ID("NYS", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Yoshi's Story
// SRAM 256K // SRAM 256K
MATCH_ID("CFZ", SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_64DD_ENHANCED), // F-Zero X (J) MATCH_ID("CFZ", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_64DD_ENHANCED), // F-Zero X (J)
MATCH_ID("CPS", SAVE_TYPE_SRAM, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium (J) MATCH_ID("CPS", SAVE_TYPE_SRAM_256KBIT, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium (J)
MATCH_ID("CZL", SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_64DD_ENHANCED), // Legend of Zelda: Ocarina of Time [Zelda no Densetsu - Toki no Ocarina (J)] MATCH_ID("CZL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_64DD_ENHANCED), // Legend of Zelda: Ocarina of Time [Zelda no Densetsu - Toki no Ocarina (J)]
MATCH_ID("NA2", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 2 MATCH_ID("NA2", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 2
MATCH_ID("NAL", SAVE_TYPE_SRAM, FEAT_RPAK), // Super Smash Bros. [Nintendo All-Star! Dairantou Smash Brothers (J)] MATCH_ID("NAL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Super Smash Bros. [Nintendo All-Star! Dairantou Smash Brothers (J)]
MATCH_ID("NB5", SAVE_TYPE_SRAM, FEAT_RPAK), // Biohazard 2 (J) MATCH_ID("NB5", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Biohazard 2 (J)
MATCH_ID("NDD", SAVE_TYPE_SRAM, FEAT_EXP_PAK_REQUIRED | FEAT_64DD_CONVERSION), // 64DD Conversion Rom MATCH_ID("NDD", SAVE_TYPE_SRAM_256KBIT, FEAT_EXP_PAK_REQUIRED | FEAT_64DD_CONVERSION), // 64DD Conversion Rom
MATCH_ID("NFZ", SAVE_TYPE_SRAM, FEAT_RPAK), // F-Zero X (U + E) MATCH_ID("NFZ", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // F-Zero X (U + E)
MATCH_ID("NG6", SAVE_TYPE_SRAM, FEAT_RPAK), // Ganmare Goemon: Dero Dero Douchuu Obake Tenkomori MATCH_ID("NG6", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Ganmare Goemon: Dero Dero Douchuu Obake Tenkomori
MATCH_ID("NGP", SAVE_TYPE_SRAM, FEAT_CPAK), // Goemon: Mononoke Sugoroku MATCH_ID("NGP", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Goemon: Mononoke Sugoroku
MATCH_ID("NHY", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Hybrid Heaven (J) MATCH_ID("NHY", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Hybrid Heaven (J)
MATCH_ID("NIB", SAVE_TYPE_SRAM, FEAT_RPAK), // Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban! MATCH_ID("NIB", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!
MATCH_ID("NJ5", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 5 MATCH_ID("NJ5", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 5
MATCH_ID("NJG", SAVE_TYPE_SRAM, FEAT_RPAK), // Jinsei Game 64 MATCH_ID("NJG", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Jinsei Game 64
MATCH_ID("NKG", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Major League Baseball featuring Ken Griffey Jr. MATCH_ID("NKG", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Major League Baseball featuring Ken Griffey Jr.
MATCH_ID("NMF", SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_TPAK), // Mario Golf 64 MATCH_ID("NMF", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_TPAK), // Mario Golf 64
MATCH_ID("NOB", SAVE_TYPE_SRAM, FEAT_NONE), // Ogre Battle 64: Person of Lordly Caliber MATCH_ID("NOB", SAVE_TYPE_SRAM_256KBIT, FEAT_NONE), // Ogre Battle 64: Person of Lordly Caliber
MATCH_ID("NP4", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 4 MATCH_ID("NP4", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 4
MATCH_ID("NP6", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 6 MATCH_ID("NP6", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 6
MATCH_ID("NPA", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 2000 MATCH_ID("NPA", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 2000
MATCH_ID("NPE", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu Basic Ban 2001 MATCH_ID("NPE", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu Basic Ban 2001
MATCH_ID("NPM", SAVE_TYPE_SRAM, FEAT_CPAK), // Premier Manager 64 MATCH_ID("NPM", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Premier Manager 64
MATCH_ID("NPS", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Jikkyou J.League 1999: Perfect Striker 2 MATCH_ID("NPS", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Jikkyou J.League 1999: Perfect Striker 2
MATCH_ID("NRE", SAVE_TYPE_SRAM, FEAT_RPAK), // Resident Evil 2 MATCH_ID("NRE", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Resident Evil 2
MATCH_ID("NRI", SAVE_TYPE_SRAM, FEAT_CPAK), // New Tetris, The MATCH_ID("NRI", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // New Tetris, The
MATCH_ID("NS4", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_TPAK), // Super Robot Taisen 64 MATCH_ID("NS4", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Super Robot Taisen 64
MATCH_ID("NSI", SAVE_TYPE_SRAM, FEAT_CPAK), // Fushigi no Dungeon: Fuurai no Shiren 2 MATCH_ID("NSI", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Fushigi no Dungeon: Fuurai no Shiren 2
MATCH_ID("NT3", SAVE_TYPE_SRAM, FEAT_CPAK), // Shin Nihon Pro Wrestling - Toukon Road 2 - The Next Generation (J) MATCH_ID("NT3", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Shin Nihon Pro Wrestling - Toukon Road 2 - The Next Generation (J)
MATCH_ID("NTE", SAVE_TYPE_SRAM, FEAT_RPAK), // 1080 Snowboarding MATCH_ID("NTE", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // 1080 Snowboarding
MATCH_ID("NUM", SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64: Shiokaze ni Notte MATCH_ID("NUM", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64: Shiokaze ni Notte
MATCH_ID("NUT", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64 MATCH_ID("NUT", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64
MATCH_ID("NVB", SAVE_TYPE_SRAM, FEAT_RPAK), // Bass Rush - ECOGEAR PowerWorm Championship (J) MATCH_ID("NVB", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Bass Rush - ECOGEAR PowerWorm Championship (J)
MATCH_ID("NVP", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 64 MATCH_ID("NVP", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 64
MATCH_ID("NW2", SAVE_TYPE_SRAM, FEAT_RPAK), // WCW-nWo Revenge MATCH_ID("NW2", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // WCW-nWo Revenge
MATCH_ID("NWL", SAVE_TYPE_SRAM, FEAT_RPAK), // Waialae Country Club: True Golf Classics MATCH_ID("NWL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Waialae Country Club: True Golf Classics
MATCH_ID("NWX", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // WWF WrestleMania 2000 MATCH_ID("NWX", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // WWF WrestleMania 2000
MATCH_ID("NYW", SAVE_TYPE_SRAM, FEAT_NONE), // Harvest Moon 64 MATCH_ID("NYW", SAVE_TYPE_SRAM_256KBIT, FEAT_NONE), // Harvest Moon 64
MATCH_ID("NZL", SAVE_TYPE_SRAM, FEAT_RPAK), // Legend of Zelda: Ocarina of Time (E) MATCH_ID("NZL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Legend of Zelda: Ocarina of Time (E)
// SRAM 768K // SRAM 768K
MATCH_ID("CDZ", SAVE_TYPE_SRAM_BANKED, FEAT_RPAK | FEAT_64DD_ENHANCED), // Dezaemon 3D MATCH_ID("CDZ", SAVE_TYPE_SRAM_BANKED, FEAT_RPAK | FEAT_64DD_ENHANCED), // Dezaemon 3D
// FLASHRAM // FLASHRAM
MATCH_ID("CP2", SAVE_TYPE_FLASHRAM, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium 2 (J) MATCH_ID("CP2", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium 2 (J)
MATCH_ID("NAF", SAVE_TYPE_FLASHRAM, FEAT_CPAK | FEAT_RTC), // Doubutsu no Mori MATCH_ID("NAF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK | FEAT_RTC), // Doubutsu no Mori
MATCH_ID("NCC", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Command & Conquer MATCH_ID("NCC", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Command & Conquer
MATCH_ID("NCV", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Cubivore (Translation) MATCH_ID("NCV", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Cubivore (Translation)
MATCH_ID("NCK", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // NBA Courtside 2 featuring Kobe Bryant MATCH_ID("NCK", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // NBA Courtside 2 featuring Kobe Bryant
MATCH_ID("NDA", SAVE_TYPE_FLASHRAM, FEAT_CPAK), // Derby Stallion 64 MATCH_ID("NDA", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK), // Derby Stallion 64
MATCH_ID("NDP", SAVE_TYPE_FLASHRAM, FEAT_EXP_PAK_REQUIRED), // Dinosaur Planet (Unlicensed) MATCH_ID("NDP", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_EXP_PAK_REQUIRED), // Dinosaur Planet (Unlicensed)
MATCH_ID("NJF", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Jet Force Gemini [Star Twins (J)] MATCH_ID("NJF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Jet Force Gemini [Star Twins (J)]
MATCH_ID("NKJ", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Ken Griffey Jr.'s Slugfest MATCH_ID("NKJ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Ken Griffey Jr.'s Slugfest
MATCH_ID("NM6", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Mega Man 64 MATCH_ID("NM6", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Mega Man 64
MATCH_ID("NMQ", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Paper Mario MATCH_ID("NMQ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Paper Mario
MATCH_ID("NPF", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Pokemon Snap [Pocket Monsters Snap (J)] MATCH_ID("NPF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Pokemon Snap [Pocket Monsters Snap (J)]
MATCH_ID("NPN", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Pokemon Puzzle League MATCH_ID("NPN", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Pokemon Puzzle League
MATCH_ID("NPO", SAVE_TYPE_FLASHRAM, FEAT_TPAK), // Pokemon Stadium MATCH_ID("NPO", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_TPAK), // Pokemon Stadium
MATCH_ID("NRH", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Rockman Dash - Hagane no Boukenshin (J) MATCH_ID("NRH", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Rockman Dash - Hagane no Boukenshin (J)
MATCH_ID("NSQ", SAVE_TYPE_FLASHRAM, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // StarCraft 64 MATCH_ID("NSQ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // StarCraft 64
MATCH_ID("NT9", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Tigger's Honey Hunt MATCH_ID("NT9", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Tigger's Honey Hunt
MATCH_ID("NW4", SAVE_TYPE_FLASHRAM, FEAT_CPAK | FEAT_RPAK), // WWF No Mercy MATCH_ID("NW4", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK | FEAT_RPAK), // WWF No Mercy
MATCH_ID("NZS", SAVE_TYPE_FLASHRAM, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Legend of Zelda: Majora's Mask [Zelda no Densetsu - Mujura no Kamen (J)] MATCH_ID("NZS", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Legend of Zelda: Majora's Mask [Zelda no Densetsu - Mujura no Kamen (J)]
MATCH_ID("NP3", SAVE_TYPE_FLASHRAM_PKST2, FEAT_TPAK), // Pokemon Stadium 2 [Pocket Monsters Stadium - Kin Gin (J)] MATCH_ID("NP3", SAVE_TYPE_FLASHRAM_PKST2, FEAT_TPAK), // Pokemon Stadium 2 [Pocket Monsters Stadium - Kin Gin (J)]
@ -750,12 +750,12 @@ static void extract_rom_info (match_t *match, rom_header_t *rom_header, rom_info
} }
switch ((rom_header->version & 0xF0) >> 4) { switch ((rom_header->version & 0xF0) >> 4) {
case 0: match->data.save = SAVE_TYPE_NONE; break; case 0: match->data.save = SAVE_TYPE_NONE; break;
case 1: match->data.save = SAVE_TYPE_EEPROM_4K; break; case 1: match->data.save = SAVE_TYPE_EEPROM_4KBIT; break;
case 2: match->data.save = SAVE_TYPE_EEPROM_16K; break; case 2: match->data.save = SAVE_TYPE_EEPROM_16KBIT; break;
case 3: match->data.save = SAVE_TYPE_SRAM; break; case 3: match->data.save = SAVE_TYPE_SRAM_256KBIT; break;
case 4: match->data.save = SAVE_TYPE_SRAM_BANKED; break; case 4: match->data.save = SAVE_TYPE_SRAM_BANKED; break;
case 5: match->data.save = SAVE_TYPE_FLASHRAM; break; case 5: match->data.save = SAVE_TYPE_FLASHRAM_1MBIT; break;
case 6: match->data.save = SAVE_TYPE_SRAM_128K; break; case 6: match->data.save = SAVE_TYPE_SRAM_1MBIT; break;
default: match->data.save = SAVE_TYPE_NONE; break; default: match->data.save = SAVE_TYPE_NONE; break;
} }
} }

View File

@ -114,12 +114,12 @@ typedef enum {
typedef enum { typedef enum {
/** @brief There is no expected save type. */ /** @brief There is no expected save type. */
SAVE_TYPE_NONE = 0, SAVE_TYPE_NONE = 0,
SAVE_TYPE_EEPROM_4K = 1, SAVE_TYPE_EEPROM_4KBIT = 1,
SAVE_TYPE_EEPROM_16K = 2, SAVE_TYPE_EEPROM_16KBIT = 2,
SAVE_TYPE_SRAM = 3, SAVE_TYPE_SRAM_256KBIT = 3,
SAVE_TYPE_SRAM_BANKED = 4, SAVE_TYPE_SRAM_BANKED = 4,
SAVE_TYPE_SRAM_128K = 5, SAVE_TYPE_SRAM_1MBIT = 5,
SAVE_TYPE_FLASHRAM = 6, SAVE_TYPE_FLASHRAM_1MBIT = 6,
SAVE_TYPE_FLASHRAM_PKST2 = 7, SAVE_TYPE_FLASHRAM_PKST2 = 7,
SAVE_TYPE_AUTOMATIC = -1, SAVE_TYPE_AUTOMATIC = -1,
} rom_save_type_t; } rom_save_type_t;

View File

@ -50,6 +50,14 @@ void sound_init_sfx (void) {
sfx_enabled = true; sfx_enabled = true;
} }
void sound_use_sfx(bool state) {
if (state) {
sfx_enabled = true;
}
else {
sfx_enabled = false;
}
}
void sound_play_effect(sound_effect_t sfx) { void sound_play_effect(sound_effect_t sfx) {
if(sfx_enabled) { if(sfx_enabled) {

View File

@ -7,6 +7,7 @@
#ifndef SOUND_H__ #ifndef SOUND_H__
#define SOUND_H__ #define SOUND_H__
#include <stdbool.h>
#define SOUND_MP3_PLAYER_CHANNEL (0) #define SOUND_MP3_PLAYER_CHANNEL (0)
#define SOUND_SFX_CHANNEL (2) #define SOUND_SFX_CHANNEL (2)
@ -23,6 +24,7 @@ typedef enum {
void sound_init_default (void); void sound_init_default (void);
void sound_init_mp3_playback (void); void sound_init_mp3_playback (void);
void sound_init_sfx (void); void sound_init_sfx (void);
void sound_use_sfx(bool);
void sound_play_effect(sound_effect_t sfx); void sound_play_effect(sound_effect_t sfx);
void sound_deinit (void); void sound_deinit (void);
void sound_poll (void); void sound_poll (void);

View File

@ -25,7 +25,14 @@ static const char *hidden_paths[] = {
"/ED64", "/ED64",
"/ED64P", "/ED64P",
"/sc64menu.n64", "/sc64menu.n64",
// Windows garbage
"/System Volume Information", "/System Volume Information",
// macOS garbage
"/.fseventsd",
"/.Spotlight-V100",
"/.Trashes",
"/.VolumeIcon.icns",
"/.metadata_never_index",
NULL, NULL,
}; };

View File

@ -13,8 +13,8 @@ static const char *patch_extensions[] = { "aps", "bps", "ips", "pps", "ups", "xd
static const char *archive_extensions[] = { "zip", "rar", "7z", "tar", "gz", NULL }; static const char *archive_extensions[] = { "zip", "rar", "7z", "tar", "gz", NULL };
static const char *image_extensions[] = { "png", "jpg", "gif", NULL }; static const char *image_extensions[] = { "png", "jpg", "gif", NULL };
static const char *music_extensions[] = { "mp3", "wav", "ogg", "wma", "flac", NULL }; static const char *music_extensions[] = { "mp3", "wav", "ogg", "wma", "flac", NULL };
static const char *dexdrive_extensions[] = { "mpk", NULL }; static const char *controller_pak_extensions[] = { "mpk", "pak", NULL };
static const char *emulator_extensions[] = { "emu", NULL }; static const char *emulator_extensions[] = { "nes", "smc", "gb", "gbc", "sms", "gg", NULL };
static struct stat st; static struct stat st;
@ -39,10 +39,10 @@ static char *format_file_type (char *name, bool is_directory) {
return " Type: Image file\n"; return " Type: Image file\n";
} else if (file_has_extensions(name, music_extensions)) { } else if (file_has_extensions(name, music_extensions)) {
return " Type: Music file\n"; return " Type: Music file\n";
} else if (file_has_extensions(name, dexdrive_extensions)) { } else if (file_has_extensions(name, controller_pak_extensions)) {
return " Type: DexDrive CPak backup file\n"; return " Type: Controller Pak file\n";
} else if (file_has_extensions(name, emulator_extensions)) { } else if (file_has_extensions(name, emulator_extensions)) {
return " Type: Emulator file\n"; return " Type: Emulator ROM file\n";
} }
return " Type: Unknown file\n"; return " Type: Unknown file\n";
} }

View File

@ -4,7 +4,7 @@
#include "../sound.h" #include "../sound.h"
#include "views.h" #include "views.h"
static bool show_extra_info_message = false;
static bool load_pending; static bool load_pending;
static component_boxart_t *boxart; static component_boxart_t *boxart;
@ -66,16 +66,16 @@ static const char *format_rom_destination_market (rom_destination_type_t market_
} }
} }
static const char *format_rom_save_type (rom_save_type_t save_type) { static const char *format_rom_save_type (rom_save_type_t save_type, bool supports_cpak) {
switch (save_type) { switch (save_type) {
case SAVE_TYPE_NONE: return "None"; case SAVE_TYPE_NONE: return supports_cpak ? "Controller PAK" : "None";
case SAVE_TYPE_EEPROM_4K: return "EEPROM 4K"; case SAVE_TYPE_EEPROM_4KBIT: return supports_cpak ? "EEPROM 4kbit | Controller PAK" : "EEPROM 4kbit";
case SAVE_TYPE_EEPROM_16K: return "EEPROM 16K"; case SAVE_TYPE_EEPROM_16KBIT: return supports_cpak ? "EEPROM 16kbit | Controller PAK" : "EEPROM 16kbit";
case SAVE_TYPE_SRAM: return "SRAM"; case SAVE_TYPE_SRAM_256KBIT: return supports_cpak ? "SRAM 256kbit | Controller PAK" : "SRAM 256kbit";
case SAVE_TYPE_SRAM_BANKED: return "SRAM Banked"; case SAVE_TYPE_SRAM_BANKED: return supports_cpak ? "SRAM 768kbit / 3 banks | Controller PAK" : "SRAM 768kbit / 3 banks";
case SAVE_TYPE_SRAM_128K: return "SRAM 128K"; case SAVE_TYPE_SRAM_1MBIT: return supports_cpak ? "SRAM 1Mbit | Controller PAK" : "SRAM 1Mbit";
case SAVE_TYPE_FLASHRAM: return "FlashRAM"; case SAVE_TYPE_FLASHRAM_1MBIT: return supports_cpak ? "FlashRAM 1Mbit | Controller PAK" : "FlashRAM 1Mbit";
case SAVE_TYPE_FLASHRAM_PKST2: return "FlashRAM (Pokemon Stadium 2)"; case SAVE_TYPE_FLASHRAM_PKST2: return supports_cpak ? "FlashRAM (Pokemon Stadium 2) | Controller PAK" : "FlashRAM (Pokemon Stadium 2)";
default: return "Unknown"; default: return "Unknown";
} }
} }
@ -166,12 +166,12 @@ static component_context_menu_t set_cic_type_context_menu = { .list = {
static component_context_menu_t set_save_type_context_menu = { .list = { static component_context_menu_t set_save_type_context_menu = { .list = {
{ .text = "Automatic", .action = set_save_type, .arg = (void *) (SAVE_TYPE_AUTOMATIC) }, { .text = "Automatic", .action = set_save_type, .arg = (void *) (SAVE_TYPE_AUTOMATIC) },
{ .text = "None", .action = set_save_type, .arg = (void *) (SAVE_TYPE_NONE) }, { .text = "None", .action = set_save_type, .arg = (void *) (SAVE_TYPE_NONE) },
{ .text = "EEPROM 4kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_4K) }, { .text = "EEPROM 4kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_4KBIT) },
{ .text = "EEPROM 16kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_16K) }, { .text = "EEPROM 16kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_16KBIT) },
{ .text = "SRAM 256kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM) }, { .text = "SRAM 256kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_256KBIT) },
{ .text = "SRAM 768kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_BANKED) }, { .text = "SRAM 768kbit / 3 banks", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_BANKED) },
{ .text = "SRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_128K) }, { .text = "SRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_1MBIT) },
{ .text = "FlashRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_FLASHRAM) }, { .text = "FlashRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_FLASHRAM_1MBIT) },
COMPONENT_CONTEXT_MENU_LIST_END, COMPONENT_CONTEXT_MENU_LIST_END,
}}; }};
@ -203,6 +203,13 @@ static void process (menu_t *menu) {
} else if (menu->actions.options) { } else if (menu->actions.options) {
component_context_menu_show(&options_context_menu); component_context_menu_show(&options_context_menu);
sound_play_effect(SFX_SETTING); sound_play_effect(SFX_SETTING);
} else if (menu->actions.lz_context) {
if (show_extra_info_message) {
show_extra_info_message = false;
} else {
show_extra_info_message = true;
}
sound_play_effect(SFX_SETTING);
} }
} }
@ -230,20 +237,48 @@ static void draw (menu_t *menu, surface_t *d) {
"\n" "\n"
"\n" "\n"
"\n" "\n"
" Endianness: %s\n" "Description:\n None.\n\n\n\n\n\n\n\n"
" Title: %.20s\n" "Expansion PAK: %s\n"
" Game code: %c%c%c%c\n" "TV type: %s\n"
" Media type: %s\n" "CIC: %s\n"
" Destination market: %s\n" "GS/AR Cheats: Off\n"
" Version: %hhu\n" "Patches: Off\n"
" Check code: 0x%016llX\n" "Save type: %s\n",
" Save type: %s\n" format_rom_expansion_pak_info(menu->load.rom_info.features.expansion_pak),
" TV type: %s\n" format_rom_tv_type(rom_info_get_tv_type(&menu->load.rom_info)),
" Expansion PAK: %s\n" format_cic_type(rom_info_get_cic_type(&menu->load.rom_info)),
" CIC: %s\n" format_rom_save_type(rom_info_get_save_type(&menu->load.rom_info), menu->load.rom_info.features.controller_pak)
" Boot address: 0x%08lX\n" );
" SDK version: %.1f%c\n"
" Clock Rate: %.2fMHz\n", component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP,
"A: Load and run ROM\n"
"B: Back"
);
component_actions_bar_text_draw(
ALIGN_RIGHT, VALIGN_TOP,
"L|Z: Extra Info\n"
"R: Options"
);
component_boxart_draw(boxart);
if (show_extra_info_message) {
component_messagebox_draw(
"EXTRA ROM INFO\n"
"\n"
"Endianness: %s\n"
"Title: %.20s\n"
"Game code: %c%c%c%c\n"
"Media type: %s\n"
"Variant: %s\n"
"Version: %hhu\n"
"Check code: 0x%016llX\n"
"Boot address: 0x%08lX\n"
"SDK version: %.1f%c\n"
"Clock Rate: %.2fMHz\n\n\n"
"Press L|Z to return.\n",
format_rom_endianness(menu->load.rom_info.endianness), format_rom_endianness(menu->load.rom_info.endianness),
menu->load.rom_info.title, menu->load.rom_info.title,
menu->load.rom_info.game_code[0], menu->load.rom_info.game_code[1], menu->load.rom_info.game_code[2], menu->load.rom_info.game_code[3], menu->load.rom_info.game_code[0], menu->load.rom_info.game_code[1], menu->load.rom_info.game_code[2], menu->load.rom_info.game_code[3],
@ -251,28 +286,11 @@ static void draw (menu_t *menu, surface_t *d) {
format_rom_destination_market(menu->load.rom_info.destination_code), format_rom_destination_market(menu->load.rom_info.destination_code),
menu->load.rom_info.version, menu->load.rom_info.version,
menu->load.rom_info.check_code, menu->load.rom_info.check_code,
format_rom_save_type(rom_info_get_save_type(&menu->load.rom_info)),
format_rom_tv_type(rom_info_get_tv_type(&menu->load.rom_info)),
format_rom_expansion_pak_info(menu->load.rom_info.features.expansion_pak),
format_cic_type(rom_info_get_cic_type(&menu->load.rom_info)),
menu->load.rom_info.boot_address, menu->load.rom_info.boot_address,
(menu->load.rom_info.libultra.version / 10.0f), menu->load.rom_info.libultra.revision, (menu->load.rom_info.libultra.version / 10.0f), menu->load.rom_info.libultra.revision,
menu->load.rom_info.clock_rate menu->load.rom_info.clock_rate
); );
}
component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP,
"A: Load and run ROM\n"
"B: Exit"
);
component_actions_bar_text_draw(
ALIGN_RIGHT, VALIGN_TOP,
"\n"
"R: Options"
);
component_boxart_draw(boxart);
component_context_menu_draw(&options_context_menu); component_context_menu_draw(&options_context_menu);
} }

View File

@ -36,7 +36,7 @@ static void draw (menu_t *menu, surface_t *d) {
"\n" "\n"
"\n" "\n"
"To set the date and time, please use the PC terminal\n" "To set the date and time, please use the PC terminal\n"
"application and set via USB.\n\n" "application and set via USB or a game that uses it.\n\n"
"Current date & time: %s\n", "Current date & time: %s\n",
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n" menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n"
); );

View File

@ -1,4 +1,6 @@
#include <stdbool.h>
#include "../sound.h" #include "../sound.h"
#include "../settings.h"
#include "views.h" #include "views.h"
@ -9,9 +11,109 @@ static const char *format_switch (bool state) {
} }
} }
static void set_pal60_type (menu_t *menu, void *arg) {
menu->settings.pal60_enabled = (bool) (arg);
settings_save(&menu->settings);
}
static void set_protected_entries_type (menu_t *menu, void *arg) {
menu->settings.show_protected_entries = (bool) (arg);
settings_save(&menu->settings);
menu->browser.reload = true;
}
static void set_use_saves_folder_type (menu_t *menu, void *arg) {
menu->settings.use_saves_folder = (bool) (arg);
settings_save(&menu->settings);
}
static void set_sound_enabled_type (menu_t *menu, void *arg) {
menu->settings.sound_enabled = (bool) (arg);
sound_use_sfx(menu->settings.sound_enabled);
settings_save(&menu->settings);
}
#ifdef BETA_SETTINGS
static void set_bgm_enabled_type (menu_t *menu, void *arg) {
menu->settings.bgm_enabled = (bool) (arg);
settings_save(&menu->settings);
}
static void set_rumble_enabled_type (menu_t *menu, void *arg) {
menu->settings.rumble_enabled = (bool) (arg);
settings_save(&menu->settings);
}
// static void set_use_default_settings (menu_t *menu, void *arg) {
// // FIXME: add implementation
// menu->browser.reload = true;
// }
#endif
static component_context_menu_t set_pal60_type_context_menu = { .list = {
{.text = "On", .action = set_pal60_type, .arg = (void *) (true) },
{.text = "Off", .action = set_pal60_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
static component_context_menu_t set_protected_entries_type_context_menu = { .list = {
{.text = "On", .action = set_protected_entries_type, .arg = (void *) (true) },
{.text = "Off", .action = set_protected_entries_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
static component_context_menu_t set_sound_enabled_type_context_menu = { .list = {
{.text = "On", .action = set_sound_enabled_type, .arg = (void *) (true) },
{.text = "Off", .action = set_sound_enabled_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
static component_context_menu_t set_use_saves_folder_type_context_menu = { .list = {
{.text = "On", .action = set_use_saves_folder_type, .arg = (void *) (true) },
{.text = "Off", .action = set_use_saves_folder_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
#ifdef BETA_SETTINGS
static component_context_menu_t set_bgm_enabled_type_context_menu = { .list = {
{.text = "On", .action = set_bgm_enabled_type, .arg = (void *) (true) },
{.text = "Off", .action = set_bgm_enabled_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
static component_context_menu_t set_rumble_enabled_type_context_menu = { .list = {
{.text = "On", .action = set_rumble_enabled_type, .arg = (void *) (true) },
{.text = "Off", .action = set_rumble_enabled_type, .arg = (void *) (false) },
COMPONENT_CONTEXT_MENU_LIST_END,
}};
#endif
static component_context_menu_t options_context_menu = { .list = {
{ .text = "PAL60 Mode", .submenu = &set_pal60_type_context_menu },
{ .text = "Show Hidden Files", .submenu = &set_protected_entries_type_context_menu },
{ .text = "Sound Effects", .submenu = &set_sound_enabled_type_context_menu },
{ .text = "Use Saves Folder", .submenu = &set_use_saves_folder_type_context_menu },
#ifdef BETA_SETTINGS
{ .text = "Background Music", .submenu = &set_bgm_enabled_type_context_menu },
{ .text = "Rumble Feedback", .submenu = &set_rumble_enabled_type_context_menu },
// { .text = "Restore Defaults", .action = set_use_default_settings },
#endif
COMPONENT_CONTEXT_MENU_LIST_END,
}};
static void process (menu_t *menu) { static void process (menu_t *menu) {
if (menu->actions.back) { if (component_context_menu_process(menu, &options_context_menu)) {
return;
}
if (menu->actions.enter) {
component_context_menu_show(&options_context_menu);
sound_play_effect(SFX_SETTING);
} else if (menu->actions.back) {
menu->next_mode = MENU_MODE_BROWSER; menu->next_mode = MENU_MODE_BROWSER;
sound_play_effect(SFX_EXIT); sound_play_effect(SFX_EXIT);
} }
@ -26,44 +128,54 @@ static void draw (menu_t *menu, surface_t *d) {
component_main_text_draw( component_main_text_draw(
ALIGN_CENTER, VALIGN_TOP, ALIGN_CENTER, VALIGN_TOP,
"SETTINGS EDITOR\n" "MENU SETTINGS EDITOR\n"
"\n" "\n"
); );
component_main_text_draw( component_main_text_draw(
ALIGN_LEFT, VALIGN_TOP, ALIGN_LEFT, VALIGN_TOP,
"\n" "\n\n"
"\n" " Default Directory : %s\n\n"
"To change the settings, please adjust them\n" "To change the following menu settings, press 'A':\n"
"directly in the 'menu/config.ini' file.\n\n" "* PAL60 Mode : %s\n"
"pal60_enabled: %s\n" " Show Hidden Files : %s\n"
"show_protected_entries: %s\n" " Use Saves folder : %s\n"
"default_directory: %s\n" " Sound Effects : %s\n"
"use_saves_folder: %s\n" #ifdef BETA_SETTINGS
"bgm_enabled: %s\n" " Background Music : %s\n"
"sound_enabled: %s\n" " Rumble Feedback : %s\n"
"rumble_enabled: %s\n", #endif
"Note: Certain settings have the following caveats:\n\n"
"* Requires a flashcart reboot.\n",
menu->settings.default_directory,
format_switch(menu->settings.pal60_enabled), format_switch(menu->settings.pal60_enabled),
format_switch(menu->settings.show_protected_entries), format_switch(menu->settings.show_protected_entries),
menu->settings.default_directory,
format_switch(menu->settings.use_saves_folder), format_switch(menu->settings.use_saves_folder),
format_switch(menu->settings.sound_enabled)
#ifdef BETA_SETTINGS
,
format_switch(menu->settings.bgm_enabled), format_switch(menu->settings.bgm_enabled),
format_switch(menu->settings.sound_enabled),
format_switch(menu->settings.rumble_enabled) format_switch(menu->settings.rumble_enabled)
#endif
); );
component_actions_bar_text_draw( component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP, ALIGN_LEFT, VALIGN_TOP,
"\n" "A: Change\n"
"B: Back" "B: Back"
); );
component_context_menu_draw(&options_context_menu);
rdpq_detach_show(); rdpq_detach_show();
} }
void view_settings_init (menu_t *menu) { void view_settings_init (menu_t *menu) {
// Nothing to initialize (yet)
component_context_menu_init(&options_context_menu);
} }
void view_settings_display (menu_t *menu, surface_t *display) { void view_settings_display (menu_t *menu, surface_t *display) {