diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index cda343ad..00000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -*.exe filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.gif filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index e73b4aeb..f8c84217 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,7 @@ build/ *.sa1 *.sa2 undefined.pius +.last_env +.last_buildtype src/data/content diff --git a/.licenses/cult-of-gba-bios.txt b/.licenses/cult-of-gba-bios.txt new file mode 100644 index 00000000..fae47d5e --- /dev/null +++ b/.licenses/cult-of-gba-bios.txt @@ -0,0 +1,7 @@ +Copyright 2020 - 2021 DenSinH and fleroviux + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.licenses/gbfs.txt b/.licenses/gbfs.txt new file mode 100644 index 00000000..645e6834 --- /dev/null +++ b/.licenses/gbfs.txt @@ -0,0 +1,21 @@ +Copyright 2002 Damian Yerrick + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/.vscode/settings.json b/.vscode/settings.json index 6be7ebb6..5a2e2714 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -79,6 +79,8 @@ "audio_store.h": "c", "stdbool.h": "c", "sys.h": "c", - "io_ezfo.h": "c" - } -} + "io_ezfo.h": "c", + "cstring": "cpp" + }, + "makefile.configureOnOpen": false +} \ No newline at end of file diff --git a/Makefile b/Makefile index f441a72e..4d73c057 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,116 @@ .SUFFIXES: # --- Paths --- -export BASE_DIR = $(GBA_DIR)\projects\piugba +export WORKDIR = $(PWD) +export DEVKITARM = $(DEVKITPRO)/devkitARM +export COMPILED_SPRITES_DIR := $(WORKDIR)/src/data/content/_compiled_sprites +LAST_ENV_FILE := $(WORKDIR)/.last_env +LAST_BUILDTYPE_FILE := $(WORKDIR)/.last_buildtype + +export LIBTONC := $(DEVKITPRO)/libtonc +export LIBGBA := $(DEVKITPRO)/libgba +export LIBGBA_SPRITE_ENGINE := $(WORKDIR)/libs/libgba-sprite-engine +export LIBUGBA := $(WORKDIR)/libs/libugba + +# === TONC RULES ====================================================== +# +# Yes, this is almost, but not quite, completely like to +# DKP's base_rules and gba_rules +# -export TONCLIB := $(DEVKITPRO)/libtonc -include $(BASE_DIR)/tonc_rules +export PATH := $(DEVKITARM)/bin:$(PATH) + + +# --- Executable names --- + +PREFIX ?= arm-none-eabi- + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AS := $(PREFIX)as +export AR := $(PREFIX)ar +export NM := $(PREFIX)nm +export OBJCOPY := $(PREFIX)objcopy + +# LD defined in Makefile + + +# === LINK / TRANSLATE ================================================ + +%.gba : %.elf + @$(OBJCOPY) -O binary $< $@ + @echo built ... $(notdir $@) + @gbafix $@ -t$(TITLE) + +#---------------------------------------------------------------------- + +%.mb.elf : + @echo Linking multiboot + $(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(NM) -Sn $@ > $(basename $(notdir $@)).map + +#---------------------------------------------------------------------- + +%.elf : + @echo Linking cartridge + $(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(NM) -Sn $@ > $(basename $(notdir $@)).map + +#---------------------------------------------------------------------- + +%.a : + @echo $(notdir $@) + @rm -f $@ + $(AR) -crs $@ $^ + + +# === OBJECTIFY ======================================================= + +%.iwram.o : %.iwram.cpp + @echo $(notdir $<) + $(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@ + +#---------------------------------------------------------------------- +%.iwram.o : %.iwram.c + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.cpp + @echo $(notdir $<) + $(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.c + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.s + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.S + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + + +#---------------------------------------------------------------------- +# canned command sequence for binary data +#---------------------------------------------------------------------- + +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( `(echo $(> `(echo $(> `(echo $( $(LAST_ENV_FILE); \ + $(MAKE) clean; \ + elif [ "$$(cat $(LAST_ENV_FILE))" != "$(ENV)" ]; then \ + echo "Environment changed from $$(cat $(LAST_ENV_FILE)) to $(ENV), running clean..."; \ + echo $(ENV) > $(LAST_ENV_FILE); \ + $(MAKE) clean; \ + fi + @if [ ! -f $(LAST_BUILDTYPE_FILE) ]; then \ + echo "Last build type unknown, running clean..."; \ + echo $(ARCADE) > $(LAST_BUILDTYPE_FILE); \ + $(MAKE) clean; \ + elif [ "$$(cat $(LAST_BUILDTYPE_FILE))" != "$(ARCADE)" ]; then \ + echo "Build type changed from ARCADE=$$(cat $(LAST_BUILDTYPE_FILE)) to ARCADE=$(ARCADE), running clean..."; \ + echo $(ARCADE) > $(LAST_BUILDTYPE_FILE); \ + $(MAKE) clean; \ + fi + +install: check-env + ./scripts/importer/install.sh + +check: check-env + ./scripts/toolchain/check.sh assets: check-env ./scripts/assets.sh + touch $(COMPILED_SPRITES_DIR)/assets.stamp + +# build: ... import: check-env - node ./scripts/importer/src/importer.js --mode "$(MODE)" --directory "$(SONGS)" --videolib="$(VIDEOLIB)" --hqaudiolib="$(HQAUDIOLIB)" --boss=$(BOSS) --arcade=$(ARCADE) --fast=$(FAST) --videoenable=$(VIDEOENABLE) --hqaudioenable=$(HQAUDIOENABLE) + ./scripts/importer/run.sh --directory "$(SONGS)" --videolib="$(VIDEOLIB)" --hqaudiolib="$(HQAUDIOLIB)" --boss=$(BOSS) --arcade=$(ARCADE) --fast=$(FAST) --videoenable=$(VIDEOENABLE) --hqaudioenable=$(HQAUDIOENABLE) cd src/data/content/_compiled_files && gbfs ../files.gbfs * -package: check-env $(BUILD) +pkg: ./scripts/package.sh "piugba.gba" "src/data/content/files.gbfs" +package: check-env build pkg + start: check-env package - start "$(TARGET).out.gba" + @if command -v start > /dev/null; then \ + start "$(TARGET).out.gba"; \ + fi rebuild: check-env clean package -restart: check-env rebuild - start "$(TARGET).out.gba" +restart: check-env rebuild start -reimport: check-env import package - start "$(TARGET).out.gba" +reimport: check-env import package start # EOF diff --git a/README.md b/README.md index 7b1f2917..7aeb4264 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ The downloads provided in our [Releases](https://github.com/afska/piugba/release - _If you use the portable importer, these files are not needed!_ - A small demo with 9 songs from [Project Outfox Serenity](https://projectoutfox.com/outfox-serenity)'s Volume I & II sets. -**To play, you need to [build a custom ROM](https://github.com/afska/piugba/wiki/Building-a-ROM) or download a complete one from [our Discord](https://discord.com/invite/JE33cc2).** +**To play, you need to [download a ROM from our Discord](https://discord.com/invite/JE33cc2) or [build a custom ROM](https://github.com/afska/piugba/wiki/Building-a-ROM).** ## How does it work? @@ -69,9 +69,64 @@ Charts are converted into a format created for this project called **PIUS**. The **[Wiki: Building a ROM](https://github.com/afska/piugba/wiki/Building-a-ROM)** -## Install +# Developing -### Windows +## Install - Any OS (Docker) + +- If you are on Windows, install [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) +- Install [Docker](https://www.docker.com/) +- Run: +```bash +# download docker image +docker pull afska/piugba-dev + +# compile game assets +./dockermake.sh assets + +# install importer dependencies +./dockermake.sh install + +# run ./dockermake.sh {action} {arguments...} +# for example, to build a clean Arcade ROM, use: +./dockermake.sh build ENV=production ARCADE=true +``` + +## Actions + +### Commands + +- `make install`: Installs the importer dependencies +- `make check`: Verifies that all the tools are installed correctly +- `make clean`: Cleans build artifacts (except assets) +- `make assets`: Compiles the needed assets in `src/data/content/_compiled_sprites` (required for compiling) +- `make build`: Compiles and generates a `.gba` file without data +- `make import`: Imports the songs from `src/data/content/songs` to a GBFS file +- `make pkg`: Appends the GBFS file to the ROM (`piugba.gba` -> `piugba.out.gba`) +- `make package`: Compiles and appends the GBFS file to the ROM _(build+pkg)_ +- `make start`: Packages and starts the compiled ROM _(package + launch rom)_ +- `make rebuild`: Recompiles a full ROM _(clean+package)_ +- `make restart`: Recompiles and starts the ROM _(rebuild+start)_ +- `make reimport`: Reimports the songs and starts the ROM without recompiling _(import+package+start)_ + +### Parameters + +| Name | Values | Description | +| --------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ENV` | **`development`**, or `debug` or `production` | `debug`: everything is unlocked, backgrounds are disabled, and stage-break is OFF.
`development`: the same thing, but including backgrounds.
`production`: backgrounds, stage-break ON, and working locks.

Non-production versions also have:

1) PIU-style controls by default, and a _debug menu_ to correct songs' offsets. See **[Wiki: Correcting offsets](https://github.com/afska/piugba/wiki/Building-a-ROM#correcting-offsets)**.

2) If _SELECT_ is pressed when a campaign song starts, stage-break will be ON regardless of the environment.

3) Profiling code and some logs. | +| `BOSS` | false or **true** | Automatically adds _boss levels_ to the campaign modes. | +| `ARCADE` | **false** or true | Creates an arcade-only version of the game that only uses numeric levels, without the campaign modes.

Add this parameter to both _import_ and _build_ commands! | +| `SONGS` | _path to a directory_ | Songs directory. Defaults to: `src/data/content/songs` | +| `VIDEOLIB` | _path to a directory_ | Video library output directory. Defaults to: `src/data/content/piuGBA_videos` | +| `VIDEOENABLE` | **false** or true | Enables the conversion of video files (from `${SONGS}/_videos`) to the `VIDEOLIB` folder. | +| `HQAUDIOLIB` | _path to a directory_ | HQ Audio library output directory. Defaults to: `src/data/content/piuGBA_audios` | +| `HQAUDIOENABLE` | **false** or true | Enables the conversion of HQ audio files to the `HQAUDIOLIB` folder. | +| `FAST` | **false** or true | Uses async I/O to import songs faster. It may disrupt stdout order. | + +> In Docker builds, for `SONGS`, `VIDEOLIB` and `HQAUDIOLIB`, only use relative paths to folders inside your project's directory! + +## Install - Windows (Native) + +> Advanced usage only! The code requires specific versions of tools that are difficult to obtain, and I cannot provide them. I created the Docker image so everyone can have the same environment. - Choose a folder (from now, `GBA_DIR`) and use this file structure: - `gba` @@ -81,17 +136,17 @@ Charts are converted into a format created for this project called **PIUS**. The - `piugba` - Install the toolchain: - Dev - - devkitPro&gcc 9.1.0: The devkit for compiling GBA ROMs. It comes with: + - **devkitPro** `r53` (with gcc `9.1.0`): The devkit for compiling GBA ROMs. It comes with: - _grit_: Used to convert paletted bitmaps to C arrays or raw binary files - _gbfs_: Used to create a package with all the game assets - - [node.js 14.\*](https://nodejs.org/en): The JS runtime - - [make 3.81](scripts/toolchain/programs/make-3.81.zip): The build automation tool + - ⚠️ While newer versions of gcc may work, they might require some tweaks. I've noticed that with gcc 14 the code runs 5% slower and have worse compatibility with some emulators, so I prefer to stick with gcc 9. + - **node** `14.*`: The JS runtime + - **make** `3.81` (compiled for `i386-pc-mingw32`): The build automation tool - Media Processing - - [ImageMagick 7.0.10.3](scripts/toolchain/programs/ImageMagick-7.0.10-3-Q16-x64-static.exe): The tool used to convert images to paletted bitmaps - - [ffmpeg _(with libgsm)_ 3.3.3](scripts/toolchain/programs/ffmpeg-3.3.3-win64-static.zip): The tool used to convert audio files to GSM - - To avoid using the `ffmpeg.exe` binary included with _ImageMagick_, add it to `PATH` first! - - Check this by running `where ffmpeg` - - [pngfix](scripts/toolchain/programs/pngfix.exe): A small command line util to fix corrupted PNG files + - **ImageMagick** `7.0.10.3`: The tool used to convert images to paletted bitmaps + - **ffmpeg** `3.3.3` (bundled with `libgsm`): The tool used to convert audio files to GSM + - ⚠️ Avoid using the `ffmpeg.exe` binary included with _ImageMagick_ or any other version. After `3.3.3`, they stopped including `libgsm` on Windows builds. + - **png-fix-IDAT-windowsize** `0.5`: A small command line util to fix corrupted PNG files - Other - [Git Bash](https://gitforwindows.org): Linux shell and tools. It contains required commands like `dd` or `md5sum` - [VSCode](https://code.visualstudio.com): The IDE @@ -116,66 +171,37 @@ export PATH="$PATH:$GBA_DIR/tools/devkitPro/devkitARM/bin" export PATH="$PATH:$GBA_DIR/tools/devkitPro/tools/bin" ``` -- You can check if the tools are installed correctly by running `./scripts/toolchain/check.sh` +- You can check if the tools are installed correctly by running `make check` -### VSCode +## VSCode - Recommended plugins: `C/C++ Extensions`, `EditorConfig`, `Prettier - Code formatter` - Recommended settings: [here](scripts/toolchain/vscode_settings.json) -## Actions - -### Commands - -- `make clean`: Cleans build artifacts -- `make assets`: Compiles the needed assets in `src/data/content/_compiled_sprites` (required for compiling) -- `make build`: Compiles and generates a `.gba` file without data -- `make import`: Imports the songs from `src/data/content/songs` to a GBFS file -- `make package`: Compiles and appends the GBFS file to the ROM -- `make start`: Starts the compiled ROM -- `make rebuild`: Recompiles (clean+build+package) a full ROM -- `make restart`: Recompiles and starts the ROM -- `make reimport`: Reimports the songs and starts the ROM without recompiling - -#### Parameters - -| Name | Values | Description | -| --------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `MODE` | **`auto`** or `manual` | When using `auto`, the import process tries to guess the missing data (e.g. difficulty levels). See **[Wiki: Autoimporting songs](https://github.com/afska/piugba/wiki/Autoimporting-songs)**. | -| `ENV` | **`development`**, or `debug` or `production` | `debug`: everything is unlocked, backgrounds are disabled, and stage-break is OFF.
`development`: the same thing, but including backgrounds.
`production`: backgrounds, stage-break ON, and working locks.

Non-production versions also have:

1) PIU-style controls by default, and a _debug menu_ to correct songs' offsets. See **[Wiki: Correcting offsets](https://github.com/afska/piugba/wiki/Building-a-ROM#correcting-offsets)**.

2) If _SELECT_ is pressed when a campaign song starts, stage-break will be ON regardless of the environment. | -| `BOSS` | false or **true** | Automatically adds _boss levels_ to the campaign modes. | -| `ARCADE` | **false** or true | Creates an arcade-only version of the game that only uses numeric levels, without the campaign modes.

Add this parameter to both _import_ and _build_ commands! | -| `SONGS` | _path to a directory_ | Songs directory. Defaults to: `src/data/content/songs` | -| `VIDEOLIB` | _path to a directory_ | Video library output directory. Defaults to: `src/data/content/piuGBA_videos` | -| `VIDEOENABLE` | **false** or true | Enables the conversion of video files (from `${SONGS}/_videos`) to the `VIDEOLIB` folder. | -| `HQAUDIOLIB` | _path to a directory_ | HQ Audio library output directory. Defaults to: `src/data/content/piuGBA_audios` | -| `HQAUDIOENABLE` | **false** or true | Enables the conversion of HQ audio files to the `HQAUDIOLIB` folder. | -| `FAST` | **false** or true | Uses async I/O to import songs faster. It may disrupt stdout order. | - -### Scripts +## Scripts -#### Build sprites +### Build sprites ```bash # use #FF00FD as transparency color grit *.bmp -ftc -pS -gB8 -gT ff00fd -O shared_palette.c ``` -#### Build backgrounds +### Build backgrounds ```bash magick file.png -resize 240x160\! -colors 255 file.bmp grit file.bmp -gt -gB8 -mRtf -mLs -ftb ``` -#### Build music +### Build music ```bash ffmpeg -y -i file.mp3 -ac 1 -af 'aresample=18157' -strict unofficial -c:a gsm file.gsm ffplay -ar 18157 file.gsm ``` -#### Build filesystem +### Build filesystem ```bash gbfs files.gbfs *.pius *.gsm *.bin @@ -183,13 +209,13 @@ gbfs files.gbfs *.pius *.gsm *.bin cat rom.gba files.gbfs > rom.out.gba ``` -#### Build gba-sprite-engine +### Build gba-sprite-engine ```bash rm -rf cmake-build-debug ; mkdir cmake-build-debug ; cd cmake-build-debug ; cmake ../ -G "Unix Makefiles" ; make ; cp engine/libgba-sprite-engine.a ../../piugba/libs/libgba-sprite-engine/lib/libgba-sprite-engine.a ; cd ../ ; rm -rf ../piugba/libs/libgba-sprite-engine/include/ ; cp -r ./engine/include ../piugba/libs/libgba-sprite-engine/ ``` -#### Build importer.exe +### Build importer.exe ```bash cd scripts/importer @@ -197,24 +223,26 @@ npm install -g pkg pkg --targets node14-win --config package.json -o importer.exe --public --public-packages "*" --no-bytecode --compress GZip src/importer.js ``` -### Troubleshooting +## Troubleshooting -#### How to debug +### How to debug - In `Makefile`, replace `-Ofast` by `-Og -g` to include debug symbols in the `.elf` file - In mGBA, go to Tools -> Start GDB server... - Start debugging in VS Code -#### Undefined reference to _function name_ +### Undefined reference to _function name_ If you've added new folders, ensure they're in `Makefile`'s `SRCDIRS` list! ## Open-source projects involved -- [wgroeneveld/gba-sprite-engine](https://github.com/wgroeneveld/gba-sprite-engine): Dec 18, 2019 +- Sprite engine by [wgroeneveld/gba-sprite-engine](https://github.com/wgroeneveld/gba-sprite-engine): Dec 18, 2019 - Forked at: [afska/gba-sprite-engine](https://github.com/afska/gba-sprite-engine) -- [pinobatch/gsmplayer-gba](https://github.com/pinobatch/gsmplayer-gba): Feb 9, 2020 -- [AntonioND/libugba](https://github.com/AntonioND/libugba): May 20, 2022 -- [afska/gba-link-connection](https://github.com/afska/gba-link-connection): v6.0.3 -- [afska/gba-flashcartio](https://github.com/afska/gba-flashcartio): v1.0.5 -- [FatFS](http://elm-chan.org/fsw/ff/): R0.15 +- GBA hardware access by [tonclib](https://github.com/gbadev-org/libtonc) +- GSM playback by [pinobatch/gsmplayer-gba](https://github.com/pinobatch/gsmplayer-gba): Feb 9, 2020 +- Interrupt handler by [AntonioND/libugba](https://github.com/AntonioND/libugba): Nov 14, 2022 +- LZ77 decompression by [Cult-of-GBA/BIOS](https://github.com/Cult-of-GBA/BIOS): Sep 11, 2024 +- Multiplayer support by [afska/gba-link-connection](https://github.com/afska/gba-link-connection): v7.0.1 +- microSD reading by [afska/gba-flashcartio](https://github.com/afska/gba-flashcartio): v1.0.5 + fixes +- FAT parsing by [FatFS](http://elm-chan.org/fsw/ff/): R0.15 diff --git a/dockermake.sh b/dockermake.sh new file mode 100755 index 00000000..e46b65cb --- /dev/null +++ b/dockermake.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e + +if [ "$#" -lt 1 ]; then + echo "Usage: $0 [make-arguments...]" + exit 1 +fi + +cleanup() { + docker kill "$container_id" + docker rm "$container_id" + exit 130 +} + +trap cleanup SIGINT + +container_id=$(docker run -it -d \ + -v "$(pwd)":/opt/piugba \ + -e PWD=/opt/piugba \ + afska/piugba-dev \ + make "$@") + +docker logs -f "$container_id" +status_code=$(docker wait "$container_id") +docker rm "$container_id" + +exit "$status_code" diff --git a/libs/interrupt.cpp b/libs/interrupt.cpp index ab575d9b..57f3797e 100644 --- a/libs/interrupt.cpp +++ b/libs/interrupt.cpp @@ -1,5 +1,5 @@ #include "interrupt.h" -#include +#include void interrupt_init(void) { IRQ_Init(); @@ -19,4 +19,4 @@ void interrupt_disable(interrupt_index index) { void interrupt_set_reference_vcount(unsigned long y) { IRQ_SetReferenceVCOUNT(y); -} \ No newline at end of file +} diff --git a/libs/interrupt.h b/libs/interrupt.h index 47c5b273..19748649 100644 --- a/libs/interrupt.h +++ b/libs/interrupt.h @@ -27,4 +27,4 @@ void interrupt_enable(interrupt_index index); void interrupt_disable(interrupt_index index); void interrupt_set_reference_vcount(unsigned long y); -#endif // INTERRUPT_H \ No newline at end of file +#endif // INTERRUPT_H diff --git a/libs/libgba-sprite-engine/include/libgba-sprite-engine/3rd_party/cult-of-gba-bios/lz77.h b/libs/libgba-sprite-engine/include/libgba-sprite-engine/3rd_party/cult-of-gba-bios/lz77.h new file mode 100644 index 00000000..6c669904 --- /dev/null +++ b/libs/libgba-sprite-engine/include/libgba-sprite-engine/3rd_party/cult-of-gba-bios/lz77.h @@ -0,0 +1,18 @@ +#ifndef CULT_OF_GBA_BIOS_H +#define CULT_OF_GBA_BIOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void swi_LZ77UnCompWrite8bit(const void* src, void* dst) + __attribute__((section(".iwram"), long_call)); + +void swi_LZ77UnCompWrite16bit(const void* src, void* dst) + __attribute__((section(".iwram"), long_call)); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/background.h b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/background.h index c7f0e3a6..51e3b0d5 100644 --- a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/background.h +++ b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/background.h @@ -19,8 +19,9 @@ class Background { int mapSize, int screenBlockIndex, int charBlockIndex, - int mapLayout) - : Background(bgIndex, data, size, map, mapSize) { + int mapLayout, + bool lz77) + : Background(bgIndex, data, size, map, mapSize, lz77) { this->screenBlockIndex = screenBlockIndex; this->charBlockIndex = charBlockIndex; this->mapLayout = mapLayout; @@ -30,7 +31,8 @@ class Background { const void* data, int size, const void* map, - int mapSize) + int mapSize, + bool lz77 = false) : data(data), bgIndex(bgIndex), size(size), @@ -39,7 +41,8 @@ class Background { screenBlockIndex(0), charBlockIndex(bgIndex), priority(bgIndex), - mapSize(mapSize) {} + mapSize(mapSize), + lz77(lz77) {} const int getScreenBlock() { return screenBlockIndex; } const int getCharBlock() { return charBlockIndex; } @@ -69,6 +72,7 @@ class Background { int mapSize, mapLayout; int screenBlockIndex, charBlockIndex, priority; bool mosaicEnabled = false; + bool lz77 = false; int scrollX = 0; int scrollY = 0; diff --git a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text.h b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text.h index 24a194e9..f943ac42 100644 --- a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text.h +++ b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text.h @@ -7,520 +7,297 @@ #define text_background_height 24 #define text_bg_palette_default_color 0x7fff +#define text_bg_palette_default_subcolor 0x20c7 -const unsigned char text_data[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +const unsigned int text_data[1536] __attribute__((aligned(4))) +__attribute__((visibility("hidden"))) = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFE000000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFFFFFE00, 0x00FEFFFF, 0xFFFFFE00, 0x00FEFFFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0xFFFE0000, 0x0000FEFF, + 0xFE000000, 0x000000FE, 0x00FE0000, 0x0000FE00, 0xFEFFFE00, 0x00FEFFFE, + 0xFEFEFFFE, 0x0000FEFF, 0xFEFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x00FEFFFF, + 0x00FEFE00, 0x0000FEFE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFE00, 0x00000000, + 0x00FEFFFE, 0x00000000, 0x0000FE00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + + 0x00000000, 0x000000FE, 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFFFE0000, 0x000000FE, 0xFFFE0000, 0x000000FE, 0xFFFE0000, 0x000000FE, + 0xFE000000, 0x0000FEFF, 0x00000000, 0x000000FE, 0xFE000000, 0x00000000, + 0xFFFE0000, 0x000000FE, 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFE000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FE00, 0x0000FE00, + 0x00FEFFFE, 0x00FEFFFE, 0xFEFFFE00, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFEFFFE00, 0x0000FEFF, 0x00FEFFFE, 0x00FEFFFE, 0x0000FE00, 0x0000FE00, + 0x00000000, 0x00000000, 0x00000000, 0x000000FE, 0xFE000000, 0x0000FEFF, + 0xFEFE0000, 0x00FEFEFF, 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0x00FEFEFF, + 0xFE000000, 0x0000FEFF, 0x00000000, 0x000000FE, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFE00, 0x00000000, + 0x00FEFFFE, 0x00000000, 0x0000FE00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFEFEFE00, 0x00FEFEFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FEFE00, 0x00000000, + 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, + 0x00000000, 0x0000FE00, 0x00000000, 0x00FEFFFE, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, 0xFFFE0000, 0x000000FE, + 0xFEFFFE00, 0x00000000, 0x00FE0000, 0x00000000, + + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, 0x00000000, 0x00000000, + 0xFEFE0000, 0x000000FE, 0xFFFFFE00, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFE0000, 0x0000FEFE, 0x00000000, 0x00000000, 0xFEFEFE00, 0x0000FEFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, + 0x00000000, 0x00000000, 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFEFE00, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFEFE00, 0xFEFFFFFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + + 0x00000000, 0x00000000, 0x00FEFE00, 0x0000FE00, 0xFEFFFFFE, 0x00FEFFFE, + 0xFEFFFFFE, 0x00FEFFFE, 0xFEFFFFFE, 0x00FEFFFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFEFEFE00, 0x00FEFFFE, 0x00000000, 0x0000FE00, 0x00000000, 0x00000000, + 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFEFE00, 0x0000FEFE, 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + 0x00000000, 0x00000000, 0xFEFEFE00, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFEFEFE00, 0xFEFFFFFE, 0xFE000000, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFFFE00, 0x000000FE, 0xFEFE0000, 0x00000000, + + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, 0x00000000, 0x00000000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFE0000, 0x0000FEFE, 0xFE000000, 0x000000FE, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0x00000000, 0x00000000, + 0x00000000, 0x0000FEFE, 0xFE000000, 0x00FEFFFF, 0xFE000000, 0x00FEFFFF, + 0x00000000, 0x0000FEFE, 0xFE000000, 0x00FEFFFF, 0x00000000, 0x00FEFFFE, + 0xFE000000, 0x0000FEFF, 0x00000000, 0x000000FE, + + 0x00000000, 0x00000000, 0x00000000, 0x0000FEFE, 0xFE000000, 0x00FEFFFF, + 0xFFFE0000, 0x0000FEFE, 0xFEFFFE00, 0x00000000, 0xFFFE0000, 0x0000FEFE, + 0xFE000000, 0x00FEFFFF, 0x00000000, 0x0000FEFE, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFEFE0000, 0x00000000, + 0xFFFFFE00, 0x000000FE, 0xFEFE0000, 0x0000FEFF, 0x00000000, 0x00FEFFFE, + 0xFEFE0000, 0x0000FEFF, 0xFFFFFE00, 0x000000FE, 0xFEFE0000, 0x00000000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFEFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0x00FEFE00, 0x00FEFE00, 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + + 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, 0xFEFEFE00, 0x00FEFEFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0x0000FEFE, 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFEFEFE00, 0x00FEFEFE, 0xFEFEFE00, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, + 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0x00FEFEFE, 0xFEFFFFFE, 0xFEFFFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0x00FEFEFE, + + 0x00FEFE00, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, 0xFE000000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFE000000, 0x000000FE, 0x00000000, 0x00FEFE00, 0x00000000, 0xFEFFFFFE, + 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + 0x00FEFE00, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFFFF, + 0xFFFFFFFE, 0x0000FEFF, 0xFFFFFFFE, 0x0000FEFF, 0xFEFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, + + 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, + 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00FEFEFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, 0x0000FE00, 0x00FEFE00, + 0x00FEFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFF, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFFFEFFFE, 0xFEFFFFFE, 0xFEFEFFFE, 0xFEFFFFFE, 0x00FEFFFE, 0xFEFFFFFE, + 0x0000FE00, 0x00FEFE00, 0x00FEFE00, 0x00FE0000, 0xFEFFFFFE, 0xFEFFFE00, + 0xFFFFFFFE, 0xFEFFFEFE, 0xFFFFFFFE, 0xFEFFFEFF, 0xFEFFFFFE, 0xFEFFFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFE00, 0x00FEFE00, 0x00FE0000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + + 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, + 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, 0xFEFE0000, 0x000000FE, + 0xFFFFFE00, 0x0000FEFF, 0xFEFFFFFE, 0x00FEFFFE, 0xFFFFFFFE, 0x00FEFFFE, + 0xFEFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x00FEFFFE, 0xFFFFFE00, 0xFEFFFEFF, + 0xFEFE0000, 0x00FE00FE, 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFFFFFE00, 0xFEFFFFFF, 0xFEFEFE00, 0xFEFFFFFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + + 0xFEFEFE00, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, 0xFFFEFE00, 0x00FEFEFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0x00FEFE00, 0x00FEFE00, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFE0000, 0x0000FEFE, 0x00FEFE00, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFE00, 0x00FEFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, + 0x00FEFE00, 0x00FE00FE, 0xFEFFFFFE, 0xFEFFFEFF, 0xFEFFFFFE, 0xFEFFFEFF, + 0xFEFFFFFE, 0xFEFFFEFF, 0xFEFFFFFE, 0xFEFFFEFF, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFFFFFE00, 0x00FEFFFE, 0xFEFE0000, 0x0000FE00, + + 0x00FEFE00, 0x00FE0000, 0xFEFFFFFE, 0xFEFFFE00, 0xFFFFFE00, 0xFEFFFFFE, + 0xFFFE0000, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, 0x00FEFE00, 0x00FEFE00, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFE000000, 0x000000FE, 0xFEFEFE00, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFEFEFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFFFFFE00, 0x000000FE, + 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, + 0xFE000000, 0x000000FE, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFFFE0000, 0x000000FE, 0xFFFE0000, 0x000000FE, 0xFFFE0000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, + + 0x00FEFE00, 0x0000FE00, 0xFEFFFFFE, 0x00FEFFFE, 0xFEFFFFFE, 0x0000FEFF, + 0xFEFEFE00, 0x0000FEFF, 0xFFFE0000, 0x00FEFEFE, 0xFFFE0000, 0xFEFFFFFE, + 0xFEFFFE00, 0xFEFFFFFE, 0x00FE0000, 0x00FEFE00, 0xFE000000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFE000000, 0x000000FE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFEFEFE00, 0x00FEFEFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, + + 0x00FE0000, 0x00000000, 0xFEFFFE00, 0x00000000, 0x00FEFFFE, 0x00000000, + 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x00FEFFFF, 0xFFFFFE00, 0xFEFFFFFF, + 0xFEFE0000, 0x00FEFEFE, 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00000000, + 0xFEFFFFFE, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + + 0x00000000, 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0xFEFE0000, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0x00FEFEFE, 0x00000000, 0x00000000, + 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFFFFFE, 0x00FEFEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFE0000, 0x0000FEFE, 0xFE000000, 0x0000FEFE, 0xFFFE0000, 0x00FEFFFF, + 0xFFFFFE00, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFFFFFE00, 0x0000FEFE, 0xFFFFFE00, 0x000000FE, 0xFEFE0000, 0x00000000, + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + + 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x0000FEFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, 0xFE000000, 0x000000FE, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFE000000, 0x000000FE, 0x00000000, 0x00FEFE00, 0x00000000, 0xFEFFFFFE, + 0x00000000, 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + 0x00FEFE00, 0x00000000, 0xFEFFFFFE, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0x00FEFFFF, 0xFFFFFFFE, 0x0000FEFF, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFF, 0x00FEFE00, 0x00FEFEFE, + + 0xFEFE0000, 0x000000FE, 0xFFFFFE00, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0x00000000, 0x00000000, + 0xFE00FE00, 0x0000FE00, 0xFFFEFFFE, 0x00FEFFFE, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFFFEFFFE, 0xFEFFFFFE, 0xFFFEFFFE, 0xFEFFFFFE, 0xFFFEFFFE, 0xFEFFFFFE, + 0xFE00FE00, 0x00FEFE00, 0x00000000, 0x00000000, 0xFEFEFE00, 0x0000FEFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0x00FEFE00, 0x00FEFE00, + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFEFE0000, 0x0000FEFE, + + 0x00000000, 0x00000000, 0xFEFEFE00, 0x0000FEFE, 0xFFFFFFFE, 0x00FEFFFF, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFFFE, 0x00FEFFFF, 0xFEFFFFFE, 0x0000FEFE, + 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, 0x00000000, 0x00000000, + 0xFEFE0000, 0x00FEFEFE, 0xFFFFFE00, 0xFEFFFFFF, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFEFE0000, 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, + 0x00000000, 0x00FEFE00, 0x00000000, 0x00000000, 0x00FEFE00, 0x00FEFEFE, + 0xFEFFFFFE, 0xFEFFFFFF, 0xFFFFFFFE, 0x00FEFEFF, 0xFFFFFFFE, 0x000000FE, + 0xFEFFFFFE, 0x00000000, 0xFEFFFFFE, 0x00000000, 0x00FEFE00, 0x00000000, + 0x00000000, 0x00000000, 0xFEFE0000, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, + 0xFEFFFFFE, 0x0000FEFE, 0xFFFFFE00, 0x00FEFFFF, 0xFEFEFE00, 0xFEFFFFFE, + 0xFFFFFFFE, 0x00FEFFFF, 0xFEFEFE00, 0x0000FEFE, + + 0x00000000, 0x00000000, 0xFE000000, 0x000000FE, 0xFFFEFE00, 0x00FEFEFF, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFFFEFE00, 0x00FEFEFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, 0x00000000, 0x00000000, + 0x00FEFE00, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFFFFFE00, 0xFEFFFFFF, + 0xFEFE0000, 0x00FEFEFE, 0x00000000, 0x00000000, 0x00FEFE00, 0x00FEFE00, + 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFE00, 0x00FEFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFE000000, 0x000000FE, + 0x00000000, 0x00000000, 0x00FEFE00, 0x00FE00FE, 0xFEFFFFFE, 0xFEFFFEFF, + 0xFEFFFFFE, 0xFEFFFEFF, 0xFEFFFFFE, 0xFEFFFEFF, 0xFFFFFFFE, 0xFEFFFFFF, + 0xFFFFFE00, 0x00FEFFFE, 0xFEFE0000, 0x0000FE00, + + 0x00000000, 0x00000000, 0xFEFEFE00, 0x00FEFE00, 0xFFFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, 0xFFFFFE00, 0x00FEFFFF, + 0xFFFFFFFE, 0xFEFFFFFE, 0xFEFEFE00, 0x00FEFE00, 0x00000000, 0x00000000, + 0x00FEFE00, 0x00FEFE00, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, 0xFEFFFFFE, + 0xFFFFFE00, 0xFEFFFFFF, 0xFFFEFE00, 0x00FEFFFF, 0xFFFFFFFE, 0x0000FEFF, + 0xFEFEFE00, 0x000000FE, 0x00000000, 0x00000000, 0xFEFEFE00, 0x00FEFEFE, + 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFFFF, 0xFFFE0000, 0x0000FEFF, + 0xFFFFFE00, 0x00FEFEFE, 0xFFFFFFFE, 0xFEFFFFFF, 0xFEFEFE00, 0x00FEFEFE, + 0x00000000, 0x000000FE, 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFFFE0000, 0x000000FE, 0xFFFFFE00, 0x000000FE, 0xFFFE0000, 0x000000FE, + 0xFE000000, 0x0000FEFF, 0x00000000, 0x000000FE, + + 0x00000000, 0x000000FE, 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x0000FEFF, 0x00000000, 0x000000FE, 0xFE000000, 0x00000000, + 0xFFFE0000, 0x000000FE, 0xFE000000, 0x0000FEFF, 0xFE000000, 0x0000FEFF, + 0xFE000000, 0x00FEFFFF, 0xFE000000, 0x0000FEFF, 0xFFFE0000, 0x000000FE, + 0xFE000000, 0x00000000, 0xFEFE0000, 0x00000000, 0xFFFFFE00, 0x000000FE, + 0xFFFFFE00, 0x000000FE, 0xFFFE0000, 0x000000FE, 0xFEFFFE00, 0x00000000, + 0x00FE0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; #endif // GBA_SPRITE_ENGINE_TEXT_H diff --git a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text_stream.h b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text_stream.h index 48a67d37..1e908bcd 100644 --- a/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text_stream.h +++ b/libs/libgba-sprite-engine/include/libgba-sprite-engine/background/text_stream.h @@ -26,6 +26,7 @@ class TextStream : public Background { void setText(const char* text, int row, int col); void setFontColor(COLOR color); + void setFontSubcolor(COLOR color); void setFontStyle(const void* data, int size); static TextStream& instance(); diff --git a/libs/libgba-sprite-engine/lib/libgba-sprite-engine.a b/libs/libgba-sprite-engine/lib/libgba-sprite-engine.a index 778dd647..1c51cdda 100644 Binary files a/libs/libgba-sprite-engine/lib/libgba-sprite-engine.a and b/libs/libgba-sprite-engine/lib/libgba-sprite-engine.a differ diff --git a/libs/libugba/include/background.h b/libs/libugba/include/ugba/background.h similarity index 100% rename from libs/libugba/include/background.h rename to libs/libugba/include/ugba/background.h diff --git a/libs/libugba/include/bios.h b/libs/libugba/include/ugba/bios.h similarity index 100% rename from libs/libugba/include/bios.h rename to libs/libugba/include/ugba/bios.h diff --git a/libs/libugba/include/bios_wrappers.h b/libs/libugba/include/ugba/bios_wrappers.h similarity index 100% rename from libs/libugba/include/bios_wrappers.h rename to libs/libugba/include/ugba/bios_wrappers.h diff --git a/libs/libugba/include/console.h b/libs/libugba/include/ugba/console.h similarity index 100% rename from libs/libugba/include/console.h rename to libs/libugba/include/ugba/console.h diff --git a/libs/libugba/include/debug.h b/libs/libugba/include/ugba/debug.h similarity index 100% rename from libs/libugba/include/debug.h rename to libs/libugba/include/ugba/debug.h diff --git a/libs/libugba/include/definitions.h b/libs/libugba/include/ugba/definitions.h similarity index 97% rename from libs/libugba/include/definitions.h rename to libs/libugba/include/ugba/definitions.h index dfa1e0c4..ce8111b8 100644 --- a/libs/libugba/include/definitions.h +++ b/libs/libugba/include/ugba/definitions.h @@ -34,6 +34,7 @@ # define EXPORT_API __declspec(dllexport) # else # define EXPORT_API __attribute__((visibility("default"))) +// Is this one below needed in MinGW? //# define EXPORT_API __attribute__((dllexport)) # endif #endif diff --git a/libs/libugba/include/display.h b/libs/libugba/include/ugba/display.h similarity index 100% rename from libs/libugba/include/display.h rename to libs/libugba/include/ugba/display.h diff --git a/libs/libugba/include/dma.h b/libs/libugba/include/ugba/dma.h similarity index 100% rename from libs/libugba/include/dma.h rename to libs/libugba/include/ugba/dma.h diff --git a/libs/libugba/include/fp_math.h b/libs/libugba/include/ugba/fp_math.h similarity index 100% rename from libs/libugba/include/fp_math.h rename to libs/libugba/include/ugba/fp_math.h diff --git a/libs/libugba/include/hardware.h b/libs/libugba/include/ugba/hardware.h similarity index 99% rename from libs/libugba/include/hardware.h rename to libs/libugba/include/ugba/hardware.h index 519bcb83..beffe5cc 100644 --- a/libs/libugba/include/hardware.h +++ b/libs/libugba/include/ugba/hardware.h @@ -529,6 +529,14 @@ EXPORT_API uintptr_t *UGBA_RegDMA3DAD(void); // 3) When starting a timer by writing to: // // REG_TM0CNT_H, REG_TM1CNT_H, REG_TM2CNT_H, REG_TM3CNT_H +// +// 4) When IME or IE have been 0 for some time, IF isn't 0, and IME or IE are +// set to a value that would trigger an interrupt: +// +// REG_IE, REG_IME +// +// Note that writing to IF doesn't work on the SDL2 port. On the GBA, writing +// a 1 to a bit sets it to 0. On the SDL2 port, it sets the bit to 1. #ifdef __GBA__ # define UGBA_RegisterUpdatedOffset(offset) do { (void)(offset); } while (0) diff --git a/libs/libugba/include/input.h b/libs/libugba/include/ugba/input.h similarity index 100% rename from libs/libugba/include/input.h rename to libs/libugba/include/ugba/input.h diff --git a/libs/libugba/include/interrupts.h b/libs/libugba/include/ugba/interrupts.h similarity index 72% rename from libs/libugba/include/interrupts.h rename to libs/libugba/include/ugba/interrupts.h index 3c0d7a9c..57611461 100644 --- a/libs/libugba/include/interrupts.h +++ b/libs/libugba/include/ugba/interrupts.h @@ -6,26 +6,25 @@ #define INTERRUPTS_H__ #include -#include #include "definitions.h" typedef enum { - IRQ_VBLANK = 0, - IRQ_HBLANK = 1, - IRQ_VCOUNT = 2, - IRQ_TIMER0 = 3, - IRQ_TIMER1 = 4, - IRQ_TIMER2 = 5, - IRQ_TIMER3 = 6, - IRQ_SERIAL = 7, - IRQ_DMA0 = 8, - IRQ_DMA1 = 9, - IRQ_DMA2 = 10, - IRQ_DMA3 = 11, - IRQ_KEYPAD = 12, - IRQ_GAMEPAK = 13, - IRQ_NUMBER + IRQ_VBLANK = 0, + IRQ_HBLANK = 1, + IRQ_VCOUNT = 2, + IRQ_TIMER0 = 3, + IRQ_TIMER1 = 4, + IRQ_TIMER2 = 5, + IRQ_TIMER3 = 6, + IRQ_SERIAL = 7, + IRQ_DMA0 = 8, + IRQ_DMA1 = 9, + IRQ_DMA2 = 10, + IRQ_DMA3 = 11, + IRQ_KEYPAD = 12, + IRQ_GAMEPAK = 13, + IRQ_NUMBER } irq_index; typedef void (*irq_vector)(void); @@ -47,4 +46,4 @@ EXPORT_API void IRQ_Disable(irq_index index); // Set the reference VCOUNT that triggers the VCOUNT interrupt. EXPORT_API void IRQ_SetReferenceVCOUNT(uint32_t y); -#endif // INTERRUPTS_H__ +#endif // INTERRUPTS_H__ diff --git a/libs/libugba/include/obj.h b/libs/libugba/include/ugba/obj.h similarity index 100% rename from libs/libugba/include/obj.h rename to libs/libugba/include/ugba/obj.h diff --git a/libs/libugba/include/sound.h b/libs/libugba/include/ugba/sound.h similarity index 100% rename from libs/libugba/include/sound.h rename to libs/libugba/include/ugba/sound.h diff --git a/libs/libugba/include/sram.h b/libs/libugba/include/ugba/sram.h similarity index 100% rename from libs/libugba/include/sram.h rename to libs/libugba/include/ugba/sram.h diff --git a/libs/libugba/include/timer.h b/libs/libugba/include/ugba/timer.h similarity index 100% rename from libs/libugba/include/timer.h rename to libs/libugba/include/ugba/timer.h diff --git a/libs/libugba/include/ugba.h b/libs/libugba/include/ugba/ugba.h similarity index 87% rename from libs/libugba/include/ugba.h rename to libs/libugba/include/ugba/ugba.h index 8c869419..aeba47a1 100644 --- a/libs/libugba/include/ugba.h +++ b/libs/libugba/include/ugba/ugba.h @@ -13,10 +13,10 @@ extern "C" { #include "bios.h" #include "bios_wrappers.h" #include "console.h" +#include "dma.h" +#include "display.h" #include "debug.h" #include "definitions.h" -#include "display.h" -#include "dma.h" #include "fp_math.h" #include "hardware.h" #include "input.h" @@ -25,16 +25,17 @@ extern "C" { #include "sound.h" #include "sram.h" #include "timer.h" +#include "version.h" #include "vram.h" // Initialize library. This function needs to be called at the start of main(). -EXPORT_API void UGBA_Init(int* argc, char** argv[]); +EXPORT_API void UGBA_Init(int *argc, char **argv[]); #ifndef __GBA__ // Initialize library with no video output (for testing). This function needs to // be called at the start of main(). Not implemented in GBA as it isn't usedul // there. -EXPORT_API void UGBA_InitHeadless(int* argc, char** argv[]); +EXPORT_API void UGBA_InitHeadless(int *argc, char **argv[]); #endif // This function tries to detect specific flashcarts with special needs and @@ -46,4 +47,4 @@ EXPORT_API uint16_t UGBA_FlashcartOptimizedWaitstates(void); } #endif -#endif // UGBA_H__ +#endif // UGBA_H__ diff --git a/libs/libugba/include/version.h b/libs/libugba/include/ugba/version.h similarity index 92% rename from libs/libugba/include/version.h rename to libs/libugba/include/ugba/version.h index c90e1987..525b0304 100644 --- a/libs/libugba/include/version.h +++ b/libs/libugba/include/ugba/version.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // -// Copyright (c) 2020 Antonio Niño Díaz +// Copyright (c) 2020-2022 Antonio Niño Díaz #ifndef VERSION_H__ #define VERSION_H__ @@ -10,7 +10,7 @@ // This library follows the Semantic Versioning rules: https://semver.org/ #define LIBUGBA_VERSION_MAJOR (0U) -#define LIBUGBA_VERSION_MINOR (2U) +#define LIBUGBA_VERSION_MINOR (3U) #define LIBUGBA_VERSION_PATCH (0U) #define LIBUGBA_VERSION ((LIBUGBA_VERSION_MAJOR << 16) | \ diff --git a/libs/libugba/include/vram.h b/libs/libugba/include/ugba/vram.h similarity index 100% rename from libs/libugba/include/vram.h rename to libs/libugba/include/ugba/vram.h diff --git a/libs/libugba/lib/libugba.a b/libs/libugba/lib/libugba.a index b0f37933..991c0903 100644 Binary files a/libs/libugba/lib/libugba.a and b/libs/libugba/lib/libugba.a differ diff --git a/scripts/assets.sh b/scripts/assets.sh old mode 100644 new mode 100755 index 60ea9f52..97b02528 --- a/scripts/assets.sh +++ b/scripts/assets.sh @@ -7,7 +7,7 @@ cd "$SOURCE" # [Setup] mkdir -p "$DESTINATION" -rm $DESTINATION/*.h $DESTINATION/*.c +rm $DESTINATION/*.h $DESTINATION/*.c > /dev/null 2>&1 # SongScene grit \ diff --git a/scripts/create_combo_value_lut.js b/scripts/create_combo_value_lut.js deleted file mode 100644 index 398e4814..00000000 --- a/scripts/create_combo_value_lut.js +++ /dev/null @@ -1,13 +0,0 @@ -const _ = require("./importer/node_modules/lodash"); - -const DIGITS = 3; -const MIN_COMBO = 0; -const MAX_COMBO = 999; - -const range = _.range(MIN_COMBO, MAX_COMBO + 1); -const lookUpTable = _.flatMap(range, (it) => { - const [d1, d2, d3] = _.padStart(it, DIGITS, 0); - return [d1, d2, d3].map((it) => parseInt(it)); -}); - -console.log(JSON.stringify(lookUpTable)); diff --git a/scripts/deploy.js b/scripts/deploy.js index 19cc40ae..959d8349 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -2,13 +2,13 @@ const fs = require("fs"); const childProcess = require("child_process"); const $path = require("path"); +// Requires the `flips` command. + const ROOT_DIR = $path.join(__dirname, ".."); -const CONTENT_DIR = $path.join(ROOT_DIR, "src/data/content"); +const CONTENT_DIR = "src/data/content"; const SONG_PACKS_DIR = $path.join(CONTENT_DIR, "songs-pack"); const ROM_PACKS_DIR = $path.join(CONTENT_DIR, "roms"); const DEV_DIR = $path.join(CONTENT_DIR, "roms/#dev"); -const FLIPS_DIR = $path.join(__dirname, "toolchain/programs/flips"); -const FLIPS_TO_CONTENT_PATH = "../../../../src/data/content"; const ROMNAME = "romname.txt"; const ARCADE_SIGNAL = "ARCADE"; const VARIANTS = ["arcade", "full"]; @@ -22,7 +22,19 @@ const OUTPUT_BUILDS = (variant) => ({ const ARCADE_FLAG = (variant) => (variant === "arcade" ? "ARCADE=true" : ""); const SEPARATOR = "----------"; -const SEARCH = process.argv[2]; +const MODE = process.argv[2]; +const SEARCH = process.argv[3]; + +let make; +if (MODE == "docker") make = "bash ./dockermake.sh"; +else if (MODE == "wsl") make = "bash ./wslmake.sh"; +else if (MODE == "native") make = "make"; +else { + console.log("Usage: node deploy.js [search]"); + console.log(": docker | wsl | native"); + console.log("[search]: ROM name"); + process.exit(1); +} const log = (text) => console.log(`${SEPARATOR}${text}${SEPARATOR}`); const run = (command, options) => { @@ -32,16 +44,19 @@ const run = (command, options) => { ...options, }); }; -const getPatches = () => { +const getBaseBranchAndPatches = () => { try { const output = run("git --no-pager branch", { cwd: ROOT_DIR, stdio: null, - }).toString(); - return output - .split("\n") + }).toString().split("\n"); + + const baseBranch = output.find((it) => it.trim().startsWith("* ")).replace("* ", ""); + const patches = output .map((it) => it.trim().replace(/^\* /, "")) .filter((it) => it.startsWith("patch_")); + + return [baseBranch, patches]; } catch (e) { console.error("Failed to get patches", e); process.exit(1); @@ -53,15 +68,15 @@ const getPatches = () => { // ----------- if (!SEARCH) { - const patches = getPatches(); + const [baseBranch, patches] = getBaseBranchAndPatches(); VARIANTS.forEach((variant) => { ENVIRONMENTS.forEach((environment) => { log(`⌚ COMPILING: VARIANT=${variant}, ENV=${environment}`); - run("git checkout master", { cwd: ROOT_DIR }); - run("make clean", { cwd: ROOT_DIR }); - run("make assets", { cwd: ROOT_DIR }); - run(`make build ENV="${environment}" ${ARCADE_FLAG(variant)}`, { + run(`git checkout ${baseBranch}`, { cwd: ROOT_DIR }); + run(`${make} clean`, { cwd: ROOT_DIR }); + run(`${make} assets`, { cwd: ROOT_DIR }); + run(`${make} build ENV="${environment}" ${ARCADE_FLAG(variant)}`, { cwd: ROOT_DIR, }); fs.copyFileSync( @@ -80,16 +95,16 @@ if (!SEARCH) { `⌚ COMPILING: VARIANT=${variant}, ENV=${environment}, PATCH=${patch}` ); run(`git checkout ${patch}`, { cwd: ROOT_DIR }); - run("make clean", { cwd: ROOT_DIR }); - run("make assets", { cwd: ROOT_DIR }); - run(`make build ENV="${environment}" ${ARCADE_FLAG(variant)}`, { + run(`${make} clean`, { cwd: ROOT_DIR }); + run(`${make} assets`, { cwd: ROOT_DIR }); + run(`${make} build ENV="${environment}" ${ARCADE_FLAG(variant)}`, { cwd: ROOT_DIR, }); fs.copyFileSync( $path.join(ROOT_DIR, OUTPUT_EMPTY), $path.join(CONTENT_DIR, outputName) ); - run("git checkout master", { cwd: ROOT_DIR }); + run(`git checkout ${baseBranch}`, { cwd: ROOT_DIR }); }); } }); @@ -108,9 +123,9 @@ if (!SEARCH) { ); run( - `flips.exe --create --ips ${FLIPS_TO_CONTENT_PATH}/${cleanFile} ${FLIPS_TO_CONTENT_PATH}/${patchedFile} ${FLIPS_TO_CONTENT_PATH}/${patch}.${variant}.prod.ips`, + `flips --create --ips ${cleanFile} ${patchedFile} ${patch}.${variant}.prod.ips`, { - cwd: FLIPS_DIR, + cwd: CONTENT_DIR, } ); run(`rm ${patchedFile}`, { cwd: CONTENT_DIR }); @@ -138,7 +153,8 @@ sources.forEach(({ name, path, variant }) => { const shortName = fs.readFileSync($path.join(path, ROMNAME)).toString(); log(`⌚ IMPORTING: ${name} <<${shortName}>>`); - run(`make import SONGS="${path}" ${ARCADE_FLAG(variant)} FAST=true`, { + const unixPath = path.replace(/\\/g, "/"); + run(`${make} import "SONGS=${unixPath}" ${ARCADE_FLAG(variant)} FAST=true`, { cwd: ROOT_DIR, }); @@ -147,7 +163,7 @@ sources.forEach(({ name, path, variant }) => { $path.join(CONTENT_DIR, OUTPUT_BUILDS(variant)[environment]), $path.join(ROOT_DIR, OUTPUT_EMPTY) ); - run("make package", { cwd: ROOT_DIR }); + run(`${make} pkg`, { cwd: ROOT_DIR }); const outputName = `${prefix} piuGBA - ${shortName}.gba`; if (environment === "production") { fs.copyFileSync( diff --git a/scripts/importer/install.sh b/scripts/importer/install.sh new file mode 100755 index 00000000..085df098 --- /dev/null +++ b/scripts/importer/install.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if [ -n "$NVM_DIR" ]; then + source $NVM_DIR/nvm.sh +fi + +cd scripts/importer && npm install diff --git a/scripts/importer/package-lock.json b/scripts/importer/package-lock.json index d8b4c20e..32931bbf 100644 --- a/scripts/importer/package-lock.json +++ b/scripts/importer/package-lock.json @@ -127,11 +127,6 @@ "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz", "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==" }, - "readline-sync": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", - "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==" - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/scripts/importer/package.json b/scripts/importer/package.json index c85543c3..031834ae 100644 --- a/scripts/importer/package.json +++ b/scripts/importer/package.json @@ -18,7 +18,6 @@ "lodash": "^4.17.19", "mkdirp": "^1.0.4", "node-getopt": "^0.3.2", - "readline-sync": "^1.4.10", "tmp": "^0.2.0" } } diff --git a/scripts/importer/run.sh b/scripts/importer/run.sh new file mode 100755 index 00000000..0a13c0c8 --- /dev/null +++ b/scripts/importer/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if [ -n "$NVM_DIR" ]; then + source $NVM_DIR/nvm.sh +fi + +node scripts/importer/src/importer.js "$@" diff --git a/scripts/importer/src/importer.js b/scripts/importer/src/importer.js index 8475c483..ec130d08 100644 --- a/scripts/importer/src/importer.js +++ b/scripts/importer/src/importer.js @@ -45,8 +45,6 @@ const FILE_VIDEO = (name) => new RegExp(`^${REGEXP_ESCAPE(name)}\\.(${FILE_VIDEO_EXTENSIONS})$`, "i"); const FILE_VIDEO_REGEXP_CODE = (name) => `${REGEXP_ESCAPE(name)}\\.(${FILE_VIDEO_EXTENSIONS})`; -const MODE_OPTIONS = ["auto", "manual"]; -const MODE_DEFAULT = "auto"; const SELECTOR_PREFIXES = { NORMAL: "_snm_", HARD: "_shd_", @@ -111,7 +109,6 @@ const opt = getopt "hqaudioenable=HQAUDIOENABLE", "enable hq audio (one of: *false*|true)", ], - ["m", "mode=MODE", "how to complete missing data (one of: *auto*|manual)"], ["b", "boss=BOSS", "automatically add boss levels (one of: false|*true*)"], ["a", "arcade=ARCADE", "arcade mode only (one of: *false*|true)"], [ @@ -125,8 +122,6 @@ const opt = getopt .parseSystem(); global.GLOBAL_OPTIONS = opt.options; -if (!_.includes(MODE_OPTIONS, GLOBAL_OPTIONS.mode)) - GLOBAL_OPTIONS.mode = MODE_DEFAULT; GLOBAL_OPTIONS.directory = $path.resolve( GLOBAL_OPTIONS.directory || DEFAULT_SONGS_PATH ); @@ -157,6 +152,7 @@ const UNIQUE_MAP_PATH = $path.resolve( const BLACK_DOT_FILE = $path.resolve(IMAGES_PATH, "black.bmp"); const BONUS_DIRECTORY = $path.join(GLOBAL_OPTIONS.directory, BONUS_FOLDER_NAME); +mkdirp.sync(GLOBAL_OPTIONS.output); if (!fs.existsSync(GLOBAL_OPTIONS.directory)) throw new Error("Songs directory not found: " + GLOBAL_OPTIONS.directory); if (!fs.existsSync(GLOBAL_OPTIONS.output)) @@ -232,7 +228,7 @@ async function run() { `${$path.join(GLOBAL_OPTIONS.directory, ROM_ID_FILE_REUSE)}`.cyan ); } catch (e) {} - await utils.run(`rm -rf ${GLOBAL_OPTIONS.output}`); + await utils.run(`rm -rf "${GLOBAL_OPTIONS.output}"`); mkdirp.sync(GLOBAL_OPTIONS.output); if (GLOBAL_OPTIONS.videoenable) mkdirp.sync(GLOBAL_OPTIONS.videolib); if (GLOBAL_OPTIONS.hqaudioenable) mkdirp.sync(GLOBAL_OPTIONS.hqaudiolib); @@ -273,13 +269,13 @@ async function run() { const path = $path.join(IMAGES_PATH, imageFile); await utils.report( - () => importers.background(name, path, GLOBAL_OPTIONS.output), + () => importers.background(name, path, GLOBAL_OPTIONS.output, null, 253), // (UI backgrounds need 3 extra colors: 1 for darkener + 2 for text) imageFile ); } await utils.report( async () => - await utils.run(`cp ${UNIQUE_MAP_PATH} ${GLOBAL_OPTIONS.output}`), + await utils.run(`cp "${UNIQUE_MAP_PATH}" "${GLOBAL_OPTIONS.output}"`), "_unique_map.map.bin" ); @@ -359,7 +355,7 @@ async function run() { if (!GLOBAL_OPTIONS.fast) { console.log( `(${(i + 1).toString().red}${"/".red}${ - songs.length.toString().red + songsToImport.length.toString().red }) ${"Importing".bold} ${song.name.cyan}...` ); } diff --git a/scripts/importer/src/importers/background.js b/scripts/importer/src/importers/background.js index df0098a4..9e8fd3ca 100644 --- a/scripts/importer/src/importers/background.js +++ b/scripts/importer/src/importers/background.js @@ -2,19 +2,20 @@ const utils = require("../utils"); const $path = require("path"); const _ = require("lodash"); -const COMMAND_BUILD = (input, output) => - `magick "${input}" -resize ${RESOLUTION} -colors 254 "${output}"`; +const COMMAND_BUILD = (input, output, colors = 254) => + `magick "${input}" -resize ${RESOLUTION} -colors ${colors} "${output}"`; const COMMAND_BUILD_REMAP = (input, firstColorPalette, tempPalette, output) => `magick "${input}" -resize ${RESOLUTION} -colors ${COLORS} -unique-colors "${tempPalette}" && ` + `magick "${firstColorPalette}" "${tempPalette}" +append "${tempPalette}" && ` + `magick "${input}" -resize ${RESOLUTION} -colors ${COLORS} -remap "${tempPalette}" "${output}" && ` + `rm "${tempPalette}"`; -const COMMAND_ENCODE = (input) => `grit "${input}" -gt -gB8 -mRtf -mLs -ftb`; +const COMMAND_ENCODE = (input) => + `grit "${input}" -gzl -gt -gB8 -mRtf -mLs -ftb`; const COMMAND_MD5SUM = (input) => `md5sum "${input}" | cut -d " " -f 1`; const COMMAND_CLEANUP = (tmp1, tmp2) => `${COMMAND_RM(tmp1)} && ${COMMAND_RM(tmp2)}`; const COMMAND_RM = (file) => `rm "${file}"`; -const COMMAND_FIX = (input) => `pngfix -f "${input}`; +const COMMAND_FIX = (input) => `pngfix -f "${input}"`; const RESOLUTION = "240x160!"; const COLORS = "253"; const EXTENSIONS_TMP = ["pal.bmp", "bmp", "h"]; @@ -29,7 +30,8 @@ module.exports = async ( name, filePath, outputPath, - transparentColor = null + transparentColor = null, + colors = 254 ) => { const tempFiles = EXTENSIONS_TMP.map((it) => $path.join(outputPath, `${name}.${it}`) @@ -44,7 +46,7 @@ module.exports = async ( tempFiles[0], tempFiles[1] ) - : COMMAND_BUILD(filePath, tempFiles[1]) + : COMMAND_BUILD(filePath, tempFiles[1], colors) ); } catch (originalException) { try { diff --git a/scripts/importer/src/importers/selector.js b/scripts/importer/src/importers/selector.js index c0668052..e8fcc693 100644 --- a/scripts/importer/src/importers/selector.js +++ b/scripts/importer/src/importers/selector.js @@ -10,7 +10,8 @@ const SELECTOR_BMP = "selector.bmp"; const SELECTOR_BNS_BMP = "selector_bns.bmp"; const SELECTOR_OUTPUT_PNG = "output.bmp"; const COMMAND_BUILD = "magick conjure msl:selector.msl || echo Done!"; -const COMMAND_ENCODE = (input) => `grit "${input}" -gt -gB8 -mRtf -mLs -ftb`; +const COMMAND_ENCODE = (input) => + `grit "${input}" -gzl -gt -gB8 -mRtf -mLs -ftb`; const COMMAND_CLEANUP = (tmpDir, tmpFile) => `rm -rf "${tmpDir}" && rm "${tmpFile}"`; const EXTENSION_TMP = "h"; diff --git a/scripts/importer/src/importers/transformations/completeMissingData.js b/scripts/importer/src/importers/transformations/completeMissingData.js index c2a4435a..e6e2f443 100644 --- a/scripts/importer/src/importers/transformations/completeMissingData.js +++ b/scripts/importer/src/importers/transformations/completeMissingData.js @@ -1,8 +1,5 @@ -const Channels = require("../../parser/Channels"); -const utils = require("../../utils"); const _ = require("lodash"); -const KNOWN_CHANNELS = ["ORIGINAL", "KPOP", "WORLD"]; const NON_NUMERIC_LEVELS = ["CRAZY", "HARD", "NORMAL"]; const VARIANTS = ["\0", ..."abcdefghijklmnopqrstuvwxyz"]; @@ -15,30 +12,11 @@ const TAGS = ["pro", "new", "ucs", "hidden", "train", "sp", "quest", "another"]; module.exports = (metadata, charts, isBonus) => { // channel - if (metadata.channel === "UNKNOWN") { - if (GLOBAL_OPTIONS.mode === "auto") metadata.channel = "ORIGINAL"; - else { - const channelOptions = KNOWN_CHANNELS.map( - (name, i) => `${i} = ${name}` - ).join(", "); - - console.log("-> channels: ".bold + `(${channelOptions})`.cyan); - const channel = utils.insistentChoice( - "What channel?", - _.range(KNOWN_CHANNELS.length) - ); - metadata.channel = _.keys(Channels)[parseInt(channel)]; - } - } + if (metadata.channel === "UNKNOWN") metadata.channel = "ORIGINAL"; // difficulty input method charts.forEach((it) => { - if ( - GLOBAL_OPTIONS.mode === "manual" || - it.header.isDouble || - GLOBAL_OPTIONS.arcade || - isBonus - ) + if (it.header.isDouble || GLOBAL_OPTIONS.arcade || isBonus) it.header.mode = "NUMERIC"; }); @@ -46,12 +24,8 @@ module.exports = (metadata, charts, isBonus) => { if (!GLOBAL_OPTIONS.arcade && !isBonus) { const singleCharts = charts.filter((it) => !it.header.isDouble); NON_NUMERIC_LEVELS.forEach((difficulty) => { - if ( - !hasDifficulty(singleCharts, difficulty) && - GLOBAL_OPTIONS.mode === "auto" - ) + if (!hasDifficulty(singleCharts, difficulty)) autoSetDifficulty(singleCharts, difficulty); - else setDifficulty(singleCharts, difficulty); }); checkLevelOrder(singleCharts); } @@ -186,31 +160,6 @@ const getChartAffinityLevel = (chart) => { return affinity; }; -const setDifficulty = (charts, difficultyName) => { - const createId = (chart) => `${chart.header.name}/${chart.header.level}`; - const numericDifficultyCharts = charts.filter( - (it) => it.header.difficulty === "NUMERIC" - ); - const levels = numericDifficultyCharts.map(createId); - - if (!hasDifficulty(charts, difficultyName)) { - console.log("-> levels: ".bold + `(${levels.join(", ")})`.cyan); - const chartName = utils.insistentChoice( - `Which one is ${difficultyName}?`, - levels - ); - - _.find( - charts, - (it) => createId(it).toLowerCase() === chartName - ).header.difficulty = difficultyName; - - return true; - } - - return false; -}; - const checkLevelOrder = (charts) => { const normal = getChartByDifficulty(charts, "NORMAL"); const hard = getChartByDifficulty(charts, "HARD"); diff --git a/scripts/importer/src/serializer/SongSerializer.js b/scripts/importer/src/serializer/SongSerializer.js index 87cca39c..a793a499 100644 --- a/scripts/importer/src/serializer/SongSerializer.js +++ b/scripts/importer/src/serializer/SongSerializer.js @@ -185,7 +185,7 @@ const EVENT_SERIALIZERS = { : (((scrollBpm & 0xffff) << 16) | scrollChangeFrames) & 0xffffffff; this.UInt32LE(combine(event.timestamp, event.type)) - .UInt32LE(normalizeInt(event.bpm)) + .UInt32LE(buildBPM(normalizeInt(event.bpm))) .UInt32LE(composedScrollBpm[0]) .UInt32LE( autoVelocityFactor >= 1 || autoVelocityFactor === 0 @@ -229,15 +229,35 @@ const combine = (timestamp, data, isFake = 0) => { return value[0]; }; +const buildBPM = (normalizedBpm) => { + if (normalizedBpm > MAX_BPM) normalizedBpm = MAX_BPM; + + let beatDurationFrames = Math.round(FRAMES_PER_MINUTE / normalizedBpm); + if (beatDurationFrames > MAX_BEAT_DURATION_FRAMES) + beatDurationFrames = MAX_BEAT_DURATION_FRAMES; + + const serialized = new Uint32Array(1); + serialized[0] = + ((beatDurationFrames & MAX_BEAT_DURATION_FRAMES) << 20) | + (normalizedBpm & MAX_BPM); + + return serialized[0]; +}; + const normalizeInt = (number) => { if (number === Infinity || number > INFINITY) return INFINITY; - return Math.round(number); + const array = new Uint32Array(1); + array[0] = Math.round(number); + return array[0]; }; const TITLE_LEN = 30 + 1; // +1 = \0; const ARTIST_LEN = 26 + 1; // +1 = \0; const MESSAGE_LEN = 25 + 2 + 25 + 2 + 25 + 2 + 25 + 1; // +2 = \r\n ; +1 = \0 const INFINITY = 0xffffffff; +const MAX_BPM = 0b11111111111111111111; +const MAX_BEAT_DURATION_FRAMES = 0b111111111111; +const FRAMES_PER_MINUTE = 60 * 60; const ARROW_MASKS = [ 0b00001000, diff --git a/scripts/importer/src/utils.js b/scripts/importer/src/utils.js index d330826a..26d6d644 100644 --- a/scripts/importer/src/utils.js +++ b/scripts/importer/src/utils.js @@ -4,7 +4,6 @@ const exec = util.promisify(childProcess.exec); const execSync = (...args) => { return { stdout: childProcess.execSync(...args) }; }; -const readlineSync = require("readline-sync"); const { printTableAndGetConsoleOutput, } = require("console-table-printer/dist/src/internalTable/internal-table-printer"); @@ -56,18 +55,6 @@ module.exports = { const func = GLOBAL_OPTIONS.fast ? chunkedProcessAsync : processSync; return await func(content, action); }, - insistentChoice(text, options, textColor = "black") { - const stringOptions = options.map((it) => `${it}`.toLowerCase()); - - let response = ""; - const matches = (option) => _.startsWith(option, response); - while (response === "" || _.filter(stringOptions, matches).length !== 1) - response = readlineSync - .question(`${text}`[textColor].bgWhite + " ") - .toLowerCase(); - - return _.find(stringOptions, matches); - }, replaceRange(input, search, replace, start, end = input.length) { return ( input.slice(0, start) + diff --git a/scripts/optimize_selection_mask.js b/scripts/optimize_selection_mask.js index e1be3098..e8f6351d 100644 --- a/scripts/optimize_selection_mask.js +++ b/scripts/optimize_selection_mask.js @@ -5,7 +5,7 @@ const TILE_SIZE = 16; const MAP_START_INDEX = 224; const MAP_END_INDEX = 416; const MAP_TOTAL_TILES = 1024; -const PALETTE_START_INDEX = 251; +const PALETTE_START_INDEX = 250; const TRANSPARENT_COLOR = 0x7C1F; const SELECTED = 0; diff --git a/scripts/package.sh b/scripts/package.sh old mode 100644 new mode 100755 index 3c837626..ee4c4235 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -23,7 +23,7 @@ KB=$((1024)) MAX_ROM_SIZE_KB=$((32 * $KB - 1)) INITIAL_REQUIRED_SIZE_KB=1024 -ROM_SIZE=$(wc -c < $FILE_INPUT) +ROM_SIZE=$(wc -c < "$FILE_INPUT") if [ $? -ne 0 ]; then exit 1 fi @@ -48,16 +48,16 @@ fi REQUIRED_SIZE_KB=$(($INITIAL_REQUIRED_SIZE_KB > $MAX_REQUIRED_SIZE_KB ? $MAX_REQUIRED_SIZE_KB : $INITIAL_REQUIRED_SIZE_KB)) PAD_NEEDED=$((($REQUIRED_SIZE_KB * $KB) - $ROM_SIZE)) -cp $FILE_INPUT $FILE_TMP +cp "$FILE_INPUT" "$FILE_TMP" if [ $? -ne 0 ]; then exit 1 fi -dd if=/dev/zero bs=1 count=$PAD_NEEDED >> $FILE_TMP +dd if=/dev/zero bs=$PAD_NEEDED count=1 >> "$FILE_TMP" if [ $? -ne 0 ]; then exit 1 fi -cat $FILE_TMP $DATA > $FILE_OUTPUT +cat "$FILE_TMP" "$DATA" > "$FILE_OUTPUT" if [ $? -ne 0 ]; then exit 1 fi -rm $FILE_TMP +rm "$FILE_TMP" diff --git a/scripts/toolchain/check.sh b/scripts/toolchain/check.sh old mode 100644 new mode 100755 index 25234190..55814127 --- a/scripts/toolchain/check.sh +++ b/scripts/toolchain/check.sh @@ -1,46 +1,52 @@ -function try { - "$@" - local status=$? +#!/bin/bash + +try() { + "$@" > /dev/null 2>&1 + status=$? if [ $status -eq 127 ]; then echo "❌ $1" >&2 - exit $? + exit $status fi } -try gbfs > /dev/null -try pngfix > /dev/null -echo "" +if [ -n "$NVM_DIR" ]; then + source $NVM_DIR/nvm.sh +fi + +try gbfs echo "✔️ gbfs" + +try pngfix echo "✔️ pngfix" -try rm --version > /dev/null +try rm --version echo "✔️ rm" -try dd --version > /dev/null +try dd --version echo "✔️ dd" -try md5sum --version > /dev/null +try md5sum --version echo "✔️ md5sum" -try cut --version > /dev/null +try cut --version echo "✔️ cut" -try ffmpeg -version > /dev/null +try ffmpeg -version echo "✔️ ffmpeg" -try ffplay -version > /dev/null +try ffplay -version echo "✔️ ffplay" -try magick -version > /dev/null +try magick -version echo "✔️ magick" -try grit > /dev/null +try grit echo "✔️ grit" -try make -version > /dev/null +try make -version echo "✔️ make" -try node -v > /dev/null +try node -v echo "✔️ node" echo "" diff --git a/scripts/toolchain/programs/ImageMagick-7.0.10-3-Q16-x64-static.exe b/scripts/toolchain/programs/ImageMagick-7.0.10-3-Q16-x64-static.exe deleted file mode 100644 index 41937d77..00000000 --- a/scripts/toolchain/programs/ImageMagick-7.0.10-3-Q16-x64-static.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50b6f2d65f37ac1501c6e4bceab15a7ae99a322a8cc4ebe01c705c2924059bf5 -size 38772288 diff --git a/scripts/toolchain/programs/ffmpeg-3.3.3-win64-static.zip b/scripts/toolchain/programs/ffmpeg-3.3.3-win64-static.zip deleted file mode 100644 index 81ffa6bf..00000000 --- a/scripts/toolchain/programs/ffmpeg-3.3.3-win64-static.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:174f97f5b5143ed959c84d62efef75773e104799c74c3cb01014756b514917c6 -size 48231202 diff --git a/scripts/toolchain/programs/flips/boring.zip b/scripts/toolchain/programs/flips/boring.zip deleted file mode 100644 index 244964a7..00000000 --- a/scripts/toolchain/programs/flips/boring.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e3ac1443ccd66b5f69e9be9c66c28b980589dbb33bdb5511c080281e8da00c8 -size 11815 diff --git a/scripts/toolchain/programs/flips/flips-linux b/scripts/toolchain/programs/flips/flips-linux deleted file mode 100644 index 961933fc..00000000 Binary files a/scripts/toolchain/programs/flips/flips-linux and /dev/null differ diff --git a/scripts/toolchain/programs/flips/flips.exe b/scripts/toolchain/programs/flips/flips.exe deleted file mode 100644 index a3836f5f..00000000 --- a/scripts/toolchain/programs/flips/flips.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d0c2fa27eba12965276a63306cba5cfe57102930dd83d10ecbc6956edf35da6 -size 113664 diff --git a/scripts/toolchain/programs/flips/flipscfg.bin b/scripts/toolchain/programs/flips/flipscfg.bin deleted file mode 100644 index 427f3cf5..00000000 Binary files a/scripts/toolchain/programs/flips/flipscfg.bin and /dev/null differ diff --git a/scripts/toolchain/programs/flips/license.txt b/scripts/toolchain/programs/flips/license.txt deleted file mode 100644 index 37fe5185..00000000 --- a/scripts/toolchain/programs/flips/license.txt +++ /dev/null @@ -1,11 +0,0 @@ -Flips is licensed under GNU General Public License, version 3.0 or higher. The full legal text can - be found in boring.zip; a rough interpretation (for non-lawyers only) follows: - -- You must credit the author. Don't claim it as your own. You may modify it and take credit for your - modifications, but the author (Alcaro) must be credited for the original software. -- If you modify this software, it must clearly be labeled as a modification. -- Any applications containing any part of this software must provide the full source code needed to - modify and rebuild this application, under the same license. Including this interpretation is - optional. -- The author claims no copyright over input, output, or error messages generated by this tool. Use - it however you want. diff --git a/scripts/toolchain/programs/flips/src.zip b/scripts/toolchain/programs/flips/src.zip deleted file mode 100644 index e1c3b78e..00000000 --- a/scripts/toolchain/programs/flips/src.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:daa34623f4ab4897d7dcffd9e3f06ca6e469db2d864fa873741e849dfc874ee8 -size 186087 diff --git a/scripts/toolchain/programs/make-3.81.zip b/scripts/toolchain/programs/make-3.81.zip deleted file mode 100644 index 9911a304..00000000 --- a/scripts/toolchain/programs/make-3.81.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c04ab0750fd2bf7cc0f14eea804d0c316705a790b50f66356a96a0f27df2c8ad -size 862472 diff --git a/scripts/toolchain/programs/pngfix.exe b/scripts/toolchain/programs/pngfix.exe deleted file mode 100644 index 40aaea98..00000000 --- a/scripts/toolchain/programs/pngfix.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d08121fb18b38da16b79b5d4b9e2e399c467ce090a92e7bf8a6797db325aec3 -size 272989 diff --git a/scripts/toolchain/vscode_settings.json b/scripts/toolchain/vscode_settings.json index 44a7c7ba..0bb57598 100644 --- a/scripts/toolchain/vscode_settings.json +++ b/scripts/toolchain/vscode_settings.json @@ -1,11 +1,28 @@ { "extensions.ignoreRecommendations": false, "terminal.integrated.profiles.windows": { + "Git Bash (MINGW64)": { + "path": [ + "C:\\Program Files\\Git\\bin\\bash.exe" + ], + "args": [ + "--login", + "-i" + ], + "icon": "terminal-bash" + }, "Git Bash": { "source": "Git Bash" + }, + "Ubuntu (WSL)": { + "path": "C:\\WINDOWS\\System32\\wsl.exe", + "args": [ + "-d", + "Ubuntu" + ] } }, - "terminal.integrated.defaultProfile.windows": "Git Bash", + "terminal.integrated.defaultProfile.windows": "Git Bash (MINGW64)", "window.zoomLevel": 1, "C_Cpp.clang_format_style": "{ BasedOnStyle: Chromium }", "editor.formatOnSave": true, diff --git a/src/data/assets/images/controls.png b/src/data/assets/images/controls.png index 42b1be52..c93f1fa3 100644 Binary files a/src/data/assets/images/controls.png and b/src/data/assets/images/controls.png differ diff --git a/src/data/assets/images/controls_md.png b/src/data/assets/images/controls_md.png index 965d1f29..cf77b186 100644 Binary files a/src/data/assets/images/controls_md.png and b/src/data/assets/images/controls_md.png differ diff --git a/src/data/assets/images/grade.png b/src/data/assets/images/grade.png index c43ad6f0..fc236ecd 100644 Binary files a/src/data/assets/images/grade.png and b/src/data/assets/images/grade.png differ diff --git a/src/data/assets/images/grade_md.png b/src/data/assets/images/grade_md.png index d1f0677f..738b38f4 100644 Binary files a/src/data/assets/images/grade_md.png and b/src/data/assets/images/grade_md.png differ diff --git a/src/data/assets/images/grade_mul.png b/src/data/assets/images/grade_mul.png index 4dce721f..b5d5d0c9 100644 Binary files a/src/data/assets/images/grade_mul.png and b/src/data/assets/images/grade_mul.png differ diff --git a/src/data/assets/images/grade_mul_md.png b/src/data/assets/images/grade_mul_md.png index 46fecb81..09f6d2f1 100644 Binary files a/src/data/assets/images/grade_mul_md.png and b/src/data/assets/images/grade_mul_md.png differ diff --git a/src/data/assets/images/selector.bmp b/src/data/assets/images/selector.bmp index 71a2bdce..946b0edf 100644 Binary files a/src/data/assets/images/selector.bmp and b/src/data/assets/images/selector.bmp differ diff --git a/src/data/assets/images/selector_bns.bmp b/src/data/assets/images/selector_bns.bmp index 29cd28a4..e7fda253 100644 Binary files a/src/data/assets/images/selector_bns.bmp and b/src/data/assets/images/selector_bns.bmp differ diff --git a/src/data/assets/images/start.png b/src/data/assets/images/start.png index b905a18b..1a4189ac 100644 Binary files a/src/data/assets/images/start.png and b/src/data/assets/images/start.png differ diff --git a/src/data/custom/bg_selectionmask.c b/src/data/custom/bg_selectionmask.c index 5d4c4e57..94fe9b8b 100644 --- a/src/data/custom/bg_selectionmask.c +++ b/src/data/custom/bg_selectionmask.c @@ -9,324 +9,324 @@ const unsigned int BG_SELECTIONMASK_TILES[][496] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 4244438016, 0, 4244438016, - 0, 4244438016, 0, 4244438016, 0, 4244438016, - 0, 4244438016, 0, 4244438016, 0, 0, + 0, 0, 0, 4227595008, 0, 4227595008, + 0, 4227595008, 0, 4227595008, 0, 4227595008, + 0, 4227595008, 0, 4227595008, 0, 0, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 0, 0, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 4244438268, 4244438268, 0, 0, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 0, 0, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 0, 0, 0, 0, + 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4244438016, - 0, 4244438016, 0, 4244438016, 0, 4244438016, - 0, 4244438016, 0, 4244438016, 0, 4244438016, - 0, 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, + 0, 0, 0, 0, 0, 4227595008, + 0, 4227595008, 0, 4227595008, 0, 4227595008, + 0, 4227595008, 0, 4227595008, 0, 4227595008, + 0, 4227595008, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, + 4261281277, 4261281277, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 4244438016, 0, 4244438016, - 0, 4244438016, 0, 4244438016, 0, 4244438016, + 0, 0, 0, 4227595008, 0, 4227595008, + 0, 4227595008, 0, 4227595008, 0, 4227595008, + 0, 0, 0, 0, 0, 0, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 4227595259, 4227595259, 0, 0, + 0, 0, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 0, 0, 0, 0, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, 0, 0, 0, 0, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 0, 0, - 0, 0, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 0, 0, 0, 0, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 0, 0, 0, 0, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, - 0, 0, 0, 0, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 0, 0, 0, 0, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 0, 0, 0, 0, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 0, 0, + 0, 0, 0, 0, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 0, 0, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 0, 0, 16514043, 0, 16514043, 0, - 16514043, 0, 16514043, 0, 16514043, 0, - 16514043, 0, 16514043, 0, 0, 0, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 0, 0, 16448250, 0, 16448250, 0, + 16448250, 0, 16448250, 0, 16448250, 0, + 16448250, 0, 16448250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 0, 0, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, + 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 4244438268, 4244438268, 0, 0, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 0, 0, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 16514043, 0, - 16514043, 0, 16514043, 0, 16514043, 0, - 16514043, 0, 16514043, 0, 16514043, 0, - 16514043, 0, 0, 0, 0, 0, + 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 16448250, 0, + 16448250, 0, 16448250, 0, 16448250, 0, + 16448250, 0, 16448250, 0, 16448250, 0, + 16448250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 0, 0, 0, 0, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 0, 0, - 0, 0, 0, 0, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 0, 0, 0, 0, - 0, 0, 16514043, 0, 16514043, 0, - 16514043, 0, 16514043, 0, 16514043, 0, + 4261281277, 4261281277, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 0, 0, + 0, 0, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 0, 0, 0, 0, + 0, 0, 16448250, 0, 16448250, 0, + 16448250, 0, 16448250, 0, 16448250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, 0, 0, 0, 0, + 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, + 4244438268, 4244438268, 4244438268, 4244438268, 0, 0, + 0, 0, 0, 0, 16579836, 4261281024, + 16579836, 4261281024, 16579836, 4261281024, 16579836, 4261281024, + 16579836, 4261281024, 0, 0, 0, 0, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, - 0, 0, 0, 0, 16645629, 4278124032, - 16645629, 4278124032, 16645629, 4278124032, 16645629, 4278124032, - 16645629, 4278124032, 0, 0, 0, 0, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 0, 0, 0, 0, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 0, 0, + 0, 0, 0, 0, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 0, 0, 4227595259, 4227595259, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 0, 0, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 0, 0, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 0, 0, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 0, 0, - 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, + 4227595259, 4227595259, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4278124032, - 0, 4278124032, 0, 4278124032, 0, 4278124032, - 0, 4278124032, 0, 4278124032, 0, 4278124032, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, + 0, 0, 0, 0, 0, 4261281024, + 0, 4261281024, 0, 4261281024, 0, 4261281024, + 0, 4261281024, 0, 4261281024, 0, 4261281024, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 0, 0, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4278124032, 0, 4278124032, 0, 4278124032, - 0, 4278124032, 0, 4278124032, 0, 4278124032, - 0, 4278124032, 0, 4278124032, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 0, 0, - 0, 0, 0, 0, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 0, 0, 0, 0, - 0, 0, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, + 0, 4261281024, 0, 4261281024, 0, 4261281024, + 0, 4261281024, 0, 4261281024, 0, 4261281024, + 0, 4261281024, 0, 4261281024, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 0, 0, + 0, 0, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 0, 0, 0, 0, + 0, 0, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, 0, 0, 0, 0, 0, 0, - 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 4244438268, 4244438268, 0, 0, - 0, 0, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 0, 0, 0, 0, + 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, + 4227595259, 4227595259, 4227595259, 4227595259, 0, 0, + 0, 0, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4278124032, - 0, 4278124032, 0, 4278124032, 0, 4278124032, - 0, 4278124032, 0, 0, 0, 0, - 0, 0, 4278124286, 4278124286, 4278124286, 4278124286, - 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, 4278124286, + 0, 0, 0, 0, 0, 4261281024, + 0, 4261281024, 0, 4261281024, 0, 4261281024, + 0, 4261281024, 0, 0, 0, 0, + 0, 0, 4261281277, 4261281277, 4261281277, 4261281277, + 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, 0, 0, 0, 0, - 4278124286, 16711422, 4278124286, 16711422, 4278124286, 16711422, - 4278124286, 16711422, 4278124286, 16711422, 0, 0, + 4261281277, 16645629, 4261281277, 16645629, 4261281277, 16645629, + 4261281277, 16645629, 4261281277, 16645629, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 0, 0, 4227595259, 4227595259, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 0, 0, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 0, 0, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 0, 0, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 0, 0, + 4227595259, 4227595259, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 4244438268, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 0, 0, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 0, 0, 16645629, 0, - 16645629, 0, 16645629, 0, 16645629, 0, - 16645629, 0, 16645629, 0, 16645629, 0, + 4244438268, 4244438268, 0, 0, 16579836, 0, + 16579836, 0, 16579836, 0, 16579836, 0, + 16579836, 0, 16579836, 0, 16579836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, + 0, 0, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 4227595259, 4227595259, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 16645629, 0, 16645629, 0, 16645629, 0, - 16645629, 0, 16645629, 0, 16645629, 0, - 16645629, 0, 16645629, 0, 0, 0, + 16579836, 0, 16579836, 0, 16579836, 0, + 16579836, 0, 16579836, 0, 16579836, 0, + 16579836, 0, 16579836, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4210752000, 4210752250, 4210752000, 4210752250, 4210752000, 4210752250, + 4210752000, 4210752250, 4210752000, 4210752250, 0, 0, + 0, 0, 0, 0, 4210752250, 4210752250, + 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, 4210752250, + 4210752250, 4210752250, 0, 0, 0, 0, + 0, 0, 16448250, 4227595008, 16448250, 4227595008, + 16448250, 4227595008, 16448250, 4227595008, 16448250, 4227595008, 0, 0, 0, 0, 0, 0, - 4227595008, 4227595259, 4227595008, 4227595259, 4227595008, 4227595259, - 4227595008, 4227595259, 4227595008, 4227595259, 0, 0, - 0, 0, 0, 0, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, 4227595259, - 4227595259, 4227595259, 0, 0, 0, 0, - 0, 0, 16514043, 4244438016, 16514043, 4244438016, - 16514043, 4244438016, 16514043, 4244438016, 16514043, 4244438016, + 4227595259, 4227595259, 4227595259, 4227595259, 0, 0, + 0, 0, 0, 0, 4227595259, 16514043, + 4227595259, 16514043, 4227595259, 16514043, 4227595259, 16514043, + 4227595259, 16514043, 0, 0, 0, 0, + 0, 0, 4244438016, 4244438268, 4244438016, 4244438268, + 4244438016, 4244438268, 4244438016, 4244438268, 4244438016, 4244438268, 0, 0, 0, 0, 0, 0, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 4244438268, 0, 0, - 0, 0, 0, 0, 4244438268, 16579836, - 4244438268, 16579836, 4244438268, 16579836, 4244438268, 16579836, - 4244438268, 16579836, 0, 0, 0, 0, - 0, 0, 4261281024, 4261281277, 4261281024, 4261281277, - 4261281024, 4261281277, 4261281024, 4261281277, 4261281024, 4261281277, - 0, 0, 0, 0, 0, 0, - 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, 4261281277, - 4261281277, 4261281277, 4261281277, 4261281277, 0, 0, - 0, 0, 0, 0, 16645629, 0, - 16645629, 0, 16645629, 0, 16645629, 0, - 16645629, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16579836, 0, + 16579836, 0, 16579836, 0, 16579836, 0, + 16579836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/src/data/custom/bg_selectionmask.h b/src/data/custom/bg_selectionmask.h index 1755f745..d4eecc5b 100644 --- a/src/data/custom/bg_selectionmask.h +++ b/src/data/custom/bg_selectionmask.h @@ -16,6 +16,6 @@ const struct { const unsigned int MAP_TOTAL_TILES; const unsigned int PALETTE_START_INDEX; const unsigned int PALETTE_LENGTH; -} BG_SELECTIONMASK_METADATA = {2, 224, 256, 496, 18, 224, 416, 1024, 251, 4}; +} BG_SELECTIONMASK_METADATA = {2, 224, 256, 496, 18, 224, 416, 1024, 250, 4}; #endif // BG_SELECTIONMASK_H diff --git a/src/data/editables_classic/buttons.xcf b/src/data/editables_classic/buttons.xcf index 12917034..576ab207 100644 Binary files a/src/data/editables_classic/buttons.xcf and b/src/data/editables_classic/buttons.xcf differ diff --git a/src/data/editables_classic/buttons_mini.xcf b/src/data/editables_classic/buttons_mini.xcf index 9880391e..4cba3e27 100644 Binary files a/src/data/editables_classic/buttons_mini.xcf and b/src/data/editables_classic/buttons_mini.xcf differ diff --git a/src/data/editables_classic/instructors.xcf b/src/data/editables_classic/instructors.xcf index 026c99f9..cf909c1c 100644 Binary files a/src/data/editables_classic/instructors.xcf and b/src/data/editables_classic/instructors.xcf differ diff --git a/src/data/editables_classic/level.xcf b/src/data/editables_classic/level.xcf index 04787eb1..2ba78eb2 100644 Binary files a/src/data/editables_classic/level.xcf and b/src/data/editables_classic/level.xcf differ diff --git a/src/data/editables_classic/metadata.txt b/src/data/editables_classic/metadata.txt index 97aa9700..bed25fc2 100644 --- a/src/data/editables_classic/metadata.txt +++ b/src/data/editables_classic/metadata.txt @@ -79,7 +79,7 @@ of: screen_song: -This screen uses colors from: +This screen uses fg colors from: arrows+combo+numbers+feedback+lifebar 105+10+30+60+64 = 269 (13 extra colors) -> these spritesheets are merges of classic&modern themes (in the `editables_merge` folder) @@ -88,12 +88,18 @@ This screen uses colors from: === +Most UI screens use 253 bg colors, leaving 1 free color for the darkener and 2 free colors for the font. + screen_selection: Image -> Mode -> Indexed... - -> 251 colors + -> 250 colors (actually exported as 251, and converted to 250 via magick) + ^ highlighter occupies 4 colors (250, 251, 252, and 253); 254 and 255 are free for text + +selector_bns: ^^^<<< Filters -> Edge-Detect -> Sobel... + screen_controls: Image -> Mode -> Indexed... - -> 254 colors + -> 253 colors -> Color dithering: None === diff --git a/src/data/editables_classic/numbers_mini.xcf b/src/data/editables_classic/numbers_mini.xcf index 92d18381..9c74de47 100644 Binary files a/src/data/editables_classic/numbers_mini.xcf and b/src/data/editables_classic/numbers_mini.xcf differ diff --git a/src/data/editables_classic/rgb/instructors.xcf b/src/data/editables_classic/rgb/instructors.xcf index 142ccf46..ce89aa22 100644 Binary files a/src/data/editables_classic/rgb/instructors.xcf and b/src/data/editables_classic/rgb/instructors.xcf differ diff --git a/src/data/editables_classic/rgb/screen_grade.xcf b/src/data/editables_classic/rgb/screen_grade.xcf index 7b460ece..58668c27 100644 Binary files a/src/data/editables_classic/rgb/screen_grade.xcf and b/src/data/editables_classic/rgb/screen_grade.xcf differ diff --git a/src/data/editables_classic/rgb/screen_grade_multi.xcf b/src/data/editables_classic/rgb/screen_grade_multi.xcf index 213aa841..7a885143 100644 Binary files a/src/data/editables_classic/rgb/screen_grade_multi.xcf and b/src/data/editables_classic/rgb/screen_grade_multi.xcf differ diff --git a/src/data/editables_classic/rgb/screen_selection.xcf b/src/data/editables_classic/rgb/screen_selection.xcf index db1d29c4..31a8e08c 100644 Binary files a/src/data/editables_classic/rgb/screen_selection.xcf and b/src/data/editables_classic/rgb/screen_selection.xcf differ diff --git a/src/data/editables_classic/text-base.bmp b/src/data/editables_classic/text-base.bmp new file mode 100644 index 00000000..4896d70e Binary files /dev/null and b/src/data/editables_classic/text-base.bmp differ diff --git a/src/data/editables_classic/text.bmp b/src/data/editables_classic/text.bmp new file mode 100644 index 00000000..5663e6ed Binary files /dev/null and b/src/data/editables_classic/text.bmp differ diff --git a/src/data/editables_classic/text.xcf b/src/data/editables_classic/text.xcf new file mode 100644 index 00000000..727a2b0f Binary files /dev/null and b/src/data/editables_classic/text.xcf differ diff --git a/src/data/editables_modern/rgb/screen_grade.xcf b/src/data/editables_modern/rgb/screen_grade.xcf index 4795c9c0..7fb38b2b 100644 Binary files a/src/data/editables_modern/rgb/screen_grade.xcf and b/src/data/editables_modern/rgb/screen_grade.xcf differ diff --git a/src/data/editables_modern/rgb/screen_grade_multi.xcf b/src/data/editables_modern/rgb/screen_grade_multi.xcf index 31eebfcb..e619d415 100644 Binary files a/src/data/editables_modern/rgb/screen_grade_multi.xcf and b/src/data/editables_modern/rgb/screen_grade_multi.xcf differ diff --git a/src/data/spr_buttons_mini.bmp b/src/data/spr_buttons_mini.bmp index a50132ee..f5fa7288 100644 Binary files a/src/data/spr_buttons_mini.bmp and b/src/data/spr_buttons_mini.bmp differ diff --git a/src/data/spr_instructors.bmp b/src/data/spr_instructors.bmp index 41889a62..f9f6127f 100644 Binary files a/src/data/spr_instructors.bmp and b/src/data/spr_instructors.bmp differ diff --git a/src/data/spr_level.bmp b/src/data/spr_level.bmp index 9984a8ff..f3a7a788 100644 Binary files a/src/data/spr_level.bmp and b/src/data/spr_level.bmp differ diff --git a/src/data/spr_numbers_mini.bmp b/src/data/spr_numbers_mini.bmp index 409f0871..38883f16 100644 Binary files a/src/data/spr_numbers_mini.bmp and b/src/data/spr_numbers_mini.bmp differ diff --git a/src/gameplay/ChartReader.cpp b/src/gameplay/ChartReader.cpp index 9bfb8333..4b099e5e 100644 --- a/src/gameplay/ChartReader.cpp +++ b/src/gameplay/ChartReader.cpp @@ -131,7 +131,7 @@ CODE_IWRAM void ChartReader::processRhythmEvents() { if (type == EventType::SET_TEMPO) { u32 oldBpm = bpm; u32 scrollChangeFrames = event->param2 & 0xffff; - bpm = event->param; + bpm = event->bpm(); scrollBpm = event->param2 >> 16; if (event->param2 == INFINITY) { scrollChangeFrames = 0; @@ -140,10 +140,11 @@ CODE_IWRAM void ChartReader::processRhythmEvents() { autoVelocityFactor = event->param3; if (oldBpm != bpm) { - lastBpmChange = event->timestamp; + lastBpmChange = event->timestamp(); lastBeat = -1; lastTick = 0; - beatDurationFrames = -1; + beatDurationFrames = + currentRate == 0 ? event->beatDurationFrames() : -1; beatFrame = 0; didSetInitialBpm = true; } @@ -182,26 +183,26 @@ CODE_IWRAM void ChartReader::processNextEvents(int now) { if (arrowPool->isFull()) return false; - processUniqueNote(event->timestamp, event->data, event->data2, - event->isFake); + processUniqueNote(event->timestamp(), event->data(), event->data2, + event->isFake()); return true; } case EventType::HOLD_START: { - startHoldNote(event->timestamp, event->data, event->param, 0, - event->isFake); + startHoldNote(event->timestamp(), event->data(), event->param, 0, + event->isFake()); if (chart->isDouble) - startHoldNote(event->timestamp, event->data2, event->param, - ARROWS_TOTAL, event->isFake); + startHoldNote(event->timestamp(), event->data2, event->param, + ARROWS_TOTAL, event->isFake()); return true; } case EventType::HOLD_END: { - endHoldNote(event->timestamp, event->data); + endHoldNote(event->timestamp(), event->data()); if (chart->isDouble) - endHoldNote(event->timestamp, event->data2, ARROWS_TOTAL); + endHoldNote(event->timestamp(), event->data2, ARROWS_TOTAL); return true; } default: { - if (now < event->timestamp || hasStopped) + if (now < event->timestamp() || hasStopped) return false; } } @@ -209,7 +210,7 @@ CODE_IWRAM void ChartReader::processNextEvents(int now) { switch (type) { case EventType::STOP: { hasStopped = true; - stopStart = event->timestamp; + stopStart = event->timestamp(); stopLength = event->param; stopAsync = event->param2; stopAsyncStoppedTime = event->param3; diff --git a/src/gameplay/ChartReader.h b/src/gameplay/ChartReader.h index 1b021a82..d283c719 100644 --- a/src/gameplay/ChartReader.h +++ b/src/gameplay/ChartReader.h @@ -16,9 +16,10 @@ #include "utils/pool/ObjectPool.h" const u8 ARROW_MIRROR_INDEXES[] = {0, 1, 2, 3, 4, 3, 4, 2, 0, 1}; -const u32 FRACUMUL_RATE_AUDIO_LAG[] = {2018634629, 3135326125, 3693671874, 0, - 472446402, 1116691497, 2319282339}; -// (0.86, 0.73, 0.47, 0, (1+)0.11, (1+)0.26, (1)+0.54) +const u32 FRACUMUL_RATE_SCALE[] = {2018634629, 3178275798, 3736621547, 0, + 558345748, 1116691497, 2276332666}; +// (0.47, 0.74, 0.87, 0, (1+)0.13, (1+)0.26, (1)+0.53) +// (empirical measure, checked multiple times) class ChartReader : public TimingProvider { public: @@ -52,14 +53,19 @@ class ChartReader : public TimingProvider { return this->multiplier != oldMultiplier; } - inline void syncRate(u32 base, int rate) { - rateAudioLag = audioLag; + inline void syncRate(u32 rateLevels, int rate) { + this->currentRate = rate; + rateAudioLag = scaleByRate(rateLevels, audioLag, rate); + beatDurationFrames = -1; + } + + inline int scaleByRate(u32 origin, int number, int rate) { if (rate > 0) - rateAudioLag += - MATH_fracumul(audioLag, FRACUMUL_RATE_AUDIO_LAG[base + rate]); + number += MATH_fracumul(number, FRACUMUL_RATE_SCALE[origin + rate]); if (rate < 0) - rateAudioLag = - MATH_fracumul(audioLag, FRACUMUL_RATE_AUDIO_LAG[base + rate]); + number = MATH_fracumul(number, FRACUMUL_RATE_SCALE[origin + rate]); + + return number; } inline int getJudgementOffset() { @@ -114,6 +120,7 @@ class ChartReader : public TimingProvider { u32 stoppedMs = 0; u32 asyncStoppedMs = 0; u32 warpedMs = 0; + int currentRate = 0; template inline void processEvents(Event* events, @@ -124,10 +131,10 @@ class ChartReader : public TimingProvider { u32 currentIndex = index; bool skipped = false; - while (targetMsecs >= events[currentIndex].timestamp && + while (targetMsecs >= events[currentIndex].timestamp() && currentIndex < count) { auto event = events + currentIndex; - EventType type = static_cast((event->data & EVENT_TYPE)); + EventType type = static_cast(event->data() & EVENT_TYPE); if (event->handled[playerId]) { currentIndex++; diff --git a/src/gameplay/DeathMix.cpp b/src/gameplay/DeathMix.cpp index 97ab2edf..8c0dc834 100644 --- a/src/gameplay/DeathMix.cpp +++ b/src/gameplay/DeathMix.cpp @@ -4,15 +4,19 @@ #include "save/SaveFile.h" -DeathMix::DeathMix(const GBFS_FILE* fs, DifficultyLevel difficultyLevel) { +DeathMix::DeathMix(const GBFS_FILE* fs, MixMode mixMode) { + this->mixMode = mixMode; + auto library = std::unique_ptr{new Library(fs)}; u32 librarySize = SAVEFILE_getLibrarySize(); u32 pages = Div(librarySize, PAGE_SIZE) + (DivMod(librarySize, PAGE_SIZE) > 0); for (u32 i = 0; i < pages; i++) - library->loadSongs(songFiles, difficultyLevel, i * PAGE_SIZE); + library->loadSongs(songFiles, DifficultyLevel::CRAZY, i * PAGE_SIZE); + // (difficulty level doesn't matter here, as the order will be random anyway) + // randomize song order for (int i = songFiles.size() - 1; i > 0; --i) { int j = qran_range(0, i + 1); std::swap(songFiles[i], songFiles[j]); @@ -22,7 +26,6 @@ DeathMix::DeathMix(const GBFS_FILE* fs, DifficultyLevel difficultyLevel) { songFiles[i]->index = i; this->fs = fs; - this->difficultyLevel = difficultyLevel; this->next = 0; this->total = librarySize; } @@ -32,9 +35,13 @@ SongChart DeathMix::getNextSongChart() { return SongChart{.song = NULL, .chart = NULL}; Song* tempSong = SONG_parse(fs, songFiles[next].get()); - u8 index = SONG_findChartIndexByDifficultyLevel(tempSong, difficultyLevel); + int index = getNextChartIndex(tempSong); SONG_free(tempSong); - Song* song = SONG_parse(fs, songFiles[next].get(), std::vector{index}); + if (index == -1) // (should not happen, just a fail-safe) + return SongChart{.song = NULL, .chart = NULL}; + + Song* song = + SONG_parse(fs, songFiles[next].get(), std::vector{(u8)index}); Chart* chart = song->charts + index; next++; diff --git a/src/gameplay/DeathMix.h b/src/gameplay/DeathMix.h index a7c693ac..7daf8935 100644 --- a/src/gameplay/DeathMix.h +++ b/src/gameplay/DeathMix.h @@ -9,6 +9,8 @@ #include "models/Song.h" #include "objects/score/Score.h" +enum MixMode { DEATH, SHUFFLE }; + typedef struct { Song* song; Chart* chart; @@ -16,6 +18,7 @@ typedef struct { class DeathMix { public: + MixMode mixMode; bool didStartScroll = false; u32 multiplier = 1; u32 combo = 0; @@ -27,18 +30,21 @@ class DeathMix { u32 points = 0; u32 longNotes = 0; - DeathMix(const GBFS_FILE* fs, DifficultyLevel difficultyLevel); + DeathMix(const GBFS_FILE* fs, MixMode mixMode); bool isInitialSong() { return next == 1; } SongChart getNextSongChart(); u32 getCurrentSongNumber() { return next - 1; } + bool isEmpty() { return songFiles.empty(); } - private: - const GBFS_FILE* fs; - DifficultyLevel difficultyLevel; + protected: + virtual int getNextChartIndex(Song* tempSong) = 0; std::vector> songFiles; u32 next; u32 total; + + private: + const GBFS_FILE* fs; }; #endif // DEATH_MIX_H diff --git a/src/gameplay/DifficultyLevelDeathMix.cpp b/src/gameplay/DifficultyLevelDeathMix.cpp new file mode 100644 index 00000000..09852388 --- /dev/null +++ b/src/gameplay/DifficultyLevelDeathMix.cpp @@ -0,0 +1,12 @@ +#include "DifficultyLevelDeathMix.h" + +DifficultyLevelDeathMix::DifficultyLevelDeathMix( + const GBFS_FILE* fs, + DifficultyLevel difficultyLevel) + : DeathMix(fs, MixMode::DEATH) { + this->difficultyLevel = difficultyLevel; +} + +int DifficultyLevelDeathMix::getNextChartIndex(Song* tempSong) { + return SONG_findChartIndexByDifficultyLevel(tempSong, difficultyLevel); +} diff --git a/src/gameplay/DifficultyLevelDeathMix.h b/src/gameplay/DifficultyLevelDeathMix.h new file mode 100644 index 00000000..7bbb79ae --- /dev/null +++ b/src/gameplay/DifficultyLevelDeathMix.h @@ -0,0 +1,18 @@ +#ifndef DIFFICULTY_LEVEL_DEATH_MIX_H +#define DIFFICULTY_LEVEL_DEATH_MIX_H + +#include "DeathMix.h" + +class DifficultyLevelDeathMix : public DeathMix { + public: + DifficultyLevelDeathMix(const GBFS_FILE* fs, DifficultyLevel difficultyLevel); + + protected: + int getNextChartIndex(Song* tempSong) override; + + private: + const GBFS_FILE* fs; + DifficultyLevel difficultyLevel; +}; + +#endif // DIFFICULTY_LEVEL_DEATH_MIX_H diff --git a/src/gameplay/Evaluation.h b/src/gameplay/Evaluation.h index ba478f4c..2c384dd1 100644 --- a/src/gameplay/Evaluation.h +++ b/src/gameplay/Evaluation.h @@ -20,6 +20,11 @@ class Evaluation { u32 longNotes = 0; u32 percent = 0; + inline bool needs4Digits() { + return perfects > 999 || greats > 999 || goods > 999 || bads > 999 || + misses > 999 || maxCombo > 999; + } + inline GradeType getGrade() { if (percent >= 95 && misses == 0) return GradeType::S; diff --git a/src/gameplay/Key.h b/src/gameplay/Key.h index 3a64d039..61980490 100644 --- a/src/gameplay/Key.h +++ b/src/gameplay/Key.h @@ -6,43 +6,43 @@ #include "multiplayer/PS2Keyboard.h" inline bool PS2_P1_DOWNLEFT() { - return ps2Keyboard->arrows[0]; + return ps2Keyboard->keys.arrows[0]; } inline bool PS2_P1_UPLEFT() { - return ps2Keyboard->arrows[1]; + return ps2Keyboard->keys.arrows[1]; } inline bool PS2_P1_CENTER() { - return ps2Keyboard->arrows[2]; + return ps2Keyboard->keys.arrows[2]; } inline bool PS2_P1_UPRIGHT() { - return ps2Keyboard->arrows[3]; + return ps2Keyboard->keys.arrows[3]; } inline bool PS2_P1_DOWNRIGHT() { - return ps2Keyboard->arrows[4]; + return ps2Keyboard->keys.arrows[4]; } inline bool PS2_P2_DOWNLEFT() { - return ps2Keyboard->arrows[5]; + return ps2Keyboard->keys.arrows[5]; } inline bool PS2_P2_UPLEFT() { - return ps2Keyboard->arrows[6]; + return ps2Keyboard->keys.arrows[6]; } inline bool PS2_P2_CENTER() { - return ps2Keyboard->arrows[7]; + return ps2Keyboard->keys.arrows[7]; } inline bool PS2_P2_UPRIGHT() { - return ps2Keyboard->arrows[8]; + return ps2Keyboard->keys.arrows[8]; } inline bool PS2_P2_DOWNRIGHT() { - return ps2Keyboard->arrows[9]; + return ps2Keyboard->keys.arrows[9]; } inline bool PS2_DOWNLEFT() { @@ -66,27 +66,27 @@ inline bool PS2_DOWNRIGHT() { } inline bool PS2_START() { - return ps2Keyboard->start1 || ps2Keyboard->start2; + return ps2Keyboard->keys.start1 || ps2Keyboard->keys.start2; } inline bool PS2_SELECT() { - return ps2Keyboard->select1 || ps2Keyboard->select2; + return ps2Keyboard->keys.select1 || ps2Keyboard->keys.select2; } inline bool PS2_LEFT() { - return ps2Keyboard->left; + return ps2Keyboard->keys.left; } inline bool PS2_RIGHT() { - return ps2Keyboard->right; + return ps2Keyboard->keys.right; } inline bool PS2_UP() { - return ps2Keyboard->up; + return ps2Keyboard->keys.up; } inline bool PS2_DOWN() { - return ps2Keyboard->down; + return ps2Keyboard->keys.down; } inline bool GBA_DOWNLEFT(u16 keys) { diff --git a/src/gameplay/NumericLevelDeathMix.cpp b/src/gameplay/NumericLevelDeathMix.cpp new file mode 100644 index 00000000..456adf38 --- /dev/null +++ b/src/gameplay/NumericLevelDeathMix.cpp @@ -0,0 +1,23 @@ +#include "NumericLevelDeathMix.h" + +NumericLevelDeathMix::NumericLevelDeathMix(const GBFS_FILE* fs, u8 numericLevel) + : DeathMix(fs, MixMode::SHUFFLE) { + this->numericLevel = numericLevel; + + for (auto it = songFiles.begin(); it != songFiles.end();) { + Song* tempSong = SONG_parse(fs, it->get()); + int index = getNextChartIndex(tempSong); + SONG_free(tempSong); + + if (index == -1) + it = songFiles.erase(it); + else + ++it; + } + + this->total = songFiles.size(); +} + +int NumericLevelDeathMix::getNextChartIndex(Song* tempSong) { + return SONG_findSingleChartIndexByNumericLevel(tempSong, numericLevel); +} diff --git a/src/gameplay/NumericLevelDeathMix.h b/src/gameplay/NumericLevelDeathMix.h new file mode 100644 index 00000000..628239a8 --- /dev/null +++ b/src/gameplay/NumericLevelDeathMix.h @@ -0,0 +1,18 @@ +#ifndef NUMERIC_LEVEL_DEATH_MIX_H +#define NUMERIC_LEVEL_DEATH_MIX_H + +#include "DeathMix.h" + +class NumericLevelDeathMix : public DeathMix { + public: + NumericLevelDeathMix(const GBFS_FILE* fs, u8 numericLevel); + + protected: + int getNextChartIndex(Song* tempSong) override; + + private: + const GBFS_FILE* fs; + u8 numericLevel; +}; + +#endif // NUMERIC_LEVEL_DEATH_MIX_H diff --git a/src/gameplay/Sequence.cpp b/src/gameplay/Sequence.cpp index eddba6bb..9195beb4 100644 --- a/src/gameplay/Sequence.cpp +++ b/src/gameplay/Sequence.cpp @@ -18,7 +18,9 @@ #include "scenes/SelectionScene.h" #include "scenes/SongScene.h" #include "scenes/StartScene.h" +#include "scenes/StatsScene.h" #include "scenes/TalkScene.h" +#include "utils/SceneUtils.h" static std::shared_ptr _engine; static const GBFS_FILE* _fs; @@ -63,11 +65,12 @@ Scene* SEQUENCE_getInitialScene() { } bool isPlaying = SAVEFILE_read8(SRAM->state.isPlaying); + bool isShuffleMode = ENV_ARCADE || SAVEFILE_read8(SRAM->isShuffleMode) == 1; auto gameMode = SAVEFILE_getGameMode(); SAVEFILE_write8(SRAM->state.isPlaying, false); if (isPlaying && gameMode == GameMode::DEATH_MIX) - return new DeathMixScene(_engine, _fs); + return new DeathMixScene(_engine, _fs, static_cast(isShuffleMode)); if (isPlaying && !IS_MULTIPLAYER(gameMode)) return new SelectionScene(_engine, _fs); @@ -104,7 +107,6 @@ Scene* SEQUENCE_getMainScene() { } Scene* SEQUENCE_activateVideo(bool showSuccessMessage) { - SAVEFILE_write8(SRAM->adminSettings.ewramOverclock, true); auto videoState = videoStore->activate(); switch (videoState) { case VideoStore::NO_SUPPORTED_FLASHCART: { @@ -134,6 +136,7 @@ Scene* SEQUENCE_activateEWRAMOverclock() { } Scene* SEQUENCE_deactivateEWRAMOverclock() { + SCENE_unoverclockEWRAM(); SAVEFILE_write8(SRAM->adminSettings.ewramOverclock, false); return SEQUENCE_halt(EWRAM_OVERCLOCK_DISABLED); } @@ -186,42 +189,55 @@ void SEQUENCE_goToGameMode(GameMode gameMode) { u16 keys = ~REG_KEYS & KEY_ANY; bool isHoldingStart = KEY_STA(keys); - bool wasBonusMode = SAVEFILE_read8(SRAM->isBonusMode); - bool isBonusMode = SAVEFILE_bonusCount(_fs) > 0 && isHoldingStart; + bool isHoldingL = keys & KEY_L; + bool isHoldingR = keys & KEY_R; auto lastGameMode = SAVEFILE_getGameMode(); + bool wasBonusMode = + lastGameMode == GameMode::ARCADE && SAVEFILE_read8(SRAM->isBonusMode); + bool isBonusMode = gameMode == GameMode::ARCADE && + SAVEFILE_bonusCount(_fs) > 0 && isHoldingStart; + bool isShuffleMode = + gameMode == GameMode::DEATH_MIX && (ENV_ARCADE || isHoldingStart); + bool isTransitioningBetweenCampaignAndChallenges = (lastGameMode == GameMode::CAMPAIGN && IS_CHALLENGE(gameMode)) || (IS_CHALLENGE(lastGameMode) && gameMode == GameMode::CAMPAIGN); - if ((lastGameMode != gameMode && - !isTransitioningBetweenCampaignAndChallenges) || - (gameMode == GameMode::ARCADE && lastGameMode == GameMode::ARCADE && - wasBonusMode != isBonusMode)) { - bool shouldResetCursor = - !(IS_STORY(lastGameMode) && gameMode == GameMode::ARCADE && - SAVEFILE_getMaxLibraryType() == - static_cast( - SAVEFILE_read8(SRAM->memory.difficultyLevel)) && - !isBonusMode); - - auto songIndex = IS_STORY(gameMode) ? SAVEFILE_getLibrarySize() - 1 : 0; + bool isTransitioningBetweenArcadeAndNonArcadeModes = + lastGameMode != gameMode && !isTransitioningBetweenCampaignAndChallenges; + bool isTransitioningBetweenBonusArcadeAndOtherMode = + wasBonusMode != isBonusMode; + + if (isTransitioningBetweenArcadeAndNonArcadeModes || + isTransitioningBetweenBonusArcadeAndOtherMode) { + bool arcadeAndCampaignUseTheSameLibrary = + SAVEFILE_getMaxLibraryType(true) == + static_cast( + SAVEFILE_read8(SRAM->memory.difficultyLevel)); + bool shouldKeepCursor = !isTransitioningBetweenBonusArcadeAndOtherMode && + arcadeAndCampaignUseTheSameLibrary; + + bool shouldResetCursor = !shouldKeepCursor; SAVEFILE_write8(SRAM->memory.numericLevel, 0); if (shouldResetCursor) { + auto songIndex = IS_STORY(gameMode) ? SAVEFILE_getLibrarySize() - 1 : 0; SAVEFILE_write8(SRAM->memory.pageIndex, Div(songIndex, PAGE_SIZE)); SAVEFILE_write8(SRAM->memory.songIndex, DivMod(songIndex, PAGE_SIZE)); } - SAVEFILE_write8(SRAM->adminSettings.arcadeCharts, ArcadeChartsOpts::SINGLE); } SAVEFILE_write8(SRAM->state.gameMode, gameMode); SAVEFILE_write8(SRAM->isBonusMode, false); + SAVEFILE_write8(SRAM->isShuffleMode, false); if (IS_MULTIPLAYER(gameMode)) { - linkUniversal->setProtocol(isHoldingStart + linkUniversal->setProtocol(isHoldingL ? LinkUniversal::Protocol::CABLE + : isHoldingR ? LinkUniversal::Protocol::WIRELESS_SERVER : LinkUniversal::Protocol::AUTODETECT); SEQUENCE_goToMultiplayerGameMode(gameMode); } else if (gameMode == GameMode::DEATH_MIX) { - goTo(new DeathMixScene(_engine, _fs)); + SAVEFILE_write8(SRAM->isShuffleMode, isShuffleMode); + goTo(new DeathMixScene(_engine, _fs, static_cast(isShuffleMode))); } else { SAVEFILE_write8(SRAM->isBonusMode, isBonusMode); @@ -323,6 +339,12 @@ void SEQUENCE_goToMessageOrSong(Song* song, Chart* chart, Chart* remoteChart) { void SEQUENCE_goToWinOrSelection(bool isLastSong) { auto gameMode = SAVEFILE_getGameMode(); + if (gameMode == GameMode::DEATH_MIX && GameState.isShuffleMode && + isLastSong) { + goTo(new DeathMixScene(_engine, _fs, MixMode::SHUFFLE)); + return; + } + if ((IS_STORY(gameMode) || gameMode == GameMode::DEATH_MIX) && isLastSong) goTo(new TalkScene( _engine, _fs, diff --git a/src/gameplay/SequenceMessages.h b/src/gameplay/SequenceMessages.h index 9d9be2bf..e31fd99f 100644 --- a/src/gameplay/SequenceMessages.h +++ b/src/gameplay/SequenceMessages.h @@ -46,9 +46,9 @@ #define MODE_IMPOSSIBLE \ "In IMPOSSIBLE MODE:\r\n" \ - "- Songs run FASTER\r\n" \ + "- Songs play FASTER\r\n" \ "- Patterns are MIRRORED\r\n" \ - "- Screen has visual MODS" + "- There are visual MODS" #define MODE_DEATH_MIX \ "In DEATHMIX MODE, you'll\r\n" \ @@ -56,6 +56,12 @@ "Life can't be recovered,\r\n" \ "so try not to MISS!" +#define MODE_SHUFFLE \ + "In SHUFFLE MODE, you'll\r\n" \ + "play a mixed nonstop set.\r\n" \ + "Pick a difficulty level\r\n" \ + "and have fun!" + #define KEYS_HINT \ "To change the speed, use:\r\n" \ " START/SELECT\r\n" \ @@ -68,10 +74,10 @@ "- Rate: B + START/SELECT\r\n" \ "- Seek: A + START/SELECT" -#define COOP_HINT \ - " CO-OP LEVEL\r\n" \ - "1) Get a friend.\r\n" \ - "2) Grab a Link Cable.\r\n" \ +#define COOP_HINT \ + " CO-OP LEVEL\r\n" \ + "1) Get a friend.\r\n" \ + "2) Grab a Link Adapter.\r\n" \ "3) Use Multi COOP." #define DOUBLE_PS2_INPUT_HINT \ @@ -93,7 +99,7 @@ " legend. Amazing work!" #define WIN_DEATHMIX \ - " WOAH, congratulations!\r\n" \ + " WHOA, congratulations!\r\n" \ " Ok, here's a secret:\r\n" \ "Try holding START when\r\n" \ "opening the ARCADE MODE!" diff --git a/src/gameplay/debug/DebugTools.h b/src/gameplay/debug/DebugTools.h index 78657a90..f9f225cc 100644 --- a/src/gameplay/debug/DebugTools.h +++ b/src/gameplay/debug/DebugTools.h @@ -1,6 +1,8 @@ #ifndef DEBUG_TOOLS_H #define DEBUG_TOOLS_H +#include +#include #include "utils/SceneUtils.h" extern "C" { @@ -64,33 +66,29 @@ inline void BSOD(std::string message) { player_stop(); SCENE_init(); BACKGROUND_enable(true, false, false, false); - TextStream::instance().setText(message, 0, -3); + TextStream::instance().setText(std::string("piuGBA - ") + + (ENV_ARCADE ? "arcade - " : "full - ") + + (ENV_DEVELOPMENT ? "dev" : "prod"), + 0, -3); + TextStream::instance().setText(message, 2, -3); while (true) ; } -inline void profileStart() { - REG_TM1CNT_L = 0; - REG_TM2CNT_L = 0; +inline vu16& _REG_LOG_ENABLE = *reinterpret_cast(0x4FFF780); +inline vu16& _REG_LOG_LEVEL = *reinterpret_cast(0x4FFF700); - REG_TM1CNT_H = 0; - REG_TM2CNT_H = 0; +static inline void log(const char* fmt, ...) { + _REG_LOG_ENABLE = 0xC0DE; - REG_TM2CNT_H = TM_ENABLE | TM_CASCADE; - REG_TM1CNT_H = TM_ENABLE | TM_FREQ_1; -} - -inline u32 profileStop() { - REG_TM1CNT_H = 0; - REG_TM2CNT_H = 0; + va_list args; + va_start(args, fmt); - return (REG_TM1CNT_L | (REG_TM2CNT_L << 16)); -} + char* const log = (char*)0x4FFF600; + vsnprintf(log, 0x100, fmt, args); + _REG_LOG_LEVEL = 0x102; // Level: WARN -inline u32 toMs(u32 cycles) { - // CPU Frequency * time per frame = cycles per frame - // 16780000 * (1/60) ~= 279666 - return (cycles * 1000) / (279666 * 60); + va_end(args); } #endif // DEBUG_TOOLS_H diff --git a/src/gameplay/debug/logDebugInfo.h b/src/gameplay/debug/logDebugInfo.h index 976820fd..265b92a5 100644 --- a/src/gameplay/debug/logDebugInfo.h +++ b/src/gameplay/debug/logDebugInfo.h @@ -37,7 +37,7 @@ void ChartReader::logDebugInfo() { u32 currentIndex = eventIndex; while (currentIndex < chart->eventCount) { Event* event = chart->events + currentIndex; - EventType type = static_cast((event->data & EVENT_TYPE)); + EventType type = static_cast((event->data() & EVENT_TYPE)); if (EVENT_HAS_PARAM(type)) break; currentIndex++; @@ -45,7 +45,7 @@ void ChartReader::logDebugInfo() { if (currentIndex < chart->eventCount) { Event* nextEvent = chart->events + currentIndex; - EventType type = static_cast((nextEvent->data & EVENT_TYPE)); + EventType type = static_cast((nextEvent->data() & EVENT_TYPE)); switch (type) { // case EventType::SET_TEMPO: @@ -65,7 +65,7 @@ void ChartReader::logDebugInfo() { } LOGSTR("EVENT:", 11); LOGSTR(typeStr, 12); - LOGN(nextEvent->timestamp, 13); + LOGN(nextEvent->timestamp(), 13); LOGSTR("-> " + DSTR(nextEvent->param), 14); } diff --git a/src/gameplay/models/Chart.h b/src/gameplay/models/Chart.h index cfc3324a..8ac1ce1f 100644 --- a/src/gameplay/models/Chart.h +++ b/src/gameplay/models/Chart.h @@ -3,6 +3,7 @@ #include +#include #include "Event.h" enum DifficultyLevel { NORMAL, HARD, CRAZY, NUMERIC }; @@ -29,6 +30,29 @@ typedef struct { // type == ChartType::DOUBLE_COOP_CHART int customOffset; u8 levelIndex; + + std::string getArcadeLevelString() { + if (difficulty == DifficultyLevel::NORMAL) + return "NM"; + + if (difficulty == DifficultyLevel::HARD) + return "HD"; + + if (difficulty == DifficultyLevel::CRAZY) + return "CZ"; + + if (type == ChartType::DOUBLE_COOP_CHART) + return ";)"; + + return ""; + } + + std::string getLevelString() { + return (type == ChartType::SINGLE_CHART ? "s" + : type == ChartType::DOUBLE_CHART ? "d" + : "m") + + (level == 99 ? "??" : std::to_string(level)); + } } Chart; #endif // CHART_H diff --git a/src/gameplay/models/Event.h b/src/gameplay/models/Event.h index 2609e19b..5355bf64 100644 --- a/src/gameplay/models/Event.h +++ b/src/gameplay/models/Event.h @@ -68,10 +68,10 @@ inline bool EVENT_HAS_PARAM3(EventType event) { typedef struct { // (PIUS file) - // u32 timestampAndData; + u32 timestampAndData; /* { [bit 0] is fake (only note types) - [bits 1-23] timestamp (signed int) + [bits 1-23] timestamp (signed int, ms) [bits 24-26] type (see EventType) [bits 27-31] data (5-bit array with the arrows) } @@ -86,14 +86,19 @@ typedef struct { // custom fields: bool handled[GAME_MAX_PLAYERS]; - bool isFake; - int timestamp; // in ms - u8 data; - /* { - [bits 0-2] type (see EventType) - [bits 3-7] data (5-bit array with the arrows) - } - */ + + inline int timestamp() { + int timestamp = (timestampAndData >> 1) & 0x7fffff; + if (timestamp & 0x400000) // (sign extension) + timestamp |= 0xff800000; + return timestamp; + } + + inline u8 data() { return (timestampAndData >> 24) & 0xff; } + inline bool isFake() { return timestampAndData & 1; } + + u32 bpm() { return param & 0b1111111111111111111; } + u32 beatDurationFrames() { return (param >> 20) & 0b111111111111; } } Event; #endif // EVENT_H diff --git a/src/gameplay/models/Song.cpp b/src/gameplay/models/Song.cpp index acb53f9d..648c4401 100644 --- a/src/gameplay/models/Song.cpp +++ b/src/gameplay/models/Song.cpp @@ -11,7 +11,7 @@ const u32 MESSAGE_LEN = 107; #define DATA_EWRAM __attribute__((section(".ewram"))) #define MAX_EVENTS 3250 #define ALLOCATION_SIZE (MAX_EVENTS * sizeof(Event)) -// (78000 bytes) -> (3250)*24 +// (65000 bytes) -> (3250)*20 typedef struct { Event events[MAX_EVENTS]; @@ -166,6 +166,16 @@ u32 SONG_findChartIndexByDifficultyLevel(Song* song, return 0; } +int SONG_findSingleChartIndexByNumericLevel(Song* song, u8 numericLevel) { + for (u32 i = 0; i < song->chartCount; i++) { + if (song->charts[i].type == ChartType::SINGLE_CHART && + song->charts[i].level == numericLevel) + return i; + } + + return -1; +} + Chart* SONG_findChartByDifficultyLevel(Song* song, DifficultyLevel difficultyLevel) { u32 index = SONG_findChartIndexByDifficultyLevel(song, difficultyLevel); @@ -218,14 +228,9 @@ void parseEvents(Event* events, for (u32 j = 0; j < count; j++) { auto event = events + j; - u32 timestampAndData = parse_u32le(data, cursor); - event->isFake = timestampAndData & 1; - event->timestamp = (timestampAndData >> 1) & 0x7fffff; - if (event->timestamp & 0x400000) // (sign extension) - event->timestamp |= 0xff800000; - event->data = (timestampAndData >> 24) & 0xff; + event->timestampAndData = parse_u32le(data, cursor); - auto eventType = static_cast(event->data & EVENT_TYPE); + auto eventType = static_cast(event->data() & EVENT_TYPE); event->data2 = EVENT_HAS_DATA2(eventType, isDouble) ? parse_u8(data, cursor) : 0; diff --git a/src/gameplay/models/Song.h b/src/gameplay/models/Song.h index db457973..01587d00 100644 --- a/src/gameplay/models/Song.h +++ b/src/gameplay/models/Song.h @@ -61,6 +61,7 @@ Channel SONG_getChannel(const GBFS_FILE* fs, DifficultyLevel difficultyLevel); u32 SONG_findChartIndexByDifficultyLevel(Song* song, DifficultyLevel difficultyLevel); +int SONG_findSingleChartIndexByNumericLevel(Song* song, u8 numericLevel); Chart* SONG_findChartByDifficultyLevel(Song* song, DifficultyLevel difficultyLevel); u32 SONG_findChartIndexByNumericLevelIndex(Song* song, diff --git a/src/gameplay/multiplayer/PS2Keyboard.h b/src/gameplay/multiplayer/PS2Keyboard.h index 9ab72081..0bd04d0f 100644 --- a/src/gameplay/multiplayer/PS2Keyboard.h +++ b/src/gameplay/multiplayer/PS2Keyboard.h @@ -32,7 +32,7 @@ #define PS2_KEY_UP 117 // Up #define PS2_KEY_DOWN 114 // Down #define PS2_KEY_ESC 118 // ESC -#define PS2_KEY_SUPR 113 // Supr +#define PS2_KEY_DELETE 113 // Delete #define PS2_KEY_RELEASE 240 #define PS2_KEY_SPECIAL 224 @@ -41,16 +41,26 @@ class PS2Keyboard { public: - bool arrows[10]; - bool start1, start2, select1, select2, left, right, up, down; - bool softReset = false; + struct Keys { + bool arrows[10]; + bool start1, start2, select1, select2, left, right, up, down; + bool softReset = false; + + void reset() { + for (u32 i = 0; i < 10; i++) + arrows[i] = false; + start1 = start2 = select1 = select2 = left = right = up = down = false; + } + }; + Keys keys; + Keys nextKeys; bool any() { for (u32 i = 0; i < 10; i++) - if (arrows[i]) + if (keys.arrows[i]) return true; - return start1 || start2 || select1 || select2 || left || right || up || - down; + return keys.start1 || keys.start2 || keys.select1 || keys.select2 || + keys.left || keys.right || keys.up || keys.down; } bool isActive() { return isEnabled; } @@ -65,6 +75,8 @@ class PS2Keyboard { reset(); } + void update() { keys = nextKeys; } + void _onVBlank() { if (!isEnabled) return; @@ -87,59 +99,62 @@ class PS2Keyboard { bool process(u8 scanCode) { switch (scanCode) { case PS2_KEY_P1_DOWNLEFT: - return assign(arrows[0]); + return assign(keys.arrows[0], nextKeys.arrows[0]); case PS2_KEY_P1_UPLEFT: - return assign(arrows[1]); + return assign(keys.arrows[1], nextKeys.arrows[1]); case PS2_KEY_P1_CENTER: - return assign(arrows[2]); + return assign(keys.arrows[2], nextKeys.arrows[2]); case PS2_KEY_P1_UPRIGHT: - return assign(arrows[3]); + return assign(keys.arrows[3], nextKeys.arrows[3]); case PS2_KEY_P1_DOWNRIGHT: - return assign(arrows[4]); + return assign(keys.arrows[4], nextKeys.arrows[4]); case PS2_KEY_P2_DOWNLEFT: - return assign(arrows[5]); + return assign(keys.arrows[5], nextKeys.arrows[5]); case PS2_KEY_P2_UPLEFT: - return assign(arrows[6]); + return assign(keys.arrows[6], nextKeys.arrows[6]); case PS2_KEY_P2_CENTER: - return assign(arrows[7]); + return assign(keys.arrows[7], nextKeys.arrows[7]); case PS2_KEY_P2_UPRIGHT: - return assign(arrows[8]); + return assign(keys.arrows[8], nextKeys.arrows[8]); case PS2_KEY_P2_DOWNRIGHT: - return assign(arrows[9]); + return assign(keys.arrows[9], nextKeys.arrows[9]); case PS2_KEY_START_1: - return assign(start1); + return assign(keys.start1, nextKeys.start1); case PS2_KEY_START_2: - return assign(start2); + return assign(keys.start2, nextKeys.start2); case PS2_KEY_SELECT_1: - return assign(select1); + return assign(keys.select1, nextKeys.select1); case PS2_KEY_SELECT_2: - return assign(select2); + return assign(keys.select2, nextKeys.select2); case PS2_KEY_LEFT: if (isSpecial) - return assign(left); + return assign(keys.left, nextKeys.left); else break; case PS2_KEY_RIGHT: if (isSpecial) - return assign(right); + return assign(keys.right, nextKeys.right); else break; case PS2_KEY_UP: if (isSpecial) - return assign(up); + return assign(keys.up, nextKeys.up); else break; case PS2_KEY_DOWN: if (isSpecial) - return assign(down); + return assign(keys.down, nextKeys.down); else break; case PS2_KEY_ESC: { - return (softReset = true); + keys.softReset = true; + nextKeys.softReset = true; + return true; } - case PS2_KEY_SUPR: { + case PS2_KEY_DELETE: { if (isSpecial) { - softReset = true; + keys.softReset = true; + nextKeys.softReset = true; return true; } else break; @@ -160,17 +175,18 @@ class PS2Keyboard { return false; } - bool assign(bool& output) { - output = !isRelease; + bool assign(bool& output, bool& nextOutput) { + if (!isRelease) + output = true; + nextOutput = !isRelease; isRelease = false; isSpecial = false; return true; } void reset() { - for (u32 i = 0; i < 10; i++) - arrows[i] = false; - start1 = start2 = select1 = select2 = left = right = up = false; + keys.reset(); + nextKeys.reset(); bitcount = 0; incoming = 0; diff --git a/src/gameplay/multiplayer/Syncer.cpp b/src/gameplay/multiplayer/Syncer.cpp index 52f66b87..a7720a1f 100644 --- a/src/gameplay/multiplayer/Syncer.cpp +++ b/src/gameplay/multiplayer/Syncer.cpp @@ -74,7 +74,12 @@ void Syncer::send(u8 event, u16 payload) { } void Syncer::directSend(u16 data) { - linkUniversal->send(data); + if (data == LINK_CABLE_DISCONNECTED || data == LINK_CABLE_NO_DATA) + return; + + bool success = false; + while (!success && linkUniversal->isConnectedAny()) + success = linkUniversal->send(data); } void Syncer::registerTimeout() { @@ -209,10 +214,16 @@ void Syncer::resetGameState() { $libraryType = 0; $completedSongs = 0; + $remoteNumericLevelIndex = -1; $remoteNumericLevel = -1; + $remoteLastNumericLevel = 0; SAVEFILE_write8(SRAM->memory.numericLevel, 0); SAVEFILE_write8(SRAM->memory.pageIndex, 0); SAVEFILE_write8(SRAM->memory.songIndex, 0); + SAVEFILE_write32(SRAM->lastNumericLevel, 0); + SAVEFILE_write8( + SRAM->adminSettings.arcadeCharts, + isCoop() ? ArcadeChartsOpts::DOUBLE : ArcadeChartsOpts::SINGLE); resetSongState(); } diff --git a/src/gameplay/multiplayer/Syncer.h b/src/gameplay/multiplayer/Syncer.h index dd77f8b7..f32ee7d3 100644 --- a/src/gameplay/multiplayer/Syncer.h +++ b/src/gameplay/multiplayer/Syncer.h @@ -5,6 +5,7 @@ #include #include +#include #include "Protocol.h" #include "gameplay/debug/DebugTools.h" #include "gameplay/save/SaveFile.h" @@ -19,10 +20,6 @@ // Number of timer ticks (61.04μs) between messages (100 = 6,104ms) #define SYNC_SEND_INTERVAL 100 -// Max 0xFFFF messages before marking remote player as disconnected -// (Not relevant for 2-player games) -#define SYNC_REMOTE_TIMEOUT 16 - enum SyncState { SYNC_STATE_SEND_ROM_ID, SYNC_STATE_SEND_PROGRESS, @@ -61,7 +58,9 @@ class Syncer { public: u8 $libraryType = 0; u8 $completedSongs = 0; + int $remoteNumericLevelIndex = -1; int $remoteNumericLevel = -1; + int $remoteLastNumericLevel = 0; bool $isPlayingSong = false; bool $hasStartedAudio = false; bool $resetFlag = false; @@ -87,6 +86,7 @@ class Syncer { } inline SyncMode getMode() { return mode; } + inline bool isOnline() { return mode > SyncMode::SYNC_MODE_OFFLINE; } void initialize(SyncMode mode); void update(); @@ -96,6 +96,11 @@ class Syncer { void clearTimeout(); void resetSongState(); + void setRemoteNumericLevel(int newIndex, int newLevel) { + $remoteNumericLevelIndex = newIndex; + $remoteNumericLevel = newLevel; + } + private: SyncState state = SyncState::SYNC_STATE_SEND_ROM_ID; SyncMode mode = SyncMode::SYNC_MODE_OFFLINE; @@ -121,6 +126,13 @@ class Syncer { void resetData(); void resetGameState(); void resetError(); + + public: + // --- + // HACK: This doesn't belong here. + // Used by SelectionScene to delay music playback until render finishes + std::string pendingAudio = ""; + u32 pendingSeek = 0; }; extern Syncer* syncer; diff --git a/src/gameplay/save/AdminSettings.h b/src/gameplay/save/AdminSettings.h index 263ab09d..6e09b8f5 100644 --- a/src/gameplay/save/AdminSettings.h +++ b/src/gameplay/save/AdminSettings.h @@ -16,13 +16,7 @@ enum SRAMBlinkOpts : u8 { SRAM_BLINK_ON_HIT }; enum NavigationStyleOpts : u8 { PIU, GBA }; -enum BackgroundVideosOpts { - dOFF, - dACTIVATING, - dACTIVE, - dVIDEO_ONLY, - dAUDIO_ONLY -}; +enum HQModeOpts : u8 { dOFF, dACTIVATING, dACTIVE, dVIDEO_ONLY, dAUDIO_ONLY }; #define RUMBLE_PREROLL(OPTS) (((OPTS) >> 4) & 0b1111) #define RUMBLE_IDLE(OPTS) (((OPTS) >> 0) & 0b1111) @@ -36,7 +30,7 @@ typedef struct __attribute__((__packed__)) { SRAMBlinkOpts sramBlink; NavigationStyleOpts navigationStyle; bool offsetEditingEnabled; - BackgroundVideosOpts backgroundVideos; + HQModeOpts hqMode; bool ewramOverclock; bool ps2Input; u8 rumbleFrames; diff --git a/src/gameplay/save/SaveFile.h b/src/gameplay/save/SaveFile.h index 47f68f28..e689b4fb 100644 --- a/src/gameplay/save/SaveFile.h +++ b/src/gameplay/save/SaveFile.h @@ -13,6 +13,7 @@ #include "Progress.h" #include "Settings.h" #include "State.h" +#include "Stats.h" #include "assets.h" #include "gameplay/debug/DebugTools.h" #include "gameplay/models/Chart.h" @@ -35,8 +36,9 @@ typedef struct __attribute__((__packed__)) { u32 romId; Settings settings; - char padding[5]; - u32 globalOffset; + char padding[1]; + u32 lastNumericLevel; // (*) (memory) (high 16bit: type; low 16bit: level) + u32 globalOffset; // (*) (adminSettings) Memory memory; Progress progress[PROGRESS_REGISTERS]; @@ -47,16 +49,22 @@ typedef struct __attribute__((__packed__)) { AdminSettings adminSettings; - bool isBonusMode; - u32 randomSeed; + bool isBonusMode; // (*) state + u32 randomSeed; // (*) state u8 beat; Mods mods; - char padding3[4]; - + char padding3[3]; + bool isShuffleMode; // (*) state DeathMixProgress deathMixProgress; - s8 customOffsets[CUSTOM_OFFSET_TABLE_SIZE]; + s8 customOffsets[CUSTOM_OFFSET_TABLE_TOTAL_SIZE]; + + char padding4[10]; + Stats stats; + + // (*) these properties shouldn't be at the root level, but we'll leave them + // there because it's important to maintain save file compatibility } SaveFile; #define SRAM ((SaveFile*)sram_mem) @@ -68,11 +76,13 @@ typedef struct __attribute__((__packed__)) { (*(((volatile char*)&TARGET) + 1) << 8) + \ (*(((volatile char*)&TARGET) + 2) << 16) + \ (*(((volatile char*)&TARGET) + 3) << 24))) -#define SAVEFILE_write32(DEST, VALUE) \ - *(((volatile char*)&DEST) + 0) = (((u32)(VALUE)) & 0x000000ff) >> 0; \ - *(((volatile char*)&DEST) + 1) = (((u32)(VALUE)) & 0x0000ff00) >> 8; \ - *(((volatile char*)&DEST) + 2) = (((u32)(VALUE)) & 0x00ff0000) >> 16; \ - *(((volatile char*)&DEST) + 3) = (((u32)(VALUE)) & 0xff000000) >> 24; +#define SAVEFILE_write32(DEST, VALUE) \ + do { \ + *(((volatile char*)&DEST) + 0) = (((u32)(VALUE)) & 0x000000ff) >> 0; \ + *(((volatile char*)&DEST) + 1) = (((u32)(VALUE)) & 0x0000ff00) >> 8; \ + *(((volatile char*)&DEST) + 2) = (((u32)(VALUE)) & 0x00ff0000) >> 16; \ + *(((volatile char*)&DEST) + 3) = (((u32)(VALUE)) & 0xff000000) >> 24; \ + } while (false); inline void SAVEFILE_resetSettings() { SAVEFILE_write32(SRAM->settings.audioLag, 0); @@ -98,9 +108,9 @@ inline void SAVEFILE_resetMods() { } inline void SAVEFILE_resetRumble() { - u8 rumbleOpts = RUMBLE_OPTS_BUILD(2, 5); + u8 rumbleOpts = RUMBLE_OPTS_BUILD(2, 0); - SAVEFILE_write8(SRAM->adminSettings.rumbleFrames, 4); + SAVEFILE_write8(SRAM->adminSettings.rumbleFrames, 10); SAVEFILE_write8(SRAM->adminSettings.rumbleOpts, rumbleOpts); } @@ -112,19 +122,28 @@ inline void SAVEFILE_resetAdminSettings() { SAVEFILE_write8(SRAM->adminSettings.navigationStyle, NavigationStyleOpts::GBA); SAVEFILE_write8(SRAM->adminSettings.offsetEditingEnabled, false); - SAVEFILE_write8(SRAM->adminSettings.backgroundVideos, - BackgroundVideosOpts::dOFF); + SAVEFILE_write8(SRAM->adminSettings.hqMode, HQModeOpts::dOFF); SAVEFILE_write8(SRAM->adminSettings.ewramOverclock, false); SAVEFILE_write8(SRAM->adminSettings.ps2Input, false); SAVEFILE_write32(SRAM->globalOffset, 0); SAVEFILE_resetRumble(); #ifdef SENV_DEVELOPMENT + SAVEFILE_write8(SRAM->adminSettings.rumble, RumbleOpts::rNO_RUMBLE); SAVEFILE_write8(SRAM->adminSettings.navigationStyle, NavigationStyleOpts::PIU); #endif } +inline void SAVEFILE_resetStats() { + SAVEFILE_write32(SRAM->stats.playTimeSeconds, 0); + SAVEFILE_write32(SRAM->stats.stagePasses, 0); + SAVEFILE_write32(SRAM->stats.stageBreaks, 0); + SAVEFILE_write32(SRAM->stats.sGrades, 0); + SAVEFILE_write32(SRAM->stats.maxCombo, 0); + SAVEFILE_write32(SRAM->stats.highestLevel, 0); +} + inline u32 SAVEFILE_normalize(u32 librarySize) { u32 fixes = 0; @@ -202,18 +221,17 @@ inline u32 SAVEFILE_normalize(u32 librarySize) { u8 navigationStyle = SAVEFILE_read8(SRAM->adminSettings.navigationStyle); u8 offsetEditingEnabled = SAVEFILE_read8(SRAM->adminSettings.offsetEditingEnabled); - u8 backgroundVideos = SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); + u8 hqMode = SAVEFILE_read8(SRAM->adminSettings.hqMode); u8 ewramOverclock = SAVEFILE_read8(SRAM->adminSettings.ewramOverclock); u8 ps2Input = SAVEFILE_read8(SRAM->adminSettings.ps2Input); u8 rumbleFrames = SAVEFILE_read8(SRAM->adminSettings.rumbleFrames); u8 rumbleOpts = SAVEFILE_read8(SRAM->adminSettings.rumbleOpts); int globalOffset = (int)SAVEFILE_read32(SRAM->globalOffset); if (arcadeCharts >= 2 || rumble >= 3 || ioBlink >= 3 || sramBlink >= 3 || - navigationStyle >= 2 || offsetEditingEnabled >= 2 || - backgroundVideos >= 5 || ewramOverclock >= 2 || ps2Input >= 2 || - rumbleFrames == 0 || rumbleFrames >= 9 || - RUMBLE_PREROLL(rumbleOpts) == 0 || RUMBLE_PREROLL(rumbleOpts) >= 9 || - RUMBLE_IDLE(rumbleOpts) <= 1 || RUMBLE_IDLE(rumbleOpts) >= 7 || + navigationStyle >= 2 || offsetEditingEnabled >= 2 || hqMode >= 5 || + ewramOverclock >= 2 || ps2Input >= 2 || rumbleFrames == 0 || + rumbleFrames >= 13 || RUMBLE_PREROLL(rumbleOpts) == 0 || + RUMBLE_PREROLL(rumbleOpts) >= 13 || RUMBLE_IDLE(rumbleOpts) >= 7 || globalOffset < -3000 || globalOffset > 3000 || (globalOffset & 7) != 0) { SAVEFILE_resetAdminSettings(); fixes |= 0b100000; @@ -264,9 +282,26 @@ inline u32 SAVEFILE_normalize(u32 librarySize) { fixes |= 0b1000000000; } + // validate stats + u32 maxCombo = SAVEFILE_read32(SRAM->stats.maxCombo); + u32 highestLevel = SAVEFILE_read32(SRAM->stats.highestLevel); + if (maxCombo > 9999 || (highestLevel & 0xff) >= 99 || + ((highestLevel >> 16) & 0xff) > 2) { + SAVEFILE_resetStats(); + fixes |= 0b10000000000; + } + + // quick fixes + u32 lastNumericLevel = SAVEFILE_read32(SRAM->lastNumericLevel); u8 isBonusMode = SAVEFILE_read8(SRAM->isBonusMode); + u8 isShuffleMode = SAVEFILE_read8(SRAM->isShuffleMode); if (isBonusMode >= 2) SAVEFILE_write8(SRAM->isBonusMode, false); + if (isShuffleMode >= 2) + SAVEFILE_write8(SRAM->isShuffleMode, false); + if ((lastNumericLevel & 0xff) > 99 || ((lastNumericLevel >> 16) & 0xff) > 2) { + SAVEFILE_write32(SRAM->lastNumericLevel, 0); + } if (fixes > 0) { // if something was fixed, reset custom offset, just in case @@ -316,6 +351,12 @@ inline u32 SAVEFILE_initialize(const GBFS_FILE* fs) { ARCADE_initialize(); OFFSET_initialize(); SAVEFILE_resetAdminSettings(); + SAVEFILE_resetStats(); + + SAVEFILE_write32(SRAM->lastNumericLevel, 0); + SAVEFILE_write8(SRAM->isBonusMode, false); + SAVEFILE_write8(SRAM->isShuffleMode, false); + SAVEFILE_write32(SRAM->randomSeed, 0); SAVEFILE_write8( SRAM->deathMixProgress.completedSongs[DifficultyLevel::NORMAL], 0); @@ -388,7 +429,7 @@ inline bool SAVEFILE_isModeUnlocked(GameMode gameMode) { gameMode == GameMode::MULTI_COOP) return maxCompletedSongs >= 1; - if (gameMode == GameMode::IMPOSSIBLE) + if (gameMode == GameMode::IMPOSSIBLE || gameMode == GameMode::DEATH_MIX) return maxCompletedSongs >= SAVEFILE_getLibrarySize(); return true; @@ -414,13 +455,16 @@ inline bool SAVEFILE_didComplete(GameMode gameMode, return completedSongs >= librarySize; } -inline DifficultyLevel SAVEFILE_getMaxLibraryType() { +inline DifficultyLevel SAVEFILE_getMaxLibraryType(bool campaignOnly = false) { DifficultyLevel maxLevel = DifficultyLevel::NORMAL; u32 max = 0; for (u32 i = 0; i < MAX_DIFFICULTY + 1; i++) { auto difficultyLevel = static_cast(i); - auto completedSongs = SAVEFILE_getCompletedSongsOf(difficultyLevel); + auto completedSongs = + campaignOnly + ? SAVEFILE_getCompletedSongsOf(GameMode::CAMPAIGN, difficultyLevel) + : SAVEFILE_getCompletedSongsOf(difficultyLevel); if (completedSongs >= max) { maxLevel = difficultyLevel; @@ -431,9 +475,9 @@ inline DifficultyLevel SAVEFILE_getMaxLibraryType() { return maxLevel; } -inline GradeType SAVEFILE_getStoryGradeOf(u8 songIndex, DifficultyLevel level) { - auto gameMode = SAVEFILE_getGameMode(); - +inline GradeType SAVEFILE_getStoryGradeOf(GameMode gameMode, + u8 songIndex, + DifficultyLevel level) { u32 index = (gameMode == GameMode::IMPOSSIBLE) * PROGRESS_IMPOSSIBLE + level; int lastIndex = SAVEFILE_read8(SRAM->progress[index].completedSongs) - 1; if (songIndex > lastIndex) @@ -443,6 +487,11 @@ inline GradeType SAVEFILE_getStoryGradeOf(u8 songIndex, DifficultyLevel level) { SAVEFILE_read8(SRAM->progress[index].grades[songIndex])); } +inline GradeType SAVEFILE_getStoryGradeOf(u8 songIndex, DifficultyLevel level) { + auto gameMode = SAVEFILE_getGameMode(); + return SAVEFILE_getStoryGradeOf(gameMode, songIndex, level); +} + inline GradeType SAVEFILE_getArcadeGradeOf(u8 songId, u8 numericLevelIndex) { return SAVEFILE_isPlayingDouble() ? ARCADE_readDouble(songId, numericLevelIndex) @@ -503,6 +552,10 @@ inline bool SAVEFILE_setGradeOf(u8 songIndex, if (firstTime || grade < currentGrade) SAVEFILE_write8(SRAM->progress[index].grades[songIndex], grade); + u8 currentArcadeGrade = ARCADE_readSingle(songId, numericLevelIndex); + if (grade < currentArcadeGrade) + ARCADE_writeSingle(songId, numericLevelIndex, grade); + return songIndex == SAVEFILE_getLibrarySize() - 1; } { diff --git a/src/gameplay/save/State.cpp b/src/gameplay/save/State.cpp index db497cbd..0432f067 100644 --- a/src/gameplay/save/State.cpp +++ b/src/gameplay/save/State.cpp @@ -11,6 +11,9 @@ void STATE_setup(Song* song, Chart* chart) { gameMode = GameMode::ARCADE; GameState.mode = gameMode; + GameState.isShuffleMode = + gameMode == DEATH_MIX && + (ENV_ARCADE || SAVEFILE_read8(SRAM->isShuffleMode) == 1); GameState.settings.audioLag = SAVEFILE_read32(SRAM->settings.audioLag); GameState.settings.gamePosition = static_cast(SAVEFILE_read8(SRAM->settings.gamePosition)); diff --git a/src/gameplay/save/State.h b/src/gameplay/save/State.h index 0f06edca..e77892a3 100644 --- a/src/gameplay/save/State.h +++ b/src/gameplay/save/State.h @@ -32,6 +32,7 @@ typedef struct { AdminSettings adminSettings; Mods mods; GameMode mode; + bool isShuffleMode; } RAMState; extern RAMState GameState; diff --git a/src/gameplay/save/Stats.h b/src/gameplay/save/Stats.h new file mode 100644 index 00000000..8a642f3a --- /dev/null +++ b/src/gameplay/save/Stats.h @@ -0,0 +1,15 @@ +#ifndef STATS_H +#define STATS_H + +#include + +typedef struct __attribute__((__packed__)) { + u32 playTimeSeconds; + u32 stagePasses; + u32 stageBreaks; + u32 sGrades; + u32 maxCombo; + u32 highestLevel; +} Stats; + +#endif // STATS_H diff --git a/src/gameplay/video/VideoStore.cpp b/src/gameplay/video/VideoStore.cpp index 1da00ec3..2dde5902 100644 --- a/src/gameplay/video/VideoStore.cpp +++ b/src/gameplay/video/VideoStore.cpp @@ -24,29 +24,26 @@ const u32 FRACUMUL_MS_TO_FRAME_AT_30FPS = 128849018; // (*30/1000) DATA_EWRAM static FATFS fatfs; DATA_EWRAM static FIL file; -BackgroundVideosOpts getMode() { - return static_cast( - SAVEFILE_read8(SRAM->adminSettings.backgroundVideos)); +HQModeOpts getMode() { + return static_cast(SAVEFILE_read8(SRAM->adminSettings.hqMode)); } bool VideoStore::isEnabled() { - return SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); + return SAVEFILE_read8(SRAM->adminSettings.hqMode); } bool VideoStore::isActivating() { - return getMode() == BackgroundVideosOpts::dACTIVATING; + return getMode() == HQModeOpts::dACTIVATING; } void VideoStore::disable() { - SAVEFILE_write8(SRAM->adminSettings.backgroundVideos, - BackgroundVideosOpts::dOFF); + SAVEFILE_write8(SRAM->adminSettings.hqMode, HQModeOpts::dOFF); } VideoStore::State VideoStore::activate() { setState(OFF); auto previousMode = getMode(); - SAVEFILE_write8(SRAM->adminSettings.backgroundVideos, - BackgroundVideosOpts::dACTIVATING); + SAVEFILE_write8(SRAM->adminSettings.hqMode, HQModeOpts::dACTIVATING); auto result = flashcartio_activate(); if (result != FLASHCART_ACTIVATED) { @@ -61,10 +58,9 @@ VideoStore::State VideoStore::activate() { return setState(MOUNT_ERROR); } - SAVEFILE_write8(SRAM->adminSettings.backgroundVideos, - previousMode > BackgroundVideosOpts::dACTIVE - ? previousMode - : BackgroundVideosOpts::dACTIVE); + SAVEFILE_write8(SRAM->adminSettings.hqMode, previousMode > HQModeOpts::dACTIVE + ? previousMode + : HQModeOpts::dACTIVE); setState(ACTIVE, &fatfs); return state; @@ -74,7 +70,7 @@ VideoStore::LoadResult VideoStore::load(std::string videoPath, int videoOffset) { if (state != ACTIVE) return LoadResult::NO_FILE; - if (getMode() == BackgroundVideosOpts::dAUDIO_ONLY) + if (getMode() == HQModeOpts::dAUDIO_ONLY) return LoadResult::NO_FILE; memory = getSecondaryMemory(REQUIRED_MEMORY); @@ -164,7 +160,7 @@ CODE_IWRAM bool VideoStore::endRead(u8* buffer, u32 sectors) { VideoStore::State VideoStore::setState(State newState, void* fatfs) { state = newState; - PlaybackState.isPCMDisabled = getMode() == BackgroundVideosOpts::dVIDEO_ONLY; + PlaybackState.isPCMDisabled = getMode() == HQModeOpts::dVIDEO_ONLY; PlaybackState.fatfs = fatfs; return newState; } diff --git a/src/main.cpp b/src/main.cpp index f378297a..69c7286d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,8 +21,11 @@ const char* SAVEFILE_TYPE_HINT = "SRAM_Vnnn\0\0"; void validateBuild(); void setUpInterrupts(); +void startRandomSeed(); +void stopRandomSeed(); void synchronizeSongStart(); static std::shared_ptr engine{new GBAEngine()}; +static bool isCalculatingRandomSeed = false; VideoStore* videoStore = new VideoStore(); PS2Keyboard* ps2Keyboard = new PS2Keyboard(); LinkUniversal* linkUniversal = @@ -31,22 +34,21 @@ LinkUniversal* linkUniversal = (LinkUniversal::CableOptions){ .baudRate = LinkCable::BAUD_RATE_1, .timeout = SYNC_IRQ_TIMEOUT, - .remoteTimeout = SYNC_REMOTE_TIMEOUT, .interval = SYNC_SEND_INTERVAL, .sendTimerId = LINK_CABLE_DEFAULT_SEND_TIMER_ID}, (LinkUniversal::WirelessOptions){ .retransmission = true, .maxPlayers = 2, .timeout = SYNC_IRQ_TIMEOUT, - .remoteTimeout = SYNC_REMOTE_TIMEOUT, .interval = SYNC_SEND_INTERVAL, - .sendTimerId = LINK_WIRELESS_DEFAULT_SEND_TIMER_ID, - .asyncACKTimerId = 2}); + .sendTimerId = LINK_WIRELESS_DEFAULT_SEND_TIMER_ID}, + __qran_seed); Syncer* syncer = new Syncer(); static const GBFS_FILE* fs = find_first_gbfs_file(0); int main() { linkUniversal->deactivate(); + RUMBLE_init(); REG_WAITCNT = 0x4317; // (3,1 waitstates, prefetch ON) @@ -54,6 +56,7 @@ int main() { setUpInterrupts(); player_init(); SEQUENCE_initialize(engine, fs); + startRandomSeed(); engine->setScene(SEQUENCE_getInitialScene()); player_forever( @@ -65,6 +68,12 @@ int main() { syncer->update(); engine->update(); + if (isCalculatingRandomSeed) { + (void)qran(); + if ((~REG_KEYS & KEY_ANY) != 0) + stopRandomSeed(); + } + if (syncer->$isPlayingSong && !syncer->$hasStartedAudio) synchronizeSongStart(); @@ -74,11 +83,23 @@ int main() { }, []() { // (onRender) - if (ps2Keyboard->softReset) + ps2Keyboard->update(); + if (ps2Keyboard->keys.softReset) SCENE_softReset(); EFFECT_render(); engine->render(); + + if (syncer->pendingAudio != "") { + player_play(syncer->pendingAudio.c_str(), + isMultiplayer() || active_flashcart == EZ_FLASH_OMEGA); + syncer->pendingAudio = ""; + } + + if (syncer->pendingSeek > 0) { + player_seek(syncer->pendingSeek); + syncer->pendingSeek = 0; + } }, [](u32 current) { // (onAudioChunk) @@ -106,7 +127,7 @@ CODE_EWRAM void ISR_reset() { syncer->$resetFlag = true; return; } - if (syncer->isPlaying()) + if (syncer->isOnline()) return; SCENE_softReset(); @@ -132,16 +153,28 @@ void setUpInterrupts() { interrupt_set_handler(INTR_TIMER3, LINK_UNIVERSAL_ISR_TIMER); interrupt_enable(INTR_TIMER3); - // LinkWireless async-ACK - interrupt_set_handler(INTR_TIMER2, LINK_UNIVERSAL_ISR_ACK_TIMER); - interrupt_enable(INTR_TIMER2); - // A+B+START+SELECT REG_KEYCNT = 0b1100000000001111; interrupt_set_handler(INTR_KEYPAD, ISR_reset); interrupt_enable(INTR_KEYPAD); } +inline void startRandomSeed() { + isCalculatingRandomSeed = true; + REG_TM2CNT_L = 0; + REG_TM2CNT_H = 0; + REG_TM2CNT_H = TM_ENABLE | TM_FREQ_1; +} + +inline void stopRandomSeed() { + isCalculatingRandomSeed = false; + + REG_TM2CNT_H = 0; + __qran_seed += SAVEFILE_read32(SRAM->randomSeed); + __qran_seed += (1 + (~REG_KEYS & KEY_ANY)) * 1664525 * REG_TM2CNT_L; + SAVEFILE_write32(SRAM->randomSeed, __qran_seed); +} + void synchronizeSongStart() { // discard all previous messages and wait for sync u8 remoteId = syncer->getRemotePlayerId(); diff --git a/src/objects/Digit.cpp b/src/objects/Digit.cpp index e44db24e..606b3615 100644 --- a/src/objects/Digit.cpp +++ b/src/objects/Digit.cpp @@ -10,28 +10,28 @@ #include "gameplay/save/SaveFile.h" #include "utils/SpriteUtils.h" -const u32 DIGIT_WIDTHS[] = {26, 19}; -const u32 RED_OFFSET = 10; +const u32 DIGIT_WIDTHS[] = {26, 19, 13}; +const u32 TOTAL_NUMBERS = 10; Digit::Digit(DigitSize size, u32 x, u32 y, u32 index, bool reuseTiles) { - relocate(size, x, y, index); + this->modern = SAVEFILE_isUsingModernTheme(); + this->size = size; + this->currentIndex = index; + reloadPosition(x, y, DIGIT_WIDTHS[size]); animationDirection = -1; SpriteBuilder builder; sprite = builder - .withData( - size == DigitSize::BIG - ? (SAVEFILE_isUsingModernTheme() ? spr_numbers_mdrnTiles - : spr_numbersTiles) - : (SAVEFILE_isUsingModernTheme() ? spr_numbers_mini_mdrnTiles - : spr_numbers_miniTiles), - size == DigitSize::BIG ? (SAVEFILE_isUsingModernTheme() - ? sizeof(spr_numbers_mdrnTiles) - : sizeof(spr_numbersTiles)) - : (SAVEFILE_isUsingModernTheme() - ? sizeof(spr_numbers_mini_mdrnTiles) - : sizeof(spr_numbers_miniTiles))) + .withData(size == DigitSize::BIG + ? (modern ? spr_numbers_mdrnTiles : spr_numbersTiles) + : (modern ? spr_numbers_mini_mdrnTiles + : spr_numbers_miniTiles), + size == DigitSize::BIG + ? (modern ? sizeof(spr_numbers_mdrnTiles) + : sizeof(spr_numbersTiles)) + : (modern ? sizeof(spr_numbers_mini_mdrnTiles) + : sizeof(spr_numbers_miniTiles))) .withSize(SIZE_32_16) .withLocation(HIDDEN_WIDTH, HIDDEN_HEIGHT) .buildPtr(); @@ -41,11 +41,24 @@ Digit::Digit(DigitSize size, u32 x, u32 y, u32 index, bool reuseTiles) { } void Digit::set(u32 value, bool isRed) { - SPRITE_goToFrame(sprite.get(), value + (isRed ? RED_OFFSET : 0)); + currentValue = value; + SPRITE_goToFrame( + sprite.get(), + value + (!modern && size == DigitSize::MINI_NARROW ? TOTAL_NUMBERS : 0) + + (isRed ? TOTAL_NUMBERS : 0)); } -void Digit::relocate(DigitSize size, u32 x, u32 y, u32 index) { - animationPositionX = x + index * DIGIT_WIDTHS[size]; +void Digit::relocate(u32 x, u32 y, u32 spacing) { + reloadPosition(x, y, spacing); + + if (!shouldBeVisible()) { + SPRITE_hide(get()); + return; + } +} + +void Digit::reloadPosition(u32 x, u32 y, u32 spacing) { + animationPositionX = x + currentIndex * spacing; animationPositionY = y; } diff --git a/src/objects/Digit.h b/src/objects/Digit.h index be6073fb..e774d4ad 100644 --- a/src/objects/Digit.h +++ b/src/objects/Digit.h @@ -5,142 +5,25 @@ #include "objects/base/AnimatedIndicator.h" -enum DigitSize { BIG, MINI }; +enum DigitSize { BIG, MINI, MINI_NARROW }; class Digit : public AnimatedIndicator { public: Digit(DigitSize size, u32 x, u32 y, u32 index, bool reuseTiles); void set(u32 value, bool isRed); - void relocate(DigitSize size, u32 x, u32 y, u32 index); + void relocate(u32 x, u32 y, u32 spacing = 26); + void reloadPosition(u32 x, u32 y, u32 spacing = 26); + bool shouldBeVisible() { return currentIndex != 0 || currentValue != 0; } Sprite* get() override; private: std::unique_ptr sprite; + DigitSize size; + u32 currentIndex; + u32 currentValue = 0; + bool modern = false; }; -const u32 LUT_DIGITS = 3; -const u8 THREE_DIGITS_LUT[] = { - 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, - 0, 8, 0, 0, 9, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 0, 1, - 6, 0, 1, 7, 0, 1, 8, 0, 1, 9, 0, 2, 0, 0, 2, 1, 0, 2, 2, 0, 2, 3, 0, 2, 4, - 0, 2, 5, 0, 2, 6, 0, 2, 7, 0, 2, 8, 0, 2, 9, 0, 3, 0, 0, 3, 1, 0, 3, 2, 0, - 3, 3, 0, 3, 4, 0, 3, 5, 0, 3, 6, 0, 3, 7, 0, 3, 8, 0, 3, 9, 0, 4, 0, 0, 4, - 1, 0, 4, 2, 0, 4, 3, 0, 4, 4, 0, 4, 5, 0, 4, 6, 0, 4, 7, 0, 4, 8, 0, 4, 9, - 0, 5, 0, 0, 5, 1, 0, 5, 2, 0, 5, 3, 0, 5, 4, 0, 5, 5, 0, 5, 6, 0, 5, 7, 0, - 5, 8, 0, 5, 9, 0, 6, 0, 0, 6, 1, 0, 6, 2, 0, 6, 3, 0, 6, 4, 0, 6, 5, 0, 6, - 6, 0, 6, 7, 0, 6, 8, 0, 6, 9, 0, 7, 0, 0, 7, 1, 0, 7, 2, 0, 7, 3, 0, 7, 4, - 0, 7, 5, 0, 7, 6, 0, 7, 7, 0, 7, 8, 0, 7, 9, 0, 8, 0, 0, 8, 1, 0, 8, 2, 0, - 8, 3, 0, 8, 4, 0, 8, 5, 0, 8, 6, 0, 8, 7, 0, 8, 8, 0, 8, 9, 0, 9, 0, 0, 9, - 1, 0, 9, 2, 0, 9, 3, 0, 9, 4, 0, 9, 5, 0, 9, 6, 0, 9, 7, 0, 9, 8, 0, 9, 9, - 1, 0, 0, 1, 0, 1, 1, 0, 2, 1, 0, 3, 1, 0, 4, 1, 0, 5, 1, 0, 6, 1, 0, 7, 1, - 0, 8, 1, 0, 9, 1, 1, 0, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1, 5, 1, 1, - 6, 1, 1, 7, 1, 1, 8, 1, 1, 9, 1, 2, 0, 1, 2, 1, 1, 2, 2, 1, 2, 3, 1, 2, 4, - 1, 2, 5, 1, 2, 6, 1, 2, 7, 1, 2, 8, 1, 2, 9, 1, 3, 0, 1, 3, 1, 1, 3, 2, 1, - 3, 3, 1, 3, 4, 1, 3, 5, 1, 3, 6, 1, 3, 7, 1, 3, 8, 1, 3, 9, 1, 4, 0, 1, 4, - 1, 1, 4, 2, 1, 4, 3, 1, 4, 4, 1, 4, 5, 1, 4, 6, 1, 4, 7, 1, 4, 8, 1, 4, 9, - 1, 5, 0, 1, 5, 1, 1, 5, 2, 1, 5, 3, 1, 5, 4, 1, 5, 5, 1, 5, 6, 1, 5, 7, 1, - 5, 8, 1, 5, 9, 1, 6, 0, 1, 6, 1, 1, 6, 2, 1, 6, 3, 1, 6, 4, 1, 6, 5, 1, 6, - 6, 1, 6, 7, 1, 6, 8, 1, 6, 9, 1, 7, 0, 1, 7, 1, 1, 7, 2, 1, 7, 3, 1, 7, 4, - 1, 7, 5, 1, 7, 6, 1, 7, 7, 1, 7, 8, 1, 7, 9, 1, 8, 0, 1, 8, 1, 1, 8, 2, 1, - 8, 3, 1, 8, 4, 1, 8, 5, 1, 8, 6, 1, 8, 7, 1, 8, 8, 1, 8, 9, 1, 9, 0, 1, 9, - 1, 1, 9, 2, 1, 9, 3, 1, 9, 4, 1, 9, 5, 1, 9, 6, 1, 9, 7, 1, 9, 8, 1, 9, 9, - 2, 0, 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0, 4, 2, 0, 5, 2, 0, 6, 2, 0, 7, 2, - 0, 8, 2, 0, 9, 2, 1, 0, 2, 1, 1, 2, 1, 2, 2, 1, 3, 2, 1, 4, 2, 1, 5, 2, 1, - 6, 2, 1, 7, 2, 1, 8, 2, 1, 9, 2, 2, 0, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, 4, - 2, 2, 5, 2, 2, 6, 2, 2, 7, 2, 2, 8, 2, 2, 9, 2, 3, 0, 2, 3, 1, 2, 3, 2, 2, - 3, 3, 2, 3, 4, 2, 3, 5, 2, 3, 6, 2, 3, 7, 2, 3, 8, 2, 3, 9, 2, 4, 0, 2, 4, - 1, 2, 4, 2, 2, 4, 3, 2, 4, 4, 2, 4, 5, 2, 4, 6, 2, 4, 7, 2, 4, 8, 2, 4, 9, - 2, 5, 0, 2, 5, 1, 2, 5, 2, 2, 5, 3, 2, 5, 4, 2, 5, 5, 2, 5, 6, 2, 5, 7, 2, - 5, 8, 2, 5, 9, 2, 6, 0, 2, 6, 1, 2, 6, 2, 2, 6, 3, 2, 6, 4, 2, 6, 5, 2, 6, - 6, 2, 6, 7, 2, 6, 8, 2, 6, 9, 2, 7, 0, 2, 7, 1, 2, 7, 2, 2, 7, 3, 2, 7, 4, - 2, 7, 5, 2, 7, 6, 2, 7, 7, 2, 7, 8, 2, 7, 9, 2, 8, 0, 2, 8, 1, 2, 8, 2, 2, - 8, 3, 2, 8, 4, 2, 8, 5, 2, 8, 6, 2, 8, 7, 2, 8, 8, 2, 8, 9, 2, 9, 0, 2, 9, - 1, 2, 9, 2, 2, 9, 3, 2, 9, 4, 2, 9, 5, 2, 9, 6, 2, 9, 7, 2, 9, 8, 2, 9, 9, - 3, 0, 0, 3, 0, 1, 3, 0, 2, 3, 0, 3, 3, 0, 4, 3, 0, 5, 3, 0, 6, 3, 0, 7, 3, - 0, 8, 3, 0, 9, 3, 1, 0, 3, 1, 1, 3, 1, 2, 3, 1, 3, 3, 1, 4, 3, 1, 5, 3, 1, - 6, 3, 1, 7, 3, 1, 8, 3, 1, 9, 3, 2, 0, 3, 2, 1, 3, 2, 2, 3, 2, 3, 3, 2, 4, - 3, 2, 5, 3, 2, 6, 3, 2, 7, 3, 2, 8, 3, 2, 9, 3, 3, 0, 3, 3, 1, 3, 3, 2, 3, - 3, 3, 3, 3, 4, 3, 3, 5, 3, 3, 6, 3, 3, 7, 3, 3, 8, 3, 3, 9, 3, 4, 0, 3, 4, - 1, 3, 4, 2, 3, 4, 3, 3, 4, 4, 3, 4, 5, 3, 4, 6, 3, 4, 7, 3, 4, 8, 3, 4, 9, - 3, 5, 0, 3, 5, 1, 3, 5, 2, 3, 5, 3, 3, 5, 4, 3, 5, 5, 3, 5, 6, 3, 5, 7, 3, - 5, 8, 3, 5, 9, 3, 6, 0, 3, 6, 1, 3, 6, 2, 3, 6, 3, 3, 6, 4, 3, 6, 5, 3, 6, - 6, 3, 6, 7, 3, 6, 8, 3, 6, 9, 3, 7, 0, 3, 7, 1, 3, 7, 2, 3, 7, 3, 3, 7, 4, - 3, 7, 5, 3, 7, 6, 3, 7, 7, 3, 7, 8, 3, 7, 9, 3, 8, 0, 3, 8, 1, 3, 8, 2, 3, - 8, 3, 3, 8, 4, 3, 8, 5, 3, 8, 6, 3, 8, 7, 3, 8, 8, 3, 8, 9, 3, 9, 0, 3, 9, - 1, 3, 9, 2, 3, 9, 3, 3, 9, 4, 3, 9, 5, 3, 9, 6, 3, 9, 7, 3, 9, 8, 3, 9, 9, - 4, 0, 0, 4, 0, 1, 4, 0, 2, 4, 0, 3, 4, 0, 4, 4, 0, 5, 4, 0, 6, 4, 0, 7, 4, - 0, 8, 4, 0, 9, 4, 1, 0, 4, 1, 1, 4, 1, 2, 4, 1, 3, 4, 1, 4, 4, 1, 5, 4, 1, - 6, 4, 1, 7, 4, 1, 8, 4, 1, 9, 4, 2, 0, 4, 2, 1, 4, 2, 2, 4, 2, 3, 4, 2, 4, - 4, 2, 5, 4, 2, 6, 4, 2, 7, 4, 2, 8, 4, 2, 9, 4, 3, 0, 4, 3, 1, 4, 3, 2, 4, - 3, 3, 4, 3, 4, 4, 3, 5, 4, 3, 6, 4, 3, 7, 4, 3, 8, 4, 3, 9, 4, 4, 0, 4, 4, - 1, 4, 4, 2, 4, 4, 3, 4, 4, 4, 4, 4, 5, 4, 4, 6, 4, 4, 7, 4, 4, 8, 4, 4, 9, - 4, 5, 0, 4, 5, 1, 4, 5, 2, 4, 5, 3, 4, 5, 4, 4, 5, 5, 4, 5, 6, 4, 5, 7, 4, - 5, 8, 4, 5, 9, 4, 6, 0, 4, 6, 1, 4, 6, 2, 4, 6, 3, 4, 6, 4, 4, 6, 5, 4, 6, - 6, 4, 6, 7, 4, 6, 8, 4, 6, 9, 4, 7, 0, 4, 7, 1, 4, 7, 2, 4, 7, 3, 4, 7, 4, - 4, 7, 5, 4, 7, 6, 4, 7, 7, 4, 7, 8, 4, 7, 9, 4, 8, 0, 4, 8, 1, 4, 8, 2, 4, - 8, 3, 4, 8, 4, 4, 8, 5, 4, 8, 6, 4, 8, 7, 4, 8, 8, 4, 8, 9, 4, 9, 0, 4, 9, - 1, 4, 9, 2, 4, 9, 3, 4, 9, 4, 4, 9, 5, 4, 9, 6, 4, 9, 7, 4, 9, 8, 4, 9, 9, - 5, 0, 0, 5, 0, 1, 5, 0, 2, 5, 0, 3, 5, 0, 4, 5, 0, 5, 5, 0, 6, 5, 0, 7, 5, - 0, 8, 5, 0, 9, 5, 1, 0, 5, 1, 1, 5, 1, 2, 5, 1, 3, 5, 1, 4, 5, 1, 5, 5, 1, - 6, 5, 1, 7, 5, 1, 8, 5, 1, 9, 5, 2, 0, 5, 2, 1, 5, 2, 2, 5, 2, 3, 5, 2, 4, - 5, 2, 5, 5, 2, 6, 5, 2, 7, 5, 2, 8, 5, 2, 9, 5, 3, 0, 5, 3, 1, 5, 3, 2, 5, - 3, 3, 5, 3, 4, 5, 3, 5, 5, 3, 6, 5, 3, 7, 5, 3, 8, 5, 3, 9, 5, 4, 0, 5, 4, - 1, 5, 4, 2, 5, 4, 3, 5, 4, 4, 5, 4, 5, 5, 4, 6, 5, 4, 7, 5, 4, 8, 5, 4, 9, - 5, 5, 0, 5, 5, 1, 5, 5, 2, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 6, 5, 5, 7, 5, - 5, 8, 5, 5, 9, 5, 6, 0, 5, 6, 1, 5, 6, 2, 5, 6, 3, 5, 6, 4, 5, 6, 5, 5, 6, - 6, 5, 6, 7, 5, 6, 8, 5, 6, 9, 5, 7, 0, 5, 7, 1, 5, 7, 2, 5, 7, 3, 5, 7, 4, - 5, 7, 5, 5, 7, 6, 5, 7, 7, 5, 7, 8, 5, 7, 9, 5, 8, 0, 5, 8, 1, 5, 8, 2, 5, - 8, 3, 5, 8, 4, 5, 8, 5, 5, 8, 6, 5, 8, 7, 5, 8, 8, 5, 8, 9, 5, 9, 0, 5, 9, - 1, 5, 9, 2, 5, 9, 3, 5, 9, 4, 5, 9, 5, 5, 9, 6, 5, 9, 7, 5, 9, 8, 5, 9, 9, - 6, 0, 0, 6, 0, 1, 6, 0, 2, 6, 0, 3, 6, 0, 4, 6, 0, 5, 6, 0, 6, 6, 0, 7, 6, - 0, 8, 6, 0, 9, 6, 1, 0, 6, 1, 1, 6, 1, 2, 6, 1, 3, 6, 1, 4, 6, 1, 5, 6, 1, - 6, 6, 1, 7, 6, 1, 8, 6, 1, 9, 6, 2, 0, 6, 2, 1, 6, 2, 2, 6, 2, 3, 6, 2, 4, - 6, 2, 5, 6, 2, 6, 6, 2, 7, 6, 2, 8, 6, 2, 9, 6, 3, 0, 6, 3, 1, 6, 3, 2, 6, - 3, 3, 6, 3, 4, 6, 3, 5, 6, 3, 6, 6, 3, 7, 6, 3, 8, 6, 3, 9, 6, 4, 0, 6, 4, - 1, 6, 4, 2, 6, 4, 3, 6, 4, 4, 6, 4, 5, 6, 4, 6, 6, 4, 7, 6, 4, 8, 6, 4, 9, - 6, 5, 0, 6, 5, 1, 6, 5, 2, 6, 5, 3, 6, 5, 4, 6, 5, 5, 6, 5, 6, 6, 5, 7, 6, - 5, 8, 6, 5, 9, 6, 6, 0, 6, 6, 1, 6, 6, 2, 6, 6, 3, 6, 6, 4, 6, 6, 5, 6, 6, - 6, 6, 6, 7, 6, 6, 8, 6, 6, 9, 6, 7, 0, 6, 7, 1, 6, 7, 2, 6, 7, 3, 6, 7, 4, - 6, 7, 5, 6, 7, 6, 6, 7, 7, 6, 7, 8, 6, 7, 9, 6, 8, 0, 6, 8, 1, 6, 8, 2, 6, - 8, 3, 6, 8, 4, 6, 8, 5, 6, 8, 6, 6, 8, 7, 6, 8, 8, 6, 8, 9, 6, 9, 0, 6, 9, - 1, 6, 9, 2, 6, 9, 3, 6, 9, 4, 6, 9, 5, 6, 9, 6, 6, 9, 7, 6, 9, 8, 6, 9, 9, - 7, 0, 0, 7, 0, 1, 7, 0, 2, 7, 0, 3, 7, 0, 4, 7, 0, 5, 7, 0, 6, 7, 0, 7, 7, - 0, 8, 7, 0, 9, 7, 1, 0, 7, 1, 1, 7, 1, 2, 7, 1, 3, 7, 1, 4, 7, 1, 5, 7, 1, - 6, 7, 1, 7, 7, 1, 8, 7, 1, 9, 7, 2, 0, 7, 2, 1, 7, 2, 2, 7, 2, 3, 7, 2, 4, - 7, 2, 5, 7, 2, 6, 7, 2, 7, 7, 2, 8, 7, 2, 9, 7, 3, 0, 7, 3, 1, 7, 3, 2, 7, - 3, 3, 7, 3, 4, 7, 3, 5, 7, 3, 6, 7, 3, 7, 7, 3, 8, 7, 3, 9, 7, 4, 0, 7, 4, - 1, 7, 4, 2, 7, 4, 3, 7, 4, 4, 7, 4, 5, 7, 4, 6, 7, 4, 7, 7, 4, 8, 7, 4, 9, - 7, 5, 0, 7, 5, 1, 7, 5, 2, 7, 5, 3, 7, 5, 4, 7, 5, 5, 7, 5, 6, 7, 5, 7, 7, - 5, 8, 7, 5, 9, 7, 6, 0, 7, 6, 1, 7, 6, 2, 7, 6, 3, 7, 6, 4, 7, 6, 5, 7, 6, - 6, 7, 6, 7, 7, 6, 8, 7, 6, 9, 7, 7, 0, 7, 7, 1, 7, 7, 2, 7, 7, 3, 7, 7, 4, - 7, 7, 5, 7, 7, 6, 7, 7, 7, 7, 7, 8, 7, 7, 9, 7, 8, 0, 7, 8, 1, 7, 8, 2, 7, - 8, 3, 7, 8, 4, 7, 8, 5, 7, 8, 6, 7, 8, 7, 7, 8, 8, 7, 8, 9, 7, 9, 0, 7, 9, - 1, 7, 9, 2, 7, 9, 3, 7, 9, 4, 7, 9, 5, 7, 9, 6, 7, 9, 7, 7, 9, 8, 7, 9, 9, - 8, 0, 0, 8, 0, 1, 8, 0, 2, 8, 0, 3, 8, 0, 4, 8, 0, 5, 8, 0, 6, 8, 0, 7, 8, - 0, 8, 8, 0, 9, 8, 1, 0, 8, 1, 1, 8, 1, 2, 8, 1, 3, 8, 1, 4, 8, 1, 5, 8, 1, - 6, 8, 1, 7, 8, 1, 8, 8, 1, 9, 8, 2, 0, 8, 2, 1, 8, 2, 2, 8, 2, 3, 8, 2, 4, - 8, 2, 5, 8, 2, 6, 8, 2, 7, 8, 2, 8, 8, 2, 9, 8, 3, 0, 8, 3, 1, 8, 3, 2, 8, - 3, 3, 8, 3, 4, 8, 3, 5, 8, 3, 6, 8, 3, 7, 8, 3, 8, 8, 3, 9, 8, 4, 0, 8, 4, - 1, 8, 4, 2, 8, 4, 3, 8, 4, 4, 8, 4, 5, 8, 4, 6, 8, 4, 7, 8, 4, 8, 8, 4, 9, - 8, 5, 0, 8, 5, 1, 8, 5, 2, 8, 5, 3, 8, 5, 4, 8, 5, 5, 8, 5, 6, 8, 5, 7, 8, - 5, 8, 8, 5, 9, 8, 6, 0, 8, 6, 1, 8, 6, 2, 8, 6, 3, 8, 6, 4, 8, 6, 5, 8, 6, - 6, 8, 6, 7, 8, 6, 8, 8, 6, 9, 8, 7, 0, 8, 7, 1, 8, 7, 2, 8, 7, 3, 8, 7, 4, - 8, 7, 5, 8, 7, 6, 8, 7, 7, 8, 7, 8, 8, 7, 9, 8, 8, 0, 8, 8, 1, 8, 8, 2, 8, - 8, 3, 8, 8, 4, 8, 8, 5, 8, 8, 6, 8, 8, 7, 8, 8, 8, 8, 8, 9, 8, 9, 0, 8, 9, - 1, 8, 9, 2, 8, 9, 3, 8, 9, 4, 8, 9, 5, 8, 9, 6, 8, 9, 7, 8, 9, 8, 8, 9, 9, - 9, 0, 0, 9, 0, 1, 9, 0, 2, 9, 0, 3, 9, 0, 4, 9, 0, 5, 9, 0, 6, 9, 0, 7, 9, - 0, 8, 9, 0, 9, 9, 1, 0, 9, 1, 1, 9, 1, 2, 9, 1, 3, 9, 1, 4, 9, 1, 5, 9, 1, - 6, 9, 1, 7, 9, 1, 8, 9, 1, 9, 9, 2, 0, 9, 2, 1, 9, 2, 2, 9, 2, 3, 9, 2, 4, - 9, 2, 5, 9, 2, 6, 9, 2, 7, 9, 2, 8, 9, 2, 9, 9, 3, 0, 9, 3, 1, 9, 3, 2, 9, - 3, 3, 9, 3, 4, 9, 3, 5, 9, 3, 6, 9, 3, 7, 9, 3, 8, 9, 3, 9, 9, 4, 0, 9, 4, - 1, 9, 4, 2, 9, 4, 3, 9, 4, 4, 9, 4, 5, 9, 4, 6, 9, 4, 7, 9, 4, 8, 9, 4, 9, - 9, 5, 0, 9, 5, 1, 9, 5, 2, 9, 5, 3, 9, 5, 4, 9, 5, 5, 9, 5, 6, 9, 5, 7, 9, - 5, 8, 9, 5, 9, 9, 6, 0, 9, 6, 1, 9, 6, 2, 9, 6, 3, 9, 6, 4, 9, 6, 5, 9, 6, - 6, 9, 6, 7, 9, 6, 8, 9, 6, 9, 9, 7, 0, 9, 7, 1, 9, 7, 2, 9, 7, 3, 9, 7, 4, - 9, 7, 5, 9, 7, 6, 9, 7, 7, 9, 7, 8, 9, 7, 9, 9, 8, 0, 9, 8, 1, 9, 8, 2, 9, - 8, 3, 9, 8, 4, 9, 8, 5, 9, 8, 6, 9, 8, 7, 9, 8, 8, 9, 8, 9, 9, 9, 0, 9, 9, - 1, 9, 9, 2, 9, 9, 3, 9, 9, 4, 9, 9, 5, 9, 9, 6, 9, 9, 7, 9, 9, 8, 9, 9, 9}; - #endif // DIGIT_H diff --git a/src/objects/LifeBar.cpp b/src/objects/LifeBar.cpp index 6d849982..752bba2a 100644 --- a/src/objects/LifeBar.cpp +++ b/src/objects/LifeBar.cpp @@ -157,10 +157,10 @@ CODE_IWRAM void LifeBar::paint(ForegroundPaletteManager* foregroundPalette) { } } - foregroundPalette->change(0, PALETTE_INDEXES[playerId][i], color); + pal_obj_bank[0][PALETTE_INDEXES[playerId][i]] = color; + if (GameState.mods.colorFilter != ColorFilter::NO_FILTER) - SCENE_applyColorFilterIndex(foregroundPalette, 0, - PALETTE_INDEXES[playerId][i], + SCENE_applyColorFilterIndex(pal_obj_bank, 0, PALETTE_INDEXES[playerId][i], GameState.mods.colorFilter); isBorder = !isBorder; diff --git a/src/objects/score/Score.cpp b/src/objects/score/Score.cpp index 68d95aba..20764c5e 100644 --- a/src/objects/score/Score.cpp +++ b/src/objects/score/Score.cpp @@ -12,11 +12,10 @@ const u32 MAX_SCALE_STEP = 5; const u32 SCALE_STEPS[] = {256, 233, 213, 197, 171, 205}; -Score::Score(LifeBar* lifeBar, u8 playerId, bool isLocal) { +Score::Score(LifeBar* lifeBar, u8 playerId, bool isVs, bool isLocal) { lifeBar->setLife(life); this->lifeBar = lifeBar; this->playerId = playerId; - this->isLocal = isLocal; feedback = std::unique_ptr{new Feedback(playerId)}; combo = std::unique_ptr{new Combo(playerId)}; @@ -32,12 +31,12 @@ Score::Score(LifeBar* lifeBar, u8 playerId, bool isLocal) { feedback->get()->setAffineId(AFFINE_BASE + playerId); combo->getTitle()->get()->setDoubleSize(true); combo->getTitle()->get()->setAffineId(AFFINE_BASE + playerId); - combo->getDigits()->at(0)->get()->setDoubleSize(true); - combo->getDigits()->at(0)->get()->setAffineId(AFFINE_BASE + playerId); - combo->getDigits()->at(1)->get()->setDoubleSize(true); - combo->getDigits()->at(1)->get()->setAffineId(AFFINE_BASE + playerId); - combo->getDigits()->at(2)->get()->setDoubleSize(true); - combo->getDigits()->at(2)->get()->setAffineId(AFFINE_BASE + playerId); + if (!isVs) { + for (u32 i = 0; i < COMBO_DIGITS; i++) { + combo->getDigits()->at(i)->get()->setDoubleSize(true); + combo->getDigits()->at(i)->get()->setAffineId(AFFINE_BASE + playerId); + } + } } } @@ -91,7 +90,7 @@ bool Score::updateLife(FeedbackType feedbackType) { return true; if (GameState.mods.stageBreak == StageBreakOpts::sSUDDEN_DEATH) return feedbackType != FeedbackType::MISS; - if (GameState.mode == GameMode::DEATH_MIX && + if (GameState.mode == GameMode::DEATH_MIX && !GameState.isShuffleMode && feedbackType != FeedbackType::MISS) return true; diff --git a/src/objects/score/Score.h b/src/objects/score/Score.h index 7f3110f0..5f0a4294 100644 --- a/src/objects/score/Score.h +++ b/src/objects/score/Score.h @@ -20,7 +20,7 @@ const u32 FRACUMUL_0_90 = 3865470565; class Score { public: - Score(LifeBar* lifeBar, u8 playerId, bool isLocal); + Score(LifeBar* lifeBar, u8 playerId, bool isVs, bool isLocal); inline u32 getPoints() { return points; } inline u32 getPercent() { @@ -90,7 +90,6 @@ class Score { std::unique_ptr combo; LifeBar* lifeBar; u8 playerId; - bool isLocal; int life = INITIAL_LIFE; bool hasMissCombo = false; diff --git a/src/objects/score/Total.cpp b/src/objects/score/Total.cpp index 2c7c3c7c..2672bf48 100644 --- a/src/objects/score/Total.cpp +++ b/src/objects/score/Total.cpp @@ -2,16 +2,34 @@ #include +#include "../../gameplay/save/SaveFile.h" #include "utils/SpriteUtils.h" -const u32 MAX_TOTAL = 999; -const u32 DIGITS = 3; +const u32 MAX_TOTAL = 9999; +const u32 DIGITS = 4; +const u32 NUMBER_WIDTH_3_DIGITS = 19; +const u32 NUMBER_WIDTH_4_DIGITS = 13; +const int OFFSET_3_DIGITS = -NUMBER_WIDTH_3_DIGITS; +const int OFFSET_4_DIGITS = -1; + +Total::Total(u32 x, u32 y, bool has4Digits, bool isFirst) { + u32 numberWidth4Digits = NUMBER_WIDTH_4_DIGITS; + u32 offset4Digits = OFFSET_4_DIGITS; + if (!SAVEFILE_isUsingModernTheme()) { + numberWidth4Digits++; + offset4Digits--; + } -Total::Total(u32 x, u32 y, bool isFirst) { for (u32 i = 0; i < DIGITS; i++) { - auto digit = - std::unique_ptr{new Digit(DigitSize::MINI, x, y, i, false)}; - digit->showAt(0); + auto digit = std::unique_ptr{new Digit( + has4Digits ? DigitSize::MINI_NARROW : DigitSize::MINI, x, y, i, false)}; + + digit->relocate(x + (i > 0 && !has4Digits ? OFFSET_3_DIGITS : 0) + + (has4Digits ? offset4Digits : 0), + y, has4Digits ? numberWidth4Digits : NUMBER_WIDTH_3_DIGITS); + + if (i > 0 || has4Digits) + digit->showAt(0); if (i == 0 && !isFirst) SPRITE_reuseTiles(digit->get()); @@ -24,9 +42,10 @@ void Total::setValue(u32 value) { if (value > MAX_TOTAL) value = MAX_TOTAL; - digits[0]->set(THREE_DIGITS_LUT[value * DIGITS], false); - digits[1]->set(THREE_DIGITS_LUT[value * DIGITS + 1], false); - digits[2]->set(THREE_DIGITS_LUT[value * DIGITS + 2], false); + for (int i = DIGITS - 1; i >= 0; i--) { + digits[i]->set(value % 10, false); + value /= 10; + } } void Total::render(std::vector* sprites) { diff --git a/src/objects/score/Total.h b/src/objects/score/Total.h index be293c0b..940eac2e 100644 --- a/src/objects/score/Total.h +++ b/src/objects/score/Total.h @@ -9,7 +9,7 @@ class Total { public: - Total(u32 x, u32 y, bool isFirst); + Total(u32 x, u32 y, bool has4Digits, bool isFirst); void setValue(u32 value); void render(std::vector* sprites); diff --git a/src/objects/score/combo/Combo.cpp b/src/objects/score/combo/Combo.cpp index a55ad56f..bca468c0 100644 --- a/src/objects/score/combo/Combo.cpp +++ b/src/objects/score/combo/Combo.cpp @@ -6,46 +6,57 @@ #include "objects/ArrowInfo.h" #include "utils/SpriteUtils.h" -const u32 MAX_COMBO = 999; -const u32 DIGITS = 3; const u32 DIGITS_POSITION_X = 7; const u32 DIGITS_POSITION_Y = 91; +const u32 NUMBER_WIDTH_3_DIGITS = 26; +const u32 NUMBER_WIDTH_4_DIGITS = 22; +const int OFFSET_3_DIGITS = -NUMBER_WIDTH_3_DIGITS; +const int OFFSET_4_DIGITS = -7; Combo::Combo(u8 playerId) { this->playerId = playerId; title = std::unique_ptr{new ComboTitle(playerId)}; - for (u32 i = 0; i < DIGITS; i++) { + if (SAVEFILE_isUsingModernTheme()) + offsetX = -1; + + for (u32 i = 0; i < COMBO_DIGITS; i++) { auto digit = std::unique_ptr{new Digit( DigitSize::BIG, (isDouble() ? GAME_POSITION_X[1] : GameState.positionX[playerId]) + - DIGITS_POSITION_X, + DIGITS_POSITION_X + offsetX + (i > 0 ? OFFSET_3_DIGITS : 0), GameState.scorePositionY + DIGITS_POSITION_Y, i, playerId > 0)}; digits.push_back(std::move(digit)); } } void Combo::setValue(int value) { + u32 oldValue = this->value; + bool isRed = value < 0; u32 absValue = min(abs(value), MAX_COMBO); this->value = absValue; - digits[0]->set(THREE_DIGITS_LUT[absValue * LUT_DIGITS], isRed); - digits[1]->set(THREE_DIGITS_LUT[absValue * LUT_DIGITS + 1], isRed); - digits[2]->set(THREE_DIGITS_LUT[absValue * LUT_DIGITS + 2], isRed); - - // Without optimizations: - // digits[0]->set(Div(absValue, 100), isRed); - // digits[1]->set(Div(DivMod(absValue, 100), 10), isRed); - // digits[2]->set(DivMod(absValue, 10), isRed); + + for (int i = COMBO_DIGITS - 1; i >= 0; i--) { + digits[i]->set(absValue % 10, isRed); + absValue /= 10; + } + + bool had4Digits = oldValue > 999; + bool has4Digits = this->value > 999; + if (has4Digits != had4Digits) + relocate(); } void Combo::show() { title->show(); - for (auto& it : digits) - it->show(); + for (auto& it : digits) { + if (it->shouldBeVisible()) + it->show(); + } } void Combo::hide() { @@ -58,16 +69,19 @@ void Combo::hide() { void Combo::relocate() { title->relocate(); - for (u32 i = 0; i < DIGITS; i++) + bool has4Digits = digits[0]->shouldBeVisible(); + for (u32 i = 0; i < COMBO_DIGITS; i++) digits[i]->relocate( - DigitSize::BIG, (isDouble() ? GAME_POSITION_X[1] : GameState.positionX[playerId]) + - DIGITS_POSITION_X, - GameState.scorePositionY + DIGITS_POSITION_Y, i); + DIGITS_POSITION_X + offsetX + + (i > 0 && !has4Digits ? OFFSET_3_DIGITS : 0) + + (has4Digits ? OFFSET_4_DIGITS : 0), + GameState.scorePositionY + DIGITS_POSITION_Y, + has4Digits ? NUMBER_WIDTH_4_DIGITS : NUMBER_WIDTH_3_DIGITS); } void Combo::disableMosaic() { - for (u32 i = 0; i < DIGITS; i++) + for (u32 i = 0; i < COMBO_DIGITS; i++) digits[i]->get()->oam.attr0 = digits[i]->get()->oam.attr0 & 0b1110111111111111; } @@ -75,8 +89,10 @@ void Combo::disableMosaic() { void Combo::tick() { title->tick(); - for (auto& it : digits) - it->tick(); + for (auto& it : digits) { + if (it->shouldBeVisible()) + it->tick(); + } } Combo::~Combo() { diff --git a/src/objects/score/combo/Combo.h b/src/objects/score/combo/Combo.h index 4cb5a870..7d986c9c 100644 --- a/src/objects/score/combo/Combo.h +++ b/src/objects/score/combo/Combo.h @@ -8,6 +8,9 @@ #include "ComboTitle.h" #include "objects/Digit.h" +#define MAX_COMBO 9999 +#define COMBO_DIGITS 4 + class Combo { public: Combo(u8 playerId); @@ -31,6 +34,7 @@ class Combo { std::unique_ptr title; std::vector> digits; u8 playerId; + int offsetX = 0; }; #endif // COMBO_H diff --git a/src/objects/ui/Button.cpp b/src/objects/ui/Button.cpp index ac742781..e6c20473 100644 --- a/src/objects/ui/Button.cpp +++ b/src/objects/ui/Button.cpp @@ -11,24 +11,19 @@ const u32 SELECTED_START = 3; Button::Button(ButtonType type, u32 x, u32 y, bool reuseTiles) { SpriteBuilder builder; - sprite = - builder - .withData(type == ButtonType::LEVEL_METER ? spr_levelTiles - : type == ButtonType::SUB_BUTTON || - type == ButtonType::SUB_BUTTON_ORANGE - ? spr_buttons_miniTiles - : spr_buttonsTiles, - type == ButtonType::LEVEL_METER ? sizeof(spr_levelTiles) - : type == ButtonType::SUB_BUTTON || - type == ButtonType::SUB_BUTTON_ORANGE - ? sizeof(spr_buttons_miniTiles) - : sizeof(spr_buttonsTiles)) - .withSize(type == ButtonType::SUB_BUTTON || - type == ButtonType::SUB_BUTTON_ORANGE - ? SIZE_16_16 - : SIZE_32_32) - .withLocation(x, y) - .buildPtr(); + sprite = builder + .withData( + type == ButtonType::LEVEL_METER ? spr_levelTiles + : type >= ButtonType::SUB_BUTTON_BLUE ? spr_buttons_miniTiles + : spr_buttonsTiles, + type == ButtonType::LEVEL_METER ? sizeof(spr_levelTiles) + : type >= ButtonType::SUB_BUTTON_BLUE + ? sizeof(spr_buttons_miniTiles) + : sizeof(spr_buttonsTiles)) + .withSize(type >= ButtonType::SUB_BUTTON_BLUE ? SIZE_16_16 + : SIZE_32_32) + .withLocation(x, y) + .buildPtr(); this->type = type; this->x = x; @@ -37,22 +32,28 @@ Button::Button(ButtonType type, u32 x, u32 y, bool reuseTiles) { if (reuseTiles) SPRITE_reuseTiles(sprite.get()); - if (type != ButtonType::LEVEL_METER && type != ButtonType::SUB_BUTTON && + if (type != ButtonType::LEVEL_METER && type != ButtonType::SUB_BUTTON_GRAY && type != ButtonType::SUB_BUTTON_ORANGE) SPRITE_goToFrame(sprite.get(), type); - if (type == SUB_BUTTON_ORANGE) - SPRITE_goToFrame(sprite.get(), 2); + if (type == ButtonType::SUB_BUTTON_BLUE) + SPRITE_goToFrame(sprite.get(), 0); + if (type == ButtonType::SUB_BUTTON_ORANGE) + SPRITE_goToFrame(sprite.get(), 4); } void Button::setSelected(bool isSelected) { - if (type == ButtonType::SUB_BUTTON) { + if (type == ButtonType::SUB_BUTTON_BLUE) { SPRITE_goToFrame(sprite.get(), isSelected ? 1 : 0); return; } - if (type == ButtonType::SUB_BUTTON_ORANGE) { + if (type == ButtonType::SUB_BUTTON_GRAY) { SPRITE_goToFrame(sprite.get(), isSelected ? 3 : 2); return; } + if (type == ButtonType::SUB_BUTTON_ORANGE) { + SPRITE_goToFrame(sprite.get(), isSelected ? 5 : 4); + return; + } SPRITE_goToFrame(sprite.get(), (isSelected ? SELECTED_START : 0) + type); } diff --git a/src/objects/ui/Button.h b/src/objects/ui/Button.h index 69445fa2..3adee7f5 100644 --- a/src/objects/ui/Button.h +++ b/src/objects/ui/Button.h @@ -8,7 +8,8 @@ enum ButtonType { GRAY, ORANGE, LEVEL_METER, - SUB_BUTTON, + SUB_BUTTON_BLUE, + SUB_BUTTON_GRAY, SUB_BUTTON_ORANGE }; diff --git a/src/objects/ui/ChannelBadge.cpp b/src/objects/ui/ChannelBadge.cpp index 3ad79899..09c73e09 100644 --- a/src/objects/ui/ChannelBadge.cpp +++ b/src/objects/ui/ChannelBadge.cpp @@ -5,6 +5,8 @@ #include "data/content/_compiled_sprites/spr_channels.h" #include "utils/SpriteUtils.h" +#define ANIMATION_TIME 6 + ChannelBadge::ChannelBadge(u32 x, u32 y, bool reuseTiles) { SpriteBuilder builder; sprite = builder.withData(spr_channelsTiles, sizeof(spr_channelsTiles)) @@ -21,9 +23,25 @@ ChannelBadge::ChannelBadge(u32 x, u32 y, bool reuseTiles) { SPRITE_reuseTiles(sprite.get()); } +void ChannelBadge::tick() { + if (currentType != Channel::BOSS) + return; + + animationCount++; + if (animationCount >= ANIMATION_TIME) { + animationCount = 0; + animationFlag = !animationFlag; + sprite->flipHorizontally(animationFlag); + } +} + void ChannelBadge::setType(Channel type) { + currentType = type; SPRITE_goToFrame(sprite.get(), type); sprite->moveTo(x, y); + sprite->flipHorizontally(false); + animationCount = 0; + animationFlag = 0; } void ChannelBadge::hide() { diff --git a/src/objects/ui/ChannelBadge.h b/src/objects/ui/ChannelBadge.h index ec77a339..708cd287 100644 --- a/src/objects/ui/ChannelBadge.h +++ b/src/objects/ui/ChannelBadge.h @@ -9,6 +9,7 @@ class ChannelBadge { public: ChannelBadge(u32 x, u32 y, bool reuseTiles); + void tick(); void setType(Channel type); void hide(); @@ -16,9 +17,11 @@ class ChannelBadge { private: std::unique_ptr sprite; - u32 x; u32 y; + Channel currentType = Channel::ORIGINAL; + u32 animationCount = 0; + bool animationFlag = false; }; #endif // CHANNEL_BADGE_H diff --git a/src/objects/ui/Instructor.h b/src/objects/ui/Instructor.h index ef8e70d9..690eb5e4 100644 --- a/src/objects/ui/Instructor.h +++ b/src/objects/ui/Instructor.h @@ -3,7 +3,7 @@ #include -enum InstructorType { Girl, Boy, AngryGirl }; +enum InstructorType { Girl, AngryGirl2, AngryGirl1 }; class Instructor { public: diff --git a/src/objects/ui/NumericProgress.cpp b/src/objects/ui/NumericProgress.cpp index 023c6e31..6b627410 100644 --- a/src/objects/ui/NumericProgress.cpp +++ b/src/objects/ui/NumericProgress.cpp @@ -31,20 +31,20 @@ NumericProgress::NumericProgress(u32 x, u32 y) { } void NumericProgress::setValue(u32 completed, u32 total) { - completedDigits[0]->set(THREE_DIGITS_LUT[completed * LUT_DIGITS + 1], false); - completedDigits[1]->set(THREE_DIGITS_LUT[completed * LUT_DIGITS + 2], false); + completedDigits[0]->set((completed % 100) / 10, false); + completedDigits[1]->set(completed % 10, false); - totalDigits[0]->set(THREE_DIGITS_LUT[total * LUT_DIGITS + 1], false); - totalDigits[1]->set(THREE_DIGITS_LUT[total * LUT_DIGITS + 2], false); + totalDigits[0]->set((total % 100) / 10, false); + totalDigits[1]->set(total % 10, false); } void NumericProgress::show() { for (u32 i = 0; i < DIGITS; i++) { - completedDigits[i]->relocate(DigitSize::BIG, x, y, i); + completedDigits[i]->relocate(x, y); completedDigits[i]->show(); } for (u32 i = 0; i < DIGITS; i++) { - totalDigits[i]->relocate(DigitSize::BIG, x + DIGITS_TOTAL_POSITION_X, y, i); + totalDigits[i]->relocate(x + DIGITS_TOTAL_POSITION_X, y); totalDigits[i]->show(); } of->get()->moveTo(x + OF_POSITION_X, y); diff --git a/src/player/player.iwram.c b/src/player/player.iwram.c index 81224483..201b148b 100644 --- a/src/player/player.iwram.c +++ b/src/player/player.iwram.c @@ -55,13 +55,13 @@ Playback PlaybackState; // 'timer =', 65536-(280896/i), '; buffer =', // i, '; sample rate =', i*(1<<24)/280896, 'hz' // ); -// Playback rate can be changed: 0.86, 0.73, 0.47, 1, 1.11, 1.26, 1.54. +// Playback rate can be changed by +/- 13%, 26%, or 53%. // - In PCM s8 mode: // Audio is taken from the flash cart's SD card (gba-flashcartio). // The sample rate is 36314hz. // Each PCM chunk is 304 bytes and represents 304 samples. // Two chunks are copied per frame. -// Playback rate can be either 1 or 1.11. +// Playback rate can be either 1 or 1.13. static const int rate_delays[] = {1, 2, 4, 0, 4, 2, 1}; static signed char rate_xfade[304]; @@ -105,6 +105,9 @@ static bool did_run = false; buffer[i] = (signed char)crossfaded_sample; \ } \ } \ + if (src_pos >= src_len) { \ + ON_STOP; \ + } \ } else { \ ON_STOP; \ } \ @@ -141,6 +144,9 @@ static bool did_run = false; *buffer++ = cur_sample >> 8; \ last_sample = cur_sample; \ } \ + if (src_pos >= src_len) { \ + ON_STOP; \ + } \ } else { \ ON_STOP; \ } \ @@ -253,7 +259,7 @@ INLINE void dsound_start_audio_copy(const void* source) { DMA_ENABLE | 1; } -INLINE void loadFile(const char* name, bool forceGSM) { +INLINE void load_file(const char* name, bool forceGSM) { PlaybackState.msecs = 0; PlaybackState.hasFinished = false; PlaybackState.isLooping = false; @@ -299,12 +305,12 @@ CODE_ROM void player_unload() { } CODE_ROM bool player_playSfx(const char* name) { - loadFile(name, active_flashcart == EZ_FLASH_OMEGA); + load_file(name, active_flashcart == EZ_FLASH_OMEGA); return is_pcm; } CODE_ROM bool player_play(const char* name, bool forceGSM) { - loadFile(name, forceGSM); + load_file(name, forceGSM); return is_pcm; } @@ -355,7 +361,6 @@ CODE_ROM void player_stop() { rate = 0; rate_counter = 0; current_audio_chunk = 0; - is_pcm = false; } CODE_ROM bool player_isPlaying() { diff --git a/src/scenes/AdminScene.cpp b/src/scenes/AdminScene.cpp index 44858c49..e303290b 100644 --- a/src/scenes/AdminScene.cpp +++ b/src/scenes/AdminScene.cpp @@ -8,7 +8,7 @@ #include "scenes/StartScene.h" #include "utils/SceneUtils.h" -#define TITLE "ADMIN MENU (v1.10.0)" +#define TITLE "ADMIN MENU (v1.11.0)" #define SUBMENU_RUMBLE 0 #define SUBMENU_OFFSETS 1 #define SUBMENU_RESET 2 @@ -25,7 +25,7 @@ #define OPTION_RUMBLE 1 #define OPTION_IO_BLINK 2 #define OPTION_SRAM_BLINK 3 -#define OPTION_BACKGROUND_VIDEOS 4 +#define OPTION_HQ_MODE 4 #define OPTION_EWRAM_OVERCLOCK 5 #define OPTION_PS2_INPUT 6 #define OPTION_RUMBLE_OPTS 7 @@ -125,7 +125,7 @@ void AdminScene::printOptions() { u8 rumble = SAVEFILE_read8(SRAM->adminSettings.rumble); u8 ioBlink = SAVEFILE_read8(SRAM->adminSettings.ioBlink); u8 sramBlink = SAVEFILE_read8(SRAM->adminSettings.sramBlink); - u8 backgroundVideos = SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); + u8 hqMode = SAVEFILE_read8(SRAM->adminSettings.hqMode); u8 ewramOverclock = SAVEFILE_read8(SRAM->adminSettings.ewramOverclock); u8 ps2Input = SAVEFILE_read8(SRAM->adminSettings.ps2Input); @@ -147,18 +147,17 @@ void AdminScene::printOptions() { : sramBlink == 2 ? "ON HIT" : "OFF", 8); - printOption(OPTION_BACKGROUND_VIDEOS, "HQ (audio / video)", + printOption(OPTION_HQ_MODE, "HQ (audio / video)", ps2Input > 0 ? "---" - : (backgroundVideos == 3 ? "VIDEO" - : backgroundVideos == 4 ? "AUDIO" - : backgroundVideos > 0 ? "ALL" - : "OFF"), + : (hqMode == 3 ? "VIDEO" + : hqMode == 4 ? "AUDIO" + : hqMode > 0 ? "ALL" + : "OFF"), 9); - printOption( - OPTION_EWRAM_OVERCLOCK, "EWRAM overclock", - ewramOverclock == 1 ? (backgroundVideos > 0 ? "*!*" : "ON") : "OFF", 10); + printOption(OPTION_EWRAM_OVERCLOCK, "EWRAM overclock", + ewramOverclock == 1 ? "ON" : "OFF", 10); printOption(OPTION_PS2_INPUT, "PS/2 input", - backgroundVideos > 0 ? "---" : (ps2Input > 0 ? "ON" : "OFF"), 11); + hqMode > 0 ? "---" : (ps2Input > 0 ? "ON" : "OFF"), 11); printOption(OPTION_RUMBLE_OPTS, "[RUMBLE OPTIONS]", "", 13); printOption(OPTION_CUSTOM_OFFSETS, "[CUSTOM OFFSETS]", "", 14); @@ -177,21 +176,21 @@ bool AdminScene::selectOption(u32 selected, int direction) { switch (selected) { case 0: { SAVEFILE_write8(SRAM->adminSettings.rumbleFrames, - 1 + change(rumbleFrames - 1, 8, direction)); + 1 + change(rumbleFrames - 1, 12, direction)); return true; } case 1: { - SAVEFILE_write8( - SRAM->adminSettings.rumbleOpts, - RUMBLE_OPTS_BUILD(1 + change(rumblePreRollFrames - 1, 8, direction), - rumbleIdleCyclePeriod)); + SAVEFILE_write8(SRAM->adminSettings.rumbleOpts, + RUMBLE_OPTS_BUILD( + 1 + change(rumblePreRollFrames - 1, 12, direction), + rumbleIdleCyclePeriod)); return true; } case 2: { - SAVEFILE_write8(SRAM->adminSettings.rumbleOpts, - RUMBLE_OPTS_BUILD(rumblePreRollFrames, - 2 + change(rumbleIdleCyclePeriod - 2, - 5, direction))); + SAVEFILE_write8( + SRAM->adminSettings.rumbleOpts, + RUMBLE_OPTS_BUILD(rumblePreRollFrames, + change(rumbleIdleCyclePeriod, 7, direction))); return true; } case 3: { @@ -335,43 +334,34 @@ bool AdminScene::selectOption(u32 selected, int direction) { change(value, 3, direction)); return true; } - case OPTION_BACKGROUND_VIDEOS: { + case OPTION_HQ_MODE: { u8 ps2Input = SAVEFILE_read8(SRAM->adminSettings.ps2Input); if (ps2Input > 0) return true; - u8 backgroundVideos = - SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); - u8 updatedBackgroundVideos = change(backgroundVideos, 5, direction); - bool wasOn = backgroundVideos > 1; - bool isOn = updatedBackgroundVideos > 1; + u8 hqMode = SAVEFILE_read8(SRAM->adminSettings.hqMode); + u8 updatedHQMode = change(hqMode, 5, direction); + bool wasOn = hqMode > 1; + bool isOn = updatedHQMode > 1; if (wasOn && isOn) { - SAVEFILE_write8(SRAM->adminSettings.backgroundVideos, - updatedBackgroundVideos); + SAVEFILE_write8(SRAM->adminSettings.hqMode, updatedHQMode); PlaybackState.isPCMDisabled = - static_cast(updatedBackgroundVideos) == - BackgroundVideosOpts::dVIDEO_ONLY; + static_cast(updatedHQMode) == HQModeOpts::dVIDEO_ONLY; return true; } else { player_stop(); - engine->transitionIntoScene(backgroundVideos > 0 - ? SEQUENCE_deactivateVideo() - : SEQUENCE_activateVideo(true), + engine->transitionIntoScene(hqMode > 0 ? SEQUENCE_deactivateVideo() + : SEQUENCE_activateVideo(true), new PixelTransitionEffect()); return false; } } case OPTION_EWRAM_OVERCLOCK: { - u8 backgroundVideos = - SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); u8 ewramOverclock = SAVEFILE_read8(SRAM->adminSettings.ewramOverclock); if (ewramOverclock > 0) { - if (backgroundVideos > 0) - return true; - player_stop(); engine->transitionIntoScene(SEQUENCE_deactivateEWRAMOverclock(), new PixelTransitionEffect()); @@ -386,9 +376,8 @@ bool AdminScene::selectOption(u32 selected, int direction) { } } case OPTION_PS2_INPUT: { - u8 backgroundVideos = - SAVEFILE_read8(SRAM->adminSettings.backgroundVideos); - if (backgroundVideos > 0) + u8 hqMode = SAVEFILE_read8(SRAM->adminSettings.hqMode); + if (hqMode > 0) return true; u8 value = SAVEFILE_read8(SRAM->adminSettings.ps2Input); diff --git a/src/scenes/CalibrateScene.cpp b/src/scenes/CalibrateScene.cpp index 664a7733..4a8bea55 100644 --- a/src/scenes/CalibrateScene.cpp +++ b/src/scenes/CalibrateScene.cpp @@ -157,6 +157,7 @@ void CalibrateScene::processKeys(u16 keys) { void CalibrateScene::printTitle() { TextStream::instance().setFontColor(TEXT_COLOR); + TextStream::instance().setFontSubcolor(text_bg_palette_default_subcolor); TextStream::instance().clear(); SCENE_write(TITLE, TEXT_ROW_TITLE); diff --git a/src/scenes/ControlsScene.cpp b/src/scenes/ControlsScene.cpp index 45872fd8..b442ed14 100644 --- a/src/scenes/ControlsScene.cpp +++ b/src/scenes/ControlsScene.cpp @@ -55,6 +55,7 @@ void ControlsScene::load() { setUpSpritesPalette(); setUpBackground(); + pixelBlink = std::unique_ptr{new PixelBlink(PIXEL_BLINK_LEVEL)}; setUpArrows(); diff --git a/src/scenes/DanceGradeScene.cpp b/src/scenes/DanceGradeScene.cpp index bacd7995..9ba56e76 100644 --- a/src/scenes/DanceGradeScene.cpp +++ b/src/scenes/DanceGradeScene.cpp @@ -6,6 +6,7 @@ #include "gameplay/Key.h" #include "gameplay/Sequence.h" #include "gameplay/multiplayer/Syncer.h" +#include "objects/score/combo/Combo.h" #include "player/PlaybackState.h" #include "utils/SceneUtils.h" #include "utils/StringUtils.h" @@ -25,15 +26,15 @@ extern "C" { const u32 ID_MAIN_BACKGROUND = 1; const u32 BANK_BACKGROUND_TILES = 0; const u32 BANK_BACKGROUND_MAP = 16; -const u32 TEXT_COLOR = 0x7FFF; +const u32 TEXT_COLOR = 0b111111111111101; const u32 TEXT_ROW = 17; const u32 SCORE_DIGITS = 8; const u32 TOTALS_X[] = {11, 160}; -const u32 TOTALS_Y[] = {37, 53, 69, 85, 101}; -const u32 TOTAL_MAX_COMBO_Y = 117; +const u32 TOTALS_Y[] = {37 - 2, 53 - 2, 69 - 2, 85 - 2, 101 - 2}; +const u32 TOTAL_MAX_COMBO_Y = 117 - 2; const u32 GRADE_X = 88; -const u32 GRADE_Y = 52; +const u32 GRADE_Y = 52 - 2; const u32 MINI_GRADE_X[] = {37, 187}; const u32 MINI_GRADE_Y = 137; @@ -41,12 +42,18 @@ DanceGradeScene::DanceGradeScene(std::shared_ptr engine, const GBFS_FILE* fs, std::unique_ptr evaluation, std::unique_ptr remoteEvaluation, + std::string songTitle, + std::string songArtist, + std::string songLevel, bool differentCharts, bool isLastSong) : Scene(engine) { this->fs = fs; this->evaluation = std::move(evaluation); this->remoteEvaluation = std::move(remoteEvaluation); + this->songTitle = songTitle; + this->songArtist = songArtist; + this->songLevel = songLevel; this->differentCharts = differentCharts; this->isLastSong = isLastSong; } @@ -90,11 +97,21 @@ void DanceGradeScene::load() { setUpBackground(); printScore(); + SCENE_write(songTitle, 1); + TextStream::instance().setText( + "- " + songArtist + " -", 2, + TEXT_MIDDLE_COL - (songArtist.length() + 4) / 2); + SCENE_write(songLevel, 3); + + bool has4Digits = evaluation->needs4Digits() || + (isVs() && remoteEvaluation->needs4Digits()); + u32 totalsX = TOTALS_X[!isVs() || syncer->getLocalPlayerId() == 1]; for (u32 i = 0; i < totals.size(); i++) - totals[i] = std::unique_ptr{new Total(totalsX, TOTALS_Y[i], i == 0)}; - maxComboTotal = - std::unique_ptr{new Total(totalsX, TOTAL_MAX_COMBO_Y, false)}; + totals[i] = std::unique_ptr{ + new Total(totalsX, TOTALS_Y[i], has4Digits, i == 0)}; + maxComboTotal = std::unique_ptr{ + new Total(totalsX, TOTAL_MAX_COMBO_Y, has4Digits, false)}; totals[FeedbackType::PERFECT]->setValue(evaluation->perfects); totals[FeedbackType::GREAT]->setValue(evaluation->greats); @@ -120,9 +137,9 @@ void DanceGradeScene::load() { for (u32 i = 0; i < remoteTotals.size(); i++) remoteTotals[i] = std::unique_ptr{ - new Total(TOTALS_X[remoteId], TOTALS_Y[i], false)}; + new Total(TOTALS_X[remoteId], TOTALS_Y[i], has4Digits, false)}; remoteMaxComboTotal = std::unique_ptr{ - new Total(TOTALS_X[remoteId], TOTAL_MAX_COMBO_Y, false)}; + new Total(TOTALS_X[remoteId], TOTAL_MAX_COMBO_Y, has4Digits, false)}; remoteTotals[FeedbackType::PERFECT]->setValue(remoteEvaluation->perfects); remoteTotals[FeedbackType::GREAT]->setValue(remoteEvaluation->greats); @@ -136,6 +153,8 @@ void DanceGradeScene::load() { grade->get()->setDoubleSize(true); grade->get()->setAffineId(AFFINE_BASE); } + + updateStats(); } void DanceGradeScene::tick(u16 keys) { @@ -238,6 +257,7 @@ void DanceGradeScene::finish() { void DanceGradeScene::printScore() { TextStream::instance().setFontColor(TEXT_COLOR); + TextStream::instance().setFontSubcolor(text_bg_palette_default_subcolor); if (isVs()) { TextStream::instance().scrollNow(0, -1); @@ -294,6 +314,25 @@ u32 DanceGradeScene::getMultiplayerPointsOf(Evaluation* evaluation) { return differentCharts ? evaluation->percent : evaluation->points; } +void DanceGradeScene::updateStats() { + u32 passes = SAVEFILE_read32(SRAM->stats.stagePasses); + SAVEFILE_write32(SRAM->stats.stagePasses, passes + 1); + + GradeType gradeType = isVs() ? miniGrades[0]->getType() : grade->getType(); + if (gradeType == GradeType::S) { + u32 sGrades = SAVEFILE_read32(SRAM->stats.sGrades); + SAVEFILE_write32(SRAM->stats.sGrades, sGrades + 1); + } + + u32 newCombo = evaluation->maxCombo; + if (newCombo > MAX_COMBO) + newCombo = MAX_COMBO; + u32 maxCombo = SAVEFILE_read32(SRAM->stats.maxCombo); + if (newCombo > maxCombo) { + SAVEFILE_write32(SRAM->stats.maxCombo, newCombo); + } +} + void DanceGradeScene::playSound() { auto gradeType = isVs() ? miniGrades[0].get()->getType() : grade->getType(); auto forceGSM = isMultiplayer() || active_flashcart == EZ_FLASH_OMEGA; diff --git a/src/scenes/DanceGradeScene.h b/src/scenes/DanceGradeScene.h index 13754e63..4db511b5 100644 --- a/src/scenes/DanceGradeScene.h +++ b/src/scenes/DanceGradeScene.h @@ -25,6 +25,9 @@ class DanceGradeScene : public Scene { const GBFS_FILE* fs, std::unique_ptr evaluation, std::unique_ptr remoteEvaluation, + std::string songTitle, + std::string songArtist, + std::string songLevel, bool differentCharts, bool isLastSong); @@ -42,6 +45,9 @@ class DanceGradeScene : public Scene { std::unique_ptr evaluation; std::unique_ptr remoteEvaluation; + std::string songTitle; + std::string songArtist; + std::string songLevel; std::unique_ptr grade; std::array, FEEDBACK_TYPES_TOTAL> totals; std::unique_ptr maxComboTotal; @@ -60,6 +66,7 @@ class DanceGradeScene : public Scene { void printScore(); std::string pointsToString(u32 points); u32 getMultiplayerPointsOf(Evaluation* evaluation); + void updateStats(); void playSound(); void processMultiplayerUpdates(); diff --git a/src/scenes/DeathMixScene.cpp b/src/scenes/DeathMixScene.cpp index e56692ef..c06fabdd 100644 --- a/src/scenes/DeathMixScene.cpp +++ b/src/scenes/DeathMixScene.cpp @@ -6,10 +6,12 @@ #include "SongScene.h" #include "assets.h" #include "data/content/_compiled_sprites/palette_selection.h" -#include "gameplay/DeathMix.h" +#include "gameplay/DifficultyLevelDeathMix.h" #include "gameplay/Key.h" +#include "gameplay/NumericLevelDeathMix.h" #include "gameplay/SequenceMessages.h" #include "utils/SceneUtils.h" +#include "utils/StringUtils.h" extern "C" { #include "player/player.h" @@ -28,21 +30,34 @@ const u32 NEXT_X = 198; const u32 NEXT_Y = 112; const u32 MULTIPLIER_X = 143; const u32 MULTIPLIER_Y = 93; +const u32 NUMERIC_LEVEL_X = 134; +const u32 NUMERIC_LEVEL_Y = 112; +const u32 NUMERIC_BUTTON_OFFSET_X = 24; +const u32 NUMERIC_BUTTON_OFFSET_Y = 7; +const u32 TEXT_ROW = 15; +const u32 TEXT_COL = 15; +const u32 MIN_LEVEL = 1; +const u32 MAX_LEVEL = 25; std::vector DeathMixScene::sprites() { auto sprites = TalkScene::sprites(); sprites.push_back(backButton->get()); sprites.push_back(nextButton->get()); - difficulty->render(&sprites); - progress->render(&sprites); - sprites.push_back(gradeBadge->get()); + if (mixMode == MixMode::DEATH) { + difficulty->render(&sprites); + progress->render(&sprites); + sprites.push_back(gradeBadge->get()); + } else { + sprites.push_back(numericLevelBadge->get()); + } sprites.push_back(multiplier->get()); return sprites; } void DeathMixScene::load() { + SAVEFILE_write8(SRAM->state.isPlaying, false); TalkScene::load(); setUpSpritesPalette(); @@ -50,13 +65,19 @@ void DeathMixScene::load() { pixelBlink = std::unique_ptr{new PixelBlink(PIXEL_BLINK_LEVEL)}; multiplier = std::unique_ptr{new Multiplier( MULTIPLIER_X, MULTIPLIER_Y, SAVEFILE_read8(SRAM->mods.multiplier))}; - difficulty = - std::unique_ptr{new Difficulty(DIFFICULTY_X, DIFFICULTY_Y)}; - progress = std::unique_ptr{ - new NumericProgress(PROGRESS_X, PROGRESS_Y)}; - gradeBadge = std::unique_ptr{ - new GradeBadge(GRADE_X, GRADE_Y, false, false)}; - gradeBadge->setType(GradeType::UNPLAYED); + if (mixMode == MixMode::DEATH) { + difficulty = + std::unique_ptr{new Difficulty(DIFFICULTY_X, DIFFICULTY_Y)}; + progress = std::unique_ptr{ + new NumericProgress(PROGRESS_X, PROGRESS_Y)}; + gradeBadge = std::unique_ptr{ + new GradeBadge(GRADE_X, GRADE_Y, false, false)}; + gradeBadge->setType(GradeType::UNPLAYED); + } else { + numericLevelBadge = std::unique_ptr