diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e9c4915a..4904518e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,19 +1,15 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/ubuntu/.devcontainer/base.Dockerfile # [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 -ARG VARIANT="jammy" -FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} -USER vscode +FROM devkitpro/devkitppc # [Optional] Uncomment this section to install additional OS packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # && apt-get -y install --no-install-recommends -RUN sudo dpkg --add-architecture i386 +#RUN sudo dpkg --add-architecture i386 RUN sudo apt-get update && sudo apt-get install -y build-essential -RUN sudo apt-get install -y python3-pip -RUN sudo apt-get install -y libarchive-tools -RUN sudo apt-get install -y clang-format-10 +RUN sudo apt-get install -y libarchive-tools RUN sudo apt-get install -y cmake # RUN sudo apt-get install -y wine64 # RUN sudo apt-get install -y wine @@ -21,19 +17,6 @@ RUN sudo apt-get install -y ninja-build RUN sudo apt-get upgrade -y RUN sudo apt-get install -y libtinfo5 -RUN python3 -m pip install Pillow - -# Install DevkitPPC -RUN sudo ln -sf /proc/self/mounts /etc/mtab -WORKDIR /tmp -COPY install-devkitpro-pacman install-devkitpro-pacman -RUN sudo chmod +x ./install-devkitpro-pacman -RUN sudo ./install-devkitpro-pacman -RUN sudo dkp-pacman -Syu --noconfirm -WORKDIR /etc -RUN sudo ln -sf /proc/self/mounts mtab -RUN sudo dkp-pacman -S --noconfirm gamecube-dev wii-dev - # # Install the patchers # WORKDIR /workspaces/romhack/wii # RUN curl -L https://github.com/zsrtp/romhack-compiler/releases/download/v0.1.1-r2/romhack-v0.1.1-r2-linux-x64-musl.zip | bsdtar -xvf - diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9bd539da..aadd334b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,32 +1,43 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/ubuntu { - "name": "Ubuntu", + "name": "TGPZ", "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 - // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. - "args": { "VARIANT": "ubuntu-20.04" } + "dockerfile": "Dockerfile" }, - "extensions": [ - "ms-vscode.cpptools-extension-pack", - "ms-vscode.makefile-tools", - "ms-python.python", - "ms-vscode.hexeditor", - "twxs.cmake", - "Gruntfuggly.todo-tree", - "bungcip.better-toml", - "mhutchie.git-graph" - ], + "features": { + "ghcr.io/devcontainers/features/python:1": { + "version": "3.12.5" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools-extension-pack", + "ms-vscode.makefile-tools", + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.vscode-pylance", + "ms-vscode.hexeditor", + "twxs.cmake", + "Gruntfuggly.todo-tree", + "bungcip.better-toml", + "mhutchie.git-graph" + ] + } + }, + + "onCreateCommand": "python3 -m pip install Pillow pycryptodome", // Use 'forwardPorts' to make a list of ports inside the container available locally. "runArgs": [ "--network=host" - ], + ] // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "uname -a", // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "vscode" + //"remoteUser": "vscode" } diff --git a/.github/workflows/multi-region-tests.yml b/.github/workflows/multi-region-tests.yml index 042fea45..b97a5561 100644 --- a/.github/workflows/multi-region-tests.yml +++ b/.github/workflows/multi-region-tests.yml @@ -2,7 +2,7 @@ name: Multi-Region Tests on: pull_request: - branches: [ master ] + branches: [ main ] jobs: build: @@ -53,7 +53,7 @@ jobs: dolphin_memory: "0x8044A6C0" iso_name: tpgz.iso container: - image: ghcr.io/pheenoh/zsrtp-tpgz:${{ matrix.container }} + image: ghcr.io/zsrtp/zsrtp-tpgz:${{ matrix.container }} options: --shm-size=128m --ulimit core=-1 --privileged=true name: ${{ matrix.platform }}-${{ matrix.region }} Test steps: @@ -70,4 +70,4 @@ jobs: run: | dolphin-emu-nogui --platform=headless --video_backend=Null -e build/${{ matrix.iso_name }} & sleep 15 - /dme -c ${{ matrix.dolphin_memory }} + dme -d dolphin-emu-nog -a ${{ matrix.dolphin_memory }} -q 0 --platform offscreen diff --git a/.github/workflows/tpgz-release.yml b/.github/workflows/tpgz-release.yml index 8bbb420c..2adc8e3c 100644 --- a/.github/workflows/tpgz-release.yml +++ b/.github/workflows/tpgz-release.yml @@ -20,6 +20,13 @@ jobs: with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ${{ secrets.AWS_REGION }} + - name: Download existing meta.json + run: aws s3 cp s3://${{ secrets.AWS_S3_BUCKET }}/patches/meta.json meta.json + - name: Update meta.json + run: | + python3 external/misc/meta.py + - name: Upload updated meta.json to S3 + run: aws s3 cp meta.json s3://${{ secrets.AWS_S3_BUCKET }}/patches/meta.json --acl public-read - name: Sync directory to S3 run: | aws s3 sync patches/ s3://${{ secrets.AWS_S3_BUCKET }}/patches/ --acl public-read diff --git a/CMakeLists.txt b/CMakeLists.txt index 155868de..29ac53a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ include(cmake/relmapper.cmake) include(cmake/fonts.cmake) project(TPGZ - VERSION 1.0.0 + VERSION 1.1.0 DESCRIPTION "Twilight Princess speedrunning practice and testing tool" HOMEPAGE_URL "tpgz.io" LANGUAGES C CXX ASM) diff --git a/README.md b/README.md index 967829a0..3009f8fe 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ A *Twilight Princess* ROM hack for speedrun practice and research. ## Download ### Web -Patch your TP (GameCube) rom on the web using our website [tpgz.io](https://tpgz.io). -- This uses a lot of memory, so it requires a decent computer. -- The Wii version is currently not supported for web patching. Please follow the offline patching guide. +Patch your TP (GameCube/Wii) rom on the web using our website [tpgz.io](https://tpgz.io). ### Offline To patch your rom offline, please follow our [guide](./docs/CreatingAnIso.md). diff --git a/RomHack.toml.in b/RomHack.toml.in index a6d3e6a0..675cb76f 100644 --- a/RomHack.toml.in +++ b/RomHack.toml.in @@ -25,8 +25,8 @@ iso = "@TPGZ_CFG_BLD_ISO@" "tpgz/save_files/any" = "../@TPGZ_CFG_SAVE_ANY_PATH@/any" # any% bite saves -"tpgz/save_files/any_bite.bin" = "../res/save_files/any_bite.bin" -"tpgz/save_files/any_bite" = "../res/save_files/any_bite" +"tpgz/save_files/any_bite.bin" = "../@TPGZ_CFG_SAVE_ANY_PATH@/any_bite.bin" +"tpgz/save_files/any_bite" = "../@TPGZ_CFG_SAVE_ANY_PATH@/any_bite" # 100% saves "tpgz/save_files/hundo.bin" = "../res/save_files/hundo.bin" diff --git a/external/gcn_c/include/nand.h b/external/gcn_c/include/nand.h index d5cac321..109d6323 100644 --- a/external/gcn_c/include/nand.h +++ b/external/gcn_c/include/nand.h @@ -10,6 +10,10 @@ #define NAND_OPEN_WRITE 0x02 #define NAND_OPEN_RW (NAND_OPEN_READ | NAND_OPEN_WRITE) +#define NAND_SEEK_BEG 0 +#define NAND_SEEK_CUR 1 +#define NAND_SEEK_END 2 + typedef struct NANDInfo { uint8_t unk[0x90]; } NANDInfo; diff --git a/external/gcn_c/include/storage.h b/external/gcn_c/include/storage.h index 477dcfed..7642c4e7 100644 --- a/external/gcn_c/include/storage.h +++ b/external/gcn_c/include/storage.h @@ -10,6 +10,9 @@ #define OPEN_MODE_READ #define OPEN_MODE_WRITE #define OPEN_MODE_RW +#define STORAGE_SEEK_BEG 0 +#define STORAGE_SEEK_CUR 1 +#define STORAGE_SEEK_END 2 #else // WII_PLATFORM #include "nand.h" #define STORAGE_FILENAME_MAX NAND_FILENAME_MAX @@ -17,6 +20,9 @@ #define OPEN_MODE_READ NAND_OPEN_READ #define OPEN_MODE_WRITE NAND_OPEN_WRITE #define OPEN_MODE_RW NAND_OPEN_RW +#define STORAGE_SEEK_BEG NAND_SEEK_BEG +#define STORAGE_SEEK_CUR NAND_SEEK_CUR +#define STORAGE_SEEK_END NAND_SEEK_END #endif // WII_PLATFORM enum StorageError { @@ -45,6 +51,7 @@ typedef struct Storage { int32_t result; char file_name_buffer[STORAGE_FILENAME_MAX * 2]; uint32_t result_size; + uint32_t position; } Storage; #ifndef WII_PLATFORM @@ -52,10 +59,26 @@ typedef struct Storage { #define StorageDelete(ch, fileName) CARDDelete(ch, fileName) #define StorageOpen(ch, fileName, fileInfo, mode) CARDOpen(ch, fileName, fileInfo) #define StorageClose(fileInfo) CARDClose(fileInfo) -#define StorageRead(storage, data, length, offset) \ - ({ (storage).result = CARDRead(&(storage).info, data, length, offset); }) -#define StorageWrite(storage, data, length, offset) \ - ({ (storage).result = CARDWrite(&(storage).info, data, length, offset); }) +#define StorageRead(storage, data, length) \ + ({ (storage).result = CARDRead(&(storage).info, data, length, (storage).position); (storage).position += length; (storage).result; }) +#define StorageWrite(storage, data, length) \ + ({ (storage).result = CARDWrite(&(storage).info, data, length, (storage).position); (storage).position += length; (storage).result; }) +inline int32_t StorageSeek(Storage* storage, int32_t offset, int32_t whence) { + switch (whence) { + case STORAGE_SEEK_BEG: + storage->position = (uint32_t)offset; + break; + case STORAGE_SEEK_CUR: + storage->position += offset; + break; + case STORAGE_SEEK_END: + storage->position = storage->info.length + offset; + break; + default: + return IoError; + } + return storage->position; +} #else // WII_PLATFORM #define StorageCreate(ch, fileName, size, fileBuffer) \ ({ \ @@ -66,20 +89,17 @@ typedef struct Storage { #define StorageDelete(ch, fileName) NANDDelete(fileName) #define StorageOpen(ch, fileName, fileInfo, mode) NANDOpen(fileName, fileInfo, mode) #define StorageClose(fileInfo) NANDClose(fileInfo) -#define StorageRead(storage, data, length, offset) \ +#define StorageRead(storage, data, length) \ ({ \ - (storage).result = NANDSeek(&(storage).info, offset, 0); \ - if ((storage).result == Ready) { \ - (storage).result_size = NANDRead(&(storage).info, data, length); \ - } \ + (storage).result_size = NANDRead(&(storage).info, data, length); \ + (storage).result = Ready; \ }) -#define StorageWrite(storage, data, length, offset) \ +#define StorageWrite(storage, data, length) \ ({ \ - (storage).result = NANDSeek(&(storage).info, offset, 0); \ - if ((storage).result == Ready) { \ - (storage).result_size = NANDWrite(&(storage).info, data, length); \ - } \ + (storage).result_size = NANDWrite(&(storage).info, data, length); \ + (storage).result = Ready; \ }) +#define StorageSeek(storage, offset, whence) NANDSeek(&(*(storage)).info, offset, whence) #endif // WII_PLATFORM #endif // __STORAGE_H__ \ No newline at end of file diff --git a/external/libtp_c/include/JSystem/JAudio2/JAISound.h b/external/libtp_c/include/JSystem/JAudio2/JAISound.h index a8c7fe43..6ff6c0f1 100644 --- a/external/libtp_c/include/JSystem/JAudio2/JAISound.h +++ b/external/libtp_c/include/JSystem/JAudio2/JAISound.h @@ -8,12 +8,31 @@ class JAISoundID { public: - operator u32() const { return this->mId; } - JAISoundID(u32 pId) { mId = pId; }; + operator u32() const { return this->mId.mFullId; } + + JAISoundID(u32 pId) { mId.mFullId = pId; }; + + JAISoundID(JAISoundID const& other) { mId = other.mId; }; + JAISoundID() {} -private: - u32 mId; + bool isAnonymous() { return mId.mFullId == 0xffffffff; } + void setAnonymous() { mId.mFullId = -1; } + + union { + u32 mFullId; + struct { + u8 b0; + u8 b1; + u8 b2; + u8 b3; + } mBytes; + struct { + u16 mSoundType; + u16 mShortId; + } mAdvancedId; // Debug doesn't have an inline for referencing the short ID so I assume + // it's similar to this + } mId; }; struct JASTrack {}; diff --git a/external/libtp_c/include/SSystem/SComponent/c_phase.h b/external/libtp_c/include/SSystem/SComponent/c_phase.h new file mode 100644 index 00000000..917f85ac --- /dev/null +++ b/external/libtp_c/include/SSystem/SComponent/c_phase.h @@ -0,0 +1,22 @@ +#ifndef C_PHASE_H +#define C_PHASE_H + +#include "../../dolphin/types.h" + +typedef int (*cPhs__Handler)(void*); + +enum cPhs__Step { + /* 0x0 */ cPhs_INIT_e, + /* 0x1 */ cPhs_LOADING_e, + /* 0x2 */ cPhs_NEXT_e, + /* 0x3 */ cPhs_UNK3_e, // appears to be an alternate error code, unsure how it differs + /* 0x4 */ cPhs_COMPLEATE_e, + /* 0x5 */ cPhs_ERROR_e, +}; + +typedef struct request_of_phase_process_class { + cPhs__Handler* mpHandlerTable; + int id; +} request_of_phase_process_class; + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/Z2AudioLib/Z2AudioMgr.h b/external/libtp_c/include/Z2AudioLib/Z2AudioMgr.h index 4d93ef79..053c0bab 100644 --- a/external/libtp_c/include/Z2AudioLib/Z2AudioMgr.h +++ b/external/libtp_c/include/Z2AudioLib/Z2AudioMgr.h @@ -12,6 +12,7 @@ #include "Z2SoundStarter.h" #include "Z2SpeechMgr2.h" #include "Z2StatusMgr.h" +#include "../defines.h" #ifdef GCN_PLATFORM class Z2AudioMgr { @@ -62,8 +63,24 @@ class Z2AudioMgr { }; #endif -/* inline Z2AudioMgr* Z2GetAudioMgr() { - return Z2AudioMgr::getInterface(); -} */ +#ifdef WII_PLATFORM +#define mAudioMgrPtr Z2SeMgr__mAudioMgrPtr +#else +#define mAudioMgrPtr mAudioMgrPtr__10Z2AudioMgr +#endif + +extern "C" Z2AudioMgr* mAudioMgrPtr; + +inline Z2AudioMgr* Z2GetAudioMgr() { + return mAudioMgrPtr; +} + +LIBTP_DEFINE_FUNC(seStart__7Z2SeMgrF10JAISoundIDPC3VecUlScffffUc, + Z2SeMgr__seStart_JAISoundID__Vec_const____unsigned_long__signed_char__float__float__float__float__unsigned_char_, + bool, Z2SeMgr__seStart, (Z2SeMgr*, JAISoundID, Vec const*, u32, s8, f32, f32, f32, f32, u8)) + +LIBTP_DEFINE_FUNC(seStop__7Z2SeMgrF10JAISoundIDUl, + Z2SeMgr__seStop_JAISoundID__unsigned_long_, + bool, Z2SeMgr__seStop, (Z2SeMgr*, JAISoundID, u32)) #endif /* Z2AUDIOMGR_H */ \ No newline at end of file diff --git a/external/libtp_c/include/d/com/d_com_inf_game.h b/external/libtp_c/include/d/com/d_com_inf_game.h index 57e4c683..65c5d715 100644 --- a/external/libtp_c/include/d/com/d_com_inf_game.h +++ b/external/libtp_c/include/d/com/d_com_inf_game.h @@ -344,6 +344,9 @@ extern TitleScreenInfo l_fpcNdRq_Queue; LIBTP_DEFINE_FUNC(getLayerNo_common_common__14dComIfG_play_cFPCcii, dComIfG_play_c__getLayerNo_common_common_char_const____int__int_, int, tp_getLayerNo, (const char* stageName, int roomId, int layerOverride)) +LIBTP_DEFINE_FUNC(getLayerNo__14dComIfG_play_cFi, dComIfG_play_c__getLayerNo_int_, + int, dComIfG_play_c__getLayerNo, (int)) + inline dBgS* dComIfG_Bgsp() { return &g_dComIfG_gameInfo.play.mDBgS; } @@ -432,6 +435,9 @@ inline void dComIfGs_setLife(u16 amount) { inline void dComIfGs_setMaxLife(u8 max) { g_dComIfG_gameInfo.info.getPlayer().getPlayerStatusA().setMaxLife(max); } +inline void dComIfGs_setCollectSmell(u8 smell_id) { + g_dComIfG_gameInfo.info.getPlayer().getPlayerStatusA().setSelectEquip(3, smell_id); +} /* inline void dComIfGs_onDungeonItemBossKey(void) { g_dComIfG_gameInfo.info.getMemory().getBit().onDungeonItemBossKey(); @@ -619,6 +625,10 @@ inline void dComIfGs_offSwitch(int i_no, int i_roomNo) { dSv_info_c__offSwitch(&g_dComIfG_gameInfo.info, i_no, i_roomNo); } +inline BOOL dComIfGs_isSwitch(int i_no, int i_roomNo) { + return dSv_info_c__isSwitch(&g_dComIfG_gameInfo.info, i_no, i_roomNo); +} + inline void dComIfGs_putSave(int i_stageNo) { tp_putSave(&g_dComIfG_gameInfo.info, i_stageNo); } @@ -700,6 +710,18 @@ inline void dComIfGs_offEventBit(u16 flag) { dSv_event_c__offEventBit(&g_dComIfG_gameInfo.info.mSavedata.mEvent, flag); } +inline bool dComIfGs_isTmpBit(u16 flag) { + return dSv_event_c__isEventBit(&g_dComIfG_gameInfo.info.mTmp, flag); +} + +inline void dComIfGs_onTmpBit(u16 flag) { + dSv_event_c__onEventBit(&g_dComIfG_gameInfo.info.mTmp, flag); +} + +inline void dComIfGs_offTmpBit(u16 flag) { + dSv_event_c__offEventBit(&g_dComIfG_gameInfo.info.mTmp, flag); +} + inline void dComIfGs_setKeyNum(u8 num) { g_dComIfG_gameInfo.info.getMemory().getBit().setKeyNum(num); } @@ -753,6 +775,20 @@ LIBTP_DEFINE_FUNC(dComIfGs_onOneZoneSwitch__Fii, dComIfGs_onOneZoneSwitch_int__i LIBTP_DEFINE_FUNC(dComIfGs_onZoneSwitch__Fii, dComIfGs_onZoneSwitch_int__int_, void, dComIfGs_onZoneSwitch, (int, int)) +LIBTP_DEFINE_FUNC(setEventReg__11dSv_event_cFUsUc, dSv_event_c__setEventReg_unsigned_short__unsigned_char_, + void, dSv_event_c__setEventReg, (dSv_event_c*, u16, u8)) + +LIBTP_DEFINE_FUNC(getEventReg__11dSv_event_cCFUs, dSv_event_c__getEventReg_unsigned_short__const, + u8, dSv_event_c__getEventReg, (dSv_event_c*, u16)) + +inline void dComIfGs_setEventReg(u16 flag, u8 value) { + dSv_event_c__setEventReg(&g_dComIfG_gameInfo.info.getSavedata().getEvent(), flag, value); +} + +inline u8 dComIfGs_getEventReg(u16 flag) { + return dSv_event_c__getEventReg(&g_dComIfG_gameInfo.info.getSavedata().getEvent(), flag); +} + class dComIfAc_gameInfo { public: u8 field_0x0[4]; diff --git a/external/libtp_c/include/d/d_stage.h b/external/libtp_c/include/d/d_stage.h index 915c55d3..6d033a7b 100644 --- a/external/libtp_c/include/d/d_stage.h +++ b/external/libtp_c/include/d/d_stage.h @@ -256,4 +256,6 @@ extern dStage_nextStage_c__set_t dStage_nextStage_c__set; #endif extern dStage_roomStatus_c dStage_roomControl_c__mStatus[64]; +extern "C" s8 dStage_roomControl_c__mStayNo; + #endif /* D_D_STAGE_H */ diff --git a/external/libtp_c/include/d/meter/d_meter2_info.h b/external/libtp_c/include/d/meter/d_meter2_info.h index 1372d032..64f2a3de 100644 --- a/external/libtp_c/include/d/meter/d_meter2_info.h +++ b/external/libtp_c/include/d/meter/d_meter2_info.h @@ -25,6 +25,7 @@ class dMeter2Info_c { u8& getDirectUseItem() { return mDirectUseItem; } dMeterMap_c* getMeterMapClass() { return mMeterMap; } void offUseButton(int pButton) { mUseButton &= ~(u16)pButton; } + void offMenuInForce(int flag) { mMenuInForce &= ~(1 << flag); } /* 0x00 */ void* vtable; /* 0x04 */ u8 unk4[4]; @@ -56,7 +57,7 @@ class dMeter2Info_c { /* 0x90 */ u32 mTempBits; /* 0x94 */ s16 mMsgKeyWaitTimer; /* 0x96 */ u16 mHorseLifeCount; - /* 0x98 */ u16 unk152; + /* 0x98 */ u16 mMenuInForce; /* 0x9A */ u16 mHotSpringTimer[4]; /* 0xA2 */ u16 mSub2DStatus; /* 0xA4 */ u16 mFloatingFlowID; diff --git a/external/libtp_c/include/d/s/d_s_logo.h b/external/libtp_c/include/d/s/d_s_logo.h new file mode 100644 index 00000000..09660602 --- /dev/null +++ b/external/libtp_c/include/d/s/d_s_logo.h @@ -0,0 +1,152 @@ +#ifndef D_D_S_LOGO_H +#define D_D_S_LOGO_H + +#include "../../f_op/f_op_scene.h" + +class mDoDvdThd_mountXArchive_c; +class mDoDvdThd_toMainRam_c; +class dDlst_2D_c; +class ResTIMG; +class JKRExpHeap; +class JKRHeap; + + +#if defined(WII_PLATFORM) || defined(GCN_PAL) +class dScnLogo_c { +public: + enum { + /* 0x0 */ EXEC_WARNING_IN, + /* 0x1 */ EXEC_WARNING_DISP, + /* 0x2 */ EXEC_WARNING_OUT, + /* 0x3 */ EXEC_NINTENDO_IN, + /* 0x4 */ EXEC_NINTENDO_OUT, + /* 0x5 */ EXEC_DOLBY_IN, + /* 0x6 */ EXEC_DOLBY_OUT, + /* 0x7 */ EXEC_DOLBY_OUT2, + /* 0x8 */ EXEC_PROG_IN, + /* 0x9 */ EXEC_PROG_SEL, + /* 0xA */ EXEC_PROG_OUT, + /* 0xB */ EXEC_PROG_SET, + /* 0xC */ EXEC_PROG_SET2, + /* 0xD */ EXEC_PROG_CHANGE, + /* 0xE */ EXEC_DVD_WAIT, + /* 0xF */ EXEC_SCENE_CHANGE, + }; + + /* 0x000*/ u8 field_0x00[0x20c]; + /* 0x20C */ u8 mExecCommand; + /* 0x20D */ u8 field_0x209; + /* 0x20E */ u8 field_0x20a; + /* 0x20F */ u8 field_0x20b; + /* 0x210 */ u16 mTimer; +}; +#else +class dScnLogo_c : public scene_class { +public: + enum { + /* 0x0 */ EXEC_WARNING_IN, + /* 0x1 */ EXEC_WARNING_DISP, + /* 0x2 */ EXEC_WARNING_OUT, + /* 0x3 */ EXEC_NINTENDO_IN, + /* 0x4 */ EXEC_NINTENDO_OUT, + /* 0x5 */ EXEC_DOLBY_IN, + /* 0x6 */ EXEC_DOLBY_OUT, + /* 0x7 */ EXEC_DOLBY_OUT2, + /* 0x8 */ EXEC_PROG_IN, + /* 0x9 */ EXEC_PROG_SEL, + /* 0xA */ EXEC_PROG_OUT, + /* 0xB */ EXEC_PROG_SET, + /* 0xC */ EXEC_PROG_SET2, + /* 0xD */ EXEC_PROG_CHANGE, + /* 0xE */ EXEC_DVD_WAIT, + /* 0xF */ EXEC_SCENE_CHANGE, + }; + + dScnLogo_c() {} + /* 802560B4 */ void preLoad_dyl_create(); + /* 802560F8 */ void preLoad_dyl_remove(); + /* 8025611C */ bool preLoad_dyl(); + /* 80256198 */ void checkProgSelect(); + /* 80256210 */ int draw(); + /* 80256264 */ void progInDraw(); + /* 8025631C */ void progSelDraw(); + /* 802568E0 */ void progOutDraw(); + /* 80256A3C */ void progSetDraw(); + /* 80256AC0 */ void progSet2Draw(); + /* 80256B3C */ void progChangeDraw(); + /* 80256BF4 */ void warningInDraw(); + /* 80256C68 */ void warningDispDraw(); + /* 80256DC4 */ void warningOutDraw(); + /* 80256E48 */ void nintendoInDraw(); + /* 80256ECC */ void nintendoOutDraw(); + /* 80256F50 */ void dolbyInDraw(); + /* 80256FD4 */ void dolbyOutDraw(); + /* 80257058 */ void dolbyOutDraw2(); + /* 80257070 */ void dvdWaitDraw(); + /* 80257284 */ void nextSceneChange(); + /* 802572B8 */ ~dScnLogo_c(); + /* 80257AE0 */ int create(); + /* 80257C64 */ void logoInitGC(); + /* 80257FEC */ void dvdDataLoad(); + /* 802584D8 */ void setProgressiveMode(u8); + /* 802584FC */ u8 getProgressiveMode(); + /* 80258520 */ bool isProgressiveMode(); + /* 8025854C */ void setRenderMode(); + +public: + /* 0x1C4 */ request_of_phase_process_class field_0x1c4; + /* 0x1CC */ mDoDvdThd_toMainRam_c* sceneCommand; + /* 0x1D0 */ JKRExpHeap* field_0x1d0; + /* 0x1D4 */ JKRExpHeap* field_0x1d4; + /* 0x1D8 */ JKRHeap* mpHeap; + /* 0x1DC */ dDlst_2D_c* mWarning; + /* 0x1E0 */ dDlst_2D_c* mWarningStart; + /* 0x1E4 */ dDlst_2D_c* mNintendoLogo; + /* 0x1E8 */ dDlst_2D_c* mDolbyLogo; + /* 0x1EC */ dDlst_2D_c* mProgressiveChoice; + /* 0x1F0 */ dDlst_2D_c* mProgressiveYes; + /* 0x1F4 */ dDlst_2D_c* mProgressiveNo; + /* 0x1F8 */ dDlst_2D_c* mProgressiveSel; + /* 0x1FC */ request_of_phase_process_class* m_preLoad_dylPhase; + /* 0x200 */ ResTIMG* mProgressivePro; + /* 0x204 */ ResTIMG* mProgressiveInter; + /* 0x208 */ u8 mExecCommand; + /* 0x209 */ u8 field_0x209; + /* 0x20A */ u8 field_0x20a; + /* 0x20B */ u8 field_0x20b; + /* 0x20C */ u16 mTimer; + /* 0x20E */ u16 field_0x20e; + /* 0x210 */ u16 field_0x210; + /* 0x212 */ u16 field_0x212; + /* 0x214 */ u16 field_0x214; + /* 0x218 */ u32 field_0x218; + /* 0x21C */ void* buffer; + /* 0x220 */ mDoDvdThd_mountXArchive_c* mpField0Command; + /* 0x224 */ mDoDvdThd_mountXArchive_c* mpAlAnmCommand; + /* 0x228 */ u8 field_0x228[4]; + /* 0x22C */ mDoDvdThd_mountXArchive_c* mpFmapResCommand; + /* 0x230 */ mDoDvdThd_mountXArchive_c* mpDmapResCommand; + /* 0x234 */ mDoDvdThd_mountXArchive_c* mpCollectResCommand; + /* 0x238 */ u8 field_0x238[4]; + /* 0x23C */ mDoDvdThd_mountXArchive_c* mpItemIconCommand; + /* 0x240 */ mDoDvdThd_mountXArchive_c* mpRingResCommand; + /* 0x244 */ u8 field_0x244[4]; + /* 0x248 */ mDoDvdThd_mountXArchive_c* mpPlayerNameCommand; + /* 0x24C */ mDoDvdThd_mountXArchive_c* mpItemInfResCommand; + /* 0x250 */ mDoDvdThd_mountXArchive_c* mpButtonCommand; + /* 0x254 */ u8 field_0x254[4]; + /* 0x258 */ mDoDvdThd_mountXArchive_c* mpCardIconCommand; + /* 0x25C */ mDoDvdThd_mountXArchive_c* mpBmgResCommand; + /* 0x260 */ mDoDvdThd_mountXArchive_c* mpMsgComCommand; + /* 0x264 */ mDoDvdThd_mountXArchive_c* mpMsgResCommand[7]; + /* 0x280 */ u8 field_0x280[0x10]; + /* 0x290 */ mDoDvdThd_mountXArchive_c* mpFontResCommand; + /* 0x294 */ mDoDvdThd_mountXArchive_c* mpMain2DCommand; + /* 0x298 */ mDoDvdThd_mountXArchive_c* mpRubyResCommand; + /* 0x29C */ mDoDvdThd_toMainRam_c* mParticleCommand; + /* 0x2A0 */ mDoDvdThd_toMainRam_c* mItemTableCommand; + /* 0x2A4 */ mDoDvdThd_toMainRam_c* mEnemyItemCommand; +}; +#endif + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/d/save/d_save.h b/external/libtp_c/include/d/save/d_save.h index 6f9f08c7..703a5637 100644 --- a/external/libtp_c/include/d/save/d_save.h +++ b/external/libtp_c/include/d/save/d_save.h @@ -783,6 +783,7 @@ class dSv_info_c { dSv_memory_c& getMemory() { return mMemory; } dSv_zone_c* getZones() { return mZone; } dSv_player_c& getPlayer() { return mSavedata.getPlayer(); } + dSv_event_c& getEvent() { return mTmp; } dSv_event_c& getTmp() { return mTmp; } /* 0x000 */ dSv_save_c mSavedata; @@ -850,6 +851,9 @@ LIBTP_DEFINE_FUNC(onSwitch__10dSv_info_cFii, dSv_info_c__onSwitch_int__int_, LIBTP_DEFINE_FUNC(offSwitch__10dSv_info_cFii, dSv_info_c__offSwitch_int__int_, void, dSv_info_c__offSwitch, (void* addr, int i_no, int i_roomNo)) +LIBTP_DEFINE_FUNC(isSwitch__10dSv_info_cCFii, dSv_info_c__isSwitch_int__int__const, + BOOL, dSv_info_c__isSwitch, (void* addr, int i_no, int i_roomNo)) + LIBTP_DEFINE_FUNC(isSwitch__12dSv_memBit_cCFi, dSv_memBit_c__isSwitch_int__const, bool, dSv_memBit_c__isSwitch, (void* addr, int i_no)) diff --git a/external/libtp_c/include/f_op/f_op_actor_mng.h b/external/libtp_c/include/f_op/f_op_actor_mng.h index 2c01efdf..38f3018f 100644 --- a/external/libtp_c/include/f_op/f_op_actor_mng.h +++ b/external/libtp_c/include/f_op/f_op_actor_mng.h @@ -272,6 +272,9 @@ LIBTP_DEFINE_FUNC(fopAcM_seenActorAngleY__FPC10fopAc_ac_cPC10fopAc_ac_c, fopAcM_ LIBTP_DEFINE_FUNC(gndCheck__11fopAcM_gc_cFPC4cXyz, fopAcM_gc_c__gndCheck_cXyz_const___, bool, fopAcM_gc_c__gndCheck, (const cXyz*)) +LIBTP_DEFINE_FUNC(fopAcM_CreateAppend__Fv, fopAcM_CreateAppend_void_, + fopAcM_prm_class*, fopAcM_CreateAppend, (void)) + #define tp_fopAcM_gc_c__mGroundY_addr 0x80450cd0 #define tp_fopAcM_gc_c__mGroundY (*(f32*)(tp_fopAcM_gc_c__mGroundY_addr)) diff --git a/external/libtp_c/include/f_op/f_op_scene.h b/external/libtp_c/include/f_op/f_op_scene.h new file mode 100644 index 00000000..eda0a9a6 --- /dev/null +++ b/external/libtp_c/include/f_op/f_op_scene.h @@ -0,0 +1,22 @@ +#ifndef F_F_OP_SCENE_H_ +#define F_F_OP_SCENE_H_ + +#include "../f_op/f_op_scene_tag.h" + +struct request_of_phase_process_class; +class mDoDvdThd_command_c; + +typedef struct scene_process_profile_definition { + /* 0x00 */ node_process_profile_definition mBase; + /* 0x20 */ process_method_class* mpMtd; // Subclass methods + /* 0x24 */ u32 field_0x24; // padding? +} scene_process_profile_definition; + +class scene_class { +public: + /* 0x000 */ process_node_class mBase; + /* 0x1AC */ process_method_class * mpMtd; + /* 0x1B0 */ scene_tag_class mScnTg; +}; + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/f_op/f_op_scene_tag.h b/external/libtp_c/include/f_op/f_op_scene_tag.h new file mode 100644 index 00000000..d99b933c --- /dev/null +++ b/external/libtp_c/include/f_op/f_op_scene_tag.h @@ -0,0 +1,12 @@ +#ifndef F_OP_SCENE_TAG_H +#define F_OP_SCENE_TAG_H + +#include "../f_pc/f_pc_node.h" +#include "../SSystem/SComponent/c_phase.h" + +class scene_tag_class { +public: + u8 field_0x00[0x14]; +}; + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/f_pc/f_pc_create_req.h b/external/libtp_c/include/f_pc/f_pc_create_req.h new file mode 100644 index 00000000..383c0aab --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_create_req.h @@ -0,0 +1,31 @@ + +#ifndef F_PC_CREATE_REQ_H_ +#define F_PC_CREATE_REQ_H_ + +#include "../SSystem/SComponent/c_phase.h" +#include "f_pc_create_tag.h" +#include "f_pc_method.h" +#include "f_pc_method_tag.h" + +typedef struct base_process_class base_process_class; +typedef struct layer_class layer_class; + +typedef struct create_request_method_class { + cPhs__Handler mpHandler; + process_method_func mpCancel; + process_method_func mpDelete; +} create_request_method_class; + +typedef struct create_request { + create_tag mBase; + s8 mbIsCreating; + s8 mbIsCancelling; + process_method_tag_class mMtdTg; + create_request_method_class* mpCtRqMtd; + void* mpUnk1; + s32 mBsPcId; + struct base_process_class* mpRes; + layer_class* mpLayer; +} create_request; // Size: 0x48 + +#endif diff --git a/external/libtp_c/include/f_pc/f_pc_create_tag.h b/external/libtp_c/include/f_pc/f_pc_create_tag.h new file mode 100644 index 00000000..2ddc7ed6 --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_create_tag.h @@ -0,0 +1,14 @@ + +#ifndef F_PC_CREATE_TAG_H_ +#define F_PC_CREATE_TAG_H_ + +#include "../SSystem/SComponent/c_list.h" +#include "../SSystem/SComponent/c_tag.h" + +typedef struct create_tag { + create_tag_class mBase; +} create_tag; + +extern "C" node_list_class g_fpcCtTg_Queue; + +#endif diff --git a/external/libtp_c/include/f_pc/f_pc_executor.h b/external/libtp_c/include/f_pc/f_pc_executor.h new file mode 100644 index 00000000..c24d192f --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_executor.h @@ -0,0 +1,19 @@ + +#ifndef F_PC_EXECUTOR_H_ +#define F_PC_EXECUTOR_H_ + +#include "f_pc_layer_iter.h" +#include "f_pc_line_iter.h" + +typedef struct base_process_class base_process_class; + +// base_process_class* fpcEx_Search(fpcLyIt_JudgeFunc pFunc, void* pUserData); +base_process_class* fpcEx_SearchByID(unsigned int id); +BOOL fpcEx_IsExist(unsigned int id); +s32 fpcEx_ToLineQ(base_process_class* pProc); +s32 fpcEx_ExecuteQTo(base_process_class* pProc); +s32 fpcEx_Execute(base_process_class* pProc); +s32 fpcEx_ToExecuteQ(base_process_class* pProc); +void fpcEx_Handler(fpcLnIt_QueueFunc pFunc); + +#endif diff --git a/external/libtp_c/include/f_pc/f_pc_layer.h b/external/libtp_c/include/f_pc/f_pc_layer.h index 43cab5d4..3a387b4a 100644 --- a/external/libtp_c/include/f_pc/f_pc_layer.h +++ b/external/libtp_c/include/f_pc/f_pc_layer.h @@ -21,4 +21,7 @@ typedef struct layer_class { } counts; } layer_class; +LIBTP_DEFINE_FUNC(fpcLy_CurrentLayer__Fv, fpcLy_CurrentLayer_void_, + layer_class*, fpcLy_CurrentLayer, (void)) + #endif diff --git a/external/libtp_c/include/f_pc/f_pc_layer_iter.h b/external/libtp_c/include/f_pc/f_pc_layer_iter.h new file mode 100644 index 00000000..f0cdfbb1 --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_layer_iter.h @@ -0,0 +1,21 @@ +#ifndef F_PC_LAYER_ITER_H_ +#define F_PC_LAYER_ITER_H_ + +#include "../dolphin/types.h" + +typedef struct layer_class layer_class; + +typedef struct layer_iter { + void* mpFunc; + void* mpUserData; +} layer_iter; + +typedef int (*fpcLyIt_OnlyHereFunc)(void*, void*); +typedef void* (*fpcLyIt_JudgeFunc)(void*, void*); + +s32 fpcLyIt_OnlyHere(layer_class* pLayer, fpcLyIt_OnlyHereFunc pFunc, void* pUserData); +s32 fpcLyIt_OnlyHereLY(layer_class* pLayer, fpcLyIt_OnlyHereFunc pFunc, void* pUserData); +void* fpcLyIt_Judge(layer_class* pLayer, fpcLyIt_JudgeFunc pFunc, void* pUserData); +void* fpcLyIt_AllJudge(fpcLyIt_JudgeFunc pFunc, void* pUserData); + +#endif diff --git a/external/libtp_c/include/f_pc/f_pc_line_iter.h b/external/libtp_c/include/f_pc/f_pc_line_iter.h new file mode 100644 index 00000000..97a2fe57 --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_line_iter.h @@ -0,0 +1,9 @@ + +#ifndef F_PC_LINE_ITER_H_ +#define F_PC_LINE_ITER_H_ + +typedef int (*fpcLnIt_QueueFunc)(void*, void*); + +void fpcLnIt_Queue(fpcLnIt_QueueFunc pFunc); + +#endif diff --git a/external/libtp_c/include/f_pc/f_pc_manager.h b/external/libtp_c/include/f_pc/f_pc_manager.h index cb179c4d..25b7d836 100644 --- a/external/libtp_c/include/f_pc/f_pc_manager.h +++ b/external/libtp_c/include/f_pc/f_pc_manager.h @@ -2,10 +2,10 @@ #define F_PC_MANAGER_H_ #include "f_pc_leaf.h" +#include "f_pc_executor.h" +#include "f_pc_node.h" -enum { - fpcM_ERROR_PROCESS_ID_e = -1, -}; +LIBTP_DEFINE_FUNC(fpcEx_Search__FPFPvPv_PvPv, fpcEx_Search_void______void____void_____void___, base_process_class*, fpcEx_Search, (fpcLyIt_JudgeFunc pFunc, void* pUserData)) typedef int (*FastCreateReqFunc)(void*); typedef void (*fpcM_ManagementFunc)(void); @@ -37,4 +37,37 @@ inline void* fpcM_GetAppend(const void* proc) { return ((base_process_class*)proc)->mpUserData; } +enum { + fpcM_ERROR_PROCESS_ID_e = 0xFFFFFFFF +}; + +typedef int (*FastCreateReqFunc)(void*); +typedef void (*fpcM_ManagementFunc)(void); +typedef int (*fpcM_DrawIteraterFunc)(void*, void*); + +inline process_profile_definition* fpcM_GetProfile(void* proc) { + return (process_profile_definition*)((base_process_class*)proc)->mpProf; +} + +inline BOOL fpcM_IsExecuting(unsigned int id) { + return fpcEx_IsExist(id); +} + +inline void* fpcM_LyJudge(process_node_class* i_node, fpcLyIt_JudgeFunc i_func, void* i_data) { + return fpcLyIt_Judge(&i_node->mLayer, i_func, i_data); +} + +void fpcM_Draw(void* pProc); +s32 fpcM_DrawIterater(fpcM_DrawIteraterFunc pFunc); +s32 fpcM_Execute(void* pProc); +s32 fpcM_Delete(void* pProc); +BOOL fpcM_IsCreating(unsigned int pID); +void fpcM_Management(fpcM_ManagementFunc pFunc1, fpcM_ManagementFunc pFunc2); +void fpcM_Init(); +base_process_class* fpcM_FastCreate(s16 pProcTypeID, FastCreateReqFunc param_2, void* param_3, + void* pData); +s32 fpcM_IsPause(void* pProc, u8 param_2); +void fpcM_PauseEnable(void* pProc, u8 param_2); +void fpcM_PauseDisable(void* pProc, u8 param_2); + #endif diff --git a/external/libtp_c/include/f_pc/f_pc_node.h b/external/libtp_c/include/f_pc/f_pc_node.h new file mode 100644 index 00000000..82d28495 --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_node.h @@ -0,0 +1,19 @@ +#ifndef F_PC_NODE_H_ +#define F_PC_NODE_H_ + +#include "../f_pc/f_pc_base.h" + +typedef struct process_node_class { + /* 0x00 */ base_process_class mBase; + /* 0xB8 */ nodedraw_method_class* mpNodeMtd; + /* 0xBC */ layer_class mLayer; + /* 0xE8 */ node_list_class mLayerNodeLists[16]; + /* 0x1A8 */ s8 mUnk0; +} process_node_class; + +typedef struct node_process_profile_definition { + /* 0x00 */ process_profile_definition mBase; + /* 0x1C */ process_method_class* sub_method; // Subclass methods +} node_process_profile_definition; + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/f_pc/f_pc_stdcreate_req.h b/external/libtp_c/include/f_pc/f_pc_stdcreate_req.h new file mode 100644 index 00000000..5b3dba1d --- /dev/null +++ b/external/libtp_c/include/f_pc/f_pc_stdcreate_req.h @@ -0,0 +1,22 @@ +#ifndef F_PC_STDCREATE_H_ +#define F_PC_STDCREATE_H_ + +#include "f_pc_create_req.h" + +typedef struct layer_class layer_class; + +typedef int (*stdCreateFunc)(void*, void*); + +typedef struct standard_create_request_class { + /* 0x00 */ create_request mBase; + /* 0x48 */ request_of_phase_process_class unk_0x48; + /* 0x50 */ s16 mLoadID; + /* 0x54 */ void* unk_0x54; + /* 0x58 */ stdCreateFunc unk_0x58; + /* 0x5C */ void* unk_0x5C; +} standard_create_request_class; + +LIBTP_DEFINE_FUNC(fpcSCtRq_Request__FP11layer_classsPFPvPv_iPvPv, fpcSCtRq_Request_layer_class____short__int_____void____void_____void____void___, + int, fpcSCtRq_Request, (layer_class*, s16, stdCreateFunc, void*, void*)) + +#endif \ No newline at end of file diff --git a/external/libtp_c/include/m_Do/m_Do_audio.h b/external/libtp_c/include/m_Do/m_Do_audio.h index 90c680a8..1de771d6 100644 --- a/external/libtp_c/include/m_Do/m_Do_audio.h +++ b/external/libtp_c/include/m_Do/m_Do_audio.h @@ -13,11 +13,12 @@ extern "C" { extern mDoAud_zelAudio_c g_mDoAud_zelAudio; } -// Functions -#ifdef GCN_PLATFORM -typedef void (*mDoAud_seStartLevel_t)(u32, Vec const*, u32, s8); -#define mDoAud_seStartLevel ((mDoAud_seStartLevel_t)mDoAud_seStartLevel_addr) +inline void mDoAud_seStart(u32 i_sfxID, const Vec* i_sePos, u32 param_2, s8 i_reverb) { + Z2SeMgr__seStart(&Z2GetAudioMgr()->mSeMgr, i_sfxID, i_sePos, param_2, i_reverb, 1.0f, 1.0f, -1.0f, -1.0f, 0); +} -#endif +inline void mDoAud_seStop(u32 i_sfxID, u32 param_2) { + Z2SeMgr__seStop(&Z2GetAudioMgr()->mSeMgr, i_sfxID, param_2); +} #endif /* M_DO_M_DO_AUDIO_H */ diff --git a/external/libtp_c/include/utils.h b/external/libtp_c/include/utils.h index 3fdcd332..02d745da 100644 --- a/external/libtp_c/include/utils.h +++ b/external/libtp_c/include/utils.h @@ -7,6 +7,15 @@ // Toggles save event flags void setEventFlag(u16 flag); +// Toggles temp event flags +void setTempEventFlag(u16 flag); + +// Toggles equipment items +void setItemFirstBit(u8 item); + +// Toggle dungeon switches +void setDungeonSwitch(int pFlag, int i_roomNo); + // Set Savefile spawn info void setReturnPlace(const char* stage, s8 room, u8 spawn); diff --git a/external/libtp_c/src/utils.cpp b/external/libtp_c/src/utils.cpp index 6901da63..ccf46d8c 100644 --- a/external/libtp_c/src/utils.cpp +++ b/external/libtp_c/src/utils.cpp @@ -4,11 +4,22 @@ // Toggles save event flags KEEP_FUNC void setEventFlag(u16 flag) { - if (dComIfGs_isEventBit(flag)) { - dComIfGs_offEventBit(flag); - } else { - dComIfGs_onEventBit(flag); - } + dComIfGs_isEventBit(flag) ? dComIfGs_offEventBit(flag) : dComIfGs_onEventBit(flag); +} + +// Toggles temp event flags +KEEP_FUNC void setTempEventFlag(u16 flag) { + dComIfGs_isTmpBit(flag) ? dComIfGs_offTmpBit(flag) : dComIfGs_onTmpBit(flag); +} + +// Toggles equipment items +KEEP_FUNC void setItemFirstBit(u8 item) { + dComIfGs_isItemFirstBit(item) ? dComIfGs_offItemFirstBit(item) : dComIfGs_onItemFirstBit(item); +} + +// Toggle dungeon switches +KEEP_FUNC void setDungeonSwitch(int pFlag, int i_roomNo) { + dComIfGs_isSwitch(pFlag, i_roomNo) ? dComIfGs_offSwitch(pFlag, i_roomNo) : dComIfGs_onSwitch(pFlag, i_roomNo); } // Set Savefile spawn info diff --git a/external/misc/any.py b/external/misc/any.py index 294e39c1..adf2f7d4 100644 --- a/external/misc/any.py +++ b/external/misc/any.py @@ -138,7 +138,7 @@ def main(args=None): "arealfos", "cits_2", "cits_tower", - "argarok", + "argorok", "palace_1", "palace_2", "early_platform", @@ -153,14 +153,20 @@ def main(args=None): any_p = [{**copy.deepcopy(default_entry), "id": i, "filename": name} for i, name in enumerate(file_names)] - file_dict = {e: i for i, e in enumerate(file_names)} + file_dict = {} + for i, e in enumerate(file_names): + if not e in file_dict: + file_dict[e] = [i] + else: + file_dict[e].append(i) - def update_entry(filename, data): - if filename in file_names: - any_p[file_dict[filename]] = {**any_p[file_dict[filename]], **data} + def update_entry(filename, data, n = 1): + count = sum(1 for entry in any_p if entry["filename"] == filename) + if n <= count and n > 0: + any_p[file_dict[filename][n - 1]] = {**any_p[file_dict[filename][n - 1]], **data} # ordon gate clip - update_entry("ordon_gate_clip", { + update_entry("ordon_gate_clip", n = 1, data = { 'requirements': Requirements.POS | Requirements.CAM, 'pos': (827.450012, 216.490097, -4533.90625), 'angle': 498, @@ -172,12 +178,16 @@ def update_entry(filename, data): }) if args.platform is Platform.GCN: - any_p[1]["requirements"] = Requirements.POS | Requirements.CAM - any_p[1]["pos"] = (466.622467, 319.770752, -11651.3867) - any_p[1]["angle"] = 52540 - any_p[1]["cam"]["pos"] = (735.525391, 524.418701, -11576.4746) - any_p[1]["cam"]["target"] = (465.674622, 421.052704, -11651.0684) - any_p[1]["counter"] = 10 + update_entry("ordon_gate_clip", n = 2, data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (466.622467, 319.770752, -11651.3867), + 'angle': 52540, + 'cam': { + 'pos': (735.525391, 524.418701, -11576.4746), + 'target': (465.674622, 421.052704, -11651.0684) + }, + 'counter': 10 + }) # back in time update_entry("bit", { diff --git a/external/misc/anyb.py b/external/misc/anyb.py index 1fb2ff16..2f6801da 100644 --- a/external/misc/anyb.py +++ b/external/misc/anyb.py @@ -1,171 +1,350 @@ +import copy +import sys +import argparse import struct +from enum import IntEnum, unique -REQ_POS = 1 -REQ_CAM = 2 - -default_entry = { - "requirements": 0, - "pos": (0.0,0.0,0.0), - "angle": 0, - "cam": {"pos":(0,0,0), "target": (0,0,0)}, - "counter": 0, -} - -# order matters -file_names = [ - "ordon_gate_clip", - "ordon_gate_clip", - "goats", - "hugo", - "faron_twilight", - "ems", - "purple_mist", - "forest_bit", - "forest_escape", - "lanayru_gate_clip", - "pillar_clip", - "lakebed_1", - "deku_toad", - "karg", - "kb1", - "eldin_twilight", - "lanayru_twilight", - "waterfall_sidehop", - "iza", - "spr_warp", - "spr", - "darkhammer", - "lakebed_bk_skip", - "onebomb", - "mdh_tower", - "mdh_bridge", - "camp", - "ag", - "poe_1_skip", - "death_sword_skip", - "stallord", - "stallord", - "silver_rupee", - "cits_early", - "cits_1", - "aeralfos_skip", - "fan_tower", - "argorok", - "palace_1", - "palace_2", - "early_platform", - "zant", - "hc", - "hc_tower", - "beast_ganon", - "horseback_ganon", -] - -anyb_p = [{**default_entry, "id": i, "filename": file_names[i]} for i in range(46)] - -# ordon gate clip -anyb_p[0]["requirements"] = REQ_POS | REQ_CAM -anyb_p[0]["pos"] = (827.450012, 216.490097, -4533.90625) -anyb_p[0]["angle"] = 498 -anyb_p[0]["cam"]["pos"] = (833.467468, 477.604675, -4241.97266) -anyb_p[0]["cam"]["target"] = (827.497559, 329.622986, -4532.90723) -anyb_p[0]["counter"] = 10 - -# back in time -anyb_p[1]["requirements"] = REQ_POS | REQ_CAM -anyb_p[1]["pos"] = (466.622467, 319.770752, -11651.3867) -anyb_p[1]["angle"] = 52540 -anyb_p[1]["cam"]["pos"] = (735.525391, 524.418701, -11576.4746) -anyb_p[1]["cam"]["target"] = (465.674622, 421.052704, -11651.0684) -anyb_p[1]["counter"] = 10 - -# hugo -anyb_p[3]["requirements"] = REQ_POS | REQ_CAM -anyb_p[3]["pos"] = (701.797302, 85.5212784, -5299.6123) -anyb_p[3]["angle"] = 63622 -anyb_p[3]["cam"]["pos"] = (735.525391, 524.418701, -11576.4746) -anyb_p[3]["cam"]["target"] = (465.674622, 421.052704, -11651.0684) - -# purple mist -anyb_p[6]["requirements"] = REQ_POS -anyb_p[6]["pos"] = (-23524.6152, 250.0, -16220.166) -anyb_p[6]["angle"] = 40758 -anyb_p[6]["counter"] = 30 - -# forest escape -anyb_p[8]["requirements"] = REQ_POS | REQ_CAM -anyb_p[8]["pos"] = (-12433.6016, -235.969193, -17103.998) -anyb_p[8]["angle"] = 29553 -anyb_p[8]["cam"]["pos"] = (-12552.8252, -53.5801048, -16729.5313) -anyb_p[8]["cam"]["target"] = (-12433.2979, -106.667023, -17104.9512) -anyb_p[8]["counter"] = 30 - -# lanayru gate clip -anyb_p[9]["requirements"] = REQ_POS | REQ_CAM -anyb_p[9]["pos"] = (-63026.2852, -9065.92578, 71680.3438) -anyb_p[9]["angle"] = 44248 -anyb_p[9]["cam"]["pos"] = (-62655.8125, -8900.91309, 71903.6328) -anyb_p[9]["cam"]["target"] = (-63064.2148, -8969.97656, 71661.0781) -anyb_p[9]["counter"] = 15 - -# eldin twilight -anyb_p[15]["requirements"] = REQ_POS | REQ_CAM -anyb_p[15]["pos"] = (455.088379, -150.0, 11516.7227) -anyb_p[15]["angle"] = 6058 -anyb_p[15]["cam"]["pos"] = (219.367218, -20.1253014, 11157.582) -anyb_p[15]["cam"]["target"] = (482.515137, -39.9999771, 11558.5283) -anyb_p[15]["counter"] = 10 - -# iza -anyb_p[18]["requirements"] = REQ_POS -anyb_p[18]["pos"] = (5979.97217, 150.0, -2748.34155) -anyb_p[18]["angle"] = 10114 - -# snowpeak messenger skip -anyb_p[19]["requirements"] = REQ_POS | REQ_CAM -anyb_p[19]["pos"] = (-9294.87988, 980.0, -11712.3838) -anyb_p[19]["angle"] = 346 -anyb_p[19]["cam"]["pos"] = (-9309.65137, 1280.4469, -12130.7695) -anyb_p[19]["cam"]["target"] = (-9294.2207, 1180.0, -11692.3945) -anyb_p[19]["counter"] = 10 - -# spr -anyb_p[20]["requirements"] = REQ_POS -anyb_p[20]["pos"] = (0.0, -150.0, 6000.0) -anyb_p[20]["angle"] = 33768 - -# bk skip -anyb_p[22]["requirements"] = REQ_POS | REQ_CAM -anyb_p[22]["pos"] = (71.9835968, 1500.00, 2839.01587) -anyb_p[22]["angle"] = 32767 -anyb_p[22]["cam"]["pos"] = (71.9835968, 1719.93542, 2969.04565) -anyb_p[22]["cam"]["target"] = (71.9835968, 1660.0, 2839.01587) -anyb_p[22]["counter"] = 30 - -# morpheel -anyb_p[23]["requirements"] = REQ_POS | REQ_CAM -anyb_p[23]["pos"] = (-1193.0, -23999.00, -770.0) -anyb_p[23]["angle"] = 10754 -anyb_p[23]["counter"] = 20 - -# poe 1 skip -anyb_p[28]["requirements"] = REQ_POS | REQ_CAM -anyb_p[28]["pos"] = (-2046.97168, 0.0, -587.304871) -anyb_p[28]["angle"] = 49030 -anyb_p[28]["cam"]["pos"] = (-1779.00293, 213.707397, -584.686768) -anyb_p[28]["cam"]["target"] = (-2047.97168, 130.16568, -587.317139) -anyb_p[28]["counter"] = 10 - -file = open("any_bite.bin", "wb") - -for entry in anyb_p: - print(entry) - file.write(entry["requirements"].to_bytes(1, "big", signed=False)) - file.write(int(0).to_bytes(1, "big", signed=False)) # padding - file.write(entry["angle"].to_bytes(2, "big", signed=False)) - file.write(struct.pack('>fff', *entry["pos"])) - file.write(struct.pack('>fff', *entry["cam"]["pos"])) - file.write(struct.pack('>fff', *entry["cam"]["target"])) - file.write(entry["counter"].to_bytes(4, "big", signed=False)) - file.write(struct.pack(">32s", entry["filename"].encode("ascii"))) - file.write(int(0).to_bytes(4, "big", signed=False)) # padding +@unique +class Platform(IntEnum): + GCN = 0 + WII = 1 + + +class Requirements(IntEnum): + POS = 1 + CAM = 2 + +def main(args=None): + parser = argparse.ArgumentParser( + sys.argv[0], description="A tool to generate the metadata file for the any% BiTE save files.") + parser.add_argument( + "-p", "--platform", type=str.upper, choices=[e.name for e in Platform], default=Platform.GCN.name, help="The platform to generate for.") + args = parser.parse_args() + + args.platform = Platform[args.platform] + + default_entry = { + "requirements": 0, + "pos": (0.0,0.0,0.0), + "angle": 0, + "cam": {"pos":(0,0,0), "target": (0,0,0)}, + "counter": 0, + } + + # order matters + file_names = [ + "ordon_gate_clip", + "ordon_gate_clip", + "goats", + "hugo", + "faron_twilight", + "ems", + "purple_mist", + "forest_bit", + "forest_escape", + "lanayru_gate_clip", + "pillar_clip", + "lakebed_1", + "deku_toad", + "karg", + "kb1", + "eldin_twilight", + "lanayru_twilight", + "waterfall_sidehop", + "iza", + "spr_warp", + "spr", + "darkhammer", + "lakebed_bk_skip", + "onebomb", + "mdh_tower", + "mdh_bridge", + "camp", + "ag", + "poe_1_skip", + "death_sword_skip", + "stallord", + "stallord", + "silver_rupee", + "cits_early", + "cits_1", + "aeralfos_skip", + "fan_tower", + "argorok", + "palace_1", + "palace_2", + "early_platform", + "zant", + "hc", + "hc_tower", + "beast_ganon", + "horseback_ganon", + ] + + if args.platform is Platform.WII: + # order matters + file_names = [ + "ordon_gate_clip", + "ordon_gate_clip", + "seam_clip", + "goats", + "hugo", + "faron_twilight", + "ems", + "purple_mist", + "kb1", + "eldin_twilight", + "bombhouse_skip", + "epona_oob_to_flight_by_fowl", + "lanayru_twilight", + "waterfall_sidehop", + "boss_bug", + "iza", + "plumm_oob", + "enter_lakebed", + "lakebed_1", + "deku_toad", + "morpheel", + "mdh_tower", + "mdh_bridge", + "messenger_skip", + "snowpeak_ruins_mbbb", + "freezard_skip", + "dark_hammer", + "bulblin_camp", + "ag", + "poe_1_skip", + "early_boss_key", + "death_sword", + "stallord", + "stallord", + "early_city", + "cits", + "arealfos", + "cits_2", + "fan_tower", + "argorok", + "pot1", + "stupidroom", + "pot2", + "earlypf", + "zant", + "hc", + "darknut", + "towerclimb", + "beast_ganon", + "horseback", + ] + + anyb_p = [{**copy.deepcopy(default_entry), "id": i, "filename": file_names[i]} for i in range(len(file_names))] + + file_dict = {} + for i, e in enumerate(file_names): + if not e in file_dict: + file_dict[e] = [i] + else: + file_dict[e].append(i) + + def update_entry(filename, data, n = 1): + count = sum(1 for entry in anyb_p if entry["filename"] == filename) + if n <= count and n > 0: + anyb_p[file_dict[filename][n - 1]] = {**anyb_p[file_dict[filename][n - 1]], **data} + + # ordon gate clip + update_entry("ordon_gate_clip", n = 1, data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (827.450012, 216.490097, -4533.90625), + 'angle': 498, + 'cam': {'pos': (833.467468, 477.604675, -4241.97266), 'target': (827.497559, 329.622986, -4532.90723)}, + 'counter': 10, + }) + + # back in time + update_entry("ordon_gate_clip", n = 2, data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (466.622467, 319.770752, -11651.3867), + 'angle': 52540, + 'cam': {'pos': (735.525391, 524.418701, -11576.4746), 'target': (465.674622, 421.052704, -11651.0684)}, + 'counter': 10, + }) + + # hugo + update_entry("hugo", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (701.797302, 85.5212784, -5299.6123), + 'angle': 63622, + 'cam': {'pos': (735.525391, 524.418701, -11576.4746), 'target': (465.674622, 421.052704, -11651.0684)}, + }) + + # purple mist + update_entry("purple_mist", data = { + 'requirements': Requirements.POS, + 'pos': (-23524.6152, 250.0, -16220.166), + 'angle': 40758, + 'counter': 30, + }) + + # king bulblin 1 + if args.platform is Platform.WII: + update_entry("kb1", data = { + 'requirements': Requirements.POS, + 'pos': (-9717.6035, 337.0316, 97.9661), + 'angle': 16384, + 'counter': 30, + }) + + # boss bug + if args.platform is Platform.WII: + update_entry("boss_bug", data = { + 'requirements': Requirements.POS, + 'pos': (-87517.1562, -18789.2812, 38927.0820), + 'angle': 41851, + 'counter': 30, + }) + + # plumm oob + if args.platform is Platform.WII: + update_entry("plumm_oob", data = { + 'requirements': Requirements.POS, + 'pos': (-104271.3750, -18470.0, 52661.7812), + 'angle': 45103, + 'counter': 30, + }) + + # mdh tower + if args.platform is Platform.WII: + update_entry("mdh_tower", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (25362.3184, -3028.7673, 10060.8379), + 'angle': 29327, + 'counter': 30, + }) + + # mdh bridge + if args.platform is Platform.WII: + update_entry("mdh_bridge", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (13050.0, 9825.0, 36202.0), + 'angle': 32768, + 'counter': 30, + }) + + # freezard skip + if args.platform is Platform.WII: + update_entry("freezard_skip", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-1125.0, 0.0, -1275.0), + 'angle': 32768, + 'counter': 30, + }) + + # dark hammer + if args.platform is Platform.WII: + update_entry("dark_hammer", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (0.7448, 0.0, 1330.9711), + 'angle': 32768, + 'counter': 20, + }) + + # forest escape + update_entry("forest_escape", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-12433.6016, -235.969193, -17103.998), + 'angle': 29553, + 'cam': {'pos': (-12552.8252, -53.5801048, -16729.5313), 'target': (-12433.2979, -106.667023, -17104.9512)}, + 'counter': 30, + }) + + # lanayru gate clip + update_entry("lanayru_gate_clip", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-63026.2852, -9065.92578, 71680.3438), + 'angle': 44248, + 'cam': {'pos': (-62655.8125, -8900.91309, 71903.6328), 'target': (-63064.2148, -8969.97656, 71661.0781)}, + 'counter': 15, + }) + + # eldin twilight + update_entry("eldin_twilight", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (455.088379, -150.0, 11516.7227), + 'angle': 6058, + 'cam': {'pos': (219.367218, -20.1253014, 11157.582), 'target': (482.515137, -39.9999771, 11558.5283)}, + 'counter': 10, + }) + + # waterfall sidehop + if args.platform is Platform.WII: + update_entry("waterfall_sidehop", data = { + 'requirements': Requirements.POS, + 'pos': (1169.5876, 12.6414, -1114.5820), + 'angle': 0, + 'counter': 10, + }) + + # iza + update_entry("iza", data = { + 'requirements': Requirements.POS, + 'pos': (5979.97217, 150.0, -2748.34155), + 'angle': 10114, + }) + + # snowpeak messenger skip + update_entry("spr_warp", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-9294.87988, 980.0, -11712.3838), + 'angle': 346, + 'cam': {'pos': (-9309.65137, 1280.4469, -12130.7695), 'target': (-9294.2207, 1180.0, -11692.3945)}, + 'counter': 10, + }) + + # spr + update_entry("spr", data = { + 'requirements': Requirements.POS, + 'pos': (0.0, 150.0, 6000.0), + 'angle': 33768, + }) + + # bk skip + update_entry("lakebed_bk_skip", data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (71.9835968, 1500.0, 2839.01587), + 'angle': 32767, + 'cam': {'pos': (71.9835968, 1719.93542, 2969.04565), 'target': (71.9835968, 1660.0, 2839.01587)}, + 'counter': 30, + }) + + # morpheel + update_entry('onebomb', data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-1193.0, -23999.00, -770.0), + 'angle': 10754, + 'counter': 20, + }) + + # poe 1 skip + update_entry('poe_1_skip', data = { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-2046.97168, 0.0, -587.304871), + 'angle': 49030, + 'cam': {'pos': (-1779.00293, 213.707397, -584.686768), 'target': (-2047.97168, 130.16568, -587.317139)}, + 'counter': 10, + }) + + file = open("any_bite.bin", "wb") + + for entry in anyb_p: + print(entry) + file.write(entry["requirements"].to_bytes(1, "big", signed=False)) + file.write(int(0).to_bytes(1, "big", signed=False)) # padding + file.write(entry["angle"].to_bytes(2, "big", signed=False)) + file.write(struct.pack('>fff', *entry["pos"])) + file.write(struct.pack('>fff', *entry["cam"]["pos"])) + file.write(struct.pack('>fff', *entry["cam"]["target"])) + file.write(entry["counter"].to_bytes(4, "big", signed=False)) + file.write(struct.pack(">32s", entry["filename"].encode("ascii"))) + file.write(int(0).to_bytes(4, "big", signed=False)) # padding + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/external/misc/dat2qlogs.py b/external/misc/dat2qlogs.py new file mode 100755 index 00000000..e04f1e13 --- /dev/null +++ b/external/misc/dat2qlogs.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import argparse, os, re, struct, sys + +def main(): + parser = argparse.ArgumentParser(description="Parses out quest logs from a Twilight Princess savefiles") + parser.add_argument("wsd", help="A valid twilight princess save data file extracted from a savefile (data.bin)") + wsdbytes = None + args = parser.parse_args() + file_in = args.wsd + with open(file_in,"rb") as wsdfile: + wsdbytes = bytearray(wsdfile.read()) + + qlog1 = wsdbytes[0x0008:0x0A9B] + qlog2 = wsdbytes[0x0A9C:0x152F] + qlog3 = wsdbytes[0x1530:0x1FC3] + + with open("qlog1.bin", "wb") as outfile: + outfile.write(qlog1) + + with open("qlog2.bin", "wb") as outfile: + outfile.write(qlog2) + + with open("qlog3.bin", "wb") as outfile: + outfile.write(qlog3) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/external/misc/gci2qlogs.py b/external/misc/gci2qlogs.py new file mode 100755 index 00000000..681c9b1e --- /dev/null +++ b/external/misc/gci2qlogs.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import argparse, os, re, struct, sys + +def main(): + parser = argparse.ArgumentParser(description="Parses out quest logs from a Twilight Princess GCI") + parser.add_argument("gci", help="A valid twilight princess GCI file") + gcibytes = None + args = parser.parse_args() + file_in = args.gci + with open(file_in,"rb") as gcifile: + gcibytes = bytearray(gcifile.read()) + + qlog1 = gcibytes[0x4048:0x4AD4] + qlog2 = gcibytes[0x4ADC:0x5568] + qlog3 = gcibytes[0x5570:0x5FFC] + + with open("qlog1.bin", "w") as outfile: + outfile.write(qlog1) + + with open("qlog2.bin", "w") as outfile: + outfile.write(qlog2) + + with open("qlog3.bin", "w") as outfile: + outfile.write(qlog3) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/external/misc/hundo.py b/external/misc/hundo.py index 968651bb..fcc379c5 100644 --- a/external/misc/hundo.py +++ b/external/misc/hundo.py @@ -1,235 +1,292 @@ +#!/usr/bin/python3 + +""" +Generates the metadata file for the 100% save files. +""" + +import sys +import argparse +import copy +from enum import IntEnum, unique import struct -REQ_POS = 1 -REQ_CAM = 2 - -default_entry = { - "requirements": 0, - "pos": (0.0,0.0,0.0), - "angle": 0, - "cam": {"pos":(0,0,0), "target": (0,0,0)}, - "counter": 0, -} - -# order matters -file_names = [ - "goats", - "ordon_gate_clip", - "goats_2", - "faron_twilight", - "ems", - "purple_mist", - "forest_bit", - "forest_2", - "ookless", - "eldin_twilight", - "bomb_house_skip", - "lanayru_gate_clip", - "pillar_clip", - "lakebed_1", - "deku_toad", - "karg", - "lanayru_twilight", - "boss_bug", - "kb2", - "kb2", - "corotd", - "gm", - "dangoro", - "post_gm", - "lakebed_bk_skip", - "morpheel", - "mdh_tower", - "mdh_bridge", - "post_mdh", - "star_1", - "kb1", # new - "iza_1_skip", - "lh_cave", - "camp", - "ag", - "poe_1_skip", - "death_sword_skip", - "stallord", - "post_ag", - "spr", - "darkhammer", - "spr_superjump", - "spr_bk_lja", - "spr_bk_lja", - "blizzeta", - "nf_bomb_boost", - "grove_skip", - "grove_boost", - "tot", - "tot_early_poe", - "tot_statue_throws", - "tot_early_hp", - "tot_darknut", - "dot_skip", - "post_tot", - "hotspring", - "gorge_arc", # new - "ice_puzzle", - "hv_archery", - "cits_1", - "aeralfos_skip", - "cits_2", - "cits_poe_cycle", - "fan_tower", - "argorok", - "star_2", - "palace_1", - "palace_2", - "early_platform", - "zant", - "coo", - "coo_10", - "coo_20", - "coo_30", - "coo_40", - "cats", - "hc", - "hc_darknut", - "hc_tower", - "beast_ganon", - "horseback_ganon", -] - -hundo_p = [{**default_entry, "id": i, "filename": file_names[i]} for i in range(81)] - -# ordon gate clip -hundo_p[1]["requirements"] = REQ_POS | REQ_CAM -hundo_p[1]["cam"]["target"] = 827.497559, 329.622986, -4532.90723 -hundo_p[1]["cam"]["pos"] = 833.467468, 477.604675, -4241.97266 -hundo_p[1]["angle"] = 498 -hundo_p[1]["pos"] = 827.450012, 216.490097, -4533.90625 -hundo_p[1]["counter"] = 10 - -# purple mist -hundo_p[5]["requirements"] = REQ_POS -hundo_p[5]["angle"] = 40758 -hundo_p[5]["pos"] = -23524.6152, 250.0, -16220.166 -hundo_p[5]["counter"] = 30 - -# lanayru gate clip -hundo_p[11]["requirements"] = REQ_POS | REQ_CAM -hundo_p[11]["cam"]["target"] = -63064.2148, -8969.97656, 71661.0781 -hundo_p[11]["cam"]["pos"] = -62655.8125, -8900.91309, 71903.6328 -hundo_p[11]["angle"] = 44248 -hundo_p[11]["pos"] = -63026.2852, -9065.92578, 71680.3438 -hundo_p[11]["counter"] = 15 - -# boss bug -hundo_p[17]["requirements"] = REQ_POS -hundo_p[17]["angle"] = 21504 -hundo_p[17]["pos"] = -89100.00, -18811.2363, 39410.00 - -# kb2 -hundo_p[18]["requirements"] = REQ_POS | REQ_CAM -hundo_p[18]["cam"]["target"] = -92098.1797, -5398.54883, 22599.9102 -hundo_p[18]["cam"]["pos"] = -92795.1328, -5302.87988, 22505.3359 -hundo_p[18]["angle"] = 14957 -hundo_p[18]["counter"] = 30 - -# coro td -hundo_p[20]["requirements"] = REQ_POS -hundo_p[20]["angle"] = 27714 -hundo_p[20]["pos"] = -13715.0712, 0.00, -14238.0654 - -# lakebed bk skip -hundo_p[24]["requirements"] = REQ_POS | REQ_CAM -hundo_p[24]["cam"]["target"] = 71.9835968, 1660.0, 2839.01587 -hundo_p[24]["cam"]["pos"] = 71.9835968, 1719.93542, 2969.04565 -hundo_p[24]["angle"] = 32767 -hundo_p[24]["pos"] = 71.9835968, 1500.00, 2839.01587 -hundo_p[24]["counter"] = 30 - -# mdh tower -hundo_p[26]["requirements"] = REQ_POS | REQ_CAM -hundo_p[26]["cam"]["target"] = 25256.7285, -2919.95215, 2839.01587 -hundo_p[26]["cam"]["pos"] = 10193.6064, 25254.7852, -2874.2627 -hundo_p[26]["angle"] = 32025 -hundo_p[26]["pos"] = 25254.6875, -3031.50854, 10222.1445 -hundo_p[26]["counter"] = 15 - -# poe 1 skip -hundo_p[35]["requirements"] = REQ_POS | REQ_CAM -hundo_p[35]["cam"]["target"] = -2047.97168, 130.16568, -587.317139 -hundo_p[35]["cam"]["pos"] = -1779.00293, 213.707397, -584.686768 -hundo_p[35]["angle"] = 49030 -hundo_p[35]["pos"] = -2046.97168, 0.0, -587.304871 -hundo_p[35]["counter"] = 10 - -# spr superjump -hundo_p[41]["requirements"] = REQ_POS | REQ_CAM -hundo_p[41]["cam"]["target"] = 1529.35425, 466.16306, 3684.08252 -hundo_p[41]["cam"]["pos"] = 1765.20581, 691.830688, 3662.42749 -hundo_p[41]["angle"] = 50120 -hundo_p[41]["pos"] = 1530.35, 359.56, 3683.99 -hundo_p[41]["counter"] = 30 - -# spr bk lja -hundo_p[42]["requirements"] = REQ_POS -hundo_p[42]["angle"] = 32887 -hundo_p[42]["pos"] = -2171.19, 973.96, -2384.89 -hundo_p[42]["counter"] = 30 - -# grove skip -hundo_p[46]["requirements"] = REQ_POS -hundo_p[46]["cam"]["target"] = -9965.82617, 2176.59863, 4084.57056 -hundo_p[46]["cam"]["pos"] = -10415.2363, 2212.92139, 4370.72852 -hundo_p[46]["angle"] = 22306 -hundo_p[46]["pos"] = -9966.6689, 2000.0, 4085.1082 -hundo_p[46]["counter"] = 30 - -# grove boost -hundo_p[47]["requirements"] = REQ_POS -hundo_p[47]["cam"]["target"] = -1765.32605, 1180.38452, 4303.98584 -hundo_p[47]["cam"]["pos"] = -1368.4314, 1347.8916, 4057.84863 -hundo_p[47]["angle"] = 54947 -hundo_p[47]["pos"] = -1764.4763, 1000.0, 4303.4585 -hundo_p[47]["counter"] = 30 - -# dot skip -hundo_p[53]["requirements"] = REQ_POS | REQ_CAM -hundo_p[53]["cam"]["target"] = 1361.59766, -33.1954155, -1090.47632 -hundo_p[53]["cam"]["pos"] = 1396.36316, 9.51973343, -719.644531 -hundo_p[53]["angle"] = 33673 -hundo_p[53]["pos"] = 1361.68408, -143.56076, -1089.4801 - -# hv archery -hundo_p[58]["requirements"] = REQ_POS -hundo_p[58]["angle"] = 64520 -hundo_p[58]["pos"] = 3125.57, -62.16, -9360.22 -hundo_p[58]["counter"] = 30 - -# city 1 -hundo_p[59]["requirements"] = REQ_POS | REQ_CAM -hundo_p[59]["cam"]["target"] = 1313.54285, -234.203003, 5545.16846 -hundo_p[59]["cam"]["pos"] = 1027.53259, -108.096123, 5605.23047 -hundo_p[59]["angle"] = 16384 -hundo_p[59]["pos"] = 1309.60645, -240.0, 5533.43848 -hundo_p[59]["counter"] = 10 - -# cats -hundo_p[75]["requirements"] = REQ_POS | REQ_CAM -hundo_p[75]["cam"]["target"] = 5309.32373, 160.1, -3581.83423 -hundo_p[75]["cam"]["pos"] = 4893.25391, 160.117676, -3524.51245 -hundo_p[75]["angle"] = 17282 -hundo_p[75]["pos"] = 5238.59, 0.00, -3575.74 -hundo_p[75]["counter"] = 30 - -file = open("hundo.bin", "wb") - -for entry in hundo_p: - print(entry) - file.write(entry["requirements"].to_bytes(1, "big", signed=False)) - file.write(int(0).to_bytes(1, "big", signed=False)) # padding - file.write(entry["angle"].to_bytes(2, "big", signed=False)) - file.write(struct.pack('>fff', *entry["pos"])) - file.write(struct.pack('>fff', *entry["cam"]["pos"])) - file.write(struct.pack('>fff', *entry["cam"]["target"])) - file.write(entry["counter"].to_bytes(4, "big", signed=False)) - file.write(struct.pack(">32s", entry["filename"].encode("ascii"))) - file.write(int(0).to_bytes(4, "big", signed=False)) # padding + +@unique +class Platform(IntEnum): + GCN = 0 + WII = 1 + + +class Requirements(IntEnum): + POS = 1 + CAM = 2 + + +def main(args=None): + parser = argparse.ArgumentParser( + sys.argv[0], description="A tool to generate the metadata file for the 100% save files.") + parser.add_argument( + "-p", "--platform", type=str.upper, choices=[e.name for e in Platform], default=Platform.GCN.name, help="The platform to generate for.") + args = parser.parse_args() + + args.platform = Platform[args.platform] + + default_entry = { + "requirements": 0, + "pos": (0.0, 0.0, 0.0), + "angle": 0, + "cam": {"pos": (0, 0, 0), "target": (0, 0, 0)}, + "counter": 0, + } + + # order matters + file_names = [ + "goats", + "ordon_gate_clip", + "goats_2", + "faron_twilight", + "ems", + "purple_mist", + "forest_bit", + "forest_2", + "ookless", + "eldin_twilight", + "bomb_house_skip", + "lanayru_gate_clip", + "pillar_clip", + "lakebed_1", + "deku_toad", + "karg", + "lanayru_twilight", + "corotd", + "early_ele", + "gm", + "dangoro", + "fyrus", + "waterfall_sidehop", + "boss_bug", + "kb2", + "kb2", + "eldin_collection", + "lakebed_bk_skip", + "morpheel", + "mdh_tower", + "mdh_bridge", + "post_mdh", + "star_1", + "kb1", + "iza_1_skip", + "lh_cave", + "camp", + "ag", + "poe_1_skip", + "death_sword_skip", + "stallord", + "post_ag", + "spr", + "darkhammer", + "spr_2", + "spr_bk_lja", + "spr_bk", + "blizzeta", + "nf_bomb_boost", + "grove_skip", + "grove_boost", + "tot", + "tot_early_poe", + "tot_statue_throws", + "tot_early_hp", + "tot_darknut", + "dot_skip", + "post_tot", + "hotspring", + "gorge_arc", + "silver_rupee", + "ice_puzzle", + "iza_2", + "hv_archery", + "cits_1", + "aeralfos_skip", + "cits_2", + "cits_poe_cycle", + "fan_tower", + "argorok", + "star_2", + "palace_1", + "palace_2", + "early_platform", + "zant", + "coo", + "coo_10", + "coo_20", + "coo_30", + "coo_40", + "cats", + "hc", + "hc_darknut", + "hc_tower", + "beast_ganon", + "horseback_ganon", + ] + + hundo_p = [{**copy.deepcopy(default_entry), "id": i, "filename": name} + for i, name in enumerate(file_names)] + + file_dict = {e: i for i, e in enumerate(file_names)} + + def update_entry(filename, data): + if filename in file_names: + hundo_p[file_dict[filename]] = {**hundo_p[file_dict[filename]], **data} + + update_entry("ordon_gate_clip", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (827.497559, 329.622986, -4532.90723), + 'angle': 498, + 'cam': { + 'pos': (833.467468, 477.604675, -4241.97266), + 'target': (827.497559, 329.622986, -4532.90723) + }, + 'counter': 10 + }) + + update_entry("purple_mist", { + 'requirements': Requirements.POS, + 'pos': (-23524.6152, 250.0, -16220.166), + 'angle': 40758, + 'counter': 30 + }) + + update_entry("lanayru_gate_clip", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-63026.2852, -9065.92578, 71680.3438), + 'angle': 44248, + 'cam': { + 'pos': (-62655.8125, -8900.91309, 71903.6328), + 'target': (-63064.2148, -8969.97656, 71661.0781) + }, + 'counter': 15 + }) + + update_entry("early_ele", { + 'requirements': Requirements.POS, + 'pos': (1197.00, -355.55, -5468.84), + 'angle': 45137, + }) + + update_entry("boss_bug", { + 'requirements': Requirements.POS, + 'pos': (-89100.00, -18811.2363, 39410.00), + 'angle': 21504, + }) + + update_entry("kb2", { + 'requirements': Requirements.POS | Requirements.CAM, + 'angle': 14957, + 'cam': { + 'pos': (-92795.1328, -5302.87988, 22505.3359), + 'target': (-92098.1797, -5398.54883, 22599.9102) + }, + 'counter': 30 + }) + + update_entry("corotd", { + 'requirements': Requirements.POS, + 'pos': (-13715.0712, 0.00, -14238.0654), + 'angle': 27714, + }) + + update_entry("lakebed_bk_skip", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (71.9835968, 1500.00, 2839.01587), + 'angle': 32767, + 'cam': { + 'pos': (71.9835968, 1719.93542, 2969.04565), + 'target': (71.9835968, 1660.0, 2839.01587) + }, + 'counter': 30 + }) + + update_entry("mdh_tower", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (25254.6875, -3031.50854, 10222.1445), + 'angle': 32025, + 'cam': { + 'pos': (10193.6064, 25254.7852, -2874.2627), + 'target': (25256.7285, -2919.95215, 2839.01587) + }, + 'counter': 15 + }) + + update_entry("poe_1_skip", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-2046.97168, 0.0, -587.304871), + 'angle': 49030, + 'cam': { + 'pos': (-1779.00293, 213.707397, -584.686768), + 'target': (-2047.97168, 130.16568, -587.317139) + }, + 'counter': 10 + }) + + update_entry("spr_bk_lja", { + 'requirements': Requirements.POS, + 'pos': (-2171.19, 973.96, -2384.89), + 'angle': 32887, + }) + + update_entry("grove_skip", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (-9966.6689, 2000.0, 4085.1082), + 'angle': 22306, + 'cam': { + 'pos': (-10415.2363, 2212.92139, 4370.72852), + 'target': (-9965.82617, 2176.59863, 4084.57056) + }, + 'counter': 30 + }) + + update_entry("hv_archery", { + 'requirements': Requirements.POS, + 'pos': (3125.57, -62.16, -9360.22), + 'angle': 64520, + }) + + update_entry("cits_1", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (1309.60645, -240.0, 5533.43848), + 'angle': 16384, + 'cam': { + 'pos': (1027.53259, -108.096123, 5605.23047), + 'target': (1313.54285, -234.203003, 5545.16846) + }, + 'counter': 10 + }) + + update_entry("cats", { + 'requirements': Requirements.POS | Requirements.CAM, + 'pos': (5238.59, 0.00, -3575.74), + 'angle': 17282, + 'cam': { + 'pos': (4893.25391, 160.117676, -3524.51245), + 'target': (5309.32373, 160.1, -3581.83423) + }, + 'counter': 30 + }) + + file = open("hundo.bin", "wb") + + for entry in hundo_p: + print(entry) + file.write(entry["requirements"].to_bytes(1, "big", signed=False)) + file.write(int(0).to_bytes(1, "big", signed=False)) # padding + file.write(entry["angle"].to_bytes(2, "big", signed=False)) + file.write(struct.pack('>fff', *entry["pos"])) + file.write(struct.pack('>fff', *entry["cam"]["pos"])) + file.write(struct.pack('>fff', *entry["cam"]["target"])) + file.write(entry["counter"].to_bytes(4, "big", signed=False)) + file.write(struct.pack(">32s", entry["filename"].encode("ascii"))) + file.write(int(0).to_bytes(4, "big", signed=False)) # padding + + +if __name__ == "__main__": + main(sys.argv) diff --git a/external/misc/meta.py b/external/misc/meta.py new file mode 100644 index 00000000..b2efdee6 --- /dev/null +++ b/external/misc/meta.py @@ -0,0 +1,49 @@ +import json +import os +import re + +# Load the meta.json file +with open('meta.json', 'r') as f: + meta_data = json.load(f) + +# Extract current patch files from the 'patches/' directory +patch_files = [f for f in os.listdir('patches') if os.path.isfile(os.path.join('patches', f))] + +# Define a regex pattern to extract SemVer from filenames (assuming the format contains semver) +semver_pattern = r'(\d+\.\d+\.\d+)(.*)' + +# Function to extract the SemVer and the part after it from a patch file name +def extract_semver_and_suffix(filename): + match = re.search(semver_pattern, filename) + if match: + semver = match.group(1) + suffix = match.group(2).lstrip('-').replace('-', '_').replace('.patch','') # Remove leading hyphen and replace hyphens with underscores + return semver, suffix + return None, None + +# Extract SemVer and suffix for all patch files +patch_versions = {extract_semver_and_suffix(patch) for patch in patch_files if extract_semver_and_suffix(patch)[0]} + +# Check if the SemVer exists in the meta.json data +def patch_exists_in_meta(semver): + return any(item['name'] == semver for item in meta_data) + +# Add new patches to meta.json if not already present +for semver, suffix in patch_versions: + if semver and not patch_exists_in_meta(semver): + # Find all patches with this version + version_patches = [p for p in patch_files if semver in p] + for patch in version_patches: + new_patch_entry = { + 'name': semver, + 'path': f'patches/{patch}', + 'version': suffix # Use the converted suffix + } + meta_data.append(new_patch_entry) + print(f"Added new patch version {semver}: {patch}") + +# Write updated meta.json back to disk +with open('meta.json', 'w') as f: + json.dump(meta_data, f, indent=2) + +print("meta.json has been updated.") \ No newline at end of file diff --git a/external/misc/nandpack.py b/external/misc/nandpack.py new file mode 100755 index 00000000..13dc0822 --- /dev/null +++ b/external/misc/nandpack.py @@ -0,0 +1,1788 @@ +#!/usr/bin/python3 + +"""Tool to pack/unpack Wii saves & inject REL modules.""" + +# Copyright 2021 kipcode66 & Seeky +# Based off of Dolphin Emulator Project https://github.com/dolphin-emu/dolphin.git +# Copyright 2010 Dolphin Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +# Based off of tachtig/twintig http://git.infradead.org/?p=users/segher/wii.git +# See also: https://wiibrew.org/wiki/Segher%27s_Wii.git +# Copyright 2007,2008 Segher Boessenkool +# Licensed under the terms of the GNU GPL, version 2 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +# The binary data loaded in the save files is taken from the REL loader code from PistonMiner. +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright 2020 Linus S. (aka PistonMiner) +# Modifications made by Zephiles + +from functools import reduce +import logging +import sys +import os +import argparse +import struct +import ctypes +from io import FileIO +from enum import IntEnum +from typing import Any, Dict, List +import hashlib +import secrets +import json +import base64 +from datetime import datetime, timezone +import re +from Crypto.Cipher import AES + +# +----------------------+ +# | Constants definition | +# +----------------------+ + +# Program Constants/global variables +VERSION = "0.2.2" + +# Constants +BLOCK_SZ = 0x40 +BNR_SZ = 0x60a0 +ICON_SZ = 0x1200 +FULL_BNR_MIN = 0x72a0 # BNR_SZ + 1*ICON_SZ +FULL_BNR_MAX = 0xF0A0 # BNR_SZ + 8*ICON_SZ +BK_LISTED_SZ = 0x70 +SIG_SZ = 0x40 +FULL_CERT_SZ = 0x3C0 + +DEFAULT_DEVICE_ID = 0x0403AC68 + +OS_BUS_CLOCK = 243000000 + +# Crypto values +SD_KEY = bytes([0xab, 0x01, 0xb9, 0xd8, + 0xe1, 0x62, 0x2b, 0x08, + 0xaf, 0xba, 0xd8, 0x4d, + 0xbf, 0xc2, 0xa5, 0x5d]) +SD_INITIAL_IV = bytes([0x21, 0x67, 0x12, 0xE6, + 0xAA, 0x1F, 0x68, 0x9F, + 0x95, 0xC5, 0xA2, 0x23, + 0x24, 0xDC, 0x6A, 0x98]) +MD5_BLANKER = bytes([0x0E, 0x65, 0x37, 0x81, + 0x99, 0xBE, 0x45, 0x17, + 0xAB, 0x06, 0xEC, 0x22, + 0x45, 0x1A, 0x57, 0x93]) +NG_ID = 0x0403AC68 +CA_ID = 1 +MS_ID = 2 + +DEFAULT_KEY_ID = 0x6AAB8C59 + +SYSTEM_MENU = 0x0000000100000002 + +DEFAULT_SIGNATURE = bytes([ + # R + 0x00, 0xD8, 0x81, 0x63, 0xB2, 0x00, 0x6B, 0x0B, 0x54, 0x82, + 0x88, 0x63, 0x81, 0x1C, 0x00, 0x71, 0x12, 0xED, 0xB7, 0xFD, + 0x21, 0xAB, 0x0E, 0x50, 0x0E, 0x1F, 0xBF, 0x78, 0xAD, 0x37, + # S + 0x00, 0x71, 0x8D, 0x82, 0x41, 0xEE, 0x45, 0x11, 0xC7, 0x3B, + 0xAC, 0x08, 0xB6, 0x83, 0xDC, 0x05, 0xB8, 0xA8, 0x90, 0x1F, + 0xA8, 0x2A, 0x0E, 0x4E, 0x76, 0xEF, 0x44, 0x72, 0x99, 0xF8 +]) + +DEFAULT_PRIVATE_KEY = bytes([0x00, 0xAB, 0xEE, 0xC1, 0xDD, 0xB4, + 0xA6, 0x16, 0x6B, 0x70, 0xFD, 0x7E, + 0x56, 0x67, 0x70, 0x57, 0x55, 0x27, + 0x38, 0xA3, 0x26, 0xC5, 0x46, 0x16, + 0xF7, 0x62, 0xC9, 0xED, 0x73, 0xF2]) + +# DEFAULT_PUBLIC_KEY = ec.privToPub(commondefs.DEFAULT_PRIVATE_KEY) +DEFAULT_PUBLIC_KEY = bytes([0x01, 0x04, 0x0b, 0xe0, 0x46, 0xea, + 0x95, 0x19, 0xf2, 0x85, 0x9b, 0x0d, + 0x94, 0x29, 0xa2, 0xc6, 0x91, 0x80, + 0x15, 0x89, 0x8f, 0x2e, 0xba, 0x20, + 0xcf, 0xfd, 0xb3, 0x16, 0x4f, 0x0c, + 0x01, 0x38, 0xc5, 0xd2, 0x2f, 0xc1, + 0xe9, 0xee, 0x17, 0x6c, 0x2d, 0x8f, + 0xa4, 0x74, 0xb0, 0xe9, 0x38, 0x66, + 0x6e, 0x60, 0xcf, 0x06, 0xd5, 0x08, + 0x7a, 0xc2, 0x4f, 0x01, 0x39, 0x79]) + +SQUARE = bytes([0x00, 0x01, 0x04, 0x05, + 0x10, 0x11, 0x14, 0x15, + 0x40, 0x41, 0x44, 0x45, + 0x50, 0x51, 0x54, 0x55]) + +SIGNATURE_END_MAGIC = 0x2f536969 + +# ACE data + +TIDS = {0x00010000525a4445: "us0", + 0x00010000525a4450: "eu", 0x00010000525a444a: "jp"} + +VERSIONS = {"us0": 0x00010000525a4445, "us2": 0x00010000525a4445, + "eu": 0x00010000525a4450, "jp": 0x00010000525a444a} + +GAME_INFO_PTR = { + # NA 1.0 + "us0": 0x80492928, + # NA 1.2 + "us2": 0x80479F30, + # PAL + "eu": 0x8047A828, + # JP + "jp": 0x80477DB0, +} + +BIN_DATA_INIT = { + # NA 1.0 + "us0": base64.b64decode("PICASYiEOEAchAqUOIQCCDyggEZgpYPgfYUiFH2JA6ZOgAQg"), + # NA 1.2 + "us2": base64.b64decode("PICASIiErkgchAqUOIQCCDyggERgpfngfYUiFH2JA6ZOgAQg"), + # PAL + "eu": base64.b64decode("PICASIiEt0AchAqUOIQCCDyggEVgpQLgfYUiFH2JA6ZOgAQg"), + # JP + "jp": base64.b64decode("PICASIiEjMgchAqUOIQCCDyggERgpdhgfYUiFH2JA6ZOgAQg"), +} + +BIN_DATA_MAIN = { + '1': { + # NA 1.0 + "us0": base64.b64decode("PYCANGGMovR9iAOmToAAITxggDRgY8V0SAAABXyIAqY4h" + "ABQSAABSYhtsmAsAwAAQYIAIIBtu0g4gAAFOKAAAT2AgC" + "phjPzcfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyp+H2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMYPYCAPGGMCRR9iAOmT" + "oAAIX+j63g4gAMYSAAA0ZOtv5A4fQMYkG2/lDxggDRgY3" + "f0Y6QA/EgAAJ09gIA0YYzFeH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuEduB8fxt4P8CAAGPDW/Q8gICwOKADG" + "EuMB+Vjw1v0OIADGEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CANGBjxXQ8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDRjpWGIfKgDpk6AACFjo2JsfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2yZJ" + "Qh/1B8CAKmkAEAtL9BAAhINEUZfHobeD/ggAA7wAAAO6E" + "AIGPjXwR/pOt4OKAAAUg2wVUsAwAAQIIA5H+j63g4gAAA" + "OKAAAkg2ur0sAwAAQYAAzDuDAB9XnAA0f6PreDiAAAA4o" + "AAASDa6nSwDAABBgACsgG2zZH+E43g4oAAgSC3RbXx7G3" + "h/o+t4f2TbeH+F43hINrixLAMAAECBAFyAbbNsgJsAIIC" + "7AERILdFBfHwbeEg0RGF/Y9t4f4TjeEg0UXUsAwABQIIA" + "GEg0RF2Tn1S4k39UvIPbADRIAAAof2PbeEg0U51INERBg" + "G2zbH+E43hILdeFgG2zZH9k23hILdd5f6PreEg2wlEsHg" + "AAQYIADH/IA6ZOgAAhf0PTeEg0RB27QQAIgAEAtHwIA6Y" + "4IQCwSAAnSA=="), # 6D6F642E72656C00 + # NA 1.2 + "us2": base64.b64decode("PYCAM2GMTMR9iAOmToAAITxggDNgY29ESAAABXyIAqY4h" + "ABQSAABSYhtseAsAwAAQYIAIIBtuug4gAAFOKAAAT2AgC" + "phjPbwfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyqsH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMYPYCAOmGMs0x9iAOmT" + "oAAIX+j63g4gAMYSAAA0ZOtvwg4fQMYkG2/DDxggDNgYy" + "HEY6QA/EgAAJ09gIAzYYxvSH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDILB8fxt4P8CAAGPDW/Q8gICwOKADG" + "EuKsh1jw1v0OIADGEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2Bjb0Q8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpQtYfKgDpk6AACFjoww8fGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2x5J" + "Qh/1B8CAKmkAEAtL9BAAhIMu7pfHobeD/ggAA7wAAAO6E" + "AIGPjXwR/pOt4OKAAAUg1a40sAwAAQIIA5H+j63g4gAAA" + "OKAAAkg1ZPUsAwAAQYAAzDuDAB9XnAA0f6PreDiAAAA4o" + "AAASDVk1SwDAABBgACsgG2y5H+E43g4oAAgSCx7PXx7G3" + "h/o+t4f2TbeH+F43hINWLpLAMAAECBAFyAbbLsgJsAIIC" + "7AERILHsRfHwbeEgy7jF/Y9t4f4TjeEgy+0UsAwABQIIA" + "GEgy7i2Tn1S4k39UvIPbADRIAAAof2PbeEgy/W1IMu4Rg" + "G2y7H+E43hILIFVgG2y5H9k23hILIFJf6PreEg1bIksHg" + "AAQYIADH/IA6ZOgAAhf0PTeEgy7e27QQAIgAEAtHwIA6Y" + "4IQCwSAAnSA=="), # 6D6F642E72656C00 + # PAL + "eu": base64.b64decode("PYCAM2GMUPR9iAOmToAAITxggDNgY3N0SAAABXyIAqY4h" + "ABQSAABSYhtsKAsAwAAQYIAIIBtuag4gAAFOKAAAT2AgC" + "phjPsgfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyqoH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMYPYCAOmGMt9B9iAOmT" + "oAAIX+j63g4gAMYSAAA0ZOtvcg4fQMYkG29zDxggDNgYy" + "X0Y6QA/EgAAJ09gIAzYYxzeH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDJOB8fxt4P8CAAGPDW/Q8gICwOKADG" + "EuKtqFjw1v0OIADGEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2Bjc3Q8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpQ+IfKgDpk6AACFjoxBsfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2wpJ" + "Qh/1B8CAKmkAEAtL9BAAhIMvMZfHobeD/ggAA7wAAAO6E" + "AIGPjXwR/pOt4OKAAAUg1b70sAwAAQIIA5H+j63g4gAAA" + "OKAAAkg1aSUsAwAAQYAAzDuDAB9XnAA0f6PreDiAAAA4o" + "AAASDVpBSwDAABBgACsgG2xpH+E43g4oAAgSCx/bXx7G3" + "h/o+t4f2TbeH+F43hINWcZLAMAAECBAFyAbbGsgJsAIIC" + "7AERILH9BfHwbeEgy8mF/Y9t4f4TjeEgy/3UsAwABQIIA" + "GEgy8l2Tn1S4k39UvIPbADRIAAAof2PbeEgzAZ1IMvJBg" + "G2xrH+E43hILIWFgG2xpH9k23hILIV5f6PreEg1cLksHg" + "AAQYIADH/IA6ZOgAAhf0PTeEgy8h27QQAIgAEAtHwIA6Y" + "4IQCwSAAnSA=="), # 6D6F642E72656C00 + # JP + "jp": base64.b64decode("PYCAM2GMZ+R9iAOmToAAITxggDNgY4pkSAAABXyIAqY4h" + "ABQSAABSYhtseAsAwAAQYIAIIBtutg4gAAFOKAAAT2AgC" + "thjBIQfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyrLH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMYPYCAOmGMzgR9iAOmT" + "oAAIX+j63g4gAMYSAAA0ZOtvvg4fQMYkG2+/DxggDNgYz" + "zkY6QA/EgAAJ09gIAzYYyKaH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDO9B8fxt4P8CAAGPDW/Q8gICwOKADG" + "EuKzNVjw1v0OIADGEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2BjimQ8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpSZ4fKgDpk6AACFjoydcfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2x5J" + "Qh/1B8CAKmkAEAtL9BAAhIMwoJfHobeD/ggAA7wAAAO6E" + "AIGPjXwR/pOt4OKAAAUg1hkUsAwAAQIIA5H+j63g4gAAA" + "OKAAAkg1f60sAwAAQYAAzDuDAB9XnAA0f6PreDiAAAA4o" + "AAASDV/jSwDAABBgACsgG2y5H+E43g4oAAgSCyWXXx7G3" + "h/o+t4f2TbeH+F43hINX2hLAMAAECBAFyAbbLsgJsAIIC" + "7AERILJYxfHwbeEgzCVF/Y9t4f4TjeEgzFmUsAwABQIIA" + "GEgzCU2Tn1S4k39UvIPbADRIAAAof2PbeEgzGI1IMwkxg" + "G2y7H+E43hILJx1gG2y5H9k23hILJxpf6PreEg1h0EsHg" + "AAQYIADH/IA6ZOgAAhf0PTeEgzCQ27QQAIgAEAtHwIA6Y" + "4IQCwSAAnSA=="), # 6D6F642E72656C00 + }, + '2': { + # NA 1.0 + "us0": base64.b64decode("PYCANGGMovR9iAOmToAAITxggDRgY8V0SAAABXyIAqY4h" + "ABQSAABSYhtsmAsAwAAQYIAIIBtu0g4gAAFOKAAAT2AgC" + "phjPzcfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyp+H2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMsPYCAPGGMCRR9iAOmT" + "oAAIX+j63g4gAMsSAAA0ZOtv5A4fQMskG2/lDxggDRgY3" + "f0Y6QA/EgAAJ09gIA0YYzFeH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuEduB8fxt4P8CAAGPDW/Q8gICwOKADL" + "EuMB+Vjw1v0OIADLEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CANGBjxXQ8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDRjpWGIfKgDpk6AACFjo2JsfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2yZJ" + "Qh/1B8CAKmkAEAtL9BAAhINEUZfHobeD/ggAA7wAAAO6E" + "AIGPjXxh/pOt4OKAAAUg2wVUsAwAAQIIA+H+j63g4gAAA" + "OKAAAkg2ur0sAwAAQYAA4DuDAB9XnAA0f6PreDiAAAA4o" + "AAASDa6nSwDAABBgADAgG2zZH+E43g4oAAgSC3RbXx7G3" + "h/o+t4f2TbeH+F43hINrixLAMAAECBAHCAbbNsgJsAIIC" + "7AERILdFBfHwbeEg0RGF/Y9t4f4TjeEg0UX0sAwABQIIA" + "LEg0RF2AuwBIfLsoUIBts2R/ZNt4SC3ZfZOfVLiTf1S8g" + "9sANEgAACh/Y9t4SDRTiUg0RC2AbbNsf4TjeEgt13GAbb" + "Nkf2TbeEgt12V/o+t4SDbCPSweAABBggAMf8gDpk6AACF" + "/Q9N4SDRECbtBAAiAAQC0fAgDpjghALBIACc0"), + # NA 1.2 + "us2": base64.b64decode("PYCAM2GMTMR9iAOmToAAITxggDNgY29ESAAABXyIAqY4h" + "ABQSAABSYhtseAsAwAAQYIAIIBtuug4gAAFOKAAAT2AgC" + "phjPbwfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyqsH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMsPYCAOmGMs0x9iAOmT" + "oAAIX+j63g4gAMsSAAA0ZOtvwg4fQMskG2/DDxggDNgYy" + "HEY6QA/EgAAJ09gIAzYYxvSH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDILB8fxt4P8CAAGPDW/Q8gICwOKADL" + "EuKsh1jw1v0OIADLEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2Bjb0Q8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpQtYfKgDpk6AACFjoww8fGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2x5J" + "Qh/1B8CAKmkAEAtL9BAAhIMu7pfHobeD/ggAA7wAAAO6E" + "AIGPjXxh/pOt4OKAAAUg1a40sAwAAQIIA+H+j63g4gAAA" + "OKAAAkg1ZPUsAwAAQYAA4DuDAB9XnAA0f6PreDiAAAA4o" + "AAASDVk1SwDAABBgADAgG2y5H+E43g4oAAgSCx7PXx7G3" + "h/o+t4f2TbeH+F43hINWLpLAMAAECBAHCAbbLsgJsAIIC" + "7AERILHsRfHwbeEgy7jF/Y9t4f4TjeEgy+00sAwABQIIA" + "LEgy7i2AuwBIfLsoUIBtsuR/ZNt4SCyDTZOfVLiTf1S8g" + "9sANEgAACh/Y9t4SDL9WUgy7f2AbbLsf4TjeEgsgUGAbb" + "Lkf2TbeEgsgTV/o+t4SDVsdSweAABBggAMf8gDpk6AACF" + "/Q9N4SDLt2btBAAiAAQC0fAgDpjghALBIACc0"), + # PAL + "eu": base64.b64decode("PYCAM2GMUPR9iAOmToAAITxggDNgY3N0SAAABXyIAqY4h" + "ABQSAABSYhtsKAsAwAAQYIAIIBtuag4gAAFOKAAAT2AgC" + "phjPsgfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyqoH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMsPYCAOmGMt9B9iAOmT" + "oAAIX+j63g4gAMsSAAA0ZOtvcg4fQMskG29zDxggDNgYy" + "X0Y6QA/EgAAJ09gIAzYYxzeH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDJOB8fxt4P8CAAGPDW/Q8gICwOKADL" + "EuKtqFjw1v0OIADLEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2Bjc3Q8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpQ+IfKgDpk6AACFjoxBsfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2wpJ" + "Qh/1B8CAKmkAEAtL9BAAhIMvMZfHobeD/ggAA7wAAAO6E" + "AIGPjXxh/pOt4OKAAAUg1b70sAwAAQIIA+H+j63g4gAAA" + "OKAAAkg1aSUsAwAAQYAA4DuDAB9XnAA0f6PreDiAAAA4o" + "AAASDVpBSwDAABBgADAgG2xpH+E43g4oAAgSCx/bXx7G3" + "h/o+t4f2TbeH+F43hINWcZLAMAAECBAHCAbbGsgJsAIIC" + "7AERILH9BfHwbeEgy8mF/Y9t4f4TjeEgy/30sAwABQIIA" + "LEgy8l2AuwBIfLsoUIBtsaR/ZNt4SCyHfZOfVLiTf1S8g" + "9sANEgAACh/Y9t4SDMBiUgy8i2AbbGsf4TjeEgshXGAbb" + "Gkf2TbeEgshWV/o+t4SDVwpSweAABBggAMf8gDpk6AACF" + "/Q9N4SDLyCbtBAAiAAQC0fAgDpjghALBIACc0"), + # JP + "jp": base64.b64decode("PYCAM2GMZ+R9iAOmToAAITxggDNgY4pkSAAABXyIAqY4h" + "ABQSAABSYhtseAsAwAAQYIAIIBtutg4gAAFOKAAAT2AgC" + "thjBIQfYgDpk6AACE4YAAAPICAADigAAA9gIABYYyrLH2" + "JA6ZOgAQglCH/4HwIAqaQAQAkv6EACHx+G3h8nyN4P6CA" + "sH+j63hIAAAFfIgCpjiE/3A4oAMsPYCAOmGMzgR9iAOmT" + "oAAIX+j63g4gAMsSAAA0ZOtvvg4fQMskG2+/DxggDNgYz" + "zkY6QA/EgAAJ09gIAzYYyKaH2JA6Z/w/N4f+T7eLuhAAi" + "AAQAkfAgDpjghACBOgAQgfH8beDxggTNgYzqcPICAsGCE" + "ARxIAABdf+P7eEuDO9B8fxt4P8CAAGPDW/Q8gICwOKADL" + "EuKzNVjw1v0OIADLEgAAEk8YIAAYGOGRGPEXchIAAAhPG" + "CAM2BjimQ8gIAAYIRcYEgAAA1/4/t4SIM5OHyDIFBUhAG" + "6PKBIAHylI3iQowAAOIAABJQh/+B8CAKmkAEAJL+hAAh8" + "fxt4fJ4jeD+ggDNjpSZ4fKgDpk6AACFjoydcfGgDpn/j+" + "3h/xPN4ToAAIbuhAAiAAQAkfAgDpjghACBOgAAgkG2x5J" + "Qh/1B8CAKmkAEAtL9BAAhIMwoJfHobeD/ggAA7wAAAO6E" + "AIGPjXxh/pOt4OKAAAUg1hkUsAwAAQIIA+H+j63g4gAAA" + "OKAAAkg1f60sAwAAQYAA4DuDAB9XnAA0f6PreDiAAAA4o" + "AAASDV/jSwDAABBgADAgG2y5H+E43g4oAAgSCyWXXx7G3" + "h/o+t4f2TbeH+F43hINX2hLAMAAECBAHCAbbLsgJsAIIC" + "7AERILJYxfHwbeEgzCVF/Y9t4f4TjeEgzFm0sAwABQIIA" + "LEgzCU2AuwBIfLsoUIBtsuR/ZNt4SCyebZOfVLiTf1S8g" + "9sANEgAACh/Y9t4SDMYeUgzCR2AbbLsf4TjeEgsnGGAbb" + "Lkf2TbeEgsnFV/o+t4SDWHLSweAABBggAMf8gDpk6AACF" + "/Q9N4SDMI+btBAAiAAQC0fAgDpjghALBIACc0"), + } +} + +# +------------------+ +# | Common functions | +# +------------------+ + + +def alignUp(value: int, size: int): + """Aligns and address to the given size. + + :param value: The address to align up. + :type value: int + :param size: The size to which we align the address. + :type size: int + + :return The aligned address. + :rtype int + """ + return value + (size - value % size) % size + + +def sha1(data: bytes) -> bytes: + hasher = hashlib.sha1() + hasher.update(data) + return hasher.digest() + + +def md5(data: bytes) -> bytes: + hasher = hashlib.md5() + hasher.update(data) + return hasher.digest() + + +def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_CBC, iv).decrypt(data) + + +def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_CBC, iv).encrypt(data) + +# +-------------------+ +# | Class definitions | +# +-------------------+ + +# Classes used to generate a new signature +# (Algorithm from the Dolphin Emulator project) + + +class Elt: + pass + + +class Elt: + __slots__ = ('data',) + + def __init__(self, data: bytes = bytes(30)): + self.data = bytes(data[0:min(30, len(data))]) + \ + bytes(max(0, 30 - len(data))) + + def is_zero(self): + return all(d == 0 for d in self.data) + + def mulX(self): + new_data = bytearray(self.data) + carry = new_data[0] & 1 + + # x = (self.data[29] << 1) & 0xFF + # xs = itertools.chain([0], ((y << 1) & 0xFF for y in self.data[1:-1])) + # new_data[:-1] = list((x ^ (y >> 7)) & 0xFF for x, y in zip(xs, self.data[1:])) + x = 0 + for i in range(29): + y = new_data[i + 1] + new_data[i] = (x ^ (y >> 7)) & 0xFF + x = (y << 1) & 0xFF + + new_data[29] = (x ^ carry) & 0xFF + new_data[20] ^= (carry << 2) & 0xFF + self.data = bytes(new_data) + + def square(self): + # wide = bytearray(y for x in ( + # (SQUARE[x >> 4], SQUARE[x & 0xF]) for x in self.data) for y in x) + wide = bytearray(60) + for i in range(30): + wide[2 * i] = SQUARE[self.data[i] >> 4] + wide[2 * i + 1] = SQUARE[self.data[i] & 0xF] + + for i in range(30): + x = wide[i] + wide[i + 19] ^= x >> 7 + wide[i + 20] ^= (x << 1) & 0xFF + wide[i + 29] ^= x >> 1 + wide[i + 30] ^= (x << 7) & 0xFF + x = wide[30] & ~1 + wide[49] ^= x >> 7 + wide[50] ^= (x << 1) & 0xFF + wide[59] ^= x >> 1 + wide[30] &= 1 + return Elt(wide[30:]) + + def ItohTsujii(self, b, j): + t = Elt(self.data) + for _ in range(j): + t = t.square() + return t * b + + def inv(self): + t = self.ItohTsujii(self, 1) + s = t.ItohTsujii(self, 1) + t = s.ItohTsujii(s, 3) + s = t.ItohTsujii(self, 1) + t = s.ItohTsujii(s, 7) + s = t.ItohTsujii(t, 14) + t = s.ItohTsujii(self, 1) + s = t.ItohTsujii(t, 29) + t = s.ItohTsujii(s, 58) + s = t.ItohTsujii(t, 116) + return s.square() + + def __add__(self, other): + if not isinstance(other, Elt): + raise TypeError( + f"Cannot add {self.__class__.__name__} " + f"with {other.__class__.__name__}") + return Elt(bytes(a ^ b for a, b in zip(self.data, other.data))) + + def __truediv__(self, other): + if not isinstance(other, Elt): + raise TypeError( + f"Cannot divide {self.__class__.__name__} " + f"with {other.__class__.__name__}") + return self * other.inv() + + def __mul__(self, other: Elt): + if not isinstance(other, Elt): + raise TypeError( + f"Cannot multiply {self.__class__.__name__} " + f"with {other.__class__.__name__}") + d = Elt() + i = 0 + mask = 1 + for _ in range(233): + d.mulX() + if (self.data[i] & mask) != 0: + d = d + other + mask >>= 1 + if mask == 0: + mask = 0x80 + i += 1 + return d + + +class Point: + __slots__ = ('x', 'y',) + + def __init__(self, x: Elt = Elt(), y: Elt = Elt()): + self.x = Elt(x.data) + self.y = Elt(y.data) + + def is_zero(self): + return self.x.is_zero() and self.y.is_zero() + + def double(self): + r = Point() + if self.x.is_zero(): + return r + s = (self.y / self.x) + # print(s.data.hex()) + s = s + self.x + r.x = s.square() + s + r_x_data = bytearray(r.x.data) + r_x_data[29] ^= 1 + r.x.data = bytes(r_x_data) + r.y = s * r.x + r.x + self.x.square() + return r + + def __add__(self, other): + if not isinstance(other, Point): + raise TypeError( + f"Cannot add {self.__class__.__name__} " + f"with {other.__class__.__name__}") + if self.is_zero(): + return Point(other.x, other.y) + if other.is_zero(): + return Point(self.x, self.y) + u = self.x + other.x + if u.is_zero(): + u = self.y + other.y + if u.is_zero(): + return self.double() + return Point() + s = (self.y + other.y) / u + t = s.square() + s + other.x + t_data = bytearray(t.data) + t_data[29] ^= 1 + t.data = bytes(t_data) + rx = t + self.x + ry = s * t + self.y + rx + return Point(rx, ry) + + def __mul__(self, other): + if not isinstance(other, bytes | bytearray | memoryview): + raise TypeError( + f"Point only multiplies with bytes, " + f"got {other.__class__.__name__}") + d = Point() + for i in range(30): + mask = 0x80 + while mask != 0: + d = d.double() + if (other[i] & mask) != 0: + d = d + self + mask >>= 1 + return d + + +EC_G = Point(Elt(bytes([0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, + 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, + 0xbb, 0x75, 0x5f, 0xef, 0x65, 0xbc, + 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, + 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b])), + Elt(bytes([0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, + 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, + 0x28, 0xbe, 0xbf, 0x8a, 0x0b, 0xef, + 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, + 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52]))) + +EC_N = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xe9, 0x74, 0xe7, 0x2f, + 0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7]) + + +class SignatureType(IntEnum): + RSA4096 = 0x00010000 + RSA2048 = 0x00010001 + ECC = 0x00010002 + + +class PublicKeyType(IntEnum): + RSA4096 = 0x00000000 + RSA2048 = 0x00000001 + ECC = 0x00000002 + + +class SignatureECC: + __slots__ = ('type', 'sig', 'fill', 'issuer',) + PACK_FORMAT = struct.Struct('>I60s64s64s') + + def __init__(self, type: SignatureType, sig, fill, issuer): + self.type = type + self.sig = sig + self.fill = fill + self.issuer = issuer + + def pack(self): + return SignatureECC.PACK_FORMAT.pack(self.type.value, self.sig, self.fill, self.issuer) + + +class CertHeader: + __slots__ = ('public_key_type', 'name', 'id',) + PACK_FORMAT = struct.Struct('>I64sI') + + def __init__(self, public_key_type: PublicKeyType, name, id): + self.public_key_type = public_key_type + self.name = name + self.id = id + + def pack(self): + return CertHeader.PACK_FORMAT.pack(self.public_key_type.value, self.name, self.id) + + +class CertECC: + __slots__ = ("signature", "header", "public_key", "padding",) + + def __init__(self, signature: SignatureECC, header: CertHeader, public_key: bytes, padding: bytes): + self.signature = signature + self.header = header + self.public_key = public_key + self.padding = padding + + def pack(self): + return self.signature.pack() + self.header.pack() + self.public_key + self.padding + +# +---------------------+ +# | Signature functions | +# +---------------------+ + + +def priv_to_pub(key: bytes): + data = EC_G * bytes(key) + return data.x.data + data.y.data + + +def make_blank_ecc_cert(issuer, name, public_key: bytes, key_id): + return CertECC(SignatureECC(SignatureType.ECC, bytes(60), bytes(0x40), bytes(issuer, 'utf-8')[0:min(0x3F, len(issuer))] + b'\0'), CertHeader(PublicKeyType.ECC, bytes(name, 'utf-8')[0:min(0x3F, len(name))] + b'\0', key_id), public_key, bytes(60)) + + +def get_device_certificate(device_id=DEFAULT_DEVICE_ID): + name = f"NG{device_id:08x}" + cert = make_blank_ecc_cert( + f"Root-CA{CA_ID:08x}-MS{MS_ID:08x}", name, DEFAULT_PUBLIC_KEY, DEFAULT_KEY_ID) + cert.signature.sig = DEFAULT_SIGNATURE + return cert + + +def bn_sub_modulus(a, N, n): + a = bytearray(a) + c = 0 + for i in range(n - 1, -1, -1): + dig = N[i] + c + c = a[i] < dig + a[i] = (a[i] - dig) & 0xFF + return a + + +def bn_add(a: bytes, b: bytes, N, n): + d = bytearray(n) + c = 0 + for i in range(n - 1, -1, -1): + dig = a[i] + b[i] + c + c = (dig >= 0x100) + d[i] = (dig) & 0xFF + + if c: + d = bn_sub_modulus(d, N, n) + if d >= N: + d = bn_sub_modulus(d, N, n) + return d + + +def bn_mul(a, b, N, n): + d = bytearray(n) + for i in range(n): + mask = 0x80 + while mask != 0: + d = bn_add(d, d, N, n) + if (a[i] & mask) != 0: + d = bn_add(d, b, N, n) + mask >>= 1 + return d + + +def bn_exp(a, N, n, e, en): + t = bytearray(512) + d = bytearray(n) + d[n - 1] = 1 + for i in range(en): + mask = 0x80 + while mask != 0: + t = bn_mul(d, d, N, n) + if (e[i] & mask) != 0: + d = bn_mul(t, a, N, n) + else: + d[:] = t[:n] + mask >>= 1 + return d + + +def bn_inv(a, N, n): + d = bytearray(n) + t = bytearray(512) + s = bytearray(512) + t[0:n] = N + s[n - 1] = 2 + t = bn_sub_modulus(t, s, n) + d = bn_exp(a, N, n, t, n) + return d + + +def sign2(key: bytes, hash: bytes): + e = bytearray(30) + e[10:] = hash + m = bytearray(secrets.token_bytes(30)) + m[0] &= 1 + while m >= EC_N: + m = bytearray(secrets.token_bytes(30)) + m[0] &= 1 + r = (EC_G * m).x + if r.data >= EC_N: + r.data = bytes(bn_sub_modulus(r.data, EC_N, 30)) + + kk = bytearray(30) + kk[:] = key + if kk >= EC_N: + kk = bn_sub_modulus(kk, EC_N, 30) + s = Elt(bn_mul(r.data, kk, EC_N, 30)) + kk = bn_add(s.data, e, EC_N, 30) + minv = bn_inv(m, EC_N, 30) + s.data = bytes(bn_mul(minv, kk, EC_N, 30)) + + signature = bytearray(60) + signature[:30] = r.data + signature[30:] = s.data + return bytes(signature) + + +def sign(title_id, data, device_id=DEFAULT_DEVICE_ID): + hash = bytearray(20) + ap_priv = bytearray(30) + ap_priv[0x1d] = 1 + + logging.debug(f"Signing for device #{device_id:08x}") + # In practice, we can reduce the encryption time by using a + # pre-calculated "cert", but it's not a significant amount of time + signer = f"Root-CA{CA_ID:08x}-MS{MS_ID:08x}-NG{device_id:08x}" + name = f"AP{title_id:016x}" + logging.debug("Creating certificate...") + cert = make_blank_ecc_cert(signer, name, priv_to_pub(ap_priv), 0) + cert_packed = cert.pack() + hash = sha1(cert_packed[0x80:]) + cert.signature.sig = sign2(DEFAULT_PRIVATE_KEY, hash) + cert = cert.pack() + + logging.debug("Signing data...") + hash = sha1(data) + signature = sign2(ap_priv, hash) + logging.debug("Signed") + + return (signature, cert) + + +def verify_signature(public_key, signature, hash): + r = signature[:30] + s = signature[30:] + + s_inv = bn_inv(s, EC_N, 30) + e = bytearray(30) + e[10:] = hash[:20] + + w1 = bn_mul(e, s_inv, EC_N, 30) + w2 = bn_mul(r, s_inv, EC_N, 30) + + public_key_point = Point(Elt(public_key[:30]), Elt(public_key[30:])) + r1 = EC_G * w1 + public_key_point * w2 + rx = r1.x.data + if rx >= EC_N: + rx = bn_sub_modulus(rx, EC_N, 30) + + return rx == r + + +class Header: + """The encryption header. + + It contains the necessary data for the save file's encryption and + signature. It wraps the archive that contains the game's saved + files. + """ + + __slots__ = ("tid", "banner_size", "permissions", + "unk1", "md5", "unk2", "banner",) + PACK_FORMAT = struct.Struct('>QIBB16sH') + PACK_SIZE = PACK_FORMAT.size + FULL_BNR_MAX + + def __init__(self, tid: int, banner_size: int, permissions: int, unk1: int, md5: bytes, unk2: int, banner=bytes()): + self.tid = tid + self.banner_size = banner_size + self.permissions = permissions + self.unk1 = unk1 + self.md5 = md5 + self.unk2 = unk2 + self.banner = banner + + def __repr__(self) -> str: + return (f"Header(tid=0x{self.tid:016x}, " + f"banner_size=0x{self.banner_size:08x}, " + f"permissions=0x{self.permissions:02x}, " + f"unk1=0x{self.unk1:02x}, " + f"md5=0x{self.md5.hex()}, " + f"unk2={self.unk2:04x}, " + f"banner={self.banner})") + + def __str__(self) -> str: + return (f"Header(tid=0x{self.tid:016x}, " + f"banner_size=0x{self.banner_size:08x}, " + f"permissions=0x{self.permissions:02x}, " + f"unk1=0x{self.unk1:02x}, " + f"md5=0x{self.md5.hex()}, " + f"unk2={self.unk2:04x}, " + f"banner={self.banner.__class__.__name__}({len(self.banner)}))") + + def updateBanner(self, banner: bytes): + """Updates the headers and sets the new banner. + + :param banner: The banner file + :type banner: bytes + """ + new_size = len(banner) + if (new_size < FULL_BNR_MIN) or (new_size > FULL_BNR_MAX) or (((new_size - BNR_SZ) % ICON_SZ) != 0): + logging.error(f"Invalid banner size {new_size:04x}") + self.banner_size = new_size + self.banner = banner + self.md5 = md5(self.to_bytes()) + + @staticmethod + def generate(banner: bytes, game_version: str): + """Generates a new header from a given banner for the given version + of 'The Legend of Zelda: Twilight Princess'. + """ + hdr = Header(VERSIONS[game_version], len( + banner), 0x34, 0, MD5_BLANKER, 0, banner) + hdr.md5 = md5(hdr.to_bytes()) + return hdr + + @staticmethod + def unpack(buffer: bytes): + data = aes_cbc_decrypt(SD_KEY, SD_INITIAL_IV, + buffer[0:Header.PACK_SIZE]) + hdr = Header( + *Header.PACK_FORMAT.unpack(data[0:Header.PACK_FORMAT.size])) + hdr.banner = data[Header.PACK_FORMAT.size:][0:hdr.banner_size] + if (hdr.banner_size < FULL_BNR_MIN) or (hdr.banner_size > FULL_BNR_MAX) or (((hdr.banner_size - BNR_SZ) % ICON_SZ) != 0): + logging.error( + "Warning: Not a Wii save or read failure for " + f"banner size 0x{hdr.banner_size:04x} ({hdr.banner_size})") + return + hdr_md5 = hdr.md5 + hdr.md5 = MD5_BLANKER + md5_calc = md5(hdr.to_bytes()) + hdr.md5 = hdr_md5 + if md5_calc != hdr_md5: + logging.error( + f"[Header] MD5 mismatch: {hdr_md5.hex()} != {md5_calc.hex()}") + return + return hdr + + @staticmethod + def from_file(reader: FileIO): + reader.seek(0) + return Header.unpack(reader.read(Header.PACK_SIZE)) + + def to_bytes(self): + data1 = Header.PACK_FORMAT.pack( + self.tid, self.banner_size, self.permissions, self.unk1, self.md5, self.unk2) + data2 = self.banner + if len(data2) < FULL_BNR_MAX: + data2 += bytes(FULL_BNR_MAX - self.banner_size) + return data1 + data2 + + def pack(self): + self.md5 = MD5_BLANKER + self.md5 = md5(self.to_bytes()) + return aes_cbc_encrypt(SD_KEY, SD_INITIAL_IV, self.to_bytes()) + + +class BkHeader: + """The archive header. + + This header contains the data related to the archival of + the files saved by the game. + """ + + __slots__ = ("size", "magic", "ngid", "number_of_files", "size_of_files", + "unk1", "unk2", "total_size", "unk3", "tid", "mac_address", + "padding",) + PACK_FORMAT = struct.Struct('>8I64sQ6s18s') + MAGIC = 0x426B0001 + + def __init__(self, size, magic, ngid, number_of_files, size_of_files, unk1, unk2, total_size, unk3, tid, mac_address, padding): + self.size = size + self.magic = magic + self.ngid = ngid + self.number_of_files = number_of_files + self.size_of_files = size_of_files + self.unk1 = unk1 + self.unk2 = unk2 + self.total_size = total_size + self.unk3 = unk3 + self.tid = tid + self.mac_address = mac_address + self.padding = padding + + def __repr__(self) -> str: + return f"BkHeader(size=0x{self.size:08x}, magic=0x{self.magic:08x}, ngid=0x{self.ngid:08x}, number_of_files={self.number_of_files}, size_of_files={self.size_of_files}, unk1={self.unk1}, unk2={self.unk2}, total_size={self.total_size}, unk3={self.unk3}, tid=0x{self.tid:016x}, mac_address={self.mac_address}, padding={self.padding})" + + def __str__(self) -> str: + return f"BkHeader(size=0x{self.size:08x}, magic=0x{self.magic:08x}, ngid=0x{self.ngid:08x}, number_of_files={self.number_of_files}, size_of_files={self.size_of_files}, unk1={self.unk1}, unk2={self.unk2}, total_size={self.total_size}, unk3={self.unk3.__class__.__name__}({len(self.unk3)}), tid=0x{self.tid:016x}, mac_address={self.mac_address.hex()}, padding={self.padding.__class__.__name__}({len(self.padding)}))" + + @staticmethod + def generate(files: list, game_version: str): + size_of_files = sum(len(file) for file in files) + bkh = BkHeader(BK_LISTED_SZ, BkHeader.MAGIC, DEFAULT_DEVICE_ID, len(files), size_of_files, 0, 0, + size_of_files + FULL_CERT_SZ, bytes(0x40), VERSIONS[game_version], bytes(6), bytes(0x12)) + return bkh + + @staticmethod + def unpack(buffer): + hdr = BkHeader(*BkHeader.PACK_FORMAT.unpack(buffer)) + if hdr.size != BK_LISTED_SZ: + logging.error( + f"[BkHeader] Invalid header size: {BK_LISTED_SZ} != {hdr.size}") + return + if hdr.magic != BkHeader.MAGIC: + logging.error( + f"[BkHeader] Magic mismatch: {BkHeader.MAGIC:08x} != {hdr.magic:08x}") + return + if hdr.size_of_files + FULL_CERT_SZ != hdr.total_size: + logging.error( + f"[BkHeader] Invalid files size: {hdr.size_of_files + FULL_CERT_SZ} != {hdr.total_size}") + return + return hdr + + @staticmethod + def from_file(reader: FileIO): + reader.seek(Header.PACK_SIZE) + data = reader.read(BkHeader.PACK_FORMAT.size) + return BkHeader.unpack(data) + + def to_bytes(self): + return BkHeader.PACK_FORMAT.pack(self.size, self.magic, self.ngid, self.number_of_files, self.size_of_files, self.unk1, self.unk2, self.total_size, self.unk3, self.tid, self.mac_address, self.padding) + + def pack(self): + return self.to_bytes() + + +class NodeType(IntEnum): + FILE = 1 + DIR = 2 + + +class FileHDR: + __slots__ = ("magic", "size", "permissions", "attrib", + "node_type", "name", "padding", "iv", "unk",) + PACK_FORMAT = struct.Struct('>II3B64s5s16s32s') + MAGIC = 0x03adf17e + + def __init__(self, magic, size, permissions, attrib, node_type: NodeType, name, padding, iv, unk): + self.magic = magic + self.size = size + self.permissions = permissions + self.attrib = attrib + self.node_type = NodeType(node_type) + self.name = name + self.padding = padding + self.iv = iv + self.unk = unk + + def __str__(self) -> str: + return f"FileHDR(magic=0x{self.magic:08x}, size=0x{self.size:08x}, permissions=0x{self.permissions:02x}, attrib=0x{self.attrib:02x}, node_type={self.node_type.name[:1].upper() + self.node_type.name.lower()[1:]}, name={self.name}, padding=bytes({len(self.padding)}), iv={self.iv.hex()}, unk={self.unk})" + + @staticmethod + def unpack(buffer): + file_hdr = FileHDR(*FileHDR.PACK_FORMAT.unpack(buffer)) + if file_hdr.magic != FileHDR.MAGIC: + logging.error( + f"[FileHDR] magic field mismatch: {FileHDR.MAGIC:08x} != {file_hdr.magic:08x}") + return + return file_hdr + + @staticmethod + def from_save_file(save): + if len(save.path) >= 0x40: + logging.error( + f"Error: file name {save.path!a} is too long (64 characters max)") + return + file_hdr = FileHDR(FileHDR.MAGIC, len(save.data) if save.node_type == 1 else 0, save.mode, + save.attributes, save.node_type, bytes(save.path, 'utf-8')[:min(0x40, len(save.path))] + bytes(max(0, 0x40-len(save.path))), bytes(5), SD_INITIAL_IV, bytes(0x20)) + return file_hdr + + def pack(self): + return FileHDR.PACK_FORMAT.pack(self.magic, self.size, self.permissions, self.attrib, self.node_type, self.name, self.padding, self.iv, self.unk) + + +class SaveNode: + def __init__(self, mode=0, attributes=0, node_type: NodeType = NodeType.DIR, path="", data=None): + self.mode = mode + self.attributes = attributes + self.node_type = NodeType(node_type) + self.path = path + self.data = data + + def __repr__(self) -> str: + data = f", data={self.data}" if self.data is not None else "" + return f"SaveNode(path={repr(self.path)}, node_type={self.node_type}, mode={self.mode}, attributes={self.attributes}{data})" + + def __str__(self) -> str: + data = f", data={self.data.__class__.__name__}({len(self.data)})" if self.data is not None else "" + return f"SaveNode(path=\"{self.path}\", node_type={self.node_type.name[:1].upper() + self.node_type.name.lower()[1:]}, mode={self.mode}, attributes={self.attributes}{data})" + + @staticmethod + def unpack(reader: FileIO): + data = reader.read(FileHDR.PACK_FORMAT.size) + file_hdr = FileHDR.unpack(data) + if file_hdr is None: + return + file_data = None + if file_hdr.node_type == NodeType.FILE: + size = file_hdr.size + rounded_size = alignUp(size, BLOCK_SZ) + file_data = reader.read(rounded_size) + file_data = aes_cbc_decrypt(SD_KEY, file_hdr.iv, file_data)[0:size] + return SaveNode(file_hdr.permissions, file_hdr.attrib, file_hdr.node_type, + file_hdr.name.split(b'\x00')[0].decode('utf-8'), file_data) + + @staticmethod + def unpack_all(reader: FileIO, bkh: BkHeader): + files: List[SaveNode] = [] + reader.seek(Header.PACK_SIZE + BkHeader.PACK_FORMAT.size) + for i in range(0, bkh.number_of_files): + logging.debug(f"[SaveNode] Unpacking file #{i}") + file = SaveNode.unpack(reader) + if not file is None: + files.append(file) + else: + logging.error(f"[SaveNode] Error while unpacking file #{i}") + return + return files + + def pack(self): + file_hdr = FileHDR.from_save_file(self) + if file_hdr is None: + return + data_enc = bytes(0) + if not self.data is None and len(self.data) > 0: + data_aligned = self.data + \ + bytes(alignUp(len(self.data), BLOCK_SZ) - len(self.data)) + data_enc = aes_cbc_encrypt(SD_KEY, file_hdr.iv, data_aligned) + return file_hdr.pack() + data_enc + + def metadata(self): + return {'path': self.path, 'mode': self.mode, 'attributes': self.attributes, 'type': self.node_type} + + @staticmethod + def pack_all(files): + data = bytes() + for file in files: + data = data + file.pack() + return data + + def __len__(self): + return FileHDR.PACK_FORMAT.size + alignUp(len(self.data), BLOCK_SZ) if self.node_type == 1 else 0 + + +class SaveBin: + def __init__(self, header: Header, bkheader: BkHeader, files: List[SaveNode]): + self.header = header + self.bkheader = bkheader + self.files = files + + def __repr__(self) -> str: + return f"SaveBin(header={repr(self.header)}, bkheader={repr(self.bkheader)}, files=[{', '.join([repr(file) for file in self.files])}])" + + def __str__(self) -> str: + return f"SaveBin(header={str(self.header)}, bkheader={str(self.bkheader)}, files=[{', '.join([str(file) for file in self.files])}])" + + @staticmethod + def from_file(reader: FileIO): + header = Header.from_file(reader) + if header is None: + logging.error("[SaveBin] Could not parse Header") + return + bkheader = BkHeader.from_file(reader) + if bkheader is None: + logging.error("[SaveBin] Could not parse BkHeader") + return + files = SaveNode.unpack_all(reader, bkheader) + if files is None: + logging.error("[SaveBin] Could not parse files") + return + return SaveBin(header, bkheader, files) + + @staticmethod + def generate(banner: FileIO, game_version: str): + files = [] + bkheader = BkHeader.generate(files, game_version) + header = Header.generate(banner.read(), game_version) + return SaveBin(header, bkheader, files) + + def to_file(self, writer: FileIO): + writer.write(self.header.pack()) + data1 = self.bkheader.pack() + SaveNode.pack_all(self.files) + writer.write(data1) + data_sha1 = sha1(data1) + ap_sig, ap_cert = sign(SYSTEM_MENU, data_sha1, self.bkheader.ngid) + writer.write(ap_sig + struct.pack('>I', SIGNATURE_END_MAGIC) + + get_device_certificate(self.bkheader.ngid).pack() + ap_cert) + + def _update_bk_files(self): + self.bkheader.number_of_files = len(self.files) + self.bkheader.size_of_files = sum(len(file) for file in self.files) + self.bkheader.total_size = self.bkheader.size_of_files + FULL_CERT_SZ + + def add_file(self, path, data, mode=0x3f, attributes=0, node_type=NodeType.FILE): + indices = [i for i, f in enumerate( + self.files) if f.path == path] + indices.sort(reverse=True) + # Remove all duplicate occurences + n_idx = len(indices) + if n_idx > 0: + logging.debug( + f"{n_idx} file{'s' if n_idx > 1 else ''} already exist with the same name. Removing them...") + for idx in indices: + self.files.pop(idx) + # Split the path into component dirs, and fold it to get each directory's full path. + def fold(acc, x): + l = [] + l.extend(acc) + l.append(acc[-1] + '/' + x) + return l + dirs = path.split('/')[:-1] + if len(dirs) > 1: + dirs = reduce(fold, dirs[1:], [dirs[0]]) + # Checking for all the parent directories if they exist + for d in dirs: + # For each parent directory, find it in the list... + f = next((f for f in self.files if f.path == d), None) + if not f is None: + # ... if found, skip to the next directory... + if f.node_type != NodeType.DIR: + raise RuntimeError(f"'{d}' already exists and is not a directory") + logging.debug(f"'{d}' found") + continue + else: + # ... else create directory. + logging.debug(f"'{d}' not found") + self.add_file(d, None, mode, attributes, NodeType.DIR) + logging.debug(f"Adding '{path}'...") + self.files.append(SaveNode(mode, attributes, node_type, path, data)) + self._sort_files() + self._update_bk_files() + + def _sort_files(self): + self.files.sort(key=lambda x: x.path) + pass + + def rm_file(self, path): + indices = [i for i, f in enumerate( + self.files) if f.path == path] + indices.sort(reverse=True) + # Remove all occurences + n_idx = len(indices) + if n_idx > 0: + # If it is a directory, remove all the children recursively + for f in [self.files[idx] for idx in indices]: + if f.node_type == NodeType.DIR: + for sub_path in [x.path for x in self.files if x.path.startswith(f.path + '/')]: + self.rm_file(sub_path) + logging.debug(f"removing '{path}'...") + for idx in indices: + self.files.pop(idx) + self._sort_files() + self._update_bk_files() + + def config(self): + return {'tid': self.header.tid, 'permissions': self.header.permissions, 'ngid': self.bkheader.ngid, 'mac_address': struct.unpack('>Q', bytes(2) + self.bkheader.mac_address)[0], 'files': [file.metadata() for file in self.files]} + +# +------------------------------+ +# | Save file patching functions | +# +------------------------------+ + + +def find_zeldaTp_idx(save_bin: SaveBin): + idx = -1 + for i in range(len(save_bin.files)): + file = save_bin.files[i] + if file.path == "zeldaTp.dat": + idx = i + return idx if idx > -1 else None + + +def update_checksum(data: bytes, fileNumber: int): + data = bytearray(data) + + offsetFile0 = (fileNumber - 1) * 0xA94 + 0x8 + offsetFile1 = offsetFile0 + 0x2000 + + def patchFilesU32(offset: int, value: int): + data[offsetFile0 + offset:offsetFile0 + + offset + 4] = struct.pack('>I', value) + data[offsetFile1 + offset:offsetFile1 + + offset + 4] = struct.pack('>I', value) + + dataFieldSize = 0xA8C + + dataFieldSum = 0 + for i in range(dataFieldSize): + dataFieldSum = ctypes.c_uint32( + dataFieldSum + data[offsetFile0 + i]).value + + # Patch in checksums. + patchFilesU32(0xA8C, dataFieldSum) + patchFilesU32( + 0xA90, ctypes.c_uint32(-(dataFieldSum + dataFieldSize)).value) + + return bytes(data) + + +def patch_file(data: bytes, fileNumber: int, version: str, rel_name: str = "mod.rel", bin_data_version='1', file_name=None): + data = bytearray(data) + + offsetFile0 = (fileNumber - 1) * 0xA94 + 0x8 + offsetFile1 = offsetFile0 + 0x2000 + + def patchFilesU16(offset: int, value: int): + data[offsetFile0 + offset:offsetFile0 + + offset + 2] = struct.pack('>H', value) + data[offsetFile1 + offset:offsetFile1 + + offset + 2] = struct.pack('>H', value) + + def patchFilesU32(offset: int, value: int): + data[offsetFile0 + offset:offsetFile0 + + offset + 4] = struct.pack('>I', value) + data[offsetFile1 + offset:offsetFile1 + + offset + 4] = struct.pack('>I', value) + + def patchFilesU64(offset: int, value: int): + data[offsetFile0 + offset:offsetFile0 + + offset + 8] = struct.pack('>Q', value) + data[offsetFile1 + offset:offsetFile1 + + offset + 8] = struct.pack('>Q', value) + + def patchFilesS64(offset: int, value: int): + data[offsetFile0 + offset:offsetFile0 + + offset + 8] = struct.pack('>q', value) + data[offsetFile1 + offset:offsetFile1 + + offset + 8] = struct.pack('>q', value) + + def patchFilesBytes(offset: int, value: bytes): + data[offsetFile0 + offset:offsetFile0 + offset + len(value)] = value + data[offsetFile1 + offset:offsetFile1 + offset + len(value)] = value + + # Set the last save time to the current date (as a kind of build date) + ticks = (datetime.now(timezone.utc).replace(tzinfo=None) - datetime(2000, 1, 1) + ).total_seconds() * (OS_BUS_CLOCK / 4) + patchFilesS64(0x28, int(ticks)) + + # Write the new file name (Link's name). + if file_name is None: + file_name = b'REL Loader v' + bytes(bin_data_version, 'utf-8') + else: + file_name = bytes(file_name, 'utf-8') + patchFilesBytes(0x1B4, file_name + b'\0') + + # Overwrite the next stage string with a bunch of filler 3s. + patchFilesBytes(0x58, b"3" * 0x12) + + # Write the pointer to the pointer to the init ASM function. + patchFilesU32(0x6A, GAME_INFO_PTR[version] + 0x1CC - 0xBC) + + # Write the pointer to the init ASM function. + patchFilesU32(0x1CC, GAME_INFO_PTR[version] + 0x1E4) + + # Write the init ASM function. + patchFilesBytes(0x1E4, BIN_DATA_INIT[version]) + + # Write the main ASM function. + patchFilesBytes( + 0x1E4 + len(BIN_DATA_INIT[version]), BIN_DATA_MAIN[bin_data_version][version] + bytes(rel_name, 'utf-8') + b'\x00') + + return update_checksum(data, fileNumber) + + +def generate_zeldaTp(save_bin: SaveBin): + data = bytes(0x4000) + for i in range(1, 4): + data = update_checksum(data, i) + save_bin.add_file("zeldaTp.dat", data, 0x34, 0, NodeType.FILE) + +# +-------------+ +# | Main script | +# +-------------+ + +def main(): + + # Function definitions used in the argument parser + # (shouldn't be defined in the root scope, since there + # is no need to make them available when imported as library) + + def parseFileNumber(string): + val = int(string) + if val < 1 or val > 3: + raise argparse.ArgumentTypeError( + "File number can only have integer values between 1 and 3") + return val + + + def parseFileName(string): + if len(string) > 12: + raise argparse.ArgumentTypeError( + f"File name is too long (12 characters max; got {len(string)})") + return string + + + def parseSaveFileName(string): + if len(string) > 31: + raise argparse.ArgumentTypeError( + f"File path is too long (31 characters max; got {len(string)})") + return string + + + def directoryPathParser(string): + if os.path.exists(string): + if os.path.isfile(string): + raise argparse.ArgumentTypeError( + "The output has to be an existing directory or a new directory; Got a file") + return string + + + def filePathParser(string): + if os.path.exists(string): + if not os.path.isfile(string): + raise argparse.ArgumentTypeError( + "The output has to be a file; Got a directory") + return string + + file_map_parser_re = re.compile("^([^\\:]*?)\\:([^\\:]*?)$") + def fileMapParser(string): + m = file_map_parser_re.match(string) + if not m: + raise argparse.ArgumentTypeError(f'"{string}" is not a valid mapping') + if len(m.group(2)) > 31: + raise argparse.ArgumentTypeError( + f"File path is too long (31 characters max; got {len(m.group(2))})") + return string + + class NameMapping: + def __init__(self, old, new): + self.old = old + self.new = new + + @staticmethod + def parse(string): + m = file_map_parser_re.match(string) + return NameMapping(m.group(1), m.group(2)) + + # Functions only used in the main function + # (shouldn't be defined in the root scope, since there + # is no need to make them available when imported as library) + + def updateMetaData(save_bin: SaveBin, meta: Dict[str, Any]): + save_bin.header.tid = meta["tid"] if "tid" in meta else save_bin.header.tid + save_bin.header.permissions = meta["permissions"] if "permissions" in meta else save_bin.header.permissions + save_bin.bkheader.ngid = meta["ngid"] if "ngid" in meta else save_bin.bkheader.ngid + save_bin.bkheader.mac_address = struct.pack(">Q", meta["mac_address"])[ + 2:] if "mac_address" in meta else save_bin.bkheader.mac_address + if "files" in meta: + for i in range(len(save_bin.files)): + try: + idx = [file["path"] + for file in meta["files"]].index(save_bin.files[i].path) + save_bin.files[i].attributes = meta["files"][idx]["attributes"] if "attributes" in meta["files"][idx] else save_bin.files[i].attributes + save_bin.files[i].mode = meta["files"][idx]["mode"] if "mode" in meta["files"][idx] else save_bin.files[i].mode + save_bin.files[i].node_type = meta["files"][idx]["type"] if "type" in meta["files"][idx] else save_bin.files[i].node_type + except ValueError as err: + continue + + + parser = argparse.ArgumentParser( + sys.argv[0], description="Tool to pack/unpack Wii saves & inject REL modules.") + parser.add_argument("-v", "--verbose", action="count", + help="increase verbosity of the output", default=1) + parser.add_argument("-q", "--quiet", action="store_true", + help="prevents output to the console", default=False) + parser.add_argument("-V", "--version", action="version", version=VERSION) + subparsers = parser.add_subparsers( + dest="command", metavar="command", help="Available commands are: generate, inject, patch, unpack, pack, meta, banner, files") + # Generate + gen_parser = subparsers.add_parser( + "generate", description="Generate a new save file", help="Generate a new save file") + gen_parser.add_argument("-i", "--index", action="append", type=parseFileNumber, + help="file number to inject the custom rel into (1 to 3)") + gen_parser.add_argument("-n", "--name", type=parseFileName, + help="overwrite the name of the internal REL file that will be loaded", default="mod.rel") + gen_parser.add_argument("rel", type=argparse.FileType( + 'rb'), help="Path to the REL module to pack") + gen_parser.add_argument("banner", type=argparse.FileType( + 'rb'), help="Path to the banner of the game") + gen_parser.add_argument( + "out", type=str, help="Path where to write the generated save file") + gen_parser.add_argument("-g", "--game-version", choices=[ + "us0", "us2", "eu", "jp"], help="Version to generate the save for", required=True) + gen_parser.add_argument("-m", "--meta", type=argparse.FileType("r"), + help="Metadata to use for the save file") + gen_parser.add_argument("--get-meta", type=argparse.FileType('w'), + help="Extract the medatada of the generated save") + gen_parser.add_argument("-l", "--loader-version", choices=[ + '1', '2'], help="Choose which version of the loader to put in the save file", default='1') + gen_parser.add_argument("-f", "--file-name", type=parseSaveFileName, + help="The player name in the save file (31 character max)", default=None) + # Inject + inj_parser = subparsers.add_parser( + "inject", description="Injects into an existing save file", help="Injects into an existing save file") + inj_parser.add_argument("-i", "--index", action="append", type=parseFileNumber, + help="file number to inject the custom rel into (1 to 3)") + inj_parser.add_argument("-n", "--name", type=parseFileName, + help="overwrite the name of the internal REL file that will be loaded", default="mod.rel") + inj_parser.add_argument("rel", type=argparse.FileType( + 'rb'), help="Path to the REL module to pack") + inj_parser.add_argument("save", type=argparse.FileType( + 'rb'), help="Save file to inject into") + inj_parser.add_argument( + "out", type=str, help="Path where to write the generated save file") + inj_parser.add_argument( + "-g", "--game-version", choices=["us0", "us2", "eu", "jp"], help="Version of the save file") + inj_parser.add_argument("-m", "--meta", type=argparse.FileType("r"), + help="Overwrite the metadata using the provided file") + inj_parser.add_argument("--get-meta", type=argparse.FileType('w'), + help="Extract the medatada of the generated save") + inj_parser.add_argument( + "-b", "--banner", type=argparse.FileType("rb"), help="Overwrite the banner") + inj_parser.add_argument("-l", "--loader-version", choices=[ + '1', '2'], help="Choose which version of the loader to put in the save file", default='1') + inj_parser.add_argument("-f", "--file-name", type=parseSaveFileName, + help="The player name in the save file (31 character max)", default=None) + # Patch + patch_parser = subparsers.add_parser( + "patch", description="Patches a zeldaTp.dat file", help="Patches a zeldaTp.dat file") + patch_parser.add_argument("-i", "--index", action="append", type=parseFileNumber, + help="file number to inject the custom rel into (1 to 3)") + patch_parser.add_argument("-n", "--name", type=parseFileName, + help="overwrite the name of the internal REL file that will be loaded", default="mod.rel") + patch_parser.add_argument("file", type=argparse.FileType( + 'rb'), help="The zeldaTp.dat file to patch") + patch_parser.add_argument( + "out", type=str, help="Where to write the patched file") + patch_parser.add_argument("-g", "--game-version", choices=[ + "us0", "us2", "eu", "jp"], help="Version to generate the save for", required=True) + patch_parser.add_argument("-l", "--loader-version", choices=[ + '1', '2'], help="Choose which version of the loader to put in the save file", default='2') + patch_parser.add_argument("-f", "--file-name", type=parseSaveFileName, + help="The player name in the save file (31 character max)", default=None) + # Unpack + unpack_parser = subparsers.add_parser( + "unpack", description="Unpacks a save into a directory", help="Unpacks a save into a directory") + unpack_parser.add_argument("save", type=argparse.FileType( + 'rb'), help="Path to the save file to unpack") + unpack_parser.add_argument("out_dir", type=directoryPathParser, + help="Path to the directory to unpack the save into") + unpack_parser.add_argument("--get-meta", type=argparse.FileType('w'), + help="Extract the medatada of the generated save") + # Pack + pack_parser = subparsers.add_parser( + "pack", description="Packs a folder into a new save file", help="Packs data files into a new save file") + pack_parser.add_argument("out_path", type=argparse.FileType( + 'wb'), help="Where to write the packed save") + pack_parser.add_argument("header", type=argparse.FileType( + 'rb'), help='Path to "header.bin"') + pack_parser.add_argument("bkheader", type=argparse.FileType( + 'rb'), help='Path to "bkheader.bin"') + pack_parser.add_argument("files", metavar="file", type=argparse.FileType( + 'rb'), nargs="*", help="Any file you want to pack in the save") + pack_parser.add_argument( + "-m", "--meta", type=argparse.FileType("r"), help="Metadata to use for the save file") + pack_parser.add_argument("--get-meta", type=argparse.FileType('w'), + help="Extract the medatada of the generated save") + # Meta + meta_parser = subparsers.add_parser( + "meta", description="Extract metadata from a save file", help="Extract metadata from a save file") + meta_parser.add_argument("save", type=argparse.FileType( + 'rb'), help="Save file to extract the metadata from") + meta_parser.add_argument("out", type=argparse.FileType( + 'w'), help="Path the the file where to write the metadata (JSON format)") + # Banner + banner_parser = subparsers.add_parser( + "banner", description="Extract banner from save file", help="Extract banner from save file") + banner_parser.add_argument("save", type=argparse.FileType( + 'rb'), help="Path to the save file to unpack") + banner_parser.add_argument("out", type=filePathParser, + help="Path to the file to store the banner into") + # Files + files_parser = subparsers.add_parser( + "files", description="Operations on the file inside the save.", help="Operations on the file inside the save.") + files_subparser = files_parser.add_subparsers( + dest="files_cmd", metavar="CMD", help="Available commands are: add, list, rm", required=True) + # Files; Add + files_add_parser = files_subparser.add_parser( + "add", description="Adds file(s) to a save", help="Adds file(s) to a save") + files_add_parser.add_argument( + "save", type=argparse.FileType('rb'), metavar="", help="Path to the save file") + files_add_parser.add_argument("-o", "--output", nargs='?', type=argparse.FileType( + 'wb'), default=None, help="Path to where to store the result (default: overwrites 'save')") + files_add_parser.add_argument( + "-M", "--map", action="extend", nargs='*', type=fileMapParser, help="Map a file name to an other one") + files_add_parser.add_argument("file", type=argparse.FileType( + 'rb'), nargs="+", metavar="", help="Path to the file(s) to add to the save") + # Files; List + files_list_parser = files_subparser.add_parser( + "list", description="Lists the file(s) within a given save", help="Lists the files within a given save") + files_list_parser.add_argument("save", type=argparse.FileType( + 'rb'), metavar="", help="Path to the save file") + # Files; Remove + files_rm_parser = files_subparser.add_parser( + "rm", description="Removes the file(s) within the save", help="Removes the file(s) within the save") + files_rm_parser.add_argument("save", type=argparse.FileType( + 'rb'), metavar="", help="Path to the save file") + files_rm_parser.add_argument("-o", "--output", nargs='?', type=argparse.FileType( + 'wb'), default=None, help="Path to where to store the result (default: overwrites 'save')") + files_rm_parser.add_argument( + "file", type=str, nargs="+", metavar="", help="Name of the file(s) to remove from the save") + # Help + help_parser = subparsers.add_parser( + "help", description="Get a help guide for a command", help="Get a help guide for a command") + help_parser.add_argument("cmd", choices=[ + "generate", "inject", "pack", "unpack", "patch", "meta", "banner", "files", "help"], help="A command you need help with", nargs='?') + + args = parser.parse_args() + + # Phase 1: Extract the simple options and check if it's only looking for a help text. + + if not "command" in args or args.command is None: + parser.print_help() + sys.exit(0) + + parsers = {"generate": gen_parser, "inject": inj_parser, "patch": patch_parser, + "pack": pack_parser, "unpack": unpack_parser, "help": help_parser, "meta": meta_parser, "banner": banner_parser, "files": files_parser} + + if args.command == "help": + if not args.cmd is None: + parsers[args.cmd].print_help() + else: + parser.print_help() + sys.exit(0) + + verbosity = args.verbose if not args.quiet else 0 + + LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] + loglevel = LEVELS[min(max(4 - verbosity, 0), 4)] + + numeric_level = getattr(logging, loglevel.upper(), logging.CRITICAL) + logging.basicConfig( + level=numeric_level, format="[%(levelname)s]\t[%(asctime)s]\t%(pathname)s:%(lineno)d %(funcName)s: %(message)s") + + mappings = {} + if args.command == "files" and args.files_cmd == "add": + if args.map is None: + args.map = [] + for m in args.map: + mapping = NameMapping.parse(m) + logging.info(f"parsed mapping '{mapping.old}' to '{mapping.new}'") + mappings[mapping.old] = mapping.new + + # Phase 2: Load files and data/options + + # Phase 2.1: Load and/or generate the Save File (if needed) + save_bin = None + if args.command in ["inject", "unpack", "meta", "banner", "files"]: + # We need to fetch the save_bin from a provided file + with args.save as save: + if args.command == "inject": + prefix_len = len(os.path.commonprefix( + [args.rel.name, save.name])) + logging.info( + f"injecting '{'.../' if prefix_len > 0 else ''}{args.rel.name[prefix_len:]}' into '{'.../' if prefix_len > 0 else ''}{args.save.name[prefix_len:]}'") + save_bin = SaveBin.from_file(save) + if save_bin is None: + logging.error("Could not parse save file") + sys.exit(1) + logging.info("Loaded SaveBin") + logging.debug(f"{save_bin}") + elif args.command == "generate": + # We need to generate a new save_bin + logging.info("Generating new save file") + with args.banner as banner: + save_bin = SaveBin.generate(banner, args.game_version) + generate_zeldaTp(save_bin) + logging.debug(f"{save_bin}") + elif args.command in ["pack", "patch"]: + # We don't need any save file + pass + else: + logging.error(f'Error: command not supported {args.command!a}') + sys.exit(1) + + # Phase 2.2: Make sure we have a valid file index to put the loader into (if needed) + + if args.command in ["inject", "generate", "patch"]: + # We need to make sure we have the index of the file to patch the loader into. Default is file 3 + if args.index is None: + logging.info("No file index provided, defaulting to 3") + args.index = [3] + + # Phase 2.3: Load and process the rel file (if needed) + + rel_bin = None + if args.command in ["inject", "generate"]: + # Load the rel file + with args.rel as rel: + rel_bin = rel.read() + + # Phase 3: Execute the command and save the results + + if args.command in ["inject", "generate"]: + # Inject the rel into the save_bin + args.out = open(args.out, 'wb') + if args.game_version is None: + if not save_bin.header.tid in TIDS.keys(): + logging.error( + "Error: Game version unrecognized, please provide the --game-version option.") + sys.exit(1) + args.game_version = TIDS[save_bin.header.tid] + logging.info( + f'Game ID: {save_bin.header.tid >> 32:08x}-{struct.pack(">I", save_bin.header.tid & 0xffffffff).decode()}') + save_bin.add_file(args.name, rel_bin) + zeldaTp_idx = find_zeldaTp_idx(save_bin) + if not zeldaTp_idx is None: + for file_idx in args.index: + save_bin.files[zeldaTp_idx].data = bytes( + patch_file(save_bin.files[zeldaTp_idx].data, file_idx, args.game_version, args.name, args.loader_version, args.file_name)) + else: + logging.error( + 'Error: no "zeldaTp.dat" file in the save archive') + sys.exit(1) + + if "meta" in args and not args.meta is None: + meta = json.load(args.meta) + args.meta.close() + updateMetaData(save_bin, meta) + + if not args.get_meta is None: + json.dump(save_bin.config(), args.get_meta, + sort_keys=True, indent=4) + args.get_meta.close() + + logging.debug(f"Produced SaveBin: {save_bin}") + + save_bin.to_file(args.out) + elif args.command == "unpack": + path = os.path.realpath(args.out_dir) + if not os.path.exists(path): + os.mkdir(path) + header_file = open(args.out_dir + os.path.sep + "header.bin", 'wb') + header_file.write(save_bin.header.pack()) + header_file.close() + bkheader_file = open(args.out_dir + os.path.sep + "bkheader.bin", 'wb') + bkheader_file.write(save_bin.bkheader.pack()) + bkheader_file.close() + for file in save_bin.files: + file_handle = open(args.out_dir + os.path.sep + file.path, 'wb') + file_handle.write(file.data) + file_handle.close() + + if not args.get_meta is None: + json.dump(save_bin.config(), args.get_meta, + sort_keys=True, indent=4) + args.get_meta.close() + elif args.command == "pack": + header = Header.unpack(args.header.read()) + bkheader = BkHeader.unpack(args.bkheader.read()) + args.header.close() + args.bkheader.close() + save_bin = SaveBin(header, bkheader, []) + save_bin._update_bk_files() + for file in args.files: + save_bin.add_file(os.path.basename(file.name), + file.read(), node_type=NodeType.FILE) + file.close() + + if "meta" in args and not args.meta is None: + meta = json.load(args.meta) + args.meta.close() + updateMetaData(save_bin, meta) + + if not args.get_meta is None: + json.dump(save_bin.config(), args.get_meta, + sort_keys=True, indent=4) + args.get_meta.close() + + logging.debug(f"Generated SaveBin: {save_bin}") + # Recalculate the checksums + zeldaTp_idx = find_zeldaTp_idx(save_bin) + if zeldaTp_idx is not None: + data = save_bin.files[zeldaTp_idx].data + for i in range(1, 4): + data = update_checksum(data, i) + save_bin.files[zeldaTp_idx].data = data + save_bin.to_file(args.out_path) + elif args.command == "patch": + if args.game_version is None: + logging.error( + "Error: Game version required, please provide it through the --game-version option.") + sys.exit(1) + zeldaTp_data = args.file.read() + args.file.close() + if len(zeldaTp_data) != 0x4000: + logging.error( + f"Error: wrong file size (0x{len(zeldaTp_data):08x}; expected 0x4000)") + sys.exit(1) + for file_idx in args.index: + zeldaTp_data = bytes(patch_file( + zeldaTp_data, file_idx, args.game_version, args.name, args.loader_version, args.file_name)) + out = open(args.out, 'wb') + out.write(zeldaTp_data) + out.close() + elif args.command == "banner": + out = open(args.out, 'wb') + out.write(save_bin.header.banner) + out.close() + elif args.command == "meta": + json.dump(save_bin.config(), args.out, sort_keys=True, indent=4) + elif args.command == "files": + if args.files_cmd == "add": + file_path = args.save.name + for file in args.file: + file_name = file.name + logging.info(f"Loading '{file_name}'...") + with file as f: + file_data = f.read() + logging.debug(f"Adding '{file_name}'...") + if file_name in mappings.keys(): + file_name = mappings.get(file_name) + logging.debug(f"(Mapped to '{file_name}')") + save_bin.add_file(file_name, file_data) + if args.output is None: + logging.info( + f"No output file provided, overwritting input save") + logging.debug(f"({file_path})") + with open(file_path, 'wb') as f: + save_bin.to_file(f) + else: + with args.output as out: + save_bin.to_file(out) + elif args.files_cmd == "list": + print("id\ttype\tmode\tattr\tpath") + for i, file in enumerate(save_bin.files): + print( + f"#{i:04d}\t{file.node_type.name[:1].upper() + file.node_type.name.lower()[1:]}\t{file.mode}\t{file.attributes}\t{file.path}") + elif args.files_cmd == "rm": + file_path = args.save.name + for file in args.file: + save_bin.rm_file(file) + if args.output is None: + logging.info( + f"No output file provided, overwritting input save") + logging.debug(f"({file_path})") + with open(file_path, 'wb') as f: + save_bin.to_file(f) + else: + with args.output as out: + save_bin.to_file(out) + # TODO Add a command to edit a file's properties. + else: + raise ValueError( + f"'{args.files_cmd}' is not a recognized 'files' command.") + + +if __name__ == "__main__": + main() diff --git a/modules/boot/include/gz_flags.h b/modules/boot/include/gz_flags.h index 4ba3e4a0..a17ec2e7 100644 --- a/modules/boot/include/gz_flags.h +++ b/modules/boot/include/gz_flags.h @@ -32,6 +32,8 @@ enum GZFlags { GZFLG_FREEZE_TIME, GZFLG_DISABLE_BGM, GZFLG_DISABLE_SFX, + GZFLG_LFC, + GZFLG_EE, }; struct GZFlag { diff --git a/modules/boot/include/menus/menu.h b/modules/boot/include/menus/menu.h index f7e872a4..d8bc5e9e 100644 --- a/modules/boot/include/menus/menu.h +++ b/modules/boot/include/menus/menu.h @@ -38,12 +38,17 @@ enum MenuIndex { MN_GENERAL_FLAGS_INDEX, MN_DUNGEON_FLAGS_INDEX, MN_PORTAL_FLAGS_INDEX, + MN_RUPEE_FLAGS_INDEX, MN_FLAG_RECORDS_INDEX, MN_FLAG_LOG_INDEX, // Inventory menu's sub menus MN_ITEM_WHELL_INDEX, MN_PAUSE_INDEX, MN_AMOUNTS_INDEX, + // Pause menu's sub menus + MN_EQUIPMENT_INDEX, + MN_GOLDEN_BUGS_INDEX, + MN_HIDDEN_SKILLS_INDEX, // Memory menu's sub menus MN_WATCHES_INDEX, MN_MEMORY_EDITOR_INDEX, @@ -61,10 +66,17 @@ enum MenuIndex { MN_COLLISION_VIEW_INDEX, MN_PROJECTION_VIEW_INDEX, MN_TRIGGER_VIEW_INDEX, + MN_SOUND_TEST_INDEX, // Setting menu's sub menus MN_POS_SETTINGS_INDEX, MN_CREDITS_INDEX, MN_COMBO_INDEX, + // Tools menu's sub menus + MN_TOOLS_CHECKERS_INDEX, + MN_TOOLS_CONTROLLER_INDEX, + MN_TOOLS_LINK_INDEX, + MN_TOOLS_SCENE_INDEX, + MN_TOOLS_TIMERS_INDEX, // This entry is used only to get a count of the number of valid entries. MN_COUNT diff --git a/modules/boot/include/modules.h b/modules/boot/include/modules.h index 1c0f7b0e..179ea2d5 100644 --- a/modules/boot/include/modules.h +++ b/modules/boot/include/modules.h @@ -22,6 +22,8 @@ bool umd_active(); bool bit_active(); #endif bool corotd_active(); +bool lfc_active(); +bool ee_active(); bool mash_checker_active(); bool gorge_active(); bool rollcheck_active(); diff --git a/modules/boot/include/pos_settings.h b/modules/boot/include/pos_settings.h index d0b12069..35a54898 100644 --- a/modules/boot/include/pos_settings.h +++ b/modules/boot/include/pos_settings.h @@ -3,11 +3,12 @@ #include "settings.h" #include "libtp_c/include/dolphin/mtx/vec.h" -#define SPRITES_AMNT 10 +#define SPRITES_AMNT 11 enum SpritesIndex { MENU_INDEX, VIEWER_INDEX, DEBUG_INFO_INDEX, + STAGE_INFO_INDEX, TIMER_SPR_INDEX, LOAD_TIMER_SPR_INDEX, IGT_TIMER_SPR_INDEX, diff --git a/modules/boot/include/practice.h b/modules/boot/include/practice.h index d9a2e613..c8583883 100644 --- a/modules/boot/include/practice.h +++ b/modules/boot/include/practice.h @@ -4,9 +4,7 @@ enum { ANY_INDEX, -#ifdef GCN_PLATFORM ANY_BITE_INDEX, -#endif HUNDO_INDEX, AD_INDEX, #ifdef GCN_PLATFORM diff --git a/modules/boot/include/save_manager.h b/modules/boot/include/save_manager.h index 0eec1fc9..0674d84a 100644 --- a/modules/boot/include/save_manager.h +++ b/modules/boot/include/save_manager.h @@ -81,12 +81,9 @@ class SaveManager { AreaReload mAreaReloadOpts; special* mSpecials; bool loading_initiated = false; - int repeat_count = 0; - bool repeat_during = false; static bool s_injectSave; static bool s_injectMemfile; - static s8 s_applyAfterTimer; public: static void injectSave(void* buffer); diff --git a/modules/boot/include/save_specials.h b/modules/boot/include/save_specials.h index 68f9caac..ec412588 100644 --- a/modules/boot/include/save_specials.h +++ b/modules/boot/include/save_specials.h @@ -14,6 +14,11 @@ void SaveMngSpecial_PurpleMist(); void SaveMngSpecial_KargOoB(); void SaveMngSpecial_WaterfallSidehop(); +void SaveMngSpecial_EarlyEle(); + +void SaveMngSpecial_HorseSpawn(); +void SaveMngSpecial_EldinCollection(); + void SaveMngSpecial_KB2Skip(); void SaveMngSpecial_Escort(); void SaveMngSpecial_EscortKeys(); diff --git a/modules/boot/include/scene.h b/modules/boot/include/scene.h index 111e6bf0..24cabadb 100644 --- a/modules/boot/include/scene.h +++ b/modules/boot/include/scene.h @@ -17,6 +17,7 @@ enum SceneIndex { COLLISION_VIEW_INDEX, PROJECTION_VIEW_INDEX, TRIGGER_VIEW_INDEX, + SOUND_TEST_INDEX, SCENE_MENU_MAX }; diff --git a/modules/boot/include/settings.h b/modules/boot/include/settings.h index 9e344a38..1abe511f 100644 --- a/modules/boot/include/settings.h +++ b/modules/boot/include/settings.h @@ -103,6 +103,11 @@ enum GZSettingID : uint32_t { STNG_CMD_BIT, // Wii only, but we reserve the id anyway STNG_CMD_GORGE_VOID, STNG_CMD_MOON_JUMP, + // New Adds + STNG_TOOLS_LFC, + STNG_TOOLS_ELEVATOR_ESCAPE, + STNG_TOOLS_STAGE_INFO, + STNG_SPRITES_STAGE_INFO, }; struct GZSettingEntry { diff --git a/modules/boot/include/tools.h b/modules/boot/include/tools.h index d4333a50..5b0d6b79 100644 --- a/modules/boot/include/tools.h +++ b/modules/boot/include/tools.h @@ -1,30 +1,11 @@ #pragma once enum ToolsIndex { - RELOAD_AREA_INDEX, - FRAME_ADVANCE_INDEX, - FAST_BONK_INDEX, - FAST_MOVEMENT_INDEX, - GORGE_INDEX, -#ifdef WII_PLATFORM - BIT_INDEX, -#endif - COROTD_INDEX, - UMD_INDEX, - INPUT_VIEWER_INDEX, - LINK_DEBUG_INDEX, - HEAP_DEBUG_INDEX, - SAND_INDEX, - ROLL_INDEX, - MASH_CHECKER_INDEX, - TELEPORT_INDEX, - TURBO_MODE_INDEX, - TIMER_INDEX, - LOAD_TIMER_INDEX, - IGT_TIMER_INDEX, - FREE_CAM_INDEX, - MOVE_LINK_INDEX, - TUNIC_COLOR_INDEX, + CHECKERS_INDEX, + CONTROLLER_INDEX, + LINK_INDEX, + SCENE_INDEX, + TIMERS_INDEX, // Entry used as a counter TOOLS_COUNT diff --git a/modules/boot/include/trigger_view.h b/modules/boot/include/trigger_view.h index e6da4840..4ce22548 100644 --- a/modules/boot/include/trigger_view.h +++ b/modules/boot/include/trigger_view.h @@ -13,6 +13,7 @@ enum TriggerViewIndex { VIEW_SWITCH_AREAS, VIEW_TRANSFORM_DISTS, VIEW_TW_GATES, + VIEW_LEEVER_RANGE, TRIGGER_VIEW_MAX, }; diff --git a/modules/boot/include/utils/lines.h b/modules/boot/include/utils/lines.h index 0a9ae932..a3d104fe 100644 --- a/modules/boot/include/utils/lines.h +++ b/modules/boot/include/utils/lines.h @@ -17,7 +17,7 @@ struct ListMember { struct Line { char line[50]; - const uint32_t idx; + uint32_t idx; char description[MAX_DESCRIPTION_LENGTH]; bool toggleable = false; bool (*active)(); diff --git a/modules/boot/include/utils/link.h b/modules/boot/include/utils/link.h index 29f6a440..127c583a 100644 --- a/modules/boot/include/utils/link.h +++ b/modules/boot/include/utils/link.h @@ -2,5 +2,6 @@ #include "font.h" void GZ_displayLinkInfo(); +void GZ_displayStageInfo(); void GZ_setTunicColor(); \ No newline at end of file diff --git a/modules/boot/src/global_data.cpp b/modules/boot/src/global_data.cpp index 51018a17..5b77a095 100644 --- a/modules/boot/src/global_data.cpp +++ b/modules/boot/src/global_data.cpp @@ -23,6 +23,7 @@ KEEP_VAR TriggerViewItem g_triggerViewFlags[TRIGGER_VIEW_MAX] = { {VIEW_TRANSFORM_DISTS, false}, {VIEW_ATTN_DISTS, false}, {VIEW_MIST_AVOID, false}, + {VIEW_LEEVER_RANGE, false}, }; KEEP_VAR ProjectionLine g_ljaProjectionLine; diff --git a/modules/boot/src/gz_flags.cpp b/modules/boot/src/gz_flags.cpp index 3dc8228e..65c33369 100644 --- a/modules/boot/src/gz_flags.cpp +++ b/modules/boot/src/gz_flags.cpp @@ -118,14 +118,12 @@ void GZ_execute(int phase) { } } - // Timer set after dScnPly__phase_4, delay until objects are fully loaded - if (!fopScnRq.isLoading && SaveManager::s_applyAfterTimer > 0) { - SaveManager::s_applyAfterTimer--; - } else if (SaveManager::s_applyAfterTimer == 0) { + // Check for post load callback and run it once link is valid + if (!fopScnRq.isLoading && dComIfGp_getPlayer()) { if (gSaveManager.mPracticeFileOpts.inject_options_after_load) { gSaveManager.mPracticeFileOpts.inject_options_after_load(); + gSaveManager.mPracticeFileOpts.inject_options_after_load = nullptr; } - SaveManager::s_applyAfterTimer = -1; } // normally oxygen doesn't get set until going to the file select screen diff --git a/modules/boot/src/menus/menu.cpp b/modules/boot/src/menus/menu.cpp index 0dcde5ed..882e4427 100644 --- a/modules/boot/src/menus/menu.cpp +++ b/modules/boot/src/menus/menu.cpp @@ -3,18 +3,22 @@ // This array must correspond to the order of the MenuIndex enum. const char* g_menuPaths[MN_COUNT] = { - "main", "cheats", "flags", - "inventory", "memory", "practice", - "scene", "settings", "tools", - "warp", "general_flags", "dungeon_flags", - "portal_flags", "flag_records", "flag_log", - "item_wheel", "pause", "amounts", - "watches", "memory_editor", "memfiles", - "any_saves", "any_bite_saves", "hundo_saves", - "ad_saves", "nosq_saves", "glitchless_saves", - "actor_spawn", "actor_list", "collision_view", - "projection_view", "trigger_view", "pos_settings", - "credits", "combo" + "main", "cheats", "flags", + "inventory", "memory", "practice", + "scene", "settings", "tools", + "warp", "general_flags", "dungeon_flags", + "portal_flags", "rupee_flags", "flag_records", + "flag_log", "item_wheel", "pause", + "amounts", "equipment", "golden_bugs", + "hidden_skills", + "watches", "memory_editor", "memfiles", + "any_saves", "any_bite_saves", "hundo_saves", + "ad_saves", "nosq_saves", "glitchless_saves", + "actor_spawn", "actor_list", "collision_view", + "projection_view", "trigger_view", "sound_test", + "pos_settings", "credits", "combo", + "tools_checkers", "tools_controller", "tools_link", + "tools_scene", "tools_timers" }; KEEP_FUNC Menu::Menu(Cursor& cursor) : cursor(cursor) {} \ No newline at end of file diff --git a/modules/boot/src/modules.cpp b/modules/boot/src/modules.cpp index 75f042b9..c4151795 100644 --- a/modules/boot/src/modules.cpp +++ b/modules/boot/src/modules.cpp @@ -72,6 +72,14 @@ KEEP_FUNC bool corotd_active() { return GZStng_getData(STNG_TOOLS_COROTD, false); } +KEEP_FUNC bool lfc_active() { + return GZStng_getData(STNG_TOOLS_LFC, false); +} + +KEEP_FUNC bool ee_active() { + return GZStng_getData(STNG_TOOLS_ELEVATOR_ESCAPE, false); +} + KEEP_FUNC bool mash_checker_active() { return GZStng_getData(STNG_TOOLS_MASH_CHECKER, false); } diff --git a/modules/boot/src/save_manager.cpp b/modules/boot/src/save_manager.cpp index ca916304..7a8c380d 100644 --- a/modules/boot/src/save_manager.cpp +++ b/modules/boot/src/save_manager.cpp @@ -20,7 +20,6 @@ SaveManager gSaveManager; KEEP_VAR bool SaveManager::s_injectSave = false; KEEP_VAR bool SaveManager::s_injectMemfile = false; -KEEP_VAR s8 SaveManager::s_applyAfterTimer = -1; void SaveManager::injectSave(void* buffer) { memcpy(&g_dComIfG_gameInfo, buffer, 0x9F8); diff --git a/modules/boot/src/save_specials.cpp b/modules/boot/src/save_specials.cpp index f187bab1..8735f7fd 100644 --- a/modules/boot/src/save_specials.cpp +++ b/modules/boot/src/save_specials.cpp @@ -110,6 +110,21 @@ KEEP_FUNC void SaveMngSpecial_WaterfallSidehop() { g_dComIfG_gameInfo.info.mRestart.mLastSpeedF = 10.0f; // link spawns swimming forward } +KEEP_FUNC void SaveMngSpecial_EarlyEle() { + gSaveManager.injectDefault_during(); + dComIfGs_onTmpBit(0x0002); +} + +KEEP_FUNC void SaveMngSpecial_HorseSpawn() { + gSaveManager.injectDefault_during(); + g_dComIfG_gameInfo.info.mRestart.mLastMode = 1; // spawn on epona +} + +KEEP_FUNC void SaveMngSpecial_EldinCollection() { + SaveMngSpecial_HorseSpawn(); + g_dComIfG_gameInfo.info.mRestart.mLastSpeedF = 42.0f; +} + KEEP_FUNC void SaveMngSpecial_KB2Skip() { gSaveManager.injectDefault_during(); setNextStageLayer(3); @@ -182,12 +197,11 @@ KEEP_FUNC void SaveMngSpecial_Stallord() { } KEEP_FUNC void SaveMngSpecial_Stallord2() { - gSaveManager.mPracticeFileOpts.inject_options_after_counter = 20; - daB_DS_c* stallord = (daB_DS_c*)fopAcM_SearchByName(PROC_B_DS); + // create the phase 2 version of stallord fopAcM_create(PROC_B_DS, fopAcM_GetParam(stallord) | 2, &stallord->current.pos, - fopAcM_GetRoomNo(stallord), nullptr, nullptr, -1); + fopAcM_GetRoomNo(stallord), nullptr, nullptr, -1); fopAcM_delete(stallord); // delete phase 1 stallord daObjLv4Wall_c* rwall = (daObjLv4Wall_c*)fopAcM_SearchByName(PROC_Obj_Lv4RailWall); @@ -199,9 +213,6 @@ KEEP_FUNC void SaveMngSpecial_Stallord2() { } KEEP_FUNC void SaveMngSpecial_Stallord2_init() { - gSaveManager.repeat_during = true; - gSaveManager.repeat_count = 120; - gSaveManager.injectDefault_during(); g_dComIfG_gameInfo.info.mZone[0].mBit.mSwitch[0] |= 0x300000; // turn off intro cs, start fight setNextStagePoint(1); // spawn at in front of stally @@ -235,8 +246,8 @@ KEEP_FUNC void SaveMngSpecial_HugoArchery() { KEEP_FUNC void SaveMngSpecial_CityPoeCycle() { gSaveManager.injectDefault_during(); - gSaveManager.setSaveAngle(71); - gSaveManager.setSavePosition(-14005.31f, 3000.0f, -15854.05f); + gSaveManager.setSaveAngle(0); + gSaveManager.setSavePosition(-13990.0f, 3000.0f, -16200.0f); gSaveManager.setLinkInfo(); } diff --git a/modules/boot/src/utils/card.cpp b/modules/boot/src/utils/card.cpp index 67da2e20..4fa39441 100644 --- a/modules/boot/src/utils/card.cpp +++ b/modules/boot/src/utils/card.cpp @@ -36,18 +36,27 @@ int32_t GZ_storageWrite(Storage* storage, void* data, int32_t size, int32_t offs int32_t read_bytes = 0; while (result == Ready && size > 0) { - StorageRead(*storage, buf, sector_size, (offset & ~(sector_size - 1))); - if (result != Ready) { + OSReport("GZ_storageWrite: Writing 0x%x bytes to offset 0x%x\n", MIN(size, sector_size), offset); + StorageSeek(storage, (offset & ~(sector_size - 1)), STORAGE_SEEK_BEG); + StorageRead(*storage, buf, sector_size); + if (storage->result != Ready) { + result = IoError; break; } int32_t rem_size = sector_size - (offset & (sector_size - 1)); memcpy(buf + (offset & (sector_size - 1)), (void*)((uint32_t)data + read_bytes), MIN(rem_size, size)); - StorageWrite(*storage, buf, sector_size, (offset & ~(sector_size - 1))); + StorageSeek(storage, (offset & ~(sector_size - 1)), STORAGE_SEEK_BEG); + StorageWrite(*storage, buf, sector_size); + if (storage->result != Ready) { + result = IoError; + break; + } read_bytes += MIN(rem_size, size); size -= rem_size; offset += rem_size; } + OSReport("GZ_storageWrite: Done Writing\n"); delete[] buf; return result; } @@ -62,7 +71,8 @@ int32_t GZ_storageRead(Storage* storage, void* data, int32_t size, int32_t offse int32_t read_bytes = 0; while (result == Ready && size > 0) { - StorageRead(*storage, buf, sector_size, (offset & ~(sector_size - 1))); + StorageSeek(storage, (offset & ~(sector_size - 1)), STORAGE_SEEK_BEG); + StorageRead(*storage, buf, sector_size); if (result != Ready) { break; } @@ -244,7 +254,11 @@ KEEP_FUNC void GZ_storeMemfile(Storage& storage) { posData.cam.target = matrixInfo.matrix_info->target; posData.cam.pos = matrixInfo.matrix_info->pos; posData.angle = dComIfGp_getPlayer()->shape_angle.y; - uint32_t file_size = (uint32_t)(ceil((double)sizeof(dSv_info_c) / (double)storage.sector_size) * + OSReport("GZ_storeMemfile: position: {%f, %f, %f}\n", posData.link.x, posData.link.y, posData.link.z); + OSReport("GZ_storeMemfile: angle: %f\n", posData.angle); + OSReport("GZ_storeMemfile: cam target: {%f, %f, %f}\n", posData.cam.target.x, posData.cam.target.y, posData.cam.target.z); + OSReport("GZ_storeMemfile: cam pos: {%f, %f, %f}\n", posData.cam.pos.x, posData.cam.pos.y, posData.cam.pos.z); + uint32_t file_size = (uint32_t)(ceil((double)(sizeof(dSv_info_c) + 1 + sizeof(PositionData)) / (double)storage.sector_size) * storage.sector_size); storage.result = StorageDelete(0, storage.file_name_buffer); @@ -258,10 +272,13 @@ KEEP_FUNC void GZ_storeMemfile(Storage& storage) { setReturnPlace(g_dComIfG_gameInfo.play.mStartStage.mStage, g_dComIfG_gameInfo.play.mEvent.field_0x12c, 0); - storage.result = GZ_storageWrite(&storage, &g_dComIfG_gameInfo, sizeof(dSv_info_c), 0, + uint8_t* data = new (-32) uint8_t[sizeof(dSv_info_c) + 1 + sizeof(PositionData)]; + memcpy(data, &g_dComIfG_gameInfo, sizeof(dSv_info_c)); + memcpy(&data[sizeof(dSv_info_c) + 1], &posData, sizeof(PositionData)); + storage.result = GZ_storageWrite(&storage, data, sizeof(dSv_info_c) + 1 + sizeof(PositionData), 0, storage.sector_size); - storage.result = GZ_storageWrite(&storage, &posData, sizeof(posData), - sizeof(dSv_info_c) + 1, storage.sector_size); + OSReport("GZ_storeMemfile: data write result: %d\n", storage.result); + delete[] data; if (storage.result == Ready) { FIFOQueue::push("saved memfile!", Queue); } else { @@ -332,7 +349,13 @@ KEEP_FUNC void GZ_loadMemfile(Storage& storage) { storage.result = StorageOpen(0, storage.file_name_buffer, &storage.info, OPEN_MODE_RW); if (storage.result == Ready) { PositionData posData; + OSReport("GZ_loadMemfile: reading position data at 0x%x\n", sizeof(dSv_info_c) + 1); storage.result = GZ_readMemfile(&storage, posData, storage.sector_size); + OSReport("GZ_loadMemfile: result: %d\n", storage.result); + OSReport("GZ_loadMemfile: position: {%f, %f, %f}\n", posData.link.x, posData.link.y, posData.link.z); + OSReport("GZ_loadMemfile: angle: %f\n", posData.angle); + OSReport("GZ_loadMemfile: cam target: {%f, %f, %f}\n", posData.cam.target.x, posData.cam.target.y, posData.cam.target.z); + OSReport("GZ_loadMemfile: cam pos: {%f, %f, %f}\n", posData.cam.pos.x, posData.cam.pos.y, posData.cam.pos.z); if (storage.result == Ready) { FIFOQueue::push("loaded memfile!", Queue); SaveManager::injectDefault_before(); diff --git a/modules/boot/src/utils/hook.cpp b/modules/boot/src/utils/hook.cpp index 397ac53b..5779829e 100644 --- a/modules/boot/src/utils/hook.cpp +++ b/modules/boot/src/utils/hook.cpp @@ -18,6 +18,7 @@ #include "collision_view.h" #include "features/projection_view/include/projection_view.h" #include "libtp_c/include/m_Do/m_Do_printf.h" +#include "libtp_c/include/d/s/d_s_logo.h" #define HOOK_DEF(rettype, name, params) \ typedef rettype(*tp_##name##_t) params; \ @@ -51,7 +52,6 @@ HOOK_DEF(void, dCcS__draw, (dCcS*)); HOOK_DEF(void, BeforeOfPaint, (void)); HOOK_DEF(void, dCcS__MoveAfterCheck, (dCcS*)); - HOOK_DEF(int, dScnPly__phase_1, (void*)); HOOK_DEF(int, dScnPly__phase_4, (void*)); @@ -59,6 +59,14 @@ HOOK_DEF(void, dBgS_Acch__CrrPos, (dBgS_Acch*, dBgS&)); HOOK_DEF(void, daAlink_c__setCutJumpSpeed, (daAlink_c*, int)); HOOK_DEF(void, daAlink_c__posMove, (daAlink_c*)); +#ifdef WII_PLATFORM +HOOK_DEF(void, dScnLogo_c__create, (dScnLogo_c*)); +HOOK_DEF(void, dScnLogo_c__dvdWaitDraw, (dScnLogo_c*)); +HOOK_DEF(int, mDoGph_gInf_c__startFadeOut, (int)); +#else +HOOK_DEF(void, dScnLogo_c__warningInDraw, (dScnLogo_c*)); +#endif + namespace Hook { void gameLoopHook(void) { game_loop(); @@ -74,9 +82,9 @@ void drawHook(void* p1) { #ifdef PR_TEST void myExceptionCallbackHook(void) { ExceptionCallbackTrampoline(); - gzCrashAddr = 1; - DCFlushRange((void*)(&gzCrashAddr), sizeof(gzCrashAddr)); - ICInvalidateRange((void*)(&gzCrashAddr), sizeof(gzCrashAddr)); + gzCrashReport = 1; + DCFlushRange((void*)(&gzCrashReport), sizeof(gzCrashReport)); + ICInvalidateRange((void*)(&gzCrashReport), sizeof(gzCrashReport)); } #endif // PR_TEST @@ -151,6 +159,8 @@ void onSwitchHook(void* addr, int pFlag, int i_roomNo) { if (g_flagLogEnabled) { if (pFlag < 0x80) { snprintf(buf, sizeof(buf), "%s[%d] : %d | ON", "Memory Switch", tmp >> 5, tmp & 0x1F); + OSReport("pFlag: %d\n", pFlag); + OSReport("roomNo: %d\n", i_roomNo); } else if (pFlag < 0xC0) { tmp -= 0x80; snprintf(buf, sizeof(buf), "%s[%d] : %d | ON", "Dan Switch", tmp >> 5, tmp & 0x1F); @@ -189,10 +199,6 @@ int endSaveInjectHook(void* i_scene) { int rt = dScnPly__phase_4Trampoline(i_scene); if (SaveManager::s_injectSave || SaveManager::s_injectMemfile) { - if (gSaveManager.mPracticeFileOpts.inject_options_after_load) { - SaveManager::s_applyAfterTimer = 5; - } - SaveManager::s_injectSave = false; SaveManager::s_injectMemfile = false; } @@ -228,6 +234,28 @@ void daAlink_c__setCutJumpSpeedHook(daAlink_c* i_this, int i_air) { daAlink_c__setCutJumpSpeedTrampoline(i_this, i_air); } +#ifdef WII_PLATFORM +// Skip intro logos (Wii) +void dScnLogo_c__create(dScnLogo_c* i_this) { + dScnLogo_c__createTrampoline(i_this); + i_this->mExecCommand = dScnLogo_c::EXEC_DVD_WAIT; +} + +int mDoGph_gInf_c__startFadeOut(int i) { + return mDoGph_gInf_c__startFadeOutTrampoline(i); +} + +void dScnLogo_c__dvdWaitDraw(dScnLogo_c* i_this) { + dScnLogo_c__dvdWaitDrawTrampoline(i_this); +} + +#else +// Skip intro logos (GCN) +void dScnLogo_c__warningInDraw(dScnLogo_c* i_this) { + i_this->mExecCommand = dScnLogo_c::EXEC_DVD_WAIT; +} +#endif + void setupLJAProjectionLine(daAlink_c* i_this) { bool got_it = false; @@ -392,12 +420,16 @@ void daAlink_c__posMoveHook(daAlink_c* i_this) { #define f_myExceptionCallback myExceptionCallback_unsigned #define f_dScnPly__phase_1 phase_1_dScnPly_c___ #define f_dScnPly__phase_4 phase_4_dScnPly_c___ +#define f_dScnLogo_c__warningInDraw dScnLogo_c__warningInDraw_void_ #define f_dCcS__Draw dCcS__Draw_void_ #define f_dScnPly_BeforeOfPaint mDoGph_BeforeOfDraw_void_ #define f_dCcS__MoveAfterCheck dCcS__MoveAfterCheck_void_ #define f_dBgS_Acch__CrrPos dBgS_Acch__CrrPos_dBgS___ #define f_daAlink_c__setCutJumpSpeed daAlink_c__setCutJumpSpeed_int_ #define f_daAlink_c__posMove daAlink_c__posMove_void_ +#define f_dScnLogo_c__create dScnLogo_c__create_void_ +#define f_dScnLogo_c__dvdWaitDraw dScnLogo_c__dvdWaitDraw_void_ +#define f_mDoGph_gInf_c__startFadeOut mDoGph_gInf_c__startFadeOut_int_ #else #define draw_console draw__17JUTConsoleManagerCFv #define f_fapGm_Execute fapGm_Execute__Fv @@ -412,6 +444,7 @@ void daAlink_c__posMoveHook(daAlink_c* i_this) { #define f_myExceptionCallback myExceptionCallback__FUsP9OSContextUlUl #define f_dScnPly__phase_1 phase_1__FP9dScnPly_c #define f_dScnPly__phase_4 phase_4__FP9dScnPly_c +#define f_dScnLogo_c__warningInDraw warningInDraw__10dScnLogo_cFv #define f_dCcS__Draw Draw__4dCcSFv #define f_dScnPly_BeforeOfPaint dScnPly_BeforeOfPaint__Fv #define f_dCcS__MoveAfterCheck MoveAfterCheck__4dCcSFv @@ -441,6 +474,13 @@ void f_dCcS__MoveAfterCheck(dCcS*); void f_dBgS_Acch__CrrPos(dBgS_Acch*, dBgS&); void f_daAlink_c__setCutJumpSpeed(daAlink_c*, int); void f_daAlink_c__posMove(daAlink_c*); +#ifdef WII_PLATFORM +void f_dScnLogo_c__create(dScnLogo_c*); +void f_dScnLogo_c__dvdWaitDraw(dScnLogo_c*); +void f_mDoGph_gInf_c__startFadeOut(int); +#else +void f_dScnLogo_c__warningInDraw(dScnLogo_c*); +#endif } KEEP_FUNC void applyHooks() { @@ -468,6 +508,14 @@ KEEP_FUNC void applyHooks() { APPLY_HOOK(daAlink_c__setCutJumpSpeed, &f_daAlink_c__setCutJumpSpeed, daAlink_c__setCutJumpSpeedHook); APPLY_HOOK(daAlink_c__posMove, &f_daAlink_c__posMove, daAlink_c__posMoveHook); +#ifdef WII_PLATFORM + APPLY_HOOK(dScnLogo_c__create, &f_dScnLogo_c__create, dScnLogo_c__create); + APPLY_HOOK(dScnLogo_c__dvdWaitDraw, &f_dScnLogo_c__dvdWaitDraw, dScnLogo_c__dvdWaitDraw); + APPLY_HOOK(mDoGph_gInf_c__startFadeOut, &f_mDoGph_gInf_c__startFadeOut, mDoGph_gInf_c__startFadeOut); +#else +APPLY_HOOK(dScnLogo_c__warningInDraw, &f_dScnLogo_c__warningInDraw, dScnLogo_c__warningInDraw); +#endif + #ifdef PR_TEST APPLY_HOOK(ExceptionCallback, &f_myExceptionCallback, myExceptionCallbackHook); #endif diff --git a/modules/boot/src/utils/link.cpp b/modules/boot/src/utils/link.cpp index 9b494596..51371e80 100644 --- a/modules/boot/src/utils/link.cpp +++ b/modules/boot/src/utils/link.cpp @@ -24,6 +24,7 @@ KEEP_FUNC void GZ_displayLinkInfo() { char link_x[22]; char link_y[22]; char link_z[22]; + char link_action[22]; snprintf(link_angle, sizeof(link_angle), "angle: %d", (uint16_t)dComIfGp_getPlayer()->shape_angle.y); @@ -32,6 +33,8 @@ KEEP_FUNC void GZ_displayLinkInfo() { snprintf(link_x, sizeof(link_x), "x-pos: %.4f", dComIfGp_getPlayer()->current.pos.x); snprintf(link_y, sizeof(link_y), "y-pos: %.4f", dComIfGp_getPlayer()->current.pos.y); snprintf(link_z, sizeof(link_z), "z-pos: %.4f", dComIfGp_getPlayer()->current.pos.z); + snprintf(link_action, sizeof(link_action), "action: %d", dComIfGp_getPlayer()->mActionID); + Font::GZ_drawStr(link_angle, spriteOffset.x, spriteOffset.y + 20.0f, 0xFFFFFFFF, @@ -51,6 +54,9 @@ KEEP_FUNC void GZ_displayLinkInfo() { Font::GZ_drawStr(link_z, spriteOffset.x, spriteOffset.y + 120.0f, 0xFFFFFFFF, GZ_checkDropShadows()); + Font::GZ_drawStr(link_action, spriteOffset.x, + spriteOffset.y + 140.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); } else { Font::GZ_drawStr("angle: n/a", spriteOffset.x, spriteOffset.y + 20.0f, 0xFFFFFFFF, @@ -70,9 +76,62 @@ KEEP_FUNC void GZ_displayLinkInfo() { Font::GZ_drawStr("z-pos: n/a", spriteOffset.x, spriteOffset.y + 120.0f, 0xFFFFFFFF, GZ_checkDropShadows()); + Font::GZ_drawStr("action: n/a", spriteOffset.x, + spriteOffset.y + 140.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); } } +KEEP_FUNC void GZ_displayStageInfo() { + if (!GZStng_getData(STNG_TOOLS_STAGE_INFO, false)) { + return; + } + + Vec2 spriteOffset = GZ_getSpriteOffset(STNG_SPRITES_STAGE_INFO); + + char cur_stage[15]; + char cur_room[10]; + char cur_point[11]; + char cur_layer[10]; + + snprintf(cur_stage, sizeof(cur_stage), "Stage: %s", g_dComIfG_gameInfo.play.mStartStage.mStage); + snprintf(cur_room, sizeof(cur_room), "Room: %d", dStage_roomControl_c__mStayNo); + snprintf(cur_point, sizeof(cur_point), "Point: %d", g_dComIfG_gameInfo.play.mStartStage.mPoint); + snprintf(cur_layer, sizeof(cur_layer), "Layer: %d", dComIfG_play_c__getLayerNo(0)); + + Font::GZ_drawStr(cur_stage, spriteOffset.x, + spriteOffset.y + 20.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + Font::GZ_drawStr(cur_room, spriteOffset.x, + spriteOffset.y + 40.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + Font::GZ_drawStr(cur_point, spriteOffset.x, + spriteOffset.y + 60.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + Font::GZ_drawStr(cur_layer, spriteOffset.x, + spriteOffset.y + 80.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + + + char save_stage[20]; + char save_room[15]; + char save_point[16]; + + snprintf(save_stage, sizeof(save_stage), "Save Stage: %s", g_dComIfG_gameInfo.info.getPlayer().getPlayerReturnPlace().mName); + snprintf(save_room, sizeof(save_room), "Save Room: %d", g_dComIfG_gameInfo.info.getPlayer().getPlayerReturnPlace().mRoomNo); + snprintf(save_point, sizeof(save_point), "Save Point: %d", g_dComIfG_gameInfo.info.getPlayer().getPlayerReturnPlace().mPlayerStatus); + + Font::GZ_drawStr(save_stage, spriteOffset.x + 150.0f, + spriteOffset.y + 20.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + Font::GZ_drawStr(save_room, spriteOffset.x + 150.0f, + spriteOffset.y + 40.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); + Font::GZ_drawStr(save_point, spriteOffset.x + 150.0f, + spriteOffset.y + 60.0f, 0xFFFFFFFF, + GZ_checkDropShadows()); +} + KEEP_FUNC void GZ_setTunicColor() { static int16_t cycle_r = 0; static int16_t cycle_g = 0; diff --git a/modules/features/ee_checker/CMakeLists.txt b/modules/features/ee_checker/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/features/ee_checker/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/features/ee_checker/include/ee_checker.h b/modules/features/ee_checker/include/ee_checker.h new file mode 100644 index 00000000..c2c7ac00 --- /dev/null +++ b/modules/features/ee_checker/include/ee_checker.h @@ -0,0 +1,5 @@ +#pragma once + +namespace EEChecker { +void execute(); +} // namespace EEChecker \ No newline at end of file diff --git a/modules/features/ee_checker/include/main.h b/modules/features/ee_checker/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/features/ee_checker/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/features/ee_checker/src/ee_checker.cpp b/modules/features/ee_checker/src/ee_checker.cpp new file mode 100644 index 00000000..5e702494 --- /dev/null +++ b/modules/features/ee_checker/src/ee_checker.cpp @@ -0,0 +1,108 @@ +#include "ee_checker.h" +#include "controller.h" +#include "fifo_queue.h" +#include +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/f_op/f_op_actor_mng.h" +#include "libtp_c/include/m_Do/m_Do_printf.h" +#include "libtp_c/include/d/d_procname.h" +#include "libtp_c/include/SSystem/SComponent/c_counter.h" + +u16 previous_action; // Tracks the previous action for adjusting the frame timing window, because some actions like land dive cut the beginning of the roll short +bool game_paused; // Whether the game is paused or not. Used to determine if the roll start frame should be incremented. +char msg_buffer[20]; // Buffer for the message to be printed. +s32 early_roll_frame; +s32 late_roll_frame; +s32 target_frame; +const u8 metamorphose_anm_length = 56; // length of the metamorphose animation in frames +s32 metamorphose_start_frame; // frame that the metamorphose animation starts on + +void checkRollFrame(daAlink_c* link) { + switch (link->mActionID) { + case daAlink_c::PROC_TALK: + previous_action = daAlink_c::PROC_TALK; + break; + case daAlink_c::PROC_METAMORPHOSE: + if (previous_action == daAlink_c::PROC_TALK) { + metamorphose_start_frame = cCt_getFrameCount(); + } + +#if DEBUG + OSReport("previous action: %d\n", previous_action); + OSReport("metamorphose start frame: %d\n", metamorphose_start_frame); + OSReport("Current metamorphose frame: %d\n", (cCt_getFrameCount() - metamorphose_start_frame)); +#endif + + if (GZ_getButtonPressed(A) && !GZ_getButtonHold(A)) { + early_roll_frame = cCt_getFrameCount(); + snprintf(msg_buffer, sizeof(msg_buffer), "early by %df", metamorphose_anm_length - (cCt_getFrameCount() - metamorphose_start_frame)); + FIFOQueue::push(msg_buffer, Queue, 0x0000CC00); + } + + previous_action = daAlink_c::PROC_METAMORPHOSE; + break; + + case daAlink_c::PROC_WAIT: + late_roll_frame = 0; + target_frame = cCt_getFrameCount(); + break; + case daAlink_c::PROC_MOVE: + case daAlink_c::PROC_WAIT_TURN: + case daAlink_c::PROC_MOVE_TURN: + if (GZ_getButtonPressed(A) && !GZ_getButtonHold(A)) { + late_roll_frame = cCt_getFrameCount(); + } + break; + case daAlink_c::PROC_FRONT_ROLL: +#if DEBUG + OSReport("Front roll, last action: %d\n", previous_action); + OSReport("Early roll frame: %d\n", early_roll_frame); + OSReport("Late roll frame: %d\n", late_roll_frame); +#endif + if (late_roll_frame == 0 && previous_action != daAlink_c::PROC_FRONT_ROLL) { + FIFOQueue::push("<3", Queue, 0x00CC0000); + } else if (previous_action != daAlink_c::PROC_FRONT_ROLL) { + snprintf(msg_buffer, sizeof(msg_buffer), "late by %df", late_roll_frame - target_frame); + FIFOQueue::push(msg_buffer, Queue, 0xCC000000); + } + + previous_action = daAlink_c::PROC_FRONT_ROLL; + break; + default: + early_roll_frame = 0; + late_roll_frame = 0; + } +} + +KEEP_FUNC void EEChecker::execute() { + // Retrieve player pointer + daAlink_c* link = dComIfGp_getPlayer(); + + // Early return if player pointer is invalid + if (!link) { + return; + } + + if (!daAlink_c__checkStageName("R_SP110")) { +#if DEBUG + OSReport("Player is not in goron elder room\n"); +#endif + return; + } + + if (link->current.pos.x > -1400.0f || link->current.pos.x < -1600.0f) { +#if DEBUG + OSReport("Player is not in the correct x position\n"); + return; +#endif + } + + if (link->current.pos.z < 4000.0f || link->current.pos.z > 4400.0f) { +#if DEBUG + OSReport("Player is not in the correct z position\n"); + return; +#endif + } + + checkRollFrame(link); +} \ No newline at end of file diff --git a/modules/features/ee_checker/src/main.cpp b/modules/features/ee_checker/src/main.cpp new file mode 100644 index 00000000..5ca0ec16 --- /dev/null +++ b/modules/features/ee_checker/src/main.cpp @@ -0,0 +1,15 @@ +#include +#include "gz_flags.h" +#include "ee_checker.h" + +namespace tpgz::modules { +void main() { + GZFlg_addFlag( + new GZFlag{GZFLG_EE, ACTIVE_FUNC(STNG_TOOLS_ELEVATOR_ESCAPE), GAME_LOOP, EEChecker::execute}); +} +void exit() { + auto* flg = GZFlg_removeFlag(GZFLG_EE); + delete flg; +} + +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/features/lfc_checker/CMakeLists.txt b/modules/features/lfc_checker/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/features/lfc_checker/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/features/lfc_checker/include/lfc_checker.h b/modules/features/lfc_checker/include/lfc_checker.h new file mode 100644 index 00000000..462c1b03 --- /dev/null +++ b/modules/features/lfc_checker/include/lfc_checker.h @@ -0,0 +1,5 @@ +#pragma once + +namespace LFCChecker { +void execute(); +} // namespace LFCChecker \ No newline at end of file diff --git a/modules/features/lfc_checker/include/main.h b/modules/features/lfc_checker/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/features/lfc_checker/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/features/lfc_checker/src/lfc_checker.cpp b/modules/features/lfc_checker/src/lfc_checker.cpp new file mode 100644 index 00000000..4746432e --- /dev/null +++ b/modules/features/lfc_checker/src/lfc_checker.cpp @@ -0,0 +1,213 @@ +#include "lfc_checker.h" +#include "controller.h" +#include "fifo_queue.h" +#include +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/f_op/f_op_actor_mng.h" +#include "libtp_c/include/m_Do/m_Do_printf.h" +#include "libtp_c/include/d/d_procname.h" +#include "libtp_c/include/SSystem/SComponent/c_counter.h" + +enum Phase { + LADDER_START, + LADDER_DURING, + LADDER_DURING_2, + LADDER_DROP, + LADDER_DROP_2, + LADDER_REGRAB +}; + +u8 phase = Phase::LADDER_START; +int frameDelta = 0; +s32 drop_1_start_frame; // The frame the first drop started on. +s32 drop_2_start_frame; // The frame the second drop started on. +bool game_paused; + +static void* searchLadderFreezard(void* i_actor, void* i_data) { + const float LADDER_FREEZARD_Y_POS = 950.0f; + + if (fopAcM_GetName(i_actor) == PROC_E_FB && static_cast(i_actor)->current.pos.y == LADDER_FREEZARD_Y_POS) { + return i_actor; + } + + return NULL; +} + +void checkOnLadder(daAlink_c* link) { + u16 current_action = link->mActionID; + + if (current_action == daAlink_c::PROC_LADDER_UP_START || + current_action == daAlink_c::PROC_LADDER_UP_END || + current_action == daAlink_c::PROC_LADDER_DOWN_START || + current_action == daAlink_c::PROC_LADDER_DOWN_END || + current_action == daAlink_c::PROC_LADDER_MOVE) { + if (phase == Phase::LADDER_START) { + phase = Phase::LADDER_DURING; + } else if (phase == Phase::LADDER_DROP) { + phase = Phase::LADDER_DURING_2; + } else { + phase = Phase::LADDER_REGRAB; + } + } else if (phase != Phase::LADDER_DROP) { + phase = Phase::LADDER_START; + } +} + +void checkFirstDrop(daAlink_c* link) { + if (link->mActionID == daAlink_c::PROC_FALL) { + if (link->current.pos.y < 247.0f) { + char msg[15]; + sprintf(msg, "off by -%f", 247.0f - link->current.pos.y); + FIFOQueue::push(msg, Queue, 0xFFFF0000); + phase = Phase::LADDER_START; + return; + } + + if (link->current.pos.y >= 247.0f && link->current.pos.y < 249.8f) { + FIFOQueue::push("Got it (1/2)", Queue, 0x00FF0000); + phase = Phase::LADDER_DROP; + drop_1_start_frame = cCt_getFrameCount(); + return; + } + + if (link->current.pos.y >= 249.8f) { + char msg[15]; + sprintf(msg, "off by +%f", link->current.pos.y - 249.8f); + FIFOQueue::push(msg, Queue, 0xFF000000); + phase = Phase::LADDER_START; + return; + } + } +} + +void checkSecondDrop(daAlink_c* link) { + if (link->mActionID == daAlink_c::PROC_FALL) { + drop_2_start_frame = cCt_getFrameCount(); + s32 delta = drop_2_start_frame - drop_1_start_frame; +#if DEBUG + OSReport("delta: %d\n", delta); +#endif + + + if (delta < 260 && delta >= 255) { + char msg[15]; + sprintf(msg, "early by %df", 260 - delta); + FIFOQueue::push(msg, Queue, 0x00FF0000); + phase = Phase::LADDER_DROP_2; + return; + } + + if (delta >= 260 && delta < 268) { + FIFOQueue::push("Got it (2/2)", Queue, 0x00FF0000); + phase = Phase::LADDER_REGRAB; + return; + } + + if (delta >= 268 && delta < 273) { + char msg[15]; + sprintf(msg, "late by %df", delta - 267); + FIFOQueue::push(msg, Queue, 0x00FF0000); + phase = Phase::LADDER_DROP_2; + return; + } + + if (delta >= 273) { + phase = Phase::LADDER_START; + return; + } + + } +} + +void framePauseUpdate() { + if (g_dComIfG_gameInfo.play.mPauseFlag) { +#if DEBUG + OSReport("game paused, incrementing start frame!\n"); +#endif + + drop_1_start_frame += 1; + game_paused = true; + } else { + if (game_paused) { + game_paused = false; + drop_1_start_frame++; + } + } +} + +KEEP_FUNC void LFCChecker::execute() { + // Retrieve player pointer + daAlink_c* link = dComIfGp_getPlayer(); + + // Early return if player pointer is invalid + if (!link) { + return; + } + + if (dComIfGp_getEvent().mHalt == true) { +#if DEBUG + OSReport("In event\n"); +#endif + return; + } + + if (dComIfGs_getTransformStatus() != STATUS_HUMAN) { +#if DEBUG + OSReport("Player is not in human form\n"); +#endif + return; + } + + if (!daAlink_c__checkStageName("D_MN11")) { +#if DEBUG + OSReport("Player is not in Snowpeak Ruins\n"); +#endif + return; + } + + if (fopAcM_GetRoomNo(link) != 4) { +#if DEBUG + OSReport("Player is not in courtyard\n"); +#endif + return; + } + + fopAc_ac_c* ladder_freezard = (fopAc_ac_c*)fpcEx_Search(searchLadderFreezard, nullptr); + + if (!ladder_freezard) { +#if DEBUG + OSReport("Ladder Freezard not found\n"); +#endif + return; + } + + switch(phase) { + case Phase::LADDER_START: + OSReport("Checking for link on ladder 1\n"); + checkOnLadder(link); + break; + case Phase::LADDER_DURING: + OSReport("Checking for first drop\n"); + checkFirstDrop(link); + break; + case Phase::LADDER_DROP: + OSReport("Checking for link on ladder 2\n"); + checkOnLadder(link); + framePauseUpdate(); + break; + case Phase::LADDER_DURING_2: + OSReport("Checking for second drop\n"); + framePauseUpdate(); + checkSecondDrop(link); + break; + case Phase::LADDER_DROP_2: + OSReport("Checking for link on ladder 3\n"); + checkOnLadder(link); + break; + case Phase::LADDER_REGRAB: + OSReport("Finished!\n"); + default: + phase = Phase::LADDER_START; + break; + } +} \ No newline at end of file diff --git a/modules/features/lfc_checker/src/main.cpp b/modules/features/lfc_checker/src/main.cpp new file mode 100644 index 00000000..bf81595c --- /dev/null +++ b/modules/features/lfc_checker/src/main.cpp @@ -0,0 +1,15 @@ +#include +#include "gz_flags.h" +#include "lfc_checker.h" + +namespace tpgz::modules { +void main() { + GZFlg_addFlag( + new GZFlag{GZFLG_LFC, ACTIVE_FUNC(STNG_TOOLS_LFC), GAME_LOOP, LFCChecker::execute}); +} +void exit() { + auto* flg = GZFlg_removeFlag(GZFLG_LFC); + delete flg; +} + +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/features/trigger_view/src/trigger_view.cpp b/modules/features/trigger_view/src/trigger_view.cpp index 487e6d3f..b86b1d61 100644 --- a/modules/features/trigger_view/src/trigger_view.cpp +++ b/modules/features/trigger_view/src/trigger_view.cpp @@ -368,6 +368,30 @@ void drawPurpleMistAvoid(fopAc_ac_c* actor) { dDbVw_drawCubeXlu(tag->mTargetAvoidPos, cubeSize, cubeAngle, targetColor); } +void drawLeeverData(fopAc_ac_c* actor) { + struct e_rb_class : public fopAc_ac_c { + u8 data[0xA66 - 0x568]; + /* 0xA66 */ u8 mIsChild; + /* 0xA67 */ u8 field_0xa67; + /* 0xA68 */ u8 mAppearRange; + /* 0xA69 */ u8 mDisappearRange; + }; + e_rb_class* leever = (e_rb_class*)actor; + + if (!leever->mIsChild) { + GXColor color = {0xFF, 0x00, 0x00, g_geometryOpacity}; + GXColor color2 = {0x00, 0x00, 0xFF, g_geometryOpacity}; + + cXyz pos(leever->current.pos); + if (pos.y < dComIfGp_getPlayer()->mLinkAcch.GetGroundH()) { + pos.y = dComIfGp_getPlayer()->mLinkAcch.GetGroundH() + 100.0f; + } + + dDbVw_drawCircleXlu(pos, leever->mAppearRange * 100.0f, color, 1, 20); + dDbVw_drawCircleXlu(pos, leever->mDisappearRange * 100.0f, color2, 1, 20); + } +} + KEEP_FUNC void execute() { if (g_triggerViewFlags[VIEW_LOAD_ZONES].active) { searchActorForCallback(PROC_SCENE_EXIT, drawSceneExit); @@ -413,5 +437,9 @@ KEEP_FUNC void execute() { if (g_triggerViewFlags[VIEW_MIST_AVOID].active) { searchActorForCallback(PROC_KYTAG08, drawPurpleMistAvoid); } + + if (g_triggerViewFlags[VIEW_LEEVER_RANGE].active) { + searchActorForCallback(PROC_E_RB, drawLeeverData); + } } } // namespace TriggerViewer \ No newline at end of file diff --git a/modules/init/src/main.cpp b/modules/init/src/main.cpp index fa0aa878..89e1cf5c 100644 --- a/modules/init/src/main.cpp +++ b/modules/init/src/main.cpp @@ -45,6 +45,7 @@ void main() { g_drawListener->addListener(GZ_renderMenuTitle); g_drawListener->addListener(GZ_renderFifoQueue); g_drawListener->addListener(GZ_displayLinkInfo); + g_drawListener->addListener(GZ_displayStageInfo); g_drawListener->addListener(GZ_drawHeapInfo); g_drawListener->addListener(Timer::drawTimer); g_drawListener->addListener(Timer::drawLoadTimer); @@ -67,6 +68,8 @@ void main() { g_modules.push_back(new Module{bit_active, "/tpgz/rels/features/bit.rel"}); #endif g_modules.push_back(new Module{corotd_active, "/tpgz/rels/features/corotd.rel"}); + g_modules.push_back(new Module{lfc_active, "/tpgz/rels/features/lfc_checker.rel"}); + g_modules.push_back(new Module{ee_active, "/tpgz/rels/features/ee_checker.rel"}); g_modules.push_back(new Module{mash_checker_active, "/tpgz/rels/features/mash_checker.rel"}); g_modules.push_back(new Module{gorge_active, "/tpgz/rels/features/gorge.rel"}); g_modules.push_back(new Module{rollcheck_active, "/tpgz/rels/features/rollcheck.rel"}); @@ -120,6 +123,7 @@ void GZ_PosSettings_initDefaults() { #endif GZStng_add(STNG_SPRITES_MENU, new Vec2{25.f, 60.f}, sizeof(Vec2)); GZStng_add(STNG_SPRITES_DEBUG_INFO, new Vec2{450.0f, 200.f}, sizeof(Vec2)); + GZStng_add(STNG_SPRITES_STAGE_INFO, new Vec2{145.0f, 350.f}, sizeof(Vec2)); GZStng_add(STNG_SPRITES_TIMER_SPR, new Vec2{450.0f, 420.f}, sizeof(Vec2)); GZStng_add(STNG_SPRITES_LOAD_TIMER_SPR, new Vec2{450.0f, 30.f}, sizeof(Vec2)); GZStng_add(STNG_SPRITES_IGT_TIMER_SPR, new Vec2{35.0f, 30.f}, sizeof(Vec2)); diff --git a/modules/menus/menu_actor_list/include/actor_list_menu.h b/modules/menus/menu_actor_list/include/actor_list_menu.h index 57c94b60..67242279 100644 --- a/modules/menus/menu_actor_list/include/actor_list_menu.h +++ b/modules/menus/menu_actor_list/include/actor_list_menu.h @@ -22,6 +22,8 @@ enum { ACTOR_ANGLE_X_INDEX, ACTOR_ANGLE_Y_INDEX, ACTOR_ANGLE_Z_INDEX, + ACTOR_ADDRESS_INDEX, + ACTOR_PROC_INDEX, ACTOR_PARAMS_INDEX, ACTOR_LIST_LINE_COUNT, @@ -36,7 +38,7 @@ class ActorListMenu : public Menu { private: void updateActorData(); template - void updateValue(T* value, f32 smallChange, f32 largeChange, bool increase, bool largeIncrement); + void updateValue(T*, bool); void loadActorName(); void checkAndCloseMenu(); void checkAndRestoreMenu(); diff --git a/modules/menus/menu_actor_list/src/actor_list_menu.cpp b/modules/menus/menu_actor_list/src/actor_list_menu.cpp index bf506391..8b1501b5 100644 --- a/modules/menus/menu_actor_list/src/actor_list_menu.cpp +++ b/modules/menus/menu_actor_list/src/actor_list_menu.cpp @@ -19,20 +19,26 @@ #ifdef GCN_PLATFORM #define CONTROLLER_RIGHT GZPad::DPAD_RIGHT #define CONTROLLER_LEFT GZPad::DPAD_LEFT -#define CONTROLLER_Z GZPad::Z #define CONTROLLER_A GZPad::A -#define MEM_SWITCH_BTN GZPad::Y -#define CONTROL_TEXT "Y" +#define MEM_SWITCH_BTN GZPad::Z +#define SLOW_INC_BTN GZPad::X +#define FAST_INC_BTN GZPad::Y +#define MEM_TEXT "Z" +#define SLOW_INC_TEXT "X" +#define FAST_INC_TEXT "Y" #define DELETE_TEXT "START" #define DELETE_BUTTON GZPad::START #endif #ifdef WII_PLATFORM #define CONTROLLER_RIGHT GZPad::DPAD_RIGHT #define CONTROLLER_LEFT GZPad::DPAD_LEFT -#define CONTROLLER_Z GZPad::Z #define CONTROLLER_A GZPad::A -#define MEM_SWITCH_BTN GZPad::C -#define CONTROL_TEXT "C" +#define MEM_SWITCH_BTN GZPad::ONE +#define SLOW_INC_BTN GZPad::Z +#define FAST_INC_BTN GZPad::C +#define MEM_TEXT "1" +#define SLOW_INC_TEXT "Z" +#define FAST_INC_TEXT "C" #define DELETE_TEXT "PLUS" #define DELETE_BUTTON GZPad::PLUS #endif @@ -42,99 +48,12 @@ */ procBinData l_procData; -void ring_close_proc_wrapper(void* arg) { - dMw_c__ring_close_proc(arg); -} - -void collect_close_proc_wrapper(void* arg) { - dMw_c__collect_close_proc(arg); -} - -void dmap_close_proc_wrapper(void* arg) { - dMw_c__dmap_close_proc(arg); -} - -void fmap_close_proc_wrapper(void* arg) { - dMw_c__fmap_close_proc(arg); -} - -void collect_save_close_proc_wrapper(void* arg) { - dMw_c__collect_save_close_proc(arg); -} - -void collect_option_close_proc_wrapper(void* arg) { - dMw_c__collect_option_close_proc(arg); -} - -void collect_letter_close_proc_wrapper(void* arg) { - dMw_c__collect_letter_close_proc(arg); -} - -void collect_fishing_close_proc_wrapper(void* arg) { - dMw_c__collect_fishing_close_proc(arg); -} - -void collect_skill_close_proc_wrapper(void* arg) { - dMw_c__collect_skill_close_proc(arg); -} - -void collect_insect_close_proc_wrapper(void* arg) { - dMw_c__collect_insect_close_proc(arg); -} - -void insect_close_proc_wrapper(void* arg) { - dMw_c__insect_close_proc(arg); -} - -typedef void (*procFunc)(void*); -procFunc move_proc[] = { - NULL, - NULL, - ring_close_proc_wrapper, - NULL, - NULL, - collect_close_proc_wrapper, - NULL, - NULL, - fmap_close_proc_wrapper, - NULL, - NULL, - dmap_close_proc_wrapper, - NULL, - NULL, - collect_save_close_proc_wrapper, - NULL, - NULL, - collect_option_close_proc_wrapper, - NULL, - NULL, - collect_letter_close_proc_wrapper, - NULL, - NULL, - collect_fishing_close_proc_wrapper, - NULL, - NULL, - collect_skill_close_proc_wrapper, - NULL, - NULL, - collect_insect_close_proc_wrapper, - NULL, - NULL, - NULL, - insect_close_proc_wrapper -}; - /** * @brief Checks and closes any menu that's currently open. * * @details This function is used to close any menu that's currently open. * It stores the current menu status and then closes the menu by setting the status to none and running the currently open menu's closer function via move_proc function table. * - * @note Currently the function won't catch if the menu status is in opening or closing status (two statuses during menu transitions). It will only catch the "move" status. - * We may have to account for this later. - * - * @note The move_proc function table already exists in code. We can probably just map directly to it in the future instead of defining our own. - * */ void ActorListMenu::checkAndCloseMenu() { if (g_meter2_info.mMenuWindowClass) { @@ -142,22 +61,14 @@ void ActorListMenu::checkAndCloseMenu() { case dMw_c::NO_MENU: g_dComIfG_gameInfo.play.mPauseFlag = false; break; - case dMw_c::RING_MOVE: - case dMw_c::COLLECT_MOVE: - case dMw_c::DMAP_MOVE: - case dMw_c::FMAP_MOVE: - case dMw_c::SAVE_MOVE: - case dMw_c::OPTIONS_MOVE: - case dMw_c::LETTER_MOVE: - case dMw_c::FISHING_MOVE: - case dMw_c::SKILL_MOVE: - case dMw_c::INSECT_MOVE: - case dMw_c::INSECT_AGITHA_MOVE: + default: l_menuStatus = g_meter2_info.mMenuWindowClass->mMenuStatus; l_windowStatus = g_meter2_info.mWindowStatus; + g_meter2_info.offMenuInForce(g_meter2_info.mMenuWindowClass->mMenuStatus); + g_meter2_info.mMenuWindowClass->mMenuStatus = dMw_c::NO_MENU; g_meter2_info.mWindowStatus = dMw_c::NO_MENU; - move_proc[g_meter2_info.mMenuWindowClass->mMenuStatus](g_meter2_info.mMenuWindowClass); g_dComIfG_gameInfo.play.mPauseFlag = false; + break; } } } @@ -175,23 +86,8 @@ void ActorListMenu::checkAndCloseMenu() { void ActorListMenu::checkAndRestoreMenu() { if (l_menuStatus != dMw_c::NO_MENU) { g_dComIfG_gameInfo.play.mPauseFlag = true; - - switch (l_menuStatus) { - case dMw_c::RING_MOVE: - case dMw_c::COLLECT_MOVE: - case dMw_c::FMAP_MOVE: - case dMw_c::SAVE_MOVE: - case dMw_c::OPTIONS_MOVE: - case dMw_c::LETTER_MOVE: - case dMw_c::FISHING_MOVE: - case dMw_c::SKILL_MOVE: - case dMw_c::INSECT_MOVE: - case dMw_c::INSECT_AGITHA_MOVE: - case dMw_c::DMAP_MOVE: - g_meter2_info.mWindowStatus = l_windowStatus; - g_meter2_info.mMenuWindowClass->mMenuStatus = l_menuStatus; - break; - } + g_meter2_info.mWindowStatus = l_windowStatus; + g_meter2_info.mMenuWindowClass->mMenuStatus = l_menuStatus; } } @@ -199,13 +95,15 @@ KEEP_FUNC ActorListMenu::ActorListMenu(Cursor& cursor, ActorListData& data) : Menu(cursor), l_index(data.l_index), lines{ - {"", ACTOR_NAME_INDEX, "Z+A: freeze actor, Z+" DELETE_TEXT ": delete actor, " CONTROL_TEXT " view memory", false}, - {"", ACTOR_POSITION_X_INDEX, "dpad: +/-10.0, Z+dpad: +/-100.0", false}, - {"", ACTOR_POSITION_Y_INDEX, "dpad: +/-10.0, Z+dpad: +/-100.0", false}, - {"", ACTOR_POSITION_Z_INDEX, "dpad: +/-10.0, Z+dpad: +/-100.0", false}, - {"", ACTOR_ANGLE_X_INDEX, "dpad: +/-10, Z+dpad: +/-100", false}, - {"", ACTOR_ANGLE_Y_INDEX, "dpad: +/-10, Z+dpad: +/-100", false}, - {"", ACTOR_ANGLE_Z_INDEX, "dpad: +/-10, Z+dpad: +/-100", false}, + {"", ACTOR_NAME_INDEX, "A: freeze actor, " DELETE_TEXT ": delete actor, " MEM_TEXT " view memory", false}, + {"", ACTOR_POSITION_X_INDEX, "dpad: +/-100.0, " SLOW_INC_TEXT "+dpad: +/-1.0, " FAST_INC_TEXT "+dpad: +/-1000.0", false}, + {"", ACTOR_POSITION_Y_INDEX, "dpad: +/-100.0, " SLOW_INC_TEXT "+dpad: +/-1.0, " FAST_INC_TEXT "+dpad: +/-1000.0", false}, + {"", ACTOR_POSITION_Z_INDEX, "dpad: +/-100.0, " SLOW_INC_TEXT "+dpad: +/-1.0, " FAST_INC_TEXT "+dpad: +/-1000.0", false}, + {"", ACTOR_ANGLE_X_INDEX, "dpad: +/-100, " SLOW_INC_TEXT "+dpad: +/-1, " FAST_INC_TEXT "+dpad: +/-1000", false}, + {"", ACTOR_ANGLE_Y_INDEX, "dpad: +/-100, " SLOW_INC_TEXT "+dpad: +/-1, " FAST_INC_TEXT "+dpad: +/-1000", false}, + {"", ACTOR_ANGLE_Z_INDEX, "dpad: +/-100, " SLOW_INC_TEXT "+dpad: +/-1, " FAST_INC_TEXT "+dpad: +/-1000", false}, + {"", ACTOR_ADDRESS_INDEX, "current actor address", false}, + {"", ACTOR_PROC_INDEX, "current actor proc id", false}, {"", ACTOR_PARAMS_INDEX, "current actor parameters", false}, } { // store camera position and target @@ -228,15 +126,18 @@ ActorListMenu::~ActorListMenu() { matrixInfo.matrix_info->pos = l_cameraPos; matrixInfo.matrix_info->target = l_cameraTarget; + // restore evt manager camera play & HUD dComIfGp_getEventManager().mCameraPlay = 0; g_drawHIO.mHUDAlpha = 1.0f; - } template -void ActorListMenu::updateValue(T* value, f32 smallChange, f32 largeChange, bool increase, bool largeIncrement) { +void ActorListMenu::updateValue(T* value, bool increase) { if (value != NULL) { - *value += (increase ? 1 : -1) * (largeIncrement ? largeChange : smallChange); + f32 change; + GZ_getButtonPressed(FAST_INC_BTN) ? change = 1000.0f : GZ_getButtonPressed(SLOW_INC_BTN) ? change = 1.0f : change = 100.0f; + + *value += (increase ? 1 : -1) * change; } } @@ -277,10 +178,7 @@ void ActorListMenu::draw() { bool rightPressed = GZ_getButtonRepeat(CONTROLLER_RIGHT,1); bool leftPressed = GZ_getButtonRepeat(CONTROLLER_LEFT,1); - bool zPressed = GZ_getButtonPressed(CONTROLLER_Z); - - f32 smallPosChange = 10.0f, largePosChange = 100.0f; - int smallAngleChange = 100, largeAngleChange = 1000; + switch (cursor.y) { case ACTOR_NAME_INDEX: @@ -302,7 +200,7 @@ void ActorListMenu::draw() { loadActorName(); } - if (GZ_getButtonPressed(CONTROLLER_Z) && GZ_getButtonPressed(DELETE_BUTTON)) { + if (GZ_getButtonRepeat(DELETE_BUTTON)) { if (g_currentActor) { if (g_currentActor->mBase.mProcName != PROC_ALINK) { fopAcM_delete(g_currentActor); @@ -310,7 +208,7 @@ void ActorListMenu::draw() { } } - if (GZ_getButtonPressed(CONTROLLER_Z) && GZ_getButtonPressed(CONTROLLER_A)) { + if (GZ_getButtonRepeat(CONTROLLER_A)) { if (g_currentActor) { g_currentActor->mBase.mPauseFlag = !g_currentActor->mBase.mPauseFlag; } @@ -328,34 +226,35 @@ void ActorListMenu::draw() { break; case ACTOR_POSITION_X_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->current.pos.x, smallPosChange, largePosChange, rightPressed, zPressed); + updateValue(&g_currentActor->current.pos.x, rightPressed); } break; case ACTOR_POSITION_Y_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->current.pos.y, smallPosChange, largePosChange, rightPressed, zPressed); + updateValue(&g_currentActor->current.pos.y, rightPressed); } break; case ACTOR_POSITION_Z_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->current.pos.z, smallPosChange, largePosChange, rightPressed, zPressed); + updateValue(&g_currentActor->current.pos.z, rightPressed); } break; case ACTOR_ANGLE_X_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->shape_angle.x, smallAngleChange, largeAngleChange, rightPressed, zPressed); + updateValue(&g_currentActor->shape_angle.x, rightPressed); } break; case ACTOR_ANGLE_Y_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->shape_angle.y, smallAngleChange, largeAngleChange, rightPressed, zPressed); + updateValue(&g_currentActor->shape_angle.y, rightPressed); } break; case ACTOR_ANGLE_Z_INDEX: if (rightPressed || leftPressed) { - updateValue(&g_currentActor->shape_angle.z, smallAngleChange, largeAngleChange, rightPressed, zPressed); + updateValue(&g_currentActor->shape_angle.z, rightPressed); } break; + case ACTOR_PROC_INDEX: case ACTOR_PARAMS_INDEX: // allowing arbitrary updates here causes frequent crashes. removing for now. break; @@ -369,6 +268,8 @@ void ActorListMenu::draw() { lines[ACTOR_ANGLE_X_INDEX].printf("rot-x: <0x%04X>", static_cast(g_currentActor->shape_angle.x)); lines[ACTOR_ANGLE_Y_INDEX].printf("rot-y: <0x%04X>", static_cast(g_currentActor->shape_angle.y)); lines[ACTOR_ANGLE_Z_INDEX].printf("rot-z: <0x%04X>", static_cast(g_currentActor->shape_angle.z)); + lines[ACTOR_ADDRESS_INDEX].printf("addr: 0x%08X", g_currentActor); + lines[ACTOR_PROC_INDEX].printf("proc id: %d", g_currentActor->mBase.mProcName); lines[ACTOR_PARAMS_INDEX].printf("params: 0x%08X", g_currentActor->mBase.mParameters); } diff --git a/modules/menus/menu_actor_spawn/src/actor_spawn_menu.cpp b/modules/menus/menu_actor_spawn/src/actor_spawn_menu.cpp index dc1be7de..a625e936 100644 --- a/modules/menus/menu_actor_spawn/src/actor_spawn_menu.cpp +++ b/modules/menus/menu_actor_spawn/src/actor_spawn_menu.cpp @@ -3,6 +3,7 @@ #include "settings.h" #include "libtp_c/include/d/com/d_com_inf_game.h" #include "libtp_c/include/f_op/f_op_actor_mng.h" +#include "libtp_c/include/f_pc/f_pc_stdcreate_req.h" #include "libtp_c/include/m_Do/m_Do_printf.h" #include "gz_flags.h" #include "pos_settings.h" @@ -57,10 +58,19 @@ KEEP_FUNC ActorSpawnMenu::ActorSpawnMenu(ActorSpawnData& data) ActorSpawnMenu::~ActorSpawnMenu() {} -void actorFastCreateAtLink(short id, uint32_t parameters, int8_t subtype) { - fopAcM_create(id, parameters, &dComIfGp_getPlayer()->current.pos, - dComIfGp_getPlayer()->current.roomNo, &dComIfGp_getPlayer()->current.angle, - nullptr, subtype); +void actorFastCreateAtLink(s16 id, u32 parameters, s8 subtype) { + fopAcM_prm_class* appen = fopAcM_CreateAppend(); + if (appen != NULL) { + appen->mParameter = parameters; + appen->mPos = dComIfGp_getPlayer()->current.pos; + appen->mAngle = dComIfGp_getPlayer()->current.angle; + appen->mEnemyNo = 0xFFFF; + appen->mSubtype = subtype; + appen->mRoomNo = dComIfGp_getPlayer()->current.roomNo; + + layer_class* curLayer = fpcLy_CurrentLayer(); + fpcSCtRq_Request(curLayer, id, nullptr, nullptr, appen); + } } void ActorSpawnMenu::loadActorName(s16& i_procName) { diff --git a/modules/menus/menu_any_bite_saves/include/any_bite_saves_menu.h b/modules/menus/menu_any_bite_saves/include/any_bite_saves_menu.h index aecd0681..25b8a816 100644 --- a/modules/menus/menu_any_bite_saves/include/any_bite_saves_menu.h +++ b/modules/menus/menu_any_bite_saves/include/any_bite_saves_menu.h @@ -1,5 +1,6 @@ #include "menus/menu.h" +#ifdef GCN_PLATFORM #define ANY_BITE_SPECIALS_AMNT 18 enum AnyBiTEPracticeIndex { @@ -53,6 +54,66 @@ enum AnyBiTEPracticeIndex { // Entry used as a count of entries ANY_BITE_SAVES_COUNT }; +#endif +#ifdef WII_PLATFORM +#define ANY_BITE_SPECIALS_AMNT 13 + +enum AnyBiTEPracticeIndex { + BITE_ORDON_GATE_CLIP_INDEX, + BITE_BACK_IN_TIME_INDEX, + BITE_SEAM_CLIP_INDEX, + BITE_GOATS_INDEX, + BITE_HUGO_INDEX, + BITE_FARON_TWILIGHT_INDEX, + BITE_EMS_INDEX, + BITE_MIST_INDEX, + BITE_KB1_INDEX, + BITE_ELDIN_TWILIGHT_INDEX, + BITE_BOMBHOUSE_SKIP_INDEX, + BITE_EPONA_OOB_INDEX, + BITE_LANAYRU_TWILIGHT_INDEX, + BITE_WATERFALL_SIDEHOP_INDEX, + BITE_BOSS_BUG_INDEX, + BITE_IZA_INDEX, + BITE_PLUMM_OOB_INDEX, + BITE_ENTER_LAKEBED_INDEX, + BITE_LAKEBED_1_INDEX, + BITE_TOAD_INDEX, + BITE_ONEBOMB_INDEX, + BITE_MDH_TOWER_INDEX, + BITE_MDH_BRIDGE_INDEX, + BITE_MESSENGER_SKIP_INDEX, + BITE_SPR_MBBB_INDEX, + BITE_FREEZARD_SKIP_INDEX, + BITE_DARK_HAMMER_INDEX, + BITE_BULBLIN_CAMP_INDEX, + BITE_AG_INDEX, + BITE_POE_1_SKIP_INDEX, + BITE_EARLY_BOSS_KEY_INDEX, + BITE_DSS_INDEX, + BITE_STALLORD_INDEX, + BITE_STALLORD2_INDEX, + BITE_CITS_EARLY_INDEX, + BITE_CITS_1_INDEX, + BITE_AERALFOS_SKIP_INDEX, + BITE_CITS_2_INDEX, + BITE_FAN_TOWER_INDEX, + BITE_ARGOROK_INDEX, + BITE_PALACE_1_INDEX, + BITE_STUPID_ROOM_INDEX, + BITE_PALACE_2_INDEX, + BITE_EARLY_PLATFORM_INDEX, + BITE_ZANT_INDEX, + BITE_HC_INDEX, + BITE_DARKNUT_INDEX, + BITE_HC_TOWER_INDEX, + BITE_BEAST_GANON_INDEX, + BITE_HORSEBACK_GANON_INDEX, + + // Entry used as a count of entries + ANY_BITE_SAVES_COUNT +}; +#endif class AnyBiTESavesMenu : public Menu { public: diff --git a/modules/menus/menu_any_bite_saves/src/any_bite_saves_menu.cpp b/modules/menus/menu_any_bite_saves/src/any_bite_saves_menu.cpp index 50aee8c9..7c7dc5b6 100644 --- a/modules/menus/menu_any_bite_saves/src/any_bite_saves_menu.cpp +++ b/modules/menus/menu_any_bite_saves/src/any_bite_saves_menu.cpp @@ -7,6 +7,7 @@ KEEP_FUNC AnyBiTESavesMenu::AnyBiTESavesMenu(Cursor& cursor) : Menu(cursor), lines{ +#ifdef GCN_PLATFORM {"ordon gate clip", BITE_ORDON_GATE_CLIP_INDEX, "Gate Clip outside Ordon Spring"}, {"back in time", BITE_BACK_IN_TIME_INDEX, "Back in Time off the Ordon Spring bridge"}, {"goats", BITE_GOATS_INDEX, "Goat herding 2"}, @@ -54,6 +55,59 @@ KEEP_FUNC AnyBiTESavesMenu::AnyBiTESavesMenu(Cursor& cursor) {"final tower climb", BITE_HC_TOWER_INDEX, "The tower climb before Ganondorf"}, {"beast ganon", BITE_BEAST_GANON_INDEX, "The Beast Ganon fight"}, {"horseback ganon", BITE_HORSEBACK_GANON_INDEX, "The Horseback Ganondorf fight"}, +#endif +#ifdef WII_PLATFORM + {"ordon gate clip", BITE_ORDON_GATE_CLIP_INDEX, "Gate Clip outside Ordon Spring"}, + {"back in time", BITE_BACK_IN_TIME_INDEX, "Back in Time off the Ordon Spring bridge"}, + {"seam clip", BITE_SEAM_CLIP_INDEX, "Seam Clip in Hyrule Field South"}, + {"goats", BITE_GOATS_INDEX, "Goat herding 2"}, + {"sword and shield skip", BITE_HUGO_INDEX, "Hangin' with Hugo"}, + {"faron twilight", BITE_FARON_TWILIGHT_INDEX, "Faron Twilight tears"}, + {"early master sword", BITE_EMS_INDEX, "Super Jump to Sacred Grove"}, + {"purple mist", BITE_MIST_INDEX, "Purple mist in Faron Woods (post-EMS)"}, + {"king bulblin 1", BITE_KB1_INDEX, "King Bulblin 1 fight"}, + {"eldin twilight", BITE_ELDIN_TWILIGHT_INDEX, "Eldin Twilight tears"}, + {"bombhouse skip", BITE_BOMBHOUSE_SKIP_INDEX, "Bombhouse skip in Kakariko"}, + {"epona oob", BITE_EPONA_OOB_INDEX, "Epona OoB in Eldin Province"}, + {"lanayru twilight", BITE_LANAYRU_TWILIGHT_INDEX, "Lanayru Twilight tears"}, + {"waterfall sidehop", BITE_WATERFALL_SIDEHOP_INDEX, "Waterfall sidehop after Rutela skip"}, + {"boss bug", BITE_BOSS_BUG_INDEX, "Boss Bug in Lake Hylia"}, + {"iza", BITE_IZA_INDEX, "Steal Iza's bomb bag"}, + {"plumm oob", BITE_PLUMM_OOB_INDEX, "Plumm OoB in Zora's Domain"}, + {"enter lakebed", BITE_ENTER_LAKEBED_INDEX, "Enter Lakebed Temple"}, + {"lakebed 1", BITE_LAKEBED_1_INDEX, "The 1st Lakebed Temple segment"}, + {"deku toad", BITE_TOAD_INDEX, "Lakebed Temple miniboss"}, + {"onebomb morpheel", BITE_ONEBOMB_INDEX, "Morpheel fight (no Zora Armor)"}, + {"mdh tower", BITE_MDH_TOWER_INDEX, "MDH tower climb"}, + {"mdh bridge", BITE_MDH_BRIDGE_INDEX, "MDH castle rooftops"}, + {"messenger skip", BITE_MESSENGER_SKIP_INDEX, "LJA to skip the Snowpeak messengers"}, + {"snowpeak mbbb", BITE_SPR_MBBB_INDEX, "Snowpeak Ruins miniboss"}, + {"freezard skip", BITE_FREEZARD_SKIP_INDEX, "Freezard skip in Snowpeak Ruins"}, + {"darkhammer", BITE_DARK_HAMMER_INDEX, "Snowpeak Ruins miniboss"}, + {"bulblin camp", BITE_BULBLIN_CAMP_INDEX, "The camp before Arbiter's Grounds"}, + {"arbiter's grounds", BITE_AG_INDEX, "The Arbiter's Grounds segment"}, + {"poe 1 skip", BITE_POE_1_SKIP_INDEX, "The pillar jump in Arbiter's Grounds"}, + {"early boss key", BITE_EARLY_BOSS_KEY_INDEX, "Early Boss Key in Arbiter's Grounds"}, + {"death sword", BITE_DSS_INDEX, "Arbiter's Grounds miniboss"}, + {"stallord", BITE_STALLORD_INDEX, "Arbiter's Grounds boss"}, + {"stallord 2", BITE_STALLORD2_INDEX, "Stallord 2nd phase"}, + {"city early", BITE_CITS_EARLY_INDEX, "Clip to the cannon early"}, + {"city 1", BITE_CITS_1_INDEX, "The 1st City in the Sky segment"}, + {"aeralfos skip", BITE_AERALFOS_SKIP_INDEX, "City in the Sky miniboss"}, + {"city 2", BITE_CITS_2_INDEX, "The 2nd City in the Sky segment"}, + {"fan tower", BITE_FAN_TOWER_INDEX, "Final fan room in City"}, + {"argorok", BITE_ARGOROK_INDEX, "City in the Sky boss"}, + {"palace sol 1", BITE_PALACE_1_INDEX, "The 1st Sol of Palace of Twilight"}, + {"palace sol 2", BITE_STUPID_ROOM_INDEX, "The 2nd Sol of Palace of Twilight"}, + {"palace 2", BITE_PALACE_2_INDEX, "After light sword"}, + {"early platform", BITE_EARLY_PLATFORM_INDEX, "Early platform in Palace of Twilight"}, + {"zant", BITE_ZANT_INDEX, "Palace of Twilight boss"}, + {"hyrule castle", BITE_HC_INDEX, "The Hyrule Castle segment"}, + {"darknut", BITE_DARKNUT_INDEX, "The Darknut fight in Hyrule Castle"}, + {"final tower climb", BITE_HC_TOWER_INDEX, "The tower climb before Ganondorf"}, + {"beast ganon", BITE_BEAST_GANON_INDEX, "The Beast Ganon fight"}, + {"horseback ganon", BITE_HORSEBACK_GANON_INDEX, "The Horseback Ganondorf fight"}, +#endif } {} AnyBiTESavesMenu::~AnyBiTESavesMenu() {} @@ -68,14 +122,16 @@ void AnyBiTESavesMenu::draw() { special AnySpecials[] = { special(BITE_ORDON_GATE_CLIP_INDEX, nullptr, SaveMngSpecial_OrdonRock), special(BITE_HUGO_INDEX, SaveMngSpecial_Hugo, SaveMngSpecial_SpawnHugo), +#ifdef GCN_PLATFORM special(BITE_KARG_INDEX, SaveMngSpecial_KargOoB, nullptr), special(BITE_LAKEBED_BK_SKIP_INDEX, SaveMngSpecial_LakebedBKSkip, nullptr), - special(BITE_ONEBOMB_INDEX, nullptr, SaveMngSpecial_Morpheel), - special(BITE_STALLORD_INDEX, SaveMngSpecial_Stallord, nullptr), - special(BITE_STALLORD2_INDEX, SaveMngSpecial_Stallord2_init, SaveMngSpecial_Stallord2), special(BITE_FRST_ESCAPE_INDEX, SaveMngSpecial_BossFlags, nullptr), special(BITE_LANAYRU_GATE_CLIP_INDEX, SaveMngSpecial_BossFlags, nullptr), special(BITE_PILLAR_CLIP_INDEX, SaveMngSpecial_BossFlags, nullptr), +#endif + special(BITE_ONEBOMB_INDEX, nullptr, SaveMngSpecial_Morpheel), + special(BITE_STALLORD_INDEX, SaveMngSpecial_Stallord, nullptr), + special(BITE_STALLORD2_INDEX, SaveMngSpecial_Stallord2_init, SaveMngSpecial_Stallord2), special(BITE_LAKEBED_1_INDEX, SaveMngSpecial_BossFlags, nullptr), special(BITE_WATERFALL_SIDEHOP_INDEX, SaveMngSpecial_WaterfallSidehop, nullptr), special(BITE_DARK_HAMMER_INDEX, SaveMngSpecial_BossFlags, SaveMngSpecial_Darkhammer), diff --git a/modules/menus/menu_any_saves/include/any_saves_menu.h b/modules/menus/menu_any_saves/include/any_saves_menu.h index 38a85225..30641fce 100644 --- a/modules/menus/menu_any_saves/include/any_saves_menu.h +++ b/modules/menus/menu_any_saves/include/any_saves_menu.h @@ -127,10 +127,5 @@ class AnySavesMenu : public Menu { virtual void draw(); private: -#ifdef GCN_PLATFORM Line lines[ANY_SAVES_COUNT]; -#endif -#ifdef WII_PLATFORM - Line lines[ANY_SAVES_COUNT]; -#endif }; \ No newline at end of file diff --git a/modules/menus/menu_dungeon_flags/include/dungeon_flags_menu.h b/modules/menus/menu_dungeon_flags/include/dungeon_flags_menu.h index 5873df4d..ef21a018 100644 --- a/modules/menus/menu_dungeon_flags/include/dungeon_flags_menu.h +++ b/modules/menus/menu_dungeon_flags/include/dungeon_flags_menu.h @@ -3,6 +3,7 @@ struct DungeonFlagsData { bool init_once = false; + // bool l_introFlag; bool l_mapFlag; bool l_compassFlag; bool l_bosskeyFlag; @@ -15,12 +16,15 @@ struct DungeonFlagsData { enum DungeonFlagsIndex { SELECT_DUNGEON_INDEX, SMALL_KEY_FLAG_INDEX, + // INTRO_CS_FLAG_INDEX, MAP_FLAG_INDEX, COMPASS_FLAG_INDEX, BOSS_KEY_FLAG_INDEX, DEFEAT_MINIBOSS_FLAG_INDEX, DEFEAT_BOSS_FLAG_INDEX, - CLEAR_DUNGEON_FLAGS_INDEX + CLEAR_DUNGEON_FLAGS_INDEX, + + DUNGEON_FLAGS_COUNT }; extern DungeonFlagsData* dungeonFlagsData; @@ -33,5 +37,5 @@ class DungeonFlagsMenu : public Menu { private: - Line lines[8]; + Line lines[DUNGEON_FLAGS_COUNT]; }; diff --git a/modules/menus/menu_dungeon_flags/src/dungeon_flags_menu.cpp b/modules/menus/menu_dungeon_flags/src/dungeon_flags_menu.cpp index ec48a652..8afacc6f 100644 --- a/modules/menus/menu_dungeon_flags/src/dungeon_flags_menu.cpp +++ b/modules/menus/menu_dungeon_flags/src/dungeon_flags_menu.cpp @@ -4,6 +4,7 @@ #include "gz_flags.h" #include "rels/include/defines.h" #include "menus/utils/menu_mgr.h" +#include "libtp_c/include/utils.h" #define MAX_DUNGEON_OPTIONS 9 @@ -15,6 +16,8 @@ KEEP_FUNC DungeonFlagsMenu::DungeonFlagsMenu(Cursor& cursor) {"dungeon:", SELECT_DUNGEON_INDEX, "Selected dungeon flags", false, nullptr, MAX_DUNGEON_OPTIONS}, {"small keys", SMALL_KEY_FLAG_INDEX, "Selected dungeon small keys", false, nullptr, 5}, + // {"intro cutscene", INTRO_CS_FLAG_INDEX, "Toggle selected dungeon intro cutscene", true, + // [](){return dungeonFlagsData->l_introFlag;}}, {"have map", MAP_FLAG_INDEX, "Give selected dungeon map", true, [](){return dungeonFlagsData->l_mapFlag;}}, {"have compass", COMPASS_FLAG_INDEX, "Give selected dungeon compass", true, [](){return dungeonFlagsData->l_compassFlag;}}, @@ -41,6 +44,20 @@ void setSaveDungeonItem(int32_t stage, int32_t flag) { } } +#include "libtp_c/include/m_Do/m_Do_printf.h" // OSReport + +bool getDungeonMemSwitch(int32_t stage, int32_t flag) { + return dSv_memBit_c__isSwitch(&dComIfGs_getSavedata().mSave[stage].mBit, flag); +} + +void setDungeonMemSwitch(int32_t stage, int32_t flag) { + if (getDungeonMemSwitch(stage, flag)) { + dSv_memBit_c__onSwitch(&dComIfGs_getSavedata().mSave[stage].mBit, flag); + } else { + dSv_memBit_c__offSwitch(&dComIfGs_getSavedata().mSave[stage].mBit, flag); + } +} + uint8_t getSaveDungeonKeys(int32_t stage) { return dComIfGs_getSavedata().mSave[stage].mBit.getKeyNum(); } @@ -123,6 +140,36 @@ void DungeonFlagsMenu::draw() { } // update flags + // switch (area_id) { + // case dSv_memory_c::FOREST_TEMPLE: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 105); + // break; + // case dSv_memory_c::GORON_MINES: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 85); + // break; + // case dSv_memory_c::LAKEBED: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 120); + // break; + // case dSv_memory_c::ARBITERS: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 124); + // break; + // case dSv_memory_c::SNOWPEAK_RUINS: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 120); + // break; + // case dSv_memory_c::TEMPLE_OF_TIME: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 21); + // break; + // case dSv_memory_c::CITY: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 111); + // break; + // case dSv_memory_c::PALACE: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 1); + // break; + // case dSv_memory_c::HYRULE_CASTLE: + // dungeonFlagsData->l_introFlag = getDungeonMemSwitch(area_id, 98); + // break; + // } + dungeonFlagsData->l_mapFlag = getSaveDungeonItem(area_id, dSv_memBit_c::MAP); dungeonFlagsData->l_compassFlag = getSaveDungeonItem(area_id, dSv_memBit_c::COMPASS); dungeonFlagsData->l_bosskeyFlag = getSaveDungeonItem(area_id, dSv_memBit_c::BOSS_KEY); @@ -131,6 +178,37 @@ void DungeonFlagsMenu::draw() { if (GZ_getButtonTrig(SELECTION_BUTTON)) { switch (cursor.y) { + // case INTRO_CS_FLAG_INDEX: + // switch (area_id) { + // case dSv_memory_c::FOREST_TEMPLE: + // setDungeonMemSwitch(area_id, 105); + // break; + // case dSv_memory_c::GORON_MINES: + // setDungeonMemSwitch(area_id, 85); + // break; + // case dSv_memory_c::LAKEBED: + // setDungeonMemSwitch(area_id, 120); + // break; + // case dSv_memory_c::ARBITERS: + // setDungeonMemSwitch(area_id, 124); + // break; + // case dSv_memory_c::SNOWPEAK_RUINS: + // setDungeonMemSwitch(area_id, 120); + // break; + // case dSv_memory_c::TEMPLE_OF_TIME: + // setDungeonMemSwitch(area_id, 21); + // break; + // case dSv_memory_c::CITY: + // setDungeonMemSwitch(area_id, 111); + // break; + // case dSv_memory_c::PALACE: + // setDungeonMemSwitch(area_id, 1); + // break; + // case dSv_memory_c::HYRULE_CASTLE: + // setDungeonMemSwitch(area_id, 98); + // break; + // } + // break; case MAP_FLAG_INDEX: setSaveDungeonItem(area_id, dSv_memBit_c::MAP); break; diff --git a/modules/menus/menu_equipment/CMakeLists.txt b/modules/menus/menu_equipment/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_equipment/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_equipment/include/equipment_menu.h b/modules/menus/menu_equipment/include/equipment_menu.h new file mode 100644 index 00000000..44172cde --- /dev/null +++ b/modules/menus/menu_equipment/include/equipment_menu.h @@ -0,0 +1,45 @@ +#include "menus/menu.h" + +struct EquipmentData { + uint8_t l_ordonSword_idx; + uint8_t l_masterSword_idx; + uint8_t l_woodShield_idx; + uint8_t l_hyShield_idx; + uint8_t l_tunic_idx; + uint8_t l_zoraArmor_idx; + uint8_t l_magicArmor_idx; + uint8_t l_bombCap_idx; + uint8_t l_wallet_idx; + uint8_t l_arrowCap_idx; +}; + +enum EquipmentIndex { + ORDON_SWORD_INDEX, + MASTER_SWORD_INDEX, + WOOD_SHIELD_INDEX, + HYLIAN_SHIELD_INDEX, + HERO_TUNIC_INDEX, + ZORA_ARMOR_INDEX, + MAGIC_ARMOR_INDEX, + BOMB_CAPACITY_INDEX, + WALLET_INDEX, + ARROW_CAPACITY_INDEX, + + EQUIPMENT_INDEX_COUNT +}; + +extern EquipmentData* equipmentData; + +class EquipmentMenu : public Menu { +public: + EquipmentMenu(Cursor&); + virtual ~EquipmentMenu(); + virtual void draw(); + +private: + Line lines[EQUIPMENT_INDEX_COUNT]; + + void resetIndex(); + void getEquipment(); + void setEquipment(); +}; \ No newline at end of file diff --git a/modules/menus/menu_equipment/include/main.h b/modules/menus/menu_equipment/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_equipment/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_equipment/src/equipment_menu.cpp b/modules/menus/menu_equipment/src/equipment_menu.cpp new file mode 100644 index 00000000..f4c33d99 --- /dev/null +++ b/modules/menus/menu_equipment/src/equipment_menu.cpp @@ -0,0 +1,351 @@ +#include "menus/menu_equipment/include/equipment_menu.h" +#include +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/utils.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +#define MAX_ORDON_SWORD_OPT 3 +#define MAX_MASTER_SWORD_OPT 3 +#define MAX_WOOD_SHIELD_OPT 3 +#define MAX_HYLIAN_SHIELD_OPT 2 +#define MAX_HERO_TUNIC_OPT 2 +#define MAX_ZORA_ARMOR_OPT 2 +#define MAX_MAGIC_ARMOR_OPT 2 +#define MAX_BOMB_CAPACITY_OPT 2 +#define MAX_WALLET_OPT 3 +#define MAX_ARROW_CAPACITY_OPT 3 + +KEEP_VAR EquipmentData* equipmentData; + +KEEP_FUNC EquipmentMenu::EquipmentMenu(Cursor& cursor) + : Menu(cursor), + lines{{"ordon sword:", ORDON_SWORD_INDEX, "Wooden Sword / Ordon Sword", false, nullptr, + MAX_ORDON_SWORD_OPT}, + {"master sword:", MASTER_SWORD_INDEX, "Master Sword / Light Sword", false, nullptr, + MAX_MASTER_SWORD_OPT}, + {"wooden shield:", WOOD_SHIELD_INDEX, "Ordon Shield / Wooden Shield", false, nullptr, + MAX_WOOD_SHIELD_OPT}, + {"hylian shield:", HYLIAN_SHIELD_INDEX, "Hylian Shield", false, nullptr, + MAX_HYLIAN_SHIELD_OPT}, + {"hero's tunic:", HERO_TUNIC_INDEX, "Hero's Tunic", false, nullptr, MAX_HERO_TUNIC_OPT}, + {"zora armor:", ZORA_ARMOR_INDEX, "Zora Armor", false, nullptr, MAX_ZORA_ARMOR_OPT}, + {"magic armor:", MAGIC_ARMOR_INDEX, "Magic Armor", false, nullptr, MAX_MAGIC_ARMOR_OPT}, + {"bomb capacity:", BOMB_CAPACITY_INDEX, "Bomb Bag Capacity", false, nullptr, + MAX_BOMB_CAPACITY_OPT}, + {"wallet upgrade:", WALLET_INDEX, "Wallet Capacity", false, nullptr, MAX_WALLET_OPT}, + {"arrow capacity:", ARROW_CAPACITY_INDEX, "Arrow Quiver Capacity", false, nullptr, + MAX_ARROW_CAPACITY_OPT}} {} + +EquipmentMenu::~EquipmentMenu() {} + +void EquipmentMenu::resetIndex() { + equipmentData->l_ordonSword_idx = 0; + equipmentData->l_masterSword_idx = 0; + equipmentData->l_woodShield_idx = 0; + equipmentData->l_hyShield_idx = 0; + equipmentData->l_tunic_idx = 0; + equipmentData->l_zoraArmor_idx = 0; + equipmentData->l_magicArmor_idx = 0; + equipmentData->l_bombCap_idx = 0; + equipmentData->l_wallet_idx = 0; + equipmentData->l_arrowCap_idx = 0; +} + +void EquipmentMenu::getEquipment() { + if (dComIfGs_isItemFirstBit(SWORD)) { + equipmentData->l_ordonSword_idx = 2; + } else if (dComIfGs_isItemFirstBit(WOOD_STICK)) { + equipmentData->l_ordonSword_idx = 1; + } + + if (dComIfGs_isItemFirstBit(LIGHT_SWORD)) { + equipmentData->l_masterSword_idx = 2; + } else if (dComIfGs_isItemFirstBit(MASTER_SWORD)) { + equipmentData->l_masterSword_idx = 1; + } + + if (dComIfGs_isItemFirstBit(SHIELD)) { + equipmentData->l_woodShield_idx = 2; + } else if (dComIfGs_isItemFirstBit(WOOD_SHIELD)) { + equipmentData->l_woodShield_idx = 1; + } + + if (dComIfGs_isItemFirstBit(HYLIA_SHIELD)) { + equipmentData->l_hyShield_idx = 1; + } + + if (dComIfGs_isItemFirstBit(WEAR_KOKIRI)) { + equipmentData->l_tunic_idx = 1; + } + + if (dComIfGs_isItemFirstBit(WEAR_ZORA)) { + equipmentData->l_zoraArmor_idx = 1; + } + + if (dComIfGs_isItemFirstBit(ARMOR)) { + equipmentData->l_magicArmor_idx = 1; + } + + if (dComIfGs_isItemFirstBit(BOMB_BAG_LV2)) { + equipmentData->l_bombCap_idx = 1; + } + + switch (dComIfGs_getWalletSize()) { + case 1: + equipmentData->l_wallet_idx = 1; + break; + case 2: + equipmentData->l_wallet_idx = 2; + break; + } + + if (dComIfGs_getArrowMax() == 100) { + equipmentData->l_arrowCap_idx = 2; + } else if (dComIfGs_getArrowMax() == 60) { + equipmentData->l_arrowCap_idx = 1; + } +} + +void EquipmentMenu::setEquipment() { + switch (equipmentData->l_ordonSword_idx) { + case 0: + dComIfGs_offItemFirstBit(WOOD_STICK); + dComIfGs_offItemFirstBit(SWORD); + break; + case 1: + dComIfGs_onItemFirstBit(WOOD_STICK); + dComIfGs_offItemFirstBit(SWORD); + break; + case 2: + dComIfGs_onItemFirstBit(SWORD); + dComIfGs_offItemFirstBit(WOOD_STICK); + break; + } + + switch (equipmentData->l_masterSword_idx) { + case 0: + dComIfGs_offItemFirstBit(MASTER_SWORD); + dComIfGs_offItemFirstBit(LIGHT_SWORD); + break; + case 1: + dComIfGs_onItemFirstBit(MASTER_SWORD); + dComIfGs_offItemFirstBit(LIGHT_SWORD); + break; + case 2: + dComIfGs_onItemFirstBit(LIGHT_SWORD); + break; + } + + switch (equipmentData->l_woodShield_idx) { + case 0: + dComIfGs_offItemFirstBit(SHIELD); + dComIfGs_offItemFirstBit(WOOD_SHIELD); + break; + case 1: + dComIfGs_onItemFirstBit(WOOD_SHIELD); + break; + case 2: + dComIfGs_onItemFirstBit(SHIELD); + break; + } + + switch (equipmentData->l_hyShield_idx) { + case 0: + dComIfGs_offItemFirstBit(HYLIA_SHIELD); + break; + case 1: + dComIfGs_onItemFirstBit(HYLIA_SHIELD); + break; + } + + switch (equipmentData->l_tunic_idx) { + case 0: + dComIfGs_offItemFirstBit(WEAR_KOKIRI); + break; + case 1: + dComIfGs_onItemFirstBit(WEAR_KOKIRI); + break; + } + + switch (equipmentData->l_zoraArmor_idx) { + case 0: + dComIfGs_offItemFirstBit(WEAR_ZORA); + break; + case 1: + dComIfGs_onItemFirstBit(WEAR_ZORA); + break; + } + + switch (equipmentData->l_magicArmor_idx) { + case 0: + dComIfGs_offItemFirstBit(ARMOR); + break; + case 1: + dComIfGs_onItemFirstBit(ARMOR); + break; + } + + switch (equipmentData->l_bombCap_idx) { + case 0: + dComIfGs_offItemFirstBit(BOMB_BAG_LV2); + break; + case 1: + dComIfGs_onItemFirstBit(BOMB_BAG_LV2); + break; + } + + switch (equipmentData->l_wallet_idx) { + case 0: + dComIfGs_setWalletSize(WALLET); + break; + case 1: + dComIfGs_setWalletSize(BIG_WALLET); + break; + case 2: + dComIfGs_setWalletSize(GIANT_WALLET); + break; + } + + switch (equipmentData->l_arrowCap_idx) { + case 0: + dComIfGs_setArrowMax(30); + break; + case 1: + dComIfGs_setArrowMax(60); + break; + case 2: + dComIfGs_setArrowMax(100); + break; + } +} + +void EquipmentMenu::draw() { + static bool init = false; + cursor.setMode(Cursor::MODE_LIST); + + if (!init) { + getEquipment(); + init = true; + } + + if (GZ_getButtonTrig(BACK_BUTTON)) { + init = false; + g_menuMgr->pop(); + resetIndex(); + return; + } + + ListMember ordonSword_opt[3] = {"none", "wooden sword", "ordon sword"}; + ListMember masterSword_opt[3] = {"none", "master sword", "light sword"}; + ListMember woodShield_opt[3] = {"none", "ordon shield", "wooden shield"}; + ListMember hyShield_opt[2] = {"none", "hylian shield"}; + ListMember tunic_opt[2] = {"none", "hero's tunic"}; + ListMember zoraArmor_opt[2] = {"none", "zora armor"}; + ListMember magicArmor_opt[2] = {"none", "magic armor"}; + ListMember bombCap_opt[2] = {"30/15/10", "60/30/20"}; + ListMember wallet_opt[3] = {"300 Rupees", "600 Rupees", "1000 Rupees"}; + ListMember arrowCap_opt[3] = {"30 Arrows", "60 Arrows", "100 Arrows"}; + + switch (cursor.y) { + case ORDON_SWORD_INDEX: + cursor.x = equipmentData->l_ordonSword_idx; + cursor.move(MAX_ORDON_SWORD_OPT, MENU_LINE_NUM); + + if (cursor.y == ORDON_SWORD_INDEX) { + equipmentData->l_ordonSword_idx = cursor.x; + } + break; + case MASTER_SWORD_INDEX: + cursor.x = equipmentData->l_masterSword_idx; + cursor.move(MAX_MASTER_SWORD_OPT, MENU_LINE_NUM); + + if (cursor.y == MASTER_SWORD_INDEX) { + equipmentData->l_masterSword_idx = cursor.x; + } + break; + case WOOD_SHIELD_INDEX: + cursor.x = equipmentData->l_woodShield_idx; + cursor.move(MAX_WOOD_SHIELD_OPT, MENU_LINE_NUM); + + if (cursor.y == WOOD_SHIELD_INDEX) { + equipmentData->l_woodShield_idx = cursor.x; + } + break; + case HYLIAN_SHIELD_INDEX: + cursor.x = equipmentData->l_hyShield_idx; + cursor.move(MAX_HYLIAN_SHIELD_OPT, MENU_LINE_NUM); + + if (cursor.y == HYLIAN_SHIELD_INDEX) { + equipmentData->l_hyShield_idx = cursor.x; + } + break; + case HERO_TUNIC_INDEX: + cursor.x = equipmentData->l_tunic_idx; + cursor.move(MAX_HERO_TUNIC_OPT, MENU_LINE_NUM); + + if (cursor.y == HERO_TUNIC_INDEX) { + equipmentData->l_tunic_idx = cursor.x; + } + break; + case ZORA_ARMOR_INDEX: + cursor.x = equipmentData->l_zoraArmor_idx; + cursor.move(MAX_ZORA_ARMOR_OPT, MENU_LINE_NUM); + + if (cursor.y == ZORA_ARMOR_INDEX) { + equipmentData->l_zoraArmor_idx = cursor.x; + } + break; + case MAGIC_ARMOR_INDEX: + cursor.x = equipmentData->l_magicArmor_idx; + cursor.move(MAX_MAGIC_ARMOR_OPT, MENU_LINE_NUM); + + if (cursor.y == MAGIC_ARMOR_INDEX) { + equipmentData->l_magicArmor_idx = cursor.x; + } + break; + case BOMB_CAPACITY_INDEX: + cursor.x = equipmentData->l_bombCap_idx; + cursor.move(MAX_BOMB_CAPACITY_OPT, MENU_LINE_NUM); + + if (cursor.y == BOMB_CAPACITY_INDEX) { + equipmentData->l_bombCap_idx = cursor.x; + } + break; + case WALLET_INDEX: + cursor.x = equipmentData->l_wallet_idx; + cursor.move(MAX_WALLET_OPT, MENU_LINE_NUM); + + if (cursor.y == WALLET_INDEX) { + equipmentData->l_wallet_idx = cursor.x; + } + break; + case ARROW_CAPACITY_INDEX: + cursor.x = equipmentData->l_arrowCap_idx; + cursor.move(MAX_ARROW_CAPACITY_OPT, MENU_LINE_NUM); + + if (cursor.y == ARROW_CAPACITY_INDEX) { + equipmentData->l_arrowCap_idx = cursor.x; + } + break; + default: + cursor.move(0, MENU_LINE_NUM); + break; + } + + setEquipment(); + + lines[ORDON_SWORD_INDEX].printf(" <%s>", ordonSword_opt[equipmentData->l_ordonSword_idx].member); + lines[MASTER_SWORD_INDEX].printf(" <%s>", masterSword_opt[equipmentData->l_masterSword_idx].member); + lines[WOOD_SHIELD_INDEX].printf(" <%s>", woodShield_opt[equipmentData->l_woodShield_idx].member); + lines[HYLIAN_SHIELD_INDEX].printf(" <%s>", hyShield_opt[equipmentData->l_hyShield_idx].member); + lines[HERO_TUNIC_INDEX].printf(" <%s>", tunic_opt[equipmentData->l_tunic_idx].member); + lines[ZORA_ARMOR_INDEX].printf(" <%s>", zoraArmor_opt[equipmentData->l_zoraArmor_idx].member); + lines[MAGIC_ARMOR_INDEX].printf(" <%s>", magicArmor_opt[equipmentData->l_magicArmor_idx].member); + lines[BOMB_CAPACITY_INDEX].printf(" <%s>", bombCap_opt[equipmentData->l_bombCap_idx].member); + lines[WALLET_INDEX].printf(" <%s>", wallet_opt[equipmentData->l_wallet_idx].member); + lines[ARROW_CAPACITY_INDEX].printf(" <%s>", arrowCap_opt[equipmentData->l_arrowCap_idx].member); + + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_equipment/src/main.cpp b/modules/menus/menu_equipment/src/main.cpp new file mode 100644 index 00000000..ed0a6b41 --- /dev/null +++ b/modules/menus/menu_equipment/src/main.cpp @@ -0,0 +1,56 @@ +#include +#include "menus/menu_equipment/include/equipment_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +EquipmentMenu* l_menu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + g_menuMgr->setPersistentData(new EquipmentData); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + equipmentData = g_menuMgr->getPersistentData(); + l_menu = new EquipmentMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_menu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_menu; +} + +void onDelete() { + auto data = g_menuMgr->getPersistentData(); + delete data; + g_menuMgr->setPersistentData(nullptr); +} diff --git a/modules/menus/menu_flags/include/flags_menu.h b/modules/menus/menu_flags/include/flags_menu.h index f80942f1..10869a45 100644 --- a/modules/menus/menu_flags/include/flags_menu.h +++ b/modules/menus/menu_flags/include/flags_menu.h @@ -5,8 +5,11 @@ enum FlagsIndex { GENERAL_FLAGS_INDEX, DUNGEON_FLAGS_INDEX, PORTAL_FLAGS_INDEX, + RUPEE_FLAGS_INDEX, FLAG_RECORDS_INDEX, - FLAG_LOG_INDEX + FLAG_LOG_INDEX, + + FLAGS_COUNT }; class FlagsMenu : public Menu { @@ -16,5 +19,5 @@ class FlagsMenu : public Menu { virtual void draw(); private: - Line lines[5]; + Line lines[FLAGS_COUNT]; }; diff --git a/modules/menus/menu_flags/src/flags_menu.cpp b/modules/menus/menu_flags/src/flags_menu.cpp index 4f589fc0..d578ab43 100644 --- a/modules/menus/menu_flags/src/flags_menu.cpp +++ b/modules/menus/menu_flags/src/flags_menu.cpp @@ -8,6 +8,7 @@ KEEP_FUNC FlagsMenu::FlagsMenu(Cursor& cursor) {"general flags", GENERAL_FLAGS_INDEX, "General flags", false}, {"dungeon flags", DUNGEON_FLAGS_INDEX, "Dungeon flags", false}, {"portal flags", PORTAL_FLAGS_INDEX, "Warp portal flags", false}, + {"rupee flags", RUPEE_FLAGS_INDEX, "Rupee related flags", false}, {"flag records", FLAG_RECORDS_INDEX, "Edit flag records", false}, {"flag log", FLAG_LOG_INDEX, "Toggle the flag log", false}, } {} @@ -31,6 +32,9 @@ void FlagsMenu::draw() { case PORTAL_FLAGS_INDEX: g_menuMgr->push(MN_PORTAL_FLAGS_INDEX); return; + case RUPEE_FLAGS_INDEX: + g_menuMgr->push(MN_RUPEE_FLAGS_INDEX); + return; case FLAG_RECORDS_INDEX: g_menuMgr->push(MN_FLAG_RECORDS_INDEX); return; diff --git a/modules/menus/menu_general_flags/include/general_flags_menu.h b/modules/menus/menu_general_flags/include/general_flags_menu.h index 0e3f3438..76deb2bb 100644 --- a/modules/menus/menu_general_flags/include/general_flags_menu.h +++ b/modules/menus/menu_general_flags/include/general_flags_menu.h @@ -3,12 +3,14 @@ struct GeneralFlagsData { bool l_bossFlag; - bool l_rupeeFlag; + bool l_coroTD; bool l_midnaCharge; bool l_transformWarp; bool l_midnaZ; + bool l_ruslTD; bool l_eponaStolen; bool l_eponaTamed; + bool l_maloMartCT; bool l_mapWarping; bool l_midnaHealed; bool l_midnaRide; @@ -17,16 +19,20 @@ struct GeneralFlagsData { enum GeneralFlagsIndex { BOSS_FLAG_INDEX, - RUPEE_CS_FLAG_INDEX, + CORO_TD_INDEX, EPONA_STOLEN_INDEX, EPONA_TAMED_INDEX, + MALO_MART_CT_INDEX, MAP_WARPING_INDEX, MIDNA_CHARGE_INDEX, MIDNA_HEALTHY, MIDNA_ON_BACK, MIDNA_Z_INDEX, + RUSL_TD_INDEX, TRANSFORM_WARP_INDEX, - WOLF_SENSE_INDEX + WOLF_SENSE_INDEX, + + GENERAL_FLAGS_COUNT }; extern GeneralFlagsData* generalFlagsData; @@ -38,5 +44,5 @@ class GeneralFlagsMenu : public Menu { virtual void draw(); private: - Line lines[11]; + Line lines[GENERAL_FLAGS_COUNT]; }; diff --git a/modules/menus/menu_general_flags/src/general_flags_menu.cpp b/modules/menus/menu_general_flags/src/general_flags_menu.cpp index a54732da..22ee4cce 100644 --- a/modules/menus/menu_general_flags/src/general_flags_menu.cpp +++ b/modules/menus/menu_general_flags/src/general_flags_menu.cpp @@ -11,12 +11,14 @@ KEEP_FUNC GeneralFlagsMenu::GeneralFlagsMenu(Cursor& cursor) : Menu(cursor), lines{ {"boss flag", BOSS_FLAG_INDEX, "Sets the boss flag value", true, [](){return generalFlagsData->l_bossFlag;}}, - {"rupee cutscenes", RUPEE_CS_FLAG_INDEX, "Toggle rupee cutscenes being enabled", true, - [](){return generalFlagsData->l_rupeeFlag;}}, + {"coro td", CORO_TD_INDEX, "Toggle temporary flag for Coro text displacement", true, + [](){return generalFlagsData->l_coroTD;}}, {"epona stolen", EPONA_STOLEN_INDEX, "Toggle flag for Epona being stolen", true, [](){return generalFlagsData->l_eponaStolen;}}, {"epona tamed", EPONA_TAMED_INDEX, "Toggle flag for Epona being tamed", true, [](){return generalFlagsData->l_eponaTamed;}}, + {"malo mart in castle town", MALO_MART_CT_INDEX, "Toggle flag for Malo Mart being open in Castle Town", true, + [](){return generalFlagsData->l_maloMartCT;}}, {"map warping", MAP_WARPING_INDEX, "Toggle flag for map warping", true, [](){return generalFlagsData->l_mapWarping;}}, {"midna charge", MIDNA_CHARGE_INDEX, "Toggle flag for Midna charge", true, [](){return generalFlagsData->l_midnaCharge;}}, @@ -26,6 +28,8 @@ KEEP_FUNC GeneralFlagsMenu::GeneralFlagsMenu(Cursor& cursor) true, [](){return generalFlagsData->l_midnaRide;}}, {"midna available", MIDNA_Z_INDEX, "Toggle flag for being able to call Midna", true, [](){return generalFlagsData->l_midnaZ;}}, + {"rusl td", RUSL_TD_INDEX, "Toggle temporary flag for Rusl text displacement", true, + [](){return generalFlagsData->l_ruslTD;}}, {"transform/warp", TRANSFORM_WARP_INDEX, "Toggle flag for transforming/warping", true, [](){return generalFlagsData->l_transformWarp;}}, {"wolf sense", WOLF_SENSE_INDEX, "Toggle flag for wolf sense", true, [](){return generalFlagsData->l_wolfSense;}}, @@ -40,22 +44,19 @@ void GeneralFlagsMenu::draw() { // update flags generalFlagsData->l_bossFlag = bossFlags > 0; + generalFlagsData->l_coroTD = dComIfGs_isTmpBit(0x0002); + generalFlagsData->l_ruslTD = dComIfGs_isTmpBit(0x0006); generalFlagsData->l_midnaCharge = dComIfGs_isEventBit(0x0501); generalFlagsData->l_transformWarp = dComIfGs_isEventBit(0x0D04); generalFlagsData->l_midnaZ = dComIfGs_isEventBit(0x0C10); generalFlagsData->l_eponaStolen = dComIfGs_isEventBit(0x0580); generalFlagsData->l_eponaTamed = dComIfGs_isEventBit(0x0601); + generalFlagsData->l_maloMartCT = dComIfGs_isEventBit(0x2210); generalFlagsData->l_mapWarping = dComIfGs_isEventBit(0x0604); generalFlagsData->l_midnaHealed = dComIfGs_isEventBit(0x1E08); generalFlagsData->l_midnaRide = dComIfGs_isTransformLV(3); generalFlagsData->l_wolfSense = dComIfGs_isEventBit(0x4308); - - for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { - if (dComIfGs_isItemFirstBit(i)) { - generalFlagsData->l_rupeeFlag = true; - break; - } - } + if (GZ_getButtonTrig(BACK_BUTTON)) { g_menuMgr->pop(); @@ -71,17 +72,8 @@ void GeneralFlagsMenu::draw() { bossFlags = 255; } break; - case RUPEE_CS_FLAG_INDEX: - if (generalFlagsData->l_rupeeFlag) { - for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { - dComIfGs_offItemFirstBit(i); - } - generalFlagsData->l_rupeeFlag = false; - } else { - for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { - dComIfGs_onItemFirstBit(i); - } - } + case CORO_TD_INDEX: + setTempEventFlag(0x0002); break; case EPONA_STOLEN_INDEX: setEventFlag(0x0580); @@ -89,6 +81,9 @@ void GeneralFlagsMenu::draw() { case EPONA_TAMED_INDEX: setEventFlag(0x0601); break; + case MALO_MART_CT_INDEX: + setEventFlag(0x2210); + break; case MAP_WARPING_INDEX: setEventFlag(0x0604); break; @@ -105,6 +100,9 @@ void GeneralFlagsMenu::draw() { case MIDNA_Z_INDEX: setEventFlag(0x0C10); break; + case RUSL_TD_INDEX: + setTempEventFlag(0x0006); + break; case TRANSFORM_WARP_INDEX: setEventFlag(0x0D04); break; diff --git a/modules/menus/menu_golden_bugs/CMakeLists.txt b/modules/menus/menu_golden_bugs/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_golden_bugs/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_golden_bugs/include/golden_bugs_menu.h b/modules/menus/menu_golden_bugs/include/golden_bugs_menu.h new file mode 100644 index 00000000..038fd5c8 --- /dev/null +++ b/modules/menus/menu_golden_bugs/include/golden_bugs_menu.h @@ -0,0 +1,72 @@ +#include "menus/menu.h" + +struct GoldenBugData { + uint8_t l_mAntIdx; + uint8_t l_fAntIdx; + uint8_t l_mBeetleIdx; + uint8_t l_fBeetleIdx; + uint8_t l_mButterflyIdx; + uint8_t l_fButterflyIdx; + uint8_t l_mDayflyIdx; + uint8_t l_fDayflyIdx; + uint8_t l_mDragonflyIdx; + uint8_t l_fDragonflyIdx; + uint8_t l_mGrasshopperIdx; + uint8_t l_fGrasshopperIdx; + uint8_t l_mLadybugIdx; + uint8_t l_fLadybugIdx; + uint8_t l_mMantisIdx; + uint8_t l_fMantisIdx; + uint8_t l_mPhasmidIdx; + uint8_t l_fPhasmidIdx; + uint8_t l_mPillBugIdx; + uint8_t l_fPillBugIdx; + uint8_t l_mSnailIdx; + uint8_t l_fSnailIdx; + uint8_t l_mStagBeetleIdx; + uint8_t l_fStagBeetleIdx; +}; + +enum BugIndex { + M_ANT_INDEX, + F_ANT_INDEX, + M_BEETLE_INDEX, + F_BEETLE_INDEX, + M_BUTTERFLY_INDEX, + F_BUTTERFLY_INDEX, + M_DAYFLY_INDEX, + F_DAYFLY_INDEX, + M_DRAGONFLY_INDEX, + F_DRAGONFLY_INDEX, + M_GRASSHOPPER_INDEX, + F_GRASSHOPPER_INDEX, + M_LADYBUG_INDEX, + F_LADYBUG_INDEX, + M_MANTIS_INDEX, + F_MANTIS_INDEX, + M_PHASMID_INDEX, + F_PHASMID_INDEX, + M_PILL_BUG_INDEX, + F_PILL_BUG_INDEX, + M_SNAIL_INDEX, + F_SNAIL_INDEX, + M_STAG_BEETLE_INDEX, + F_STAG_BEETLE_INDEX, + + GB_INDEX_COUNT +}; + +extern GoldenBugData* gbData; + +class GoldenBugMenu : public Menu { +public: + GoldenBugMenu(Cursor&); + virtual ~GoldenBugMenu(); + virtual void draw(); + +private: + uint8_t getBugIdx(u8 bug, u16 flag); + void setBugIdx(u8 bug, u8 idx, u16 flag); + void setBugs(); + Line lines[GB_INDEX_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_golden_bugs/include/main.h b/modules/menus/menu_golden_bugs/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_golden_bugs/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_golden_bugs/src/golden_bugs_menu.cpp b/modules/menus/menu_golden_bugs/src/golden_bugs_menu.cpp new file mode 100644 index 00000000..a54d7ccc --- /dev/null +++ b/modules/menus/menu_golden_bugs/src/golden_bugs_menu.cpp @@ -0,0 +1,730 @@ +#include "menus/menu_golden_bugs/include/golden_bugs_menu.h" +#include +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/utils.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +KEEP_VAR GoldenBugData* gbData; + +#define MAX_GB_OPT 3 + +KEEP_FUNC GoldenBugMenu::GoldenBugMenu(Cursor& cursor) + : Menu(cursor), + lines{ + {"Ant (M):", M_ANT_INDEX, "Male Ant", false, nullptr, MAX_GB_OPT}, + {"Ant (F):", F_ANT_INDEX, "Female Ant", false, nullptr, MAX_GB_OPT}, + {"Beetle (M:", M_BEETLE_INDEX, "Male Beetle", false, nullptr, MAX_GB_OPT}, + {"Beetle (F):", F_BEETLE_INDEX, "Female Beetle", false, nullptr, MAX_GB_OPT}, + {"Butterfly (M):", M_BUTTERFLY_INDEX, "Male Butterfly", false, nullptr, MAX_GB_OPT}, + {"Butterfly (F):", F_BUTTERFLY_INDEX, "Female Butterfly", false, nullptr, MAX_GB_OPT}, + {"Dayfly (M):", M_DAYFLY_INDEX, "Male Dayfly", false, nullptr, MAX_GB_OPT}, + {"Dayfly (F):", F_DAYFLY_INDEX, "Female Dayfly", false, nullptr, MAX_GB_OPT}, + {"Dragonfly (M):", M_DRAGONFLY_INDEX, "Male Dragonfly", false, nullptr, MAX_GB_OPT}, + {"Dragonfly (F):", F_DRAGONFLY_INDEX, "Female Dragonfly", false, nullptr, MAX_GB_OPT}, + {"Grasshopper (M):", M_GRASSHOPPER_INDEX, "Male Grasshopper", false, nullptr, MAX_GB_OPT}, + {"Grasshopper (F):", F_GRASSHOPPER_INDEX, "Female Grasshopper", false, nullptr, MAX_GB_OPT}, + {"Ladybug (M):", M_LADYBUG_INDEX, "Male Ladybug", false, nullptr, MAX_GB_OPT}, + {"Ladybug (F):", F_LADYBUG_INDEX, "Female Ladybug", false, nullptr, MAX_GB_OPT}, + {"Mantis (M):", M_MANTIS_INDEX, "Male Mantis", false, nullptr, MAX_GB_OPT}, + {"Mantis (F):", F_MANTIS_INDEX, "Female Mantis", false, nullptr, MAX_GB_OPT}, + {"Phasmid (M):", M_PHASMID_INDEX, "Male Phasmid", false, nullptr, MAX_GB_OPT}, + {"Phasmid (F):", F_PHASMID_INDEX, "Female Phasmid", false, nullptr, MAX_GB_OPT}, + {"Pill Bug (M):", M_PILL_BUG_INDEX, "Male Pill Bug", false, nullptr, MAX_GB_OPT}, + {"Pill Bug (F):", F_PILL_BUG_INDEX, "Female Pill Bug", false, nullptr, MAX_GB_OPT}, + {"Snail (M):", M_SNAIL_INDEX, "Male Snail", false, nullptr, MAX_GB_OPT}, + {"Snail (F):", F_SNAIL_INDEX, "Female Snail", false, nullptr, MAX_GB_OPT}, + {"Stag Beetle (M):", M_STAG_BEETLE_INDEX, "Male Stag Beetle", false, nullptr, MAX_GB_OPT}, + {"Stag Beetle (F):", F_STAG_BEETLE_INDEX, "Female Stag Beetle", false, nullptr, MAX_GB_OPT}, + } { + + } + +GoldenBugMenu::~GoldenBugMenu() {} + +void GoldenBugMenu::setBugs() { + switch (gbData->l_mAntIdx) { + case 0: + dComIfGs_offItemFirstBit(M_ANT); + dComIfGs_offEventBit(0x3301); + break; + case 1: + dComIfGs_onItemFirstBit(M_ANT); + dComIfGs_offEventBit(0x3301); + break; + case 2: + dComIfGs_onItemFirstBit(M_ANT); + dComIfGs_onEventBit(0x3301); + break; + } + + switch (gbData->l_fAntIdx) { + case 0: + dComIfGs_offItemFirstBit(F_ANT); + dComIfGs_offEventBit(0x3480); + break; + case 1: + dComIfGs_onItemFirstBit(F_ANT); + dComIfGs_offEventBit(0x3480); + break; + case 2: + dComIfGs_onItemFirstBit(F_ANT); + dComIfGs_onEventBit(0x3480); + break; + } + + switch (gbData->l_mBeetleIdx) { + case 0: + dComIfGs_offItemFirstBit(M_BEETLE); + dComIfGs_offEventBit(0x3110); + break; + case 1: + dComIfGs_onItemFirstBit(M_BEETLE); + dComIfGs_offEventBit(0x3110); + break; + case 2: + dComIfGs_onItemFirstBit(M_BEETLE); + dComIfGs_onEventBit(0x3110); + break; + } + + switch (gbData->l_fBeetleIdx) { + case 0: + dComIfGs_offItemFirstBit(F_BEETLE); + dComIfGs_offEventBit(0x3108); + break; + case 1: + dComIfGs_onItemFirstBit(F_BEETLE); + dComIfGs_offEventBit(0x3108); + break; + case 2: + dComIfGs_onItemFirstBit(F_BEETLE); + dComIfGs_onEventBit(0x3108); + break; + } + + switch (gbData->l_mButterflyIdx) { + case 0: + dComIfGs_offItemFirstBit(M_BUTTERFLY); + dComIfGs_offEventBit(0x3104); + break; + case 1: + dComIfGs_onItemFirstBit(M_BUTTERFLY); + dComIfGs_offEventBit(0x3104); + break; + case 2: + dComIfGs_onItemFirstBit(M_BUTTERFLY); + dComIfGs_onEventBit(0x3104); + break; + } + + switch (gbData->l_fButterflyIdx) { + case 0: + dComIfGs_offItemFirstBit(F_BUTTERFLY); + dComIfGs_offEventBit(0x3102); + break; + case 1: + dComIfGs_onItemFirstBit(F_BUTTERFLY); + dComIfGs_offEventBit(0x3102); + break; + case 2: + dComIfGs_onItemFirstBit(F_BUTTERFLY); + dComIfGs_onEventBit(0x3102); + break; + } + + switch (gbData->l_mDayflyIdx) { + case 0: + dComIfGs_offItemFirstBit(M_MAYFLY); + dComIfGs_offEventBit(0x3440); + break; + case 1: + dComIfGs_onItemFirstBit(M_MAYFLY); + dComIfGs_offEventBit(0x3440); + break; + case 2: + dComIfGs_onItemFirstBit(M_MAYFLY); + dComIfGs_onEventBit(0x3440); + break; + } + + switch (gbData->l_fDayflyIdx) { + case 0: + dComIfGs_offItemFirstBit(F_MAYFLY); + dComIfGs_offEventBit(0x3420); + break; + case 1: + dComIfGs_onItemFirstBit(F_MAYFLY); + dComIfGs_offEventBit(0x3420); + break; + case 2: + dComIfGs_onItemFirstBit(F_MAYFLY); + dComIfGs_onEventBit(0x3420); + break; + } + + switch (gbData->l_mDragonflyIdx) { + case 0: + dComIfGs_offItemFirstBit(M_DRAGONFLY); + dComIfGs_offEventBit(0x3304); + break; + case 1: + dComIfGs_onItemFirstBit(M_DRAGONFLY); + dComIfGs_offEventBit(0x3304); + break; + case 2: + dComIfGs_onItemFirstBit(M_DRAGONFLY); + dComIfGs_onEventBit(0x3304); + break; + } + + switch (gbData->l_fDragonflyIdx) { + case 0: + dComIfGs_offItemFirstBit(F_DRAGONFLY); + dComIfGs_offEventBit(0x3302); + break; + case 1: + dComIfGs_onItemFirstBit(F_DRAGONFLY); + dComIfGs_offEventBit(0x3302); + break; + case 2: + dComIfGs_onItemFirstBit(F_DRAGONFLY); + dComIfGs_onEventBit(0x3302); + break; + } + + switch (gbData->l_mGrasshopperIdx) { + case 0: + dComIfGs_offItemFirstBit(M_GRASSHOPPER); + dComIfGs_offEventBit(0x3240); + break; + case 1: + dComIfGs_onItemFirstBit(M_GRASSHOPPER); + dComIfGs_offEventBit(0x3240); + break; + case 2: + dComIfGs_onItemFirstBit(M_GRASSHOPPER); + dComIfGs_onEventBit(0x3240); + break; + } + + switch (gbData->l_fGrasshopperIdx) { + case 0: + dComIfGs_offItemFirstBit(F_GRASSHOPPER); + dComIfGs_offEventBit(0x3220); + break; + case 1: + dComIfGs_onItemFirstBit(F_GRASSHOPPER); + dComIfGs_offEventBit(0x3220); + break; + case 2: + dComIfGs_onItemFirstBit(F_GRASSHOPPER); + dComIfGs_onEventBit(0x3220); + break; + } + + switch (gbData->l_mLadybugIdx) { + case 0: + dComIfGs_offItemFirstBit(M_LADYBUG); + dComIfGs_offEventBit(0x3340); + break; + case 1: + dComIfGs_onItemFirstBit(M_LADYBUG); + dComIfGs_offEventBit(0x3340); + break; + case 2: + dComIfGs_onItemFirstBit(M_LADYBUG); + dComIfGs_onEventBit(0x3340); + break; + } + + switch (gbData->l_fLadybugIdx) { + case 0: + dComIfGs_offItemFirstBit(F_LADYBUG); + dComIfGs_offEventBit(0x3320); + break; + case 1: + dComIfGs_onItemFirstBit(F_LADYBUG); + dComIfGs_offEventBit(0x3320); + break; + case 2: + dComIfGs_onItemFirstBit(F_LADYBUG); + dComIfGs_onEventBit(0x3320); + break; + } + + switch (gbData->l_mMantisIdx) { + case 0: + dComIfGs_offItemFirstBit(M_MANTIS); + dComIfGs_offEventBit(0x3201); + break; + case 1: + dComIfGs_onItemFirstBit(M_MANTIS); + dComIfGs_offEventBit(0x3201); + break; + case 2: + dComIfGs_onItemFirstBit(M_MANTIS); + dComIfGs_onEventBit(0x3201); + break; + } + + switch (gbData->l_fMantisIdx) { + case 0: + dComIfGs_offItemFirstBit(F_MANTIS); + dComIfGs_offEventBit(0x3380); + break; + case 1: + dComIfGs_onItemFirstBit(F_MANTIS); + dComIfGs_offEventBit(0x3380); + break; + case 2: + dComIfGs_onItemFirstBit(F_MANTIS); + dComIfGs_onEventBit(0x3380); + break; + } + + switch (gbData->l_mPhasmidIdx) { + case 0: + dComIfGs_offItemFirstBit(M_NANAFUSHI); + dComIfGs_offEventBit(0x3210); + break; + case 1: + dComIfGs_onItemFirstBit(M_NANAFUSHI); + dComIfGs_offEventBit(0x3210); + break; + case 2: + dComIfGs_onItemFirstBit(M_NANAFUSHI); + dComIfGs_onEventBit(0x3210); + break; + } + + switch (gbData->l_fPhasmidIdx) { + case 0: + dComIfGs_offItemFirstBit(F_NANAFUSHI); + dComIfGs_offEventBit(0x3208); + break; + case 1: + dComIfGs_onItemFirstBit(F_NANAFUSHI); + dComIfGs_offEventBit(0x3208); + break; + case 2: + dComIfGs_onItemFirstBit(F_NANAFUSHI); + dComIfGs_onEventBit(0x3208); + break; + } + + switch (gbData->l_mPillBugIdx) { + case 0: + dComIfGs_offItemFirstBit(M_DANGOMUSHI); + dComIfGs_offEventBit(0x3204); + break; + case 1: + dComIfGs_onItemFirstBit(M_DANGOMUSHI); + dComIfGs_offEventBit(0x3204); + break; + case 2: + dComIfGs_onItemFirstBit(M_DANGOMUSHI); + dComIfGs_onEventBit(0x3204); + break; + } + + switch (gbData->l_fPillBugIdx) { + case 0: + dComIfGs_offItemFirstBit(F_DANGOMUSHI); + dComIfGs_offEventBit(0x3202); + break; + case 1: + dComIfGs_onItemFirstBit(F_DANGOMUSHI); + dComIfGs_offEventBit(0x3202); + break; + case 2: + dComIfGs_onItemFirstBit(F_DANGOMUSHI); + dComIfGs_onEventBit(0x3202); + break; + } + + switch (gbData->l_mSnailIdx) { + case 0: + dComIfGs_offItemFirstBit(M_SNAIL); + dComIfGs_offEventBit(0x3310); + break; + case 1: + dComIfGs_onItemFirstBit(M_SNAIL); + dComIfGs_offEventBit(0x3310); + break; + case 2: + dComIfGs_onItemFirstBit(M_SNAIL); + dComIfGs_onEventBit(0x3310); + break; + } + + switch (gbData->l_fSnailIdx) { + case 0: + dComIfGs_offItemFirstBit(F_SNAIL); + dComIfGs_offEventBit(0x3308); + break; + case 1: + dComIfGs_onItemFirstBit(F_SNAIL); + dComIfGs_offEventBit(0x3308); + break; + case 2: + dComIfGs_onItemFirstBit(F_SNAIL); + dComIfGs_onEventBit(0x3308); + break; + } + + switch (gbData->l_mStagBeetleIdx) { + case 0: + dComIfGs_offItemFirstBit(M_STAG_BEETLE); + dComIfGs_offEventBit(0x3101); + break; + case 1: + dComIfGs_onItemFirstBit(M_STAG_BEETLE); + dComIfGs_offEventBit(0x3101); + break; + case 2: + dComIfGs_onItemFirstBit(M_STAG_BEETLE); + dComIfGs_onEventBit(0x3101); + break; + } + + switch (gbData->l_fStagBeetleIdx) { + case 0: + dComIfGs_offItemFirstBit(F_STAG_BEETLE); + dComIfGs_offEventBit(0x3280); + break; + case 1: + dComIfGs_onItemFirstBit(F_STAG_BEETLE); + dComIfGs_offEventBit(0x3280); + break; + case 2: + dComIfGs_onItemFirstBit(F_STAG_BEETLE); + dComIfGs_onEventBit(0x3280); + break; + } +} + +u8 GoldenBugMenu::getBugIdx(u8 bug, u16 flag) { + if (dComIfGs_isEventBit(flag)) { + return 2; + } + + if (dComIfGs_isItemFirstBit(bug)) { + return 1; + } + + return 0; +} + +void GoldenBugMenu::draw() { + cursor.setMode(Cursor::MODE_LIST); + + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + // update gb flags + gbData->l_mAntIdx = getBugIdx(M_ANT,0x3301); + gbData->l_fAntIdx = getBugIdx(F_ANT,0x3480); + gbData->l_mBeetleIdx = getBugIdx(M_BEETLE,0x3110); + gbData->l_fBeetleIdx = getBugIdx(F_BEETLE,0x3108); + gbData->l_mButterflyIdx = getBugIdx(M_BUTTERFLY,0x3104); + gbData->l_fButterflyIdx = getBugIdx(F_BUTTERFLY,0x3102); + gbData->l_mDayflyIdx = getBugIdx(M_MAYFLY,0x3440); + gbData->l_fDayflyIdx = getBugIdx(F_MAYFLY,0x3420); + gbData->l_mDragonflyIdx = getBugIdx(M_DRAGONFLY,0x3304); + gbData->l_fDragonflyIdx = getBugIdx(F_DRAGONFLY,0x3302); + gbData->l_mGrasshopperIdx = getBugIdx(M_GRASSHOPPER,0x3240); + gbData->l_fGrasshopperIdx = getBugIdx(F_GRASSHOPPER,0x3220); + gbData->l_mLadybugIdx = getBugIdx(M_LADYBUG,0x3340); + gbData->l_fLadybugIdx = getBugIdx(F_LADYBUG,0x3320); + gbData->l_mMantisIdx = getBugIdx(M_MANTIS,0x3201); + gbData->l_fMantisIdx = getBugIdx(F_MANTIS,0x3380); + gbData->l_mPhasmidIdx = getBugIdx(M_NANAFUSHI,0x3210); + gbData->l_fPhasmidIdx = getBugIdx(F_NANAFUSHI,0x3208); + gbData->l_mPillBugIdx = getBugIdx(M_DANGOMUSHI,0x3204); + gbData->l_fPillBugIdx = getBugIdx(F_DANGOMUSHI,0x3202); + gbData->l_mSnailIdx = getBugIdx(M_SNAIL,0x3310); + gbData->l_fSnailIdx = getBugIdx(F_SNAIL,0x3308); + gbData->l_mStagBeetleIdx = getBugIdx(M_STAG_BEETLE,0x3101); + gbData->l_fStagBeetleIdx = getBugIdx(F_STAG_BEETLE,0x3280); + + ListMember mAnt_opt[3] = {"none", "Ant (M)", "Ant (M) (turned in)"}; + ListMember fAnt_opt[3] = {"none", "Ant (F)", "Ant (F) (turned in)"}; + ListMember mBeetle_opt[3] = {"none", "Beetle (M)", "Beetle (M) (turned in)"}; + ListMember fBeetle_opt[3] = {"none", "Beetle (F)", "Beetle (F) (turned in)"}; + ListMember mButterfly_opt[3] = {"none", "Butterfly (M)", "Butterfly (M) (turned in)"}; + ListMember fButterfly_opt[3] = {"none", "Butterfly (F)", "Butterfly (F) (turned in)"}; + ListMember mDayfly_opt[3] = {"none", "Dayfly (M)", "Dayfly (M) (turned in)"}; + ListMember fDayfly_opt[3] = {"none", "Dayfly (F)", "Dayfly (F) (turned in)"}; + ListMember mDragonfly_opt[3] = {"none", "Dragonfly (M)", "Dragonfly (M) (turned in)"}; + ListMember fDragonfly_opt[3] = {"none", "Dragonfly (F)", "Dragonfly (F) (turned in)"}; + ListMember mGrasshopper_opt[3] = {"none", "Grasshopper (M)", "Grasshopper (M) (turned in)"}; + ListMember fGrasshopper_opt[3] = {"none", "Grasshopper (F)", "Grasshopper (F) (turned in)"}; + ListMember mLadybug_opt[3] = {"none", "Ladybug (M)", "Ladybug (M) (turned in)"}; + ListMember fLadybug_opt[3] = {"none", "Ladybug (F)", "Ladybug (F) (turned in)"}; + ListMember mMantis_opt[3] = {"none", "Mantis (M)", "Mantis (M) (turned in)"}; + ListMember fMantis_opt[3] = {"none", "Mantis (F)", "Mantis (F) (turned in)"}; + ListMember mPhasmid_opt[3] = {"none", "Phasmid (M)", "Phasmid (M) (turned in)"}; + ListMember fPhasmid_opt[3] = {"none", "Phasmid (F)", "Phasmid (F) (turned in)"}; + ListMember mPillBug_opt[3] = {"none", "Pill Bug (M)", "Pill Bug (M) (turned in)"}; + ListMember fPillBug_opt[3] = {"none", "Pill Bug (F)", "Pill Bug (F) (turned in)"}; + ListMember mSnail_opt[3] = {"none", "Snail (M)", "Snail (M) (turned in)"}; + ListMember fSnail_opt[3] = {"none", "Snail (F)", "Snail (F) (turned in)"}; + ListMember mStagBeetle_opt[3] = {"none", "Stag Beetle (M)", "Stag Beetle (M) (turned in)"}; + ListMember fStagBeetle_opt[3] = {"none", "Stag Beetle (F)", "Stag Beetle (F) (turned in)"}; + + switch (cursor.y) { + case M_ANT_INDEX: + cursor.x = gbData->l_mAntIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_ANT_INDEX) { + gbData->l_mAntIdx = cursor.x; + } + + break; + case F_ANT_INDEX: + cursor.x = gbData->l_fAntIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_ANT_INDEX) { + gbData->l_fAntIdx = cursor.x; + } + + break; + case M_BEETLE_INDEX: + cursor.x = gbData->l_mBeetleIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_BEETLE_INDEX) { + gbData->l_mBeetleIdx = cursor.x; + } + + break; + case F_BEETLE_INDEX: + cursor.x = gbData->l_fBeetleIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_BEETLE_INDEX) { + gbData->l_fBeetleIdx = cursor.x; + } + + break; + case M_BUTTERFLY_INDEX: + cursor.x = gbData->l_mButterflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_BUTTERFLY_INDEX) { + gbData->l_mButterflyIdx = cursor.x; + } + + break; + case F_BUTTERFLY_INDEX: + cursor.x = gbData->l_fButterflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_BUTTERFLY_INDEX) { + gbData->l_fButterflyIdx = cursor.x; + } + + break; + case M_DAYFLY_INDEX: + cursor.x = gbData->l_mDayflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_DAYFLY_INDEX) { + gbData->l_mDayflyIdx = cursor.x; + } + + break; + case F_DAYFLY_INDEX: + cursor.x = gbData->l_fDayflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_DAYFLY_INDEX) { + gbData->l_fDayflyIdx = cursor.x; + } + + break; + case M_DRAGONFLY_INDEX: + cursor.x = gbData->l_mDragonflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_DRAGONFLY_INDEX) { + gbData->l_mDragonflyIdx = cursor.x; + } + + break; + case F_DRAGONFLY_INDEX: + cursor.x = gbData->l_fDragonflyIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_DRAGONFLY_INDEX) { + gbData->l_fDragonflyIdx = cursor.x; + } + + break; + case M_GRASSHOPPER_INDEX: + cursor.x = gbData->l_mGrasshopperIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_GRASSHOPPER_INDEX) { + gbData->l_mGrasshopperIdx = cursor.x; + } + + break; + case F_GRASSHOPPER_INDEX: + cursor.x = gbData->l_fGrasshopperIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_GRASSHOPPER_INDEX) { + gbData->l_fGrasshopperIdx = cursor.x; + } + + break; + case M_LADYBUG_INDEX: + cursor.x = gbData->l_mLadybugIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_LADYBUG_INDEX) { + gbData->l_mLadybugIdx = cursor.x; + } + + break; + case F_LADYBUG_INDEX: + cursor.x = gbData->l_fLadybugIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_LADYBUG_INDEX) { + gbData->l_fLadybugIdx = cursor.x; + } + + break; + case M_MANTIS_INDEX: + cursor.x = gbData->l_mMantisIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_MANTIS_INDEX) { + gbData->l_mMantisIdx = cursor.x; + } + + break; + case F_MANTIS_INDEX: + cursor.x = gbData->l_fMantisIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_MANTIS_INDEX) { + gbData->l_fMantisIdx = cursor.x; + } + + break; + case M_PHASMID_INDEX: + cursor.x = gbData->l_mPhasmidIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_PHASMID_INDEX) { + gbData->l_mPhasmidIdx = cursor.x; + } + + break; + case F_PHASMID_INDEX: + cursor.x = gbData->l_fPhasmidIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_PHASMID_INDEX) { + gbData->l_fPhasmidIdx = cursor.x; + } + + break; + case M_PILL_BUG_INDEX: + cursor.x = gbData->l_mPillBugIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_PILL_BUG_INDEX) { + gbData->l_mPillBugIdx = cursor.x; + } + + break; + case F_PILL_BUG_INDEX: + cursor.x = gbData->l_fPillBugIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_PILL_BUG_INDEX) { + gbData->l_fPillBugIdx = cursor.x; + } + + break; + case M_SNAIL_INDEX: + cursor.x = gbData->l_mSnailIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_SNAIL_INDEX) { + gbData->l_mSnailIdx = cursor.x; + } + + break; + case F_SNAIL_INDEX: + cursor.x = gbData->l_fSnailIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_SNAIL_INDEX) { + gbData->l_fSnailIdx = cursor.x; + } + + break; + case M_STAG_BEETLE_INDEX: + cursor.x = gbData->l_mStagBeetleIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == M_STAG_BEETLE_INDEX) { + gbData->l_mStagBeetleIdx = cursor.x; + } + + break; + case F_STAG_BEETLE_INDEX: + cursor.x = gbData->l_fStagBeetleIdx; + cursor.move(MAX_GB_OPT, MENU_LINE_NUM); + + if (cursor.y == F_STAG_BEETLE_INDEX) { + gbData->l_fStagBeetleIdx = cursor.x; + } + + break; + default: + cursor.move(0, MENU_LINE_NUM); + break; + } + + setBugs(); + + lines[M_ANT_INDEX].printf(" <%s>", mAnt_opt[gbData->l_mAntIdx].member); + lines[F_ANT_INDEX].printf(" <%s>", fAnt_opt[gbData->l_fAntIdx].member); + lines[M_BEETLE_INDEX].printf(" <%s>", mBeetle_opt[gbData->l_mBeetleIdx].member); + lines[F_BEETLE_INDEX].printf(" <%s>", fBeetle_opt[gbData->l_fBeetleIdx].member); + lines[M_BUTTERFLY_INDEX].printf(" <%s>", mButterfly_opt[gbData->l_mButterflyIdx].member); + lines[F_BUTTERFLY_INDEX].printf(" <%s>", fButterfly_opt[gbData->l_fButterflyIdx].member); + lines[M_DAYFLY_INDEX].printf(" <%s>", mDayfly_opt[gbData->l_mDayflyIdx].member); + lines[F_DAYFLY_INDEX].printf(" <%s>", fDayfly_opt[gbData->l_fDayflyIdx].member); + lines[M_DRAGONFLY_INDEX].printf(" <%s>", mDragonfly_opt[gbData->l_mDragonflyIdx].member); + lines[F_DRAGONFLY_INDEX].printf(" <%s>", fDragonfly_opt[gbData->l_fDragonflyIdx].member); + lines[M_GRASSHOPPER_INDEX].printf(" <%s>", mGrasshopper_opt[gbData->l_mGrasshopperIdx].member); + lines[F_GRASSHOPPER_INDEX].printf(" <%s>", fGrasshopper_opt[gbData->l_fGrasshopperIdx].member); + lines[M_LADYBUG_INDEX].printf(" <%s>", mLadybug_opt[gbData->l_mLadybugIdx].member); + lines[F_LADYBUG_INDEX].printf(" <%s>", fLadybug_opt[gbData->l_fLadybugIdx].member); + lines[M_MANTIS_INDEX].printf(" <%s>", mMantis_opt[gbData->l_mMantisIdx].member); + lines[F_MANTIS_INDEX].printf(" <%s>", fMantis_opt[gbData->l_fMantisIdx].member); + lines[M_PHASMID_INDEX].printf(" <%s>", mPhasmid_opt[gbData->l_mPhasmidIdx].member); + lines[F_PHASMID_INDEX].printf(" <%s>", fPhasmid_opt[gbData->l_fPhasmidIdx].member); + lines[M_PILL_BUG_INDEX].printf(" <%s>", mPillBug_opt[gbData->l_mPillBugIdx].member); + lines[F_PILL_BUG_INDEX].printf(" <%s>", fPillBug_opt[gbData->l_fPillBugIdx].member); + lines[M_SNAIL_INDEX].printf(" <%s>", mSnail_opt[gbData->l_mSnailIdx].member); + lines[F_SNAIL_INDEX].printf(" <%s>", fSnail_opt[gbData->l_fSnailIdx].member); + lines[M_STAG_BEETLE_INDEX].printf(" <%s>", mStagBeetle_opt[gbData->l_mStagBeetleIdx].member); + lines[F_STAG_BEETLE_INDEX].printf(" <%s>", fStagBeetle_opt[gbData->l_fStagBeetleIdx].member); + + + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} \ No newline at end of file diff --git a/modules/menus/menu_golden_bugs/src/main.cpp b/modules/menus/menu_golden_bugs/src/main.cpp new file mode 100644 index 00000000..31b88873 --- /dev/null +++ b/modules/menus/menu_golden_bugs/src/main.cpp @@ -0,0 +1,56 @@ +#include +#include "menus/menu_golden_bugs/include/golden_bugs_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +GoldenBugMenu* l_goldenBugMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + g_menuMgr->setPersistentData(new GoldenBugData); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + gbData = g_menuMgr->getPersistentData(); + l_goldenBugMenu = new GoldenBugMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_goldenBugMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_goldenBugMenu; +} + +void onDelete() { + auto data = g_menuMgr->getPersistentData(); + delete data; + g_menuMgr->setPersistentData(nullptr); +} diff --git a/modules/menus/menu_hidden_skills/CMakeLists.txt b/modules/menus/menu_hidden_skills/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_hidden_skills/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_hidden_skills/include/hidden_skills_menu.h b/modules/menus/menu_hidden_skills/include/hidden_skills_menu.h new file mode 100644 index 00000000..cdc5b3a8 --- /dev/null +++ b/modules/menus/menu_hidden_skills/include/hidden_skills_menu.h @@ -0,0 +1,35 @@ +#include "menus/menu.h" + +struct HiddenSkillsData { + bool l_ebFlag; + bool l_sbFlag; + bool l_bsFlag; + bool l_hsFlag; + bool l_mdFlag; + bool l_jsFlag; + bool l_gsFlag; +}; + +enum HiddenSkillsIndex { + ENDING_BLOW_INDEX, + SHIELD_BASH_INDEX, + BACKSLICE_INDEX, + HELM_SPLITTER_INDEX, + MORTAL_DRAW_INDEX, + JUMP_STRIKE_INDEX, + GREAT_SPIN_INDEX, + + HIDDEN_SKILLS_INDEX_COUNT +}; + +extern HiddenSkillsData* hiddenSkillsData; + +class HiddenSkillsMenu : public Menu { +public: + HiddenSkillsMenu(Cursor&); + virtual ~HiddenSkillsMenu(); + virtual void draw(); + +private: + Line lines[HIDDEN_SKILLS_INDEX_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_hidden_skills/include/main.h b/modules/menus/menu_hidden_skills/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_hidden_skills/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_hidden_skills/src/hidden_skills_menu.cpp b/modules/menus/menu_hidden_skills/src/hidden_skills_menu.cpp new file mode 100644 index 00000000..fd4b75a6 --- /dev/null +++ b/modules/menus/menu_hidden_skills/src/hidden_skills_menu.cpp @@ -0,0 +1,68 @@ +#include "menus/menu_hidden_skills/include/hidden_skills_menu.h" +#include +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/utils.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +KEEP_VAR HiddenSkillsData* hiddenSkillsData; + +KEEP_FUNC HiddenSkillsMenu::HiddenSkillsMenu(Cursor& cursor) + : Menu(cursor), + lines{{"ending blow:", ENDING_BLOW_INDEX, "Ending Blow", true, [](){return hiddenSkillsData->l_ebFlag;}}, + {"shield bash:", SHIELD_BASH_INDEX, "Shield Bash", true, [](){return hiddenSkillsData->l_sbFlag;}}, + {"backslice:", BACKSLICE_INDEX, "Backslice", true, [](){return hiddenSkillsData->l_bsFlag;}}, + {"helm splitter:", HELM_SPLITTER_INDEX, "Helm Splitter", true, [](){return hiddenSkillsData->l_hsFlag;}}, + {"mortal draw:", MORTAL_DRAW_INDEX, "Mortal Draw", true, [](){return hiddenSkillsData->l_mdFlag;}}, + {"jump strike:", JUMP_STRIKE_INDEX, "Jump Strike", true, [](){return hiddenSkillsData->l_jsFlag;}}, + {"greatspin:", GREAT_SPIN_INDEX, "Greatspin", true, [](){return hiddenSkillsData->l_gsFlag;}}} {} + +HiddenSkillsMenu::~HiddenSkillsMenu() {} + +void HiddenSkillsMenu::draw() { + cursor.setMode(Cursor::MODE_LIST); + + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + // update hidden skill flags + hiddenSkillsData->l_ebFlag = dComIfGs_isEventBit(0x2904); + hiddenSkillsData->l_sbFlag = dComIfGs_isEventBit(0x2908); + hiddenSkillsData->l_bsFlag = dComIfGs_isEventBit(0x2902); + hiddenSkillsData->l_hsFlag = dComIfGs_isEventBit(0x2901); + hiddenSkillsData->l_mdFlag = dComIfGs_isEventBit(0x2A80); + hiddenSkillsData->l_jsFlag = dComIfGs_isEventBit(0x2A40); + hiddenSkillsData->l_gsFlag = dComIfGs_isEventBit(0x2A20); + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + switch (cursor.y) { + case ENDING_BLOW_INDEX: + setEventFlag(0x2904); + break; + case SHIELD_BASH_INDEX: + setEventFlag(0x2908); + break; + case BACKSLICE_INDEX: + setEventFlag(0x2902); + break; + case HELM_SPLITTER_INDEX: + setEventFlag(0x2901); + break; + case MORTAL_DRAW_INDEX: + setEventFlag(0x2A80); + break; + case JUMP_STRIKE_INDEX: + setEventFlag(0x2A40); + break; + case GREAT_SPIN_INDEX: + setEventFlag(0x2A20); + break; + } + } + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_hidden_skills/src/main.cpp b/modules/menus/menu_hidden_skills/src/main.cpp new file mode 100644 index 00000000..aa517183 --- /dev/null +++ b/modules/menus/menu_hidden_skills/src/main.cpp @@ -0,0 +1,56 @@ +#include +#include "menus/menu_hidden_skills/include/hidden_skills_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +HiddenSkillsMenu* l_menu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + g_menuMgr->setPersistentData(new HiddenSkillsData); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + hiddenSkillsData = g_menuMgr->getPersistentData(); + l_menu = new HiddenSkillsMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_menu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_menu; +} + +void onDelete() { + auto data = g_menuMgr->getPersistentData(); + delete data; + g_menuMgr->setPersistentData(nullptr); +} diff --git a/modules/menus/menu_hundo_saves/include/hundo_saves_menu.h b/modules/menus/menu_hundo_saves/include/hundo_saves_menu.h index f60a3e3b..5c20b5d7 100644 --- a/modules/menus/menu_hundo_saves/include/hundo_saves_menu.h +++ b/modules/menus/menu_hundo_saves/include/hundo_saves_menu.h @@ -22,13 +22,16 @@ enum HundoPracticeIndex { HND_TOAD_INDEX, HND_KARG_INDEX, HND_LANAYRU_TWILIGHT_INDEX, - HND_BOSS_BUG_INDEX, - HND_KB_2_INDEX, - HND_ESCORT_INDEX, HND_COROTD_INDEX, + HND_EARLY_ELE_INDEX, HND_GM_INDEX, HND_DANGORO_INDEX, - HND_POST_GM_INDEX, + HND_FYRUS_INDEX, + HND_WATERFALL_SIDEHOP_INDEX, + HND_BOSS_BUG_INDEX, + HND_KB_2_INDEX, + HND_ESCORT_INDEX, + HND_ELDIN_COLLECT_INDEX, HND_LAKEBED_BK_SKIP_INDEX, HND_MORPHEEL_INDEX, HND_MDH_TOWER_INDEX, @@ -46,7 +49,7 @@ enum HundoPracticeIndex { HND_POST_AG_INDEX, HND_SPR_INDEX, HND_DARK_HAMMER_INDEX, - HND_SPR_SUPERJUMP_INDEX, + HND_SPR_2_INDEX, HND_SPR_BK_LJA_INDEX, HND_SPR_BK_ROOM_INDEX, HND_BLIZZETA_INDEX, @@ -62,7 +65,9 @@ enum HundoPracticeIndex { HND_POST_TOT_INDEX, HND_HOTSPRING_INDEX, HND_GORGE_ARC_INDEX, + HND_SILVER_RUPEE_INDEX, HND_PUZZLE_INDEX, + HND_IZA2_INDEX, HND_ARCHERY_INDEX, HND_CITY_1_INDEX, HND_AERALFOS_INDEX, diff --git a/modules/menus/menu_hundo_saves/src/hundo_saves_menu.cpp b/modules/menus/menu_hundo_saves/src/hundo_saves_menu.cpp index 5b7acee8..91204add 100644 --- a/modules/menus/menu_hundo_saves/src/hundo_saves_menu.cpp +++ b/modules/menus/menu_hundo_saves/src/hundo_saves_menu.cpp @@ -24,13 +24,16 @@ KEEP_FUNC HundoSavesMenu::HundoSavesMenu(Cursor& cursor) {"deku toad", HND_TOAD_INDEX, "Lakebed Temple miniboss"}, {"kargorok flight", HND_KARG_INDEX, "Clip OoB with trumpet bird"}, {"lanayru twilight", HND_LANAYRU_TWILIGHT_INDEX, "Lanayru Twilight tears"}, - {"boss bug", HND_BOSS_BUG_INDEX, "Lanayru Twilight boss bug"}, - {"kb2 skip", HND_KB_2_INDEX, "Clip to skip King Bulblin 2"}, - {"wagon escort", HND_ESCORT_INDEX, "Telma wagon escort"}, {"coro td", HND_COROTD_INDEX, "Text Displacement with Coro"}, + {"early ele", HND_EARLY_ELE_INDEX, "OoB LJA to Death Mountain Elevator"}, {"goron mines", HND_GM_INDEX, "The Goron Mines segment"}, {"dangoro", HND_DANGORO_INDEX, "Goron Mines miniboss"}, - {"post gm", HND_POST_GM_INDEX, "The segment after Goron Mines"}, + {"fyrus", HND_FYRUS_INDEX, "Goron Mines boss"}, + {"waterfall sidehop", HND_WATERFALL_SIDEHOP_INDEX, "Waterfall sidehop after Rutela skip"}, + {"boss bug", HND_BOSS_BUG_INDEX, "Lanayru Twilight boss bug"}, + {"kb2 skip", HND_KB_2_INDEX, "Clip to skip King Bulblin 2"}, + {"wagon escort", HND_ESCORT_INDEX, "Telma wagon escort"}, + {"eldin collection", HND_ELDIN_COLLECT_INDEX, "Eldin Field collection segment"}, {"lakebed bk skip", HND_LAKEBED_BK_SKIP_INDEX, "Boss Key skip in Lakebed Temple"}, {"morpheel", HND_MORPHEEL_INDEX, "Lakebed Temple boss"}, {"mdh tower", HND_MDH_TOWER_INDEX, "MDH tower climb"}, @@ -48,7 +51,7 @@ KEEP_FUNC HundoSavesMenu::HundoSavesMenu(Cursor& cursor) {"post ag", HND_POST_AG_INDEX, "Collection cycle after Arbiter's"}, {"snowpeak", HND_SPR_INDEX, "The Snowpeak Ruins segment"}, {"darkhammer", HND_DARK_HAMMER_INDEX, "Snowpeak Ruins miniboss"}, - {"spr superjump", HND_SPR_SUPERJUMP_INDEX, "SPR Super Jump to 2nd floor"}, + {"spr 2", HND_SPR_2_INDEX, "The 2nd half of Snowpeak Ruins"}, {"spr bk lja", HND_SPR_BK_LJA_INDEX, "LJA to Snowpeak Boss Key room"}, {"spr bk room", HND_SPR_BK_ROOM_INDEX, "Snowpeak Boss Key room"}, {"blizzeta", HND_BLIZZETA_INDEX, "Snowpeak Ruins boss"}, @@ -64,7 +67,9 @@ KEEP_FUNC HundoSavesMenu::HundoSavesMenu(Cursor& cursor) {"post tot", HND_POST_TOT_INDEX, "Collection cycle after Temple of Time"}, {"hotspring minigame", HND_HOTSPRING_INDEX, "Goron hotspring water minigame"}, {"gorge arc", HND_GORGE_ARC_INDEX, "Gorge / South Faron collection"}, + {"silver rupee", HND_SILVER_RUPEE_INDEX, "Getting the Kakariko Silver Rupee"}, {"ice puzzle", HND_PUZZLE_INDEX, "The Ice Puzzle segment"}, + {"iza 2", HND_IZA2_INDEX, "Iza River Ride minigame"}, {"hugo archery", HND_ARCHERY_INDEX, "Archery in Hidden Village"}, {"city 1", HND_CITY_1_INDEX, "The 1st City in the Sky segment"}, {"aeralfos skip", HND_AERALFOS_INDEX, "the city in the sky miniboss"}, @@ -94,13 +99,16 @@ KEEP_FUNC HundoSavesMenu::HundoSavesMenu(Cursor& cursor) HundoSavesMenu::~HundoSavesMenu() {} void HundoSavesMenu::draw() { - special HundoSpecials[HND_SPECIALS_AMNT] = { + special HundoSpecials[] = { special(HND_GOATS_1_INDEX, SaveMngSpecial_Goats1, nullptr), special(HND_MIST_INDEX, SaveMngSpecial_PurpleMist, nullptr), special(HND_KARG_INDEX, SaveMngSpecial_KargOoB, nullptr), + special(HND_EARLY_ELE_INDEX, SaveMngSpecial_EarlyEle, nullptr), special(HND_KB_2_INDEX, SaveMngSpecial_KB2Skip, nullptr), special(HND_ESCORT_INDEX, SaveMngSpecial_Escort, SaveMngSpecial_EscortKeys), + special(HND_ELDIN_COLLECT_INDEX, SaveMngSpecial_EldinCollection, nullptr), special(HND_DANGORO_INDEX, nullptr, SaveMngSpecial_Dangoro), + special(HND_WATERFALL_SIDEHOP_INDEX, SaveMngSpecial_WaterfallSidehop, nullptr), special(HND_LAKEBED_BK_SKIP_INDEX, SaveMngSpecial_LakebedBKSkip, nullptr), special(HND_MORPHEEL_INDEX, nullptr, SaveMngSpecial_Morpheel), special(HND_IZA_1_SKIP_INDEX, SaveMngSpecial_Iza1Skip, nullptr), @@ -128,7 +136,7 @@ void HundoSavesMenu::draw() { } if (GZ_getButtonTrig(SELECTION_BUTTON)) { - SaveManager::triggerLoad(cursor.y, "hundo", HundoSpecials, HND_SPECIALS_AMNT); + SaveManager::triggerLoad(cursor.y, "hundo", HundoSpecials, ARRAY_COUNT(HundoSpecials)); g_menuMgr->hide(); } diff --git a/modules/menus/menu_item_wheel/include/item_wheel_menu.h b/modules/menus/menu_item_wheel/include/item_wheel_menu.h index 70d666d3..1538dd75 100644 --- a/modules/menus/menu_item_wheel/include/item_wheel_menu.h +++ b/modules/menus/menu_item_wheel/include/item_wheel_menu.h @@ -4,7 +4,7 @@ #define ITEM_WHEEL_SLOTS 24 struct ItemWheelData { - int l_listIdx; + unsigned int l_listIdx; }; struct ItemLookup { @@ -21,7 +21,7 @@ class ItemWheelMenu : public Menu { void fixSpecialItems(int i); private: - int& l_listIdx; + unsigned int& l_listIdx; Line lines[ITEM_WHEEL_SLOTS]; }; \ No newline at end of file diff --git a/modules/menus/menu_item_wheel/src/item_wheel_menu.cpp b/modules/menus/menu_item_wheel/src/item_wheel_menu.cpp index febb8c10..2115e272 100644 --- a/modules/menus/menu_item_wheel/src/item_wheel_menu.cpp +++ b/modules/menus/menu_item_wheel/src/item_wheel_menu.cpp @@ -8,7 +8,7 @@ #include "menus/utils/menu_mgr.h" #define ITEM_WHEEL_SLOTS 24 -#define MAX_ITEMS 58 +#define MAX_ITEMS ARRAY_COUNT(l_lookupTbl) #ifdef GCN_PLATFORM #define DEFAULT_BTN_TXT "Z" @@ -90,11 +90,11 @@ const uint8_t l_defaultItems[ITEM_WHEEL_SLOTS] = { BOOMERANG, KANTERA, SPINNER, HVY_BOOTS, BOW, HAWK_EYE, IRONBALL, NO_ITEM, COPY_ROD, HOOKSHOT, W_HOOKSHOT, EMPTY_BOTTLE, EMPTY_BOTTLE, EMPTY_BOTTLE, EMPTY_BOTTLE, - BOMB_BAG_LV1, BOMB_BAG_LV1, BOMB_BAG_LV1, DUNGEON_EXIT, RAFRELS_MEMO, + NORMAL_BOMB, WATER_BOMB, POKE_BOMB, DUNGEON_EXIT, RAFRELS_MEMO, FISHING_ROD_1, HORSE_FLUTE, ANCIENT_DOCUMENT, PACHINKO, }; -const ItemLookup l_lookupTbl[MAX_ITEMS] = { +const ItemLookup l_lookupTbl[] = { {NO_ITEM, "n/a"}, {ANCIENT_DOCUMENT, "ancient sky book (empty)"}, {ANCIENT_DOCUMENT2, "ancient sky book (filled)"}, @@ -157,7 +157,7 @@ const ItemLookup l_lookupTbl[MAX_ITEMS] = { void ItemWheelMenu::updateListIdx() { uint8_t item_id = dComIfGs_getSavedata().getPlayer().getItem().mItems[cursor.y]; - for (int i = 0; i < MAX_ITEMS; i++) { + for (unsigned int i = 0; i < MAX_ITEMS; i++) { if (item_id == l_validItems[i]) { l_listIdx = i; } @@ -193,14 +193,14 @@ void ItemWheelMenu::draw() { for (size_t slot_no = 0; slot_no < MENU_LINE_NUM; slot_no++) { int item_id = dComIfGs_getItem(slot_no, false); - for (int j = 0; j < MAX_ITEMS; j++) { + for (unsigned int j = 0; j < MAX_ITEMS; j++) { if (l_lookupTbl[j].item_id == item_id) { lines[slot_no].printf(" <%s>", item_id != NO_ITEM ? l_lookupTbl[j].name : "n/a"); } if (l_lookupTbl[j].item_id == l_defaultItems[slot_no]) { snprintf(lines[slot_no].description, sizeof(lines[slot_no].description), - "Slot %d default: %s. Press " DEFAULT_BTN_TXT " to set to default; " RESET_BTN_TXT " to reset.", + "Slot %d default: %s. " DEFAULT_BTN_TXT ": set default; " RESET_BTN_TXT ": reset.", slot_no, l_lookupTbl[j].name); } else { continue; diff --git a/modules/menus/menu_memfiles/include/memfiles_menu.h b/modules/menus/menu_memfiles/include/memfiles_menu.h index c5f269d1..a7518fda 100644 --- a/modules/menus/menu_memfiles/include/memfiles_menu.h +++ b/modules/menus/menu_memfiles/include/memfiles_menu.h @@ -8,12 +8,13 @@ #define MEMFILE_DELETE_INDEX 3 struct MemfilesData { + Cursor cursor; uint8_t l_fileNo = 1; }; class MemfilesMenu : public Menu { public: - MemfilesMenu(Cursor&, MemfilesData&); + MemfilesMenu(MemfilesData&); virtual ~MemfilesMenu(); virtual void draw(); diff --git a/modules/menus/menu_memfiles/src/main.cpp b/modules/menus/menu_memfiles/src/main.cpp index 3008489c..5a7a3e9b 100644 --- a/modules/menus/menu_memfiles/src/main.cpp +++ b/modules/menus/menu_memfiles/src/main.cpp @@ -28,15 +28,13 @@ void exit() { } // namespace tpgz::modules void onCreate() { - g_menuMgr->setPersistentData(new MemfilesData()); - if (!g_menuMgr->getPermanentData()) { - g_menuMgr->setPermanentData(new Cursor); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new MemfilesData); } } void onLoad() { - l_menu = new MemfilesMenu(*g_menuMgr->getPermanentData(), - *g_menuMgr->getPersistentData()); + l_menu = new MemfilesMenu(*g_menuMgr->getPermanentData()); g_drawListener->addListener(onDraw); } @@ -49,8 +47,4 @@ void onUnload() { delete l_menu; } -void onDelete() { - auto data = g_menuMgr->getPersistentData(); - delete data; - g_menuMgr->setPersistentData(nullptr); -} +void onDelete() {} diff --git a/modules/menus/menu_memfiles/src/memfiles_menu.cpp b/modules/menus/menu_memfiles/src/memfiles_menu.cpp index 11711e94..6f759b4b 100644 --- a/modules/menus/menu_memfiles/src/memfiles_menu.cpp +++ b/modules/menus/menu_memfiles/src/memfiles_menu.cpp @@ -11,17 +11,12 @@ #define MAX_SAVE_SLOTS 20 -PositionData memfile_posdata; - -KEEP_FUNC MemfilesMenu::MemfilesMenu(Cursor& cursor, MemfilesData& data) - : Menu(cursor), - l_fileNo(data.l_fileNo), lines{ - {"file slot:", MEMFILE_SLOT_INDEX, "Select memfile slot"}, - {"save", MEMFILE_SAVE_INDEX, "Save memfile to slot", false}, - {"load", MEMFILE_LOAD_INDEX, "Load memfile from slot", false}, - {"delete", MEMFILE_DELETE_INDEX, "Delete memfile from slot", - false}, - } {} +KEEP_FUNC MemfilesMenu::MemfilesMenu(MemfilesData& data) + : Menu(data.cursor), l_fileNo(data.l_fileNo), lines{ + {"file slot:", MEMFILE_SLOT_INDEX, "Select memfile slot"}, + {"save", MEMFILE_SAVE_INDEX, "Save memfile to slot", false}, + {"load", MEMFILE_LOAD_INDEX, "Load memfile from slot", false}, + {"delete", MEMFILE_DELETE_INDEX, "Delete memfile from slot", false}} {} MemfilesMenu::~MemfilesMenu() {} diff --git a/modules/menus/menu_pause/include/pause_menu.h b/modules/menus/menu_pause/include/pause_menu.h index 1d6543fc..403334b1 100644 --- a/modules/menus/menu_pause/include/pause_menu.h +++ b/modules/menus/menu_pause/include/pause_menu.h @@ -1,43 +1,16 @@ #include "menus/menu.h" struct PauseData { - uint8_t l_ordonSword_idx; - uint8_t l_masterSword_idx; - uint8_t l_woodShield_idx; - uint8_t l_hyShield_idx; - uint8_t l_tunic_idx; - uint8_t l_zoraArmor_idx; - uint8_t l_magicArmor_idx; - uint8_t l_bombCap_idx; - uint8_t l_wallet_idx; - uint8_t l_arrowCap_idx; - bool l_ebFlag; - bool l_sbFlag; - bool l_bsFlag; - bool l_hsFlag; - bool l_mdFlag; - bool l_jsFlag; - bool l_gsFlag; + uint8_t l_scent_idx; }; enum PauseIndex { - ORDON_SWORD_INDEX, - MASTER_SWORD_INDEX, - WOOD_SHIELD_INDEX, - HYLIAN_SHIELD_INDEX, - HERO_TUNIC_INDEX, - ZORA_ARMOR_INDEX, - MAGIC_ARMOR_INDEX, - BOMB_CAPACITY_INDEX, - WALLET_INDEX, - ARROW_CAPACITY_INDEX, - ENDING_BLOW_INDEX, - SHIELD_BASH_INDEX, - BACKSLICE_INDEX, - HELM_SPLITTER_INDEX, - MORTAL_DRAW_INDEX, - JUMP_STRIKE_INDEX, - GREAT_SPIN_INDEX + EQUIPMENT_INDEX, + GOLDEN_BUG_INDEX, + HIDDEN_SKILL_INDEX, + SCENT_INDEX, + + PAUSE_INDEX_COUNT }; extern PauseData* pauseData; @@ -49,9 +22,5 @@ class PauseMenu : public Menu { virtual void draw(); private: - Line lines[17]; - - void resetIndex(); - void getEquipment(); - void setEquipment(); + Line lines[PAUSE_INDEX_COUNT]; }; \ No newline at end of file diff --git a/modules/menus/menu_pause/src/pause_menu.cpp b/modules/menus/menu_pause/src/pause_menu.cpp index 4f04ef9d..78e2594b 100644 --- a/modules/menus/menu_pause/src/pause_menu.cpp +++ b/modules/menus/menu_pause/src/pause_menu.cpp @@ -6,389 +6,98 @@ #include "rels/include/defines.h" #include "menus/utils/menu_mgr.h" -#define MAX_ORDON_SWORD_OPT 3 -#define MAX_MASTER_SWORD_OPT 3 -#define MAX_WOOD_SHIELD_OPT 3 -#define MAX_HYLIAN_SHIELD_OPT 2 -#define MAX_HERO_TUNIC_OPT 2 -#define MAX_ZORA_ARMOR_OPT 2 -#define MAX_MAGIC_ARMOR_OPT 2 -#define MAX_BOMB_CAPACITY_OPT 2 -#define MAX_WALLET_OPT 3 -#define MAX_ARROW_CAPACITY_OPT 3 -#define MAX_HIDDEN_SKILL_OPT 2 +#define MAX_SCENT_OPT 6 KEEP_VAR PauseData* pauseData; KEEP_FUNC PauseMenu::PauseMenu(Cursor& cursor) : Menu(cursor), - lines{{"ordon sword:", ORDON_SWORD_INDEX, "Wooden Sword / Ordon Sword", false, nullptr, - MAX_ORDON_SWORD_OPT}, - {"master sword:", MASTER_SWORD_INDEX, "Master Sword / Light Sword", false, nullptr, - MAX_MASTER_SWORD_OPT}, - {"wooden shield:", WOOD_SHIELD_INDEX, "Ordon Shield / Wooden Shield", false, nullptr, - MAX_WOOD_SHIELD_OPT}, - {"hylian shield:", HYLIAN_SHIELD_INDEX, "Hylian Shield", false, nullptr, - MAX_HYLIAN_SHIELD_OPT}, - {"hero's tunic:", HERO_TUNIC_INDEX, "Hero's Tunic", false, nullptr, MAX_HERO_TUNIC_OPT}, - {"zora armor:", ZORA_ARMOR_INDEX, "Zora Armor", false, nullptr, MAX_ZORA_ARMOR_OPT}, - {"magic armor:", MAGIC_ARMOR_INDEX, "Magic Armor", false, nullptr, MAX_MAGIC_ARMOR_OPT}, - {"bomb capacity:", BOMB_CAPACITY_INDEX, "Bomb Bag Capacity", false, nullptr, - MAX_BOMB_CAPACITY_OPT}, - {"wallet upgrade:", WALLET_INDEX, "Wallet Capacity", false, nullptr, MAX_WALLET_OPT}, - {"arrow capacity:", ARROW_CAPACITY_INDEX, "Arrow Quiver Capacity", false, nullptr, - MAX_ARROW_CAPACITY_OPT}, - {"ending blow:", ENDING_BLOW_INDEX, "Ending Blow", true, [](){return pauseData->l_ebFlag;}}, - {"shield bash:", SHIELD_BASH_INDEX, "Shield Bash", true, [](){return pauseData->l_sbFlag;}}, - {"backslice:", BACKSLICE_INDEX, "Backslice", true, [](){return pauseData->l_bsFlag;}}, - {"helm splitter:", HELM_SPLITTER_INDEX, "Helm Splitter", true, [](){return pauseData->l_hsFlag;}}, - {"mortal draw:", MORTAL_DRAW_INDEX, "Mortal Draw", true, [](){return pauseData->l_mdFlag;}}, - {"jump strike:", JUMP_STRIKE_INDEX, "Jump Strike", true, [](){return pauseData->l_jsFlag;}}, - {"greatspin:", GREAT_SPIN_INDEX, "Greatspin", true, [](){return pauseData->l_gsFlag;}}} {} + lines{{"equipment", EQUIPMENT_INDEX, "Equipment", false, nullptr}, + {"golden bugs", GOLDEN_BUG_INDEX, "Golden Bugs", false, nullptr}, + {"hidden skills", HIDDEN_SKILL_INDEX, "Hidden Skills", false, nullptr}, + {"scent:", SCENT_INDEX, "Current Scent", false, nullptr}} {} PauseMenu::~PauseMenu() {} -void PauseMenu::resetIndex() { - pauseData->l_ordonSword_idx = 0; - pauseData->l_masterSword_idx = 0; - pauseData->l_woodShield_idx = 0; - pauseData->l_hyShield_idx = 0; - pauseData->l_tunic_idx = 0; - pauseData->l_zoraArmor_idx = 0; - pauseData->l_magicArmor_idx = 0; - pauseData->l_bombCap_idx = 0; - pauseData->l_wallet_idx = 0; - pauseData->l_arrowCap_idx = 0; -} - -void PauseMenu::getEquipment() { - if (dComIfGs_isItemFirstBit(SWORD)) { - pauseData->l_ordonSword_idx = 2; - } else if (dComIfGs_isItemFirstBit(WOOD_STICK)) { - pauseData->l_ordonSword_idx = 1; - } - - if (dComIfGs_isItemFirstBit(LIGHT_SWORD)) { - pauseData->l_masterSword_idx = 2; - } else if (dComIfGs_isItemFirstBit(MASTER_SWORD)) { - pauseData->l_masterSword_idx = 1; - } - - if (dComIfGs_isItemFirstBit(SHIELD)) { - pauseData->l_woodShield_idx = 2; - } else if (dComIfGs_isItemFirstBit(WOOD_SHIELD)) { - pauseData->l_woodShield_idx = 1; - } - - if (dComIfGs_isItemFirstBit(HYLIA_SHIELD)) { - pauseData->l_hyShield_idx = 1; - } - - if (dComIfGs_isItemFirstBit(WEAR_KOKIRI)) { - pauseData->l_tunic_idx = 1; - } - - if (dComIfGs_isItemFirstBit(WEAR_ZORA)) { - pauseData->l_zoraArmor_idx = 1; - } - - if (dComIfGs_isItemFirstBit(ARMOR)) { - pauseData->l_magicArmor_idx = 1; - } - - if (dComIfGs_isItemFirstBit(BOMB_BAG_LV2)) { - pauseData->l_bombCap_idx = 1; - } - - switch (dComIfGs_getWalletSize()) { - case 1: - pauseData->l_wallet_idx = 1; - break; - case 2: - pauseData->l_wallet_idx = 2; - break; - } - - if (dComIfGs_getArrowMax() == 100) { - pauseData->l_arrowCap_idx = 2; - } else if (dComIfGs_getArrowMax() == 60) { - pauseData->l_arrowCap_idx = 1; - } -} - -void PauseMenu::setEquipment() { - switch (pauseData->l_ordonSword_idx) { - case 0: - dComIfGs_offItemFirstBit(WOOD_STICK); - dComIfGs_offItemFirstBit(SWORD); - break; - case 1: - dComIfGs_onItemFirstBit(WOOD_STICK); - dComIfGs_offItemFirstBit(SWORD); - break; - case 2: - dComIfGs_onItemFirstBit(SWORD); - dComIfGs_offItemFirstBit(WOOD_STICK); - break; - } - - switch (pauseData->l_masterSword_idx) { - case 0: - dComIfGs_offItemFirstBit(MASTER_SWORD); - dComIfGs_offItemFirstBit(LIGHT_SWORD); - break; - case 1: - dComIfGs_onItemFirstBit(MASTER_SWORD); - dComIfGs_offItemFirstBit(LIGHT_SWORD); - break; - case 2: - dComIfGs_onItemFirstBit(LIGHT_SWORD); - break; - } - - switch (pauseData->l_woodShield_idx) { - case 0: - dComIfGs_offItemFirstBit(SHIELD); - dComIfGs_offItemFirstBit(WOOD_SHIELD); - break; - case 1: - dComIfGs_onItemFirstBit(WOOD_SHIELD); - break; - case 2: - dComIfGs_onItemFirstBit(SHIELD); - break; - } - - switch (pauseData->l_hyShield_idx) { - case 0: - dComIfGs_offItemFirstBit(HYLIA_SHIELD); - break; - case 1: - dComIfGs_onItemFirstBit(HYLIA_SHIELD); - break; - } - - switch (pauseData->l_tunic_idx) { - case 0: - dComIfGs_offItemFirstBit(WEAR_KOKIRI); - break; - case 1: - dComIfGs_onItemFirstBit(WEAR_KOKIRI); - break; - } - - switch (pauseData->l_zoraArmor_idx) { - case 0: - dComIfGs_offItemFirstBit(WEAR_ZORA); - break; - case 1: - dComIfGs_onItemFirstBit(WEAR_ZORA); - break; - } - - switch (pauseData->l_magicArmor_idx) { - case 0: - dComIfGs_offItemFirstBit(ARMOR); - break; - case 1: - dComIfGs_onItemFirstBit(ARMOR); - break; - } +void PauseMenu::draw() { + cursor.setMode(Cursor::MODE_LIST); - switch (pauseData->l_bombCap_idx) { - case 0: - dComIfGs_offItemFirstBit(BOMB_BAG_LV2); + switch (dComIfGs_getCollectSmell()) { + case 180: + pauseData->l_scent_idx = 1; break; - case 1: - dComIfGs_onItemFirstBit(BOMB_BAG_LV2); - break; - } - - switch (pauseData->l_wallet_idx) { - case 0: - dComIfGs_setWalletSize(WALLET); + case 176: + pauseData->l_scent_idx = 2; break; - case 1: - dComIfGs_setWalletSize(BIG_WALLET); + case 178: + pauseData->l_scent_idx = 3; break; - case 2: - dComIfGs_setWalletSize(GIANT_WALLET); + case 179: + pauseData->l_scent_idx = 4; break; - } - - switch (pauseData->l_arrowCap_idx) { - case 0: - dComIfGs_setArrowMax(30); + case 181: + pauseData->l_scent_idx = 5; break; - case 1: - dComIfGs_setArrowMax(60); - break; - case 2: - dComIfGs_setArrowMax(100); - break; - } -} - -void PauseMenu::draw() { - static bool init = false; - cursor.setMode(Cursor::MODE_LIST); + default: + pauseData->l_scent_idx = 0; - if (!init) { - getEquipment(); - init = true; } if (GZ_getButtonTrig(BACK_BUTTON)) { - init = false; g_menuMgr->pop(); - resetIndex(); return; } - // update hidden skill flags - pauseData->l_ebFlag = dComIfGs_isEventBit(0x2904); - pauseData->l_sbFlag = dComIfGs_isEventBit(0x2908); - pauseData->l_bsFlag = dComIfGs_isEventBit(0x2902); - pauseData->l_hsFlag = dComIfGs_isEventBit(0x2901); - pauseData->l_mdFlag = dComIfGs_isEventBit(0x2A80); - pauseData->l_jsFlag = dComIfGs_isEventBit(0x2A40); - pauseData->l_gsFlag = dComIfGs_isEventBit(0x2A20); - - ListMember ordonSword_opt[3] = {"none", "wooden sword", "ordon sword"}; - ListMember masterSword_opt[3] = {"none", "master sword", "light sword"}; - ListMember woodShield_opt[3] = {"none", "ordon shield", "wooden shield"}; - ListMember hyShield_opt[2] = {"none", "hylian shield"}; - ListMember tunic_opt[2] = {"none", "hero's tunic"}; - ListMember zoraArmor_opt[2] = {"none", "zora armor"}; - ListMember magicArmor_opt[2] = {"none", "magic armor"}; - ListMember bombCap_opt[2] = {"30/15/10", "60/30/20"}; - ListMember wallet_opt[3] = {"300 Rupees", "600 Rupees", "1000 Rupees"}; - ListMember arrowCap_opt[3] = {"30 Arrows", "60 Arrows", "100 Arrows"}; + ListMember scent_opt[6] = {"none", "youths' scent", "scent of ilia", "poe scent", "reekfish scent", "medicine scent"}; switch (cursor.y) { - case ORDON_SWORD_INDEX: - cursor.x = pauseData->l_ordonSword_idx; - cursor.move(MAX_ORDON_SWORD_OPT, MENU_LINE_NUM); + case SCENT_INDEX: + cursor.x = pauseData->l_scent_idx; + cursor.move(MAX_SCENT_OPT, MENU_LINE_NUM); - if (cursor.y == ORDON_SWORD_INDEX) { - pauseData->l_ordonSword_idx = cursor.x; + if (cursor.y == SCENT_INDEX) { + pauseData->l_scent_idx = cursor.x; } break; - case MASTER_SWORD_INDEX: - cursor.x = pauseData->l_masterSword_idx; - cursor.move(MAX_MASTER_SWORD_OPT, MENU_LINE_NUM); - - if (cursor.y == MASTER_SWORD_INDEX) { - pauseData->l_masterSword_idx = cursor.x; - } - break; - case WOOD_SHIELD_INDEX: - cursor.x = pauseData->l_woodShield_idx; - cursor.move(MAX_WOOD_SHIELD_OPT, MENU_LINE_NUM); - - if (cursor.y == WOOD_SHIELD_INDEX) { - pauseData->l_woodShield_idx = cursor.x; - } - break; - case HYLIAN_SHIELD_INDEX: - cursor.x = pauseData->l_hyShield_idx; - cursor.move(MAX_HYLIAN_SHIELD_OPT, MENU_LINE_NUM); - - if (cursor.y == HYLIAN_SHIELD_INDEX) { - pauseData->l_hyShield_idx = cursor.x; - } + default: + cursor.move(0, MENU_LINE_NUM); break; - case HERO_TUNIC_INDEX: - cursor.x = pauseData->l_tunic_idx; - cursor.move(MAX_HERO_TUNIC_OPT, MENU_LINE_NUM); + } - if (cursor.y == HERO_TUNIC_INDEX) { - pauseData->l_tunic_idx = cursor.x; + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + switch (cursor.y) { + case EQUIPMENT_INDEX: + g_menuMgr->push(MN_EQUIPMENT_INDEX); + return; + case GOLDEN_BUG_INDEX: + g_menuMgr->push(MN_GOLDEN_BUGS_INDEX); + return; + case HIDDEN_SKILL_INDEX: + g_menuMgr->push(MN_HIDDEN_SKILLS_INDEX); } - break; - case ZORA_ARMOR_INDEX: - cursor.x = pauseData->l_zoraArmor_idx; - cursor.move(MAX_ZORA_ARMOR_OPT, MENU_LINE_NUM); + } - if (cursor.y == ZORA_ARMOR_INDEX) { - pauseData->l_zoraArmor_idx = cursor.x; - } + switch (pauseData->l_scent_idx) { + case 1: + dComIfGs_setCollectSmell(180); break; - case MAGIC_ARMOR_INDEX: - cursor.x = pauseData->l_magicArmor_idx; - cursor.move(MAX_MAGIC_ARMOR_OPT, MENU_LINE_NUM); - - if (cursor.y == MAGIC_ARMOR_INDEX) { - pauseData->l_magicArmor_idx = cursor.x; - } + case 2: + dComIfGs_setCollectSmell(176); break; - case BOMB_CAPACITY_INDEX: - cursor.x = pauseData->l_bombCap_idx; - cursor.move(MAX_BOMB_CAPACITY_OPT, MENU_LINE_NUM); - - if (cursor.y == BOMB_CAPACITY_INDEX) { - pauseData->l_bombCap_idx = cursor.x; - } + case 3: + dComIfGs_setCollectSmell(178); break; - case WALLET_INDEX: - cursor.x = pauseData->l_wallet_idx; - cursor.move(MAX_WALLET_OPT, MENU_LINE_NUM); - - if (cursor.y == WALLET_INDEX) { - pauseData->l_wallet_idx = cursor.x; - } + case 4: + dComIfGs_setCollectSmell(179); break; - case ARROW_CAPACITY_INDEX: - cursor.x = pauseData->l_arrowCap_idx; - cursor.move(MAX_ARROW_CAPACITY_OPT, MENU_LINE_NUM); - - if (cursor.y == ARROW_CAPACITY_INDEX) { - pauseData->l_arrowCap_idx = cursor.x; - } + case 5: + dComIfGs_setCollectSmell(181); break; default: - cursor.move(0, MENU_LINE_NUM); - break; + dComIfGs_setCollectSmell(255); } - if (GZ_getButtonTrig(SELECTION_BUTTON)) { - switch (cursor.y) { - case ENDING_BLOW_INDEX: - setEventFlag(0x2904); - break; - case SHIELD_BASH_INDEX: - setEventFlag(0x2908); - break; - case BACKSLICE_INDEX: - setEventFlag(0x2902); - break; - case HELM_SPLITTER_INDEX: - setEventFlag(0x2901); - break; - case MORTAL_DRAW_INDEX: - setEventFlag(0x2A80); - break; - case JUMP_STRIKE_INDEX: - setEventFlag(0x2A40); - break; - case GREAT_SPIN_INDEX: - setEventFlag(0x2A20); - break; - } - } - - setEquipment(); - - lines[ORDON_SWORD_INDEX].printf(" <%s>", ordonSword_opt[pauseData->l_ordonSword_idx].member); - lines[MASTER_SWORD_INDEX].printf(" <%s>", masterSword_opt[pauseData->l_masterSword_idx].member); - lines[WOOD_SHIELD_INDEX].printf(" <%s>", woodShield_opt[pauseData->l_woodShield_idx].member); - lines[HYLIAN_SHIELD_INDEX].printf(" <%s>", hyShield_opt[pauseData->l_hyShield_idx].member); - lines[HERO_TUNIC_INDEX].printf(" <%s>", tunic_opt[pauseData->l_tunic_idx].member); - lines[ZORA_ARMOR_INDEX].printf(" <%s>", zoraArmor_opt[pauseData->l_zoraArmor_idx].member); - lines[MAGIC_ARMOR_INDEX].printf(" <%s>", magicArmor_opt[pauseData->l_magicArmor_idx].member); - lines[BOMB_CAPACITY_INDEX].printf(" <%s>", bombCap_opt[pauseData->l_bombCap_idx].member); - lines[WALLET_INDEX].printf(" <%s>", wallet_opt[pauseData->l_wallet_idx].member); - lines[ARROW_CAPACITY_INDEX].printf(" <%s>", arrowCap_opt[pauseData->l_arrowCap_idx].member); + lines[SCENT_INDEX].printf(" <%s>", scent_opt[pauseData->l_scent_idx].member); GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); } diff --git a/modules/menus/menu_pos_settings/src/position_settings_menu.cpp b/modules/menus/menu_pos_settings/src/position_settings_menu.cpp index f942aaa0..249bf25d 100644 --- a/modules/menus/menu_pos_settings/src/position_settings_menu.cpp +++ b/modules/menus/menu_pos_settings/src/position_settings_menu.cpp @@ -18,6 +18,8 @@ KEEP_FUNC PosSettingsMenu::PosSettingsMenu(Cursor& cursor, PosSettingsData& data {"input viewer", SpritesIndex::VIEWER_INDEX, "Change input viewer position", false}, {"link debug info", SpritesIndex::DEBUG_INFO_INDEX, "Change link debug info position", false}, + {"stage info", SpritesIndex::STAGE_INFO_INDEX, "Change link stage info position", + false}, {"timer", SpritesIndex::TIMER_SPR_INDEX, "Change timer position", false}, {"load timer", SpritesIndex::LOAD_TIMER_SPR_INDEX, "Change load timer position", false}, {"igt timer", SpritesIndex::IGT_TIMER_SPR_INDEX, "Change IGT timer position", false}, @@ -48,6 +50,7 @@ GZSettingID l_mapping[] = { STNG_SPRITES_MENU, STNG_SPRITES_INPUT_VIEWER, STNG_SPRITES_DEBUG_INFO, + STNG_SPRITES_STAGE_INFO, STNG_SPRITES_TIMER_SPR, STNG_SPRITES_LOAD_TIMER_SPR, STNG_SPRITES_IGT_TIMER_SPR, diff --git a/modules/menus/menu_practice/include/practice_menu.h b/modules/menus/menu_practice/include/practice_menu.h index c66a8f65..0a9c14bb 100644 --- a/modules/menus/menu_practice/include/practice_menu.h +++ b/modules/menus/menu_practice/include/practice_menu.h @@ -6,7 +6,7 @@ #ifdef GCN_PLATFORM #define PRACTICE_MENU_NUM 6 #elif defined WII_PLATFORM -#define PRACTICE_MENU_NUM 4 +#define PRACTICE_MENU_NUM 5 #endif class PracticeMenu : public Menu { diff --git a/modules/menus/menu_practice/src/practice_menu.cpp b/modules/menus/menu_practice/src/practice_menu.cpp index 15f00994..f1cd0992 100644 --- a/modules/menus/menu_practice/src/practice_menu.cpp +++ b/modules/menus/menu_practice/src/practice_menu.cpp @@ -6,9 +6,7 @@ KEEP_FUNC PracticeMenu::PracticeMenu(Cursor& cursor) : Menu(cursor), lines{ {"any%", ANY_INDEX, "Any% practice saves", false}, -#ifdef GCN_PLATFORM {"any% BiTE", ANY_BITE_INDEX, "Any% (BiTE route) practice saves", false}, -#endif {"100%", HUNDO_INDEX, "100% practice saves", false}, {"all dungeons", AD_INDEX, "All Dungeons practice saves", false}, #ifdef GCN_PLATFORM @@ -30,11 +28,9 @@ void PracticeMenu::draw() { case ANY_INDEX: g_menuMgr->push(MN_ANY_SAVES_INDEX); return; -#ifdef GCN_PLATFORM case ANY_BITE_INDEX: g_menuMgr->push(MN_ANY_BITE_SAVES_INDEX); return; -#endif case HUNDO_INDEX: g_menuMgr->push(MN_HUNDO_SAVES_INDEX); return; diff --git a/modules/menus/menu_rupee_flags/CMakeLists.txt b/modules/menus/menu_rupee_flags/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_rupee_flags/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_rupee_flags/include/main.h b/modules/menus/menu_rupee_flags/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_rupee_flags/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_rupee_flags/include/rupee_flags_menu.h b/modules/menus/menu_rupee_flags/include/rupee_flags_menu.h new file mode 100644 index 00000000..800fd1fb --- /dev/null +++ b/modules/menus/menu_rupee_flags/include/rupee_flags_menu.h @@ -0,0 +1,32 @@ +#pragma once +#include "menus/menu.h" + +struct RupeeFlagsData { + u16 l_donationAmount; + u16 l_fundraisingAmount; + bool l_fundraising1; + bool l_fundraising2; + bool l_rupeeFlag; +}; + +enum GeneralFlagsIndex { + DONATION_AMT_INDEX, + FUNDRAISING_AMT_INDEX, + FUNDRAISING_1_INDEX, + FUNDRAISING_2_INDEX, + RUPEE_CS_FLAG_INDEX, + + RUPEE_FLAGS_COUNT +}; + +extern RupeeFlagsData* rupeeFlagsData; + +class RupeeFlagsMenu : public Menu { +public: + RupeeFlagsMenu(Cursor&); + virtual ~RupeeFlagsMenu(); + virtual void draw(); + +private: + Line lines[RUPEE_FLAGS_COUNT]; +}; diff --git a/modules/menus/menu_rupee_flags/src/main.cpp b/modules/menus/menu_rupee_flags/src/main.cpp new file mode 100644 index 00000000..679cc18b --- /dev/null +++ b/modules/menus/menu_rupee_flags/src/main.cpp @@ -0,0 +1,56 @@ +#include +#include "menus/menu_rupee_flags/include/rupee_flags_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +RupeeFlagsMenu* l_menu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + g_menuMgr->setPersistentData(new RupeeFlagsData); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + rupeeFlagsData = g_menuMgr->getPersistentData(); + l_menu = new RupeeFlagsMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_menu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_menu; +} + +void onDelete() { + auto data = g_menuMgr->getPersistentData(); + delete data; + g_menuMgr->setPersistentData(nullptr); +} diff --git a/modules/menus/menu_rupee_flags/src/rupee_flags_menu.cpp b/modules/menus/menu_rupee_flags/src/rupee_flags_menu.cpp new file mode 100644 index 00000000..b47acae1 --- /dev/null +++ b/modules/menus/menu_rupee_flags/src/rupee_flags_menu.cpp @@ -0,0 +1,109 @@ +#include "menus/menu_rupee_flags/include/rupee_flags_menu.h" +#include "gz_flags.h" +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/utils.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +KEEP_VAR RupeeFlagsData* rupeeFlagsData; + +KEEP_FUNC RupeeFlagsMenu::RupeeFlagsMenu(Cursor& cursor) + : Menu(cursor), + lines{ + {"donation amount:", DONATION_AMT_INDEX, "Sets the amount of rupees donated to Charlo"}, + {"fundraising amount:", FUNDRAISING_AMT_INDEX, "Sets the current fundraising amount"}, + {"fundraising 1", FUNDRAISING_1_INDEX, "Toggle flag for first fundraising being complete", true, + [](){return rupeeFlagsData->l_fundraising1;}}, + {"fundraising 2", FUNDRAISING_2_INDEX, "Toggle flag for second fundraising being complete", true, + [](){return rupeeFlagsData->l_fundraising2;}}, + {"rupee cutscenes", RUPEE_CS_FLAG_INDEX, "Toggle rupee cutscenes being enabled", true, + [](){return rupeeFlagsData->l_rupeeFlag;}}, + } {} + +RupeeFlagsMenu::~RupeeFlagsMenu() {} + +void RupeeFlagsMenu::draw() { + cursor.setMode(Cursor::MODE_LIST); + + if (!rupeeFlagsData) { + return; + } + + // update flags + rupeeFlagsData->l_fundraising1 = dComIfGs_isEventBit(0x2e20); + rupeeFlagsData->l_fundraising2 = dComIfGs_isEventBit(0x0f10); + + // update donation amount + u8 donation_high_bits = dComIfGs_getEventReg(0xf7ff); + u8 donation_low_bits = dComIfGs_getEventReg(0xf8ff); + + rupeeFlagsData->l_donationAmount = donation_high_bits << 8 | donation_low_bits; + + // update fundraising amount + u8 fund_high_bits = dComIfGs_getEventReg(0xf9ff); + u8 fund_low_bits = dComIfGs_getEventReg(0xfaff); + + rupeeFlagsData->l_fundraisingAmount = fund_high_bits << 8 | fund_low_bits; + + for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { + if (dComIfGs_isItemFirstBit(i)) { + rupeeFlagsData->l_rupeeFlag = true; + break; + } + } + + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + switch (cursor.y) { + case DONATION_AMT_INDEX: + Cursor::moveList(rupeeFlagsData->l_donationAmount); + + if (rupeeFlagsData->l_donationAmount > 1000) + rupeeFlagsData->l_donationAmount = 1000; + + dComIfGs_setEventReg(0xf7ff, (rupeeFlagsData->l_donationAmount >> 8) & 0xFF); + dComIfGs_setEventReg(0xf8ff, rupeeFlagsData->l_donationAmount & 0xFF); + break; + case FUNDRAISING_AMT_INDEX: + Cursor::moveList(rupeeFlagsData->l_fundraisingAmount); + + if (rupeeFlagsData->l_fundraisingAmount > 2000) + rupeeFlagsData->l_fundraisingAmount = 2000; + + dComIfGs_setEventReg(0xf9ff, (rupeeFlagsData->l_fundraisingAmount >> 8) & 0xFF); + dComIfGs_setEventReg(0xfaff, rupeeFlagsData->l_fundraisingAmount & 0xFF); + break; + } + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + switch (cursor.y) { + case FUNDRAISING_1_INDEX: + setEventFlag(0x2e20); + break; + case FUNDRAISING_2_INDEX: + setEventFlag(0x0f10); + break; + case RUPEE_CS_FLAG_INDEX: + if (rupeeFlagsData->l_rupeeFlag) { + for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { + dComIfGs_offItemFirstBit(i); + } + rupeeFlagsData->l_rupeeFlag = false; + } else { + for (int i = BLUE_RUPEE; i <= SILVER_RUPEE; i++) { + dComIfGs_onItemFirstBit(i); + } + } + break; + } + } + + lines[DONATION_AMT_INDEX].printf(" <%d>", rupeeFlagsData->l_donationAmount); + lines[FUNDRAISING_AMT_INDEX].printf(" <%d>", rupeeFlagsData->l_fundraisingAmount); + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_scene/src/scene_menu.cpp b/modules/menus/menu_scene/src/scene_menu.cpp index 9f7fc36c..72d9c06e 100644 --- a/modules/menus/menu_scene/src/scene_menu.cpp +++ b/modules/menus/menu_scene/src/scene_menu.cpp @@ -36,6 +36,7 @@ KEEP_FUNC SceneMenu::SceneMenu(Cursor& cursor) {"collision viewer", COLLISION_VIEW_INDEX, "Change Collision Viewer settings", false}, {"projection viewer", PROJECTION_VIEW_INDEX, "Change Projection Viewer settings", false}, {"trigger viewer", TRIGGER_VIEW_INDEX, "Change Trigger Viewer settings", false}, + {"sound test", SOUND_TEST_INDEX, "Play a specified sound effect", false}, } {} SceneMenu::~SceneMenu() {} @@ -95,6 +96,9 @@ void SceneMenu::draw() { case TRIGGER_VIEW_INDEX: g_menuMgr->push(MN_TRIGGER_VIEW_INDEX); return; + case SOUND_TEST_INDEX: + g_menuMgr->push(MN_SOUND_TEST_INDEX); + return; } } diff --git a/modules/menus/menu_sound_test/CMakeLists.txt b/modules/menus/menu_sound_test/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_sound_test/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_sound_test/include/main.h b/modules/menus/menu_sound_test/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_sound_test/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_sound_test/include/sound_test_menu.h b/modules/menus/menu_sound_test/include/sound_test_menu.h new file mode 100644 index 00000000..19453bfb --- /dev/null +++ b/modules/menus/menu_sound_test/include/sound_test_menu.h @@ -0,0 +1,11 @@ +#include "menus/menu.h" + +class SoundTestMenu : public Menu { +public: + SoundTestMenu(Cursor&); + virtual ~SoundTestMenu(); + virtual void draw(); + +private: + Line lines[4]; +}; diff --git a/modules/menus/menu_sound_test/src/main.cpp b/modules/menus/menu_sound_test/src/main.cpp new file mode 100644 index 00000000..ffeba234 --- /dev/null +++ b/modules/menus/menu_sound_test/src/main.cpp @@ -0,0 +1,50 @@ +#include +#include "menus/menu_sound_test/include/sound_test_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +SoundTestMenu* l_menu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + l_menu = new SoundTestMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_menu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_menu; +} + +void onDelete() {} diff --git a/modules/menus/menu_sound_test/src/sound_test_menu.cpp b/modules/menus/menu_sound_test/src/sound_test_menu.cpp new file mode 100644 index 00000000..636880f9 --- /dev/null +++ b/modules/menus/menu_sound_test/src/sound_test_menu.cpp @@ -0,0 +1,64 @@ +#include "menus/menu_sound_test/include/sound_test_menu.h" +#include +#include "settings.h" +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "libtp_c/include/f_op/f_op_actor_mng.h" +#include "libtp_c/include/m_Do/m_Do_printf.h" +#include "libtp_c/include/m_Do/m_Do_audio.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +KEEP_FUNC SoundTestMenu::SoundTestMenu(Cursor& cursor) + : Menu(cursor), lines{ + {"category id:", 0, "Select Sound Category ID", false}, + {"sound id:", 1, "Select Sound Effect ID", false}, + {"play", 2, "Play Sound Effect", false}, + {"stop", 3, "Stop Sound Effect", false}, + } {} + +SoundTestMenu::~SoundTestMenu() {} + +void SoundTestMenu::draw() { + cursor.setMode(Cursor::MODE_LIST); + static u32 l_categoryID = 0; + static u32 l_soundID = 0; + + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + switch (cursor.y) { + case 0: + Cursor::moveList(l_categoryID); + if (l_categoryID > 9) { + l_categoryID = 0; + } + break; + case 1: + Cursor::moveList(l_soundID); + if (l_soundID > 0xFFFF) { + l_soundID = 0; + } + break; + } + + u32 composite_id = (l_categoryID << 0x10) | l_soundID; + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + switch (cursor.y) { + case 2: + mDoAud_seStart(composite_id, nullptr, 0, 0); + break; + case 3: + mDoAud_seStop(composite_id, 0); + break; + } + } + + lines[0].printf(" <%d>", l_categoryID); + lines[1].printf(" <%d>", l_soundID); + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} \ No newline at end of file diff --git a/modules/menus/menu_tools/include/tools_menu.h b/modules/menus/menu_tools/include/tools_menu.h index 2043c905..34d27c12 100644 --- a/modules/menus/menu_tools/include/tools_menu.h +++ b/modules/menus/menu_tools/include/tools_menu.h @@ -3,45 +3,12 @@ #include "menus/menu.h" #include "tools.h" -#ifdef GCN_PLATFORM -#define FRAME_ADVANCE_TEXT "R + D-Pad Up" -#define FRAME_PAUSE_TEXT "R" -#define GORGE_VOID_TEXT "L+Z" -#define STORE_POSITION_TEXT "D-PAD up + R" -#define LOAD_POSITION_TEXT "D-PAD down + R" -#define RELOAD_AREA_TEXT "L+R+A+Start" -#define TIMER_TOGGLE_TEXT "Z+A" -#define TIMER_RESET_TEXT "Z+B" -#define FREE_CAM_TEXT "Z+B+A" -#define MOVE_LINK_TEXT "L+R+Y" -#endif - -#ifdef WII_PLATFORM -#define FRAME_ADVANCE_TEXT "Z+C+Plus+Minus" -#define FRAME_PAUSE_TEXT "2" -#define GORGE_VOID_TEXT "Z+C+A+1" -#define BACK_IN_TIME_TEXT "Z+C+A+2" -#define STORE_POSITION_TEXT "Z+C+1" -#define LOAD_POSITION_TEXT "Z+C+2" -#define RELOAD_AREA_TEXT "Z+C+B+2" -#define TIMER_TOGGLE_TEXT "Z+C+A+B" -#define TIMER_RESET_TEXT "Z+C+B+1" -#define FREE_CAM_TEXT "Z+C+B+Minus" -#define MOVE_LINK_TEXT "Z+C+B+Plus" -#endif - -struct ToolsData { - uint8_t l_tunicCol_idx; -}; - class ToolsMenu : public Menu { public: - ToolsMenu(Cursor&, ToolsData&); + ToolsMenu(Cursor&); virtual ~ToolsMenu(); virtual void draw(); private: - uint8_t& l_tunicCol_idx; - Line lines[TOOLS_COUNT]; }; \ No newline at end of file diff --git a/modules/menus/menu_tools/src/main.cpp b/modules/menus/menu_tools/src/main.cpp index 2eb088f6..9f2b0b2e 100644 --- a/modules/menus/menu_tools/src/main.cpp +++ b/modules/menus/menu_tools/src/main.cpp @@ -28,15 +28,13 @@ void exit() { } // namespace tpgz::modules void onCreate() { - g_menuMgr->setPersistentData(new ToolsData()); if (!g_menuMgr->getPermanentData()) { g_menuMgr->setPermanentData(new Cursor); } } void onLoad() { - l_toolsMenu = new ToolsMenu(*g_menuMgr->getPermanentData(), - *g_menuMgr->getPersistentData()); + l_toolsMenu = new ToolsMenu(*g_menuMgr->getPermanentData()); g_drawListener->addListener(onDraw); } @@ -49,8 +47,4 @@ void onUnload() { delete l_toolsMenu; } -void onDelete() { - auto data = g_menuMgr->getPersistentData(); - delete data; - g_menuMgr->setPersistentData(nullptr); -} +void onDelete() {} diff --git a/modules/menus/menu_tools/src/tools_menu.cpp b/modules/menus/menu_tools/src/tools_menu.cpp index 51f77ff0..7ccbc7c7 100644 --- a/modules/menus/menu_tools/src/tools_menu.cpp +++ b/modules/menus/menu_tools/src/tools_menu.cpp @@ -1,299 +1,43 @@ #include "menus/menu_tools/include/tools_menu.h" -#include -#include "commands.h" -#include "global_data.h" -#include "timer.h" -#include "libtp_c/include/d/com/d_com_inf_game.h" -#include "gz_flags.h" -#include "rels/include/defines.h" -#include "rels/include/defines.h" #include "menus/utils/menu_mgr.h" -#ifdef GCN_PLATFORM -#define FREE_CAM_MOVEMENT_TEXT "Stick/L/R" -#define FREE_CAM_VIEW_TEXT "C-stick" -#define MOVE_LINK_MOVEMENT_TEXT "Stick/C" -#define MOVE_LINK_ANGLE_TEXT "C-left/right" -#define PREVIOUS_TUNIC_COLOR GZPad::Y -#define PREVIOUS_TUNIC_COLOR_TEXT "Y" -#define NEXT_TUNIC_COLOR GZPad::X -#define NEXT_TUNIC_COLOR_TEXT "X" -#endif -#ifdef WII_PLATFORM -#define FREE_CAM_MOVEMENT_TEXT "Stick+DPad" -#define FREE_CAM_VIEW_TEXT "C+Stick" -#define MOVE_LINK_MOVEMENT_TEXT "Stick" -#define MOVE_LINK_ANGLE_TEXT "C+Stick" -#define PREVIOUS_TUNIC_COLOR GZPad::TWO -#define PREVIOUS_TUNIC_COLOR_TEXT "TWO" -#define NEXT_TUNIC_COLOR GZPad::ONE -#define NEXT_TUNIC_COLOR_TEXT "ONE" -#endif - -#define MAX_TUNIC_COLORS 7 - -const char l_descTemplates[TOOLS_COUNT][100] = { - "use %s to reload current area", - "use %s to pause, %s to frame advance", - "reduces bonk animation significantly", - "link's movement is much faster", - "use %s to warp to kakariko gorge", -#ifdef WII_PLATFORM - "use %s to warp to ordon bridge", -#endif - "show frame info when doing coro td", - "practice snowpeak universal map delay timing", - "show current inputs", - "show Link's position, angle, and speed", - "show Heap size info", - "link won't sink in sand", - "frame counter for chaining rolls", - "display A/B button mashing speeds", - "%s to set, %s to load", - "simulates turbo controller inputs", - "frame timer: %s to start/stop, %s to reset", - "loading zone timer: %s to reset", - "In-game time timer: %s to start/stop, %s to reset", - FREE_CAM_TEXT " to activate, " FREE_CAM_MOVEMENT_TEXT " to move, " FREE_CAM_VIEW_TEXT - " to view, Z to speed", - MOVE_LINK_TEXT " to activate. " MOVE_LINK_MOVEMENT_TEXT " to move, " MOVE_LINK_ANGLE_TEXT - " to change angle", - "changes link's tunic color. " NEXT_TUNIC_COLOR_TEXT "/" PREVIOUS_TUNIC_COLOR_TEXT - " to cycle through colors", -}; - -KEEP_FUNC ToolsMenu::ToolsMenu(Cursor& cursor, ToolsData& data) - : Menu(cursor), l_tunicCol_idx(data.l_tunicCol_idx), - lines{{"area reload", RELOAD_AREA_INDEX, "use " RELOAD_AREA_TEXT " to reload current area", - true, ACTIVE_FUNC(STNG_TOOLS_RELOAD_AREA)}, - {"frame advance", FRAME_ADVANCE_INDEX, "use " FRAME_ADVANCE_TEXT " to pause, " FRAME_PAUSE_TEXT " to frame advance", - true, ACTIVE_FUNC(STNG_TOOLS_FRAME_ADVANCE)}, - {"fast bonk recovery", FAST_BONK_INDEX, "reduces bonk animation significantly", true, - ACTIVE_FUNC(STNG_TOOLS_FAST_BONK)}, - {"fast movement", FAST_MOVEMENT_INDEX, "link's movement is much faster", true, - ACTIVE_FUNC(STNG_TOOLS_FAST_MOVEMENT)}, - {"gorge checker", GORGE_INDEX, "use " GORGE_VOID_TEXT " to warp to kakariko gorge", - true, ACTIVE_FUNC(STNG_TOOLS_GORGE)}, -#ifdef WII_PLATFORM - {"bit checker", BIT_INDEX, "use " BACK_IN_TIME_TEXT " to warp to ordon bridge", true, - ACTIVE_FUNC(STNG_TOOLS_BIT)}, -#endif - {"coro td checker", COROTD_INDEX, "show frame info when doing coro td", true, - ACTIVE_FUNC(STNG_TOOLS_COROTD)}, - {"umd checker", UMD_INDEX, "practice snowpeak universal map delay timing", true, - ACTIVE_FUNC(STNG_TOOLS_UMD)}, - {"input viewer", INPUT_VIEWER_INDEX, "show current inputs", true, - ACTIVE_FUNC(STNG_TOOLS_INPUT_VIEWER)}, - {"link debug info", LINK_DEBUG_INDEX, "show Link's position, angle, and speed", true, - ACTIVE_FUNC(STNG_TOOLS_LINK_DEBUG)}, - {"heap debug info", HEAP_DEBUG_INDEX, "show Heap size info", true, - ACTIVE_FUNC(STNG_TOOLS_HEAP_DEBUG)}, - {"no sinking in sand", SAND_INDEX, "link won't sink in sand", true, - ACTIVE_FUNC(STNG_TOOLS_SAND)}, - {"roll checker", ROLL_INDEX, "frame counter for chaining rolls", true, - ACTIVE_FUNC(STNG_TOOLS_ROLL)}, - {"mash checker", MASH_CHECKER_INDEX, "display A/B button mashing speeds", true, - ACTIVE_FUNC(STNG_TOOLS_MASH_CHECKER)}, - {"teleport", TELEPORT_INDEX, - STORE_POSITION_TEXT " to set, " LOAD_POSITION_TEXT " to load", true, - ACTIVE_FUNC(STNG_TOOLS_TELEPORT)}, - {"turbo mode", TURBO_MODE_INDEX, "simulates turbo controller inputs", true, - ACTIVE_FUNC(STNG_TOOLS_TURBO_MODE)}, - {"timer", TIMER_INDEX, - "frame timer: " TIMER_TOGGLE_TEXT " to start/stop, " TIMER_RESET_TEXT " to reset", - true, ACTIVE_FUNC(STNG_TOOLS_TIMER)}, - {"load timer", LOAD_TIMER_INDEX, "loading zone timer: " TIMER_RESET_TEXT " to reset", - true, ACTIVE_FUNC(STNG_TOOLS_LOAD_TIMER)}, - {"igt timer", IGT_TIMER_INDEX, - "In-game time timer: " TIMER_TOGGLE_TEXT " to start/stop, " TIMER_RESET_TEXT - " to reset", - true, ACTIVE_FUNC(STNG_TOOLS_IGT_TIMER)}, - {"free cam", FREE_CAM_INDEX, - FREE_CAM_TEXT " to activate, " FREE_CAM_MOVEMENT_TEXT " to move, " FREE_CAM_VIEW_TEXT - " to view, Z to speed", - true, ACTIVE_FUNC(STNG_TOOLS_FREE_CAM)}, - {"move link", MOVE_LINK_INDEX, - MOVE_LINK_TEXT " to activate. " MOVE_LINK_MOVEMENT_TEXT - " to move, " MOVE_LINK_ANGLE_TEXT " to change angle", - true, ACTIVE_FUNC(STNG_TOOLS_MOVE_LINK)}, - {"link tunic color:", TUNIC_COLOR_INDEX, - "changes link's tunic color. " NEXT_TUNIC_COLOR_TEXT "/" PREVIOUS_TUNIC_COLOR_TEXT - " to cycle through colors", - false, nullptr, MAX_TUNIC_COLORS}} { +KEEP_FUNC ToolsMenu::ToolsMenu(Cursor& cursor) + : Menu(cursor), + lines{{"checkers", CHECKERS_INDEX, "Various checker tools", false}, + {"controller", CONTROLLER_INDEX, "Controller related tools", false}, + {"link", LINK_INDEX, "Link related tools", false}, + {"scene", SCENE_INDEX, "Scene related tools", false}, + {"timers", TIMERS_INDEX, "Various timer tools", false}} { } ToolsMenu::~ToolsMenu() {} -GZSettingID l_mapping[] = { - STNG_TOOLS_RELOAD_AREA, STNG_TOOLS_FRAME_ADVANCE, STNG_TOOLS_FAST_BONK, - STNG_TOOLS_FAST_MOVEMENT, STNG_TOOLS_GORGE, -#ifdef WII_PLATFORM - STNG_TOOLS_BIT, -#endif - STNG_TOOLS_COROTD, STNG_TOOLS_UMD, STNG_TOOLS_INPUT_VIEWER, - STNG_TOOLS_LINK_DEBUG, STNG_TOOLS_HEAP_DEBUG, STNG_TOOLS_SAND, - STNG_TOOLS_ROLL, STNG_TOOLS_MASH_CHECKER, STNG_TOOLS_TELEPORT, - STNG_TOOLS_TURBO_MODE, STNG_TOOLS_TIMER, STNG_TOOLS_LOAD_TIMER, - STNG_TOOLS_IGT_TIMER, STNG_TOOLS_FREE_CAM, STNG_TOOLS_MOVE_LINK, -}; - -#define set_active(id, status) \ - ({ \ - auto* stng = GZStng_get(id); \ - if (stng) \ - *(bool*)stng->data = status; \ - }) - void ToolsMenu::draw() { - l_tunicCol_idx = g_tunic_color; - if (GZ_getButtonTrig(BACK_BUTTON)) { g_menuMgr->pop(); return; } - ListMember tunicCol_opt[MAX_TUNIC_COLORS] = {"green", "blue", "red", "orange", - "yellow", "white", "cycle"}; - - if (cursor.y == TUNIC_COLOR_INDEX) { - cursor.x = l_tunicCol_idx; - cursor.move(MAX_TUNIC_COLORS, MENU_LINE_NUM); - - if (GZ_getButtonRepeat(NEXT_TUNIC_COLOR)) { - l_tunicCol_idx++; - - if (l_tunicCol_idx >= MAX_TUNIC_COLORS) - l_tunicCol_idx = 0; - } - - if (GZ_getButtonRepeat(PREVIOUS_TUNIC_COLOR)) { - l_tunicCol_idx--; - - if (l_tunicCol_idx >= MAX_TUNIC_COLORS) - l_tunicCol_idx = MAX_TUNIC_COLORS - 1; - } - - g_tunic_color = l_tunicCol_idx; - } else { - cursor.move(0, MENU_LINE_NUM); - } - if (GZ_getButtonTrig(SELECTION_BUTTON)) { - GZSettingEntry* stng = nullptr; - if (cursor.y < TOOLS_COUNT && cursor.y != TUNIC_COLOR_INDEX) { - stng = GZStng_get(l_mapping[cursor.y]); - if (!stng) { - stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; - g_settings.push_back(stng); - } + switch (cursor.y) { + case CHECKERS_INDEX: + g_menuMgr->push(MN_TOOLS_CHECKERS_INDEX); + return; + case CONTROLLER_INDEX: + g_menuMgr->push(MN_TOOLS_CONTROLLER_INDEX); + return; + case LINK_INDEX: + g_menuMgr->push(MN_TOOLS_LINK_INDEX); + return; + case SCENE_INDEX: + g_menuMgr->push(MN_TOOLS_SCENE_INDEX); + return; + case TIMERS_INDEX: + g_menuMgr->push(MN_TOOLS_TIMERS_INDEX); + return; } - if (stng) { - *(bool*)stng->data = !*(bool*)stng->data; - if (*(bool*)stng->data) { - switch (cursor.y) { - case TIMER_INDEX: - set_active(STNG_TOOLS_LOAD_TIMER, false); - set_active(STNG_TOOLS_IGT_TIMER, false); - break; - case LOAD_TIMER_INDEX: - set_active(STNG_TOOLS_TIMER, false); - set_active(STNG_TOOLS_IGT_TIMER, false); - break; - case IGT_TIMER_INDEX: - set_active(STNG_TOOLS_TIMER, false); - set_active(STNG_TOOLS_LOAD_TIMER, false); - break; - } - } - } - } - - char buf[100]; - switch (cursor.y) { - case RELOAD_AREA_INDEX: { - uint16_t combo = GZStng_getData(STNG_CMD_RELOAD_AREA, RELOAD_AREA_BUTTONS); - char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; - GZCmd_comboToStr(combo, comboStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); - delete[] comboStr; - break; - } - case FRAME_ADVANCE_INDEX: { - uint16_t comboPause = - GZStng_getData(STNG_CMD_FRAME_PAUSE, FRAME_PAUSE_BUTTONS); - char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; - GZCmd_comboToStr(comboPause, comboPauseStr); - uint16_t comboAdvance = - GZStng_getData(STNG_CMD_FRAME_ADVANCE, FRAME_ADVANCE_BUTTONS); - char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; - GZCmd_comboToStr(comboAdvance, comboAdvanceStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); - delete[] comboAdvanceStr; - delete[] comboPauseStr; - break; - } - case GORGE_INDEX: { - uint16_t combo = GZStng_getData(STNG_CMD_GORGE_VOID, GORGE_VOID_BUTTONS); - char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; - GZCmd_comboToStr(combo, comboStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); - delete[] comboStr; - break; - } -#ifdef WII_PLATFORM - case BIT_INDEX: { - uint16_t combo = GZStng_getData(STNG_CMD_BIT, BACK_IN_TIME_BUTTONS); - char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; - GZCmd_comboToStr(combo, comboStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); - delete[] comboStr; - break; - } -#endif - case TELEPORT_INDEX: { - uint16_t comboPause = - GZStng_getData(STNG_CMD_STORE_POSITION, STORE_POSITION_BUTTONS); - char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; - GZCmd_comboToStr(comboPause, comboPauseStr); - uint16_t comboAdvance = - GZStng_getData(STNG_CMD_LOAD_POSITION, LOAD_POSITION_BUTTONS); - char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; - GZCmd_comboToStr(comboAdvance, comboAdvanceStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); - delete[] comboAdvanceStr; - delete[] comboPauseStr; - break; - } - case IGT_TIMER_INDEX: // fallthrough - case TIMER_INDEX: { - uint16_t comboPause = - GZStng_getData(STNG_CMD_TIMER_TOGGLE, TIMER_TOGGLE_BUTTONS); - char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; - GZCmd_comboToStr(comboPause, comboPauseStr); - uint16_t comboAdvance = - GZStng_getData(STNG_CMD_TIMER_RESET, TIMER_RESET_BUTTONS); - char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; - GZCmd_comboToStr(comboAdvance, comboAdvanceStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); - delete[] comboAdvanceStr; - delete[] comboPauseStr; - break; - } - case LOAD_TIMER_INDEX: { - uint16_t combo = GZStng_getData(STNG_CMD_TIMER_RESET, TIMER_RESET_BUTTONS); - char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; - GZCmd_comboToStr(combo, comboStr); - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); - delete[] comboStr; - break; - } - default: { - snprintf(buf, sizeof(buf), l_descTemplates[cursor.y]); - break; - } } - strncpy(lines[cursor.y].description, buf, sizeof(lines[cursor.y].description)); - lines[TUNIC_COLOR_INDEX].printf(" <%s>", tunicCol_opt[l_tunicCol_idx].member); + cursor.move(0, MENU_LINE_NUM); GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); } diff --git a/modules/menus/menu_tools_checkers/CMakeLists.txt b/modules/menus/menu_tools_checkers/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_tools_checkers/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_tools_checkers/include/main.h b/modules/menus/menu_tools_checkers/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_tools_checkers/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_tools_checkers/include/tools_checkers_menu.h b/modules/menus/menu_tools_checkers/include/tools_checkers_menu.h new file mode 100644 index 00000000..71fe3f50 --- /dev/null +++ b/modules/menus/menu_tools_checkers/include/tools_checkers_menu.h @@ -0,0 +1,42 @@ +#pragma once + +#include "menus/menu.h" + +#ifdef GCN_PLATFORM +#define GORGE_VOID_TEXT "L+Z" +#endif + +#ifdef WII_PLATFORM +#define GORGE_VOID_TEXT "Z+C+A+1" +#define BACK_IN_TIME_TEXT "Z+C+A+2" +#endif + +enum CheckersIndex { + +#ifdef WII_PLATFORM + BIT_INDEX, +#endif + COROTD_INDEX, + ELEVATOR_ESCAPE_INDEX, + GORGE_INDEX, + LFC_INDEX, + MASH_CHECKER_INDEX, + ROLL_INDEX, + UMD_INDEX, + + CHECKERS_COUNT, +}; + +struct CheckersData { + Cursor cursor; +}; + +class CheckersMenu : public Menu { +public: + CheckersMenu(CheckersData&); + virtual ~CheckersMenu(); + virtual void draw(); + +private: + Line lines[CHECKERS_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_tools_checkers/src/main.cpp b/modules/menus/menu_tools_checkers/src/main.cpp new file mode 100644 index 00000000..17c3f6dc --- /dev/null +++ b/modules/menus/menu_tools_checkers/src/main.cpp @@ -0,0 +1,50 @@ +#include +#include "menus/menu_tools_checkers/include/tools_checkers_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +CheckersMenu* l_checkersMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new CheckersData); + } +} + +void onLoad() { + l_checkersMenu = new CheckersMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_checkersMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_checkersMenu; +} + +void onDelete() {} \ No newline at end of file diff --git a/modules/menus/menu_tools_checkers/src/tools_checkers_menu.cpp b/modules/menus/menu_tools_checkers/src/tools_checkers_menu.cpp new file mode 100644 index 00000000..b4255bb1 --- /dev/null +++ b/modules/menus/menu_tools_checkers/src/tools_checkers_menu.cpp @@ -0,0 +1,111 @@ +#include "menus/menu_tools_checkers/include/tools_checkers_menu.h" +#include "menus/utils/menu_mgr.h" + +const char l_descTemplates[CHECKERS_COUNT][100] = { +#ifdef WII_PLATFORM + "use %s to warp to ordon bridge", +#endif + "show frame info when doing coro td", + "show frame info when doing elevator escape", + "use %s to warp to kakariko gorge", + "ladder freezard cancel checker", + "display A/B button mashing speeds", + "frame counter for chaining rolls", + "practice snowpeak universal map delay timing", +}; + +KEEP_FUNC CheckersMenu::CheckersMenu(CheckersData& data) + : Menu(data.cursor), lines{ +#ifdef WII_PLATFORM + {"bit", BIT_INDEX, "use " BACK_IN_TIME_TEXT " to warp to ordon bridge", true, + ACTIVE_FUNC(STNG_TOOLS_BIT)}, +#endif + {"coro td", COROTD_INDEX, "show frame info when doing coro td", true, + ACTIVE_FUNC(STNG_TOOLS_COROTD)}, + {"elevator escape", ELEVATOR_ESCAPE_INDEX, "show frame info when doing elevator escape", + true, ACTIVE_FUNC(STNG_TOOLS_ELEVATOR_ESCAPE)}, + {"gorge void", GORGE_INDEX, "use " GORGE_VOID_TEXT " to warp to kakariko gorge", + true, ACTIVE_FUNC(STNG_TOOLS_GORGE)}, + {"ladder freezard cancel", LFC_INDEX, "ladder freezard cancel checker", + true, ACTIVE_FUNC(STNG_TOOLS_LFC)}, + {"a/b mash rate", MASH_CHECKER_INDEX, "display A/B button mashing speeds", true, + ACTIVE_FUNC(STNG_TOOLS_MASH_CHECKER)}, + {"rolling", ROLL_INDEX, "frame counter for chaining rolls", true, + ACTIVE_FUNC(STNG_TOOLS_ROLL)}, + {"universal map delay", UMD_INDEX, "practice snowpeak universal map delay timing", true, + ACTIVE_FUNC(STNG_TOOLS_UMD)}} { +} + +CheckersMenu::~CheckersMenu() {} + +GZSettingID l_mapping[] = { +#ifdef WII_PLATFORM + STNG_TOOLS_BIT, +#endif + STNG_TOOLS_COROTD, + STNG_TOOLS_ELEVATOR_ESCAPE, + STNG_TOOLS_GORGE, + STNG_TOOLS_LFC, + STNG_TOOLS_MASH_CHECKER, + STNG_TOOLS_ROLL, + STNG_TOOLS_UMD, +}; + +#define set_active(id, status) \ + ({ \ + auto* stng = GZStng_get(id); \ + if (stng) \ + *(bool*)stng->data = status; \ + }) + +void CheckersMenu::draw() { + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + cursor.move(0, MENU_LINE_NUM); + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + GZSettingEntry* stng = nullptr; + + stng = GZStng_get(l_mapping[cursor.y]); + + if (!stng) { + stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; + g_settings.push_back(stng); + } + + if (stng) + *(bool*)stng->data = !*(bool*)stng->data; + } + + char buf[100]; + switch (cursor.y) { + case GORGE_INDEX: { + uint16_t combo = GZStng_getData(STNG_CMD_GORGE_VOID, GORGE_VOID_BUTTONS); + char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; + GZCmd_comboToStr(combo, comboStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); + delete[] comboStr; + break; + } +#ifdef WII_PLATFORM + case BIT_INDEX: { + uint16_t combo = GZStng_getData(STNG_CMD_BIT, BACK_IN_TIME_BUTTONS); + char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; + GZCmd_comboToStr(combo, comboStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); + delete[] comboStr; + break; + } +#endif + default: { + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y]); + break; + } + } + + strncpy(lines[cursor.y].description, buf, sizeof(lines[cursor.y].description)); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_tools_controller/CMakeLists.txt b/modules/menus/menu_tools_controller/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_tools_controller/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_tools_controller/include/main.h b/modules/menus/menu_tools_controller/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_tools_controller/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_tools_controller/include/tools_controller_menu.h b/modules/menus/menu_tools_controller/include/tools_controller_menu.h new file mode 100644 index 00000000..5ba687d8 --- /dev/null +++ b/modules/menus/menu_tools_controller/include/tools_controller_menu.h @@ -0,0 +1,21 @@ +#pragma once + +#include "menus/menu.h" +#include "tools.h" + +enum ToolsControllerIndex { + INPUT_VIEWER_INDEX, + TURBO_MODE_INDEX, + + TOOLS_CONTROLLER_COUNT +}; + +class ToolsControllerMenu : public Menu { +public: + ToolsControllerMenu(Cursor&); + virtual ~ToolsControllerMenu(); + virtual void draw(); + +private: + Line lines[TOOLS_CONTROLLER_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_tools_controller/src/main.cpp b/modules/menus/menu_tools_controller/src/main.cpp new file mode 100644 index 00000000..01087973 --- /dev/null +++ b/modules/menus/menu_tools_controller/src/main.cpp @@ -0,0 +1,50 @@ +#include +#include "menus/menu_tools_controller/include/tools_controller_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +ToolsControllerMenu* l_toolsControllerMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + l_toolsControllerMenu = new ToolsControllerMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_toolsControllerMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_toolsControllerMenu; +} + +void onDelete() {} diff --git a/modules/menus/menu_tools_controller/src/tools_controller_menu.cpp b/modules/menus/menu_tools_controller/src/tools_controller_menu.cpp new file mode 100644 index 00000000..2c74eeb8 --- /dev/null +++ b/modules/menus/menu_tools_controller/src/tools_controller_menu.cpp @@ -0,0 +1,38 @@ +#include "menus/menu_tools_controller/include/tools_controller_menu.h" +#include "menus/utils/menu_mgr.h" + +KEEP_FUNC ToolsControllerMenu::ToolsControllerMenu(Cursor& cursor) + : Menu(cursor), + lines{{"input viewer", INPUT_VIEWER_INDEX, "show current inputs", true, + ACTIVE_FUNC(STNG_TOOLS_INPUT_VIEWER)}, + {"turbo mode", TURBO_MODE_INDEX, "simulates turbo controller inputs", true, + ACTIVE_FUNC(STNG_TOOLS_TURBO_MODE)}} { +} + +ToolsControllerMenu::~ToolsControllerMenu() {} + +GZSettingID l_mapping[] = {STNG_TOOLS_INPUT_VIEWER, STNG_TOOLS_TURBO_MODE}; + +void ToolsControllerMenu::draw() { + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + GZSettingEntry* stng = nullptr; + + stng = GZStng_get(l_mapping[cursor.y]); + + if (!stng) { + stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; + g_settings.push_back(stng); + } + + if (stng) + *(bool*)stng->data = !*(bool*)stng->data; + } + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_tools_link/CMakeLists.txt b/modules/menus/menu_tools_link/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_tools_link/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_tools_link/include/main.h b/modules/menus/menu_tools_link/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_tools_link/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_tools_link/include/tools_link_menu.h b/modules/menus/menu_tools_link/include/tools_link_menu.h new file mode 100644 index 00000000..e2ac8e6c --- /dev/null +++ b/modules/menus/menu_tools_link/include/tools_link_menu.h @@ -0,0 +1,45 @@ +#pragma once + +#include "menus/menu.h" +#include "tools.h" + +#ifdef GCN_PLATFORM +#define STORE_POSITION_TEXT "D-PAD up + R" +#define LOAD_POSITION_TEXT "D-PAD down + R" +#define MOVE_LINK_TEXT "L+R+Y" +#endif + +#ifdef WII_PLATFORM +#define STORE_POSITION_TEXT "Z+C+1" +#define LOAD_POSITION_TEXT "Z+C+2" +#define MOVE_LINK_TEXT "Z+C+B+Plus" +#endif + +enum ToolsLinkIndex { + FAST_BONK_INDEX, + FAST_MOVEMENT_INDEX, + LINK_DEBUG_INDEX, + LINK_STAGE_INFO_INDEX, + SAND_INDEX, + TELEPORT_INDEX, + MOVE_LINK_INDEX, + TUNIC_COLOR_INDEX, + + TOOLS_LINK_COUNT +}; + +struct ToolsLinkData { + uint8_t l_tunicCol_idx; +}; + +class ToolsLinkMenu : public Menu { +public: + ToolsLinkMenu(Cursor&, ToolsLinkData&); + virtual ~ToolsLinkMenu(); + virtual void draw(); + +private: + uint8_t& l_tunicCol_idx; + + Line lines[TOOLS_LINK_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_tools_link/src/main.cpp b/modules/menus/menu_tools_link/src/main.cpp new file mode 100644 index 00000000..1d410189 --- /dev/null +++ b/modules/menus/menu_tools_link/src/main.cpp @@ -0,0 +1,56 @@ +#include +#include "menus/menu_tools_link/include/tools_link_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +ToolsLinkMenu* l_toolsLinkMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + g_menuMgr->setPersistentData(new ToolsLinkData()); + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + l_toolsLinkMenu = new ToolsLinkMenu(*g_menuMgr->getPermanentData(), + *g_menuMgr->getPersistentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_toolsLinkMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_toolsLinkMenu; +} + +void onDelete() { + auto data = g_menuMgr->getPersistentData(); + delete data; + g_menuMgr->setPersistentData(nullptr); +} diff --git a/modules/menus/menu_tools_link/src/tools_link_menu.cpp b/modules/menus/menu_tools_link/src/tools_link_menu.cpp new file mode 100644 index 00000000..0e4a9147 --- /dev/null +++ b/modules/menus/menu_tools_link/src/tools_link_menu.cpp @@ -0,0 +1,163 @@ +#include "menus/menu_tools_link/include/tools_link_menu.h" +#include +#include "commands.h" +#include "global_data.h" +#include "timer.h" +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +#ifdef GCN_PLATFORM +#define MOVE_LINK_MOVEMENT_TEXT "Stick/C" +#define MOVE_LINK_ANGLE_TEXT "C-left/right" +#define PREVIOUS_TUNIC_COLOR GZPad::Y +#define PREVIOUS_TUNIC_COLOR_TEXT "Y" +#define NEXT_TUNIC_COLOR GZPad::X +#define NEXT_TUNIC_COLOR_TEXT "X" +#endif +#ifdef WII_PLATFORM +#define MOVE_LINK_MOVEMENT_TEXT "Stick" +#define MOVE_LINK_ANGLE_TEXT "C+Stick" +#define PREVIOUS_TUNIC_COLOR GZPad::TWO +#define PREVIOUS_TUNIC_COLOR_TEXT "TWO" +#define NEXT_TUNIC_COLOR GZPad::ONE +#define NEXT_TUNIC_COLOR_TEXT "ONE" +#endif + +#define MAX_TUNIC_COLORS 7 + +const char l_descTemplates[TOOLS_LINK_COUNT][100] = { + "reduces bonk animation significantly", + "link's movement is much faster", + "show Link's position, angle, and speed", + "show Link's current stage info", + "link won't sink in sand", + "%s to set, %s to load", + MOVE_LINK_TEXT " to activate. " MOVE_LINK_MOVEMENT_TEXT " to move, " MOVE_LINK_ANGLE_TEXT + " to change angle", + "changes link's tunic color. " NEXT_TUNIC_COLOR_TEXT "/" PREVIOUS_TUNIC_COLOR_TEXT + " to cycle through colors", +}; + +KEEP_FUNC ToolsLinkMenu::ToolsLinkMenu(Cursor& cursor, ToolsLinkData& data) + : Menu(cursor), l_tunicCol_idx(data.l_tunicCol_idx), + lines{{"fast bonk recovery", FAST_BONK_INDEX, "reduces bonk animation significantly", true, + ACTIVE_FUNC(STNG_TOOLS_FAST_BONK)}, + {"fast movement", FAST_MOVEMENT_INDEX, "link's movement is much faster", true, + ACTIVE_FUNC(STNG_TOOLS_FAST_MOVEMENT)}, + {"link debug info", LINK_DEBUG_INDEX, "show Link's position, angle, and speed", true, + ACTIVE_FUNC(STNG_TOOLS_LINK_DEBUG)}, + {"stage info", LINK_STAGE_INFO_INDEX, "show Link's current stage info", true, + ACTIVE_FUNC(STNG_TOOLS_STAGE_INFO)}, + {"no sinking in sand", SAND_INDEX, "link won't sink in sand", true, + ACTIVE_FUNC(STNG_TOOLS_SAND)}, + {"teleport", TELEPORT_INDEX, + STORE_POSITION_TEXT " to set, " LOAD_POSITION_TEXT " to load", true, + ACTIVE_FUNC(STNG_TOOLS_TELEPORT)}, + {"move link", MOVE_LINK_INDEX, + MOVE_LINK_TEXT " to activate. " MOVE_LINK_MOVEMENT_TEXT + " to move, " MOVE_LINK_ANGLE_TEXT " to change angle", + true, ACTIVE_FUNC(STNG_TOOLS_MOVE_LINK)}, + {"link tunic color:", TUNIC_COLOR_INDEX, + "changes link's tunic color. " NEXT_TUNIC_COLOR_TEXT "/" PREVIOUS_TUNIC_COLOR_TEXT + " to cycle through colors", + false, nullptr, MAX_TUNIC_COLORS}} { +} + +ToolsLinkMenu::~ToolsLinkMenu() {} + +GZSettingID l_mapping[] = { + STNG_TOOLS_FAST_BONK, + STNG_TOOLS_FAST_MOVEMENT, + STNG_TOOLS_LINK_DEBUG, + STNG_TOOLS_STAGE_INFO, + STNG_TOOLS_SAND, + STNG_TOOLS_TELEPORT, + STNG_TOOLS_MOVE_LINK, +}; + +#define set_active(id, status) \ + ({ \ + auto* stng = GZStng_get(id); \ + if (stng) \ + *(bool*)stng->data = status; \ + }) + +void ToolsLinkMenu::draw() { + l_tunicCol_idx = g_tunic_color; + + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + ListMember tunicCol_opt[MAX_TUNIC_COLORS] = {"green", "blue", "red", "orange", + "yellow", "white", "cycle"}; + + if (cursor.y == TUNIC_COLOR_INDEX) { + cursor.x = l_tunicCol_idx; + cursor.move(MAX_TUNIC_COLORS, MENU_LINE_NUM); + + if (GZ_getButtonRepeat(NEXT_TUNIC_COLOR)) { + l_tunicCol_idx++; + + if (l_tunicCol_idx >= MAX_TUNIC_COLORS) + l_tunicCol_idx = 0; + } + + if (GZ_getButtonRepeat(PREVIOUS_TUNIC_COLOR)) { + l_tunicCol_idx--; + + if (l_tunicCol_idx >= MAX_TUNIC_COLORS) + l_tunicCol_idx = MAX_TUNIC_COLORS - 1; + } + + g_tunic_color = l_tunicCol_idx; + } else { + cursor.move(0, MENU_LINE_NUM); + } + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + + GZSettingEntry* stng = nullptr; + + stng = GZStng_get(l_mapping[cursor.y]); + + if (!stng) { + stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; + g_settings.push_back(stng); + } + + if (stng) + *(bool*)stng->data = !*(bool*)stng->data; + } + + char buf[100]; + + switch (cursor.y) { + case TELEPORT_INDEX: { + uint16_t comboPause = + GZStng_getData(STNG_CMD_STORE_POSITION, STORE_POSITION_BUTTONS); + char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; + GZCmd_comboToStr(comboPause, comboPauseStr); + uint16_t comboAdvance = + GZStng_getData(STNG_CMD_LOAD_POSITION, LOAD_POSITION_BUTTONS); + char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; + GZCmd_comboToStr(comboAdvance, comboAdvanceStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); + delete[] comboAdvanceStr; + delete[] comboPauseStr; + break; + } + default: { + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y]); + break; + } + } + + strncpy(lines[cursor.y].description, buf, sizeof(lines[cursor.y].description)); + + lines[TUNIC_COLOR_INDEX].printf(" <%s>", tunicCol_opt[l_tunicCol_idx].member); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_tools_scene/CMakeLists.txt b/modules/menus/menu_tools_scene/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_tools_scene/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_tools_scene/include/main.h b/modules/menus/menu_tools_scene/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_tools_scene/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_tools_scene/include/tools_scene_menu.h b/modules/menus/menu_tools_scene/include/tools_scene_menu.h new file mode 100644 index 00000000..1891b87b --- /dev/null +++ b/modules/menus/menu_tools_scene/include/tools_scene_menu.h @@ -0,0 +1,38 @@ +#pragma once + +#include "menus/menu.h" +#include "tools.h" + +#ifdef GCN_PLATFORM +#define FRAME_ADVANCE_TEXT "R + D-Pad Up" +#define FRAME_PAUSE_TEXT "R" +#define RELOAD_AREA_TEXT "L+R+A+Start" +#define FREE_CAM_TEXT "Z+B+A" +#endif + +#ifdef WII_PLATFORM +#define FRAME_ADVANCE_TEXT "Z+C+Plus+Minus" +#define FRAME_PAUSE_TEXT "2" +#define RELOAD_AREA_TEXT "Z+C+B+2" +#define FREE_CAM_TEXT "Z+C+B+Minus" +#endif + +enum ToolsSceneIndex { + AREA_RELOAD_INDEX, + FRAME_ADVANCE_INDEX, + FREE_CAM_INDEX, + HEAP_DEBUG_INDEX, + + // Entry used as a counter + TOOLS_SCENE_COUNT +}; + +class ToolsSceneMenu : public Menu { +public: + ToolsSceneMenu(Cursor&); + virtual ~ToolsSceneMenu(); + virtual void draw(); + +private: + Line lines[TOOLS_SCENE_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_tools_scene/src/main.cpp b/modules/menus/menu_tools_scene/src/main.cpp new file mode 100644 index 00000000..1308021e --- /dev/null +++ b/modules/menus/menu_tools_scene/src/main.cpp @@ -0,0 +1,50 @@ +#include +#include "menus/menu_tools_scene/include/tools_scene_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +ToolsSceneMenu* l_toolsSceneMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + l_toolsSceneMenu = new ToolsSceneMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_toolsSceneMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_toolsSceneMenu; +} + +void onDelete() {} diff --git a/modules/menus/menu_tools_scene/src/tools_scene_menu.cpp b/modules/menus/menu_tools_scene/src/tools_scene_menu.cpp new file mode 100644 index 00000000..9cac7a34 --- /dev/null +++ b/modules/menus/menu_tools_scene/src/tools_scene_menu.cpp @@ -0,0 +1,112 @@ +#include "menus/menu_tools_scene/include/tools_scene_menu.h" +#include +#include "commands.h" +#include "global_data.h" +#include "timer.h" +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +#ifdef GCN_PLATFORM +#define FREE_CAM_MOVEMENT_TEXT "Stick/L/R" +#define FREE_CAM_VIEW_TEXT "C-stick" +#endif +#ifdef WII_PLATFORM +#define FREE_CAM_MOVEMENT_TEXT "Stick+DPad" +#define FREE_CAM_VIEW_TEXT "C+Stick" +#endif + +#define MAX_TUNIC_COLORS 7 + +const char l_descTemplates[TOOLS_SCENE_COUNT][100] = { + "use %s to reload current area", + "use %s to pause, %s to frame advance", + FREE_CAM_TEXT " to activate, " FREE_CAM_MOVEMENT_TEXT " to move, " FREE_CAM_VIEW_TEXT " to view, Z to speed", + "show Heap size info", +}; + +KEEP_FUNC ToolsSceneMenu::ToolsSceneMenu(Cursor& cursor) + : Menu(cursor), + lines{{"area reload", AREA_RELOAD_INDEX, "use " RELOAD_AREA_TEXT " to reload current area", + true, ACTIVE_FUNC(STNG_TOOLS_RELOAD_AREA)}, + {"frame advance", FRAME_ADVANCE_INDEX, "use " FRAME_ADVANCE_TEXT " to pause, " FRAME_PAUSE_TEXT " to frame advance", + true, ACTIVE_FUNC(STNG_TOOLS_FRAME_ADVANCE)}, + {"free cam", FREE_CAM_INDEX, + FREE_CAM_TEXT " to activate, " FREE_CAM_MOVEMENT_TEXT " to move, " FREE_CAM_VIEW_TEXT + " to view, Z to speed", + true, ACTIVE_FUNC(STNG_TOOLS_FREE_CAM)}, + {"heap debug info", HEAP_DEBUG_INDEX, "show Heap size info", true, + ACTIVE_FUNC(STNG_TOOLS_HEAP_DEBUG)}} {} + +ToolsSceneMenu::~ToolsSceneMenu() {} + +GZSettingID l_mapping[] = { + STNG_TOOLS_RELOAD_AREA, + STNG_TOOLS_FRAME_ADVANCE, + STNG_TOOLS_FREE_CAM, + STNG_TOOLS_HEAP_DEBUG, +}; + +#define set_active(id, status) \ + ({ \ + auto* stng = GZStng_get(id); \ + if (stng) \ + *(bool*)stng->data = status; \ + }) + +void ToolsSceneMenu::draw() { + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + GZSettingEntry* stng = nullptr; + + stng = GZStng_get(l_mapping[cursor.y]); + if (!stng) { + stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; + g_settings.push_back(stng); + } + + if (stng) + *(bool*)stng->data = !*(bool*)stng->data; + } + + char buf[100]; + + switch (cursor.y) { + case AREA_RELOAD_INDEX: { + uint16_t combo = GZStng_getData(STNG_CMD_RELOAD_AREA, RELOAD_AREA_BUTTONS); + char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; + GZCmd_comboToStr(combo, comboStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); + delete[] comboStr; + break; + } + case FRAME_ADVANCE_INDEX: { + uint16_t comboPause = + GZStng_getData(STNG_CMD_FRAME_PAUSE, FRAME_PAUSE_BUTTONS); + char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; + GZCmd_comboToStr(comboPause, comboPauseStr); + uint16_t comboAdvance = + GZStng_getData(STNG_CMD_FRAME_ADVANCE, FRAME_ADVANCE_BUTTONS); + char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; + GZCmd_comboToStr(comboAdvance, comboAdvanceStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); + delete[] comboAdvanceStr; + delete[] comboPauseStr; + break; + } + default: { + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y]); + break; + } + } + + strncpy(lines[cursor.y].description, buf, sizeof(lines[cursor.y].description)); + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_tools_timers/CMakeLists.txt b/modules/menus/menu_tools_timers/CMakeLists.txt new file mode 100644 index 00000000..24e35f3c --- /dev/null +++ b/modules/menus/menu_tools_timers/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB_RECURSE srcs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE asms CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.s") +list(APPEND srcs ${asms}) +get_filename_component(rel_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) +tpgz_add_module(${rel_name} "${srcs}" "${CMAKE_CURRENT_SOURCE_DIR}/include") \ No newline at end of file diff --git a/modules/menus/menu_tools_timers/include/main.h b/modules/menus/menu_tools_timers/include/main.h new file mode 100644 index 00000000..1935f7ae --- /dev/null +++ b/modules/menus/menu_tools_timers/include/main.h @@ -0,0 +1,6 @@ +#pragma once + +namespace tpgz::modules { +void main(); +void exit(); +} // namespace tpgz::modules \ No newline at end of file diff --git a/modules/menus/menu_tools_timers/include/tools_timers_menu.h b/modules/menus/menu_tools_timers/include/tools_timers_menu.h new file mode 100644 index 00000000..6111f900 --- /dev/null +++ b/modules/menus/menu_tools_timers/include/tools_timers_menu.h @@ -0,0 +1,33 @@ +#pragma once + +#include "menus/menu.h" +#include "tools.h" + +#ifdef GCN_PLATFORM +#define TIMER_TOGGLE_TEXT "Z+A" +#define TIMER_RESET_TEXT "Z+B" +#endif + +#ifdef WII_PLATFORM +#define TIMER_TOGGLE_TEXT "Z+C+A+B" +#define TIMER_RESET_TEXT "Z+C+B+1" +#endif + +enum ToolsTimersIndex { + TIMER_INDEX, + LOAD_TIMER_INDEX, + IGT_TIMER_INDEX, + + TOOLS_TIMERS_COUNT +}; + +class ToolsTimersMenu : public Menu { +public: + ToolsTimersMenu(Cursor&); + virtual ~ToolsTimersMenu(); + virtual void draw(); + +private: + + Line lines[TOOLS_TIMERS_COUNT]; +}; \ No newline at end of file diff --git a/modules/menus/menu_tools_timers/src/main.cpp b/modules/menus/menu_tools_timers/src/main.cpp new file mode 100644 index 00000000..d171cd8e --- /dev/null +++ b/modules/menus/menu_tools_timers/src/main.cpp @@ -0,0 +1,50 @@ +#include +#include "menus/menu_tools_timers/include/tools_timers_menu.h" +#include "events/draw_listener.h" +#include "menus/utils/menu_mgr.h" +#include "utils/draw.h" + +void onCreate(); +void onLoad(); +void onDraw(); +void onUnload(); +void onDelete(); + +ToolsTimersMenu* l_toolsTimersMenu; + +namespace tpgz::modules { +void main() { + g_menuMgr->setCreateHook(onCreate); + g_menuMgr->setLoadHook(onLoad); + g_menuMgr->setUnloadHook(onUnload); + g_menuMgr->setDeleteHook(onDelete); +} +void exit() { + g_menuMgr->setCreateHook(nullptr); + g_menuMgr->setLoadHook(nullptr); + g_menuMgr->setUnloadHook(nullptr); + g_menuMgr->setDeleteHook(nullptr); +} +} // namespace tpgz::modules + +void onCreate() { + if (!g_menuMgr->getPermanentData()) { + g_menuMgr->setPermanentData(new Cursor); + } +} + +void onLoad() { + l_toolsTimersMenu = new ToolsTimersMenu(*g_menuMgr->getPermanentData()); + g_drawListener->addListener(onDraw); +} + +void onDraw() { + l_toolsTimersMenu->draw(); +} + +void onUnload() { + g_drawListener->removeListener(onDraw); + delete l_toolsTimersMenu; +} + +void onDelete() {} diff --git a/modules/menus/menu_tools_timers/src/tools_timers_menu.cpp b/modules/menus/menu_tools_timers/src/tools_timers_menu.cpp new file mode 100644 index 00000000..c990e7b0 --- /dev/null +++ b/modules/menus/menu_tools_timers/src/tools_timers_menu.cpp @@ -0,0 +1,118 @@ +#include "menus/menu_tools_timers/include/tools_timers_menu.h" +#include +#include "commands.h" +#include "global_data.h" +#include "timer.h" +#include "libtp_c/include/d/com/d_com_inf_game.h" +#include "gz_flags.h" +#include "rels/include/defines.h" +#include "menus/utils/menu_mgr.h" + +const char l_descTemplates[TOOLS_COUNT][100] = { + "frame timer: %s to start/stop, %s to reset", + "loading zone timer: %s to reset", + "In-game time timer: %s to start/stop, %s to reset", +}; + +KEEP_FUNC ToolsTimersMenu::ToolsTimersMenu(Cursor& cursor) + : Menu(cursor), + lines{{"timer", TIMER_INDEX, + "frame timer: " TIMER_TOGGLE_TEXT " to start/stop, " TIMER_RESET_TEXT " to reset", + true, ACTIVE_FUNC(STNG_TOOLS_TIMER)}, + {"load timer", LOAD_TIMER_INDEX, "loading zone timer: " TIMER_RESET_TEXT " to reset", + true, ACTIVE_FUNC(STNG_TOOLS_LOAD_TIMER)}, + {"igt timer", IGT_TIMER_INDEX, + "In-game time timer: " TIMER_TOGGLE_TEXT " to start/stop, " TIMER_RESET_TEXT + " to reset", + true, ACTIVE_FUNC(STNG_TOOLS_IGT_TIMER)}} { +} + +ToolsTimersMenu::~ToolsTimersMenu() {} + +GZSettingID l_mapping[] = { + STNG_TOOLS_TIMER, + STNG_TOOLS_LOAD_TIMER, + STNG_TOOLS_IGT_TIMER +}; + +#define set_active(id, status) \ + ({ \ + auto* stng = GZStng_get(id); \ + if (stng) \ + *(bool*)stng->data = status; \ + }) + +void ToolsTimersMenu::draw() { + if (GZ_getButtonTrig(BACK_BUTTON)) { + g_menuMgr->pop(); + return; + } + + if (GZ_getButtonTrig(SELECTION_BUTTON)) { + GZSettingEntry* stng = nullptr; + + stng = GZStng_get(l_mapping[cursor.y]); + + if (!stng) { + stng = new GZSettingEntry{l_mapping[cursor.y], sizeof(bool), new bool}; + g_settings.push_back(stng); + } + + if (stng) { + *(bool*)stng->data = !*(bool*)stng->data; + + if (*(bool*)stng->data) { + switch (cursor.y) { + case TIMER_INDEX: + set_active(STNG_TOOLS_LOAD_TIMER, false); + set_active(STNG_TOOLS_IGT_TIMER, false); + break; + case LOAD_TIMER_INDEX: + set_active(STNG_TOOLS_TIMER, false); + set_active(STNG_TOOLS_IGT_TIMER, false); + break; + case IGT_TIMER_INDEX: + set_active(STNG_TOOLS_TIMER, false); + set_active(STNG_TOOLS_LOAD_TIMER, false); + break; + } + } + } + } + + char buf[100]; + switch (cursor.y) { + case IGT_TIMER_INDEX: // fallthrough + case TIMER_INDEX: { + uint16_t comboPause = + GZStng_getData(STNG_CMD_TIMER_TOGGLE, TIMER_TOGGLE_BUTTONS); + char* comboPauseStr = new char[GZCmd_getComboLen(comboPause) + 1]; + GZCmd_comboToStr(comboPause, comboPauseStr); + uint16_t comboAdvance = + GZStng_getData(STNG_CMD_TIMER_RESET, TIMER_RESET_BUTTONS); + char* comboAdvanceStr = new char[GZCmd_getComboLen(comboAdvance) + 1]; + GZCmd_comboToStr(comboAdvance, comboAdvanceStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboPauseStr, comboAdvanceStr); + delete[] comboAdvanceStr; + delete[] comboPauseStr; + break; + } + case LOAD_TIMER_INDEX: { + uint16_t combo = GZStng_getData(STNG_CMD_TIMER_RESET, TIMER_RESET_BUTTONS); + char* comboStr = new char[GZCmd_getComboLen(combo) + 1]; + GZCmd_comboToStr(combo, comboStr); + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y], comboStr); + delete[] comboStr; + break; + } + default: { + snprintf(buf, sizeof(buf), l_descTemplates[cursor.y]); + break; + } + } + + strncpy(lines[cursor.y].description, buf, sizeof(lines[cursor.y].description)); + + cursor.move(0, MENU_LINE_NUM); + GZ_drawMenuLines(lines, cursor.y, MENU_LINE_NUM); +} diff --git a/modules/menus/menu_trigger_view/src/trigger_view_menu.cpp b/modules/menus/menu_trigger_view/src/trigger_view_menu.cpp index f9a36d51..ae7a6c43 100644 --- a/modules/menus/menu_trigger_view/src/trigger_view_menu.cpp +++ b/modules/menus/menu_trigger_view/src/trigger_view_menu.cpp @@ -31,6 +31,8 @@ KEEP_FUNC TriggerViewMenu::TriggerViewMenu(Cursor& cursor) [](){return g_triggerViewFlags[VIEW_TRANSFORM_DISTS].active;}}, {"twilight gates", VIEW_TW_GATES, "view twilight gate triggers", true, [](){return g_triggerViewFlags[VIEW_TW_GATES].active;}}, + {"leever ranges", VIEW_LEEVER_RANGE, "view leever ranges", true, + [](){return g_triggerViewFlags[VIEW_LEEVER_RANGE].active;}}, {"opacity:", TRIGGER_VIEW_MAX, "the opacity of drawn geometry"}, } {} diff --git a/modules/menus/menu_warp/src/main.cpp b/modules/menus/menu_warp/src/main.cpp index 32298206..81807c5e 100644 --- a/modules/menus/menu_warp/src/main.cpp +++ b/modules/menus/menu_warp/src/main.cpp @@ -3,7 +3,6 @@ #include "events/draw_listener.h" #include "menus/utils/menu_mgr.h" #include "utils/draw.h" -#include "rels/include/cxx.h" void onCreate(); void onLoad(); @@ -48,4 +47,4 @@ void onUnload() { delete l_menu; } -void onDelete() {} +void onDelete() {} \ No newline at end of file diff --git a/res/map/GCN_NTSCJ.lst b/res/map/GCN_NTSCJ.lst index e8dd3859..92bbf971 100644 --- a/res/map/GCN_NTSCJ.lst +++ b/res/map/GCN_NTSCJ.lst @@ -402,6 +402,11 @@ 8044b265:sPauseTimer +// Z2AudioLib +8044b4a8:mAudioMgrPtr__10Z2AudioMgr + +8044aea4:dStage_roomControl_c__mStayNo + CC008000:wgPipe 800056c0:version_check__Fv diff --git a/res/map/GCN_NTSCU.lst b/res/map/GCN_NTSCU.lst index 6c789d32..bfc63220 100644 --- a/res/map/GCN_NTSCU.lst +++ b/res/map/GCN_NTSCU.lst @@ -185,6 +185,11 @@ 80451125:sPauseTimer +// Z2AudioLib +80451368:mAudioMgrPtr__10Z2AudioMgr + +80450d64:dStage_roomControl_c__mStayNo + CC008000:wgPipe 800056c0:version_check__Fv diff --git a/res/map/GCN_PAL.lst b/res/map/GCN_PAL.lst index cd0f4a3e..9c4e0c46 100644 --- a/res/map/GCN_PAL.lst +++ b/res/map/GCN_PAL.lst @@ -409,6 +409,11 @@ 804530ED:sPauseTimer +// Z2AudioLib +80453330:mAudioMgrPtr__10Z2AudioMgr + +80452d24:dStage_roomControl_c__mStayNo + CC008000:wgPipe 800056c0:version_check__Fv diff --git a/res/map/WII_NTSCJ.lst b/res/map/WII_NTSCJ.lst index dde11f4f..0373fd9e 100644 --- a/res/map/WII_NTSCJ.lst +++ b/res/map/WII_NTSCJ.lst @@ -258,6 +258,11 @@ 8051eca5:sPauseTimer +// Z2AudioLib +8051eef8:Z2SeMgr__mAudioMgrPtr + +8051e81C:dStage_roomControl_c__mStayNo + CC008000:wgPipe 80006920:SECallback_int__int_ diff --git a/res/map/WII_NTSCU_10.lst b/res/map/WII_NTSCU_10.lst index 6f2db620..99011d30 100644 --- a/res/map/WII_NTSCU_10.lst +++ b/res/map/WII_NTSCU_10.lst @@ -524,6 +524,11 @@ 8053ae1d:sPauseTimer +// Z2AudioLib +8053b068:Z2SeMgr__mAudioMgrPtr + +8053a994:dStage_roomControl_c__mStayNo + CC008000:wgPipe 80006920:SECallback_int__int_ diff --git a/res/map/WII_NTSCU_12.lst b/res/map/WII_NTSCU_12.lst index efe47798..0d43cd11 100644 --- a/res/map/WII_NTSCU_12.lst +++ b/res/map/WII_NTSCU_12.lst @@ -327,6 +327,11 @@ 80520e35:sPauseTimer +// Z2AudioLib +80521088:Z2SeMgr__mAudioMgrPtr + +8052099C:dStage_roomControl_c__mStayNo + CC008000:wgPipe 80006920:SECallback_int__int_ diff --git a/res/map/WII_PAL.lst b/res/map/WII_PAL.lst index 8f5c2b71..9e41ef07 100644 --- a/res/map/WII_PAL.lst +++ b/res/map/WII_PAL.lst @@ -257,6 +257,11 @@ 805215f5:sPauseTimer +// Z2AudioLib +80521848:Z2SeMgr__mAudioMgrPtr + +8052115C:dStage_roomControl_c__mStayNo + CC008000:wgPipe 80006920:SECallback_int__int_ diff --git a/res/save_files/any.bin b/res/save_files/any.bin index 23f96989..bdb33e55 100644 Binary files a/res/save_files/any.bin and b/res/save_files/any.bin differ diff --git a/res/save_files/any_bite.bin b/res/save_files/any_bite.bin index 976069cf..bb255d09 100644 Binary files a/res/save_files/any_bite.bin and b/res/save_files/any_bite.bin differ diff --git a/res/save_files/hundo.bin b/res/save_files/hundo.bin index 8cf7668a..19dc998d 100644 Binary files a/res/save_files/hundo.bin and b/res/save_files/hundo.bin differ diff --git a/res/save_files/hundo/aeralfos_skip.bin b/res/save_files/hundo/aeralfos_skip.bin index 4428ca71..3c947626 100644 Binary files a/res/save_files/hundo/aeralfos_skip.bin and b/res/save_files/hundo/aeralfos_skip.bin differ diff --git a/res/save_files/hundo/ag.bin b/res/save_files/hundo/ag.bin index 2905cb76..4bc1b658 100644 Binary files a/res/save_files/hundo/ag.bin and b/res/save_files/hundo/ag.bin differ diff --git a/res/save_files/hundo/argorok.bin b/res/save_files/hundo/argorok.bin index 2558a537..44094d42 100644 Binary files a/res/save_files/hundo/argorok.bin and b/res/save_files/hundo/argorok.bin differ diff --git a/res/save_files/hundo/blizzeta.bin b/res/save_files/hundo/blizzeta.bin index 88b136e0..1a06f580 100644 Binary files a/res/save_files/hundo/blizzeta.bin and b/res/save_files/hundo/blizzeta.bin differ diff --git a/res/save_files/hundo/boss_bug.bin b/res/save_files/hundo/boss_bug.bin index 980611b3..c7df2883 100644 Binary files a/res/save_files/hundo/boss_bug.bin and b/res/save_files/hundo/boss_bug.bin differ diff --git a/res/save_files/hundo/camp.bin b/res/save_files/hundo/camp.bin index 980fedd5..3c760100 100644 Binary files a/res/save_files/hundo/camp.bin and b/res/save_files/hundo/camp.bin differ diff --git a/res/save_files/hundo/cits_1.bin b/res/save_files/hundo/cits_1.bin index 8c5bf47a..9111a4b1 100644 Binary files a/res/save_files/hundo/cits_1.bin and b/res/save_files/hundo/cits_1.bin differ diff --git a/res/save_files/hundo/cits_2.bin b/res/save_files/hundo/cits_2.bin index a15c8bcc..14382498 100644 Binary files a/res/save_files/hundo/cits_2.bin and b/res/save_files/hundo/cits_2.bin differ diff --git a/res/save_files/hundo/cits_poe_cycle.bin b/res/save_files/hundo/cits_poe_cycle.bin index 3585b4ad..f6102f8d 100644 Binary files a/res/save_files/hundo/cits_poe_cycle.bin and b/res/save_files/hundo/cits_poe_cycle.bin differ diff --git a/res/save_files/hundo/coo.bin b/res/save_files/hundo/coo.bin index 9cce9e34..08a187d7 100644 Binary files a/res/save_files/hundo/coo.bin and b/res/save_files/hundo/coo.bin differ diff --git a/res/save_files/hundo/coo_10.bin b/res/save_files/hundo/coo_10.bin index 27ac3821..3ca880ed 100644 Binary files a/res/save_files/hundo/coo_10.bin and b/res/save_files/hundo/coo_10.bin differ diff --git a/res/save_files/hundo/coo_20.bin b/res/save_files/hundo/coo_20.bin index 050c777b..c8a1a58b 100644 Binary files a/res/save_files/hundo/coo_20.bin and b/res/save_files/hundo/coo_20.bin differ diff --git a/res/save_files/hundo/coo_30.bin b/res/save_files/hundo/coo_30.bin index 37ac36b6..5c78ebb3 100644 Binary files a/res/save_files/hundo/coo_30.bin and b/res/save_files/hundo/coo_30.bin differ diff --git a/res/save_files/hundo/coo_40.bin b/res/save_files/hundo/coo_40.bin index 6272d915..060ca3fe 100644 Binary files a/res/save_files/hundo/coo_40.bin and b/res/save_files/hundo/coo_40.bin differ diff --git a/res/save_files/hundo/corotd.bin b/res/save_files/hundo/corotd.bin index ff1ac325..58b3641d 100644 Binary files a/res/save_files/hundo/corotd.bin and b/res/save_files/hundo/corotd.bin differ diff --git a/res/save_files/hundo/dangoro.bin b/res/save_files/hundo/dangoro.bin index 90ee0611..9175be1c 100644 Binary files a/res/save_files/hundo/dangoro.bin and b/res/save_files/hundo/dangoro.bin differ diff --git a/res/save_files/hundo/darkhammer.bin b/res/save_files/hundo/darkhammer.bin index debfa0e8..06542af5 100644 Binary files a/res/save_files/hundo/darkhammer.bin and b/res/save_files/hundo/darkhammer.bin differ diff --git a/res/save_files/hundo/death_sword_skip.bin b/res/save_files/hundo/death_sword_skip.bin index d1283c64..e4fdbbfa 100644 Binary files a/res/save_files/hundo/death_sword_skip.bin and b/res/save_files/hundo/death_sword_skip.bin differ diff --git a/res/save_files/hundo/dot_skip.bin b/res/save_files/hundo/dot_skip.bin index cf75e147..dd025237 100644 Binary files a/res/save_files/hundo/dot_skip.bin and b/res/save_files/hundo/dot_skip.bin differ diff --git a/res/save_files/hundo/early_ele.bin b/res/save_files/hundo/early_ele.bin new file mode 100644 index 00000000..6e8cbc3e Binary files /dev/null and b/res/save_files/hundo/early_ele.bin differ diff --git a/res/save_files/hundo/early_platform.bin b/res/save_files/hundo/early_platform.bin index 236c3290..dd39aebb 100644 Binary files a/res/save_files/hundo/early_platform.bin and b/res/save_files/hundo/early_platform.bin differ diff --git a/res/save_files/hundo/eldin_collection.bin b/res/save_files/hundo/eldin_collection.bin index 61df282a..cc31d7f8 100644 Binary files a/res/save_files/hundo/eldin_collection.bin and b/res/save_files/hundo/eldin_collection.bin differ diff --git a/res/save_files/hundo/fan_tower.bin b/res/save_files/hundo/fan_tower.bin index 5c73ceb0..2d68535e 100644 Binary files a/res/save_files/hundo/fan_tower.bin and b/res/save_files/hundo/fan_tower.bin differ diff --git a/res/save_files/hundo/fyrus.bin b/res/save_files/hundo/fyrus.bin new file mode 100644 index 00000000..eabe47ed Binary files /dev/null and b/res/save_files/hundo/fyrus.bin differ diff --git a/res/save_files/hundo/gm.bin b/res/save_files/hundo/gm.bin index 7306c213..bbeac349 100644 Binary files a/res/save_files/hundo/gm.bin and b/res/save_files/hundo/gm.bin differ diff --git a/res/save_files/hundo/gorge_arc.bin b/res/save_files/hundo/gorge_arc.bin index 7e260094..0961fa48 100644 Binary files a/res/save_files/hundo/gorge_arc.bin and b/res/save_files/hundo/gorge_arc.bin differ diff --git a/res/save_files/hundo/grove_boost.bin b/res/save_files/hundo/grove_boost.bin index ee7ae70f..191248da 100644 Binary files a/res/save_files/hundo/grove_boost.bin and b/res/save_files/hundo/grove_boost.bin differ diff --git a/res/save_files/hundo/grove_skip.bin b/res/save_files/hundo/grove_skip.bin index d18da713..0aa1c555 100644 Binary files a/res/save_files/hundo/grove_skip.bin and b/res/save_files/hundo/grove_skip.bin differ diff --git a/res/save_files/hundo/hotspring.bin b/res/save_files/hundo/hotspring.bin index 65189f04..f617918c 100644 Binary files a/res/save_files/hundo/hotspring.bin and b/res/save_files/hundo/hotspring.bin differ diff --git a/res/save_files/hundo/hv_archery.bin b/res/save_files/hundo/hv_archery.bin index 9cb78df8..3fe53c99 100644 Binary files a/res/save_files/hundo/hv_archery.bin and b/res/save_files/hundo/hv_archery.bin differ diff --git a/res/save_files/hundo/ice_puzzle.bin b/res/save_files/hundo/ice_puzzle.bin index 1634230b..42df7114 100644 Binary files a/res/save_files/hundo/ice_puzzle.bin and b/res/save_files/hundo/ice_puzzle.bin differ diff --git a/res/save_files/hundo/iza_1_skip.bin b/res/save_files/hundo/iza_1_skip.bin index 62319f3d..9f83e5e4 100644 Binary files a/res/save_files/hundo/iza_1_skip.bin and b/res/save_files/hundo/iza_1_skip.bin differ diff --git a/res/save_files/hundo/iza_2.bin b/res/save_files/hundo/iza_2.bin index d3ce6951..93b05091 100644 Binary files a/res/save_files/hundo/iza_2.bin and b/res/save_files/hundo/iza_2.bin differ diff --git a/res/save_files/hundo/kb1.bin b/res/save_files/hundo/kb1.bin index 1300c700..5ce46d7d 100644 Binary files a/res/save_files/hundo/kb1.bin and b/res/save_files/hundo/kb1.bin differ diff --git a/res/save_files/hundo/kb2.bin b/res/save_files/hundo/kb2.bin index 117d77a2..cb94ff34 100644 Binary files a/res/save_files/hundo/kb2.bin and b/res/save_files/hundo/kb2.bin differ diff --git a/res/save_files/hundo/lakebed_bk_skip.bin b/res/save_files/hundo/lakebed_bk_skip.bin index df4a73bb..e5af5406 100644 Binary files a/res/save_files/hundo/lakebed_bk_skip.bin and b/res/save_files/hundo/lakebed_bk_skip.bin differ diff --git a/res/save_files/hundo/lanayru_twilight.bin b/res/save_files/hundo/lanayru_twilight.bin index 74af0888..052e46cd 100644 Binary files a/res/save_files/hundo/lanayru_twilight.bin and b/res/save_files/hundo/lanayru_twilight.bin differ diff --git a/res/save_files/hundo/lh_cave.bin b/res/save_files/hundo/lh_cave.bin index e8e85558..81ad8502 100644 Binary files a/res/save_files/hundo/lh_cave.bin and b/res/save_files/hundo/lh_cave.bin differ diff --git a/res/save_files/hundo/mdh tower.bin b/res/save_files/hundo/mdh tower.bin new file mode 100644 index 00000000..584d37e8 Binary files /dev/null and b/res/save_files/hundo/mdh tower.bin differ diff --git a/res/save_files/hundo/mdh.bin b/res/save_files/hundo/mdh.bin new file mode 100644 index 00000000..02ec5dd2 Binary files /dev/null and b/res/save_files/hundo/mdh.bin differ diff --git a/res/save_files/hundo/morpheel.bin b/res/save_files/hundo/morpheel.bin index caadb940..c7f53f5f 100644 Binary files a/res/save_files/hundo/morpheel.bin and b/res/save_files/hundo/morpheel.bin differ diff --git a/res/save_files/hundo/nf_bomb_boost.bin b/res/save_files/hundo/nf_bomb_boost.bin index b2c651d5..d2dc2e1b 100644 Binary files a/res/save_files/hundo/nf_bomb_boost.bin and b/res/save_files/hundo/nf_bomb_boost.bin differ diff --git a/res/save_files/hundo/palace_1.bin b/res/save_files/hundo/palace_1.bin index 7853998d..b375f93b 100644 Binary files a/res/save_files/hundo/palace_1.bin and b/res/save_files/hundo/palace_1.bin differ diff --git a/res/save_files/hundo/palace_2.bin b/res/save_files/hundo/palace_2.bin index 36d69e49..b45082a1 100644 Binary files a/res/save_files/hundo/palace_2.bin and b/res/save_files/hundo/palace_2.bin differ diff --git a/res/save_files/hundo/poe_1_skip.bin b/res/save_files/hundo/poe_1_skip.bin index 28ff8132..26850f22 100644 Binary files a/res/save_files/hundo/poe_1_skip.bin and b/res/save_files/hundo/poe_1_skip.bin differ diff --git a/res/save_files/hundo/post_ag.bin b/res/save_files/hundo/post_ag.bin index 7166409c..367fc6b4 100644 Binary files a/res/save_files/hundo/post_ag.bin and b/res/save_files/hundo/post_ag.bin differ diff --git a/res/save_files/hundo/post_mdh.bin b/res/save_files/hundo/post_mdh.bin index 5f3f76c9..724227f1 100644 Binary files a/res/save_files/hundo/post_mdh.bin and b/res/save_files/hundo/post_mdh.bin differ diff --git a/res/save_files/hundo/post_tot.bin b/res/save_files/hundo/post_tot.bin index 5cae0b36..6d036f62 100644 Binary files a/res/save_files/hundo/post_tot.bin and b/res/save_files/hundo/post_tot.bin differ diff --git a/res/save_files/hundo/silver_rupee.bin b/res/save_files/hundo/silver_rupee.bin index 69f5de20..60c988bc 100644 Binary files a/res/save_files/hundo/silver_rupee.bin and b/res/save_files/hundo/silver_rupee.bin differ diff --git a/res/save_files/hundo/spr.bin b/res/save_files/hundo/spr.bin index 0221d0d9..b4ca73e5 100644 Binary files a/res/save_files/hundo/spr.bin and b/res/save_files/hundo/spr.bin differ diff --git a/res/save_files/hundo/spr_2.bin b/res/save_files/hundo/spr_2.bin new file mode 100644 index 00000000..c39b191d Binary files /dev/null and b/res/save_files/hundo/spr_2.bin differ diff --git a/res/save_files/hundo/spr_bk.bin b/res/save_files/hundo/spr_bk.bin new file mode 100644 index 00000000..b9c291be Binary files /dev/null and b/res/save_files/hundo/spr_bk.bin differ diff --git a/res/save_files/hundo/spr_bk_lja.bin b/res/save_files/hundo/spr_bk_lja.bin index 75438f41..487bb04a 100644 Binary files a/res/save_files/hundo/spr_bk_lja.bin and b/res/save_files/hundo/spr_bk_lja.bin differ diff --git a/res/save_files/hundo/stallord.bin b/res/save_files/hundo/stallord.bin index c59e76a8..51c78802 100644 Binary files a/res/save_files/hundo/stallord.bin and b/res/save_files/hundo/stallord.bin differ diff --git a/res/save_files/hundo/star_1.bin b/res/save_files/hundo/star_1.bin index 6b36e7ac..04f1b97f 100644 Binary files a/res/save_files/hundo/star_1.bin and b/res/save_files/hundo/star_1.bin differ diff --git a/res/save_files/hundo/star_2.bin b/res/save_files/hundo/star_2.bin index 51aef026..c2a968fa 100644 Binary files a/res/save_files/hundo/star_2.bin and b/res/save_files/hundo/star_2.bin differ diff --git a/res/save_files/hundo/tot.bin b/res/save_files/hundo/tot.bin index 7f17c380..718c9ce7 100644 Binary files a/res/save_files/hundo/tot.bin and b/res/save_files/hundo/tot.bin differ diff --git a/res/save_files/hundo/tot_darknut.bin b/res/save_files/hundo/tot_darknut.bin index ef001abc..77f78c91 100644 Binary files a/res/save_files/hundo/tot_darknut.bin and b/res/save_files/hundo/tot_darknut.bin differ diff --git a/res/save_files/hundo/tot_early_hp.bin b/res/save_files/hundo/tot_early_hp.bin index e02dadbf..8cb980b7 100644 Binary files a/res/save_files/hundo/tot_early_hp.bin and b/res/save_files/hundo/tot_early_hp.bin differ diff --git a/res/save_files/hundo/tot_early_poe.bin b/res/save_files/hundo/tot_early_poe.bin index 9f78760a..1cba50b5 100644 Binary files a/res/save_files/hundo/tot_early_poe.bin and b/res/save_files/hundo/tot_early_poe.bin differ diff --git a/res/save_files/hundo/tot_statue_throws.bin b/res/save_files/hundo/tot_statue_throws.bin index 2e7f1ba0..27b1e038 100644 Binary files a/res/save_files/hundo/tot_statue_throws.bin and b/res/save_files/hundo/tot_statue_throws.bin differ diff --git a/res/save_files/hundo/waterfall_sidehop.bin b/res/save_files/hundo/waterfall_sidehop.bin new file mode 100644 index 00000000..48b84653 Binary files /dev/null and b/res/save_files/hundo/waterfall_sidehop.bin differ diff --git a/res/save_files/hundo/zant.bin b/res/save_files/hundo/zant.bin index 975da578..eab0fe71 100644 Binary files a/res/save_files/hundo/zant.bin and b/res/save_files/hundo/zant.bin differ diff --git a/res/save_files_wii/any.bin b/res/save_files_wii/any.bin index f5af9835..495e1d1d 100644 Binary files a/res/save_files_wii/any.bin and b/res/save_files_wii/any.bin differ diff --git a/res/save_files_wii/any/argarok.bin b/res/save_files_wii/any/argorok.bin similarity index 100% rename from res/save_files_wii/any/argarok.bin rename to res/save_files_wii/any/argorok.bin diff --git a/res/save_files_wii/any_bite.bin b/res/save_files_wii/any_bite.bin new file mode 100644 index 00000000..daa9c8b9 Binary files /dev/null and b/res/save_files_wii/any_bite.bin differ diff --git a/res/save_files_wii/any_bite/ag.bin b/res/save_files_wii/any_bite/ag.bin new file mode 100644 index 00000000..c1ef5870 Binary files /dev/null and b/res/save_files_wii/any_bite/ag.bin differ diff --git a/res/save_files_wii/any_bite/arbiters_grounds.bin b/res/save_files_wii/any_bite/arbiters_grounds.bin new file mode 100644 index 00000000..51215d05 Binary files /dev/null and b/res/save_files_wii/any_bite/arbiters_grounds.bin differ diff --git a/res/save_files_wii/any_bite/arealfos.bin b/res/save_files_wii/any_bite/arealfos.bin new file mode 100644 index 00000000..cddceb9a Binary files /dev/null and b/res/save_files_wii/any_bite/arealfos.bin differ diff --git a/res/save_files_wii/any_bite/argorok.bin b/res/save_files_wii/any_bite/argorok.bin new file mode 100644 index 00000000..8c73f70f Binary files /dev/null and b/res/save_files_wii/any_bite/argorok.bin differ diff --git a/res/save_files_wii/any_bite/beast_ganon.bin b/res/save_files_wii/any_bite/beast_ganon.bin new file mode 100644 index 00000000..f37d9462 Binary files /dev/null and b/res/save_files_wii/any_bite/beast_ganon.bin differ diff --git a/res/save_files_wii/any_bite/before_kb1.bin b/res/save_files_wii/any_bite/before_kb1.bin new file mode 100644 index 00000000..5c0883f5 Binary files /dev/null and b/res/save_files_wii/any_bite/before_kb1.bin differ diff --git a/res/save_files_wii/any_bite/bombhouse_skip.bin b/res/save_files_wii/any_bite/bombhouse_skip.bin new file mode 100644 index 00000000..8163a93a Binary files /dev/null and b/res/save_files_wii/any_bite/bombhouse_skip.bin differ diff --git a/res/save_files_wii/any_bite/boss_bug.bin b/res/save_files_wii/any_bite/boss_bug.bin new file mode 100644 index 00000000..8e201da2 Binary files /dev/null and b/res/save_files_wii/any_bite/boss_bug.bin differ diff --git a/res/save_files_wii/any_bite/bulblin_camp.bin b/res/save_files_wii/any_bite/bulblin_camp.bin new file mode 100644 index 00000000..1e63d35f Binary files /dev/null and b/res/save_files_wii/any_bite/bulblin_camp.bin differ diff --git a/res/save_files_wii/any_bite/cits.bin b/res/save_files_wii/any_bite/cits.bin new file mode 100644 index 00000000..6af5e3ac Binary files /dev/null and b/res/save_files_wii/any_bite/cits.bin differ diff --git a/res/save_files_wii/any_bite/cits_2.bin b/res/save_files_wii/any_bite/cits_2.bin new file mode 100644 index 00000000..5d55894d Binary files /dev/null and b/res/save_files_wii/any_bite/cits_2.bin differ diff --git a/res/save_files_wii/any_bite/cits_tower.bin b/res/save_files_wii/any_bite/cits_tower.bin new file mode 100644 index 00000000..60599205 Binary files /dev/null and b/res/save_files_wii/any_bite/cits_tower.bin differ diff --git a/res/save_files_wii/any_bite/dark_hammer.bin b/res/save_files_wii/any_bite/dark_hammer.bin new file mode 100644 index 00000000..1a2050cf Binary files /dev/null and b/res/save_files_wii/any_bite/dark_hammer.bin differ diff --git a/res/save_files_wii/any_bite/darknut.bin b/res/save_files_wii/any_bite/darknut.bin new file mode 100644 index 00000000..65f81ba7 Binary files /dev/null and b/res/save_files_wii/any_bite/darknut.bin differ diff --git a/res/save_files_wii/any_bite/death_sword.bin b/res/save_files_wii/any_bite/death_sword.bin new file mode 100644 index 00000000..5e378b98 Binary files /dev/null and b/res/save_files_wii/any_bite/death_sword.bin differ diff --git a/res/save_files_wii/any_bite/deku_toad.bin b/res/save_files_wii/any_bite/deku_toad.bin new file mode 100644 index 00000000..6dd6dc33 Binary files /dev/null and b/res/save_files_wii/any_bite/deku_toad.bin differ diff --git a/res/save_files_wii/any_bite/early_boss_key.bin b/res/save_files_wii/any_bite/early_boss_key.bin new file mode 100644 index 00000000..82071c69 Binary files /dev/null and b/res/save_files_wii/any_bite/early_boss_key.bin differ diff --git a/res/save_files_wii/any_bite/early_city.bin b/res/save_files_wii/any_bite/early_city.bin new file mode 100644 index 00000000..84357455 Binary files /dev/null and b/res/save_files_wii/any_bite/early_city.bin differ diff --git a/res/save_files_wii/any_bite/earlypf.bin b/res/save_files_wii/any_bite/earlypf.bin new file mode 100644 index 00000000..fccfcc7e Binary files /dev/null and b/res/save_files_wii/any_bite/earlypf.bin differ diff --git a/res/save_files_wii/any_bite/eldin_twilight.bin b/res/save_files_wii/any_bite/eldin_twilight.bin new file mode 100644 index 00000000..642edb3f Binary files /dev/null and b/res/save_files_wii/any_bite/eldin_twilight.bin differ diff --git a/res/save_files_wii/any_bite/ems.bin b/res/save_files_wii/any_bite/ems.bin new file mode 100644 index 00000000..38a5fefe Binary files /dev/null and b/res/save_files_wii/any_bite/ems.bin differ diff --git a/res/save_files_wii/any_bite/enter_lakebed.bin b/res/save_files_wii/any_bite/enter_lakebed.bin new file mode 100644 index 00000000..2421f01c Binary files /dev/null and b/res/save_files_wii/any_bite/enter_lakebed.bin differ diff --git a/res/save_files_wii/any_bite/epona_oob_to_flight_by_fowl.bin b/res/save_files_wii/any_bite/epona_oob_to_flight_by_fowl.bin new file mode 100644 index 00000000..7344b995 Binary files /dev/null and b/res/save_files_wii/any_bite/epona_oob_to_flight_by_fowl.bin differ diff --git a/res/save_files_wii/any_bite/fan_tower.bin b/res/save_files_wii/any_bite/fan_tower.bin new file mode 100644 index 00000000..2d3b9d9c Binary files /dev/null and b/res/save_files_wii/any_bite/fan_tower.bin differ diff --git a/res/save_files_wii/any_bite/faron_twilight.bin b/res/save_files_wii/any_bite/faron_twilight.bin new file mode 100644 index 00000000..8e1923d9 Binary files /dev/null and b/res/save_files_wii/any_bite/faron_twilight.bin differ diff --git a/res/save_files_wii/any_bite/freezard_skip.bin b/res/save_files_wii/any_bite/freezard_skip.bin new file mode 100644 index 00000000..759aaa82 Binary files /dev/null and b/res/save_files_wii/any_bite/freezard_skip.bin differ diff --git a/res/save_files_wii/any_bite/goats.bin b/res/save_files_wii/any_bite/goats.bin new file mode 100644 index 00000000..4c501d09 Binary files /dev/null and b/res/save_files_wii/any_bite/goats.bin differ diff --git a/res/save_files_wii/any_bite/hc.bin b/res/save_files_wii/any_bite/hc.bin new file mode 100644 index 00000000..17a6e3f6 Binary files /dev/null and b/res/save_files_wii/any_bite/hc.bin differ diff --git a/res/save_files_wii/any_bite/horseback.bin b/res/save_files_wii/any_bite/horseback.bin new file mode 100644 index 00000000..3ca6b794 Binary files /dev/null and b/res/save_files_wii/any_bite/horseback.bin differ diff --git a/res/save_files_wii/any_bite/hugo.bin b/res/save_files_wii/any_bite/hugo.bin new file mode 100644 index 00000000..a2406581 Binary files /dev/null and b/res/save_files_wii/any_bite/hugo.bin differ diff --git a/res/save_files_wii/any_bite/iza.bin b/res/save_files_wii/any_bite/iza.bin new file mode 100644 index 00000000..2aad0d01 Binary files /dev/null and b/res/save_files_wii/any_bite/iza.bin differ diff --git a/res/save_files_wii/any_bite/kb1.bin b/res/save_files_wii/any_bite/kb1.bin new file mode 100644 index 00000000..54331f27 Binary files /dev/null and b/res/save_files_wii/any_bite/kb1.bin differ diff --git a/res/save_files_wii/any_bite/lakebed_1.bin b/res/save_files_wii/any_bite/lakebed_1.bin new file mode 100644 index 00000000..db632e18 Binary files /dev/null and b/res/save_files_wii/any_bite/lakebed_1.bin differ diff --git a/res/save_files_wii/any_bite/lanayru_twilight.bin b/res/save_files_wii/any_bite/lanayru_twilight.bin new file mode 100644 index 00000000..ab8aa060 Binary files /dev/null and b/res/save_files_wii/any_bite/lanayru_twilight.bin differ diff --git a/res/save_files_wii/any_bite/mdh_bridge.bin b/res/save_files_wii/any_bite/mdh_bridge.bin new file mode 100644 index 00000000..e33dd428 Binary files /dev/null and b/res/save_files_wii/any_bite/mdh_bridge.bin differ diff --git a/res/save_files_wii/any_bite/mdh_tower.bin b/res/save_files_wii/any_bite/mdh_tower.bin new file mode 100644 index 00000000..829ba4eb Binary files /dev/null and b/res/save_files_wii/any_bite/mdh_tower.bin differ diff --git a/res/save_files_wii/any_bite/messenger_skip.bin b/res/save_files_wii/any_bite/messenger_skip.bin new file mode 100644 index 00000000..eea942b5 Binary files /dev/null and b/res/save_files_wii/any_bite/messenger_skip.bin differ diff --git a/res/save_files_wii/any_bite/morpheel.bin b/res/save_files_wii/any_bite/morpheel.bin new file mode 100644 index 00000000..35e62f02 Binary files /dev/null and b/res/save_files_wii/any_bite/morpheel.bin differ diff --git a/res/save_files_wii/any_bite/ordon_gate_clip.bin b/res/save_files_wii/any_bite/ordon_gate_clip.bin new file mode 100644 index 00000000..3ab14454 Binary files /dev/null and b/res/save_files_wii/any_bite/ordon_gate_clip.bin differ diff --git a/res/save_files_wii/any_bite/plumm_oob.bin b/res/save_files_wii/any_bite/plumm_oob.bin new file mode 100644 index 00000000..1b46dacd Binary files /dev/null and b/res/save_files_wii/any_bite/plumm_oob.bin differ diff --git a/res/save_files_wii/any_bite/poe_1_skip.bin b/res/save_files_wii/any_bite/poe_1_skip.bin new file mode 100644 index 00000000..4a18d28e Binary files /dev/null and b/res/save_files_wii/any_bite/poe_1_skip.bin differ diff --git a/res/save_files_wii/any_bite/pot1.bin b/res/save_files_wii/any_bite/pot1.bin new file mode 100644 index 00000000..890cfe15 Binary files /dev/null and b/res/save_files_wii/any_bite/pot1.bin differ diff --git a/res/save_files_wii/any_bite/pot2.bin b/res/save_files_wii/any_bite/pot2.bin new file mode 100644 index 00000000..0d5f49fc Binary files /dev/null and b/res/save_files_wii/any_bite/pot2.bin differ diff --git a/res/save_files_wii/any_bite/purple_mist.bin b/res/save_files_wii/any_bite/purple_mist.bin new file mode 100644 index 00000000..5b6e86a9 Binary files /dev/null and b/res/save_files_wii/any_bite/purple_mist.bin differ diff --git a/res/save_files_wii/any_bite/seam_clip.bin b/res/save_files_wii/any_bite/seam_clip.bin new file mode 100644 index 00000000..ef1f19fa Binary files /dev/null and b/res/save_files_wii/any_bite/seam_clip.bin differ diff --git a/res/save_files_wii/any_bite/snowpeak_ruins_mbbb.bin b/res/save_files_wii/any_bite/snowpeak_ruins_mbbb.bin new file mode 100644 index 00000000..068541fa Binary files /dev/null and b/res/save_files_wii/any_bite/snowpeak_ruins_mbbb.bin differ diff --git a/res/save_files_wii/any_bite/stallord.bin b/res/save_files_wii/any_bite/stallord.bin new file mode 100644 index 00000000..1f07d30f Binary files /dev/null and b/res/save_files_wii/any_bite/stallord.bin differ diff --git a/res/save_files_wii/any_bite/stupidroom.bin b/res/save_files_wii/any_bite/stupidroom.bin new file mode 100644 index 00000000..cce6bf7c Binary files /dev/null and b/res/save_files_wii/any_bite/stupidroom.bin differ diff --git a/res/save_files_wii/any_bite/towerclimb.bin b/res/save_files_wii/any_bite/towerclimb.bin new file mode 100644 index 00000000..1c6d7bb5 Binary files /dev/null and b/res/save_files_wii/any_bite/towerclimb.bin differ diff --git a/res/save_files_wii/any_bite/waterfall_sidehop.bin b/res/save_files_wii/any_bite/waterfall_sidehop.bin new file mode 100644 index 00000000..a8671b5b Binary files /dev/null and b/res/save_files_wii/any_bite/waterfall_sidehop.bin differ diff --git a/res/save_files_wii/any_bite/zant.bin b/res/save_files_wii/any_bite/zant.bin new file mode 100644 index 00000000..811bed43 Binary files /dev/null and b/res/save_files_wii/any_bite/zant.bin differ