mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-23 11:09:19 +01:00
Merge branch 'develop' into add-rom-patcher
This commit is contained in:
commit
f505135c97
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -21,6 +21,7 @@
|
||||
- [ ] Improvement (non-breaking change that adds a new feature)
|
||||
- [ ] Bug fix (fixes an issue)
|
||||
- [ ] Breaking change (breaking change)
|
||||
- [ ] Documentation Improvement
|
||||
- [ ] Config and build (change in the configuration and build system, has no impact on code or features)
|
||||
|
||||
## Checklist:
|
||||
|
31
.github/workflows/build.yml
vendored
31
.github/workflows/build.yml
vendored
@ -11,6 +11,9 @@ on:
|
||||
jobs:
|
||||
build-menu:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -68,21 +71,31 @@ jobs:
|
||||
name: SC64
|
||||
path: ./output/sc64menu.n64
|
||||
|
||||
# - name: Delete rolling-release tag and release
|
||||
# uses: dev-drprasad/delete-tag-and-release@v1.0
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
# with:
|
||||
# github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# tag_name: rolling-release
|
||||
# continue-on-error: true
|
||||
|
||||
- name: Upload rolling release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.ref == 'refs/heads/main'
|
||||
with:
|
||||
name: Rolling release
|
||||
body: Rolling release built from latest commit on `main` branch.
|
||||
tag_name: rolling-release
|
||||
tag_name: 'rolling_release'
|
||||
make_latest: true
|
||||
files: |
|
||||
./output/N64FlashcartMenu.n64
|
||||
./output/menu.bin
|
||||
# ./output/OS64.v64
|
||||
# ./output/OS64P.v64
|
||||
./output/sc64menu.n64
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload dev rolling release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.ref == 'refs/heads/develop'
|
||||
with:
|
||||
name: 'Rolling pre-release'
|
||||
body: Experimental pre-release built from latest commit on `develop` branch.
|
||||
target_commitish: develop
|
||||
tag_name: 'rolling_pre-release'
|
||||
prerelease: true
|
||||
files: |
|
||||
./output/N64FlashcartMenu.n64
|
||||
./output/menu.bin
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@
|
||||
|
||||
# Ignore generated files in the libdragon FS
|
||||
/filesystem/FiraMonoBold.font64
|
||||
/filesystem/*.wav64
|
||||
|
||||
# Ignore external development tools
|
||||
/tools/*
|
||||
|
2
Doxyfile
2
Doxyfile
@ -905,7 +905,7 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = README.md ./src
|
||||
INPUT = README.md ./src ./docs
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
18
Makefile
18
Makefile
@ -79,17 +79,27 @@ SRCS = \
|
||||
FONTS = \
|
||||
FiraMonoBold.ttf
|
||||
|
||||
SOUNDS = \
|
||||
cursorsound.wav \
|
||||
back.wav \
|
||||
enter.wav \
|
||||
error.wav \
|
||||
settings.wav
|
||||
|
||||
OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o,$(basename $(SRCS))))
|
||||
MINIZ_OBJS = $(filter $(BUILD_DIR)/libs/miniz/%.o,$(OBJS))
|
||||
SPNG_OBJS = $(filter $(BUILD_DIR)/libs/libspng/%.o,$(OBJS))
|
||||
DEPS = $(OBJS:.o=.d)
|
||||
|
||||
FILESYSTEM = \
|
||||
$(addprefix $(FILESYSTEM_DIR)/, $(notdir $(FONTS:%.ttf=%.font64)))
|
||||
$(addprefix $(FILESYSTEM_DIR)/, $(notdir $(FONTS:%.ttf=%.font64))) \
|
||||
$(addprefix $(FILESYSTEM_DIR)/, $(notdir $(SOUNDS:%.wav=%.wav64)))
|
||||
|
||||
$(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
|
||||
$(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
|
||||
|
||||
|
||||
$(@info $(shell mkdir -p ./$(FILESYSTEM_DIR) &> /dev/null))
|
||||
|
||||
@ -97,6 +107,10 @@ $(FILESYSTEM_DIR)/%.font64: $(ASSETS_DIR)/%.ttf
|
||||
@echo " [FONT] $@"
|
||||
@$(N64_MKFONT) $(MKFONT_FLAGS) -o $(FILESYSTEM_DIR) "$<"
|
||||
|
||||
$(FILESYSTEM_DIR)/%.wav64: $(ASSETS_DIR)/%.wav
|
||||
@echo " [AUDIO] $@"
|
||||
@$(N64_AUDIOCONV) $(AUDIOCONV_FLAGS) -o $(FILESYSTEM_DIR) "$<"
|
||||
|
||||
$(BUILD_DIR)/$(PROJECT_NAME).dfs: $(FILESYSTEM)
|
||||
|
||||
$(BUILD_DIR)/menu/views/credits.o: .FORCE
|
||||
|
135
README.md
135
README.md
@ -25,9 +25,15 @@ An open source menu for N64 flashcarts.
|
||||
* Comprehensive ROM information display.
|
||||
* Real Time Clock support.
|
||||
* Music playback (MP3).
|
||||
* Menu sound effects.
|
||||
|
||||
|
||||
### Video showcase (as of Oct 12 2023)
|
||||
## Documentation
|
||||
* [Getting started guide](./docs/00_getting_started_sd.md)
|
||||
* [Menu controls](./docs/01_menu_controls.md)
|
||||
* [Developer guide](./docs/99_developer_guide.md)
|
||||
|
||||
## Video showcase (as of Oct 12 2023)
|
||||
|
||||
[![N64FlashcartMenu Showcase](http://img.youtube.com/vi/6CKImHTifDA/0.jpg)](http://www.youtube.com/watch?v=6CKImHTifDA "N64FlashcartMenu Showcase (Oct 12 2023)")
|
||||
|
||||
@ -40,123 +46,60 @@ An open source menu for N64 flashcarts.
|
||||
* Support as many common mods and features as possible.
|
||||
|
||||
|
||||
## Getting started
|
||||
Using your PC, insert the SD card and ensure it is formatted for compatibility (We recommend FAT32 in most instances).
|
||||
|
||||
### Save files
|
||||
By default, all save files (whether `FlashRam`, `SRAM` or `EEPROM`) use the `.sav` extension and match the filename of the ROM.
|
||||
|
||||
Each save file can be found in the `/saves` folder located in the same directory as the ROM and shares the same file name, apart from the extension.
|
||||
|
||||
If transfering a file from a different flashcart such as the ED64, it will be necessary to change the extension of the file to `sav`.
|
||||
|
||||
i.e. for `Glover (USA).eep` you would need to change the extension to `Glover (USA).sav`
|
||||
|
||||
**NOTE:** certain emulator saves or saves created for a different ROM version or region may be incompatible.
|
||||
|
||||
## Experimental features
|
||||
These features are subject to change:
|
||||
|
||||
### ROM Boxart
|
||||
To use boxart, you need to place png files of size 158x112 in the folder `/menu/boxart` on the SD card.
|
||||
To use boxart, place PNG files in the `/menu/boxart` folder on the SD card with the following dimensions:
|
||||
* Standard covers: 158x112
|
||||
* 64DD covers: 129x112
|
||||
* Japanese covers: 112x158
|
||||
|
||||
Each file must be named according to the 2 letter ROM ID, or 3 letter ROM ID including media type.
|
||||
i.e. for GoldenEye 2 letters, this would be `GE.png`.
|
||||
i.e. for GoldenEye 3 letters, this would be `NGE.png`.
|
||||
A known set of PNG files using 2 letter ID's can be downloaded [here](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w).
|
||||
You can download these boxart packs:
|
||||
|
||||
[American Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w)
|
||||
|
||||
### Emulator support
|
||||
Emulators should be added to the `/menu/emulators` directory on the SD card.
|
||||
[European Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M)
|
||||
|
||||
[64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM)
|
||||
|
||||
Menu currently supports the following emulators and associated ROM file names:
|
||||
- **NES**: [neon64v2](https://github.com/hcs64/neon64v2) by *hcs64* - `neon64bu.rom`
|
||||
- **SNES**: [sodium64](https://github.com/Hydr8gon/sodium64) by *Hydr8gon* - `sodium64.z64`
|
||||
- **Game Boy** / **GB Color**: [gb64](https://lambertjamesd.github.io/gb64/romwrapper/romwrapper.html) by *lambertjamesd* - `gb.v64` / `gbc.v64`
|
||||
- **Sega Master System** / **Sega Game Gear** / **Sg1000**: [TotalSMS](https://github.com/ITotalJustice/TotalSMS) - `TotalSMS.z64` (Currently broken)
|
||||
|
||||
### Menu Settings
|
||||
The Menu creates a `config.ini` file in `sd:/menu/` which contains various settings that are used by the menu.
|
||||
Currently these are read-only (can be viewed in the menu by pressing `L` on the Joypad).
|
||||
If required, you can manually adjust the file on the SD card using your computer.
|
||||
|
||||
### SC64 Specific
|
||||
- Ensure the cart has the latest [firmware](https://github.com/Polprzewodnikowy/SummerCart64/releases/latest) installed.
|
||||
- Download the latest `sc64menu.n64` file from the releases page, then put it in the root directory of your SD card.
|
||||
|
||||
##### 64DD disk support
|
||||
For the ability to load and run 64DD disk images, you need to place required 64DD IPL dumps in the `/menu/64ddipl` folder on the SD card.
|
||||
For more details follow [this guide on the 64dd.org website](https://64dd.org/tutorial_sc64.html).
|
||||
## Flashcart specific
|
||||
|
||||
Note: to load an expansion disk (e.g. F-Zero X) browse to the N64 ROM and load it (but not start it) and then browse to the DD expansion file and press the `R` button.
|
||||
### SC64
|
||||
* Ensure the cart has the latest [firmware](https://github.com/Polprzewodnikowy/SummerCart64/releases/latest) installed.
|
||||
* Download the latest `sc64menu.n64` file from the [releases](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases/) page, then put it in the root directory of your SD card.
|
||||
|
||||
|
||||
### 64drive Specific
|
||||
- Ensure the cart has the latest [firmware](https://64drive.retroactive.be/support.php) installed.
|
||||
- Download the latest `menu.bin` file from the releases page, then put it in the root directory of your SD card.
|
||||
### 64drive
|
||||
* Ensure the cart has the latest [firmware](https://64drive.retroactive.be/support.php) installed.
|
||||
* Download the latest `menu.bin` file from the [releases](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases/) page, then put it in the root directory of your SD card.
|
||||
|
||||
|
||||
### ED64 & ED64P Specific
|
||||
### ED64 & ED64P
|
||||
Currently not supported, but work is in progress (See [PR's](https://github.com/Polprzewodnikowy/N64FlashcartMenu/pulls)).
|
||||
|
||||
The aim is to replace [Altra64](https://github.com/networkfusion/altra64) and [ED64-UnofficialOS](https://github.com/n64-tools/ED64-UnofficialOS-binaries).
|
||||
|
||||
|
||||
# Developer documentation
|
||||
|
||||
You can use a dev container in VSCode to ease development.
|
||||
|
||||
|
||||
## To deploy:
|
||||
### SC64
|
||||
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.18.0/sc64-deployer-windows-v2.18.0.zip)
|
||||
* Extract and place `sc64deployer.exe` in the `tools/sc64` directory.
|
||||
|
||||
Make sure that your firmware is compatible (currently v2.18.0+)
|
||||
See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.18.0/docs/00_quick_startup_guide.md#firmware-backupupdate)
|
||||
|
||||
#### From the devcontainer
|
||||
It is not currently possible to directly communicate with USB devices.
|
||||
BUT, as a work around you can use a proxy TCP/IP connection
|
||||
Set up a proxy: open a terminal window, `cd ./tools/sc64` and then `./sc64deployer.exe server`
|
||||
|
||||
Then in the dev container, use `make run` or `make run-debug`
|
||||
|
||||
|
||||
#### From your host (Windows) OS
|
||||
|
||||
* Run `./localdeploy.bat` from the terminal
|
||||
|
||||
Toggle the N64 power switch to load the ROM.
|
||||
|
||||
`ms-vscode.makefile-tools` will help (installed automatically in dev container).
|
||||
TODO: it does not yet work with `F5`: see https://devblogs.microsoft.com/cppblog/now-announcing-makefile-support-in-visual-studio-code/
|
||||
WORKAROUND: in the dev container terminal, use make directly, i.e.: `make`
|
||||
The ROM can be found in the `output` directory.
|
||||
|
||||
NOTE: a "release" version of the SC64 menu is called `sc64menu.n64` and can be created for when you want to add it directly to the SDCard. This is generated by running `make all` or running `make sc64`.
|
||||
|
||||
### Ares Emulator
|
||||
For ease of development and debugging, the menu ROM is able to run in the Ares emulator (without most flashcart features).
|
||||
|
||||
* Ensure you have the Ares emulator on you computer.
|
||||
* Load the `N64FlashcartMenu.n64` ROM.
|
||||
|
||||
### Others
|
||||
* Add the required file to the correct folder on your SD card.
|
||||
|
||||
|
||||
# Update Libdragon submodule
|
||||
This repo currently uses the `preview` branch as a submodule at a specific commit.
|
||||
To update to the latest version, use `git submodule update --remote ` from the terminal.
|
||||
|
||||
# Generate documentation
|
||||
Run `doxygen` from the dev container terminal.
|
||||
Make sure you fix the warnings before creating a PR!
|
||||
Generated documentation is located in `output/docs` folder and auto published to the `gh-pages` branch when merged with `main`.
|
||||
|
||||
Once merged, they can be viewed [here](https://polprzewodnikowy.github.io/N64FlashcartMenu/)
|
||||
|
||||
# Open source software and licenses used
|
||||
- [libdragon](https://github.com/DragonMinded/libdragon) (UNLICENSE License)
|
||||
- [libspng](https://github.com/randy408/libspng) (BSD 2-Clause License)
|
||||
- [mini.c](https://github.com/univrsal/mini.c) (BSD 2-Clause License)
|
||||
- [minimp3](https://github.com/lieff/minimp3) (CC0 1.0 Universal)
|
||||
- [miniz](https://github.com/richgel999/miniz) (MIT License)
|
||||
|
||||
* [libdragon](https://github.com/DragonMinded/libdragon) (UNLICENSE License)
|
||||
* [libspng](https://github.com/randy408/libspng) (BSD 2-Clause License)
|
||||
* [mini.c](https://github.com/univrsal/mini.c) (BSD 2-Clause License)
|
||||
* [minimp3](https://github.com/lieff/minimp3) (CC0 1.0 Universal)
|
||||
* [miniz](https://github.com/richgel999/miniz) (MIT License)
|
||||
|
||||
## Sounds
|
||||
See [License](https://pixabay.com/en/service/license-summary/) for the following sounds:
|
||||
* [Cursor sound](https://pixabay.com/en/sound-effects/click-buttons-ui-menu-sounds-effects-button-7-203601/) by Skyscraper_seven (Free to use)
|
||||
* [Actions (Enter, back) sound](https://pixabay.com/en/sound-effects/menu-button-user-interface-pack-190041/) by Liecio (Free to use)
|
||||
* [Error sound](https://pixabay.com/en/sound-effects/error-call-to-attention-129258/) by Universfield (Free to use)
|
||||
|
BIN
assets/back.wav
Normal file
BIN
assets/back.wav
Normal file
Binary file not shown.
BIN
assets/cursorsound.wav
Normal file
BIN
assets/cursorsound.wav
Normal file
Binary file not shown.
BIN
assets/enter.wav
Normal file
BIN
assets/enter.wav
Normal file
Binary file not shown.
BIN
assets/error.wav
Normal file
BIN
assets/error.wav
Normal file
Binary file not shown.
BIN
assets/settings.wav
Normal file
BIN
assets/settings.wav
Normal file
Binary file not shown.
82
docs/00_getting_started_sd.md
Normal file
82
docs/00_getting_started_sd.md
Normal file
@ -0,0 +1,82 @@
|
||||
## First time setup of SD card
|
||||
|
||||
Using your PC, insert the SD card and ensure it is formatted for compatibility with your flashcart (*FAT32 and EXFAT are fully supported on the SC64*).
|
||||
|
||||
- Download the latest `sc64menu.n64` (assuming you are using an *sc64*) file from the [releases](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases/) page, then put it in the root directory of your SD card.
|
||||
- Create a folder in the root of your SD card called `menu`.
|
||||
- Place your ROMs on the SD Card, in any folder (**except for `menu`**).
|
||||
|
||||
|
||||
### Emulator support
|
||||
Emulators should be added to the `/menu/emulators` directory on the SD card.
|
||||
|
||||
Menu currently supports the following emulators and associated ROM file names:
|
||||
- **NES**: [neon64v2](https://github.com/hcs64/neon64v2/releases) by *hcs64* - `neon64bu.rom`
|
||||
- **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` ("Download Emulator" button)
|
||||
|
||||
|
||||
### 64DD disk support
|
||||
For the ability to load and run 64DD disk images, you need to place the required 64DD IPL dumps in the `/menu/64ddipl` folder on the SD card.
|
||||
For more details, follow [this guide on the 64dd.org website](https://64dd.org/tutorial_sc64.html).
|
||||
|
||||
|
||||
#### So what would the layout of the SD Card look like?
|
||||
```plaintext
|
||||
SD:\
|
||||
│
|
||||
├── sc64menu.n64
|
||||
│
|
||||
│
|
||||
├── menu\
|
||||
│ │
|
||||
│ │
|
||||
│ ├── 64ddipl\
|
||||
│ │ ├── NDDE0.n64
|
||||
│ │ ├── NDDJ2.n64
|
||||
│ │ └── NDXJ0.n64
|
||||
│ │
|
||||
│ └── emulators
|
||||
│ ├── neon64bu.rom
|
||||
│ ├── sodium64.z64
|
||||
│ ├── gb.v64
|
||||
│ └── gbc.v64
|
||||
│
|
||||
├── (a rom).z64
|
||||
├── (a rom).n64
|
||||
├── (some folder with roms)\
|
||||
│ └── (some folder with roms)\
|
||||
| └── (Some supported ROM files)
|
||||
│
|
||||
├── (Some supported ROM files)
|
||||
|
|
||||
└── (Some folder with 64DD disk images)\
|
||||
└── (Some 64DD disk images)
|
||||
```
|
||||
|
||||
|
||||
## Save Files
|
||||
All save files (whether `FlashRam`, `SRAM` or `EEPROM`) use the `.sav` extension and match the filename of a ROM.
|
||||
|
||||
Each save file can be found in the `/saves` folder located in the **same directory** as the ROM and shares the same file name, apart from the extension.
|
||||
These files are created and modified when a "game" saves.
|
||||
|
||||
```plaintext
|
||||
├── (some folder with roms)\
|
||||
├── a_rom.z64
|
||||
├── b_rom.n64
|
||||
└── saves\
|
||||
├── a_rom.sav
|
||||
└── b_rom.sav
|
||||
```
|
||||
|
||||
### Transfering saves from an ED64
|
||||
If transferring a file from a different flashcart, such as the ED64, it will be necessary to change the extension of the file to `sav`.
|
||||
|
||||
i.e. for `Glover (USA).eep` you would need to change the extension to `Glover (USA).sav`
|
||||
|
||||
You may also need to pad/trim the files to their original size:
|
||||
- For EEPROM 4Kbit games, remove the padding.
|
||||
- For others, use a tool such as Ninjiteu's N64 Save converter.
|
||||
|
||||
**NOTE:** certain emulator saves or saves created for a different ROM version or region may be incompatible.
|
14
docs/01_menu_controls.md
Normal file
14
docs/01_menu_controls.md
Normal file
@ -0,0 +1,14 @@
|
||||
## Menu Controls
|
||||
|
||||
### Fast scroll
|
||||
Use the C-Up and C-Down buttons
|
||||
|
||||
|
||||
### DD ROMs
|
||||
|
||||
#### Expansion Disks
|
||||
To load an expansion disk (e.g. F-Zero X) browse to the N64 ROM and load it (but not start it) and then browse to the DD expansion file and press the `R` button.
|
||||
|
||||
#### Disk swapping
|
||||
This feature is not currently available in the menu.
|
||||
|
69
docs/99_developer_guide.md
Normal file
69
docs/99_developer_guide.md
Normal file
@ -0,0 +1,69 @@
|
||||
## Developer documentation
|
||||
|
||||
You can use a dev container in VSCode to ease development.
|
||||
|
||||
### A quickstart video tutorial on how to set up your environment
|
||||
[![Devcontainer quickstart guide](http://img.youtube.com/vi/h05ufOsRgZU/0.jpg)](http://www.youtube.com/watch?v=h05ufOsRgZU "Devcontainer quickstart guide").
|
||||
|
||||
|
||||
### To deploy:
|
||||
#### SC64
|
||||
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.18.0/sc64-deployer-windows-v2.18.0.zip)
|
||||
* Extract and place `sc64deployer.exe` in the `tools/sc64` directory.
|
||||
|
||||
Make sure that your firmware is compatible (currently v2.18.0+)
|
||||
See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.18.0/docs/00_quick_startup_guide.md#firmware-backupupdate)
|
||||
|
||||
##### From the devcontainer
|
||||
It is not currently possible to directly communicate with USB devices.
|
||||
BUT, as a workaround you can use a proxy TCP/IP connection
|
||||
Set up a proxy: open a terminal window, `cd ./tools/sc64` and then `./sc64deployer.exe server`
|
||||
|
||||
Then in the dev container, use `make run` or `make run-debug`
|
||||
|
||||
|
||||
##### From your host (Windows) OS
|
||||
|
||||
* Run `./localdeploy.bat` from the terminal
|
||||
|
||||
Toggle the N64 power switch to load the ROM.
|
||||
|
||||
`ms-vscode.makefile-tools` will help (installed automatically in dev container).
|
||||
NOTE: it does not yet work with `F5`: see [this blog post](https://devblogs.microsoft.com/cppblog/now-announcing-makefile-support-in-visual-studio-code/)
|
||||
WORKAROUND: in the dev container terminal, use make directly, i.e.: `make`
|
||||
The ROM can be found in the `output` directory.
|
||||
|
||||
NOTE: a "release" version of the SC64 menu is called `sc64menu.n64` and can be created for when you want to add it directly to the SDCard. This is generated by running `make all` or running `make sc64`.
|
||||
|
||||
#### Ares Emulator
|
||||
For ease of development and debugging, the menu ROM can run in the [Ares emulator](https://ares-emu.net/) (without most flashcart features).
|
||||
|
||||
* Ensure you have the Ares emulator on your computer.
|
||||
* Load the `N64FlashcartMenu.n64` ROM.
|
||||
|
||||
#### Others
|
||||
* Add the required file to the correct folder on your SD card.
|
||||
|
||||
|
||||
## Update Libdragon submodule
|
||||
This repo currently uses the `preview` branch as a submodule at a specific commit.
|
||||
To update to the latest version, use `git submodule update --remote` from the terminal.
|
||||
|
||||
## Generate documentation
|
||||
Run `doxygen` from the dev container terminal.
|
||||
Make sure you fix the warnings before creating a PR!
|
||||
Generated documentation is located in the `output/docs` folder and auto-published to the `gh-pages` branch when merged with `main`.
|
||||
|
||||
Once merged, they can be viewed [here](https://polprzewodnikowy.github.io/N64FlashcartMenu/)
|
||||
|
||||
### Test generated docs in the dev-container
|
||||
Install Prerequisites:
|
||||
```bash
|
||||
apt-get install ruby-full build-essential zlib1g-dev
|
||||
gem install jekyll bundler
|
||||
```
|
||||
|
||||
You can then serve the webpage:
|
||||
```bash
|
||||
cd output/docs && jekyll serve
|
||||
```
|
@ -1 +1 @@
|
||||
Subproject commit af650428e9615f4e08d8e7eae187929a90c15ccc
|
||||
Subproject commit 9bae49994bf1c796f9939ea1aa7c133813b9053f
|
@ -170,7 +170,7 @@ static flashcart_err_t d64_load_save (char *save_path) {
|
||||
|
||||
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);
|
||||
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:
|
||||
type = SAVE_TYPE_NONE;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_4K:
|
||||
type = SAVE_TYPE_EEPROM_4K;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_4KBIT:
|
||||
type = SAVE_TYPE_EEPROM_4KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_16K:
|
||||
type = SAVE_TYPE_EEPROM_16K;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_16KBIT:
|
||||
type = SAVE_TYPE_EEPROM_16KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_SRAM:
|
||||
type = SAVE_TYPE_SRAM;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_256KBIT:
|
||||
type = SAVE_TYPE_SRAM_256KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_BANKED:
|
||||
type = SAVE_TYPE_SRAM_BANKED;
|
||||
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
|
||||
type = SAVE_TYPE_SRAM;
|
||||
type = SAVE_TYPE_SRAM_256KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_FLASHRAM:
|
||||
type = SAVE_TYPE_FLASHRAM;
|
||||
case FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT:
|
||||
type = SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
return FLASHCART_ERR_ARGS;
|
||||
|
@ -79,10 +79,10 @@ typedef enum {
|
||||
/** @brief Save Type Enumeration. */
|
||||
typedef enum {
|
||||
SAVE_TYPE_NONE,
|
||||
SAVE_TYPE_EEPROM_4K,
|
||||
SAVE_TYPE_EEPROM_16K,
|
||||
SAVE_TYPE_SRAM,
|
||||
SAVE_TYPE_FLASHRAM,
|
||||
SAVE_TYPE_EEPROM_4KBIT,
|
||||
SAVE_TYPE_EEPROM_16KBIT,
|
||||
SAVE_TYPE_SRAM_256KBIT,
|
||||
SAVE_TYPE_FLASHRAM_1MBIT,
|
||||
SAVE_TYPE_SRAM_BANKED,
|
||||
SAVE_TYPE_FLASHRAM_PKST2,
|
||||
} d64_save_type_t;
|
||||
|
@ -34,12 +34,12 @@ typedef enum {
|
||||
/** @brief Flashcart save type enumeration */
|
||||
typedef enum {
|
||||
FLASHCART_SAVE_TYPE_NONE,
|
||||
FLASHCART_SAVE_TYPE_EEPROM_4K,
|
||||
FLASHCART_SAVE_TYPE_EEPROM_16K,
|
||||
FLASHCART_SAVE_TYPE_SRAM,
|
||||
FLASHCART_SAVE_TYPE_EEPROM_4KBIT,
|
||||
FLASHCART_SAVE_TYPE_EEPROM_16KBIT,
|
||||
FLASHCART_SAVE_TYPE_SRAM_256KBIT,
|
||||
FLASHCART_SAVE_TYPE_SRAM_BANKED,
|
||||
FLASHCART_SAVE_TYPE_SRAM_128K,
|
||||
FLASHCART_SAVE_TYPE_FLASHRAM,
|
||||
FLASHCART_SAVE_TYPE_SRAM_1MBIT,
|
||||
FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT,
|
||||
FLASHCART_SAVE_TYPE_FLASHRAM_PKST2,
|
||||
__FLASHCART_SAVE_TYPE_END
|
||||
} flashcart_save_type_t;
|
||||
|
@ -51,7 +51,7 @@ bool fatfs_get_file_sectors (char *path, uint32_t *address, address_type_t type,
|
||||
|
||||
uint32_t cluster = fil.clust;
|
||||
|
||||
if (cluster >= fs->n_fatent) {
|
||||
if ((cluster < 2) || (cluster >= fs->n_fatent)) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
@ -388,12 +388,12 @@ static flashcart_err_t sc64_load_save (char *save_path) {
|
||||
sc64_save_type_t type = (sc64_save_type_t) (value);
|
||||
|
||||
switch (type) {
|
||||
case SAVE_TYPE_EEPROM_4K:
|
||||
case SAVE_TYPE_EEPROM_16K:
|
||||
case SAVE_TYPE_EEPROM_4KBIT:
|
||||
case SAVE_TYPE_EEPROM_16KBIT:
|
||||
address = (void *) (EEPROM_ADDRESS);
|
||||
break;
|
||||
case SAVE_TYPE_SRAM:
|
||||
case SAVE_TYPE_FLASHRAM:
|
||||
case SAVE_TYPE_SRAM_256KBIT:
|
||||
case SAVE_TYPE_FLASHRAM_1MBIT:
|
||||
case SAVE_TYPE_SRAM_BANKED:
|
||||
address = (void *) (SRAM_FLASHRAM_ADDRESS);
|
||||
break;
|
||||
@ -515,26 +515,26 @@ static flashcart_err_t sc64_set_save_type (flashcart_save_type_t save_type) {
|
||||
case FLASHCART_SAVE_TYPE_NONE:
|
||||
type = SAVE_TYPE_NONE;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_4K:
|
||||
type = SAVE_TYPE_EEPROM_4K;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_4KBIT:
|
||||
type = SAVE_TYPE_EEPROM_4KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_16K:
|
||||
type = SAVE_TYPE_EEPROM_16K;
|
||||
case FLASHCART_SAVE_TYPE_EEPROM_16KBIT:
|
||||
type = SAVE_TYPE_EEPROM_16KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_SRAM:
|
||||
type = SAVE_TYPE_SRAM;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_256KBIT:
|
||||
type = SAVE_TYPE_SRAM_256KBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_BANKED:
|
||||
type = SAVE_TYPE_SRAM_BANKED;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_128K:
|
||||
type = SAVE_TYPE_SRAM_128K;
|
||||
case FLASHCART_SAVE_TYPE_SRAM_1MBIT:
|
||||
type = SAVE_TYPE_SRAM_1MBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_FLASHRAM:
|
||||
type = SAVE_TYPE_FLASHRAM;
|
||||
case FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT:
|
||||
type = SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
break;
|
||||
case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2:
|
||||
type = SAVE_TYPE_FLASHRAM;
|
||||
type = SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
break;
|
||||
default:
|
||||
return FLASHCART_ERR_ARGS;
|
||||
|
@ -76,12 +76,12 @@ typedef enum {
|
||||
/** @brief The SC64 Save Type Enumeration. */
|
||||
typedef enum {
|
||||
SAVE_TYPE_NONE,
|
||||
SAVE_TYPE_EEPROM_4K,
|
||||
SAVE_TYPE_EEPROM_16K,
|
||||
SAVE_TYPE_SRAM,
|
||||
SAVE_TYPE_FLASHRAM,
|
||||
SAVE_TYPE_EEPROM_4KBIT,
|
||||
SAVE_TYPE_EEPROM_16KBIT,
|
||||
SAVE_TYPE_SRAM_256KBIT,
|
||||
SAVE_TYPE_FLASHRAM_1MBIT,
|
||||
SAVE_TYPE_SRAM_BANKED,
|
||||
SAVE_TYPE_SRAM_128K,
|
||||
SAVE_TYPE_SRAM_1MBIT,
|
||||
} sc64_save_type_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -21,6 +21,7 @@ static void actions_clear (menu_t *menu) {
|
||||
menu->actions.back = false;
|
||||
menu->actions.options = false;
|
||||
menu->actions.settings = false;
|
||||
menu->actions.lz_context = false;
|
||||
}
|
||||
|
||||
static void actions_update_direction (menu_t *menu) {
|
||||
@ -91,6 +92,8 @@ static void actions_update_buttons (menu_t *menu) {
|
||||
menu->actions.options = true;
|
||||
} else if (pressed.start) {
|
||||
menu->actions.settings = true;
|
||||
} else if (pressed.l || pressed.z) {
|
||||
menu->actions.lz_context = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
switch (save_type) {
|
||||
case SAVE_TYPE_EEPROM_4K: return FLASHCART_SAVE_TYPE_EEPROM_4K;
|
||||
case SAVE_TYPE_EEPROM_16K: return FLASHCART_SAVE_TYPE_EEPROM_16K;
|
||||
case SAVE_TYPE_SRAM: return FLASHCART_SAVE_TYPE_SRAM;
|
||||
case SAVE_TYPE_EEPROM_4KBIT: return FLASHCART_SAVE_TYPE_EEPROM_4KBIT;
|
||||
case SAVE_TYPE_EEPROM_16KBIT: return FLASHCART_SAVE_TYPE_EEPROM_16KBIT;
|
||||
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_128K: return FLASHCART_SAVE_TYPE_SRAM_128K;
|
||||
case SAVE_TYPE_FLASHRAM: return FLASHCART_SAVE_TYPE_FLASHRAM;
|
||||
case SAVE_TYPE_SRAM_1MBIT: return FLASHCART_SAVE_TYPE_SRAM_1MBIT;
|
||||
case SAVE_TYPE_FLASHRAM_1MBIT: return FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
case SAVE_TYPE_FLASHRAM_PKST2: return FLASHCART_SAVE_TYPE_FLASHRAM_PKST2;
|
||||
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;
|
||||
case CART_LOAD_EMU_TYPE_SNES:
|
||||
path_push(path, "sodium64.z64");
|
||||
save_type = FLASHCART_SAVE_TYPE_SRAM;
|
||||
save_type = FLASHCART_SAVE_TYPE_SRAM_256KBIT;
|
||||
break;
|
||||
case CART_LOAD_EMU_TYPE_GAMEBOY:
|
||||
path_push(path, "gb.v64");
|
||||
save_type = FLASHCART_SAVE_TYPE_FLASHRAM;
|
||||
save_type = FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
break;
|
||||
case CART_LOAD_EMU_TYPE_GAMEBOY_COLOR:
|
||||
path_push(path, "gbc.v64");
|
||||
save_type = FLASHCART_SAVE_TYPE_FLASHRAM;
|
||||
save_type = FLASHCART_SAVE_TYPE_FLASHRAM_1MBIT;
|
||||
break;
|
||||
case CART_LOAD_EMU_TYPE_SEGA_GENERIC_8BIT:
|
||||
path_push(path, "TotalSMS.z64");
|
||||
save_type = FLASHCART_SAVE_TYPE_SRAM;
|
||||
save_type = FLASHCART_SAVE_TYPE_SRAM_256KBIT;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam
|
||||
|
||||
sprintf(file_name, "%.3s.png", game_code);
|
||||
path_push(path, file_name);
|
||||
if (png_decoder_start(path_get(path), BOXART_WIDTH, BOXART_HEIGHT, png_decoder_callback, b) == PNG_OK) {
|
||||
if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) {
|
||||
path_free(path);
|
||||
return b;
|
||||
}
|
||||
@ -40,7 +40,7 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam
|
||||
// TODO: This is bad, we should only check for 3 letter codes
|
||||
sprintf(file_name, "%.2s.png", game_code + 1);
|
||||
path_push(path, file_name);
|
||||
if (png_decoder_start(path_get(path), BOXART_WIDTH, BOXART_HEIGHT, png_decoder_callback, b) == PNG_OK) {
|
||||
if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) {
|
||||
path_free(path);
|
||||
return b;
|
||||
}
|
||||
@ -65,15 +65,20 @@ void component_boxart_free (component_boxart_t *b) {
|
||||
}
|
||||
|
||||
void component_boxart_draw (component_boxart_t *b) {
|
||||
if (b && b->image && b->image->width == BOXART_WIDTH && b->image->height == BOXART_HEIGHT) {
|
||||
int box_x = BOXART_X;
|
||||
int box_y = BOXART_Y;
|
||||
|
||||
if (b && b->image && b->image->width <= BOXART_WIDTH_MAX && b->image->height <= BOXART_HEIGHT_MAX) {
|
||||
rdpq_mode_push();
|
||||
rdpq_set_mode_copy(false);
|
||||
rdpq_tex_blit(
|
||||
b->image,
|
||||
BOXART_X,
|
||||
BOXART_Y,
|
||||
NULL
|
||||
);
|
||||
if (b->image->height == BOXART_HEIGHT_MAX) {
|
||||
box_x = BOXART_X_JP;
|
||||
box_y = BOXART_Y_JP;
|
||||
} else if (b->image->width == BOXART_WIDTH_DD && b->image->height == BOXART_HEIGHT_DD) {
|
||||
box_x = BOXART_X_DD;
|
||||
box_y = BOXART_Y_DD;
|
||||
}
|
||||
rdpq_tex_blit(b->image, box_x, box_y, NULL);
|
||||
rdpq_mode_pop();
|
||||
} else {
|
||||
component_box_draw(
|
||||
|
@ -118,7 +118,8 @@ void component_messagebox_draw (char *fmt, ...) {
|
||||
.height = VISIBLE_AREA_HEIGHT,
|
||||
.align = ALIGN_CENTER,
|
||||
.valign = VALIGN_CENTER,
|
||||
.wrap = WRAP_WORD
|
||||
.wrap = WRAP_WORD,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
}, FNT_DEFAULT, formatted, ¶graph_nbytes);
|
||||
|
||||
if (formatted != buffer) {
|
||||
@ -151,10 +152,11 @@ void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *f
|
||||
.align = align,
|
||||
.valign = valign,
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL,
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL,
|
||||
formatted,
|
||||
nbytes
|
||||
);
|
||||
@ -180,10 +182,11 @@ void component_actions_bar_text_draw (rdpq_align_t align, rdpq_valign_t valign,
|
||||
.align = align,
|
||||
.valign = valign,
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
|
||||
LAYOUT_ACTIONS_SEPARATOR_Y + BORDER_THICKNESS + TEXT_MARGIN_VERTICAL,
|
||||
LAYOUT_ACTIONS_SEPARATOR_Y + BORDER_THICKNESS + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL,
|
||||
formatted,
|
||||
nbytes
|
||||
);
|
||||
|
@ -65,16 +65,38 @@
|
||||
#define MESSAGEBOX_MARGIN (32)
|
||||
|
||||
#define TEXT_MARGIN_HORIZONTAL (10)
|
||||
#define TEXT_MARGIN_VERTICAL (7)
|
||||
#define TEXT_MARGIN_VERTICAL (6)
|
||||
#define TEXT_OFFSET_VERTICAL (1)
|
||||
#define TEXT_LINE_SPACING_ADJUST (0)
|
||||
|
||||
/** @brief The boxart picture width. */
|
||||
#define BOXART_WIDTH (158)
|
||||
/** @brief The boxart picture height. */
|
||||
#define BOXART_HEIGHT (112)
|
||||
|
||||
/** @brief The boxart picture width (64DD). */
|
||||
#define BOXART_WIDTH_DD (129)
|
||||
/** @brief The boxart picture height. */
|
||||
#define BOXART_HEIGHT_DD (112)
|
||||
|
||||
/** @brief The boxart picture maximum width. */
|
||||
#define BOXART_WIDTH_MAX (158)
|
||||
/** @brief The boxart picture maximum height. */
|
||||
#define BOXART_HEIGHT_MAX (158)
|
||||
|
||||
/** @brief The box art position on the X axis. */
|
||||
#define BOXART_X (VISIBLE_AREA_X1 - BOXART_WIDTH - 24)
|
||||
/** @brief The box art position on the Y axis. */
|
||||
#define BOXART_Y (LAYOUT_ACTIONS_SEPARATOR_Y - BOXART_HEIGHT - 24)
|
||||
/** @brief The box art position on the X axis for japanese caratules.*/
|
||||
#define BOXART_X_JP (VISIBLE_AREA_X1 - BOXART_WIDTH_MAX + 21)
|
||||
/** @brief The box art position on the Y axis for japanese caratules. */
|
||||
#define BOXART_Y_JP (LAYOUT_ACTIONS_SEPARATOR_Y - BOXART_HEIGHT_MAX - 24)
|
||||
|
||||
/** @brief The box art position on the X axis for 64DD caratules.*/
|
||||
#define BOXART_X_DD (VISIBLE_AREA_X1 - BOXART_WIDTH_DD - 23)
|
||||
/** @brief The box art position on the Y axis for 64DD caratules. */
|
||||
#define BOXART_Y_DD (LAYOUT_ACTIONS_SEPARATOR_Y - BOXART_HEIGHT_DD - 24)
|
||||
|
||||
/** @brief The scroll bar width. */
|
||||
#define LIST_SCROLLBAR_WIDTH (12)
|
||||
@ -86,7 +108,7 @@
|
||||
#define LIST_SCROLLBAR_Y (VISIBLE_AREA_Y0)
|
||||
|
||||
/** @brief The maximum amount of file list entries. */
|
||||
#define LIST_ENTRIES (20)
|
||||
#define LIST_ENTRIES (19)
|
||||
/** @brief The maximum width available for a file list entry. */
|
||||
#define FILE_LIST_MAX_WIDTH (480)
|
||||
#define FILE_LIST_HIGHLIGHT_WIDTH (VISIBLE_AREA_X1 - VISIBLE_AREA_X0 - LIST_SCROLLBAR_WIDTH)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "../components.h"
|
||||
#include "../fonts.h"
|
||||
#include "../sound.h"
|
||||
#include "constants.h"
|
||||
|
||||
|
||||
@ -41,6 +42,7 @@ bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm)
|
||||
} else {
|
||||
cm->hide_pending = true;
|
||||
}
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (menu->actions.enter) {
|
||||
if (cm->list[cm->selected].submenu) {
|
||||
cm->submenu = cm->list[cm->selected].submenu;
|
||||
@ -51,16 +53,19 @@ bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm)
|
||||
cm->list[cm->selected].action(menu, cm->list[cm->selected].arg);
|
||||
top->hide_pending = true;
|
||||
}
|
||||
sound_play_effect(SFX_ENTER);
|
||||
} else if (menu->actions.go_up) {
|
||||
cm->selected -= 1;
|
||||
if (cm->selected < 0) {
|
||||
cm->selected = 0;
|
||||
}
|
||||
sound_play_effect(SFX_CURSOR);
|
||||
} else if (menu->actions.go_down) {
|
||||
cm->selected += 1;
|
||||
if (cm->selected >= cm->count) {
|
||||
cm->selected = (cm->count - 1);
|
||||
}
|
||||
sound_play_effect(SFX_CURSOR);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -81,6 +86,7 @@ void component_context_menu_draw (component_context_menu_t *cm) {
|
||||
.height = VISIBLE_AREA_HEIGHT,
|
||||
.align = ALIGN_CENTER,
|
||||
.valign = VALIGN_CENTER,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
NULL
|
||||
|
@ -71,6 +71,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
.width = FILE_LIST_MAX_WIDTH - (TEXT_MARGIN_HORIZONTAL * 2),
|
||||
.height = LAYOUT_ACTIONS_SEPARATOR_Y - VISIBLE_AREA_Y0 - (TEXT_MARGIN_VERTICAL * 2),
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
file_list_layout
|
||||
@ -114,7 +115,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
layout = rdpq_paragraph_builder_end();
|
||||
|
||||
int highlight_height = (layout->bbox.y1 - layout->bbox.y0) / layout->nlines;
|
||||
int highlight_y = VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + ((selected - starting_position) * highlight_height);
|
||||
int highlight_y = VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL + ((selected - starting_position) * highlight_height);
|
||||
|
||||
component_box_draw(
|
||||
FILE_LIST_HIGHLIGHT_X,
|
||||
@ -127,7 +128,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
rdpq_paragraph_render(
|
||||
layout,
|
||||
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL
|
||||
);
|
||||
|
||||
rdpq_paragraph_free(layout);
|
||||
@ -138,6 +139,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
.height = LAYOUT_ACTIONS_SEPARATOR_Y - VISIBLE_AREA_Y0 - (TEXT_MARGIN_VERTICAL * 2),
|
||||
.align = ALIGN_RIGHT,
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
NULL
|
||||
@ -164,7 +166,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
rdpq_paragraph_render(
|
||||
layout,
|
||||
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL
|
||||
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL
|
||||
);
|
||||
|
||||
rdpq_paragraph_free(layout);
|
||||
|
@ -67,6 +67,10 @@ static void menu_init (boot_params_t *boot_params) {
|
||||
|
||||
sound_init_default();
|
||||
|
||||
JOYPAD_PORT_FOREACH (port) {
|
||||
joypad_set_rumble_active(port, false);
|
||||
}
|
||||
|
||||
menu = calloc(1, sizeof(menu_t));
|
||||
assert(menu != NULL);
|
||||
|
||||
@ -115,6 +119,11 @@ static void menu_init (boot_params_t *boot_params) {
|
||||
__boot_tvtype = TV_NTSC;
|
||||
}
|
||||
|
||||
sound_init_sfx();
|
||||
if (menu->settings.sound_enabled) {
|
||||
sound_use_sfx(true);
|
||||
}
|
||||
|
||||
display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, FILTERS_DISABLED);
|
||||
|
||||
register_VI_handler(frame_counter_handler);
|
||||
|
@ -88,6 +88,7 @@ typedef struct {
|
||||
bool back;
|
||||
bool options;
|
||||
bool settings;
|
||||
bool lz_context;
|
||||
} actions;
|
||||
|
||||
struct {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -146,234 +147,234 @@ typedef struct {
|
||||
static const match_t database[] = {
|
||||
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(0xEB85EBC9596682AF, SAVE_TYPE_FLASHRAM, FEAT_NONE), // Doubutsu Banchou
|
||||
MATCH_CHECK_CODE(0x9A746EBF2802EA99, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Toon panic
|
||||
MATCH_CHECK_CODE(0x21548CA921548CA9, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Mini racers
|
||||
MATCH_CHECK_CODE(0xBC9B2CC34ED04DA5, SAVE_TYPE_FLASHRAM, FEAT_NONE), // Starcraft 64 [Prototype 2000]
|
||||
MATCH_CHECK_CODE(0x5D40ED2C10D6ABCF, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Viewpoint 2064
|
||||
MATCH_CHECK_CODE(0x7280E03F497689BA, SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Viewpoint 2064 [ENG patch]
|
||||
MATCH_CHECK_CODE(0x0DD4ABABB5A2A91E, SAVE_TYPE_EEPROM_16KBIT, FEAT_EXP_PAK_REQUIRED), // DK Retail kiosk demo
|
||||
MATCH_CHECK_CODE(0xEB85EBC9596682AF, SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Doubutsu Banchou
|
||||
MATCH_CHECK_CODE(0x9A746EBF2802EA99, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Toon panic
|
||||
MATCH_CHECK_CODE(0x21548CA921548CA9, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Mini racers
|
||||
MATCH_CHECK_CODE(0xBC9B2CC34ED04DA5, SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Starcraft 64 [Prototype 2000]
|
||||
MATCH_CHECK_CODE(0x5D40ED2C10D6ABCF, SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Viewpoint 2064
|
||||
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(0xB66E0F7C2709C22F, SAVE_TYPE_SRAM, FEAT_RPAK), // Jet Force Gemini [PAL CRACK]
|
||||
MATCH_CHECK_CODE(0xCDB8B4D08832352D, SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Jet Force Gemini [USA 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(0x1F95CAAA047FC22A, SAVE_TYPE_SRAM, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey kong 64 [PAL 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_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", 1, SAVE_TYPE_SRAM, 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_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_256KBIT, 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("NSM", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Super Mario 64
|
||||
MATCH_ID_REGION_VERSION("NSMJ", 3, SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Super Mario 64 Shindou Edition
|
||||
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("NWR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Wave Race 64
|
||||
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_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_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_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_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("NSV", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_EXP_PAK_BROKEN), // Space Station Silicon Valley
|
||||
MATCH_ID_REGION("NSVE", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // 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
|
||||
|
||||
// EEPROM 4K
|
||||
MATCH_ID("CLB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK | FEAT_64DD_ENHANCED), // Mario Party (NTSC)
|
||||
MATCH_ID("NAB", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Air Boarder 64
|
||||
MATCH_ID("NAD", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Worms Armageddon (U)
|
||||
MATCH_ID("NAG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // AeroGauge
|
||||
MATCH_ID("NB6", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_TPAK), // Super B-Daman: Battle Phoenix 64
|
||||
MATCH_ID("NBC", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Blast Corps
|
||||
MATCH_ID("NBD", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Bomberman Hero [Mirian Ojo o Sukue! (J)]
|
||||
MATCH_ID("NBH", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Body Harvest
|
||||
MATCH_ID("NBK", SAVE_TYPE_EEPROM_4K, 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("NBN", SAVE_TYPE_EEPROM_4K, 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("NCG", SAVE_TYPE_EEPROM_4K, 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("NCR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Penny Racers [Choro Q 64 (J)]
|
||||
MATCH_ID("NCT", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Chameleon Twist
|
||||
MATCH_ID("NCU", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Cruis'n USA
|
||||
MATCH_ID("NCX", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Custom Robo
|
||||
MATCH_ID("NDQ", SAVE_TYPE_EEPROM_4K, 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("NDU", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Duck Dodgers starring Daffy Duck
|
||||
MATCH_ID("NDY", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Diddy Kong Racing
|
||||
MATCH_ID("NEA", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // PGA European Tour
|
||||
MATCH_ID("NER", SAVE_TYPE_EEPROM_4K, 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("NFG", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Fighter Destiny 2
|
||||
MATCH_ID("NFH", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // In-Fisherman Bass Hunter 64
|
||||
MATCH_ID("NFW", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // F-1 World Grand Prix
|
||||
MATCH_ID("NFX", SAVE_TYPE_EEPROM_4K, 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("NGE", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // GoldenEye 007
|
||||
MATCH_ID("NGL", SAVE_TYPE_EEPROM_4K, 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("NGV", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Glover
|
||||
MATCH_ID("NHA", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Bomberman 64: Arcade Edition (J)
|
||||
MATCH_ID("NHF", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // 64 Hanafuda: Tenshi no Yakusoku
|
||||
MATCH_ID("NHP", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Heiwa Pachinko World 64
|
||||
MATCH_ID("NIC", SAVE_TYPE_EEPROM_4K, 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("NIR", SAVE_TYPE_EEPROM_4K, 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("NK2", SAVE_TYPE_EEPROM_4K, 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("NKI", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Killer Instinct Gold
|
||||
MATCH_ID("NKT", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Mario Kart 64
|
||||
MATCH_ID("NLB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Mario Party (PAL)
|
||||
MATCH_ID("NLL", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Last Legion UX
|
||||
MATCH_ID("NLR", SAVE_TYPE_EEPROM_4K, 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("NMI", SAVE_TYPE_EEPROM_4K, 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("NMO", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Monopoly
|
||||
MATCH_ID("NMR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Multi-Racing Championship
|
||||
MATCH_ID("NMS", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // Morita Shougi 64
|
||||
MATCH_ID("NMU", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Big Mountain 2000
|
||||
MATCH_ID("NMW", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Mario Party 2
|
||||
MATCH_ID("NMZ", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Zool - Majou Tsukai Densetsu (J)
|
||||
MATCH_ID("NN6", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Dr. Mario 64
|
||||
MATCH_ID("NNA", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Wars Episode I: Battle for Naboo
|
||||
MATCH_ID("NOS", SAVE_TYPE_EEPROM_4K, 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("NPG", SAVE_TYPE_EEPROM_4K, 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("NPW", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Pilotwings 64
|
||||
MATCH_ID("NPY", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Puyo Puyo Sun 64
|
||||
MATCH_ID("NRA", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Rally '99 (J)
|
||||
MATCH_ID("NRC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Top Gear Overdrive
|
||||
MATCH_ID("NRS", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Wars: Rogue Squadron [Shutsugeki! Rogue Chuutai (J)]
|
||||
MATCH_ID("NS3", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // AI Shougi 3
|
||||
MATCH_ID("NS6", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Star Soldier: Vanishing Earth
|
||||
MATCH_ID("NSA", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Sonic Wings Assault (J)
|
||||
MATCH_ID("NSC", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Starshot: Space Circus Fever
|
||||
MATCH_ID("NSN", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Snow Speeder (J)
|
||||
MATCH_ID("NSS", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Super Robot Spirits
|
||||
MATCH_ID("NSU", SAVE_TYPE_EEPROM_4K, 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("NT6", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Tetris 64
|
||||
MATCH_ID("NTB", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Transformers: Beast Wars Metals 64 (J)
|
||||
MATCH_ID("NTC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // 64 Trump Collection
|
||||
MATCH_ID("NTJ", SAVE_TYPE_EEPROM_4K, 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("NTN", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // All Star Tennis '99
|
||||
MATCH_ID("NTP", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Tetrisphere
|
||||
MATCH_ID("NTR", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Top Gear Rally (J + E)
|
||||
MATCH_ID("NTW", SAVE_TYPE_EEPROM_4K, FEAT_CPAK), // 64 de Hakken!! Tamagotchi
|
||||
MATCH_ID("NTX", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Taz Express
|
||||
MATCH_ID("NVL", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // V-Rally Edition '99
|
||||
MATCH_ID("NVY", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // V-Rally Edition '99 (J)
|
||||
MATCH_ID("NWC", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Wild Choppers
|
||||
MATCH_ID("NWQ", SAVE_TYPE_EEPROM_4K, FEAT_CPAK | FEAT_RPAK), // Rally Challenge 2000
|
||||
MATCH_ID("NWU", SAVE_TYPE_EEPROM_4K, FEAT_NONE), // Worms Armageddon (E)
|
||||
MATCH_ID("NXO", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Cruis'n Exotica
|
||||
MATCH_ID("NYK", SAVE_TYPE_EEPROM_4K, FEAT_RPAK), // Yakouchuu II: Satsujin Kouro
|
||||
MATCH_ID("CLB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_64DD_ENHANCED), // Mario Party (NTSC)
|
||||
MATCH_ID("NAB", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Air Boarder 64
|
||||
MATCH_ID("NAD", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Worms Armageddon (U)
|
||||
MATCH_ID("NAG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // AeroGauge
|
||||
MATCH_ID("NB6", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_TPAK), // Super B-Daman: Battle Phoenix 64
|
||||
MATCH_ID("NBC", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Blast Corps
|
||||
MATCH_ID("NBD", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Bomberman Hero [Mirian Ojo o Sukue! (J)]
|
||||
MATCH_ID("NBH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Body Harvest
|
||||
MATCH_ID("NBK", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Banjo-Kazooie [Banjo to Kazooie no Daiboken (J)]
|
||||
MATCH_ID("NBM", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bomberman 64 [Baku Bomberman (J)]
|
||||
MATCH_ID("NBN", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bakuretsu Muteki Bangaioh
|
||||
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_4KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Choro Q 64 II - Hacha Mecha Grand Prix Race (J)
|
||||
MATCH_ID("NCH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Chopper Attack
|
||||
MATCH_ID("NCR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Penny Racers [Choro Q 64 (J)]
|
||||
MATCH_ID("NCT", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Chameleon Twist
|
||||
MATCH_ID("NCU", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Cruis'n USA
|
||||
MATCH_ID("NCX", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Custom Robo
|
||||
MATCH_ID("NDQ", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Disney's Donald Duck - Goin' Quackers [Quack Attack (E)]
|
||||
MATCH_ID("NDR", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Doraemon: Nobita to 3tsu no Seireiseki
|
||||
MATCH_ID("NDU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Duck Dodgers starring Daffy Duck
|
||||
MATCH_ID("NDY", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Diddy Kong Racing
|
||||
MATCH_ID("NEA", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // PGA European Tour
|
||||
MATCH_ID("NER", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Aero Fighters Assault [Sonic Wings Assault (J)]
|
||||
MATCH_ID("NF2", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // F-1 World Grand Prix II
|
||||
MATCH_ID("NFG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Fighter Destiny 2
|
||||
MATCH_ID("NFH", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // In-Fisherman Bass Hunter 64
|
||||
MATCH_ID("NFW", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // F-1 World Grand Prix
|
||||
MATCH_ID("NFX", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Fox 64 [Lylat Wars (E)]
|
||||
MATCH_ID("NFY", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Kakutou Denshou: F-Cup Maniax
|
||||
MATCH_ID("NGE", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // GoldenEye 007
|
||||
MATCH_ID("NGL", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Getter Love!!
|
||||
MATCH_ID("NGU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Tsumi to Batsu: Hoshi no Keishousha (Sin and Punishment)
|
||||
MATCH_ID("NGV", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Glover
|
||||
MATCH_ID("NHA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Bomberman 64: Arcade Edition (J)
|
||||
MATCH_ID("NHF", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // 64 Hanafuda: Tenshi no Yakusoku
|
||||
MATCH_ID("NHP", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Heiwa Pachinko World 64
|
||||
MATCH_ID("NIC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Indy Racing 2000
|
||||
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_4KBIT, FEAT_RPAK), // Utchan Nanchan no Hono no Challenger: Denryuu Ira Ira Bou
|
||||
MATCH_ID("NJM", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Earthworm Jim 3D
|
||||
MATCH_ID("NK2", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Snowboard Kids 2 [Chou Snobow Kids (J)]
|
||||
MATCH_ID("NKA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Fighters Destiny [Fighting Cup (J)]
|
||||
MATCH_ID("NKI", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Killer Instinct Gold
|
||||
MATCH_ID("NKT", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Mario Kart 64
|
||||
MATCH_ID("NLB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mario Party (PAL)
|
||||
MATCH_ID("NLL", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Last Legion UX
|
||||
MATCH_ID("NLR", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Lode Runner 3-D
|
||||
MATCH_ID("NMG", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Monaco Grand Prix [Racing Simulation 2 (G)]
|
||||
MATCH_ID("NMI", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mission: Impossible
|
||||
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_4KBIT, FEAT_NONE), // Monopoly
|
||||
MATCH_ID("NMR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Multi-Racing Championship
|
||||
MATCH_ID("NMS", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // Morita Shougi 64
|
||||
MATCH_ID("NMU", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Big Mountain 2000
|
||||
MATCH_ID("NMW", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Mario Party 2
|
||||
MATCH_ID("NMZ", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Zool - Majou Tsukai Densetsu (J)
|
||||
MATCH_ID("NN6", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Dr. Mario 64
|
||||
MATCH_ID("NNA", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Wars Episode I: Battle for Naboo
|
||||
MATCH_ID("NOS", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // 64 Oozumou
|
||||
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_4KBIT, FEAT_RPAK | FEAT_VRU), // Hey You, Pikachu! [Pikachu Genki Dechu (J)]
|
||||
MATCH_ID("NPT", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_TPAK), // Puyo Puyon Party
|
||||
MATCH_ID("NPW", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Pilotwings 64
|
||||
MATCH_ID("NPY", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Puyo Puyo Sun 64
|
||||
MATCH_ID("NRA", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Rally '99 (J)
|
||||
MATCH_ID("NRC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Top Gear Overdrive
|
||||
MATCH_ID("NRS", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Wars: Rogue Squadron [Shutsugeki! Rogue Chuutai (J)]
|
||||
MATCH_ID("NS3", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // AI Shougi 3
|
||||
MATCH_ID("NS6", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Star Soldier: Vanishing Earth
|
||||
MATCH_ID("NSA", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Sonic Wings Assault (J)
|
||||
MATCH_ID("NSC", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Starshot: Space Circus Fever
|
||||
MATCH_ID("NSN", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Snow Speeder (J)
|
||||
MATCH_ID("NSS", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Super Robot Spirits
|
||||
MATCH_ID("NSU", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Rocket: Robot on Wheels
|
||||
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_4KBIT, FEAT_NONE), // Tetris 64
|
||||
MATCH_ID("NTB", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Transformers: Beast Wars Metals 64 (J)
|
||||
MATCH_ID("NTC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // 64 Trump Collection
|
||||
MATCH_ID("NTJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Tom & Jerry in Fists of Fury
|
||||
MATCH_ID("NTM", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Mischief Makers [Yuke Yuke!! Trouble Makers (J)]
|
||||
MATCH_ID("NTN", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // All Star Tennis '99
|
||||
MATCH_ID("NTP", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Tetrisphere
|
||||
MATCH_ID("NTR", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Top Gear Rally (J + E)
|
||||
MATCH_ID("NTW", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK), // 64 de Hakken!! Tamagotchi
|
||||
MATCH_ID("NTX", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Taz Express
|
||||
MATCH_ID("NVL", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // V-Rally Edition '99
|
||||
MATCH_ID("NVY", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // V-Rally Edition '99 (J)
|
||||
MATCH_ID("NWC", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Wild Choppers
|
||||
MATCH_ID("NWQ", SAVE_TYPE_EEPROM_4KBIT, FEAT_CPAK | FEAT_RPAK), // Rally Challenge 2000
|
||||
MATCH_ID("NWU", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Worms Armageddon (E)
|
||||
MATCH_ID("NXO", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Cruis'n Exotica
|
||||
MATCH_ID("NYK", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Yakouchuu II: Satsujin Kouro
|
||||
|
||||
// EEPROM 16K
|
||||
MATCH_ID("N3D", SAVE_TYPE_EEPROM_16K, 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("NCW", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Cruis'n World
|
||||
MATCH_ID("NCZ", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Custom Robo V2
|
||||
MATCH_ID("ND2", SAVE_TYPE_EEPROM_16K, 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("NDO", SAVE_TYPE_EEPROM_16K, 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("NEV", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Neon Genesis Evangelion
|
||||
MATCH_ID("NFU", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Conker's Bad Fur Day
|
||||
MATCH_ID("NGC", SAVE_TYPE_EEPROM_16K, 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("NIM", SAVE_TYPE_EEPROM_16K, FEAT_NONE), // Ide Yosuke no Mahjong Juku
|
||||
MATCH_ID("NM8", SAVE_TYPE_EEPROM_16K, FEAT_RPAK | FEAT_TPAK), // Mario Tennis
|
||||
MATCH_ID("NMV", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Mario Party 3
|
||||
MATCH_ID("NMX", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_RPAK), // Excitebike 64
|
||||
MATCH_ID("NNB", SAVE_TYPE_EEPROM_16K, 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("NPP", SAVE_TYPE_EEPROM_16K, 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("NRZ", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Ridge Racer 64
|
||||
MATCH_ID("NUB", SAVE_TYPE_EEPROM_16K, FEAT_CPAK | FEAT_TPAK), // PD Ultraman Battle Collection 64
|
||||
MATCH_ID("NYS", SAVE_TYPE_EEPROM_16K, FEAT_RPAK), // Yoshi's Story
|
||||
MATCH_ID("N3D", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Doraemon 3: Nobita no Machi SOS!
|
||||
MATCH_ID("NB7", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Banjo-Tooie [Banjo to Kazooie no Daiboken 2 (J)]
|
||||
MATCH_ID("NCW", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Cruis'n World
|
||||
MATCH_ID("NCZ", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Custom Robo V2
|
||||
MATCH_ID("ND2", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Doraemon 2: Nobita to Hikari no Shinden
|
||||
MATCH_ID("ND6", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_VRU), // Densha de Go! 64
|
||||
MATCH_ID("NDO", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_EXP_PAK_REQUIRED), // Donkey Kong 64
|
||||
MATCH_ID("NEP", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Star Wars Episode I: Racer
|
||||
MATCH_ID("NEV", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Neon Genesis Evangelion
|
||||
MATCH_ID("NFU", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Conker's Bad Fur Day
|
||||
MATCH_ID("NGC", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // GT 64: Championship Edition
|
||||
MATCH_ID("NGT", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // City Tour GrandPrix - Zen Nihon GT Senshuken
|
||||
MATCH_ID("NIM", SAVE_TYPE_EEPROM_16KBIT, FEAT_NONE), // Ide Yosuke no Mahjong Juku
|
||||
MATCH_ID("NM8", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK | FEAT_TPAK), // Mario Tennis
|
||||
MATCH_ID("NMV", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Mario Party 3
|
||||
MATCH_ID("NMX", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Excitebike 64
|
||||
MATCH_ID("NNB", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Kobe Bryant in NBA Courtside
|
||||
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_16KBIT, FEAT_CPAK), // Parlor! Pro 64: Pachinko Jikki Simulation Game
|
||||
MATCH_ID("NR7", SAVE_TYPE_EEPROM_16KBIT, FEAT_TPAK), // Robot Poncots 64: 7tsu no Umi no Caramel
|
||||
MATCH_ID("NRZ", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Ridge Racer 64
|
||||
MATCH_ID("NUB", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_TPAK), // PD Ultraman Battle Collection 64
|
||||
MATCH_ID("NYS", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Yoshi's Story
|
||||
|
||||
// SRAM 256K
|
||||
MATCH_ID("CFZ", SAVE_TYPE_SRAM, 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("CZL", SAVE_TYPE_SRAM, 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("NAL", SAVE_TYPE_SRAM, 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("NDD", SAVE_TYPE_SRAM, 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("NG6", SAVE_TYPE_SRAM, FEAT_RPAK), // Ganmare Goemon: Dero Dero Douchuu Obake Tenkomori
|
||||
MATCH_ID("NGP", SAVE_TYPE_SRAM, FEAT_CPAK), // Goemon: Mononoke Sugoroku
|
||||
MATCH_ID("NHY", SAVE_TYPE_SRAM, 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("NJ5", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 5
|
||||
MATCH_ID("NJG", SAVE_TYPE_SRAM, FEAT_RPAK), // Jinsei Game 64
|
||||
MATCH_ID("NKG", SAVE_TYPE_SRAM, 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("NOB", SAVE_TYPE_SRAM, FEAT_NONE), // Ogre Battle 64: Person of Lordly Caliber
|
||||
MATCH_ID("NP4", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 4
|
||||
MATCH_ID("NP6", SAVE_TYPE_SRAM, 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("NPE", SAVE_TYPE_SRAM, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu Basic Ban 2001
|
||||
MATCH_ID("NPM", SAVE_TYPE_SRAM, FEAT_CPAK), // Premier Manager 64
|
||||
MATCH_ID("NPS", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Jikkyou J.League 1999: Perfect Striker 2
|
||||
MATCH_ID("NRE", SAVE_TYPE_SRAM, FEAT_RPAK), // Resident Evil 2
|
||||
MATCH_ID("NRI", SAVE_TYPE_SRAM, FEAT_CPAK), // New Tetris, The
|
||||
MATCH_ID("NS4", SAVE_TYPE_SRAM, 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("NT3", SAVE_TYPE_SRAM, 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("NUM", SAVE_TYPE_SRAM, 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("NVB", SAVE_TYPE_SRAM, FEAT_RPAK), // Bass Rush - ECOGEAR PowerWorm Championship (J)
|
||||
MATCH_ID("NVP", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 64
|
||||
MATCH_ID("NW2", SAVE_TYPE_SRAM, FEAT_RPAK), // WCW-nWo Revenge
|
||||
MATCH_ID("NWL", SAVE_TYPE_SRAM, FEAT_RPAK), // Waialae Country Club: True Golf Classics
|
||||
MATCH_ID("NWX", SAVE_TYPE_SRAM, FEAT_CPAK | FEAT_RPAK), // WWF WrestleMania 2000
|
||||
MATCH_ID("NYW", SAVE_TYPE_SRAM, FEAT_NONE), // Harvest Moon 64
|
||||
MATCH_ID("NZL", SAVE_TYPE_SRAM, FEAT_RPAK), // Legend of Zelda: Ocarina of Time (E)
|
||||
MATCH_ID("CFZ", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_64DD_ENHANCED), // F-Zero X (J)
|
||||
MATCH_ID("CPS", SAVE_TYPE_SRAM_256KBIT, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium (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_256KBIT, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 2
|
||||
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_256KBIT, FEAT_RPAK), // Biohazard 2 (J)
|
||||
MATCH_ID("NDD", SAVE_TYPE_SRAM_256KBIT, FEAT_EXP_PAK_REQUIRED | FEAT_64DD_CONVERSION), // 64DD Conversion Rom
|
||||
MATCH_ID("NFZ", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // F-Zero X (U + E)
|
||||
MATCH_ID("NG6", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Ganmare Goemon: Dero Dero Douchuu Obake Tenkomori
|
||||
MATCH_ID("NGP", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Goemon: Mononoke Sugoroku
|
||||
MATCH_ID("NHY", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Hybrid Heaven (J)
|
||||
MATCH_ID("NIB", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!
|
||||
MATCH_ID("NJ5", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 5
|
||||
MATCH_ID("NJG", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Jinsei Game 64
|
||||
MATCH_ID("NKG", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Major League Baseball featuring Ken Griffey Jr.
|
||||
MATCH_ID("NMF", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_TPAK), // Mario Golf 64
|
||||
MATCH_ID("NOB", SAVE_TYPE_SRAM_256KBIT, FEAT_NONE), // Ogre Battle 64: Person of Lordly Caliber
|
||||
MATCH_ID("NP4", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu 4
|
||||
MATCH_ID("NP6", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 6
|
||||
MATCH_ID("NPA", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Jikkyou Powerful Pro Yakyuu 2000
|
||||
MATCH_ID("NPE", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Jikkyou Powerful Pro Yakyuu Basic Ban 2001
|
||||
MATCH_ID("NPM", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Premier Manager 64
|
||||
MATCH_ID("NPS", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Jikkyou J.League 1999: Perfect Striker 2
|
||||
MATCH_ID("NRE", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Resident Evil 2
|
||||
MATCH_ID("NRI", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // New Tetris, The
|
||||
MATCH_ID("NS4", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_TPAK), // Super Robot Taisen 64
|
||||
MATCH_ID("NSI", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK), // Fushigi no Dungeon: Fuurai no Shiren 2
|
||||
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_256KBIT, FEAT_RPAK), // 1080 Snowboarding
|
||||
MATCH_ID("NUM", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64: Shiokaze ni Notte
|
||||
MATCH_ID("NUT", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK), // Nushi Zuri 64
|
||||
MATCH_ID("NVB", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Bass Rush - ECOGEAR PowerWorm Championship (J)
|
||||
MATCH_ID("NVP", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // Virtual Pro Wrestling 64
|
||||
MATCH_ID("NW2", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // WCW-nWo Revenge
|
||||
MATCH_ID("NWL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Waialae Country Club: True Golf Classics
|
||||
MATCH_ID("NWX", SAVE_TYPE_SRAM_256KBIT, FEAT_CPAK | FEAT_RPAK), // WWF WrestleMania 2000
|
||||
MATCH_ID("NYW", SAVE_TYPE_SRAM_256KBIT, FEAT_NONE), // Harvest Moon 64
|
||||
MATCH_ID("NZL", SAVE_TYPE_SRAM_256KBIT, FEAT_RPAK), // Legend of Zelda: Ocarina of Time (E)
|
||||
|
||||
// SRAM 768K
|
||||
MATCH_ID("CDZ", SAVE_TYPE_SRAM_BANKED, FEAT_RPAK | FEAT_64DD_ENHANCED), // Dezaemon 3D
|
||||
|
||||
// FLASHRAM
|
||||
MATCH_ID("CP2", SAVE_TYPE_FLASHRAM, 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("NCC", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Command & Conquer
|
||||
MATCH_ID("NCV", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Cubivore (Translation)
|
||||
MATCH_ID("NCK", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // NBA Courtside 2 featuring Kobe Bryant
|
||||
MATCH_ID("NDA", SAVE_TYPE_FLASHRAM, FEAT_CPAK), // Derby Stallion 64
|
||||
MATCH_ID("NDP", SAVE_TYPE_FLASHRAM, FEAT_EXP_PAK_REQUIRED), // Dinosaur Planet (Unlicensed)
|
||||
MATCH_ID("NJF", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Jet Force Gemini [Star Twins (J)]
|
||||
MATCH_ID("NKJ", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Ken Griffey Jr.'s Slugfest
|
||||
MATCH_ID("NM6", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Mega Man 64
|
||||
MATCH_ID("NMQ", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Paper Mario
|
||||
MATCH_ID("NPF", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Pokemon Snap [Pocket Monsters Snap (J)]
|
||||
MATCH_ID("NPN", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Pokemon Puzzle League
|
||||
MATCH_ID("NPO", SAVE_TYPE_FLASHRAM, FEAT_TPAK), // Pokemon Stadium
|
||||
MATCH_ID("NRH", SAVE_TYPE_FLASHRAM, FEAT_RPAK), // Rockman Dash - Hagane no Boukenshin (J)
|
||||
MATCH_ID("NSQ", SAVE_TYPE_FLASHRAM, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // StarCraft 64
|
||||
MATCH_ID("NT9", SAVE_TYPE_FLASHRAM, FEAT_NONE), // Tigger's Honey Hunt
|
||||
MATCH_ID("NW4", SAVE_TYPE_FLASHRAM, 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("CP2", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_TPAK | FEAT_64DD_ENHANCED), // Pocket Monsters Stadium 2 (J)
|
||||
MATCH_ID("NAF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK | FEAT_RTC), // Doubutsu no Mori
|
||||
MATCH_ID("NCC", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Command & Conquer
|
||||
MATCH_ID("NCV", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Cubivore (Translation)
|
||||
MATCH_ID("NCK", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // NBA Courtside 2 featuring Kobe Bryant
|
||||
MATCH_ID("NDA", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK), // Derby Stallion 64
|
||||
MATCH_ID("NDP", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_EXP_PAK_REQUIRED), // Dinosaur Planet (Unlicensed)
|
||||
MATCH_ID("NJF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Jet Force Gemini [Star Twins (J)]
|
||||
MATCH_ID("NKJ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Ken Griffey Jr.'s Slugfest
|
||||
MATCH_ID("NM6", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Mega Man 64
|
||||
MATCH_ID("NMQ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Paper Mario
|
||||
MATCH_ID("NPF", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Pokemon Snap [Pocket Monsters Snap (J)]
|
||||
MATCH_ID("NPN", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Pokemon Puzzle League
|
||||
MATCH_ID("NPO", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_TPAK), // Pokemon Stadium
|
||||
MATCH_ID("NRH", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK), // Rockman Dash - Hagane no Boukenshin (J)
|
||||
MATCH_ID("NSQ", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_RPAK | FEAT_EXP_PAK_RECOMMENDED), // StarCraft 64
|
||||
MATCH_ID("NT9", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_NONE), // Tigger's Honey Hunt
|
||||
MATCH_ID("NW4", SAVE_TYPE_FLASHRAM_1MBIT, FEAT_CPAK | FEAT_RPAK), // WWF No Mercy
|
||||
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)]
|
||||
|
||||
@ -749,12 +750,12 @@ static void extract_rom_info (match_t *match, rom_header_t *rom_header, rom_info
|
||||
}
|
||||
switch ((rom_header->version & 0xF0) >> 4) {
|
||||
case 0: match->data.save = SAVE_TYPE_NONE; break;
|
||||
case 1: match->data.save = SAVE_TYPE_EEPROM_4K; break;
|
||||
case 2: match->data.save = SAVE_TYPE_EEPROM_16K; break;
|
||||
case 3: match->data.save = SAVE_TYPE_SRAM; break;
|
||||
case 1: match->data.save = SAVE_TYPE_EEPROM_4KBIT; break;
|
||||
case 2: match->data.save = SAVE_TYPE_EEPROM_16KBIT; break;
|
||||
case 3: match->data.save = SAVE_TYPE_SRAM_256KBIT; break;
|
||||
case 4: match->data.save = SAVE_TYPE_SRAM_BANKED; break;
|
||||
case 5: match->data.save = SAVE_TYPE_FLASHRAM; break;
|
||||
case 6: match->data.save = SAVE_TYPE_SRAM_128K; break;
|
||||
case 5: match->data.save = SAVE_TYPE_FLASHRAM_1MBIT; break;
|
||||
case 6: match->data.save = SAVE_TYPE_SRAM_1MBIT; break;
|
||||
default: match->data.save = SAVE_TYPE_NONE; break;
|
||||
}
|
||||
}
|
||||
@ -832,13 +833,21 @@ static rom_err_t save_override (path_t *path, const char *id, int value, int def
|
||||
mini_t *ini = mini_try_load(path_get(overrides_path));
|
||||
|
||||
if (!ini) {
|
||||
return ROM_ERR_IO;
|
||||
return ROM_ERR_SAVE_IO;
|
||||
}
|
||||
|
||||
int mini_err;
|
||||
|
||||
if (value == default_value) {
|
||||
mini_delete_value(ini, NULL, id);
|
||||
mini_err = mini_delete_value(ini, NULL, id);
|
||||
} else {
|
||||
mini_set_int(ini, NULL, id, value);
|
||||
mini_err = mini_set_int(ini, NULL, id, value);
|
||||
}
|
||||
|
||||
if ((mini_err != MINI_OK) && (mini_err != MINI_VALUE_NOT_FOUND)) {
|
||||
path_free(overrides_path);
|
||||
mini_free(ini);
|
||||
return ROM_ERR_SAVE_IO;
|
||||
}
|
||||
|
||||
bool empty = mini_empty(ini);
|
||||
@ -847,16 +856,16 @@ static rom_err_t save_override (path_t *path, const char *id, int value, int def
|
||||
if (mini_save(ini, MINI_FLAGS_NONE) != MINI_OK) {
|
||||
path_free(overrides_path);
|
||||
mini_free(ini);
|
||||
return ROM_ERR_IO;
|
||||
return ROM_ERR_SAVE_IO;
|
||||
}
|
||||
}
|
||||
|
||||
mini_free(ini);
|
||||
|
||||
if (empty) {
|
||||
if (remove(path_get(overrides_path))) {
|
||||
if (remove(path_get(overrides_path)) && (errno != ENOENT)) {
|
||||
path_free(overrides_path);
|
||||
return ROM_ERR_IO;
|
||||
return ROM_ERR_SAVE_IO;
|
||||
}
|
||||
}
|
||||
|
||||
@ -946,10 +955,10 @@ rom_err_t rom_info_load (path_t *path, rom_info_t *rom_info) {
|
||||
setbuf(f, NULL);
|
||||
if (fread(&rom_header, sizeof(rom_header), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return ROM_ERR_IO;
|
||||
return ROM_ERR_LOAD_IO;
|
||||
}
|
||||
if (fclose(f)) {
|
||||
return ROM_ERR_IO;
|
||||
return ROM_ERR_LOAD_IO;
|
||||
}
|
||||
|
||||
fix_rom_header_endianness(&rom_header, rom_info);
|
||||
|
@ -18,7 +18,8 @@
|
||||
/** @brief ROM error enumeration. */
|
||||
typedef enum {
|
||||
ROM_OK,
|
||||
ROM_ERR_IO,
|
||||
ROM_ERR_LOAD_IO,
|
||||
ROM_ERR_SAVE_IO,
|
||||
ROM_ERR_NO_FILE,
|
||||
} rom_err_t;
|
||||
|
||||
@ -113,12 +114,12 @@ typedef enum {
|
||||
typedef enum {
|
||||
/** @brief There is no expected save type. */
|
||||
SAVE_TYPE_NONE = 0,
|
||||
SAVE_TYPE_EEPROM_4K = 1,
|
||||
SAVE_TYPE_EEPROM_16K = 2,
|
||||
SAVE_TYPE_SRAM = 3,
|
||||
SAVE_TYPE_EEPROM_4KBIT = 1,
|
||||
SAVE_TYPE_EEPROM_16KBIT = 2,
|
||||
SAVE_TYPE_SRAM_256KBIT = 3,
|
||||
SAVE_TYPE_SRAM_BANKED = 4,
|
||||
SAVE_TYPE_SRAM_128K = 5,
|
||||
SAVE_TYPE_FLASHRAM = 6,
|
||||
SAVE_TYPE_SRAM_1MBIT = 5,
|
||||
SAVE_TYPE_FLASHRAM_1MBIT = 6,
|
||||
SAVE_TYPE_FLASHRAM_PKST2 = 7,
|
||||
SAVE_TYPE_AUTOMATIC = -1,
|
||||
} rom_save_type_t;
|
||||
|
@ -13,10 +13,10 @@ static settings_t init = {
|
||||
.show_protected_entries = false,
|
||||
.default_directory = "/",
|
||||
.use_saves_folder = true,
|
||||
.sound_enabled = true,
|
||||
|
||||
/* Beta feature flags (should always init to off) */
|
||||
.bgm_enabled = false,
|
||||
.sound_enabled = false,
|
||||
.rumble_enabled = false,
|
||||
};
|
||||
|
||||
@ -39,10 +39,10 @@ void settings_load (settings_t *settings) {
|
||||
settings->show_protected_entries = mini_get_bool(ini, "menu", "show_protected_entries", init.show_protected_entries);
|
||||
settings->default_directory = strdup(mini_get_string(ini, "menu", "default_directory", init.default_directory));
|
||||
settings->use_saves_folder = mini_get_bool(ini, "menu", "use_saves_folder", init.use_saves_folder);
|
||||
settings->sound_enabled = mini_get_bool(ini, "menu", "sound_enabled", init.sound_enabled);
|
||||
|
||||
/* Beta feature flags, they might not be in the file */
|
||||
settings->bgm_enabled = mini_get_bool(ini, "menu_beta_flag", "bgm_enabled", init.bgm_enabled);
|
||||
settings->sound_enabled = mini_get_bool(ini, "menu_beta_flag", "sound_enabled", init.sound_enabled);
|
||||
settings->rumble_enabled = mini_get_bool(ini, "menu_beta_flag", "rumble_enabled", init.rumble_enabled);
|
||||
|
||||
mini_free(ini);
|
||||
@ -55,10 +55,10 @@ void settings_save (settings_t *settings) {
|
||||
mini_set_bool(ini, "menu", "show_protected_entries", settings->show_protected_entries);
|
||||
mini_set_string(ini, "menu", "default_directory", settings->default_directory);
|
||||
mini_set_bool(ini, "menu", "use_saves_folder", settings->use_saves_folder);
|
||||
mini_set_bool(ini, "menu", "sound_enabled", settings->sound_enabled);
|
||||
|
||||
/* Beta feature flags, they should not save until production ready! */
|
||||
// mini_set_bool(ini, "menu_beta_flag", "bgm_enabled", settings->bgm_enabled);
|
||||
// mini_set_bool(ini, "menu_beta_flag", "sound_enabled", settings->sound_enabled);
|
||||
// mini_set_bool(ini, "menu_beta_flag", "rumble_enabled", settings->rumble_enabled);
|
||||
|
||||
mini_save(ini, MINI_FLAGS_SKIP_EMPTY_GROUPS);
|
||||
|
@ -3,14 +3,18 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#include "mp3_player.h"
|
||||
#include "sound.h"
|
||||
|
||||
|
||||
#define DEFAULT_FREQUENCY (44100)
|
||||
#define NUM_BUFFERS (4)
|
||||
#define NUM_CHANNELS (2)
|
||||
#define NUM_CHANNELS (3)
|
||||
|
||||
static wav64_t sfx_cursor, sfx_error, sfx_enter, sfx_exit, sfx_setting;
|
||||
|
||||
|
||||
static bool sound_initialized = false;
|
||||
static bool sfx_enabled = false;
|
||||
|
||||
|
||||
static void sound_reconfigure (int frequency) {
|
||||
@ -35,6 +39,51 @@ void sound_init_mp3_playback (void) {
|
||||
sound_reconfigure(mp3player_get_samplerate());
|
||||
}
|
||||
|
||||
|
||||
void sound_init_sfx (void) {
|
||||
mixer_ch_set_vol(SOUND_SFX_CHANNEL, 0.5f, 0.5f);
|
||||
wav64_open(&sfx_cursor, "rom:/cursorsound.wav64");
|
||||
wav64_open(&sfx_exit, "rom:/back.wav64");
|
||||
wav64_open(&sfx_setting, "rom:/settings.wav64");
|
||||
wav64_open(&sfx_enter, "rom:/enter.wav64");
|
||||
wav64_open(&sfx_error, "rom:/error.wav64");
|
||||
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) {
|
||||
if(sfx_enabled) {
|
||||
switch (sfx) {
|
||||
case SFX_CURSOR:
|
||||
wav64_play(&sfx_cursor, SOUND_SFX_CHANNEL);
|
||||
break;
|
||||
case SFX_EXIT:
|
||||
wav64_play(&sfx_exit, SOUND_SFX_CHANNEL);
|
||||
break;
|
||||
case SFX_SETTING:
|
||||
wav64_play(&sfx_setting, SOUND_SFX_CHANNEL);
|
||||
break;
|
||||
case SFX_ENTER:
|
||||
wav64_play(&sfx_enter, SOUND_SFX_CHANNEL);
|
||||
break;
|
||||
case SFX_ERROR:
|
||||
wav64_play(&sfx_error, SOUND_SFX_CHANNEL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sound_deinit (void) {
|
||||
if (sound_initialized) {
|
||||
mixer_close();
|
||||
|
@ -7,14 +7,26 @@
|
||||
#ifndef SOUND_H__
|
||||
#define SOUND_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SOUND_MP3_PLAYER_CHANNEL (0)
|
||||
#define SOUND_SFX_CHANNEL (2)
|
||||
|
||||
typedef enum {
|
||||
SFX_CURSOR,
|
||||
SFX_ERROR,
|
||||
SFX_ENTER,
|
||||
SFX_EXIT,
|
||||
SFX_SETTING,
|
||||
} sound_effect_t;
|
||||
|
||||
|
||||
void sound_init_default (void);
|
||||
void sound_init_mp3_playback (void);
|
||||
void sound_init_sfx (void);
|
||||
void sound_use_sfx(bool);
|
||||
void sound_play_effect(sound_effect_t sfx);
|
||||
void sound_deinit (void);
|
||||
void sound_poll (void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../fonts.h"
|
||||
#include "utils/fs.h"
|
||||
#include "views.h"
|
||||
#include "../sound.h"
|
||||
|
||||
|
||||
static const char *rom_extensions[] = { "z64", "n64", "v64", "rom", NULL };
|
||||
@ -22,10 +23,17 @@ static const char *hidden_paths[] = {
|
||||
"/menu.bin",
|
||||
"/menu",
|
||||
"/N64FlashcartMenu.n64",
|
||||
"/OS64.v64",
|
||||
"/OS64P.v64",
|
||||
"/ED64",
|
||||
"/ED64P",
|
||||
"/sc64menu.n64",
|
||||
// Windows garbage
|
||||
"/System Volume Information",
|
||||
// macOS garbage
|
||||
"/.fseventsd",
|
||||
"/.Spotlight-V100",
|
||||
"/.Trashes",
|
||||
"/.VolumeIcon.icns",
|
||||
"/.metadata_never_index",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -303,16 +311,19 @@ static void process (menu_t *menu) {
|
||||
if (menu->browser.selected < 0) {
|
||||
menu->browser.selected = 0;
|
||||
}
|
||||
sound_play_effect(SFX_CURSOR);
|
||||
} else if (menu->actions.go_down) {
|
||||
menu->browser.selected += scroll_speed;
|
||||
if (menu->browser.selected >= menu->browser.entries) {
|
||||
menu->browser.selected = menu->browser.entries - 1;
|
||||
}
|
||||
sound_play_effect(SFX_CURSOR);
|
||||
}
|
||||
menu->browser.entry = &menu->browser.list[menu->browser.selected];
|
||||
}
|
||||
|
||||
if (menu->actions.enter && menu->browser.entry) {
|
||||
sound_play_effect(SFX_ENTER);
|
||||
switch (menu->browser.entry->type) {
|
||||
case ENTRY_TYPE_DIR:
|
||||
if (push_directory(menu, menu->browser.entry->name)) {
|
||||
@ -350,10 +361,13 @@ static void process (menu_t *menu) {
|
||||
menu->browser.valid = false;
|
||||
menu_show_error(menu, "Couldn't open last directory");
|
||||
}
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (menu->actions.options && menu->browser.entry) {
|
||||
component_context_menu_show(&entry_context_menu);
|
||||
sound_play_effect(SFX_SETTING);
|
||||
} else if (menu->actions.settings) {
|
||||
component_context_menu_show(&settings_context_menu);
|
||||
sound_play_effect(SFX_SETTING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "views.h"
|
||||
|
||||
#include "../sound.h"
|
||||
|
||||
#ifndef MENU_VERSION
|
||||
#define MENU_VERSION "Unknown"
|
||||
@ -13,6 +13,7 @@
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "views.h"
|
||||
#include "../sound.h"
|
||||
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +50,7 @@ void view_error_display (menu_t *menu, surface_t *display) {
|
||||
}
|
||||
|
||||
void menu_show_error (menu_t *menu, char *error_message) {
|
||||
sound_play_effect(SFX_ERROR);
|
||||
menu->next_mode = MENU_MODE_ERROR;
|
||||
menu->error_message = error_message;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <sys/stat.h>
|
||||
#include "../sound.h"
|
||||
|
||||
#include "utils/fs.h"
|
||||
#include "views.h"
|
||||
@ -12,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 *image_extensions[] = { "png", "jpg", "gif", NULL };
|
||||
static const char *music_extensions[] = { "mp3", "wav", "ogg", "wma", "flac", NULL };
|
||||
static const char *dexdrive_extensions[] = { "mpk", NULL };
|
||||
static const char *emulator_extensions[] = { "emu", NULL };
|
||||
static const char *controller_pak_extensions[] = { "mpk", "pak", NULL };
|
||||
static const char *emulator_extensions[] = { "nes", "smc", "gb", "gbc", "sms", "gg", NULL };
|
||||
|
||||
|
||||
static struct stat st;
|
||||
@ -38,10 +39,10 @@ static char *format_file_type (char *name, bool is_directory) {
|
||||
return " Type: Image file\n";
|
||||
} else if (file_has_extensions(name, music_extensions)) {
|
||||
return " Type: Music file\n";
|
||||
} else if (file_has_extensions(name, dexdrive_extensions)) {
|
||||
return " Type: DexDrive CPak backup file\n";
|
||||
} else if (file_has_extensions(name, controller_pak_extensions)) {
|
||||
return " Type: Controller Pak file\n";
|
||||
} else if (file_has_extensions(name, emulator_extensions)) {
|
||||
return " Type: Emulator file\n";
|
||||
return " Type: Emulator ROM file\n";
|
||||
}
|
||||
return " Type: Unknown file\n";
|
||||
}
|
||||
@ -50,6 +51,7 @@ static char *format_file_type (char *name, bool is_directory) {
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "views.h"
|
||||
#include "../sound.h"
|
||||
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,8 +19,17 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"FLASHCART INFORMATION\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This feature is not yet supported.\n\n"
|
||||
);
|
||||
|
||||
// FIXME: Display:
|
||||
// * cart_type
|
||||
// * Firmware version
|
||||
// * supported features (flashcart_features_t)
|
||||
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include "../sound.h"
|
||||
|
||||
#include "../png_decoder.h"
|
||||
#include "views.h"
|
||||
@ -40,6 +41,7 @@ static void process (menu_t *menu) {
|
||||
} else {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
}
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (menu->actions.enter && image) {
|
||||
if (show_message) {
|
||||
show_message = false;
|
||||
@ -48,6 +50,7 @@ static void process (menu_t *menu) {
|
||||
} else {
|
||||
show_message = true;
|
||||
}
|
||||
sound_play_effect(SFX_ENTER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
#include "../cart_load.h"
|
||||
#include "../disk_info.h"
|
||||
#include "boot/boot.h"
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
static bool load_pending;
|
||||
static bool load_rom;
|
||||
static component_boxart_t *boxart;
|
||||
|
||||
|
||||
static char *convert_error_message (disk_err_t err) {
|
||||
@ -34,8 +36,10 @@ static void process (menu_t *menu) {
|
||||
} else if (menu->actions.options && menu->load.rom_path) {
|
||||
load_pending = true;
|
||||
load_rom = true;
|
||||
sound_play_effect(SFX_SETTING);
|
||||
} else if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,6 +93,8 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"R: Load with ROM"
|
||||
);
|
||||
}
|
||||
|
||||
component_boxart_draw(boxart);
|
||||
}
|
||||
|
||||
rdpq_detach_show();
|
||||
@ -145,6 +151,9 @@ static void load (menu_t *menu) {
|
||||
}
|
||||
}
|
||||
|
||||
static void deinit (void) {
|
||||
component_boxart_free(boxart);
|
||||
}
|
||||
|
||||
void view_load_disk_init (menu_t *menu) {
|
||||
if (menu->load.disk_path) {
|
||||
@ -160,6 +169,8 @@ void view_load_disk_init (menu_t *menu) {
|
||||
if (err != DISK_OK) {
|
||||
menu_show_error(menu, convert_error_message(err));
|
||||
}
|
||||
|
||||
boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id);
|
||||
}
|
||||
|
||||
void view_load_disk_display (menu_t *menu, surface_t *display) {
|
||||
@ -171,4 +182,8 @@ void view_load_disk_display (menu_t *menu, surface_t *display) {
|
||||
load_pending = false;
|
||||
load(menu);
|
||||
}
|
||||
|
||||
if (menu->next_mode != MENU_MODE_LOAD_DISK) {
|
||||
deinit();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "../cart_load.h"
|
||||
#include "boot/boot.h"
|
||||
#include "utils/fs.h"
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
@ -36,6 +37,7 @@ static void process (menu_t *menu) {
|
||||
load_pending = true;
|
||||
} else if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,18 @@
|
||||
#include "../cart_load.h"
|
||||
#include "../rom_info.h"
|
||||
#include "boot/boot.h"
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
static bool show_extra_info_message = false;
|
||||
static bool load_pending;
|
||||
static component_boxart_t *boxart;
|
||||
|
||||
|
||||
static char *convert_error_message (rom_err_t err) {
|
||||
switch (err) {
|
||||
case ROM_ERR_IO: return "I/O error during loading/storing ROM information";
|
||||
case ROM_ERR_LOAD_IO: return "I/O error during loading ROM information and/or options";
|
||||
case ROM_ERR_SAVE_IO: return "I/O error during storing ROM options";
|
||||
case ROM_ERR_NO_FILE: return "Couldn't open ROM file";
|
||||
default: return "Unknown ROM info load error";
|
||||
}
|
||||
@ -64,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) {
|
||||
case SAVE_TYPE_NONE: return "None";
|
||||
case SAVE_TYPE_EEPROM_4K: return "EEPROM 4K";
|
||||
case SAVE_TYPE_EEPROM_16K: return "EEPROM 16K";
|
||||
case SAVE_TYPE_SRAM: return "SRAM";
|
||||
case SAVE_TYPE_SRAM_BANKED: return "SRAM Banked";
|
||||
case SAVE_TYPE_SRAM_128K: return "SRAM 128K";
|
||||
case SAVE_TYPE_FLASHRAM: return "FlashRAM";
|
||||
case SAVE_TYPE_FLASHRAM_PKST2: return "FlashRAM (Pokemon Stadium 2)";
|
||||
case SAVE_TYPE_NONE: return supports_cpak ? "Controller PAK" : "None";
|
||||
case SAVE_TYPE_EEPROM_4KBIT: return supports_cpak ? "EEPROM 4kbit | Controller PAK" : "EEPROM 4kbit";
|
||||
case SAVE_TYPE_EEPROM_16KBIT: return supports_cpak ? "EEPROM 16kbit | Controller PAK" : "EEPROM 16kbit";
|
||||
case SAVE_TYPE_SRAM_256KBIT: return supports_cpak ? "SRAM 256kbit | Controller PAK" : "SRAM 256kbit";
|
||||
case SAVE_TYPE_SRAM_BANKED: return supports_cpak ? "SRAM 768kbit / 3 banks | Controller PAK" : "SRAM 768kbit / 3 banks";
|
||||
case SAVE_TYPE_SRAM_1MBIT: return supports_cpak ? "SRAM 1Mbit | Controller PAK" : "SRAM 1Mbit";
|
||||
case SAVE_TYPE_FLASHRAM_1MBIT: return supports_cpak ? "FlashRAM 1Mbit | Controller PAK" : "FlashRAM 1Mbit";
|
||||
case SAVE_TYPE_FLASHRAM_PKST2: return supports_cpak ? "FlashRAM (Pokemon Stadium 2) | Controller PAK" : "FlashRAM (Pokemon Stadium 2)";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
@ -164,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 = {
|
||||
{ .text = "Automatic", .action = set_save_type, .arg = (void *) (SAVE_TYPE_AUTOMATIC) },
|
||||
{ .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 16kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_16K) },
|
||||
{ .text = "SRAM 256kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM) },
|
||||
{ .text = "SRAM 768kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_BANKED) },
|
||||
{ .text = "SRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_128K) },
|
||||
{ .text = "FlashRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_FLASHRAM) },
|
||||
{ .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_16KBIT) },
|
||||
{ .text = "SRAM 256kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_256KBIT) },
|
||||
{ .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_1MBIT) },
|
||||
{ .text = "FlashRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_FLASHRAM_1MBIT) },
|
||||
COMPONENT_CONTEXT_MENU_LIST_END,
|
||||
}};
|
||||
|
||||
@ -197,8 +199,17 @@ static void process (menu_t *menu) {
|
||||
load_pending = true;
|
||||
} else if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (menu->actions.options) {
|
||||
component_context_menu_show(&options_context_menu);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,22 +237,48 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Description:\n None.\n\n\n\n\n\n\n\n"
|
||||
"Expansion PAK: %s\n"
|
||||
"TV type: %s\n"
|
||||
"CIC: %s\n"
|
||||
"GS/AR Cheats: Off\n"
|
||||
"Patches: Off\n"
|
||||
"Save type: %s\n",
|
||||
format_rom_expansion_pak_info(menu->load.rom_info.features.expansion_pak),
|
||||
format_rom_tv_type(rom_info_get_tv_type(&menu->load.rom_info)),
|
||||
format_cic_type(rom_info_get_cic_type(&menu->load.rom_info)),
|
||||
format_rom_save_type(rom_info_get_save_type(&menu->load.rom_info), menu->load.rom_info.features.controller_pak)
|
||||
);
|
||||
|
||||
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"
|
||||
" Destination market: %s\n"
|
||||
"Variant: %s\n"
|
||||
"Version: %hhu\n"
|
||||
"Check code: 0x%016llX\n"
|
||||
" Save type: %s\n"
|
||||
" TV type: %s\n"
|
||||
" Expansion PAK: %s\n"
|
||||
"\n"
|
||||
" Extra information:\n"
|
||||
" CIC: %s\n"
|
||||
"Boot address: 0x%08lX\n"
|
||||
"SDK version: %.1f%c\n"
|
||||
" Clock Rate: %.2fMHz\n",
|
||||
"Clock Rate: %.2fMHz\n\n\n"
|
||||
"Press L|Z to return.\n",
|
||||
format_rom_endianness(menu->load.rom_info.endianness),
|
||||
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],
|
||||
@ -249,28 +286,11 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
format_rom_destination_market(menu->load.rom_info.destination_code),
|
||||
menu->load.rom_info.version,
|
||||
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.libultra.version / 10.0f), menu->load.rom_info.libultra.revision,
|
||||
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);
|
||||
}
|
||||
|
@ -42,11 +42,13 @@ static void process (menu_t *menu) {
|
||||
menu_show_error(menu, convert_error_message(err));
|
||||
} else if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (menu->actions.enter) {
|
||||
err = mp3player_toggle();
|
||||
if (err != MP3PLAYER_OK) {
|
||||
menu_show_error(menu, convert_error_message(err));
|
||||
}
|
||||
sound_play_effect(SFX_ENTER);
|
||||
} else if (menu->actions.go_left || menu->actions.go_right) {
|
||||
int seconds = menu->actions.go_fast ? SEEK_SECONDS_FAST : SEEK_SECONDS;
|
||||
err = mp3player_seek(menu->actions.go_left ? (-seconds) : seconds);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <time.h>
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
// FIXME: add implementation!
|
||||
@ -18,6 +19,7 @@
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +36,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"\n"
|
||||
"\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",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n"
|
||||
);
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
#include "../sound.h"
|
||||
#include "../settings.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
@ -8,10 +11,111 @@ 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) {
|
||||
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;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,44 +128,54 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"SETTINGS EDITOR\n"
|
||||
"MENU SETTINGS EDITOR\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"\n"
|
||||
"To change the settings, please adjust them\n"
|
||||
"directly in the 'menu/config.ini' file.\n\n"
|
||||
"pal60_enabled: %s\n"
|
||||
"show_protected_entries: %s\n"
|
||||
"default_directory: %s\n"
|
||||
"use_saves_folder: %s\n"
|
||||
"bgm_enabled: %s\n"
|
||||
"sound_enabled: %s\n"
|
||||
"rumble_enabled: %s\n",
|
||||
"\n\n"
|
||||
" Default Directory : %s\n\n"
|
||||
"To change the following menu settings, press 'A':\n"
|
||||
"* PAL60 Mode : %s\n"
|
||||
" Show Hidden Files : %s\n"
|
||||
" Use Saves folder : %s\n"
|
||||
" Sound Effects : %s\n"
|
||||
#ifdef BETA_SETTINGS
|
||||
" Background Music : %s\n"
|
||||
" Rumble Feedback : %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.show_protected_entries),
|
||||
menu->settings.default_directory,
|
||||
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.sound_enabled),
|
||||
format_switch(menu->settings.rumble_enabled)
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"A: Change\n"
|
||||
"B: Back"
|
||||
);
|
||||
|
||||
component_context_menu_draw(&options_context_menu);
|
||||
|
||||
rdpq_detach_show();
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
@ -28,6 +29,7 @@ static void process (menu_t *menu) {
|
||||
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "../components/constants.h"
|
||||
#include "../fonts.h"
|
||||
#include "../sound.h"
|
||||
#include "utils/utils.h"
|
||||
#include "views.h"
|
||||
|
||||
@ -55,6 +56,7 @@ static void perform_vertical_scroll (int lines) {
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
sound_play_effect(SFX_EXIT);
|
||||
} else if (text) {
|
||||
if (menu->actions.go_up) {
|
||||
perform_vertical_scroll(menu->actions.go_fast ? -10 : -1);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "fs.h"
|
||||
|
Loading…
Reference in New Issue
Block a user