From 291973fffeb9c5c41e9269d5731c296edd2f1771 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Tue, 28 May 2024 19:14:39 +0100 Subject: [PATCH 01/82] Use HOOK_ID typedef (#581) --- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 4 ++-- mm/2s2h/Enhancements/Camera/FreeLook.cpp | 4 ++-- mm/2s2h/Enhancements/Cheats/MoonJump.cpp | 2 +- mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index 0014a3f5d..c166576ce 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -214,8 +214,8 @@ void Camera_DebugCam(Camera* camera) { *eye = *eyeNext; } -static uint32_t freeCamVBHookId = 0; -static uint32_t freeCamDisableInputsId = 0; +static HOOK_ID freeCamVBHookId = 0; +static HOOK_ID freeCamDisableInputsId = 0; void RegisterDebugCam() { sDebugCamRefreshParams = true; diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.cpp b/mm/2s2h/Enhancements/Camera/FreeLook.cpp index 63a94f0d0..b7e26e51c 100644 --- a/mm/2s2h/Enhancements/Camera/FreeLook.cpp +++ b/mm/2s2h/Enhancements/Camera/FreeLook.cpp @@ -144,8 +144,8 @@ bool Camera_CanFreeLook(Camera* camera) { return sCanFreeLook; } -static uint32_t freeLookCameraSettingChangeHookId = 0; -static uint32_t freeLookCameraVBHookId = 0; +static HOOK_ID freeLookCameraSettingChangeHookId = 0; +static HOOK_ID freeLookCameraVBHookId = 0; void RegisterCameraFreeLook() { if (freeLookCameraVBHookId) { diff --git a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp index f1cb173f8..5dc2a3033 100644 --- a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp +++ b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp @@ -3,7 +3,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" #include "variables.h" -static uint32_t moonJumpOnLGameStateUpdateHookId = 0; +static HOOK_ID moonJumpOnLGameStateUpdateHookId = 0; void RegisterMoonJumpOnL() { if (moonJumpOnLGameStateUpdateHookId) { GameInteractor::Instance->UnregisterGameHook( diff --git a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp index ed8171cc9..860ee49c3 100644 --- a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp +++ b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp @@ -12,8 +12,8 @@ static uint32_t iconTimer = 0; static uint64_t currentTimestamp = 0; static uint64_t lastSaveTimestamp = GetUnixTimestamp(); -static uint32_t autosaveGameStateUpdateHookId = 0; -static uint32_t autosaveGameStateDrawFinishHookId = 0; +static HOOK_ID autosaveGameStateUpdateHookId = 0; +static HOOK_ID autosaveGameStateDrawFinishHookId = 0; // Used for saving through Autosaves and Pause Menu saves. extern "C" int32_t GetSaveEntrance(PlayState* play) { From e484e0ba825e67402e4ca0e2b49eaaa2c2fbecdc Mon Sep 17 00:00:00 2001 From: Qlonever <42286723+Qlonever@users.noreply.github.com> Date: Thu, 30 May 2024 22:36:14 -0400 Subject: [PATCH 02/82] fix control code logic (#586) --- mm/2s2h/BenGui/BenMenuBar.cpp | 4 ++++ mm/src/code/z_message_nes.c | 30 ++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 5cea0a443..1807a9a56 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -496,6 +496,10 @@ void DrawEnhancementsMenu() { { .tooltip = "Fixes a crash that can occur when performing a HESS or Weirdshot.", .defaultValue = true }); + UIWidgets::CVarCheckbox("Fix Text Control Characters", "gEnhancements.Fixes.ControlCharacters", + { .tooltip = "Fixes certain control characters not functioning properly " + "depending on their position within the text." }); + ImGui::EndMenu(); } diff --git a/mm/src/code/z_message_nes.c b/mm/src/code/z_message_nes.c index 7e6b43852..266549e83 100644 --- a/mm/src/code/z_message_nes.c +++ b/mm/src/code/z_message_nes.c @@ -431,7 +431,10 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { msgCtx->textColorR = msgCtx->textColorG = msgCtx->textColorB = 255; } - if ((i + 1) == msgCtx->textDrawPos) { + if ((i + 1) == msgCtx->textDrawPos || + // 2S2H [Enhancement] To match how PAL and GC fixed character parsing, any code that checks for + // (i + 1) == msgCtx->textDrawPos should also check for (i + 2) == msgCtx->textDrawPos + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) { msgCtx->textDrawPos++; } break; @@ -495,7 +498,8 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { msgCtx->textColorB = D_801D080C[(s16)((u8)character - 1)].b; } - if ((i + 1) == msgCtx->textDrawPos) { + if ((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) { msgCtx->textDrawPos++; } break; @@ -554,7 +558,8 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { return; case 0x17: // MESSAGE_QUICKTEXT_ENABLE - if ((i + 1) == msgCtx->textDrawPos) { + if ((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) { if ((msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) || ((msgCtx->msgMode >= MSGMODE_OCARINA_STARTING) && (msgCtx->msgMode <= MSGMODE_26))) { j = i; @@ -621,19 +626,24 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { return; case 0x1E: // MESSAGE_SFX - if (((i + 1) == msgCtx->textDrawPos) && (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) { + if (((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) && + (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) { stateTimerHi = msgCtx->decodedBuffer.schar[i + 1] << 8; stateTimerHi += (uint8_t)msgCtx->decodedBuffer.schar[i + 2]; Audio_PlaySfx(stateTimerHi); } - if ((i + 1) == msgCtx->textDrawPos) { + if ((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) { msgCtx->textDrawPos += 2; } i += 2; break; case 0x1F: - if (((i + 1) == msgCtx->textDrawPos) && (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) { + if (((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) && + (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) { msgCtx->msgMode = MSGMODE_9; stateTimerHi = msgCtx->decodedBuffer.schar[i + 1] << 8; stateTimerHi += msgCtx->decodedBuffer.schar[i + 2]; @@ -654,7 +664,9 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { case 0x5: case 0x6: msgCtx->textDelay = (u8)character - 0x0; - if ((i + 1) == msgCtx->textDrawPos) { + if ((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && + CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0))) { msgCtx->textDrawPos++; } break; @@ -851,7 +863,9 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) { default: break; } - if ((msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) && ((i + 1) == msgCtx->textDrawPos)) { + if ((msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) && + ((i + 1) == msgCtx->textDrawPos || + ((i + 2) == msgCtx->textDrawPos && CVarGetInteger("gEnhancements.Fixes.ControlCharacters", 0)))) { Audio_PlaySfx(NA_SE_NONE); } From 53e76c5aeb7f4574ba9f9101f83ba1415d1dc0fc Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 2 Jun 2024 20:10:08 -0500 Subject: [PATCH 03/82] Add time-moves-when-you-move mode (#536) --- mm/2s2h/BenGui/BenMenuBar.cpp | 4 +++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + .../Modes/TimeMovesWhenYouMove.cpp | 31 +++++++++++++++++++ .../Enhancements/Modes/TimeMovesWhenYouMove.h | 6 ++++ 5 files changed, 43 insertions(+) create mode 100644 mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp create mode 100644 mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index ae63ead7b..056fbd055 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -10,6 +10,7 @@ #include "2s2h/Enhancements/Enhancements.h" #include "2s2h/Enhancements/Graphics/MotionBlur.h" #include "2s2h/Enhancements/Graphics/PlayAsKafei.h" +#include "2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h" #include "2s2h/DeveloperTools/DeveloperTools.h" #include "2s2h/DeveloperTools/WarpPoint.h" #include "HudEditor.h" @@ -539,6 +540,9 @@ void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Modes")) { UIWidgets::CVarCheckbox("Play As Kafei", "gModes.PlayAsKafei", { .tooltip = "Requires scene reload to take effect." }); + if (UIWidgets::CVarCheckbox("Time Moves When You Move", "gModes.TimeMovesWhenYouMove")) { + RegisterTimeMovesWhenYouMove(); + } ImGui::EndMenu(); } if (UIWidgets::BeginMenu("Player Movement")) { diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index c71ab37af..c7623e6a6 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -42,6 +42,7 @@ void InitEnhancements() { // Modes RegisterPlayAsKafei(); + RegisterTimeMovesWhenYouMove(); // Player Movement RegisterClimbSpeed(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 3a6a303b6..673aa3fd1 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -23,6 +23,7 @@ #include "PlayerMovement/ClimbSpeed.h" #include "Songs/EnableSunsSong.h" #include "Saving/SavingEnhancements.h" +#include "Modes/TimeMovesWhenYouMove.h" enum AlwaysWinDoggyRaceOptions { ALWAYS_WIN_DOGGY_RACE_OFF, diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp new file mode 100644 index 000000000..8c56f8b8c --- /dev/null +++ b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp @@ -0,0 +1,31 @@ +#include "TimeMovesWhenYouMove.h" +#include "libultraship/libultraship.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "macros.h" +#include "z64.h" +extern PlayState* gPlayState; +extern SaveContext gSaveContext; +} + +static HOOK_ID onActorUpdateHookId = 0; + +void RegisterTimeMovesWhenYouMove() { + GameInteractor::Instance->UnregisterGameHookForID(onActorUpdateHookId); + onActorUpdateHookId = 0; + gSaveContext.save.timeSpeedOffset = 0; + + if (CVarGetInteger("gModes.TimeMovesWhenYouMove", 0)) { + onActorUpdateHookId = GameInteractor::Instance->RegisterGameHookForID( + ACTOR_PLAYER, [](Actor* actor) { + Player* player = GET_PLAYER(gPlayState); + + gSaveContext.save.timeSpeedOffset = -R_TIME_SPEED; + if (player->linearVelocity != 0) { + gSaveContext.save.timeSpeedOffset = + CLAMP(player->linearVelocity / 2 - R_TIME_SPEED, -R_TIME_SPEED, 10); + } + }); + } +} diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h new file mode 100644 index 000000000..15532cd21 --- /dev/null +++ b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h @@ -0,0 +1,6 @@ +#ifndef MODES_TIME_MOVES_WHEN_YOU_MOVE_H +#define MODES_TIME_MOVES_WHEN_YOU_MOVE_H + +void RegisterTimeMovesWhenYouMove(); + +#endif // MODES_TIME_MOVES_WHEN_YOU_MOVE_H From 888b8fe24acf2595e3c9e0f1735bfcada19ddf0a Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 2 Jun 2024 21:18:16 -0400 Subject: [PATCH 04/82] Skip Magic Arrow Equip Animation (#546) * Recreate Magic Equip Animation Skip PR for new Fork. * After Running Clang Powershell Script * Delete clang-format.exe * Apply suggestions from code review --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 6 ++++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 +++ mm/2s2h/Enhancements/Enhancements.h | 1 + .../Equipment/SkipMagicArrowEquip.cpp | 21 +++++++++++++++++++ .../Equipment/SkipMagicArrowEquip.h | 6 ++++++ .../GameInteractor/GameInteractor.cpp | 4 ++++ .../GameInteractor/GameInteractor.h | 3 +++ .../ovl_kaleido_scope/z_kaleido_scope_NES.c | 3 +++ 8 files changed, 47 insertions(+) create mode 100644 mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp create mode 100644 mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 056fbd055..af1bcc826 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -490,6 +490,12 @@ void DrawEnhancementsMenu() { ImGui::EndMenu(); } + if (UIWidgets::BeginMenu("Equipment")) { + UIWidgets::CVarCheckbox("Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", + { .tooltip = "Removes the animation for equipping Magic Arrows." }); + ImGui::EndMenu(); + } + if (UIWidgets::BeginMenu("Fixes")) { UIWidgets::CVarCheckbox("Fix Ammo Count Color", "gFixes.FixAmmoCountEnvColor", { .tooltip = "Fixes a missing gDPSetEnvColor, which causes the ammo count to be " diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index c7623e6a6..6896637ce 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -20,6 +20,9 @@ void InitEnhancements() { RegisterSavingEnhancements(); RegisterAutosave(); + // Equipment + RegisterSkipMagicArrowEquip(); + // Masks RegisterFastTransformation(); RegisterFierceDeityAnywhere(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 673aa3fd1..b4be56a95 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -10,6 +10,7 @@ #include "Cheats/UnbreakableRazorSword.h" #include "Cheats/UnrestrictedItems.h" #include "Cycle/EndOfCycle.h" +#include "Equipment/SkipMagicArrowEquip.h" #include "Masks/FierceDeityAnywhere.h" #include "Masks/NoBlastMaskCooldown.h" #include "Masks/FastTransformation.h" diff --git a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp new file mode 100644 index 000000000..299748061 --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp @@ -0,0 +1,21 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "z64.h" +#include "src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" + +extern "C" { +extern s16 sEquipState; +extern s16 sEquipAnimTimer; +} + +void RegisterSkipMagicArrowEquip() { + GameInteractor::Instance->RegisterGameHook([](PauseContext* pauseCtx) { + if (CVarGetInteger("gEnhancements.Equipment.MagicArrowEquipSpeed", 0)) { + if (sEquipState == EQUIP_STATE_MAGIC_ARROW_GROW_ORB) { + sEquipState = EQUIP_STATE_MAGIC_ARROW_MOVE_TO_BOW_SLOT; + sEquipAnimTimer = 2; + pauseCtx->equipAnimAlpha = 255; + } + } + }); +} diff --git a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h new file mode 100644 index 000000000..2c96b97b9 --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h @@ -0,0 +1,6 @@ +#ifndef EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H +#define EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H + +void RegisterSkipMagicArrowEquip(); + +#endif // EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index 20ddcf6ba..ae7eda45d 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -19,6 +19,10 @@ void GameInteractor_ExecuteOnGameStateUpdate() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx) { + GameInteractor::Instance->ExecuteHooks(pauseCtx); +} + void GameInteractor_ExecuteOnSaveInit(s16 fileNum) { GameInteractor::Instance->ExecuteHooks(fileNum); } diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index c6a44249d..873f5bf61 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -7,6 +7,7 @@ extern "C" { #endif #include "z64actor.h" #include "z64camera.h" +#include "z64.h" #ifdef __cplusplus } #endif @@ -254,6 +255,7 @@ class GameInteractor { DEFINE_HOOK(OnGameStateMainFinish, ()); DEFINE_HOOK(OnGameStateDrawFinish, ()); DEFINE_HOOK(OnGameStateUpdate, ()); + DEFINE_HOOK(OnKaleidoUpdate, (PauseContext * pauseCtx)); DEFINE_HOOK(OnSaveInit, (s16 fileNum)); DEFINE_HOOK(BeforeEndOfCycleSave, ()); DEFINE_HOOK(AfterEndOfCycleSave, ()); @@ -296,6 +298,7 @@ extern "C" { void GameInteractor_ExecuteOnGameStateMainFinish(); void GameInteractor_ExecuteOnGameStateDrawFinish(); void GameInteractor_ExecuteOnGameStateUpdate(); +void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx); void GameInteractor_ExecuteOnSaveInit(s16 fileNum); void GameInteractor_ExecuteBeforeEndOfCycleSave(); void GameInteractor_ExecuteAfterEndOfCycleSave(); diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index 071f4d208..0ba1082f2 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -22,6 +22,8 @@ #include "2s2h_assets.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + // Page Textures (Background of Page): // Broken up into multiple textures. // Numbered by column/row. @@ -4231,4 +4233,5 @@ void KaleidoScope_Update(PlayState* play) { if ((pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY_INIT) || (pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY)) { KaleidoScope_UpdateInventoryEditor(play); } + GameInteractor_ExecuteOnKaleidoUpdate(pauseCtx); } From 26321c9a173de63fbc1cd9d17bc9e10f4f0f00fa Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 2 Jun 2024 22:18:17 -0400 Subject: [PATCH 05/82] Adds Dungeon Items to the Save Editor (#585) * Adds Dungeon Items to the Save Editor * clang'd up * Update mm/include/z64save.h Co-authored-by: Garrett Cox * Move a few static arrays --------- Co-authored-by: Garrett Cox --- mm/2s2h/DeveloperTools/SaveEditor.cpp | 125 ++++++++++++++++++++++++++ mm/include/z64save.h | 2 + 2 files changed, 127 insertions(+) diff --git a/mm/2s2h/DeveloperTools/SaveEditor.cpp b/mm/2s2h/DeveloperTools/SaveEditor.cpp index 007f29d0e..7645708bc 100644 --- a/mm/2s2h/DeveloperTools/SaveEditor.cpp +++ b/mm/2s2h/DeveloperTools/SaveEditor.cpp @@ -2,6 +2,9 @@ #include "2s2h/BenGui/UIWidgets.hpp" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "interface/icon_item_dungeon_static/icon_item_dungeon_static.h" +#include "archives/icon_item_24_static/icon_item_24_static_yar.h" + extern "C" { #include #include @@ -280,6 +283,15 @@ void DrawGeneralTab() { gSaveContext.save.saveInfo.playerData.isMagicAcquired = false; gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired = false; } + ImGui::SameLine(); + bool spinAttack = CHECK_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK); + if (UIWidgets::Checkbox("Spin Lv2", &spinAttack, { .color = UIWidgets::Colors::DarkGreen })) { + if (spinAttack) { + SET_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK); + } else { + CLEAR_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK); + } + } UIWidgets::PushStyleSlider(UIWidgets::Colors::DarkGreen); if (ImGui::SliderScalar("##magicLevelSlider", ImGuiDataType_S8, &gSaveContext.save.saveInfo.playerData.magicLevel, &S8_ZERO, &MAGIC_LEVEL_MAX, @@ -947,6 +959,101 @@ void DrawQuestStatusTab() { ImGui::PopStyleColor(1); } +void SetDungeonItems(uint32_t dungeonItem, uint32_t dungeonId) { + if (CHECK_DUNGEON_ITEM(dungeonItem, dungeonId)) { + REMOVE_DUNGEON_ITEM(dungeonItem, dungeonId); + } else { + SET_DUNGEON_ITEM(dungeonItem, dungeonId); + } +} + +const char* dungeonNames[4] = { "Woodfall Temple", "Snowhead Temple", "Great Bay Temple", "Stone Tower Temple" }; +uint32_t smallKeyCounts[4] = { 1, 3, 1, 4 }; +const char* fairyIcons[] = { gDungeonStrayFairyWoodfallIconTex, gDungeonStrayFairySnowheadIconTex, + gDungeonStrayFairyGreatBayIconTex, gDungeonStrayFairyStoneTowerIconTex }; +void DrawDungeonItemTab() { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 8.0f)); + ImGui::BeginChild("dungeonTab", ImVec2(0, 0), true); + + for (int i = DUNGEON_INDEX_WOODFALL_TEMPLE; i <= DUNGEON_INDEX_STONE_TOWER_TEMPLE; i++) { + std::string stray_id = "Stray" + std::to_string(i); + std::string map_id = "Map" + std::to_string(i); + std::string comp_id = "Compass" + std::to_string(i); + std::string sKey_id = "Small Key" + std::to_string(i); + std::string bKey_id = "Boss Key" + std::to_string(i); + int dungeonId = i; + ImGui::BeginChild(std::to_string(i).c_str(), + ImVec2(INV_GRID_WIDTH * 6 + INV_GRID_PADDING * 2, INV_GRID_HEIGHT * 1.5 + INV_GRID_PADDING), + ImGuiChildFlags_Border); + ImGui::Text(dungeonNames[i]); + if (ImGui::ImageButton( + stray_id.c_str(), + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(fairyIcons[dungeonId]), + ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), + ImVec4(1, 1, 1, gSaveContext.save.saveInfo.inventory.strayFairies[dungeonId] ? 1.0f : 0.4f))) { + ImGui::OpenPopup("strayFairies"); + } + ImGui::SameLine(); + if (ImGui::ImageButton( + map_id.c_str(), + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gQuestIconDungeonMapTex), + ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), + ImVec4(1, 1, 1, CHECK_DUNGEON_ITEM(DUNGEON_MAP, i) ? 1.0f : 0.4f))) { + SetDungeonItems(DUNGEON_MAP, i); + } + ImGui::SameLine(); + if (ImGui::ImageButton( + comp_id.c_str(), + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gQuestIconCompassTex), + ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), + ImVec4(1, 1, 1, CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, i) ? 1.0f : 0.4f))) { + SetDungeonItems(DUNGEON_COMPASS, i); + } + ImGui::SameLine(); + if (ImGui::ImageButton( + sKey_id.c_str(), + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gQuestIconSmallKeyTex), + ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), + ImVec4(1, 1, 1, DUNGEON_KEY_COUNT(i) + 1 ? 1.0f : 0.4f))) { + ImGui::OpenPopup("smallKeys"); + } + ImGui::SameLine(); + if (ImGui::ImageButton( + bKey_id.c_str(), + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gQuestIconBossKeyTex), + ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), + ImVec4(1, 1, 1, CHECK_DUNGEON_ITEM(DUNGEON_BOSS_KEY, i) ? 1.0f : 0.4f))) { + SetDungeonItems(DUNGEON_BOSS_KEY, i); + } + if (ImGui::BeginPopup("strayFairies")) { + s32 minStray = 0; + s32 maxStray = 15; + int currentStrays = gSaveContext.save.saveInfo.inventory.strayFairies[dungeonId]; + if (ImGui::SliderScalar("##strayCount", ImGuiDataType_S32, ¤tStrays, &minStray, &maxStray, + "Strays: %d")) { + gSaveContext.save.saveInfo.inventory.strayFairies[dungeonId] = currentStrays; + } + ImGui::EndPopup(); + } + if (ImGui::BeginPopup("smallKeys")) { + s32 minKey = -1; + s32 maxKey = smallKeyCounts[dungeonId]; + int currentKeys = gSaveContext.save.saveInfo.inventory.dungeonKeys[dungeonId]; + if (ImGui::SliderScalar("##sKeyCount", ImGuiDataType_S32, ¤tKeys, &minKey, &maxKey, + "Small Keys: %d")) { + gSaveContext.save.saveInfo.inventory.dungeonKeys[dungeonId] = currentKeys; + } + ImGui::EndPopup(); + } + ImGui::EndChild(); + } + ImGui::EndChild(); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +} + void GetPlayerForm(uint32_t form) { switch (form) { case PLAYER_FORM_FIERCE_DEITY: @@ -1694,6 +1801,11 @@ void SaveEditorWindow::DrawElement() { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("Dungeon Items")) { + DrawDungeonItemTab(); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Reg Editor")) { DrawRegEditorTab(); ImGui::EndTabItem(); @@ -1720,6 +1832,15 @@ void SaveEditorWindow::DrawElement() { ImGui::End(); } +const char* textureLoad[8] = { gDungeonStrayFairyWoodfallIconTex, + gDungeonStrayFairySnowheadIconTex, + gDungeonStrayFairyGreatBayIconTex, + gDungeonStrayFairyStoneTowerIconTex, + gQuestIconDungeonMapTex, + gQuestIconCompassTex, + gQuestIconSmallKeyTex, + gQuestIconBossKeyTex }; + void SaveEditorWindow::InitElement() { initSafeItemsForInventorySlot(); @@ -1727,4 +1848,8 @@ void SaveEditorWindow::InitElement() { const char* path = static_cast(entry); Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1)); } + for (int i = 0; i <= 7; i++) { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(textureLoad[i], textureLoad[i], + ImVec4(1, 1, 1, 1)); + } } diff --git a/mm/include/z64save.h b/mm/include/z64save.h index 5dc8c5f8f..73cc19e1f 100644 --- a/mm/include/z64save.h +++ b/mm/include/z64save.h @@ -526,6 +526,8 @@ typedef enum { #define CHECK_DUNGEON_ITEM(item, dungeonIndex) (gSaveContext.save.saveInfo.inventory.dungeonItems[(void)0, dungeonIndex] & gBitFlags[item]) #define CHECK_DUNGEON_ITEM_ALT(item, dungeonIndex) (gSaveContext.save.saveInfo.inventory.dungeonItems[dungeonIndex] & gBitFlags[item]) #define SET_DUNGEON_ITEM(item, dungeonIndex) (gSaveContext.save.saveInfo.inventory.dungeonItems[(void)0, dungeonIndex] |= (u8)gBitFlags[item]) +// 2S2H [Enhancements] We added this for save editor +#define REMOVE_DUNGEON_ITEM(item, dungeonIndex) (gSaveContext.save.saveInfo.inventory.dungeonItems[(void)0, dungeonIndex] &= ~(u8)gBitFlags[item]) #define DUNGEON_KEY_COUNT(dungeonIndex) (gSaveContext.save.saveInfo.inventory.dungeonKeys[(void)0, dungeonIndex]) #define GET_DUNGEON_FLOOR_VISITED(sceneId, floor) (gSaveContext.save.saveInfo.permanentSceneFlags[(sceneId)].unk_14 & gBitFlags[floor]) #define SET_DUNGEON_FLOOR_VISITED(sceneId, floor) (gSaveContext.save.saveInfo.permanentSceneFlags[(sceneId)].unk_14 |= gBitFlags[floor]) From 139a240ed3424509eddbbef52f79292d4692a08c Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:32:19 -0400 Subject: [PATCH 06/82] [Graphics] Disable Black Bar Letterboxes (#590) * Black Bars be gone * Move it to draw/apply functions Updates in real time now * Added return instead * added space * Update mm/2s2h/Enhancements/Enhancements.cpp * Update mm/2s2h/Enhancements/Enhancements.cpp --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 5 +++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 +++ mm/2s2h/Enhancements/Enhancements.h | 1 + mm/2s2h/Enhancements/GameInteractor/GameInteractor.h | 1 + mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp | 11 +++++++++++ mm/2s2h/Enhancements/Graphics/DisableBlackBars.h | 6 ++++++ mm/src/code/z_shrink_window.c | 5 +++++ mm/src/code/z_view.c | 5 +++++ 8 files changed, 37 insertions(+) create mode 100644 mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp create mode 100644 mm/2s2h/Enhancements/Graphics/DisableBlackBars.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index af1bcc826..f1f09cb4b 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -523,6 +523,11 @@ void DrawEnhancementsMenu() { "model and texture on the boot logo start screen" }); UIWidgets::CVarCheckbox("Bow Reticle", "gEnhancements.Graphics.BowReticle", { .tooltip = "Gives the bow a reticle when you draw an arrow" }); + UIWidgets::CVarCheckbox( + "Disable Black Bar Letterboxes", "gEnhancements.Graphics.DisableBlackBars", + { .tooltip = "Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be " + "minor visual glitches that were covered up by the black bars\nPlease disable this " + "setting before reporting a bug" }); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 6896637ce..fe213e977 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -23,6 +23,9 @@ void InitEnhancements() { // Equipment RegisterSkipMagicArrowEquip(); + // Graphics + RegisterDisableBlackBars(); + // Masks RegisterFastTransformation(); RegisterFierceDeityAnywhere(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index b4be56a95..3461bda91 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -24,6 +24,7 @@ #include "PlayerMovement/ClimbSpeed.h" #include "Songs/EnableSunsSong.h" #include "Saving/SavingEnhancements.h" +#include "Graphics/DisableBlackBars.h" #include "Modes/TimeMovesWhenYouMove.h" enum AlwaysWinDoggyRaceOptions { diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 873f5bf61..fe10c1f29 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -52,6 +52,7 @@ typedef enum { GI_VB_TATL_INTERUPT_MSG6, GI_VB_ITEM_BE_RESTRICTED, GI_VB_FLIP_HOP_VARIABLE, + GI_VB_DISABLE_LETTERBOX, GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, } GIVanillaBehavior; diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp new file mode 100644 index 000000000..21466d732 --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp @@ -0,0 +1,11 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "DisableBlackBars.h" + +void RegisterDisableBlackBars() { + REGISTER_VB_SHOULD(GI_VB_DISABLE_LETTERBOX, { + if (CVarGetInteger("gEnhancements.Graphics.DisableBlackBars", 0)) { + *should = true; + } + }); +} diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h new file mode 100644 index 000000000..fc5be3b3c --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h @@ -0,0 +1,6 @@ +#ifndef GRAPHICS_DISABLE_BLACK_BARS_H +#define GRAPHICS_DISABLE_BLACK_BARS_H + +void RegisterDisableBlackBars(); + +#endif // GRAPHICS_DISABLE_BLACK_BARS_H diff --git a/mm/src/code/z_shrink_window.c b/mm/src/code/z_shrink_window.c index a1e651d01..bca613366 100644 --- a/mm/src/code/z_shrink_window.c +++ b/mm/src/code/z_shrink_window.c @@ -7,6 +7,7 @@ #include "global.h" #include "z64shrink_window.h" #include +#include "Enhancements/GameInteractor/GameInteractor.h" #include "BenPort.h" @@ -79,6 +80,10 @@ void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { s8 letterboxSize = sShrinkWindowPtr->letterboxSize; s8 pillarboxSize = sShrinkWindowPtr->pillarboxSize; + if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false, NULL)) { + return; + } + if (letterboxSize > 0) { OPEN_DISPS(gfxCtx); diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 352e3c975..1e01a9cbc 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -2,6 +2,7 @@ #include "z64shrink_window.h" #include "z64view.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "Enhancements/GameInteractor/GameInteractor.h" s32 View_ApplyPerspective(View* view); s32 View_ApplyOrtho(View* view); @@ -159,6 +160,10 @@ void View_ApplyLetterbox(View* view) { s32 lrx; s32 lry; + if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false, NULL)) { + return; + } + OPEN_DISPS(view->gfxCtx); letterboxY = ShrinkWindow_Letterbox_GetSize(); From 03a597d44c5483eb3a6e033128935f08845cd188 Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 2 Jun 2024 22:52:30 -0400 Subject: [PATCH 07/82] [Enhancement] Banker - Adds Min Max Functionality (#591) * Adds min and max functionality by pressing the R and Z buttons while the Deposit Rupees dialogue box is opened. * Place functionality behind a cvar. * clangified * I slished when i shoulda slashed! * removal of src/ * Typo in tooltip * Updated to dynamic hook registration and fix sfx spam. * clang * Remove double assignment. * Update to HOOK_ID and adds Withdrawal functionaility. * Updated currentTextId's to actual format. * Clangs * Move to dialogue menu --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 7 +- mm/2s2h/Enhancements/Dialogue/Dialogue.h | 6 ++ .../Dialogue/FastBankSelection.cpp | 86 +++++++++++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 + mm/2s2h/Enhancements/Enhancements.h | 1 + 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 mm/2s2h/Enhancements/Dialogue/Dialogue.h create mode 100644 mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index f1f09cb4b..266bf22ed 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -332,7 +332,6 @@ extern std::shared_ptr mHudEditorWindow; void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Enhancements")) { - if (UIWidgets::BeginMenu("Camera")) { ImGui::SeparatorText("Fixes"); UIWidgets::CVarCheckbox( @@ -475,7 +474,11 @@ void DrawEnhancementsMenu() { ImGui::EndMenu(); } - if (UIWidgets::BeginMenu("Dialogues")) { + if (UIWidgets::BeginMenu("Dialogue")) { + UIWidgets::CVarCheckbox( + "Fast Bank Selection", "gEnhancements.Dialogue.FastBankSelection", + { .tooltip = "Pressing the Z or R buttons while the Deposit/Withdrawl Rupees dialogue is open will set " + "the Rupees to Links current Rupees or 0 respectively." }); UIWidgets::CVarCheckbox( "Fast Text", "gEnhancements.Dialogue.FastText", { .tooltip = "Speeds up text rendering, and enables holding of B progress to next message" }); diff --git a/mm/2s2h/Enhancements/Dialogue/Dialogue.h b/mm/2s2h/Enhancements/Dialogue/Dialogue.h new file mode 100644 index 000000000..980e7d523 --- /dev/null +++ b/mm/2s2h/Enhancements/Dialogue/Dialogue.h @@ -0,0 +1,6 @@ +#ifndef DIALOGUES_H +#define DIALOGUES_H + +void RegisterFastBankSelection(); + +#endif // DIALOGUES_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp new file mode 100644 index 000000000..1035fb398 --- /dev/null +++ b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp @@ -0,0 +1,86 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "z64.h" +#include "global.h" + +#include "overlays/actors/ovl_En_Ginko_Man/z_en_ginko_man.h" + +static const char zeroRupees[3] = { '0', '0', '0' }; + +void FastBankSelection_UpdateMessage(const char rupeeValue[3]) { + for (int i = 0; i <= 2; i++) { + gPlayState->msgCtx.decodedBuffer.schar[gPlayState->msgCtx.unk120C0 + i] = rupeeValue[i]; + Font_LoadCharNES(gPlayState, gPlayState->msgCtx.decodedBuffer.schar[gPlayState->msgCtx.unk120C0 + i], + gPlayState->msgCtx.unk120C4 + (i << 7)); + } + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); +} + +void RegisterFastBankSelection() { + GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_GINKO_MAN, [](Actor* outerActor) { + static HOOK_ID enGinkoUpdateHook = 0; + static HOOK_ID enGinkoKillHook = 0; + GameInteractor::Instance->UnregisterGameHookForPtr(enGinkoUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enGinkoKillHook); + enGinkoUpdateHook = 0; + enGinkoKillHook = 0; + + enGinkoUpdateHook = GameInteractor::Instance->RegisterGameHookForPtr( + (uintptr_t)outerActor, [](Actor* actor) { + EnGinkoMan* enGinko = (EnGinkoMan*)actor; + if (CVarGetInteger("gEnhancements.Dialogue.FastBankSelection", 0)) { + if (gPlayState->msgCtx.currentTextId == 0x450) { + if (CHECK_BTN_ALL(gPlayState->state.input[0].cur.button, BTN_Z) && + gPlayState->msgCtx.bankRupeesSelected != gSaveContext.save.saveInfo.playerData.rupees) { + char firstChar = (gSaveContext.save.saveInfo.playerData.rupees / 100) + '0'; + char secondChar = ((gSaveContext.save.saveInfo.playerData.rupees / 10) % 10) + '0'; + char thirdChar = (gSaveContext.save.saveInfo.playerData.rupees % 10) + '0'; + const char rupeeChar[3] = { firstChar, secondChar, thirdChar }; + + FastBankSelection_UpdateMessage(rupeeChar); + } + } else if (gPlayState->msgCtx.currentTextId == 0x46E) { + uint32_t walletSize = CUR_UPG_VALUE(UPG_WALLET); + uint32_t currentRupees = gSaveContext.save.saveInfo.playerData.rupees; + uint32_t maxWallet; + if (CHECK_BTN_ALL(gPlayState->state.input[0].cur.button, BTN_Z)) { + switch (ITEM_WALLET_DEFAULT + walletSize) { + case ITEM_WALLET_ADULT: + maxWallet = (200 - currentRupees); + break; + case ITEM_WALLET_GIANT: + maxWallet = (500 - currentRupees); + break; + default: + maxWallet = (99 - currentRupees); + break; + } + if (maxWallet != 0 && gPlayState->msgCtx.bankRupeesSelected != maxWallet) { + char firstChar = (maxWallet / 100) + '0'; + char secondChar = ((maxWallet / 10) % 10) + '0'; + char thirdChar = (maxWallet % 10) + '0'; + const char rupeeChar[3] = { firstChar, secondChar, thirdChar }; + + FastBankSelection_UpdateMessage(rupeeChar); + } + } + } + if (gPlayState->msgCtx.currentTextId == 0x450 || gPlayState->msgCtx.currentTextId == 0x46E) { + if (CHECK_BTN_ALL(gPlayState->state.input[0].cur.button, BTN_R) && + gPlayState->msgCtx.bankRupeesSelected != 0) { + + FastBankSelection_UpdateMessage(zeroRupees); + } + } + } + }); + enGinkoKillHook = + GameInteractor::Instance->RegisterGameHook([](s8 sceneId, s8 spawnNum) { + GameInteractor::Instance->UnregisterGameHook(enGinkoUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enGinkoKillHook); + enGinkoUpdateHook = 0; + enGinkoKillHook = 0; + }); + }); +} \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index fe213e977..87a119155 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -20,6 +20,9 @@ void InitEnhancements() { RegisterSavingEnhancements(); RegisterAutosave(); + // Dialogue + RegisterFastBankSelection(); + // Equipment RegisterSkipMagicArrowEquip(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 3461bda91..9b78c6aca 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -6,6 +6,7 @@ #include "Camera/FreeLook.h" #include "Cheats/MoonJump.h" #include "Cheats/Infinite.h" +#include "Dialogue/Dialogue.h" #include "Graphics/TextBasedClock.h" #include "Cheats/UnbreakableRazorSword.h" #include "Cheats/UnrestrictedItems.h" From 5de6a9ac8f9d9b339ac51e7cfdd5789298f5aced Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Jun 2024 19:54:36 -0700 Subject: [PATCH 08/82] Add 2ship-specific BUILDING.md and supportedHashes.json. (#551) * Add 2ship-specific BUILDING.md and supportedHashes.json. * Somehow missed N64 hash. Shipwright -> 2ship2harkinian Ship.sln -> 2s2h.sln * Mac dependencies Co-authored-by: inspectredc <78732756+inspectredc@users.noreply.github.com> --------- Co-authored-by: inspectredc <78732756+inspectredc@users.noreply.github.com> --- docs/BUILDING.md | 229 ++++++++++++++++++++++++++++++++++++++ docs/supportedHashes.json | 10 ++ 2 files changed, 239 insertions(+) create mode 100644 docs/BUILDING.md create mode 100644 docs/supportedHashes.json diff --git a/docs/BUILDING.md b/docs/BUILDING.md new file mode 100644 index 000000000..24cd73f45 --- /dev/null +++ b/docs/BUILDING.md @@ -0,0 +1,229 @@ +# Building 2 Ship 2 Harkinian + +## Windows + +Requires: + * At least 8GB of RAM (machines with 4GB have seen complier failures) + * Visual Studio 2022 Community Edition with the C++ feature set + * One of the Windows SDKs that comes with Visual Studio, for example the current Windows 10 version 10.0.19041.0 + * The `MSVC v142 - VS 2019 C++ build tools` component of Visual Studio + * Python 3 (can be installed manually or as part of Visual Studio) + * Git (can be installed manually or as part of Visual Studio) + * Cmake (can be installed via chocolatey or manually) + +During installation, check the "Desktop development with C++" feature set: + +![image](https://user-images.githubusercontent.com/30329717/183511274-d11aceea-7900-46ec-acb6-3f2cc110021a.png) +Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v142 toolset. + +You can also find the v142 toolset by searching through the individual components tab: + +![image](https://user-images.githubusercontent.com/30329717/183521169-ead6a73b-a1bf-4e99-aab8-441746d8f08e.png) +While you're there, you can also install Python 3 and Git if needed. + +1. Clone the 2 Ship 2 Harkinian repository + +_Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule init`` after cloning to pull in the libultraship submodule!_ + +2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice + +_Note: Instructions assume using powershell_ +```powershell +# Navigate to the 2ship2harkinian repo within powershell. ie: cd "C:\yourpath\2ship2harkinian" +cd 2ship2harkinian + +# Setup cmake project +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) +# or for VS2019 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64 +# Extract assets & generate OTR (run this anytime you need to regenerate OTR) +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssets # --config Release (if you're packaging) +# Compile project +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 # --config Release (if you're packaging) + +# Now you can run the executable in .\build\x64 + +# If you need to clean the project you can run +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target clean + +# If you need to regenerate the asset headers to check them into source +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssetHeaders + +# If you need a newer 2ship.o2r only +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target Generate2ShipOtr +``` + +### Developing 2S2H +With the cmake build system you have two options for working on the project: + +#### Visual Studio +To develop using Visual Studio you only need to use cmake to generate the solution file: +```powershell +# Generates 2s2h.sln at `build/x64` for Visual Studio 2022 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 +# or for Visual Studio 2019 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64 +``` + +#### Visual Studio Code or another editor +To develop using Visual Studio Code or another editor you only need to open the repository in it. +To build you'll need to follow the instructions from the building section. + +_Note: If you're using Visual Studio Code, the [cpack plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._ + +_Experimental: You can also use another build system entirely rather than MSVC like [Ninja](https://ninja-build.org/) for possibly better performance._ + + +### Generating the distributable +After compiling the project you can generate the distributable by running: +```powershell +# Go to build folder +cd "build/x64" +# Generate +& 'C:\Program Files\CMake\bin\cpack.exe' -G ZIP +``` + +## Linux +### Install dependencies +#### Debian/Ubuntu +```sh +# using gcc +apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev + +# or using clang +apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev +``` +#### Arch +```sh +# using gcc +pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost + +# or using clang +pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost +``` +#### Fedora +```sh +# using gcc +dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel + +# or using clang +dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel +``` +#### openSUSE +```sh +# using gcc +zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel + +# or using clang +zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel +``` + +### Build + +_Note: If you're using Visual Studio Code, the [CMake Tools plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._ + +```bash +# Clone the repo and enter the directory +git clone https://github.com/HarbourMasters/2ship2harkinian.git +cd 2ship2harkinian + +# Clone the submodules +git submodule update --init + +# Generate Ninja project +cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -DPython3_EXECUTABLE=$(which python3) (if you are using non-standard Python installations such as PyEnv) + +# Generate 2ship.o2r +cmake --build build-cmake --target Generate2ShipOtr + +# Compile the project +cmake --build build-cmake # --config Release (if you're packaging) + +# Now you can run the executable in ./build-cmake/mm/2s2h.elf +# To develop the project open the repository in VSCode (or your preferred editor) +``` + +### Generate a distributable +After compiling the project you can generate a distributable by running of the following: +```bash +# Go to build folder +cd build-cmake +# Generate +cpack -G DEB +cpack -G ZIP +cpack -G External (creates appimage) +``` + +### Additional CMake Targets +#### Clean +```bash +# If you need to clean the project you can run +cmake --build build-cmake --target clean +``` + +#### Regenerate Asset Headers +```bash +# If you need to regenerate the asset headers to check them into source +cp OTRExporter +cmake --build build-cmake --target ExtractAssetHeaders +``` + +## macOS +Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake, nlohmann-json, libzip` (can be installed via homebrew, macports, etc) + +**Important: For maximum performance make sure you have ninja build tools installed!** + +_Note: If you're using Visual Studio Code, the [cpack plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._ + +```bash +# Clone the repo +git clone https://github.com/HarbourMasters/2ship2harkinian.git +cd 2ship2harkinian +# Clone the submodule libultraship +git submodule update --init +# Copy the baserom to the OTRExporter folder +cp OTRExporter +# Generate Ninja project +cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) +# Extract assets & generate OTR (run this anytime you need to regenerate OTR) +cmake --build build-cmake --target ExtractAssets +# Compile the project +cmake --build build-cmake # --config Release (if you're packaging) + +# Now you can run the executable file: +./build-cmake/mm/2s2h-macos +# To develop the project open the repository in VSCode (or your preferred editor) + +# If you need to clean the project you can run +cmake --build build-cmake --target clean + +# If you need to regenerate the asset headers to check them into source +cmake --build build-cmake --target ExtractAssetHeaders + +# If you need a newer 2ship.o2r only +cmake --build build-cmake --target Generate2ShipOtr +``` + +### Generating a distributable +After compiling the project you can generate a distributable by running of the following: +```bash +# Go to build folder +cd build-cmake +# Generate +cpack +``` + +# Compatible Roms +See [`supportedHashes.json`](supportedHashes.json) + +## Getting CI to work on your fork + +The CI works via [Github Actions](https://github.com/features/actions) where we mostly make use of machines hosted by Github; except for the very first step of the CI process called "Extract assets". This steps extracts assets from the game file and generates an "assets" folder in `mm/`. + +To get this step working on your fork, you'll need to add a machine to your own repository as a self-hosted runner via "Settings > Actions > Runners" in your repository settings. Make sure to add the 'asset-builder' tag to your newly added runner to assign it to run this step. To setup your runner as a service read the docs [here](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=linux). + +### Runner on Windows +You'll have to enable the ability to run unsigned scripts through PowerShell. To do this, open Powershell as administrator and run `set-executionpolicy remotesigned`. Most dependencies get installed as part of the CI process. You will also need to separately install 7z and add it to the PATH so `7z` can be run as a command. [Chocolatey](https://chocolatey.org/) or other package managers can be used to install it easily. + +### Runner on UNIX systems +If you're on macOS or Linux take a look at `macports-deps.txt` or `apt-deps.txt` to see the dependencies expected to be on your machine. diff --git a/docs/supportedHashes.json b/docs/supportedHashes.json new file mode 100644 index 000000000..f85ec84c3 --- /dev/null +++ b/docs/supportedHashes.json @@ -0,0 +1,10 @@ +[ + { + "name": "N64 US", + "sha1": "d6133ace5afaa0882cf214cf88daba39e266c078" + }, + { + "name": "GC US", + "sha1": "9743aa026e9269b339eb0e3044cd5830a440c1fd" + } +] \ No newline at end of file From 2d8bc175fef010cff5faba1c21e2dffa3643e624 Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 2 Jun 2024 23:27:33 -0400 Subject: [PATCH 09/82] [Enhancement] Blast Mask with Powder Keg (#642) * Blast Mask adds Powder Keg explosive property. * Alphabetical Menu Listing + clang * Apply suggestions from code review --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 1 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp | 31 +++++++++++++++++++++ mm/2s2h/Enhancements/Masks/BlastMaskKeg.h | 6 ++++ 5 files changed, 40 insertions(+) create mode 100644 mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp create mode 100644 mm/2s2h/Enhancements/Masks/BlastMaskKeg.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 266bf22ed..35d3f5778 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -536,6 +536,7 @@ void DrawEnhancementsMenu() { } if (UIWidgets::BeginMenu("Masks")) { + UIWidgets::CVarCheckbox("Blast Mask has Powder Keg Force", "gEnhancements.Masks.BlastMaskKeg"); UIWidgets::CVarCheckbox("Fast Transformation", "gEnhancements.Masks.FastTransformation"); UIWidgets::CVarCheckbox("Fierce Deity's Mask Anywhere", "gEnhancements.Masks.FierceDeitysAnywhere", { .tooltip = "Allow using Fierce Deity's mask outside of boss rooms." }); diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 87a119155..0b2d2f794 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -32,6 +32,7 @@ void InitEnhancements() { // Masks RegisterFastTransformation(); RegisterFierceDeityAnywhere(); + RegisterBlastMaskKeg(); RegisterNoBlastMaskCooldown(); // Minigames diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 9b78c6aca..5ad8cfb4a 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -12,6 +12,7 @@ #include "Cheats/UnrestrictedItems.h" #include "Cycle/EndOfCycle.h" #include "Equipment/SkipMagicArrowEquip.h" +#include "Masks/BlastMaskKeg.h" #include "Masks/FierceDeityAnywhere.h" #include "Masks/NoBlastMaskCooldown.h" #include "Masks/FastTransformation.h" diff --git a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp new file mode 100644 index 000000000..b883822ec --- /dev/null +++ b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp @@ -0,0 +1,31 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "global.h" + +static uint32_t bombType; + +extern "C" { +#include "overlays/actors/ovl_En_Bom/z_en_bom.h" +EquipSlot func_8082FDC4(void); +} + +void RegisterBlastMaskKeg() { + GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_BOM, [](Actor* actor, bool* should) { + Player* player = GET_PLAYER(gPlayState); + if (CVarGetInteger("gEnhancements.Masks.BlastMaskKeg", 0)) { + ItemId item; + EquipSlot i = func_8082FDC4(); + + i = ((i >= EQUIP_SLOT_A) && (player->transformation == PLAYER_FORM_FIERCE_DEITY) && + (player->heldItemAction != PLAYER_IA_SWORD_TWO_HANDED)) + ? EQUIP_SLOT_B + : i; + + item = Player_GetItemOnButton(gPlayState, player, i); + if (item == ITEM_F0) { + actor->shape.rot.x = BOMB_EXPLOSIVE_TYPE_POWDER_KEG; + } + } + }); +} diff --git a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h new file mode 100644 index 000000000..a32a4726b --- /dev/null +++ b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h @@ -0,0 +1,6 @@ +#ifndef EQUIPMENT_BLAST_MASK_KEG_H +#define EQUIPMENT_BLAST_MASK_KEG_H + +void RegisterBlastMaskKeg(); + +#endif // EQUIPMENT_BLAST_MASK_KEG_H From f8f00e6d9baf08dda5ac2e0ab5ae8ff33fc3e97f Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 2 Jun 2024 23:15:33 -0500 Subject: [PATCH 10/82] Add draw distance enhancements for actors and scene geometry (#539) --- mm/2s2h/BenGui/BenMenuBar.cpp | 31 +++++++++++++++++ mm/include/PR/gbi.h | 1 + mm/src/code/z_actor.c | 63 ++++++++++++++++++++++++++++++++--- mm/src/code/z_play.c | 10 ++++++ 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 35d3f5778..264f04744 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -532,6 +532,37 @@ void DrawEnhancementsMenu() { "minor visual glitches that were covered up by the black bars\nPlease disable this " "setting before reporting a bug" }); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 0, 255)); + ImGui::SeparatorText("Unstable"); + ImGui::PopStyleColor(); + UIWidgets::CVarCheckbox( + "Disable Scene Geometry Distance Check", "gEnhancements.Graphics.DisableSceneGeometryDistanceCheck", + { .tooltip = + "Disables the distance check for scene geometry, allowing it to be drawn no matter how far " + "away it is from the player. This may have unintended side effects." }); + // BENTODO: Not implemented yet + // UIWidgets::CVarCheckbox("Widescreen Actor Culling", + // "gEnhancements.Graphics.ActorCullingAccountsForWidescreen", + // { .tooltip = "Adjusts the culling planes to account for widescreen resolutions. " + // "This may have unintended side effects." }); + if (UIWidgets::CVarSliderInt( + "Increase Actor Draw Distance: %dx", "gEnhancements.Graphics.IncreaseActorDrawDistance", 1, 5, 1, + { .tooltip = + "Increase the range in which Actors are drawn. This may have unintended side effects." })) { + CVarSetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", + MIN(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1), + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1))); + } + if (UIWidgets::CVarSliderInt( + "Increase Actor Update Distance: %dx", "gEnhancements.Graphics.IncreaseActorUpdateDistance", 1, 5, + 1, + { .tooltip = + "Increase the range in which Actors are updated. This may have unintended side effects." })) { + CVarSetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", + MAX(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1), + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1))); + } + ImGui::EndMenu(); } diff --git a/mm/include/PR/gbi.h b/mm/include/PR/gbi.h index 262ac95e8..7820e6197 100644 --- a/mm/include/PR/gbi.h +++ b/mm/include/PR/gbi.h @@ -391,6 +391,7 @@ * G_EXTRAGEOMETRY flags: set extra custom geometry modes */ #define G_EX_INVERT_CULLING 0x00000001 +#define G_EX_ALWAYS_EXECUTE_BRANCH 0x00000002 /* Need these defined for Sprite Microcode */ #ifdef _LANGUAGE_ASSEMBLY diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 532bb599f..2a967694b 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -3070,6 +3070,45 @@ s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projec return false; } +// #region 2S2H [Enhancements] Allows us to increase the draw and update distance independently, mostly a modified +// version of the function above +void Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw, + bool* shouldUpdate) { + s32 updateMulti = CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1); + s32 drawMulti = CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1); + bool updateCheck = + (-(actor->uncullZoneScale * updateMulti) < projectedPos->z) && + (projectedPos->z < ((actor->uncullZoneForward * updateMulti) + (actor->uncullZoneScale * updateMulti))); + bool drawCheck = + (-(actor->uncullZoneScale * drawMulti) < projectedPos->z) && + (projectedPos->z < ((actor->uncullZoneForward * drawMulti) + (actor->uncullZoneScale * drawMulti))); + + if (updateCheck || drawCheck) { + f32 phi_f12; + f32 phi_f2 = CLAMP_MIN(projectedW, 1.0f); + f32 phi_f14; + f32 phi_f16; + + if (play->view.fovy != 60.0f) { + phi_f12 = actor->uncullZoneScale * play->projectionMtxFDiagonal.x * 0.76980036f; // sqrt(16/27) + + phi_f14 = play->projectionMtxFDiagonal.y * 0.57735026f; // 1 / sqrt(3) + phi_f16 = actor->uncullZoneScale * phi_f14; + phi_f14 *= actor->uncullZoneDownward; + } else { + phi_f16 = phi_f12 = actor->uncullZoneScale; + phi_f14 = actor->uncullZoneDownward; + } + + if (((fabsf(projectedPos->x) - phi_f12) < phi_f2) && ((-phi_f2 < (projectedPos->y + phi_f14))) && + ((projectedPos->y - phi_f16) < phi_f2)) { + *shouldDraw = drawCheck; + *shouldUpdate = updateCheck; + } + } +} +// #endregion + void Actor_DrawAll(PlayState* play, ActorContext* actorCtx) { s32 pad[2]; Gfx* ref2; @@ -3105,14 +3144,30 @@ void Actor_DrawAll(PlayState* play, ActorContext* actorCtx) { Actor_UpdateFlaggedAudio(actor); } - if (func_800BA2D8(play, actor)) { - actor->flags |= ACTOR_FLAG_40; + // #region 2S2H + bool shipShouldDraw = false; + bool shipShouldUpdate = false; + if (CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1) > 1 || + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1) > 1) { + Ship_CalcShouldDrawAndUpdate(play, actor, &actor->projectedPos, actor->projectedW, &shipShouldDraw, + &shipShouldUpdate); + + if (shipShouldUpdate) { + actor->flags |= ACTOR_FLAG_40; + } else { + actor->flags &= ~ACTOR_FLAG_40; + } } else { - actor->flags &= ~ACTOR_FLAG_40; + if (func_800BA2D8(play, actor)) { + actor->flags |= ACTOR_FLAG_40; + } else { + actor->flags &= ~ACTOR_FLAG_40; + } } actor->isDrawn = false; - if ((actor->init == NULL) && (actor->draw != NULL) && (actor->flags & actorFlags)) { + if ((actor->init == NULL) && (actor->draw != NULL) && ((actor->flags & actorFlags) || shipShouldDraw)) { + // #endregion if ((actor->flags & ACTOR_FLAG_REACT_TO_LENS) && ((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) || (play->actorCtx.lensMaskSize == LENS_MASK_ACTIVE_SIZE) || diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index a939ed217..a4fd7e5b5 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -1373,11 +1373,21 @@ void Play_DrawMain(PlayState* this) { if (1) { u32 roomDrawFlags = ((1) ? 1 : 0) | (((void)0, 1) ? 2 : 0); // FAKE: + if (CVarGetInteger("gEnhancements.Graphics.DisableSceneGeometryDistanceCheck", 0)) { + gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_ALWAYS_EXECUTE_BRANCH); + gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_ALWAYS_EXECUTE_BRANCH); + } + Scene_Draw(this); if (this->roomCtx.unk78) { Room_Draw(this, &this->roomCtx.curRoom, roomDrawFlags & 3); Room_Draw(this, &this->roomCtx.prevRoom, roomDrawFlags & 3); } + + if (CVarGetInteger("gEnhancements.Graphics.DisableSceneGeometryDistanceCheck", 0)) { + gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_ALWAYS_EXECUTE_BRANCH); + gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_ALWAYS_EXECUTE_BRANCH); + } } if (this->skyboxCtx.skyboxShouldDraw) { From d2a11f147681ad7ceba8553cf59963ba65f9cd24 Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:38:29 -0400 Subject: [PATCH 11/82] [Enhancement] Instant Putaway (#547) * Instant Putaway Enhancement Co-authored-by: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> * Tweak some things and merge with Player Movement --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 7 ++++--- mm/2s2h/Enhancements/Enhancements.cpp | 7 ++++--- mm/2s2h/Enhancements/Enhancements.h | 2 +- mm/2s2h/Enhancements/GameInteractor/GameInteractor.h | 1 + .../{PlayerMovement => Player}/ClimbSpeed.cpp | 4 ++-- mm/2s2h/Enhancements/Player/InstantPutaway.cpp | 10 ++++++++++ mm/2s2h/Enhancements/Player/Player.h | 7 +++++++ mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.h | 6 ------ mm/src/overlays/actors/ovl_player_actor/z_player.c | 4 +++- 9 files changed, 32 insertions(+), 16 deletions(-) rename mm/2s2h/Enhancements/{PlayerMovement => Player}/ClimbSpeed.cpp (58%) create mode 100644 mm/2s2h/Enhancements/Player/InstantPutaway.cpp create mode 100644 mm/2s2h/Enhancements/Player/Player.h delete mode 100644 mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 264f04744..849364462 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -591,10 +591,11 @@ void DrawEnhancementsMenu() { } ImGui::EndMenu(); } - if (UIWidgets::BeginMenu("Player Movement")) { - UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.PlayerMovement.ClimbSpeed", 1, 5, 1, + if (UIWidgets::BeginMenu("Player")) { + UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.Player.ClimbSpeed", 1, 5, 1, { .tooltip = "Increases the speed at which Link climbs vines and ladders." }); - + UIWidgets::CVarCheckbox("Instant Putaway", "gEnhancements.Player.InstantPutaway", + { .tooltip = "Allows Link to instantly puts away held item without waiting." }); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 0b2d2f794..c15ba3a85 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -38,6 +38,10 @@ void InitEnhancements() { // Minigames RegisterAlwaysWinDoggyRace(); + // Player + RegisterClimbSpeed(); + RegisterInstantPutaway(); + // Songs RegisterEnableSunsSong(); @@ -53,7 +57,4 @@ void InitEnhancements() { // Modes RegisterPlayAsKafei(); RegisterTimeMovesWhenYouMove(); - - // Player Movement - RegisterClimbSpeed(); } diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 5ad8cfb4a..f3d7c5d8d 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -23,7 +23,7 @@ #include "Restorations/SideRoll.h" #include "Restorations/TatlISG.h" #include "Graphics/PlayAsKafei.h" -#include "PlayerMovement/ClimbSpeed.h" +#include "Player/Player.h" #include "Songs/EnableSunsSong.h" #include "Saving/SavingEnhancements.h" #include "Graphics/DisableBlackBars.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index fe10c1f29..8da2e5ea6 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -42,6 +42,7 @@ typedef enum { GI_VB_PATCH_SIDEROLL, GI_VB_TATL_CONVERSATION_AVAILABLE, GI_VB_PREVENT_MASK_TRANSFORMATION_CS, + GI_VB_RESET_PUTAWAY_TIMER, GI_VB_SET_CLIMB_SPEED, GI_VB_PREVENT_CLOCK_DISPLAY, GI_VB_SONG_AVAILABLE_TO_PLAY, diff --git a/mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.cpp b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp similarity index 58% rename from mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.cpp rename to mm/2s2h/Enhancements/Player/ClimbSpeed.cpp index 60296c423..1a6c624d1 100644 --- a/mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.cpp +++ b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp @@ -3,9 +3,9 @@ void RegisterClimbSpeed() { REGISTER_VB_SHOULD(GI_VB_SET_CLIMB_SPEED, { - if (CVarGetInteger("gEnhancements.PlayerMovement.ClimbSpeed", 1) > 1) { + if (CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1) > 1) { f32* speed = static_cast(opt); - *speed *= CVarGetInteger("gEnhancements.PlayerMovement.ClimbSpeed", 1); + *speed *= CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1); } }); } diff --git a/mm/2s2h/Enhancements/Player/InstantPutaway.cpp b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp new file mode 100644 index 000000000..24530aca7 --- /dev/null +++ b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp @@ -0,0 +1,10 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +void RegisterInstantPutaway() { + REGISTER_VB_SHOULD(GI_VB_RESET_PUTAWAY_TIMER, { + if (CVarGetInteger("gEnhancements.Player.InstantPutaway", 0)) { + *should = false; + } + }); +} diff --git a/mm/2s2h/Enhancements/Player/Player.h b/mm/2s2h/Enhancements/Player/Player.h new file mode 100644 index 000000000..c2a23827f --- /dev/null +++ b/mm/2s2h/Enhancements/Player/Player.h @@ -0,0 +1,7 @@ +#ifndef PLAYER_H +#define PLAYER_H + +void RegisterClimbSpeed(); +void RegisterInstantPutaway(); + +#endif // PLAYER_H diff --git a/mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.h b/mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.h deleted file mode 100644 index b0596a4f9..000000000 --- a/mm/2s2h/Enhancements/PlayerMovement/ClimbSpeed.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PLAYER_MOVEMENT_CLIMB_SPEED_H -#define PLAYER_MOVEMENT_CLIMB_SPEED_H - -void RegisterClimbSpeed(); - -#endif // PLAYER_MOVEMENT_CLIMB_SPEED_H diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 7dfdc0419..f3a173303 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -11247,7 +11247,9 @@ void Player_SetDoAction(PlayState* play, Player* this) { } if (doActionA != DO_ACTION_PUTAWAY) { - this->putAwayCountdown = 20; + if (GameInteractor_Should(GI_VB_RESET_PUTAWAY_TIMER, true, NULL)) { + this->putAwayCountdown = 20; + } } else if (this->putAwayCountdown != 0) { doActionA = DO_ACTION_NONE; this->putAwayCountdown--; From 5e17828cc47aed2488257d00696beea99ed511aa Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Tue, 4 Jun 2024 01:02:48 -0400 Subject: [PATCH 12/82] [Cheat] Longer Deku Flower Gliding (#548) * Add Longer Flower Glide enhancement Co-authored-by: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> * Tweak to just modify an array * Update mm/2s2h/Enhancements/Cheats/LongerFlowerGlide.cpp --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 8 +++++++- mm/2s2h/Enhancements/Cheats/Cheats.h | 6 ++++++ .../Enhancements/Cheats/LongerFlowerGlide.cpp | 16 ++++++++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/Cheats/Cheats.h create mode 100644 mm/2s2h/Enhancements/Cheats/LongerFlowerGlide.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 849364462..f2f460a6e 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -13,6 +13,7 @@ #include "2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h" #include "2s2h/DeveloperTools/DeveloperTools.h" #include "2s2h/DeveloperTools/WarpPoint.h" +#include "2s2h/Enhancements/Cheats/Cheats.h" #include "HudEditor.h" extern "C" { @@ -644,13 +645,18 @@ void DrawCheatsMenu() { UIWidgets::CVarCheckbox("Infinite Magic", "gCheats.InfiniteMagic"); UIWidgets::CVarCheckbox("Infinite Rupees", "gCheats.InfiniteRupees"); UIWidgets::CVarCheckbox("Infinite Consumables", "gCheats.InfiniteConsumables"); + if (UIWidgets::CVarCheckbox( + "Longer Deku Flower Glide", "gCheats.LongerFlowerGlide", + { .tooltip = "Allows Deku Link to glide longer, no longer dropping after a certain distance" })) { + RegisterLongerFlowerGlide(); + } + UIWidgets::CVarCheckbox("No Clip", "gCheats.NoClip"); UIWidgets::CVarCheckbox("Unbreakable Razor Sword", "gCheats.UnbreakableRazorSword"); UIWidgets::CVarCheckbox("Unrestricted Items", "gCheats.UnrestrictedItems"); if (UIWidgets::CVarCheckbox("Moon Jump on L", "gCheats.MoonJumpOnL", { .tooltip = "Holding L makes you float into the air" })) { RegisterMoonJumpOnL(); } - UIWidgets::CVarCheckbox("No Clip", "gCheats.NoClip"); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Cheats/Cheats.h b/mm/2s2h/Enhancements/Cheats/Cheats.h new file mode 100644 index 000000000..497f5e2c5 --- /dev/null +++ b/mm/2s2h/Enhancements/Cheats/Cheats.h @@ -0,0 +1,6 @@ +#ifndef CHEATS_H +#define CHEATS_H + +void RegisterLongerFlowerGlide(); + +#endif // CHEATS_H diff --git a/mm/2s2h/Enhancements/Cheats/LongerFlowerGlide.cpp b/mm/2s2h/Enhancements/Cheats/LongerFlowerGlide.cpp new file mode 100644 index 000000000..4012e9a5a --- /dev/null +++ b/mm/2s2h/Enhancements/Cheats/LongerFlowerGlide.cpp @@ -0,0 +1,16 @@ +#include + +extern "C" { +#include "z64.h"; +extern f32 D_8085D958[2]; +} + +void RegisterLongerFlowerGlide() { + if (CVarGetInteger("gCheats.LongerFlowerGlide", 0)) { + D_8085D958[0] = 99999.9f; + D_8085D958[1] = 99999.9f; + } else { + D_8085D958[0] = 600.0f; + D_8085D958[1] = 960.0f; + } +} diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index c15ba3a85..6f2f1627e 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -8,6 +8,7 @@ void InitEnhancements() { // Cheats RegisterInfiniteCheats(); + RegisterLongerFlowerGlide(); RegisterMoonJumpOnL(); RegisterUnbreakableRazorSword(); RegisterUnrestrictedItems(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index f3d7c5d8d..57c54f414 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -8,6 +8,7 @@ #include "Cheats/Infinite.h" #include "Dialogue/Dialogue.h" #include "Graphics/TextBasedClock.h" +#include "Cheats/Cheats.h" #include "Cheats/UnbreakableRazorSword.h" #include "Cheats/UnrestrictedItems.h" #include "Cycle/EndOfCycle.h" From 51a6d9d92673f2ce2197550e8991c4d83210ac9a Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Tue, 4 Jun 2024 02:58:32 -0400 Subject: [PATCH 13/82] [Enhancement] Fast Deku Flower Launch (#549) * Add fast deku flower launch enhancement Co-authored-by: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> * Migrate to a hook --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 7 +++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + .../Enhancements/Player/FastFlowerLaunch.cpp | 47 +++++++++++++++++++ mm/2s2h/Enhancements/Player/Player.h | 1 + 4 files changed, 56 insertions(+) create mode 100644 mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index f2f460a6e..5e3ace0ce 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -14,6 +14,7 @@ #include "2s2h/DeveloperTools/DeveloperTools.h" #include "2s2h/DeveloperTools/WarpPoint.h" #include "2s2h/Enhancements/Cheats/Cheats.h" +#include "2s2h/Enhancements/Player/Player.h" #include "HudEditor.h" extern "C" { @@ -595,6 +596,12 @@ void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Player")) { UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.Player.ClimbSpeed", 1, 5, 1, { .tooltip = "Increases the speed at which Link climbs vines and ladders." }); + if (UIWidgets::CVarCheckbox("Fast Deku Flower Launch", "gEnhancements.Player.FastFlowerLaunch", + { .tooltip = + "Speeds up the time it takes to be able to get maximum height from " + "launching out of a deku flower" })) { + RegisterFastFlowerLaunch(); + } UIWidgets::CVarCheckbox("Instant Putaway", "gEnhancements.Player.InstantPutaway", { .tooltip = "Allows Link to instantly puts away held item without waiting." }); ImGui::EndMenu(); diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 6f2f1627e..663f257c4 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -41,6 +41,7 @@ void InitEnhancements() { // Player RegisterClimbSpeed(); + RegisterFastFlowerLaunch(); RegisterInstantPutaway(); // Songs diff --git a/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp new file mode 100644 index 000000000..50c2fe185 --- /dev/null +++ b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp @@ -0,0 +1,47 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "spdlog/spdlog.h" + +extern "C" { +#include "macros.h" +#include "z64.h" +extern PlayState* gPlayState; +extern Input* sPlayerControlInput; +void Player_Action_93(Player* player, PlayState* play); +} + +void RegisterFastFlowerLaunch() { + static HOOK_ID playerUpdateHook = 0; + GameInteractor::Instance->UnregisterGameHookForID(playerUpdateHook); + playerUpdateHook = 0; + + if (!CVarGetInteger("gEnhancements.Player.FastFlowerLaunch", 0)) { + return; + } + + playerUpdateHook = + GameInteractor::Instance->RegisterGameHookForID(ACTOR_PLAYER, [](Actor* actor) { + Player* player = GET_PLAYER(gPlayState); + if (player->actionFunc != Player_Action_93) { + return; + } + + DynaPolyActor* dyna; + Input* input = &gPlayState->state.input[0]; + + if (player->av1.actionVar1 != 0 && !(player->av1.actionVar1 == 1 && player->unk_B48 > -170.0f) && + player->av2.actionVar2 != 10 && !CHECK_BTN_ALL(input->cur.button, BTN_A)) { + player->unk_ABC = -3900.0f; + player->unk_B48 = -170.0f; + player->av1.actionVar1 = 2; + player->av2.actionVar2 = 10; + player->actor.scale.y = 0.01f; + dyna = DynaPoly_GetActor(&gPlayState->colCtx, player->actor.floorBgId); + + if (dyna != NULL) { + player->actor.world.pos.x = dyna->actor.world.pos.x; + player->actor.world.pos.z = dyna->actor.world.pos.z; + } + } + }); +} diff --git a/mm/2s2h/Enhancements/Player/Player.h b/mm/2s2h/Enhancements/Player/Player.h index c2a23827f..0bcc94156 100644 --- a/mm/2s2h/Enhancements/Player/Player.h +++ b/mm/2s2h/Enhancements/Player/Player.h @@ -2,6 +2,7 @@ #define PLAYER_H void RegisterClimbSpeed(); +void RegisterFastFlowerLaunch(); void RegisterInstantPutaway(); #endif // PLAYER_H From 8b2b12dbe8a308550cde067b4821025ff4128767 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 18 Jun 2024 20:00:16 -0400 Subject: [PATCH 14/82] Bump latest lus and bring over Array resource (#689) * bump latest lus and bring over array resource * use upstream otrexporter --- OTRExporter | 2 +- libultraship | 2 +- mm/2s2h/BenGui/BenMenuBar.cpp | 28 +++---- mm/2s2h/BenPort.cpp | 29 +++----- mm/2s2h/resource/importer/ArrayFactory.cpp | 64 ++++++++++++++++ mm/2s2h/resource/importer/ArrayFactory.h | 11 +++ mm/2s2h/resource/type/2shResourceType.h | 1 + mm/2s2h/resource/type/Array.cpp | 46 ++++++++++++ mm/2s2h/resource/type/Array.h | 85 ++++++++++++++++++++++ mm/src/code/stubs.c | 2 - 10 files changed, 236 insertions(+), 34 deletions(-) create mode 100644 mm/2s2h/resource/importer/ArrayFactory.cpp create mode 100644 mm/2s2h/resource/importer/ArrayFactory.h create mode 100644 mm/2s2h/resource/type/Array.cpp create mode 100644 mm/2s2h/resource/type/Array.h diff --git a/OTRExporter b/OTRExporter index 287c79891..375489d5f 160000 --- a/OTRExporter +++ b/OTRExporter @@ -1 +1 @@ -Subproject commit 287c79891882df5a0797cd9d39c0dcb97af9f007 +Subproject commit 375489d5f1f5fa4b9144ac9669c411e3b149f32a diff --git a/libultraship b/libultraship index 070eb35dd..fccf181b4 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 070eb35dde54f8dcbffad8fb3d97367bb792b6b1 +Subproject commit fccf181b449f82f3e6ae5cdc666319847f78e0a1 diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 89bb3e009..764d2ea65 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -41,10 +41,9 @@ static const std::unordered_map audioBackendsMa }; static std::unordered_map windowBackendsMap = { - { Ship::WindowBackend::DX11, "DirectX" }, - { Ship::WindowBackend::SDL_OPENGL, "OpenGL" }, - { Ship::WindowBackend::SDL_METAL, "Metal" }, - { Ship::WindowBackend::GX2, "GX2" } + { Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" }, + { Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL" }, + { Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" }, }; static const std::unordered_map clockTypeOptions = { @@ -196,19 +195,21 @@ void DrawSettingsMenu() { { // FPS Slider constexpr unsigned int minFps = 20; static unsigned int maxFps; - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) { + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == + Ship::WindowBackend::FAST3D_DXGI_DX11) { maxFps = 360; } else { maxFps = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); } unsigned int currentFps = std::max(std::min(OTRGlobals::Instance->GetInterpolationFPS(), maxFps), minFps); - bool matchingRefreshRate = - CVarGetInteger("gMatchRefreshRate", 0) && - Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() != Ship::WindowBackend::DX11; + bool matchingRefreshRate = CVarGetInteger("gMatchRefreshRate", 0) && + Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() != + Ship::WindowBackend::FAST3D_DXGI_DX11; UIWidgets::CVarSliderInt((currentFps == 20) ? "FPS: Original (20)" : "FPS: %d", "gInterpolationFPS", minFps, maxFps, 20, { .disabled = matchingRefreshRate }); - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) { + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == + Ship::WindowBackend::FAST3D_DXGI_DX11) { UIWidgets::Tooltip( "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " "purely visual and does not impact game logic, execution of glitches etc.\n\n A higher target " @@ -220,7 +221,8 @@ void DrawSettingsMenu() { } } // END FPS Slider - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) { + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == + Ship::WindowBackend::FAST3D_DXGI_DX11) { // UIWidgets::Spacer(0); if (ImGui::Button("Match Refresh Rate")) { int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); @@ -234,7 +236,8 @@ void DrawSettingsMenu() { } UIWidgets::Tooltip("Matches interpolation value to the current game's window refresh rate"); - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) { + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == + Ship::WindowBackend::FAST3D_DXGI_DX11) { UIWidgets::CVarSliderInt(CVarGetInteger("gExtraLatencyThreshold", 80) == 0 ? "Jitter fix: Off" : "Jitter fix: >= %d FPS", "gExtraLatencyThreshold", 0, 360, 80); @@ -250,8 +253,7 @@ void DrawSettingsMenu() { Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend(); Ship::WindowBackend configWindowBackend; int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); - if (configWindowBackendId != -1 && - configWindowBackendId < static_cast(Ship::WindowBackend::BACKEND_COUNT)) { + if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) { configWindowBackend = static_cast(configWindowBackendId); } else { configWindowBackend = runningWindowBackend; diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 15dc9ef65..5009eb2ce 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -20,7 +20,6 @@ #else #include #endif -#include #include #include "variables.h" #include "z64.h" @@ -57,7 +56,6 @@ CrowdControl* CrowdControl::Instance; #include "2s2h/SaveManager/SaveManager.h" // Resource Types/Factories -#include "resource/type/Array.h" #include "resource/type/Blob.h" #include "resource/type/DisplayList.h" #include "resource/type/Matrix.h" @@ -65,6 +63,7 @@ CrowdControl* CrowdControl::Instance; #include "resource/type/Vertex.h" #include "2s2h/resource/type/2shResourceType.h" #include "2s2h/resource/type/Animation.h" +#include "2s2h/resource/type/Array.h" #include "2s2h/resource/type/AudioSample.h" #include "2s2h/resource/type/AudioSequence.h" #include "2s2h/resource/type/AudioSoundFont.h" @@ -75,13 +74,13 @@ CrowdControl* CrowdControl::Instance; #include "2s2h/resource/type/Scene.h" #include "2s2h/resource/type/Skeleton.h" #include "2s2h/resource/type/SkeletonLimb.h" -#include "resource/factory/ArrayFactory.h" #include "resource/factory/BlobFactory.h" #include "resource/factory/DisplayListFactory.h" #include "resource/factory/MatrixFactory.h" #include "resource/factory/TextureFactory.h" #include "resource/factory/VertexFactory.h" #include "2s2h/resource/importer/AnimationFactory.h" +#include "2s2h/resource/importer/ArrayFactory.h" #include "2s2h/resource/importer/AudioSampleFactory.h" #include "2s2h/resource/importer/AudioSequenceFactory.h" #include "2s2h/resource/importer/AudioSoundFontFactory.h" @@ -179,10 +178,10 @@ OTRGlobals::OTRGlobals() { "DisplayList", static_cast(LUS::ResourceType::DisplayList), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Matrix", static_cast(LUS::ResourceType::Matrix), 0); - loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, - "Array", static_cast(LUS::ResourceType::Array), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Blob", static_cast(LUS::ResourceType::Blob), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "Array", static_cast(SOH::ResourceType::SOH_Array), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Animation", static_cast(SOH::ResourceType::SOH_Animation), 0); loader->RegisterResourceFactory(std::make_shared(), @@ -292,7 +291,7 @@ bool OTRGlobals::HasOriginal() { } uint32_t OTRGlobals::GetInterpolationFPS() { - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) { + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { return CVarGetInteger("gInterpolationFPS", 20); } @@ -309,9 +308,6 @@ struct ExtensionEntry { std::string ext; }; -extern uintptr_t clearMtx; -extern "C" Mtx gMtxClear; -extern "C" MtxF gMtxFClear; extern "C" void OTRMessage_Init(); extern "C" void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len); @@ -478,7 +474,6 @@ extern "C" void InitOTR() { GfxPatcher_ApplyNecessaryAuthenticPatches(); DebugConsole_Init(); - clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); OTRAudio_Init(); // OTRExtScanner(); @@ -949,8 +944,8 @@ extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) { if (res->GetInitData()->Type == static_cast(LUS::ResourceType::DisplayList)) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); - else if (res->GetInitData()->Type == static_cast(LUS::ResourceType::Array)) - return (char*)(std::static_pointer_cast(res))->Vertices.data(); + else if (res->GetInitData()->Type == static_cast(SOH::ResourceType::SOH_Array)) + return (char*)(std::static_pointer_cast(res))->Vertices.data(); else { return (char*)ResourceGetDataByName(filePath); } @@ -1063,30 +1058,30 @@ extern "C" void ResourceMgr_UnpatchGfxByName(const char* path, const char* patch } extern "C" char* ResourceMgr_LoadVtxArrayByName(const char* path) { - auto res = std::static_pointer_cast(GetResourceByName(path)); + auto res = std::static_pointer_cast(GetResourceByName(path)); return (char*)res->Vertices.data(); } extern "C" size_t ResourceMgr_GetVtxArraySizeByName(const char* path) { - auto res = std::static_pointer_cast(GetResourceByName(path)); + auto res = std::static_pointer_cast(GetResourceByName(path)); return res->Vertices.size(); } extern "C" char* ResourceMgr_LoadArrayByName(const char* path) { - auto res = std::static_pointer_cast(GetResourceByName(path)); + auto res = std::static_pointer_cast(GetResourceByName(path)); return (char*)res->Scalars.data(); } extern "C" size_t ResourceMgr_GetArraySizeByName(const char* path) { - auto res = std::static_pointer_cast(GetResourceByName(path)); + auto res = std::static_pointer_cast(GetResourceByName(path)); return res->Scalars.size(); } extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) { - auto res = std::static_pointer_cast(GetResourceByName(path)); + auto res = std::static_pointer_cast(GetResourceByName(path)); // if (res->CachedGameAsset != nullptr) // return (char*)res->CachedGameAsset; diff --git a/mm/2s2h/resource/importer/ArrayFactory.cpp b/mm/2s2h/resource/importer/ArrayFactory.cpp new file mode 100644 index 000000000..9772da149 --- /dev/null +++ b/mm/2s2h/resource/importer/ArrayFactory.cpp @@ -0,0 +1,64 @@ +#include "2s2h/resource/importer/ArrayFactory.h" +#include "2s2h/resource/type/Array.h" +#include "spdlog/spdlog.h" +#include "graphic/Fast3D/lus_gbi.h" + +namespace SOH { +std::shared_ptr ResourceFactoryBinaryArrayV0::ReadResource(std::shared_ptr file) { + if (!FileHasValidFormatAndReader(file)) { + return nullptr; + } + + auto array = std::make_shared(file->InitData); + auto reader = std::get>(file->Reader); + + array->ArrayType = (ArrayResourceType)reader->ReadUInt32(); + array->ArrayCount = reader->ReadUInt32(); + + for (uint32_t i = 0; i < array->ArrayCount; i++) { + if (array->ArrayType == ArrayResourceType::Vertex) { + // OTRTODO: Implement Vertex arrays as just a vertex resource. + F3DVtx data; + data.v.ob[0] = reader->ReadInt16(); + data.v.ob[1] = reader->ReadInt16(); + data.v.ob[2] = reader->ReadInt16(); + data.v.flag = reader->ReadUInt16(); + data.v.tc[0] = reader->ReadInt16(); + data.v.tc[1] = reader->ReadInt16(); + data.v.cn[0] = reader->ReadUByte(); + data.v.cn[1] = reader->ReadUByte(); + data.v.cn[2] = reader->ReadUByte(); + data.v.cn[3] = reader->ReadUByte(); + array->Vertices.push_back(data); + } else { + array->ArrayScalarType = (ScalarType)reader->ReadUInt32(); + + int iter = 1; + + if (array->ArrayType == ArrayResourceType::Vector) { + iter = reader->ReadUInt32(); + } + + for (int k = 0; k < iter; k++) { + ScalarData data; + + switch (array->ArrayScalarType) { + case ScalarType::ZSCALAR_S16: + data.s16 = reader->ReadInt16(); + break; + case ScalarType::ZSCALAR_U16: + data.u16 = reader->ReadUInt16(); + break; + default: + // OTRTODO: IMPLEMENT OTHER TYPES! + break; + } + + array->Scalars.push_back(data); + } + } + } + + return array; +} +} // namespace SOH \ No newline at end of file diff --git a/mm/2s2h/resource/importer/ArrayFactory.h b/mm/2s2h/resource/importer/ArrayFactory.h new file mode 100644 index 000000000..fcd307a4e --- /dev/null +++ b/mm/2s2h/resource/importer/ArrayFactory.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactoryBinary.h" + +namespace SOH { +class ResourceFactoryBinaryArrayV0 : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file) override; +}; +} // namespace SOH \ No newline at end of file diff --git a/mm/2s2h/resource/type/2shResourceType.h b/mm/2s2h/resource/type/2shResourceType.h index 4524ba88c..418e9b82f 100644 --- a/mm/2s2h/resource/type/2shResourceType.h +++ b/mm/2s2h/resource/type/2shResourceType.h @@ -2,6 +2,7 @@ namespace SOH { enum class ResourceType { + SOH_Array = 0x4F415252, // OARR SOH_Animation = 0x4F414E4D, // OANM SOH_PlayerAnimation = 0x4F50414D, // OPAM SOH_Room = 0x4F524F4D, // OROM diff --git a/mm/2s2h/resource/type/Array.cpp b/mm/2s2h/resource/type/Array.cpp new file mode 100644 index 000000000..7a9e40dc1 --- /dev/null +++ b/mm/2s2h/resource/type/Array.cpp @@ -0,0 +1,46 @@ +#include "Array.h" +#include "graphic/Fast3D/lus_gbi.h" + +namespace SOH { +Array::Array() : Resource(std::shared_ptr()) { +} + +void* Array::GetPointer() { + void* dataPointer = nullptr; + switch (ArrayType) { + case ArrayResourceType::Vertex: + dataPointer = Vertices.data(); + break; + case ArrayResourceType::Scalar: + default: + dataPointer = Scalars.data(); + break; + } + + return dataPointer; +} + +size_t Array::GetPointerSize() { + size_t typeSize = 0; + switch (ArrayType) { + case ArrayResourceType::Vertex: + typeSize = sizeof(F3DVtx); + break; + case ArrayResourceType::Scalar: + default: + switch (ArrayScalarType) { + case ScalarType::ZSCALAR_S16: + typeSize = sizeof(int16_t); + break; + case ScalarType::ZSCALAR_U16: + typeSize = sizeof(uint16_t); + break; + default: + // OTRTODO: IMPLEMENT OTHER TYPES! + break; + } + break; + } + return ArrayCount * typeSize; +} +} // namespace SOH \ No newline at end of file diff --git a/mm/2s2h/resource/type/Array.h b/mm/2s2h/resource/type/Array.h new file mode 100644 index 000000000..656b11194 --- /dev/null +++ b/mm/2s2h/resource/type/Array.h @@ -0,0 +1,85 @@ +#pragma once + +#include "Resource.h" + +union F3DVtx; +namespace SOH { +typedef union ScalarData { + uint8_t u8; + int8_t s8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + float f32; + double f64; +} ScalarData; + +enum class ScalarType { + ZSCALAR_NONE, + ZSCALAR_S8, + ZSCALAR_U8, + ZSCALAR_X8, + ZSCALAR_S16, + ZSCALAR_U16, + ZSCALAR_X16, + ZSCALAR_S32, + ZSCALAR_U32, + ZSCALAR_X32, + ZSCALAR_S64, + ZSCALAR_U64, + ZSCALAR_X64, + ZSCALAR_F32, + ZSCALAR_F64 +}; + +// OTRTODO: Replace this with something that can be shared between the exporter and importer... +enum class ArrayResourceType { + Error, + Animation, + Array, + AltHeader, + Background, + Blob, + CollisionHeader, + Cutscene, + DisplayList, + Limb, + LimbTable, + Mtx, + Path, + PlayerAnimationData, + Room, + RoomCommand, + Scalar, + Scene, + Skeleton, + String, + Symbol, + Texture, + TextureAnimation, + TextureAnimationParams, + Vector, + Vertex, + Audio +}; + +class Array : public Ship::Resource { + public: + using Resource::Resource; + + Array(); + + void* GetPointer() override; + size_t GetPointerSize() override; + + ArrayResourceType ArrayType; + ScalarType ArrayScalarType; + size_t ArrayCount; + // OTRTODO: Should be a vector of resource pointers... + std::vector Scalars; + std::vector Vertices; +}; +} // namespace SOH \ No newline at end of file diff --git a/mm/src/code/stubs.c b/mm/src/code/stubs.c index 35de8a506..dea4cedb9 100644 --- a/mm/src/code/stubs.c +++ b/mm/src/code/stubs.c @@ -92,8 +92,6 @@ u64 rspbootTextEnd[1]; u64 njpgdspMainTextStart[1]; u64 njpgdspMainDataStart[1]; -Mtx gMtxClear; - u8 gPictoPhotoI8[PICTO_PHOTO_SIZE]; u8 D_80784600[0x56200]; From e87d7c6954f2e14f9ab48d4d398ad5317c34d130 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Wed, 19 Jun 2024 01:01:17 +0100 Subject: [PATCH 15/82] Delete z_message_tables.inc (#685) --- mm/src/code/z_message_tables.inc | 1561 ------------------------------ 1 file changed, 1561 deletions(-) delete mode 100644 mm/src/code/z_message_tables.inc diff --git a/mm/src/code/z_message_tables.inc b/mm/src/code/z_message_tables.inc deleted file mode 100644 index a7b41c8a9..000000000 --- a/mm/src/code/z_message_tables.inc +++ /dev/null @@ -1,1561 +0,0 @@ -#include "include/message_data_static.h" -#include "PR/mbi.h" - -MessageTableEntry D_801C6B98[4590] = { - { 0, 0, (void*)0x08000000 }, { 2, 0, (void*)0x0800000C }, { 4, 0, (void*)0x08000064 }, - { 5, 0, (void*)0x080000B8 }, { 6, 0, (void*)0x08000110 }, { 7, 0, (void*)0x08000168 }, - { 8, 0, (void*)0x080001C4 }, { 9, 0, (void*)0x08000248 }, { 0xA, 0, (void*)0x080002A8 }, - { 0xB, 0, (void*)0x08000310 }, { 0xC, 0, (void*)0x0800031C }, { 0xD, 0, (void*)0x080003E8 }, - { 0xE, 0, (void*)0x08000474 }, { 0xF, 0, (void*)0x080004BC }, { 0x10, 0, (void*)0x08000504 }, - { 0x11, 0, (void*)0x08000510 }, { 0x12, 0, (void*)0x08000554 }, { 0x13, 0, (void*)0x08000560 }, - { 0x14, 0, (void*)0x0800056C }, { 0x15, 0, (void*)0x08000604 }, { 0x16, 0, (void*)0x080006A0 }, - { 0x17, 0, (void*)0x0800073C }, { 0x18, 0, (void*)0x080007D8 }, { 0x19, 0, (void*)0x08000874 }, - { 0x1A, 0, (void*)0x08000940 }, { 0x1B, 0, (void*)0x080009E8 }, { 0x1C, 0, (void*)0x08000A84 }, - { 0x1D, 0, (void*)0x08000AD4 }, { 0x1E, 0, (void*)0x08000B28 }, { 0x1F, 0, (void*)0x08000B58 }, - { 0x20, 0, (void*)0x08000B88 }, { 0x21, 0, (void*)0x08000BB8 }, { 0x22, 0, (void*)0x08000BE8 }, - { 0x23, 0, (void*)0x08000C78 }, { 0x24, 0, (void*)0x08000CD0 }, { 0x25, 0, (void*)0x08000D30 }, - { 0x26, 0, (void*)0x08000DA4 }, { 0x27, 0, (void*)0x08000E38 }, { 0x28, 0, (void*)0x08000EB4 }, - { 0x29, 0, (void*)0x08000F88 }, { 0x2A, 0, (void*)0x08001060 }, { 0x2B, 0, (void*)0x0800113C }, - { 0x2C, 0, (void*)0x08001148 }, { 0x2D, 0, (void*)0x08001154 }, { 0x2E, 0, (void*)0x08001160 }, - { 0x2F, 0, (void*)0x08001210 }, { 0x30, 0, (void*)0x0800121C }, { 0x31, 0, (void*)0x08001228 }, - { 0x32, 0, (void*)0x08001234 }, { 0x33, 0, (void*)0x080012D4 }, { 0x34, 0, (void*)0x0800139C }, - { 0x35, 0, (void*)0x08001428 }, { 0x36, 0, (void*)0x080014B0 }, { 0x37, 0, (void*)0x08001554 }, - { 0x38, 0, (void*)0x08001560 }, { 0x39, 0, (void*)0x08001624 }, { 0x3A, 0, (void*)0x080016B8 }, - { 0x3B, 0, (void*)0x08001768 }, { 0x3C, 0, (void*)0x08001814 }, { 0x3D, 0, (void*)0x08001884 }, - { 0x3E, 0, (void*)0x080018E0 }, { 0x3F, 0, (void*)0x080019DC }, { 0x40, 0, (void*)0x08001A48 }, - { 0x41, 0, (void*)0x08001A54 }, { 0x42, 0, (void*)0x08001B0C }, { 0x43, 0, (void*)0x08001BF4 }, - { 0x4C, 0, (void*)0x08001CBC }, { 0x4D, 0, (void*)0x08001DBC }, { 0x4E, 0, (void*)0x08001DC8 }, - { 0x50, 0, (void*)0x08001DD4 }, { 0x51, 0, (void*)0x08001EA4 }, { 0x52, 0, (void*)0x08001EB0 }, - { 0x53, 0, (void*)0x08001EFC }, { 0x54, 0, (void*)0x08001F08 }, { 0x55, 0, (void*)0x08001F14 }, - { 0x56, 0, (void*)0x08001FB8 }, { 0x57, 0, (void*)0x08002058 }, { 0x58, 0, (void*)0x080020F8 }, - { 0x59, 0, (void*)0x080021A0 }, { 0x5A, 0, (void*)0x08002290 }, { 0x5B, 0, (void*)0x080022E4 }, - { 0x5C, 0, (void*)0x08002388 }, { 0x5D, 0, (void*)0x08002434 }, { 0x5E, 0, (void*)0x080024E8 }, - { 0x5F, 0, (void*)0x08002590 }, { 0x60, 0, (void*)0x0800261C }, { 0x61, 0, (void*)0x080026F0 }, - { 0x62, 0, (void*)0x080026FC }, { 0x63, 0, (void*)0x08002760 }, { 0x64, 0, (void*)0x080027CC }, - { 0x65, 0, (void*)0x080027D8 }, { 0x66, 0, (void*)0x0800282C }, { 0x67, 0, (void*)0x08002884 }, - { 0x68, 0, (void*)0x080028EC }, { 0x69, 0, (void*)0x08002950 }, { 0x6A, 0, (void*)0x080029CC }, - { 0x6B, 0, (void*)0x08002A24 }, { 0x6E, 0, (void*)0x08002A7C }, { 0x6F, 0, (void*)0x08002A88 }, - { 0x70, 0, (void*)0x08002B54 }, { 0x71, 0, (void*)0x08002B60 }, { 0x72, 0, (void*)0x08002B6C }, - { 0x73, 0, (void*)0x08002B78 }, { 0x74, 0, (void*)0x08002B84 }, { 0x75, 0, (void*)0x08002B90 }, - { 0x76, 0, (void*)0x08002B9C }, { 0x77, 0, (void*)0x08002BA8 }, { 0x78, 0, (void*)0x08002BB4 }, - { 0x79, 0, (void*)0x08002C98 }, { 0x7A, 0, (void*)0x08002D54 }, { 0x7B, 0, (void*)0x08002E14 }, - { 0x7C, 0, (void*)0x08002E90 }, { 0x7D, 0, (void*)0x08002F20 }, { 0x7E, 0, (void*)0x08002F9C }, - { 0x7F, 0, (void*)0x0800302C }, { 0x80, 0, (void*)0x0800309C }, { 0x81, 0, (void*)0x08003144 }, - { 0x82, 0, (void*)0x080031B0 }, { 0x83, 0, (void*)0x08003224 }, { 0x84, 0, (void*)0x08003298 }, - { 0x85, 0, (void*)0x08003324 }, { 0x86, 0, (void*)0x08003370 }, { 0x87, 0, (void*)0x08003444 }, - { 0x88, 0, (void*)0x080034F8 }, { 0x89, 0, (void*)0x08003560 }, { 0x8A, 0, (void*)0x080035F4 }, - { 0x8B, 0, (void*)0x080036B8 }, { 0x8C, 0, (void*)0x08003710 }, { 0x8D, 0, (void*)0x080037A0 }, - { 0x8E, 0, (void*)0x08003828 }, { 0x8F, 0, (void*)0x080038E0 }, { 0x91, 0, (void*)0x0800396C }, - { 0x92, 0, (void*)0x08003A44 }, { 0x93, 0, (void*)0x08003B08 }, { 0x94, 0, (void*)0x08003B60 }, - { 0x95, 0, (void*)0x08003B6C }, { 0x96, 0, (void*)0x08003BC0 }, { 0x97, 0, (void*)0x08003C1C }, - { 0x98, 0, (void*)0x08003C60 }, { 0x99, 0, (void*)0x08003CA8 }, { 0x9A, 0, (void*)0x08003CF4 }, - { 0x9B, 0, (void*)0x08003D40 }, { 0x9C, 0, (void*)0x08003DE0 }, { 0x9D, 0, (void*)0x08003E78 }, - { 0x9E, 0, (void*)0x08003F10 }, { 0x9F, 0, (void*)0x08003FA8 }, { 0xA0, 0, (void*)0x08003FB4 }, - { 0xA1, 0, (void*)0x0800401C }, { 0xA2, 0, (void*)0x08004088 }, { 0xA3, 0, (void*)0x08004094 }, - { 0xA4, 0, (void*)0x080040A0 }, { 0xA9, 0, (void*)0x080040AC }, { 0xAA, 0, (void*)0x08004130 }, - { 0xAB, 0, (void*)0x08004198 }, { 0xAC, 0, (void*)0x08004240 }, { 0xAD, 0, (void*)0x0800424C }, - { 0xAE, 0, (void*)0x08004258 }, { 0xAF, 0, (void*)0x08004264 }, { 0xB0, 0, (void*)0x08004270 }, - { 0xB1, 0, (void*)0x0800427C }, { 0xB2, 0, (void*)0x08004288 }, { 0xB4, 0, (void*)0x08004294 }, - { 0xB5, 0, (void*)0x08004354 }, { 0xB6, 0, (void*)0x08004418 }, { 0xB7, 0, (void*)0x080044E0 }, - { 0xB8, 0, (void*)0x080045A8 }, { 0xB9, 0, (void*)0x08004670 }, { 0xBA, 0, (void*)0x08004738 }, - { 0xBB, 0, (void*)0x08004744 }, { 0xBC, 0, (void*)0x08004750 }, { 0xBD, 0, (void*)0x0800475C }, - { 0xBE, 0, (void*)0x08004768 }, { 0xBF, 0, (void*)0x08004774 }, { 0xC0, 0, (void*)0x08004780 }, - { 0xC4, 0, (void*)0x0800478C }, { 0xC5, 0, (void*)0x080047D0 }, { 0xC6, 0, (void*)0x08004850 }, - { 0xC7, 0, (void*)0x080048D0 }, { 0xC8, 0, (void*)0x08004954 }, { 0xC9, 0, (void*)0x08004A5C }, - { 0xCA, 0, (void*)0x08004AFC }, { 0xCB, 0, (void*)0x08004C14 }, { 0xCC, 0, (void*)0x08004C78 }, - { 0xCD, 0, (void*)0x08004CDC }, { 0xF2, 0, (void*)0x08004D8C }, { 0xF3, 0, (void*)0x08004DC8 }, - { 0xF4, 0, (void*)0x08004E3C }, { 0xF5, 0, (void*)0x08004E8C }, { 0xF6, 0, (void*)0x08004EDC }, - { 0xF7, 0, (void*)0x08004F30 }, { 0xF8, 0, (void*)0x08004F70 }, { 0xF9, 0, (void*)0x08004F9C }, - { 0xFA, 0, (void*)0x08005034 }, { 0xFB, 0, (void*)0x08005088 }, { 0xFC, 0, (void*)0x080050FC }, - { 0xFD, 0, (void*)0x0800515C }, { 0xFE, 0, (void*)0x08005184 }, { 0xFF, 0, (void*)0x080051B8 }, - { 0x100, 0, (void*)0x08005214 }, { 0x101, 0, (void*)0x08005230 }, { 0x102, 0, (void*)0x0800524C }, - { 0x103, 0, (void*)0x08005268 }, { 0x104, 0, (void*)0x08005284 }, { 0x105, 0, (void*)0x080052A0 }, - { 0x106, 0, (void*)0x080052B8 }, { 0x107, 0, (void*)0x080052D4 }, { 0x108, 0, (void*)0x080052F8 }, - { 0x109, 0, (void*)0x0800531C }, { 0x10A, 0, (void*)0x0800533C }, { 0x10B, 0, (void*)0x08005358 }, - { 0x10C, 0, (void*)0x0800537C }, { 0x10D, 0, (void*)0x08005390 }, { 0x10E, 0, (void*)0x080053A8 }, - { 0x10F, 0, (void*)0x080053C4 }, { 0x110, 0, (void*)0x080053DC }, { 0x111, 0, (void*)0x080053FC }, - { 0x112, 0, (void*)0x08005414 }, { 0x113, 0, (void*)0x0800542C }, { 0x114, 0, (void*)0x08005450 }, - { 0x115, 0, (void*)0x08005470 }, { 0x116, 0, (void*)0x0800548C }, { 0x117, 0, (void*)0x080054A8 }, - { 0x118, 0, (void*)0x080054BC }, { 0x119, 0, (void*)0x080054D4 }, { 0x11A, 0, (void*)0x080054F4 }, - { 0x11B, 0, (void*)0x08005518 }, { 0x11C, 0, (void*)0x0800553C }, { 0x11D, 0, (void*)0x0800555C }, - { 0x11E, 0, (void*)0x08005578 }, { 0x11F, 0, (void*)0x08005598 }, { 0x120, 0, (void*)0x080055B4 }, - { 0x121, 0, (void*)0x080055CC }, { 0x122, 0, (void*)0x080055E8 }, { 0x123, 0, (void*)0x08005604 }, - { 0x124, 0, (void*)0x08005620 }, { 0x125, 0, (void*)0x08005638 }, { 0x126, 0, (void*)0x0800564C }, - { 0x127, 0, (void*)0x08005668 }, { 0x129, 0, (void*)0x08005684 }, { 0x12A, 0, (void*)0x0800569C }, - { 0x12B, 0, (void*)0x080056B8 }, { 0x12C, 0, (void*)0x080056D4 }, { 0x12D, 0, (void*)0x080056F0 }, - { 0x12E, 0, (void*)0x0800570C }, { 0x12F, 0, (void*)0x08005724 }, { 0x130, 0, (void*)0x0800573C }, - { 0x131, 0, (void*)0x08005758 }, { 0x132, 0, (void*)0x08005770 }, { 0x134, 0, (void*)0x08005788 }, - { 0x135, 0, (void*)0x080057A4 }, { 0x136, 0, (void*)0x080057C0 }, { 0x137, 0, (void*)0x080057D8 }, - { 0x138, 0, (void*)0x080057F4 }, { 0x139, 0, (void*)0x08005814 }, { 0x13A, 0, (void*)0x0800582C }, - { 0x13B, 0, (void*)0x0800584C }, { 0x13D, 0, (void*)0x08005868 }, { 0x13E, 0, (void*)0x08005884 }, - { 0x13F, 0, (void*)0x080058A0 }, { 0x140, 0, (void*)0x080058C4 }, { 0x141, 0, (void*)0x080058DC }, - { 0x142, 0, (void*)0x080058F4 }, { 0x143, 0, (void*)0x08005918 }, { 0x144, 0, (void*)0x08005934 }, - { 0x145, 0, (void*)0x08005954 }, { 0x146, 0, (void*)0x08005970 }, { 0x147, 0, (void*)0x08005988 }, - { 0x148, 0, (void*)0x080059A4 }, { 0x149, 0, (void*)0x080059C0 }, { 0x200, 0, (void*)0x080059D8 }, - { 0x201, 0, (void*)0x08005A54 }, { 0x202, 0, (void*)0x08005B48 }, { 0x203, 0, (void*)0x08005B74 }, - { 0x204, 0, (void*)0x08005BE4 }, { 0x205, 0, (void*)0x08005C38 }, { 0x206, 0, (void*)0x08005C94 }, - { 0x207, 0, (void*)0x08005D04 }, { 0x208, 0, (void*)0x08005D2C }, { 0x209, 0, (void*)0x08005D64 }, - { 0x20A, 0, (void*)0x08005DB4 }, { 0x20B, 0, (void*)0x08005E08 }, { 0x20C, 0, (void*)0x08005E14 }, - { 0x20D, 0, (void*)0x08005E60 }, { 0x20E, 0, (void*)0x08005ECC }, { 0x20F, 0, (void*)0x08005ED8 }, - { 0x210, 0, (void*)0x08005F74 }, { 0x211, 0, (void*)0x08005FAC }, { 0x212, 0, (void*)0x08005FD4 }, - { 0x213, 0, (void*)0x0800602C }, { 0x214, 0, (void*)0x08006050 }, { 0x215, 0, (void*)0x08006124 }, - { 0x216, 0, (void*)0x08006358 }, { 0x217, 0, (void*)0x080065B8 }, { 0x218, 0, (void*)0x08006620 }, - { 0x219, 0, (void*)0x0800668C }, { 0x21A, 0, (void*)0x08006720 }, { 0x21B, 0, (void*)0x0800674C }, - { 0x21D, 0, (void*)0x08006774 }, { 0x21E, 0, (void*)0x080067CC }, { 0x21F, 0, (void*)0x08006874 }, - { 0x220, 0, (void*)0x080068E0 }, { 0x221, 0, (void*)0x08006978 }, { 0x222, 0, (void*)0x08006A04 }, - { 0x223, 0, (void*)0x08006A48 }, { 0x224, 0, (void*)0x08006AE8 }, { 0x225, 0, (void*)0x08006B54 }, - { 0x226, 0, (void*)0x08006BB0 }, { 0x227, 0, (void*)0x08006BE8 }, { 0x228, 0, (void*)0x08006D58 }, - { 0x229, 0, (void*)0x08006E18 }, { 0x22A, 0, (void*)0x08006EA0 }, { 0x22B, 0, (void*)0x08006F00 }, - { 0x22C, 0, (void*)0x08006F44 }, { 0x22D, 0, (void*)0x08006F60 }, { 0x22E, 0, (void*)0x08006FB0 }, - { 0x22F, 0, (void*)0x08006FC8 }, { 0x230, 0, (void*)0x08007010 }, { 0x231, 0, (void*)0x080070C0 }, - { 0x232, 0, (void*)0x08007110 }, { 0x233, 0, (void*)0x08007158 }, { 0x234, 0, (void*)0x080071A4 }, - { 0x235, 0, (void*)0x08007208 }, { 0x236, 0, (void*)0x0800725C }, { 0x237, 0, (void*)0x080072AC }, - { 0x238, 0, (void*)0x0800730C }, { 0x239, 0, (void*)0x0800734C }, { 0x23A, 0, (void*)0x08007400 }, - { 0x23B, 0, (void*)0x08007468 }, { 0x23C, 0, (void*)0x08007500 }, { 0x23D, 0, (void*)0x08007538 }, - { 0x23E, 0, (void*)0x080075E4 }, { 0x23F, 0, (void*)0x080075F0 }, { 0x240, 0, (void*)0x0800765C }, - { 0x241, 0, (void*)0x080076D0 }, { 0x242, 0, (void*)0x08007744 }, { 0x243, 0, (void*)0x080077B0 }, - { 0x244, 0, (void*)0x08007830 }, { 0x245, 0, (void*)0x08007888 }, { 0x246, 0, (void*)0x080078B4 }, - { 0x247, 0, (void*)0x08007904 }, { 0x248, 0, (void*)0x08007950 }, { 0x249, 0, (void*)0x080079A0 }, - { 0x24A, 0, (void*)0x080079F0 }, { 0x24B, 0, (void*)0x08007A30 }, { 0x24C, 0, (void*)0x08007A78 }, - { 0x24D, 0, (void*)0x08007AD8 }, { 0x24E, 0, (void*)0x08007B54 }, { 0x24F, 0, (void*)0x08007BE8 }, - { 0x250, 0, (void*)0x08007C88 }, { 0x251, 0, (void*)0x08007CEC }, { 0x252, 0, (void*)0x08007D18 }, - { 0x253, 0, (void*)0x08007D68 }, { 0x254, 0, (void*)0x08007DAC }, { 0x255, 0, (void*)0x08007E04 }, - { 0x256, 0, (void*)0x08007E4C }, { 0x257, 0, (void*)0x08007EA4 }, { 0x258, 0, (void*)0x08007F00 }, - { 0x25A, 0, (void*)0x08007F58 }, { 0x25B, 0, (void*)0x08007FA0 }, { 0x25C, 0, (void*)0x08007FDC }, - { 0x25D, 0, (void*)0x08007FF8 }, { 0x25E, 0, (void*)0x08008024 }, { 0x25F, 0, (void*)0x080080E4 }, - { 0x260, 0, (void*)0x0800818C }, { 0x261, 0, (void*)0x080081F8 }, { 0x262, 0, (void*)0x08008288 }, - { 0x263, 0, (void*)0x08008304 }, { 0x264, 0, (void*)0x08008344 }, { 0x265, 0, (void*)0x08008420 }, - { 0x302, 0, (void*)0x08008498 }, { 0x303, 0, (void*)0x080085DC }, { 0x304, 0, (void*)0x08008660 }, - { 0x305, 0, (void*)0x080086B4 }, { 0x306, 0, (void*)0x08008720 }, { 0x307, 0, (void*)0x0800872C }, - { 0x308, 0, (void*)0x0800875C }, { 0x309, 0, (void*)0x08008788 }, { 0x30A, 0, (void*)0x080087BC }, - { 0x30B, 0, (void*)0x080087E8 }, { 0x30C, 0, (void*)0x08008824 }, { 0x30D, 0, (void*)0x08008894 }, - { 0x30E, 0, (void*)0x080088E4 }, { 0x30F, 0, (void*)0x08008914 }, { 0x310, 0, (void*)0x08008970 }, - { 0x311, 0, (void*)0x080089BC }, { 0x312, 0, (void*)0x080089F0 }, { 0x313, 0, (void*)0x08008A64 }, - { 0x314, 0, (void*)0x08008AA4 }, { 0x315, 0, (void*)0x08008B0C }, { 0x316, 0, (void*)0x08008B64 }, - { 0x317, 0, (void*)0x08008BA4 }, { 0x318, 0, (void*)0x08008BF0 }, { 0x319, 0, (void*)0x08008C48 }, - { 0x31A, 0, (void*)0x08008C84 }, { 0x31B, 0, (void*)0x08008CD0 }, { 0x31C, 0, (void*)0x08008D10 }, - { 0x31D, 0, (void*)0x08008D5C }, { 0x31E, 0, (void*)0x08008DCC }, { 0x31F, 0, (void*)0x08008E2C }, - { 0x320, 0, (void*)0x08008EBC }, { 0x321, 0, (void*)0x08008F30 }, { 0x322, 0, (void*)0x08008F60 }, - { 0x323, 0, (void*)0x08008F9C }, { 0x324, 0, (void*)0x08008FFC }, { 0x325, 0, (void*)0x08009044 }, - { 0x326, 0, (void*)0x080090A8 }, { 0x327, 0, (void*)0x080090F8 }, { 0x328, 0, (void*)0x08009140 }, - { 0x329, 0, (void*)0x08009188 }, { 0x32A, 0, (void*)0x080091F0 }, { 0x32B, 0, (void*)0x08009240 }, - { 0x32C, 0, (void*)0x0800928C }, { 0x32D, 0, (void*)0x080092F0 }, { 0x32E, 0, (void*)0x08009318 }, - { 0x32F, 0, (void*)0x08009358 }, { 0x330, 0, (void*)0x0800939C }, { 0x331, 0, (void*)0x080093E4 }, - { 0x332, 0, (void*)0x08009440 }, { 0x333, 0, (void*)0x0800949C }, { 0x334, 0, (void*)0x08009518 }, - { 0x335, 0, (void*)0x0800955C }, { 0x336, 0, (void*)0x08009598 }, { 0x337, 0, (void*)0x08009658 }, - { 0x338, 0, (void*)0x08009680 }, { 0x339, 0, (void*)0x080096A8 }, { 0x33A, 0, (void*)0x080096C8 }, - { 0x33B, 0, (void*)0x080096EC }, { 0x33C, 0, (void*)0x0800973C }, { 0x33D, 0, (void*)0x08009778 }, - { 0x33E, 0, (void*)0x080097BC }, { 0x33F, 0, (void*)0x08009930 }, { 0x340, 0, (void*)0x08009C50 }, - { 0x341, 0, (void*)0x08009CC4 }, { 0x342, 0, (void*)0x08009D30 }, { 0x343, 0, (void*)0x08009D58 }, - { 0x3E8, 0, (void*)0x08009D7C }, { 0x3E9, 0, (void*)0x08009DCC }, { 0x3EA, 0, (void*)0x08009DE8 }, - { 0x3EB, 0, (void*)0x08009E2C }, { 0x3EC, 0, (void*)0x08009E54 }, { 0x3ED, 0, (void*)0x08009EB8 }, - { 0x3EE, 0, (void*)0x08009EFC }, { 0x3EF, 0, (void*)0x08009F6C }, { 0x3F0, 0, (void*)0x08009FA0 }, - { 0x3F1, 0, (void*)0x08009FF0 }, { 0x3F2, 0, (void*)0x0800A030 }, { 0x3F3, 0, (void*)0x0800A090 }, - { 0x3F4, 0, (void*)0x0800A0D0 }, { 0x3F5, 0, (void*)0x0800A0F8 }, { 0x3F6, 0, (void*)0x0800A158 }, - { 0x3F7, 0, (void*)0x0800A190 }, { 0x3F8, 0, (void*)0x0800A1BC }, { 0x3F9, 0, (void*)0x0800A214 }, - { 0x3FA, 0, (void*)0x0800A25C }, { 0x3FB, 0, (void*)0x0800A29C }, { 0x3FC, 0, (void*)0x0800A2D8 }, - { 0x3FD, 0, (void*)0x0800A31C }, { 0x3FE, 0, (void*)0x0800A40C }, { 0x3FF, 0, (void*)0x0800A478 }, - { 0x400, 0, (void*)0x0800A4EC }, { 0x401, 0, (void*)0x0800A528 }, { 0x402, 0, (void*)0x0800A560 }, - { 0x403, 0, (void*)0x0800A5D4 }, { 0x404, 0, (void*)0x0800A608 }, { 0x405, 0, (void*)0x0800A63C }, - { 0x406, 0, (void*)0x0800A680 }, { 0x407, 0, (void*)0x0800A6B8 }, { 0x408, 0, (void*)0x0800A70C }, - { 0x44C, 0, (void*)0x0800A75C }, { 0x44D, 0, (void*)0x0800A850 }, { 0x44E, 0, (void*)0x0800A8B8 }, - { 0x44F, 0, (void*)0x0800A904 }, { 0x450, 0, (void*)0x0800A924 }, { 0x451, 0, (void*)0x0800A974 }, - { 0x452, 0, (void*)0x0800A9E8 }, { 0x453, 0, (void*)0x0800AA24 }, { 0x454, 0, (void*)0x0800AA7C }, - { 0x455, 0, (void*)0x0800AAB4 }, { 0x456, 0, (void*)0x0800AB10 }, { 0x457, 0, (void*)0x0800AB44 }, - { 0x458, 0, (void*)0x0800AB78 }, { 0x459, 0, (void*)0x0800AC0C }, { 0x45A, 0, (void*)0x0800AC84 }, - { 0x45B, 0, (void*)0x0800ACD0 }, { 0x45C, 0, (void*)0x0800AD4C }, { 0x45D, 0, (void*)0x0800ADC8 }, - { 0x45E, 0, (void*)0x0800AE68 }, { 0x45F, 0, (void*)0x0800AEBC }, { 0x460, 0, (void*)0x0800AF54 }, - { 0x461, 0, (void*)0x0800AF98 }, { 0x462, 0, (void*)0x0800AFC8 }, { 0x463, 0, (void*)0x0800AFE8 }, - { 0x464, 0, (void*)0x0800B044 }, { 0x465, 0, (void*)0x0800B094 }, { 0x466, 0, (void*)0x0800B0CC }, - { 0x467, 0, (void*)0x0800B0FC }, { 0x468, 0, (void*)0x0800B178 }, { 0x469, 0, (void*)0x0800B1B8 }, - { 0x46A, 0, (void*)0x0800B1F0 }, { 0x46B, 0, (void*)0x0800B244 }, { 0x46C, 0, (void*)0x0800B258 }, - { 0x46D, 0, (void*)0x0800B2B4 }, { 0x46E, 0, (void*)0x0800B324 }, { 0x46F, 0, (void*)0x0800B374 }, - { 0x470, 0, (void*)0x0800B3A8 }, { 0x471, 0, (void*)0x0800B3F4 }, { 0x472, 0, (void*)0x0800B428 }, - { 0x473, 0, (void*)0x0800B484 }, { 0x474, 0, (void*)0x0800B4A4 }, { 0x475, 0, (void*)0x0800B514 }, - { 0x476, 0, (void*)0x0800B570 }, { 0x477, 0, (void*)0x0800B5FC }, { 0x478, 0, (void*)0x0800B65C }, - { 0x479, 0, (void*)0x0800B6CC }, { 0x47A, 0, (void*)0x0800B6FC }, { 0x47B, 0, (void*)0x0800B760 }, - { 0x47C, 0, (void*)0x0800B78C }, { 0x47D, 0, (void*)0x0800B7DC }, { 0x47E, 0, (void*)0x0800B82C }, - { 0x4B0, 0, (void*)0x0800B854 }, { 0x4B1, 0, (void*)0x0800B8B0 }, { 0x4B2, 0, (void*)0x0800B8F8 }, - { 0x4B3, 0, (void*)0x0800B93C }, { 0x4B4, 0, (void*)0x0800B994 }, { 0x4B5, 0, (void*)0x0800B9D0 }, - { 0x4B6, 0, (void*)0x0800BA04 }, { 0x4B7, 0, (void*)0x0800BA94 }, { 0x4B8, 0, (void*)0x0800BAC4 }, - { 0x4B9, 0, (void*)0x0800BB4C }, { 0x4BA, 0, (void*)0x0800BB7C }, { 0x4BB, 0, (void*)0x0800BBFC }, - { 0x4BC, 0, (void*)0x0800BC28 }, { 0x4BD, 0, (void*)0x0800BCA4 }, { 0x4BE, 0, (void*)0x0800BCD0 }, - { 0x4BF, 0, (void*)0x0800BD58 }, { 0x4C0, 0, (void*)0x0800BD84 }, { 0x4C1, 0, (void*)0x0800BE18 }, - { 0x4C2, 0, (void*)0x0800BE54 }, { 0x4C3, 0, (void*)0x0800BED0 }, { 0x4C4, 0, (void*)0x0800BEEC }, - { 0x4C5, 0, (void*)0x0800BF5C }, { 0x4C6, 0, (void*)0x0800BF78 }, { 0x4C7, 0, (void*)0x0800BFF4 }, - { 0x4C8, 0, (void*)0x0800C018 }, { 0x4C9, 0, (void*)0x0800C0A4 }, { 0x4CA, 0, (void*)0x0800C0D8 }, - { 0x4CB, 0, (void*)0x0800C140 }, { 0x4CC, 0, (void*)0x0800C158 }, { 0x4CD, 0, (void*)0x0800C1E0 }, - { 0x4CE, 0, (void*)0x0800C220 }, { 0x4CF, 0, (void*)0x0800C29C }, { 0x4D0, 0, (void*)0x0800C2D0 }, - { 0x4D1, 0, (void*)0x0800C34C }, { 0x4D2, 0, (void*)0x0800C378 }, { 0x4D3, 0, (void*)0x0800C400 }, - { 0x4D4, 0, (void*)0x0800C448 }, { 0x4D5, 0, (void*)0x0800C4BC }, { 0x4D6, 0, (void*)0x0800C4E0 }, - { 0x4D7, 0, (void*)0x0800C560 }, { 0x4D8, 0, (void*)0x0800C598 }, { 0x4D9, 0, (void*)0x0800C604 }, - { 0x4DA, 0, (void*)0x0800C63C }, { 0x4DB, 0, (void*)0x0800C6B4 }, { 0x4DC, 0, (void*)0x0800C714 }, - { 0x4DD, 0, (void*)0x0800C784 }, { 0x4DE, 0, (void*)0x0800C7B4 }, { 0x4DF, 0, (void*)0x0800C81C }, - { 0x4E0, 0, (void*)0x0800C840 }, { 0x4E1, 0, (void*)0x0800C8AC }, { 0x4E2, 0, (void*)0x0800C8CC }, - { 0x4E3, 0, (void*)0x0800C95C }, { 0x4E4, 0, (void*)0x0800C990 }, { 0x4E5, 0, (void*)0x0800CA04 }, - { 0x4E6, 0, (void*)0x0800CA20 }, { 0x4E7, 0, (void*)0x0800CA9C }, { 0x4E8, 0, (void*)0x0800CAC0 }, - { 0x4E9, 0, (void*)0x0800CB48 }, { 0x4EA, 0, (void*)0x0800CB64 }, { 0x4EB, 0, (void*)0x0800CBE8 }, - { 0x4EC, 0, (void*)0x0800CC04 }, { 0x4ED, 0, (void*)0x0800CC64 }, { 0x4EE, 0, (void*)0x0800CC88 }, - { 0x4EF, 0, (void*)0x0800CCE8 }, { 0x4F0, 0, (void*)0x0800CD0C }, { 0x4F1, 0, (void*)0x0800CD7C }, - { 0x514, 0, (void*)0x0800CDA4 }, { 0x515, 0, (void*)0x0800CED0 }, { 0x516, 0, (void*)0x0800CFE8 }, - { 0x517, 0, (void*)0x0800D094 }, { 0x518, 0, (void*)0x0800D128 }, { 0x519, 0, (void*)0x0800D1C8 }, - { 0x51A, 0, (void*)0x0800D254 }, { 0x51B, 0, (void*)0x0800D2A8 }, { 0x51C, 0, (void*)0x0800D318 }, - { 0x51D, 0, (void*)0x0800D360 }, { 0x51E, 0, (void*)0x0800D3D0 }, { 0x51F, 0, (void*)0x0800D418 }, - { 0x520, 0, (void*)0x0800D488 }, { 0x521, 0, (void*)0x0800D534 }, { 0x522, 0, (void*)0x0800D5BC }, - { 0x523, 0, (void*)0x0800D65C }, { 0x524, 0, (void*)0x0800D6E4 }, { 0x525, 0, (void*)0x0800D728 }, - { 0x526, 0, (void*)0x0800D794 }, { 0x527, 0, (void*)0x0800D7D0 }, { 0x528, 0, (void*)0x0800D834 }, - { 0x529, 0, (void*)0x0800D878 }, { 0x52A, 0, (void*)0x0800D8E4 }, { 0x52B, 0, (void*)0x0800D98C }, - { 0x52C, 0, (void*)0x0800DA2C }, { 0x52D, 0, (void*)0x0800DAC8 }, { 0x52E, 0, (void*)0x0800DB6C }, - { 0x52F, 0, (void*)0x0800DBD4 }, { 0x530, 0, (void*)0x0800DC5C }, { 0x531, 0, (void*)0x0800DCC4 }, - { 0x532, 0, (void*)0x0800DD54 }, { 0x533, 0, (void*)0x0800DDA4 }, { 0x534, 0, (void*)0x0800DE1C }, - { 0x535, 0, (void*)0x0800DEC8 }, { 0x536, 0, (void*)0x0800DF50 }, { 0x537, 0, (void*)0x0800DFF0 }, - { 0x538, 0, (void*)0x0800E078 }, { 0x539, 0, (void*)0x0800E0BC }, { 0x53A, 0, (void*)0x0800E128 }, - { 0x53B, 0, (void*)0x0800E16C }, { 0x53C, 0, (void*)0x0800E1D8 }, { 0x53D, 0, (void*)0x0800E21C }, - { 0x53E, 0, (void*)0x0800E288 }, { 0x53F, 0, (void*)0x0800E334 }, { 0x540, 0, (void*)0x0800E414 }, - { 0x541, 0, (void*)0x0800E474 }, { 0x542, 0, (void*)0x0800E50C }, { 0x543, 0, (void*)0x0800E57C }, - { 0x544, 0, (void*)0x0800E614 }, { 0x545, 0, (void*)0x0800E678 }, { 0x546, 0, (void*)0x0800E728 }, - { 0x547, 0, (void*)0x0800E794 }, { 0x548, 0, (void*)0x0800E7F4 }, { 0x549, 0, (void*)0x0800E86C }, - { 0x54A, 0, (void*)0x0800E8D8 }, { 0x54B, 0, (void*)0x0800E934 }, { 0x54C, 0, (void*)0x0800E9B4 }, - { 0x54D, 0, (void*)0x0800EA28 }, { 0x54E, 0, (void*)0x0800EB08 }, { 0x54F, 0, (void*)0x0800EB60 }, - { 0x550, 0, (void*)0x0800EBC8 }, { 0x551, 0, (void*)0x0800EC2C }, { 0x552, 0, (void*)0x0800ECAC }, - { 0x553, 0, (void*)0x0800ED1C }, { 0x554, 0, (void*)0x0800ED9C }, { 0x555, 0, (void*)0x0800EE00 }, - { 0x556, 0, (void*)0x0800EEEC }, { 0x557, 0, (void*)0x0800EF4C }, { 0x558, 0, (void*)0x0800EFBC }, - { 0x559, 0, (void*)0x0800F03C }, { 0x55A, 0, (void*)0x0800F0B4 }, { 0x55B, 0, (void*)0x0800F110 }, - { 0x55C, 0, (void*)0x0800F188 }, { 0x55D, 0, (void*)0x0800F258 }, { 0x55E, 0, (void*)0x0800F300 }, - { 0x55F, 0, (void*)0x0800F398 }, { 0x560, 0, (void*)0x0800F44C }, { 0x561, 0, (void*)0x0800F570 }, - { 0x562, 0, (void*)0x0800F688 }, { 0x563, 0, (void*)0x0800F7A8 }, { 0x564, 0, (void*)0x0800F8B8 }, - { 0x565, 0, (void*)0x0800F9D8 }, { 0x566, 0, (void*)0x0800FAEC }, { 0x567, 0, (void*)0x0800FB84 }, - { 0x568, 0, (void*)0x0800FC34 }, { 0x569, 0, (void*)0x0800FCC8 }, { 0x56A, 0, (void*)0x0800FD78 }, - { 0x56B, 0, (void*)0x0800FE0C }, { 0x56C, 0, (void*)0x0800FEBC }, { 0x56D, 0, (void*)0x08010008 }, - { 0x56E, 0, (void*)0x08010168 }, { 0x56F, 0, (void*)0x080102C4 }, { 0x570, 0, (void*)0x0801042C }, - { 0x571, 0, (void*)0x08010584 }, { 0x572, 0, (void*)0x080106EC }, { 0x573, 0, (void*)0x08010844 }, - { 0x578, 0, (void*)0x080109A4 }, { 0x579, 0, (void*)0x08010A70 }, { 0x57A, 0, (void*)0x08010B28 }, - { 0x57B, 0, (void*)0x08010C7C }, { 0x57C, 0, (void*)0x08010D98 }, { 0x57D, 0, (void*)0x08010EC4 }, - { 0x57E, 0, (void*)0x08010FF4 }, { 0x57F, 0, (void*)0x080110E4 }, { 0x580, 0, (void*)0x080111D0 }, - { 0x582, 0, (void*)0x08011260 }, { 0x583, 0, (void*)0x08011304 }, { 0x584, 0, (void*)0x08011374 }, - { 0x585, 0, (void*)0x08011408 }, { 0x586, 0, (void*)0x080114BC }, { 0x587, 0, (void*)0x08011528 }, - { 0x588, 0, (void*)0x080115C0 }, { 0x589, 0, (void*)0x08011674 }, { 0x58A, 0, (void*)0x080116E4 }, - { 0x58B, 0, (void*)0x08011760 }, { 0x58C, 0, (void*)0x08011820 }, { 0x58D, 0, (void*)0x08011884 }, - { 0x58E, 0, (void*)0x0801192C }, { 0x58F, 0, (void*)0x08011A20 }, { 0x590, 0, (void*)0x08011B08 }, - { 0x591, 0, (void*)0x08011B68 }, { 0x592, 0, (void*)0x08011BA4 }, { 0x593, 0, (void*)0x08011BE4 }, - { 0x594, 0, (void*)0x08011C20 }, { 0x595, 0, (void*)0x08011D00 }, { 0x59C, 0, (void*)0x08011DC8 }, - { 0x59D, 0, (void*)0x08011E78 }, { 0x59E, 0, (void*)0x08011EB4 }, { 0x59F, 0, (void*)0x08011EFC }, - { 0x5A0, 0, (void*)0x08011FB4 }, { 0x5A1, 0, (void*)0x08012068 }, { 0x5A2, 0, (void*)0x080120A4 }, - { 0x5A3, 0, (void*)0x080120E4 }, { 0x5A4, 0, (void*)0x08012198 }, { 0x5A5, 0, (void*)0x08012248 }, - { 0x5A6, 0, (void*)0x08012284 }, { 0x5A7, 0, (void*)0x080122C4 }, { 0x5A8, 0, (void*)0x08012380 }, - { 0x5A9, 0, (void*)0x0801243C }, { 0x5AA, 0, (void*)0x08012478 }, { 0x5DC, 0, (void*)0x080124B8 }, - { 0x5DD, 0, (void*)0x08012548 }, { 0x5DE, 0, (void*)0x080125BC }, { 0x5DF, 0, (void*)0x08012678 }, - { 0x5E0, 0, (void*)0x08012730 }, { 0x5E1, 0, (void*)0x0801276C }, { 0x5E2, 0, (void*)0x08012784 }, - { 0x5E3, 0, (void*)0x080127C4 }, { 0x5E4, 0, (void*)0x080128A8 }, { 0x5E5, 0, (void*)0x080128E0 }, - { 0x5E6, 0, (void*)0x0801294C }, { 0x5E7, 0, (void*)0x08012970 }, { 0x5E8, 0, (void*)0x080129A4 }, - { 0x5E9, 0, (void*)0x08012A5C }, { 0x5EA, 0, (void*)0x08012ACC }, { 0x5EB, 0, (void*)0x08012B4C }, - { 0x5EC, 0, (void*)0x08012BF0 }, { 0x5ED, 0, (void*)0x08012CE0 }, { 0x5EE, 0, (void*)0x08012D84 }, - { 0x5EF, 0, (void*)0x08012DE4 }, { 0x5F0, 0, (void*)0x08012E1C }, { 0x5F1, 0, (void*)0x08012E7C }, - { 0x5F2, 0, (void*)0x08012EF0 }, { 0x5F3, 0, (void*)0x08012FAC }, { 0x5F4, 0, (void*)0x08013060 }, - { 0x5F5, 0, (void*)0x080130F4 }, { 0x5F6, 0, (void*)0x0801315C }, { 0x5F7, 0, (void*)0x08013210 }, - { 0x5F8, 0, (void*)0x08013258 }, { 0x60E, 0, (void*)0x080132B0 }, { 0x60F, 0, (void*)0x08013368 }, - { 0x610, 0, (void*)0x08013470 }, { 0x611, 0, (void*)0x08013530 }, { 0x612, 0, (void*)0x080135F8 }, - { 0x613, 0, (void*)0x08013680 }, { 0x614, 0, (void*)0x080137D0 }, { 0x615, 0, (void*)0x0801386C }, - { 0x616, 0, (void*)0x08013944 }, { 0x617, 0, (void*)0x080139B8 }, { 0x618, 0, (void*)0x08013A44 }, - { 0x619, 0, (void*)0x08013AA8 }, { 0x61A, 0, (void*)0x08013BFC }, { 0x61B, 0, (void*)0x08013C5C }, - { 0x61C, 0, (void*)0x08013CB0 }, { 0x61D, 0, (void*)0x08013D00 }, { 0x61E, 0, (void*)0x08013D60 }, - { 0x61F, 0, (void*)0x08013DAC }, { 0x620, 0, (void*)0x08013DEC }, { 0x621, 0, (void*)0x08013E4C }, - { 0x622, 0, (void*)0x08013E80 }, { 0x623, 0, (void*)0x08013ED8 }, { 0x624, 0, (void*)0x08013F24 }, - { 0x625, 0, (void*)0x08013FEC }, { 0x626, 0, (void*)0x08014010 }, { 0x627, 0, (void*)0x08014064 }, - { 0x628, 0, (void*)0x080140C4 }, { 0x629, 0, (void*)0x08014170 }, { 0x62A, 0, (void*)0x08014208 }, - { 0x62B, 0, (void*)0x080142D0 }, { 0x62C, 0, (void*)0x08014398 }, { 0x640, 0, (void*)0x0801454C }, - { 0x641, 0, (void*)0x0801458C }, { 0x642, 0, (void*)0x080145B4 }, { 0x644, 0, (void*)0x080145F0 }, - { 0x645, 0, (void*)0x08014608 }, { 0x646, 0, (void*)0x08014648 }, { 0x647, 0, (void*)0x080146B0 }, - { 0x648, 0, (void*)0x080146D4 }, { 0x649, 0, (void*)0x08014760 }, { 0x64A, 0, (void*)0x08014798 }, - { 0x64B, 0, (void*)0x08014850 }, { 0x64C, 0, (void*)0x08014898 }, { 0x64D, 0, (void*)0x080148B4 }, - { 0x64E, 0, (void*)0x08014924 }, { 0x64F, 0, (void*)0x08014988 }, { 0x650, 0, (void*)0x080149F0 }, - { 0x651, 0, (void*)0x08014A50 }, { 0x652, 0, (void*)0x08014A8C }, { 0x653, 0, (void*)0x08014AF4 }, - { 0x654, 0, (void*)0x08014B34 }, { 0x655, 0, (void*)0x08014B9C }, { 0x656, 0, (void*)0x08014BD8 }, - { 0x657, 0, (void*)0x08014C38 }, { 0x658, 0, (void*)0x08014C78 }, { 0x659, 0, (void*)0x08014CBC }, - { 0x65A, 0, (void*)0x08014D10 }, { 0x65B, 0, (void*)0x08014D94 }, { 0x65C, 0, (void*)0x08014E68 }, - { 0x65D, 0, (void*)0x08014F18 }, { 0x65E, 0, (void*)0x08014F5C }, { 0x65F, 0, (void*)0x08014F88 }, - { 0x660, 0, (void*)0x08014FD0 }, { 0x661, 0, (void*)0x08015024 }, { 0x662, 0, (void*)0x080150F0 }, - { 0x663, 0, (void*)0x08015188 }, { 0x664, 0, (void*)0x080151AC }, { 0x665, 0, (void*)0x080151E4 }, - { 0x666, 0, (void*)0x08015248 }, { 0x667, 0, (void*)0x0801529C }, { 0x668, 0, (void*)0x080152CC }, - { 0x669, 0, (void*)0x0801532C }, { 0x66A, 0, (void*)0x08015390 }, { 0x66B, 0, (void*)0x080153E4 }, - { 0x66C, 0, (void*)0x08015450 }, { 0x66D, 0, (void*)0x080154BC }, { 0x66E, 0, (void*)0x08015550 }, - { 0x66F, 0, (void*)0x080155C0 }, { 0x670, 0, (void*)0x08015600 }, { 0x671, 0, (void*)0x08015634 }, - { 0x672, 0, (void*)0x0801568C }, { 0x673, 0, (void*)0x080156C8 }, { 0x674, 0, (void*)0x0801574C }, - { 0x675, 0, (void*)0x08015784 }, { 0x676, 0, (void*)0x080157F8 }, { 0x677, 0, (void*)0x0801588C }, - { 0x678, 0, (void*)0x080158E4 }, { 0x679, 0, (void*)0x08015940 }, { 0x67A, 0, (void*)0x08015994 }, - { 0x67B, 0, (void*)0x080159E8 }, { 0x67C, 0, (void*)0x08015A48 }, { 0x67D, 0, (void*)0x08015B58 }, - { 0x67E, 0, (void*)0x08015C04 }, { 0x67F, 0, (void*)0x08015C50 }, { 0x680, 0, (void*)0x08015D64 }, - { 0x681, 0, (void*)0x08015E40 }, { 0x682, 0, (void*)0x08015ED0 }, { 0x683, 0, (void*)0x08015F00 }, - { 0x684, 0, (void*)0x08015F90 }, { 0x685, 0, (void*)0x08015FCC }, { 0x686, 0, (void*)0x08016020 }, - { 0x687, 0, (void*)0x08016078 }, { 0x688, 0, (void*)0x080160AC }, { 0x689, 0, (void*)0x08016104 }, - { 0x68A, 0, (void*)0x08016130 }, { 0x6A4, 0, (void*)0x08016184 }, { 0x6A5, 0, (void*)0x080161B8 }, - { 0x6A6, 0, (void*)0x0801620C }, { 0x6A7, 0, (void*)0x08016248 }, { 0x6A8, 0, (void*)0x080162A0 }, - { 0x6A9, 0, (void*)0x080162C8 }, { 0x6AA, 0, (void*)0x0801634C }, { 0x6AB, 0, (void*)0x08016398 }, - { 0x6AC, 0, (void*)0x080163FC }, { 0x6AD, 0, (void*)0x08016478 }, { 0x6AE, 0, (void*)0x080164B4 }, - { 0x6AF, 0, (void*)0x08016508 }, { 0x6B0, 0, (void*)0x08016548 }, { 0x6B1, 0, (void*)0x080165C0 }, - { 0x6B2, 0, (void*)0x08016600 }, { 0x6B3, 0, (void*)0x08016674 }, { 0x6B4, 0, (void*)0x080166B4 }, - { 0x6B5, 0, (void*)0x0801671C }, { 0x6B6, 0, (void*)0x08016758 }, { 0x6B7, 0, (void*)0x080167C0 }, - { 0x6B8, 0, (void*)0x080167F8 }, { 0x6B9, 0, (void*)0x08016858 }, { 0x6BA, 0, (void*)0x08016894 }, - { 0x6BB, 0, (void*)0x08016900 }, { 0x6BC, 0, (void*)0x0801693C }, { 0x6BD, 0, (void*)0x0801698C }, - { 0x6BE, 0, (void*)0x080169CC }, { 0x6BF, 0, (void*)0x08016A04 }, { 0x6C0, 0, (void*)0x08016A28 }, - { 0x6C1, 0, (void*)0x08016A7C }, { 0x6C2, 0, (void*)0x08016A98 }, { 0x6C3, 0, (void*)0x08016AC8 }, - { 0x6C4, 0, (void*)0x08016AE4 }, { 0x6C5, 0, (void*)0x08016B2C }, { 0x6C6, 0, (void*)0x08016B84 }, - { 0x6C7, 0, (void*)0x08016BC8 }, { 0x6C8, 0, (void*)0x08016BE0 }, { 0x6C9, 0, (void*)0x08016C34 }, - { 0x6CA, 0, (void*)0x08016C94 }, { 0x6CB, 0, (void*)0x08016CD0 }, { 0x6CC, 0, (void*)0x08016D24 }, - { 0x6CD, 0, (void*)0x08016D64 }, { 0x6CE, 0, (void*)0x08016DC8 }, { 0x6CF, 0, (void*)0x08016E08 }, - { 0x6D0, 0, (void*)0x08016E6C }, { 0x6D1, 0, (void*)0x08016EAC }, { 0x6D2, 0, (void*)0x08016F14 }, - { 0x6D3, 0, (void*)0x08016F50 }, { 0x6D4, 0, (void*)0x08016FD0 }, { 0x6D5, 0, (void*)0x08017008 }, - { 0x6D6, 0, (void*)0x08017084 }, { 0x6D7, 0, (void*)0x080170C0 }, { 0x6D8, 0, (void*)0x08017110 }, - { 0x6D9, 0, (void*)0x0801714C }, { 0x6DA, 0, (void*)0x080171A4 }, { 0x6DB, 0, (void*)0x080171E0 }, - { 0x6DC, 0, (void*)0x08017218 }, { 0x6DD, 0, (void*)0x08017264 }, { 0x6DE, 0, (void*)0x080172E0 }, - { 0x708, 0, (void*)0x08017330 }, { 0x709, 0, (void*)0x080173C4 }, { 0x70A, 0, (void*)0x0801741C }, - { 0x70B, 0, (void*)0x080174B4 }, { 0x70C, 0, (void*)0x0801753C }, { 0x70D, 0, (void*)0x08017564 }, - { 0x70E, 0, (void*)0x0801758C }, { 0x70F, 0, (void*)0x080175FC }, { 0x710, 0, (void*)0x08017650 }, - { 0x711, 0, (void*)0x08017748 }, { 0x712, 0, (void*)0x0801775C }, { 0x713, 0, (void*)0x080177B0 }, - { 0x714, 0, (void*)0x080177D8 }, { 0x715, 0, (void*)0x0801781C }, { 0x716, 0, (void*)0x0801787C }, - { 0x717, 0, (void*)0x08017A6C }, { 0x718, 0, (void*)0x08017AB8 }, { 0x719, 0, (void*)0x08017AE8 }, - { 0x71A, 0, (void*)0x08017B48 }, { 0x71B, 0, (void*)0x08017BA0 }, { 0x721, 0, (void*)0x08017C00 }, - { 0x722, 0, (void*)0x08017C44 }, { 0x723, 0, (void*)0x08017C84 }, { 0x724, 0, (void*)0x08017CC4 }, - { 0x725, 0, (void*)0x08017D04 }, { 0x726, 0, (void*)0x08017D90 }, { 0x727, 0, (void*)0x08017DE4 }, - { 0x728, 0, (void*)0x08017DF0 }, { 0x729, 0, (void*)0x08017E50 }, { 0x72A, 0, (void*)0x08017E9C }, - { 0x72B, 0, (void*)0x08017F08 }, { 0x72C, 0, (void*)0x08017F5C }, { 0x72D, 0, (void*)0x08017F8C }, - { 0x72E, 0, (void*)0x08017FC8 }, { 0x72F, 0, (void*)0x0801800C }, { 0x730, 0, (void*)0x08018064 }, - { 0x731, 0, (void*)0x080180A0 }, { 0x732, 0, (void*)0x080180E8 }, { 0x733, 0, (void*)0x08018104 }, - { 0x734, 0, (void*)0x08018188 }, { 0x735, 0, (void*)0x08018240 }, { 0x736, 0, (void*)0x080182A8 }, - { 0x737, 0, (void*)0x080182E4 }, { 0x738, 0, (void*)0x080184D0 }, { 0x73A, 0, (void*)0x08018510 }, - { 0x73B, 0, (void*)0x08018594 }, { 0x73C, 0, (void*)0x08018618 }, { 0x73D, 0, (void*)0x080186B0 }, - { 0x73E, 0, (void*)0x0801876C }, { 0x73F, 0, (void*)0x08018818 }, { 0x740, 0, (void*)0x080188CC }, - { 0x741, 0, (void*)0x08018908 }, { 0x742, 0, (void*)0x08018938 }, { 0x743, 0, (void*)0x080189A0 }, - { 0x744, 0, (void*)0x08018A00 }, { 0x745, 0, (void*)0x08018A90 }, { 0x746, 0, (void*)0x08018B4C }, - { 0x747, 0, (void*)0x08018C18 }, { 0x748, 0, (void*)0x08018C8C }, { 0x749, 0, (void*)0x08018CE0 }, - { 0x74A, 0, (void*)0x08018D78 }, { 0x74B, 0, (void*)0x08018DD0 }, { 0x74C, 0, (void*)0x08018E38 }, - { 0x74D, 0, (void*)0x08018E78 }, { 0x74E, 0, (void*)0x08018EC0 }, { 0x74F, 0, (void*)0x08018F38 }, - { 0x750, 0, (void*)0x08018FF4 }, { 0x751, 0, (void*)0x08019014 }, { 0x752, 0, (void*)0x0801910C }, - { 0x753, 0, (void*)0x08019160 }, { 0x754, 0, (void*)0x080191A4 }, { 0x755, 0, (void*)0x080191FC }, - { 0x756, 0, (void*)0x08019254 }, { 0x757, 0, (void*)0x0801927C }, { 0x758, 0, (void*)0x080192E8 }, - { 0x759, 0, (void*)0x08019354 }, { 0x75A, 0, (void*)0x0801939C }, { 0x76C, 0, (void*)0x0801941C }, - { 0x76D, 0, (void*)0x08019468 }, { 0x76E, 0, (void*)0x080194BC }, { 0x76F, 0, (void*)0x080194F8 }, - { 0x770, 0, (void*)0x08019530 }, { 0x771, 0, (void*)0x0801956C }, { 0x772, 0, (void*)0x080195A4 }, - { 0x773, 0, (void*)0x080195DC }, { 0x774, 0, (void*)0x08019620 }, { 0x775, 0, (void*)0x08019654 }, - { 0x776, 0, (void*)0x08019688 }, { 0x777, 0, (void*)0x080196A4 }, { 0x778, 0, (void*)0x080196F0 }, - { 0x779, 0, (void*)0x080197A4 }, { 0x77A, 0, (void*)0x080197C0 }, { 0x77B, 0, (void*)0x080197E4 }, - { 0x77C, 0, (void*)0x0801982C }, { 0x77D, 0, (void*)0x08019854 }, { 0x7D0, 0, (void*)0x08019878 }, - { 0x7D1, 0, (void*)0x080198BC }, { 0x7D2, 0, (void*)0x080199A8 }, { 0x7D3, 0, (void*)0x080199BC }, - { 0x7D4, 0, (void*)0x080199E4 }, { 0x7D5, 0, (void*)0x08019AD8 }, { 0x7D6, 0, (void*)0x08019B10 }, - { 0x7D7, 0, (void*)0x08019B28 }, { 0x7D8, 0, (void*)0x08019BA4 }, { 0x7D9, 0, (void*)0x08019BC8 }, - { 0x7DC, 0, (void*)0x08019C20 }, { 0x7DD, 0, (void*)0x08019C40 }, { 0x7DE, 0, (void*)0x08019C60 }, - { 0x800, 0, (void*)0x08019C80 }, { 0x801, 0, (void*)0x08019D44 }, { 0x802, 0, (void*)0x08019DD0 }, - { 0x803, 0, (void*)0x08019E24 }, { 0x804, 0, (void*)0x08019E44 }, { 0x806, 0, (void*)0x08019F84 }, - { 0x807, 0, (void*)0x0801A0F0 }, { 0x80B, 0, (void*)0x0801A0FC }, { 0x80C, 0, (void*)0x0801A144 }, - { 0x80D, 0, (void*)0x0801A1AC }, { 0x80E, 0, (void*)0x0801A218 }, { 0x80F, 0, (void*)0x0801A288 }, - { 0x810, 0, (void*)0x0801A320 }, { 0x811, 0, (void*)0x0801A348 }, { 0x820, 0, (void*)0x0801A378 }, - { 0x821, 0, (void*)0x0801A3B4 }, { 0x822, 0, (void*)0x0801A408 }, { 0x823, 0, (void*)0x0801A484 }, - { 0x824, 0, (void*)0x0801A4D4 }, { 0x825, 0, (void*)0x0801A538 }, { 0x826, 0, (void*)0x0801A5A8 }, - { 0x827, 0, (void*)0x0801A614 }, { 0x828, 0, (void*)0x0801A654 }, { 0x829, 0, (void*)0x0801A680 }, - { 0x82A, 0, (void*)0x0801A6EC }, { 0x82B, 0, (void*)0x0801A740 }, { 0x82C, 0, (void*)0x0801A79C }, - { 0x82D, 0, (void*)0x0801A808 }, { 0x82E, 0, (void*)0x0801A868 }, { 0x82F, 0, (void*)0x0801A894 }, - { 0x830, 0, (void*)0x0801A918 }, { 0x831, 0, (void*)0x0801A968 }, { 0x832, 0, (void*)0x0801A9DC }, - { 0x833, 0, (void*)0x0801AA5C }, { 0x834, 0, (void*)0x0801AA80 }, { 0x835, 0, (void*)0x0801AAD0 }, - { 0x836, 0, (void*)0x0801AB60 }, { 0x838, 0, (void*)0x0801AC28 }, { 0x839, 0, (void*)0x0801AC7C }, - { 0x83A, 0, (void*)0x0801AD18 }, { 0x83B, 0, (void*)0x0801AD48 }, { 0x83C, 0, (void*)0x0801ADC4 }, - { 0x83D, 0, (void*)0x0801AE2C }, { 0x83E, 0, (void*)0x0801AE84 }, { 0x83F, 0, (void*)0x0801AEC4 }, - { 0x840, 0, (void*)0x0801AF0C }, { 0x841, 0, (void*)0x0801AF48 }, { 0x842, 0, (void*)0x0801AFA4 }, - { 0x843, 0, (void*)0x0801AFE4 }, { 0x844, 0, (void*)0x0801B054 }, { 0x845, 0, (void*)0x0801B090 }, - { 0x846, 0, (void*)0x0801B0CC }, { 0x847, 0, (void*)0x0801B114 }, { 0x848, 0, (void*)0x0801B168 }, - { 0x849, 0, (void*)0x0801B190 }, { 0x84A, 0, (void*)0x0801B210 }, { 0x84B, 0, (void*)0x0801B278 }, - { 0x84C, 0, (void*)0x0801B2BC }, { 0x84D, 0, (void*)0x0801B310 }, { 0x84E, 0, (void*)0x0801B380 }, - { 0x84F, 0, (void*)0x0801B3A4 }, { 0x850, 0, (void*)0x0801B3CC }, { 0x851, 0, (void*)0x0801B47C }, - { 0x852, 0, (void*)0x0801B488 }, { 0x853, 0, (void*)0x0801B4B4 }, { 0x854, 0, (void*)0x0801B5C4 }, - { 0x855, 0, (void*)0x0801B608 }, { 0x856, 0, (void*)0x0801B678 }, { 0x857, 0, (void*)0x0801B6D8 }, - { 0x858, 0, (void*)0x0801B718 }, { 0x859, 0, (void*)0x0801B78C }, { 0x85A, 0, (void*)0x0801B810 }, - { 0x85B, 0, (void*)0x0801B85C }, { 0x85C, 0, (void*)0x0801B8C4 }, { 0x85D, 0, (void*)0x0801B8F4 }, - { 0x85E, 0, (void*)0x0801B900 }, { 0x85F, 0, (void*)0x0801B92C }, { 0x860, 0, (void*)0x0801B968 }, - { 0x861, 0, (void*)0x0801B994 }, { 0x862, 0, (void*)0x0801B9E0 }, { 0x863, 0, (void*)0x0801BA6C }, - { 0x864, 0, (void*)0x0801BACC }, { 0x865, 0, (void*)0x0801BB18 }, { 0x866, 0, (void*)0x0801BB8C }, - { 0x867, 0, (void*)0x0801BBA4 }, { 0x868, 0, (void*)0x0801BC0C }, { 0x869, 0, (void*)0x0801BC88 }, - { 0x86A, 0, (void*)0x0801BCC0 }, { 0x86B, 0, (void*)0x0801BD30 }, { 0x86C, 0, (void*)0x0801BD90 }, - { 0x86D, 0, (void*)0x0801BDD4 }, { 0x86E, 0, (void*)0x0801BE60 }, { 0x86F, 0, (void*)0x0801BF1C }, - { 0x870, 0, (void*)0x0801BF40 }, { 0x871, 0, (void*)0x0801BF90 }, { 0x872, 0, (void*)0x0801BFB0 }, - { 0x873, 0, (void*)0x0801C004 }, { 0x874, 0, (void*)0x0801C038 }, { 0x875, 0, (void*)0x0801C0A0 }, - { 0x876, 0, (void*)0x0801C0F8 }, { 0x877, 0, (void*)0x0801C170 }, { 0x878, 0, (void*)0x0801C1E0 }, - { 0x879, 0, (void*)0x0801C23C }, { 0x87A, 0, (void*)0x0801C2A0 }, { 0x87B, 0, (void*)0x0801C2D4 }, - { 0x87C, 0, (void*)0x0801C314 }, { 0x87D, 0, (void*)0x0801C384 }, { 0x87E, 0, (void*)0x0801C3DC }, - { 0x87F, 0, (void*)0x0801C43C }, { 0x880, 0, (void*)0x0801C494 }, { 0x881, 0, (void*)0x0801C504 }, - { 0x882, 0, (void*)0x0801C580 }, { 0x883, 0, (void*)0x0801C5E8 }, { 0x884, 0, (void*)0x0801C694 }, - { 0x885, 0, (void*)0x0801C6DC }, { 0x886, 0, (void*)0x0801C73C }, { 0x887, 0, (void*)0x0801C798 }, - { 0x888, 0, (void*)0x0801C7EC }, { 0x889, 0, (void*)0x0801C824 }, { 0x88A, 0, (void*)0x0801C86C }, - { 0x88B, 0, (void*)0x0801C890 }, { 0x88C, 0, (void*)0x0801C8C4 }, { 0x88D, 0, (void*)0x0801C914 }, - { 0x88E, 0, (void*)0x0801C98C }, { 0x88F, 0, (void*)0x0801CA00 }, { 0x890, 0, (void*)0x0801CA40 }, - { 0x898, 0, (void*)0x0801CADC }, { 0x899, 0, (void*)0x0801CB1C }, { 0x89A, 0, (void*)0x0801CB60 }, - { 0x89B, 0, (void*)0x0801CC18 }, { 0x89C, 0, (void*)0x0801CC74 }, { 0x89D, 0, (void*)0x0801CCCC }, - { 0x89E, 0, (void*)0x0801CD40 }, { 0x89F, 0, (void*)0x0801CDA0 }, { 0x8A0, 0, (void*)0x0801CDE8 }, - { 0x8A1, 0, (void*)0x0801CE44 }, { 0x8A2, 0, (void*)0x0801CEB0 }, { 0x8A3, 0, (void*)0x0801CF0C }, - { 0x8A4, 0, (void*)0x0801CF38 }, { 0x8A5, 0, (void*)0x0801CFD0 }, { 0x8CA, 0, (void*)0x0801D010 }, - { 0x8CB, 0, (void*)0x0801D0E0 }, { 0x8CC, 0, (void*)0x0801D108 }, { 0x8CD, 0, (void*)0x0801D138 }, - { 0x8CE, 0, (void*)0x0801D170 }, { 0x8CF, 0, (void*)0x0801D1C0 }, { 0x8D0, 0, (void*)0x0801D200 }, - { 0x8D1, 0, (void*)0x0801D238 }, { 0x8D2, 0, (void*)0x0801D268 }, { 0x8D3, 0, (void*)0x0801D340 }, - { 0x8D4, 0, (void*)0x0801D3D4 }, { 0x8D5, 0, (void*)0x0801D444 }, { 0x8D6, 0, (void*)0x0801D488 }, - { 0x8D7, 0, (void*)0x0801D4D8 }, { 0x8D8, 0, (void*)0x0801D508 }, { 0x8D9, 0, (void*)0x0801D574 }, - { 0x8DA, 0, (void*)0x0801D5A0 }, { 0x8DB, 0, (void*)0x0801D5D0 }, { 0x8DC, 0, (void*)0x0801D600 }, - { 0x8DD, 0, (void*)0x0801D644 }, { 0x8DE, 0, (void*)0x0801D7C8 }, { 0x8DF, 0, (void*)0x0801D7FC }, - { 0x8E0, 0, (void*)0x0801D844 }, { 0x8E1, 0, (void*)0x0801D898 }, { 0x8E2, 0, (void*)0x0801D938 }, - { 0x8E3, 0, (void*)0x0801D9E0 }, { 0x8E4, 0, (void*)0x0801DA40 }, { 0x8E5, 0, (void*)0x0801DA9C }, - { 0x8E6, 0, (void*)0x0801DB20 }, { 0x8E7, 0, (void*)0x0801DB88 }, { 0x8E8, 0, (void*)0x0801DBB0 }, - { 0x8E9, 0, (void*)0x0801DBE4 }, { 0x8EA, 0, (void*)0x0801DC6C }, { 0x8EB, 0, (void*)0x0801DC84 }, - { 0x8EC, 0, (void*)0x0801DD18 }, { 0x910, 0, (void*)0x0801DD64 }, { 0x911, 0, (void*)0x0801DDC0 }, - { 0x912, 0, (void*)0x0801DE3C }, { 0x913, 0, (void*)0x0801DEAC }, { 0x914, 0, (void*)0x0801DF18 }, - { 0x915, 0, (void*)0x0801DF88 }, { 0x916, 0, (void*)0x0801DFF0 }, { 0x917, 0, (void*)0x0801E038 }, - { 0x918, 0, (void*)0x0801E164 }, { 0x919, 0, (void*)0x0801E1BC }, { 0x91A, 0, (void*)0x0801E204 }, - { 0x91B, 0, (void*)0x0801E330 }, { 0x91C, 0, (void*)0x0801E370 }, { 0x91E, 0, (void*)0x0801E3CC }, - { 0x92E, 0, (void*)0x0801E464 }, { 0x92F, 0, (void*)0x0801E4C0 }, { 0x930, 0, (void*)0x0801E534 }, - { 0x931, 0, (void*)0x0801E5AC }, { 0x932, 0, (void*)0x0801E5B8 }, { 0x933, 0, (void*)0x0801E608 }, - { 0x934, 0, (void*)0x0801E650 }, { 0x935, 0, (void*)0x0801E698 }, { 0x936, 0, (void*)0x0801E6D0 }, - { 0x937, 0, (void*)0x0801E738 }, { 0x938, 0, (void*)0x0801E768 }, { 0x960, 0, (void*)0x0801E774 }, - { 0x961, 0, (void*)0x0801E798 }, { 0x962, 0, (void*)0x0801E810 }, { 0x963, 0, (void*)0x0801E8AC }, - { 0x964, 0, (void*)0x0801E97C }, { 0x965, 0, (void*)0x0801E9C8 }, { 0x966, 0, (void*)0x0801EA1C }, - { 0x967, 0, (void*)0x0801EABC }, { 0x968, 0, (void*)0x0801EB08 }, { 0x969, 0, (void*)0x0801EBC8 }, - { 0x96A, 0, (void*)0x0801EC58 }, { 0x96B, 0, (void*)0x0801EC8C }, { 0x96C, 0, (void*)0x0801ECD4 }, - { 0x96D, 0, (void*)0x0801ED40 }, { 0x96E, 0, (void*)0x0801ED88 }, { 0x96F, 0, (void*)0x0801EE4C }, - { 0x970, 0, (void*)0x0801EF08 }, { 0x971, 0, (void*)0x0801EF98 }, { 0x972, 0, (void*)0x0801EFF4 }, - { 0x9C4, 0, (void*)0x0801F000 }, { 0x9C5, 0, (void*)0x0801F08C }, { 0x9C6, 0, (void*)0x0801F0B0 }, - { 0x9C7, 0, (void*)0x0801F104 }, { 0x9C8, 0, (void*)0x0801F110 }, { 0x9C9, 0, (void*)0x0801F160 }, - { 0x9CA, 0, (void*)0x0801F1D4 }, { 0x9CB, 0, (void*)0x0801F25C }, { 0x9CC, 0, (void*)0x0801F2A0 }, - { 0x9CD, 0, (void*)0x0801F2E8 }, { 0x9CE, 0, (void*)0x0801F338 }, { 0x9CF, 0, (void*)0x0801F37C }, - { 0x9D0, 0, (void*)0x0801F3CC }, { 0x9D1, 0, (void*)0x0801F424 }, { 0x9D2, 0, (void*)0x0801F450 }, - { 0x9D3, 0, (void*)0x0801F510 }, { 0x9D4, 0, (void*)0x0801F558 }, { 0x9D5, 0, (void*)0x0801F580 }, - { 0x9D6, 0, (void*)0x0801F5D0 }, { 0x9D7, 0, (void*)0x0801F61C }, { 0x9D8, 0, (void*)0x0801F65C }, - { 0x9D9, 0, (void*)0x0801F69C }, { 0x9DA, 0, (void*)0x0801F6EC }, { 0x9DB, 0, (void*)0x0801F764 }, - { 0x9DC, 0, (void*)0x0801F7B0 }, { 0x9DD, 0, (void*)0x0801F808 }, { 0x9DE, 0, (void*)0x0801F8AC }, - { 0x9DF, 0, (void*)0x0801F91C }, { 0x9E0, 0, (void*)0x0801F990 }, { 0x9E1, 0, (void*)0x0801F9CC }, - { 0x9E2, 0, (void*)0x0801FA2C }, { 0x9E3, 0, (void*)0x0801FA74 }, { 0x9E4, 0, (void*)0x0801FB24 }, - { 0x9E5, 0, (void*)0x0801FB90 }, { 0x9E6, 0, (void*)0x0801FBBC }, { 0x9E7, 0, (void*)0x0801FBE4 }, - { 0x9E8, 0, (void*)0x0801FC4C }, { 0x9E9, 0, (void*)0x0801FCA0 }, { 0x9EA, 0, (void*)0x0801FD80 }, - { 0x9EB, 0, (void*)0x0801FDE8 }, { 0x9EC, 0, (void*)0x0801FE70 }, { 0x9ED, 0, (void*)0x0801FEAC }, - { 0x9EE, 0, (void*)0x0801FF40 }, { 0x9EF, 0, (void*)0x0801FF8C }, { 0xA28, 0, (void*)0x0801FFC4 }, - { 0xA29, 0, (void*)0x0801FFF4 }, { 0xA2A, 0, (void*)0x08020014 }, { 0xA2B, 0, (void*)0x08020048 }, - { 0xA2C, 0, (void*)0x0802012C }, { 0xA2D, 0, (void*)0x08020190 }, { 0xA2E, 0, (void*)0x080201EC }, - { 0xA2F, 0, (void*)0x08020278 }, { 0xA30, 0, (void*)0x080202E4 }, { 0xA31, 0, (void*)0x0802031C }, - { 0xA32, 0, (void*)0x08020360 }, { 0xA33, 0, (void*)0x080203A4 }, { 0xA34, 0, (void*)0x080203C8 }, - { 0xA35, 0, (void*)0x08020424 }, { 0xA36, 0, (void*)0x0802047C }, { 0xA37, 0, (void*)0x080204F0 }, - { 0xA38, 0, (void*)0x08020534 }, { 0xA39, 0, (void*)0x08020570 }, { 0xA3A, 0, (void*)0x080205E4 }, - { 0xBB8, 0, (void*)0x08020668 }, { 0xBB9, 0, (void*)0x080206A4 }, { 0xBBA, 0, (void*)0x080206EC }, - { 0xBBB, 0, (void*)0x08020710 }, { 0xBBC, 0, (void*)0x08020764 }, { 0xBBD, 0, (void*)0x080207A4 }, - { 0xBBE, 0, (void*)0x080207E8 }, { 0xBBF, 0, (void*)0x08020814 }, { 0xBC0, 0, (void*)0x08020858 }, - { 0xBC1, 0, (void*)0x080208B0 }, { 0xBC2, 0, (void*)0x08020910 }, { 0xBC3, 0, (void*)0x08020960 }, - { 0xBC4, 0, (void*)0x080209C4 }, { 0xBC5, 0, (void*)0x080209F0 }, { 0xBC6, 0, (void*)0x08020A50 }, - { 0xBC7, 0, (void*)0x08020A8C }, { 0xBC8, 0, (void*)0x08020B00 }, { 0xBC9, 0, (void*)0x08020B3C }, - { 0xBCA, 0, (void*)0x08020BB8 }, { 0xBCB, 0, (void*)0x08020BF4 }, { 0xBCC, 0, (void*)0x08020C4C }, - { 0xBCD, 0, (void*)0x08020C88 }, { 0xBCE, 0, (void*)0x08020CF0 }, { 0xBCF, 0, (void*)0x08020D2C }, - { 0xBD0, 0, (void*)0x08020D80 }, { 0xBD1, 0, (void*)0x08020DC0 }, { 0xBD2, 0, (void*)0x08020DFC }, - { 0xBD3, 0, (void*)0x08020E58 }, { 0xBD4, 0, (void*)0x08020E88 }, { 0xBD5, 0, (void*)0x08020EE0 }, - { 0xBD6, 0, (void*)0x08020F18 }, { 0xBD7, 0, (void*)0x08020F44 }, { 0xBEA, 0, (void*)0x08020F60 }, - { 0xBEB, 0, (void*)0x08021158 }, { 0xBEC, 0, (void*)0x080211C0 }, { 0xBED, 0, (void*)0x080211EC }, - { 0xBEE, 0, (void*)0x08021350 }, { 0xBEF, 0, (void*)0x08021380 }, { 0xBF0, 0, (void*)0x080213F8 }, - { 0xBF1, 0, (void*)0x08021480 }, { 0xBF2, 0, (void*)0x08021558 }, { 0xBF3, 0, (void*)0x08021588 }, - { 0xBF4, 0, (void*)0x080215E0 }, { 0xBF5, 0, (void*)0x080216A0 }, { 0xBF6, 0, (void*)0x080217CC }, - { 0xBF7, 0, (void*)0x08021858 }, { 0xBF8, 0, (void*)0x080218CC }, { 0xBF9, 0, (void*)0x08021974 }, - { 0xBFA, 0, (void*)0x080219F8 }, { 0xBFB, 0, (void*)0x08021A68 }, { 0xBFC, 0, (void*)0x08021AF8 }, - { 0xBFD, 0, (void*)0x08021B9C }, { 0xBFE, 0, (void*)0x08021BE0 }, { 0xBFF, 0, (void*)0x08021C54 }, - { 0xC00, 0, (void*)0x08021C80 }, { 0xC01, 0, (void*)0x08021CC8 }, { 0xC02, 0, (void*)0x08021F20 }, - { 0xC03, 0, (void*)0x08021F50 }, { 0xC04, 0, (void*)0x08022024 }, { 0xC1D, 0, (void*)0x08022090 }, - { 0xC1E, 0, (void*)0x080220B8 }, { 0xC1F, 0, (void*)0x080220D0 }, { 0xC20, 0, (void*)0x08022104 }, - { 0xC21, 0, (void*)0x08022198 }, { 0xC22, 0, (void*)0x080221B8 }, { 0xC23, 0, (void*)0x080221DC }, - { 0xC24, 0, (void*)0x08022248 }, { 0xC25, 0, (void*)0x08022288 }, { 0xC26, 0, (void*)0x08022308 }, - { 0xC27, 0, (void*)0x0802233C }, { 0xC28, 0, (void*)0x0802239C }, { 0xC29, 0, (void*)0x080223E4 }, - { 0xC2A, 0, (void*)0x08022408 }, { 0xC2B, 0, (void*)0x08022470 }, { 0xC2C, 0, (void*)0x080224C4 }, - { 0xC2D, 0, (void*)0x0802255C }, { 0xC2E, 0, (void*)0x08022584 }, { 0xC2F, 0, (void*)0x080225AC }, - { 0xC30, 0, (void*)0x08022640 }, { 0xC31, 0, (void*)0x08022670 }, { 0xC32, 0, (void*)0x0802268C }, - { 0xC33, 0, (void*)0x080226A0 }, { 0xC34, 0, (void*)0x080226E0 }, { 0xC35, 0, (void*)0x08022738 }, - { 0xC36, 0, (void*)0x08022760 }, { 0xC37, 0, (void*)0x08022780 }, { 0xC38, 0, (void*)0x080227B8 }, - { 0xC39, 0, (void*)0x080227F0 }, { 0xC3A, 0, (void*)0x080228DC }, { 0xC3B, 0, (void*)0x08022954 }, - { 0xC3C, 0, (void*)0x08022AD4 }, { 0xC3D, 0, (void*)0x08022B48 }, { 0xC3E, 0, (void*)0x08022C14 }, - { 0xC3F, 0, (void*)0x08022C48 }, { 0xC40, 0, (void*)0x08022C78 }, { 0xC41, 0, (void*)0x08022CB0 }, - { 0xC42, 0, (void*)0x08022CFC }, { 0xC43, 0, (void*)0x08022D64 }, { 0xC44, 0, (void*)0x08022D84 }, - { 0xC45, 0, (void*)0x08022DEC }, { 0xC46, 0, (void*)0x08022EBC }, { 0xC47, 0, (void*)0x08022F9C }, - { 0xC48, 0, (void*)0x08023004 }, { 0xC49, 0, (void*)0x08023024 }, { 0xC4A, 0, (void*)0x080230B0 }, - { 0xC4B, 0, (void*)0x080230E0 }, { 0xC4C, 0, (void*)0x080231E4 }, { 0xC4D, 0, (void*)0x0802329C }, - { 0xC4E, 0, (void*)0x080232FC }, { 0xC4F, 0, (void*)0x08023360 }, { 0xC50, 0, (void*)0x080233BC }, - { 0xC51, 0, (void*)0x080233F4 }, { 0xC52, 0, (void*)0x0802352C }, { 0xC53, 0, (void*)0x08023550 }, - { 0xC54, 0, (void*)0x08023640 }, { 0xC55, 0, (void*)0x08023668 }, { 0xC56, 0, (void*)0x080236A4 }, - { 0xC57, 0, (void*)0x080236F4 }, { 0xC58, 0, (void*)0x08023788 }, { 0xC80, 0, (void*)0x080237C4 }, - { 0xC81, 0, (void*)0x08023824 }, { 0xC82, 0, (void*)0x080238F0 }, { 0xC83, 0, (void*)0x08023920 }, - { 0xC84, 0, (void*)0x080239E4 }, { 0xC85, 0, (void*)0x08023B24 }, { 0xC86, 0, (void*)0x08023B58 }, - { 0xC87, 0, (void*)0x08023C3C }, { 0xC88, 0, (void*)0x08023CF0 }, { 0xC89, 0, (void*)0x08023D44 }, - { 0xC8A, 0, (void*)0x08023D80 }, { 0xC8B, 0, (void*)0x08023DB0 }, { 0xC8C, 0, (void*)0x08023E0C }, - { 0xC8D, 0, (void*)0x08023E60 }, { 0xC8E, 0, (void*)0x08023E90 }, { 0xC8F, 0, (void*)0x08023F40 }, - { 0xC90, 0, (void*)0x08023FA0 }, { 0xC91, 0, (void*)0x0802400C }, { 0xC92, 0, (void*)0x08024058 }, - { 0xC93, 0, (void*)0x080240D0 }, { 0xC94, 0, (void*)0x0802410C }, { 0xCE4, 0, (void*)0x08024164 }, - { 0xCE5, 0, (void*)0x080241D4 }, { 0xCE6, 0, (void*)0x08024254 }, { 0xCE7, 0, (void*)0x08024304 }, - { 0xCE8, 0, (void*)0x08024330 }, { 0xCE9, 0, (void*)0x08024360 }, { 0xCEA, 0, (void*)0x0802444C }, - { 0xCEB, 0, (void*)0x08024470 }, { 0xCEC, 0, (void*)0x080244E8 }, { 0xCED, 0, (void*)0x08024548 }, - { 0xCEE, 0, (void*)0x08024634 }, { 0xCEF, 0, (void*)0x08024718 }, { 0xCF0, 0, (void*)0x0802476C }, - { 0xCF1, 0, (void*)0x080247F8 }, { 0xCF2, 0, (void*)0x0802483C }, { 0xCF3, 0, (void*)0x08024880 }, - { 0xCF4, 0, (void*)0x08024918 }, { 0xCF5, 0, (void*)0x08024994 }, { 0xCF6, 0, (void*)0x08024B58 }, - { 0xCF7, 0, (void*)0x08024BD8 }, { 0xCF8, 0, (void*)0x08024C84 }, { 0xCF9, 0, (void*)0x08024D10 }, - { 0xCFA, 0, (void*)0x08024D44 }, { 0xCFB, 0, (void*)0x08024D8C }, { 0xCFC, 0, (void*)0x08024DB8 }, - { 0xCFD, 0, (void*)0x08024DFC }, { 0xCFE, 0, (void*)0x08024E6C }, { 0xCFF, 0, (void*)0x08024EA4 }, - { 0xD00, 0, (void*)0x08024ED4 }, { 0xD01, 0, (void*)0x08024F4C }, { 0xD02, 0, (void*)0x08024F8C }, - { 0xD03, 0, (void*)0x08024FDC }, { 0xD04, 0, (void*)0x08025040 }, { 0xD05, 0, (void*)0x080250D8 }, - { 0xD06, 0, (void*)0x08025100 }, { 0xD07, 0, (void*)0x08025134 }, { 0xD08, 0, (void*)0x0802516C }, - { 0xD09, 0, (void*)0x080251B4 }, { 0xD0A, 0, (void*)0x080251E0 }, { 0xD0B, 0, (void*)0x08025260 }, - { 0xD0C, 0, (void*)0x080252AC }, { 0xD0D, 0, (void*)0x080252E4 }, { 0xD0E, 0, (void*)0x08025330 }, - { 0xD0F, 0, (void*)0x08025358 }, { 0xD10, 0, (void*)0x08025394 }, { 0xD11, 0, (void*)0x080253C8 }, - { 0xD12, 0, (void*)0x08025434 }, { 0xD13, 0, (void*)0x0802547C }, { 0xD14, 0, (void*)0x080254C0 }, - { 0xD15, 0, (void*)0x0802550C }, { 0xD16, 0, (void*)0x08025550 }, { 0xD17, 0, (void*)0x080255A4 }, - { 0xD18, 0, (void*)0x080255DC }, { 0xD19, 0, (void*)0x080255FC }, { 0xD1A, 0, (void*)0x0802563C }, - { 0xD1B, 0, (void*)0x080256C8 }, { 0xD1C, 0, (void*)0x08025708 }, { 0xD1D, 0, (void*)0x0802575C }, - { 0xD1E, 0, (void*)0x080257B8 }, { 0xD1F, 0, (void*)0x08025814 }, { 0xD20, 0, (void*)0x08025874 }, - { 0xD21, 0, (void*)0x080258EC }, { 0xD48, 0, (void*)0x08025960 }, { 0xD49, 0, (void*)0x0802597C }, - { 0xD4A, 0, (void*)0x080259B8 }, { 0xD4B, 0, (void*)0x080259F8 }, { 0xD4C, 0, (void*)0x08025A9C }, - { 0xD4D, 0, (void*)0x08025AF4 }, { 0xD4E, 0, (void*)0x08025B4C }, { 0xD4F, 0, (void*)0x08025B80 }, - { 0xD5E, 0, (void*)0x08025BBC }, { 0xD5F, 0, (void*)0x08025BD8 }, { 0xD60, 0, (void*)0x08025BFC }, - { 0xD61, 0, (void*)0x08025C3C }, { 0xD62, 0, (void*)0x08025C7C }, { 0xD63, 0, (void*)0x08025CE0 }, - { 0xD64, 0, (void*)0x08025D64 }, { 0xD65, 0, (void*)0x08025D90 }, { 0xD66, 0, (void*)0x08025DC0 }, - { 0xD67, 0, (void*)0x08025E34 }, { 0xD68, 0, (void*)0x08025E74 }, { 0xD69, 0, (void*)0x08025EB0 }, - { 0xD6A, 0, (void*)0x08025EE4 }, { 0xD6B, 0, (void*)0x08025F14 }, { 0xD6C, 0, (void*)0x08025F4C }, - { 0xD6D, 0, (void*)0x08025F9C }, { 0xD6E, 0, (void*)0x08025FEC }, { 0xD6F, 0, (void*)0x08026024 }, - { 0xD70, 0, (void*)0x08026064 }, { 0xD71, 0, (void*)0x080260D4 }, { 0xD72, 0, (void*)0x0802613C }, - { 0xD73, 0, (void*)0x08026190 }, { 0xD74, 0, (void*)0x080261E4 }, { 0xD75, 0, (void*)0x0802621C }, - { 0xD76, 0, (void*)0x0802626C }, { 0xD77, 0, (void*)0x08026354 }, { 0xD78, 0, (void*)0x0802637C }, - { 0xD79, 0, (void*)0x080263C8 }, { 0xD7A, 0, (void*)0x08026444 }, { 0xD7B, 0, (void*)0x08026490 }, - { 0xD7C, 0, (void*)0x080264EC }, { 0xD7D, 0, (void*)0x08026548 }, { 0xD7E, 0, (void*)0x08026598 }, - { 0xD7F, 0, (void*)0x080265C4 }, { 0xD80, 0, (void*)0x080265F8 }, { 0xD81, 0, (void*)0x08026628 }, - { 0xD82, 0, (void*)0x08026658 }, { 0xD83, 0, (void*)0x08026688 }, { 0xD84, 0, (void*)0x080266D0 }, - { 0xD85, 0, (void*)0x08026728 }, { 0xD86, 0, (void*)0x08026770 }, { 0xD87, 0, (void*)0x080267B4 }, - { 0xD88, 0, (void*)0x08026850 }, { 0xD89, 0, (void*)0x080268B0 }, { 0xD8A, 0, (void*)0x08026998 }, - { 0xD8B, 0, (void*)0x08026A5C }, { 0xDAC, 0, (void*)0x08026AA0 }, { 0xDAD, 0, (void*)0x08026AC8 }, - { 0xDAE, 0, (void*)0x08026B04 }, { 0xDAF, 0, (void*)0x08026B9C }, { 0xDB0, 0, (void*)0x08026BDC }, - { 0xDB1, 0, (void*)0x08026C6C }, { 0xDB2, 0, (void*)0x08026CD8 }, { 0xDB3, 0, (void*)0x08026D4C }, - { 0xDB4, 0, (void*)0x08026DB4 }, { 0xDB5, 0, (void*)0x08026E34 }, { 0xDB6, 0, (void*)0x08026EA4 }, - { 0xDB7, 0, (void*)0x08026EBC }, { 0xDB8, 0, (void*)0x08026EE8 }, { 0xDB9, 0, (void*)0x08026F28 }, - { 0xDBA, 0, (void*)0x08026F70 }, { 0xDBB, 0, (void*)0x08026FA0 }, { 0xDBC, 0, (void*)0x0802701C }, - { 0xDBD, 0, (void*)0x08027070 }, { 0xDBE, 0, (void*)0x08027088 }, { 0xDBF, 0, (void*)0x080270BC }, - { 0xDC0, 0, (void*)0x080270E0 }, { 0xDC1, 0, (void*)0x0802713C }, { 0xDC2, 0, (void*)0x08027194 }, - { 0xDC3, 0, (void*)0x08027220 }, { 0xDC4, 0, (void*)0x0802727C }, { 0xDC5, 0, (void*)0x08027300 }, - { 0xDC6, 0, (void*)0x08027334 }, { 0xDC7, 0, (void*)0x08027370 }, { 0xDC8, 0, (void*)0x08027394 }, - { 0xDC9, 0, (void*)0x080273A8 }, { 0xDCA, 0, (void*)0x080273D0 }, { 0xDCB, 0, (void*)0x08027414 }, - { 0xDCC, 0, (void*)0x0802744C }, { 0xDCD, 0, (void*)0x080274BC }, { 0xDCE, 0, (void*)0x08027500 }, - { 0xDCF, 0, (void*)0x080275D4 }, { 0xDD0, 0, (void*)0x0802762C }, { 0xDD1, 0, (void*)0x08027668 }, - { 0xDD2, 0, (void*)0x08027684 }, { 0xDD3, 0, (void*)0x080276D8 }, { 0xDD4, 0, (void*)0x08027710 }, - { 0xDD5, 0, (void*)0x0802773C }, { 0xDD6, 0, (void*)0x08027760 }, { 0xDD7, 0, (void*)0x08027798 }, - { 0xDD8, 0, (void*)0x080277C0 }, { 0xDD9, 0, (void*)0x08027824 }, { 0xDDA, 0, (void*)0x080278AC }, - { 0xDDB, 0, (void*)0x08027934 }, { 0xDDC, 0, (void*)0x08027984 }, { 0xDDD, 0, (void*)0x080279E8 }, - { 0xDDE, 0, (void*)0x08027A70 }, { 0xDDF, 0, (void*)0x08027AE8 }, { 0xDE0, 0, (void*)0x08027B28 }, - { 0xDE1, 0, (void*)0x08027B84 }, { 0xDE2, 0, (void*)0x08027BF4 }, { 0xDE3, 0, (void*)0x08027C40 }, - { 0xDE4, 0, (void*)0x08027C84 }, { 0xDE5, 0, (void*)0x08027CC8 }, { 0xDE6, 0, (void*)0x08027D3C }, - { 0xDE7, 0, (void*)0x08027D8C }, { 0xDE8, 0, (void*)0x08027DBC }, { 0xDE9, 0, (void*)0x08027DEC }, - { 0xDEA, 0, (void*)0x08027E78 }, { 0xDEB, 0, (void*)0x08027EBC }, { 0xDEC, 0, (void*)0x08027EE4 }, - { 0xDED, 0, (void*)0x08027F4C }, { 0xDEE, 0, (void*)0x08027F9C }, { 0xDEF, 0, (void*)0x0802800C }, - { 0xDF0, 0, (void*)0x08028058 }, { 0xDF1, 0, (void*)0x080280A4 }, { 0xDF2, 0, (void*)0x080280DC }, - { 0xDF3, 0, (void*)0x08028134 }, { 0xDF4, 0, (void*)0x080281B0 }, { 0xDF5, 0, (void*)0x080281E8 }, - { 0xDF6, 0, (void*)0x08028234 }, { 0xDF7, 0, (void*)0x08028264 }, { 0xDF8, 0, (void*)0x080282C0 }, - { 0xDF9, 0, (void*)0x080282F8 }, { 0xDFA, 0, (void*)0x08028378 }, { 0xDFB, 0, (void*)0x080283C4 }, - { 0xDFC, 0, (void*)0x080283FC }, { 0xDFD, 0, (void*)0x08028444 }, { 0xDFE, 0, (void*)0x08028478 }, - { 0xDFF, 0, (void*)0x080284BC }, { 0xE02, 0, (void*)0x080284F4 }, { 0xE03, 0, (void*)0x08028540 }, - { 0xE04, 0, (void*)0x08028588 }, { 0xE05, 0, (void*)0x080285C8 }, { 0xE06, 0, (void*)0x08028604 }, - { 0xE07, 0, (void*)0x08028620 }, { 0xE10, 0, (void*)0x08028670 }, { 0xE11, 0, (void*)0x080286AC }, - { 0xE12, 0, (void*)0x08028744 }, { 0xE13, 0, (void*)0x080287C4 }, { 0xE14, 0, (void*)0x0802885C }, - { 0xE15, 0, (void*)0x08028940 }, { 0xE16, 0, (void*)0x080289D4 }, { 0xE17, 0, (void*)0x08028A20 }, - { 0xE18, 0, (void*)0x08028A58 }, { 0xE19, 0, (void*)0x08028AA8 }, { 0xE1A, 0, (void*)0x08028B5C }, - { 0xE1B, 0, (void*)0x08028B8C }, { 0xE1C, 0, (void*)0x08028BF0 }, { 0xE1D, 0, (void*)0x08028C38 }, - { 0xE1E, 0, (void*)0x08028C98 }, { 0xE1F, 0, (void*)0x08028CBC }, { 0xE20, 0, (void*)0x08028D10 }, - { 0xE21, 0, (void*)0x08028D28 }, { 0xE22, 0, (void*)0x08028D68 }, { 0xE23, 0, (void*)0x08028DC8 }, - { 0xE24, 0, (void*)0x08028E24 }, { 0xE25, 0, (void*)0x08028E44 }, { 0xE26, 0, (void*)0x08028E88 }, - { 0xE27, 0, (void*)0x08028ED0 }, { 0xE28, 0, (void*)0x08028EEC }, { 0xE29, 0, (void*)0x08028F40 }, - { 0xE2A, 0, (void*)0x08028F9C }, { 0xE2B, 0, (void*)0x08029010 }, { 0xE2C, 0, (void*)0x08029078 }, - { 0xE2D, 0, (void*)0x08029104 }, { 0xE2E, 0, (void*)0x08029174 }, { 0xE2F, 0, (void*)0x080291D4 }, - { 0xE30, 0, (void*)0x08029238 }, { 0xE31, 0, (void*)0x080292B8 }, { 0xE32, 0, (void*)0x0802933C }, - { 0xE42, 0, (void*)0x0802939C }, { 0xE43, 0, (void*)0x080293FC }, { 0xE44, 0, (void*)0x08029428 }, - { 0xE45, 0, (void*)0x080294A8 }, { 0xE46, 0, (void*)0x08029500 }, { 0xE47, 0, (void*)0x080295A0 }, - { 0xE48, 0, (void*)0x080295C4 }, { 0xE49, 0, (void*)0x08029634 }, { 0xE4A, 0, (void*)0x0802969C }, - { 0xE4B, 0, (void*)0x08029704 }, { 0xE4C, 0, (void*)0x08029774 }, { 0xE4D, 0, (void*)0x080297D4 }, - { 0xE4E, 0, (void*)0x08029860 }, { 0xE4F, 0, (void*)0x080298C8 }, { 0xE50, 0, (void*)0x08029948 }, - { 0xE51, 0, (void*)0x080299D0 }, { 0xE52, 0, (void*)0x08029A30 }, { 0xE74, 0, (void*)0x08029AC0 }, - { 0xE75, 0, (void*)0x08029B20 }, { 0xE76, 0, (void*)0x08029B74 }, { 0xE77, 0, (void*)0x08029BD4 }, - { 0xE78, 0, (void*)0x08029C48 }, { 0xE79, 0, (void*)0x08029C9C }, { 0xE7A, 0, (void*)0x08029CB0 }, - { 0xE7B, 0, (void*)0x08029CCC }, { 0xE7C, 0, (void*)0x08029D58 }, { 0xE7D, 0, (void*)0x08029DAC }, - { 0xE7E, 0, (void*)0x08029DC0 }, { 0xE7F, 0, (void*)0x08029E10 }, { 0xE80, 0, (void*)0x08029E74 }, - { 0xE81, 0, (void*)0x08029ED4 }, { 0xE82, 0, (void*)0x08029F2C }, { 0xE83, 0, (void*)0x08029F54 }, - { 0xE84, 0, (void*)0x08029FCC }, { 0xE85, 0, (void*)0x0802A03C }, { 0xE86, 0, (void*)0x0802A090 }, - { 0xE87, 0, (void*)0x0802A0D8 }, { 0xE88, 0, (void*)0x0802A128 }, { 0xE89, 0, (void*)0x0802A1BC }, - { 0xE8A, 0, (void*)0x0802A1F4 }, { 0xE8B, 0, (void*)0x0802A260 }, { 0xE8C, 0, (void*)0x0802A2A4 }, - { 0xE8D, 0, (void*)0x0802A2F4 }, { 0xE8E, 0, (void*)0x0802A334 }, { 0xE8F, 0, (void*)0x0802A37C }, - { 0xE90, 0, (void*)0x0802A3DC }, { 0xE91, 0, (void*)0x0802A448 }, { 0xE92, 0, (void*)0x0802A47C }, - { 0xE93, 0, (void*)0x0802A4A8 }, { 0xE94, 0, (void*)0x0802A550 }, { 0xE95, 0, (void*)0x0802A5B0 }, - { 0xE97, 0, (void*)0x0802A608 }, { 0xE98, 0, (void*)0x0802A69C }, { 0xE99, 0, (void*)0x0802A6F0 }, - { 0xFA0, 0, (void*)0x0802A760 }, { 0xFA1, 0, (void*)0x0802A79C }, { 0xFA2, 0, (void*)0x0802A7F4 }, - { 0xFA3, 0, (void*)0x0802A84C }, { 0xFA4, 0, (void*)0x0802A8F4 }, { 0xFA5, 0, (void*)0x0802AA24 }, - { 0xFA6, 0, (void*)0x0802AAA0 }, { 0xFA7, 0, (void*)0x0802AB04 }, { 0xFA8, 0, (void*)0x0802ABA0 }, - { 0xFA9, 0, (void*)0x0802AC08 }, { 0xFAA, 0, (void*)0x0802ACA4 }, { 0xFAB, 0, (void*)0x0802AD1C }, - { 0xFAC, 0, (void*)0x0802AD8C }, { 0xFAD, 0, (void*)0x0802ADF4 }, { 0xFAE, 0, (void*)0x0802AE90 }, - { 0xFAF, 0, (void*)0x0802AF00 }, { 0xFB0, 0, (void*)0x0802AF70 }, { 0xFB1, 0, (void*)0x0802B018 }, - { 0xFB2, 0, (void*)0x0802B0B8 }, { 0xFB3, 0, (void*)0x0802B110 }, { 0xFB4, 0, (void*)0x0802B190 }, - { 0xFB5, 0, (void*)0x0802B24C }, { 0xFB6, 0, (void*)0x0802B288 }, { 0xFB7, 0, (void*)0x0802B2E4 }, - { 0xFB8, 0, (void*)0x0802B314 }, { 0xFB9, 0, (void*)0x0802B39C }, { 0xFBA, 0, (void*)0x0802B40C }, - { 0xFBB, 0, (void*)0x0802B488 }, { 0xFBC, 0, (void*)0x0802B4EC }, { 0xFBD, 0, (void*)0x0802B598 }, - { 0xFBE, 0, (void*)0x0802B650 }, { 0xFBF, 0, (void*)0x0802B6F8 }, { 0x1004, 0, (void*)0x0802B750 }, - { 0x1005, 0, (void*)0x0802B778 }, { 0x1006, 0, (void*)0x0802B7A0 }, { 0x1007, 0, (void*)0x0802B7C8 }, - { 0x1008, 0, (void*)0x0802B7EC }, { 0x1009, 0, (void*)0x0802B84C }, { 0x100A, 0, (void*)0x0802B890 }, - { 0x100B, 0, (void*)0x0802B8D8 }, { 0x100C, 0, (void*)0x0802B908 }, { 0x100D, 0, (void*)0x0802B97C }, - { 0x100E, 0, (void*)0x0802BA00 }, { 0x100F, 0, (void*)0x0802BA54 }, { 0x1010, 0, (void*)0x0802BAC0 }, - { 0x1011, 0, (void*)0x0802BB28 }, { 0x1012, 0, (void*)0x0802BB94 }, { 0x1013, 0, (void*)0x0802BC18 }, - { 0x1014, 0, (void*)0x0802BC44 }, { 0x1015, 0, (void*)0x0802BC88 }, { 0x1016, 0, (void*)0x0802BCE0 }, - { 0x1017, 0, (void*)0x0802BD24 }, { 0x1018, 0, (void*)0x0802BD8C }, { 0x1019, 0, (void*)0x0802BE18 }, - { 0x101A, 0, (void*)0x0802BE80 }, { 0x101B, 0, (void*)0x0802BF84 }, { 0x101C, 0, (void*)0x0802C048 }, - { 0x101D, 0, (void*)0x0802C064 }, { 0x101E, 0, (void*)0x0802C15C }, { 0x101F, 0, (void*)0x0802C284 }, - { 0x1020, 0, (void*)0x0802C3BC }, { 0x1021, 0, (void*)0x0802C3D4 }, { 0x1022, 0, (void*)0x0802C438 }, - { 0x1023, 0, (void*)0x0802C470 }, { 0x1024, 0, (void*)0x0802C494 }, { 0x1025, 0, (void*)0x0802C4C4 }, - { 0x1026, 0, (void*)0x0802C4F8 }, { 0x1027, 0, (void*)0x0802C564 }, { 0x1028, 0, (void*)0x0802C5F8 }, - { 0x1029, 0, (void*)0x0802C67C }, { 0x102A, 0, (void*)0x0802C6DC }, { 0x102B, 0, (void*)0x0802C73C }, - { 0x102C, 0, (void*)0x0802C798 }, { 0x102D, 0, (void*)0x0802C824 }, { 0x102E, 0, (void*)0x0802C87C }, - { 0x102F, 0, (void*)0x0802C8B8 }, { 0x1030, 0, (void*)0x0802C928 }, { 0x1031, 0, (void*)0x0802CA60 }, - { 0x1032, 0, (void*)0x0802CAB4 }, { 0x1033, 0, (void*)0x0802CB00 }, { 0x1034, 0, (void*)0x0802CB3C }, - { 0x1035, 0, (void*)0x0802CB94 }, { 0x1036, 0, (void*)0x0802CBF0 }, { 0x1037, 0, (void*)0x0802CC28 }, - { 0x1038, 0, (void*)0x0802CC80 }, { 0x1039, 0, (void*)0x0802CCE0 }, { 0x103A, 0, (void*)0x0802CD30 }, - { 0x103B, 0, (void*)0x0802CD64 }, { 0x103C, 0, (void*)0x0802CDDC }, { 0x1068, 0, (void*)0x0802CE10 }, - { 0x1069, 0, (void*)0x0802CE64 }, { 0x106A, 0, (void*)0x0802CF30 }, { 0x106B, 0, (void*)0x0802CF90 }, - { 0x106C, 0, (void*)0x0802CFD4 }, { 0x106D, 0, (void*)0x0802D07C }, { 0x106E, 0, (void*)0x0802D0C0 }, - { 0x106F, 0, (void*)0x0802D110 }, { 0x1070, 0, (void*)0x0802D178 }, { 0x1071, 0, (void*)0x0802D1C4 }, - { 0x1072, 0, (void*)0x0802D234 }, { 0x1073, 0, (void*)0x0802D27C }, { 0x1074, 0, (void*)0x0802D2BC }, - { 0x1075, 0, (void*)0x0802D314 }, { 0x1076, 0, (void*)0x0802D354 }, { 0x1077, 0, (void*)0x0802D3AC }, - { 0x1078, 0, (void*)0x0802D3F0 }, { 0x1079, 0, (void*)0x0802D434 }, { 0x107A, 0, (void*)0x0802D4AC }, - { 0x107B, 0, (void*)0x0802D4EC }, { 0x107C, 0, (void*)0x0802D554 }, { 0x107D, 0, (void*)0x0802D5A8 }, - { 0x107E, 0, (void*)0x0802D5FC }, { 0x107F, 0, (void*)0x0802D69C }, { 0x1080, 0, (void*)0x0802D6E8 }, - { 0x1081, 0, (void*)0x0802D744 }, { 0x1082, 0, (void*)0x0802D7A4 }, { 0x1083, 0, (void*)0x0802D7EC }, - { 0x1084, 0, (void*)0x0802D82C }, { 0x1085, 0, (void*)0x0802D8B0 }, { 0x1086, 0, (void*)0x0802D8F0 }, - { 0x1087, 0, (void*)0x0802D954 }, { 0x1088, 0, (void*)0x0802D9DC }, { 0x1089, 0, (void*)0x0802DA24 }, - { 0x108A, 0, (void*)0x0802DA8C }, { 0x108B, 0, (void*)0x0802DACC }, { 0x108C, 0, (void*)0x0802DB30 }, - { 0x108D, 0, (void*)0x0802DBA0 }, { 0x108E, 0, (void*)0x0802DBF4 }, { 0x108F, 0, (void*)0x0802DC28 }, - { 0x1090, 0, (void*)0x0802DC94 }, { 0x1091, 0, (void*)0x0802DCFC }, { 0x1092, 0, (void*)0x0802DDC0 }, - { 0x1093, 0, (void*)0x0802DE18 }, { 0x1094, 0, (void*)0x0802DEA0 }, { 0x1095, 0, (void*)0x0802DF10 }, - { 0x1096, 0, (void*)0x0802DF78 }, { 0x1097, 0, (void*)0x0802DFE0 }, { 0x1098, 0, (void*)0x0802E024 }, - { 0x1099, 0, (void*)0x0802E088 }, { 0x109A, 0, (void*)0x0802E170 }, { 0x109B, 0, (void*)0x0802E1F8 }, - { 0x109C, 0, (void*)0x0802E240 }, { 0x109D, 0, (void*)0x0802E290 }, { 0x109E, 0, (void*)0x0802E2D8 }, - { 0x109F, 0, (void*)0x0802E308 }, { 0x10A0, 0, (void*)0x0802E364 }, { 0x10A1, 0, (void*)0x0802E3B8 }, - { 0x10A2, 0, (void*)0x0802E3DC }, { 0x10A3, 0, (void*)0x0802E480 }, { 0x10A4, 0, (void*)0x0802E4D4 }, - { 0x10A5, 0, (void*)0x0802E53C }, { 0x10A6, 0, (void*)0x0802E624 }, { 0x10A7, 0, (void*)0x0802E68C }, - { 0x10A8, 0, (void*)0x0802E738 }, { 0x10A9, 0, (void*)0x0802E78C }, { 0x10CE, 0, (void*)0x0802E830 }, - { 0x10CF, 0, (void*)0x0802E878 }, { 0x10D0, 0, (void*)0x0802E8CC }, { 0x10D1, 0, (void*)0x0802E90C }, - { 0x10D2, 0, (void*)0x0802E970 }, { 0x10D3, 0, (void*)0x0802E9A4 }, { 0x10D4, 0, (void*)0x0802E9D0 }, - { 0x10D6, 0, (void*)0x0802EA7C }, { 0x10D7, 0, (void*)0x0802EB50 }, { 0x10D8, 0, (void*)0x0802EB6C }, - { 0x10D9, 0, (void*)0x0802EBA0 }, { 0x10DA, 0, (void*)0x0802EBC8 }, { 0x10DB, 0, (void*)0x0802EC10 }, - { 0x10DC, 0, (void*)0x0802EC40 }, { 0x10DD, 0, (void*)0x0802EC6C }, { 0x10DE, 0, (void*)0x0802ECA8 }, - { 0x10DF, 0, (void*)0x0802ECD8 }, { 0x10E0, 0, (void*)0x0802ED14 }, { 0x10E1, 0, (void*)0x0802ED40 }, - { 0x10E2, 0, (void*)0x0802ED68 }, { 0x10E3, 0, (void*)0x0802EDA0 }, { 0x10E4, 0, (void*)0x0802EE18 }, - { 0x10E5, 0, (void*)0x0802EE44 }, { 0x10E6, 0, (void*)0x0802EEB0 }, { 0x10E7, 0, (void*)0x0802EEE8 }, - { 0x10E8, 0, (void*)0x0802EF24 }, { 0x10E9, 0, (void*)0x0802EF84 }, { 0x10EA, 0, (void*)0x0802EFCC }, - { 0x10EB, 0, (void*)0x0802EFF8 }, { 0x10EC, 0, (void*)0x0802F030 }, { 0x10ED, 0, (void*)0x0802F078 }, - { 0x10EE, 0, (void*)0x0802F0B4 }, { 0x10EF, 0, (void*)0x0802F0E0 }, { 0x10F0, 0, (void*)0x0802F110 }, - { 0x10F1, 0, (void*)0x0802F14C }, { 0x10F2, 0, (void*)0x0802F184 }, { 0x10F3, 0, (void*)0x0802F1A8 }, - { 0x10F4, 0, (void*)0x0802F1D4 }, { 0x10F5, 0, (void*)0x0802F204 }, { 0x10F6, 0, (void*)0x0802F258 }, - { 0x10F7, 0, (void*)0x0802F28C }, { 0x10F8, 0, (void*)0x0802F2D4 }, { 0x10F9, 0, (void*)0x0802F30C }, - { 0x10FA, 0, (void*)0x0802F334 }, { 0x10FB, 0, (void*)0x0802F3A8 }, { 0x10FC, 0, (void*)0x0802F3D8 }, - { 0x10FD, 0, (void*)0x0802F408 }, { 0x10FE, 0, (void*)0x0802F44C }, { 0x10FF, 0, (void*)0x0802F484 }, - { 0x1100, 0, (void*)0x0802F4CC }, { 0x1101, 0, (void*)0x0802F500 }, { 0x1102, 0, (void*)0x0802F590 }, - { 0x1103, 0, (void*)0x0802F5CC }, { 0x1104, 0, (void*)0x0802F604 }, { 0x1105, 0, (void*)0x0802F660 }, - { 0x1106, 0, (void*)0x0802F694 }, { 0x1107, 0, (void*)0x0802F6B8 }, { 0x1108, 0, (void*)0x0802F730 }, - { 0x1109, 0, (void*)0x0802F7B4 }, { 0x1130, 0, (void*)0x0802F7D8 }, { 0x1131, 0, (void*)0x0802F7F4 }, - { 0x1132, 0, (void*)0x0802F82C }, { 0x1133, 0, (void*)0x0802F8C0 }, { 0x1134, 0, (void*)0x0802F8E8 }, - { 0x1135, 0, (void*)0x0802F8F4 }, { 0x1136, 0, (void*)0x0802F900 }, { 0x1137, 0, (void*)0x0802F960 }, - { 0x1138, 0, (void*)0x0802F9D0 }, { 0x1139, 0, (void*)0x0802FA70 }, { 0x113A, 0, (void*)0x0802FB2C }, - { 0x113B, 0, (void*)0x0802FB64 }, { 0x113C, 0, (void*)0x0802FBF4 }, { 0x113D, 0, (void*)0x0802FC4C }, - { 0x113E, 0, (void*)0x0802FCA0 }, { 0x113F, 0, (void*)0x0802FD10 }, { 0x1140, 0, (void*)0x0802FDA8 }, - { 0x1141, 0, (void*)0x0802FE38 }, { 0x1142, 0, (void*)0x0802FE7C }, { 0x1143, 0, (void*)0x0802FEBC }, - { 0x1144, 0, (void*)0x0802FEF8 }, { 0x1145, 0, (void*)0x0802FF58 }, { 0x1146, 0, (void*)0x0802FFB4 }, - { 0x1147, 0, (void*)0x08030004 }, { 0x1148, 0, (void*)0x08030018 }, { 0x1149, 0, (void*)0x080300B8 }, - { 0x114A, 0, (void*)0x08030114 }, { 0x114B, 0, (void*)0x08030170 }, { 0x114C, 0, (void*)0x080301CC }, - { 0x114D, 0, (void*)0x08030228 }, { 0x114E, 0, (void*)0x08030284 }, { 0x114F, 0, (void*)0x080302E0 }, - { 0x1150, 0, (void*)0x08030318 }, { 0x1151, 0, (void*)0x080303C8 }, { 0x1152, 0, (void*)0x080303DC }, - { 0x1194, 0, (void*)0x08030438 }, { 0x1195, 0, (void*)0x08030458 }, { 0x1196, 0, (void*)0x080304AC }, - { 0x1197, 0, (void*)0x080304E0 }, { 0x1198, 0, (void*)0x08030578 }, { 0x1199, 0, (void*)0x080305E4 }, - { 0x119A, 0, (void*)0x080305FC }, { 0x119B, 0, (void*)0x08030638 }, { 0x119C, 0, (void*)0x080306D0 }, - { 0x119D, 0, (void*)0x08030748 }, { 0x119E, 0, (void*)0x08030770 }, { 0x119F, 0, (void*)0x08030784 }, - { 0x11A0, 0, (void*)0x080307EC }, { 0x11A1, 0, (void*)0x08030828 }, { 0x11A2, 0, (void*)0x080308E0 }, - { 0x11A3, 0, (void*)0x08030918 }, { 0x11A4, 0, (void*)0x08030934 }, { 0x11A5, 0, (void*)0x08030948 }, - { 0x11A6, 0, (void*)0x080309BC }, { 0x11A7, 0, (void*)0x080309E8 }, { 0x11A8, 0, (void*)0x08030A38 }, - { 0x11A9, 0, (void*)0x08030A60 }, { 0x11AA, 0, (void*)0x08030AA0 }, { 0x11AB, 0, (void*)0x08030ADC }, - { 0x11AC, 0, (void*)0x08030B10 }, { 0x11AD, 0, (void*)0x08030B40 }, { 0x11AE, 0, (void*)0x08030B80 }, - { 0x11AF, 0, (void*)0x08030BB4 }, { 0x11F8, 0, (void*)0x08030BFC }, { 0x11F9, 0, (void*)0x08030C64 }, - { 0x11FA, 0, (void*)0x08030CA0 }, { 0x11FB, 0, (void*)0x08030D28 }, { 0x11FC, 0, (void*)0x08030D58 }, - { 0x11FD, 0, (void*)0x08030E14 }, { 0x11FE, 0, (void*)0x08030E94 }, { 0x11FF, 0, (void*)0x08030F2C }, - { 0x1200, 0, (void*)0x08030F6C }, { 0x1201, 0, (void*)0x08031004 }, { 0x1202, 0, (void*)0x08031038 }, - { 0x1203, 0, (void*)0x080310A4 }, { 0x1204, 0, (void*)0x08031110 }, { 0x1205, 0, (void*)0x08031154 }, - { 0x1206, 0, (void*)0x080311EC }, { 0x1207, 0, (void*)0x08031230 }, { 0x1208, 0, (void*)0x08031290 }, - { 0x1209, 0, (void*)0x080312C4 }, { 0x120A, 0, (void*)0x08031304 }, { 0x120B, 0, (void*)0x08031320 }, - { 0x120C, 0, (void*)0x08031348 }, { 0x120D, 0, (void*)0x08031390 }, { 0x120E, 0, (void*)0x080313DC }, - { 0x120F, 0, (void*)0x08031470 }, { 0x1210, 0, (void*)0x08031498 }, { 0x1211, 0, (void*)0x08031520 }, - { 0x1212, 0, (void*)0x08031580 }, { 0x1213, 0, (void*)0x080315A8 }, { 0x1214, 0, (void*)0x08031644 }, - { 0x1215, 0, (void*)0x080316AC }, { 0x1216, 0, (void*)0x08031708 }, { 0x1217, 0, (void*)0x0803176C }, - { 0x1218, 0, (void*)0x080317BC }, { 0x1219, 0, (void*)0x080317E8 }, { 0x121A, 0, (void*)0x08031834 }, - { 0x121B, 0, (void*)0x080318B8 }, { 0x121C, 0, (void*)0x08031900 }, { 0x121D, 0, (void*)0x08031930 }, - { 0x121E, 0, (void*)0x08031984 }, { 0x121F, 0, (void*)0x080319C8 }, { 0x1220, 0, (void*)0x08031A08 }, - { 0x1221, 0, (void*)0x08031A7C }, { 0x1222, 0, (void*)0x08031AFC }, { 0x1223, 0, (void*)0x08031B68 }, - { 0x1224, 0, (void*)0x08031BC0 }, { 0x1225, 0, (void*)0x08031C10 }, { 0x1226, 0, (void*)0x08031CD4 }, - { 0x1227, 0, (void*)0x08031D38 }, { 0x1228, 0, (void*)0x08031DC0 }, { 0x1229, 0, (void*)0x08031E00 }, - { 0x122A, 0, (void*)0x08031E54 }, { 0x122B, 0, (void*)0x08031E80 }, { 0x122C, 0, (void*)0x08031EF8 }, - { 0x122D, 0, (void*)0x08031F1C }, { 0x122E, 0, (void*)0x08031FA4 }, { 0x122F, 0, (void*)0x0803202C }, - { 0x1230, 0, (void*)0x08032050 }, { 0x1231, 0, (void*)0x0803210C }, { 0x1232, 0, (void*)0x08032148 }, - { 0x1233, 0, (void*)0x080321B4 }, { 0x1234, 0, (void*)0x08032200 }, { 0x1235, 0, (void*)0x08032250 }, - { 0x1236, 0, (void*)0x080322C4 }, { 0x1237, 0, (void*)0x08032330 }, { 0x1238, 0, (void*)0x08032364 }, - { 0x1239, 0, (void*)0x08032414 }, { 0x123A, 0, (void*)0x08032464 }, { 0x123B, 0, (void*)0x08032504 }, - { 0x123C, 0, (void*)0x08032550 }, { 0x123D, 0, (void*)0x080325A4 }, { 0x123E, 0, (void*)0x08032638 }, - { 0x123F, 0, (void*)0x08032698 }, { 0x1240, 0, (void*)0x080326FC }, { 0x1241, 0, (void*)0x080327D4 }, - { 0x1242, 0, (void*)0x0803284C }, { 0x1243, 0, (void*)0x08032904 }, { 0x1244, 0, (void*)0x08032964 }, - { 0x1245, 0, (void*)0x080329B8 }, { 0x1246, 0, (void*)0x080329E4 }, { 0x1247, 0, (void*)0x08032A54 }, - { 0x1248, 0, (void*)0x08032AC0 }, { 0x1249, 0, (void*)0x08032B08 }, { 0x124A, 0, (void*)0x08032B68 }, - { 0x124B, 0, (void*)0x08032BC4 }, { 0x124C, 0, (void*)0x08032BE0 }, { 0x124D, 0, (void*)0x08032C24 }, - { 0x124E, 0, (void*)0x08032C68 }, { 0x124F, 0, (void*)0x08032CD8 }, { 0x1250, 0, (void*)0x08032D1C }, - { 0x1251, 0, (void*)0x08032D6C }, { 0x1252, 0, (void*)0x08032DE4 }, { 0x1253, 0, (void*)0x08032E0C }, - { 0x1254, 0, (void*)0x08032E60 }, { 0x1255, 0, (void*)0x08032EC4 }, { 0x1256, 0, (void*)0x08032F38 }, - { 0x1257, 0, (void*)0x08032F7C }, { 0x1258, 0, (void*)0x08032FF4 }, { 0x1259, 0, (void*)0x08033030 }, - { 0x125A, 0, (void*)0x080330BC }, { 0x125B, 0, (void*)0x080330F8 }, { 0x125C, 0, (void*)0x0803319C }, - { 0x125D, 0, (void*)0x08033224 }, { 0x125E, 0, (void*)0x080332D0 }, { 0x125F, 0, (void*)0x08033358 }, - { 0x1260, 0, (void*)0x080333CC }, { 0x1261, 0, (void*)0x08033410 }, { 0x1262, 0, (void*)0x08033450 }, - { 0x1263, 0, (void*)0x080334BC }, { 0x1264, 0, (void*)0x080334F4 }, { 0x1265, 0, (void*)0x0803353C }, - { 0x1266, 0, (void*)0x08033588 }, { 0x1267, 0, (void*)0x080335F4 }, { 0x1268, 0, (void*)0x08033678 }, - { 0x1269, 0, (void*)0x0803370C }, { 0x126A, 0, (void*)0x08033778 }, { 0x126B, 0, (void*)0x080337CC }, - { 0x126C, 0, (void*)0x08033830 }, { 0x126D, 0, (void*)0x080338B0 }, { 0x126E, 0, (void*)0x08033934 }, - { 0x126F, 0, (void*)0x0803397C }, { 0x1270, 0, (void*)0x080339F0 }, { 0x1271, 0, (void*)0x08033A14 }, - { 0x1272, 0, (void*)0x08033A44 }, { 0x1273, 0, (void*)0x08033A88 }, { 0x1274, 0, (void*)0x08033AE0 }, - { 0x1275, 0, (void*)0x08033B74 }, { 0x1276, 0, (void*)0x08033BC0 }, { 0x1277, 0, (void*)0x08033C24 }, - { 0x1278, 0, (void*)0x08033CA0 }, { 0x1279, 0, (void*)0x08033D10 }, { 0x127A, 0, (void*)0x08033D80 }, - { 0x127B, 0, (void*)0x08033DB4 }, { 0x127C, 0, (void*)0x08033E18 }, { 0x127D, 0, (void*)0x08033E68 }, - { 0x127E, 0, (void*)0x08033EB4 }, { 0x127F, 0, (void*)0x08033F04 }, { 0x1280, 0, (void*)0x08033F58 }, - { 0x1281, 0, (void*)0x08033FB8 }, { 0x1282, 0, (void*)0x08034014 }, { 0x1283, 0, (void*)0x08034044 }, - { 0x1284, 0, (void*)0x0803409C }, { 0x1285, 0, (void*)0x080340EC }, { 0x1286, 0, (void*)0x08034140 }, - { 0x1287, 0, (void*)0x080341A0 }, { 0x1288, 0, (void*)0x08034204 }, { 0x1289, 0, (void*)0x08034248 }, - { 0x128A, 0, (void*)0x080342A8 }, { 0x128B, 0, (void*)0x080342E0 }, { 0x128C, 0, (void*)0x08034314 }, - { 0x128D, 0, (void*)0x08034340 }, { 0x128E, 0, (void*)0x08034368 }, { 0x128F, 0, (void*)0x080343C8 }, - { 0x1290, 0, (void*)0x0803445C }, { 0x1291, 0, (void*)0x080344E8 }, { 0x1292, 0, (void*)0x08034528 }, - { 0x1293, 0, (void*)0x08034538 }, { 0x1294, 0, (void*)0x08034578 }, { 0x1295, 0, (void*)0x080345C4 }, - { 0x1296, 0, (void*)0x08034618 }, { 0x1297, 0, (void*)0x08034680 }, { 0x1298, 0, (void*)0x080346AC }, - { 0x1299, 0, (void*)0x08034728 }, { 0x129A, 0, (void*)0x0803479C }, { 0x129B, 0, (void*)0x08034808 }, - { 0x129C, 0, (void*)0x08034854 }, { 0x129D, 0, (void*)0x08034888 }, { 0x129E, 0, (void*)0x080348B4 }, - { 0x129F, 0, (void*)0x080348FC }, { 0x12A0, 0, (void*)0x08034938 }, { 0x12A1, 0, (void*)0x08034984 }, - { 0x12A2, 0, (void*)0x080349C4 }, { 0x12A3, 0, (void*)0x08034A24 }, { 0x12A4, 0, (void*)0x08034A80 }, - { 0x12A5, 0, (void*)0x08034AF0 }, { 0x12A6, 0, (void*)0x08034B40 }, { 0x12A7, 0, (void*)0x08034B74 }, - { 0x12A8, 0, (void*)0x08034BCC }, { 0x12A9, 0, (void*)0x08034C2C }, { 0x12AA, 0, (void*)0x08034CA0 }, - { 0x12AB, 0, (void*)0x08034CDC }, { 0x12AC, 0, (void*)0x08034D50 }, { 0x12AD, 0, (void*)0x08034D9C }, - { 0x12AE, 0, (void*)0x08034E10 }, { 0x12AF, 0, (void*)0x08034E40 }, { 0x12B0, 0, (void*)0x08034E70 }, - { 0x12B1, 0, (void*)0x08034EDC }, { 0x12B2, 0, (void*)0x08034F28 }, { 0x12B3, 0, (void*)0x08034F74 }, - { 0x12B4, 0, (void*)0x08034FA0 }, { 0x12B5, 0, (void*)0x08034FF4 }, { 0x12B6, 0, (void*)0x08035018 }, - { 0x12B7, 0, (void*)0x0803504C }, { 0x12B8, 0, (void*)0x08035078 }, { 0x12B9, 0, (void*)0x080350C0 }, - { 0x12BA, 0, (void*)0x080350F0 }, { 0x12BB, 0, (void*)0x08035134 }, { 0x12BC, 0, (void*)0x0803516C }, - { 0x12BD, 0, (void*)0x080351D0 }, { 0x12BE, 0, (void*)0x0803521C }, { 0x12BF, 0, (void*)0x08035288 }, - { 0x12C0, 0, (void*)0x08035308 }, { 0x12C1, 0, (void*)0x0803534C }, { 0x12C2, 0, (void*)0x0803539C }, - { 0x12C3, 0, (void*)0x080353CC }, { 0x12C4, 0, (void*)0x08035410 }, { 0x12C5, 0, (void*)0x08035470 }, - { 0x12C6, 0, (void*)0x080354B8 }, { 0x12C7, 0, (void*)0x08035520 }, { 0x12C8, 0, (void*)0x08035560 }, - { 0x12C9, 0, (void*)0x08035604 }, { 0x12CA, 0, (void*)0x0803566C }, { 0x12CB, 0, (void*)0x080356A4 }, - { 0x12CC, 0, (void*)0x080356E4 }, { 0x12CD, 0, (void*)0x0803577C }, { 0x12CE, 0, (void*)0x080357EC }, - { 0x12CF, 0, (void*)0x0803581C }, { 0x12D0, 0, (void*)0x08035848 }, { 0x12D1, 0, (void*)0x08035888 }, - { 0x12D2, 0, (void*)0x080358D0 }, { 0x12D3, 0, (void*)0x080358E8 }, { 0x12D4, 0, (void*)0x0803590C }, - { 0x12D5, 0, (void*)0x0803592C }, { 0x12D6, 0, (void*)0x0803596C }, { 0x12D7, 0, (void*)0x080359C4 }, - { 0x12D8, 0, (void*)0x08035A10 }, { 0x12D9, 0, (void*)0x08035A80 }, { 0x12DA, 0, (void*)0x08035ADC }, - { 0x12DB, 0, (void*)0x08035B48 }, { 0x12DC, 0, (void*)0x08035BB8 }, { 0x12DD, 0, (void*)0x08035BF8 }, - { 0x12DE, 0, (void*)0x08035C74 }, { 0x12DF, 0, (void*)0x08035CB0 }, { 0x12E0, 0, (void*)0x08035D10 }, - { 0x12E3, 0, (void*)0x08035D4C }, { 0x12E4, 0, (void*)0x08035D70 }, { 0x12E5, 0, (void*)0x08035DAC }, - { 0x12E6, 0, (void*)0x08035DD8 }, { 0x12E7, 0, (void*)0x08035DF4 }, { 0x12E8, 0, (void*)0x08035E0C }, - { 0x12E9, 0, (void*)0x08035E58 }, { 0x12EA, 0, (void*)0x08035ED4 }, { 0x12EB, 0, (void*)0x08035F44 }, - { 0x12EC, 0, (void*)0x08036074 }, { 0x12ED, 0, (void*)0x080360BC }, { 0x12EE, 0, (void*)0x08036104 }, - { 0x12EF, 0, (void*)0x0803613C }, { 0x12F0, 0, (void*)0x080361A0 }, { 0x12F1, 0, (void*)0x080361F0 }, - { 0x12F2, 0, (void*)0x08036248 }, { 0x12F3, 0, (void*)0x08036260 }, { 0x12F4, 0, (void*)0x080362A0 }, - { 0x12F5, 0, (void*)0x08036300 }, { 0x12F6, 0, (void*)0x08036324 }, { 0x12F7, 0, (void*)0x080363A0 }, - { 0x12F8, 0, (void*)0x0803640C }, { 0x12F9, 0, (void*)0x08036474 }, { 0x12FA, 0, (void*)0x080364CC }, - { 0x12FB, 0, (void*)0x08036508 }, { 0x12FC, 0, (void*)0x0803655C }, { 0x12FD, 0, (void*)0x08036578 }, - { 0x12FE, 0, (void*)0x080365D4 }, { 0x12FF, 0, (void*)0x080365F8 }, { 0x1300, 0, (void*)0x08036654 }, - { 0x1301, 0, (void*)0x080366A4 }, { 0x1302, 0, (void*)0x080366F0 }, { 0x1303, 0, (void*)0x08036738 }, - { 0x1304, 0, (void*)0x08036770 }, { 0x1305, 0, (void*)0x080367AC }, { 0x1306, 0, (void*)0x080367F0 }, - { 0x1307, 0, (void*)0x08036830 }, { 0x1308, 0, (void*)0x08036850 }, { 0x1309, 0, (void*)0x0803688C }, - { 0x130A, 0, (void*)0x080368F0 }, { 0x130B, 0, (void*)0x08036924 }, { 0x130C, 0, (void*)0x0803695C }, - { 0x130D, 0, (void*)0x080369A8 }, { 0x130E, 0, (void*)0x080369FC }, { 0x130F, 0, (void*)0x08036A40 }, - { 0x1310, 0, (void*)0x08036A74 }, { 0x1311, 0, (void*)0x08036AB8 }, { 0x1312, 0, (void*)0x08036B14 }, - { 0x1313, 0, (void*)0x08036B4C }, { 0x1314, 0, (void*)0x08036BAC }, { 0x1315, 0, (void*)0x08036C0C }, - { 0x1316, 0, (void*)0x08036C64 }, { 0x1317, 0, (void*)0x08036CBC }, { 0x1318, 0, (void*)0x08036D1C }, - { 0x1319, 0, (void*)0x08036D80 }, { 0x131A, 0, (void*)0x08036DC4 }, { 0x131B, 0, (void*)0x08036E0C }, - { 0x131C, 0, (void*)0x08036E8C }, { 0x131D, 0, (void*)0x08036F14 }, { 0x1388, 0, (void*)0x08036F8C }, - { 0x1389, 0, (void*)0x08036FB4 }, { 0x138A, 0, (void*)0x08036FF8 }, { 0x138B, 0, (void*)0x08037034 }, - { 0x138C, 0, (void*)0x08037060 }, { 0x138D, 0, (void*)0x0803709C }, { 0x138E, 0, (void*)0x0803711C }, - { 0x138F, 0, (void*)0x08037140 }, { 0x1390, 0, (void*)0x08037178 }, { 0x1391, 0, (void*)0x080371AC }, - { 0x1392, 0, (void*)0x08037204 }, { 0x1393, 0, (void*)0x08037234 }, { 0x1394, 0, (void*)0x08037288 }, - { 0x1395, 0, (void*)0x080372BC }, { 0x1396, 0, (void*)0x080372F0 }, { 0x1397, 0, (void*)0x08037310 }, - { 0x1398, 0, (void*)0x08037338 }, { 0x1399, 0, (void*)0x080373C4 }, { 0x139A, 0, (void*)0x08037438 }, - { 0x139B, 0, (void*)0x080374A0 }, { 0x139C, 0, (void*)0x0803751C }, { 0x139D, 0, (void*)0x0803758C }, - { 0x139E, 0, (void*)0x08037620 }, { 0x139F, 0, (void*)0x08037704 }, { 0x13A0, 0, (void*)0x08037764 }, - { 0x13A1, 0, (void*)0x080377F4 }, { 0x13A2, 0, (void*)0x08037838 }, { 0x13A3, 0, (void*)0x08037894 }, - { 0x13A4, 0, (void*)0x08037918 }, { 0x13A5, 0, (void*)0x08037974 }, { 0x13A6, 0, (void*)0x080379CC }, - { 0x13A7, 0, (void*)0x08037A68 }, { 0x13A8, 0, (void*)0x08037ACC }, { 0x13AE, 0, (void*)0x08037B5C }, - { 0x13AF, 0, (void*)0x08037BF8 }, { 0x13B0, 0, (void*)0x08037CE0 }, { 0x13B1, 0, (void*)0x08037D2C }, - { 0x13B2, 0, (void*)0x08037D54 }, { 0x13B3, 0, (void*)0x08037D74 }, { 0x13EC, 0, (void*)0x08037DB8 }, - { 0x13ED, 0, (void*)0x08037DCC }, { 0x13EE, 0, (void*)0x08037E30 }, { 0x13EF, 0, (void*)0x08037EB4 }, - { 0x13F0, 0, (void*)0x08037EF4 }, { 0x13F1, 0, (void*)0x08037F34 }, { 0x13F2, 0, (void*)0x08037F74 }, - { 0x13F3, 0, (void*)0x08037F8C }, { 0x13F4, 0, (void*)0x08037FA4 }, { 0x13F5, 0, (void*)0x08037FC8 }, - { 0x13F6, 0, (void*)0x08037FF8 }, { 0x13F7, 0, (void*)0x0803800C }, { 0x13F8, 0, (void*)0x0803803C }, - { 0x13F9, 0, (void*)0x08038084 }, { 0x13FA, 0, (void*)0x080380C8 }, { 0x13FB, 0, (void*)0x08038108 }, - { 0x13FC, 0, (void*)0x080381A4 }, { 0x13FD, 0, (void*)0x080381FC }, { 0x13FE, 0, (void*)0x08038254 }, - { 0x13FF, 0, (void*)0x080382D8 }, { 0x1400, 0, (void*)0x080383A8 }, { 0x1401, 0, (void*)0x08038504 }, - { 0x1402, 0, (void*)0x080385A8 }, { 0x1403, 0, (void*)0x08038630 }, { 0x1404, 0, (void*)0x0803868C }, - { 0x1405, 0, (void*)0x080386C4 }, { 0x1406, 0, (void*)0x08038728 }, { 0x1407, 0, (void*)0x08038824 }, - { 0x1408, 0, (void*)0x08038844 }, { 0x1409, 0, (void*)0x080388F4 }, { 0x140A, 0, (void*)0x08038984 }, - { 0x140B, 0, (void*)0x080389D0 }, { 0x140C, 0, (void*)0x08038A3C }, { 0x140D, 0, (void*)0x08038A88 }, - { 0x140E, 0, (void*)0x08038AE8 }, { 0x140F, 0, (void*)0x08038B20 }, { 0x1410, 0, (void*)0x08038B60 }, - { 0x1411, 0, (void*)0x08038BBC }, { 0x1412, 0, (void*)0x08038BF4 }, { 0x1413, 0, (void*)0x08038C34 }, - { 0x1414, 0, (void*)0x08038CC0 }, { 0x1450, 0, (void*)0x08038D04 }, { 0x1451, 0, (void*)0x08038EC4 }, - { 0x1452, 0, (void*)0x08038EF8 }, { 0x1453, 0, (void*)0x08038F10 }, { 0x1454, 0, (void*)0x08038F50 }, - { 0x1455, 0, (void*)0x08038F9C }, { 0x1456, 0, (void*)0x08038FE4 }, { 0x1457, 0, (void*)0x08039064 }, - { 0x1458, 0, (void*)0x080390A8 }, { 0x1459, 0, (void*)0x080390D4 }, { 0x145A, 0, (void*)0x08039128 }, - { 0x145B, 0, (void*)0x08039198 }, { 0x145C, 0, (void*)0x080391C4 }, { 0x145D, 0, (void*)0x080391D8 }, - { 0x145E, 0, (void*)0x08039204 }, { 0x145F, 0, (void*)0x080392B0 }, { 0x1460, 0, (void*)0x08039360 }, - { 0x1461, 0, (void*)0x080393A8 }, { 0x1462, 0, (void*)0x080393BC }, { 0x1463, 0, (void*)0x080393EC }, - { 0x1464, 0, (void*)0x0803940C }, { 0x1465, 0, (void*)0x0803942C }, { 0x1466, 0, (void*)0x08039454 }, - { 0x1467, 0, (void*)0x0803948C }, { 0x1468, 0, (void*)0x080394E8 }, { 0x1469, 0, (void*)0x08039548 }, - { 0x146A, 0, (void*)0x080395A8 }, { 0x146B, 0, (void*)0x08039638 }, { 0x146C, 0, (void*)0x08039700 }, - { 0x146D, 0, (void*)0x08039738 }, { 0x146E, 0, (void*)0x08039758 }, { 0x146F, 0, (void*)0x080397D8 }, - { 0x1470, 0, (void*)0x08039858 }, { 0x1471, 0, (void*)0x08039880 }, { 0x1472, 0, (void*)0x080398B8 }, - { 0x1473, 0, (void*)0x08039924 }, { 0x1474, 0, (void*)0x08039950 }, { 0x1475, 0, (void*)0x08039A64 }, - { 0x1476, 0, (void*)0x08039AE8 }, { 0x1477, 0, (void*)0x08039B4C }, { 0x1478, 0, (void*)0x08039B70 }, - { 0x1479, 0, (void*)0x08039B98 }, { 0x147A, 0, (void*)0x08039BCC }, { 0x147B, 0, (void*)0x08039C00 }, - { 0x147C, 0, (void*)0x08039D6C }, { 0x147D, 0, (void*)0x08039E18 }, { 0x14B4, 0, (void*)0x08039E78 }, - { 0x14B5, 0, (void*)0x08039EA8 }, { 0x14B6, 0, (void*)0x08039EF8 }, { 0x14B7, 0, (void*)0x08039F64 }, - { 0x14B8, 0, (void*)0x08039F90 }, { 0x14B9, 0, (void*)0x08039FE4 }, { 0x14BA, 0, (void*)0x0803A044 }, - { 0x14BB, 0, (void*)0x0803A090 }, { 0x14BC, 0, (void*)0x0803A110 }, { 0x14BD, 0, (void*)0x0803A138 }, - { 0x14BE, 0, (void*)0x0803A1B8 }, { 0x14BF, 0, (void*)0x0803A208 }, { 0x14C0, 0, (void*)0x0803A25C }, - { 0x14C1, 0, (void*)0x0803A29C }, { 0x14C2, 0, (void*)0x0803A2E8 }, { 0x14C3, 0, (void*)0x0803A384 }, - { 0x14C4, 0, (void*)0x0803A3FC }, { 0x14C5, 0, (void*)0x0803A458 }, { 0x14C6, 0, (void*)0x0803A514 }, - { 0x14C7, 0, (void*)0x0803A540 }, { 0x14C8, 0, (void*)0x0803A570 }, { 0x14C9, 0, (void*)0x0803A5E4 }, - { 0x14CA, 0, (void*)0x0803A614 }, { 0x14CB, 0, (void*)0x0803A684 }, { 0x14CC, 0, (void*)0x0803A700 }, - { 0x14CD, 0, (void*)0x0803A79C }, { 0x14CE, 0, (void*)0x0803A7B8 }, { 0x14CF, 0, (void*)0x0803A880 }, - { 0x14D0, 0, (void*)0x0803A8AC }, { 0x14D1, 0, (void*)0x0803A96C }, { 0x14D2, 0, (void*)0x0803AA08 }, - { 0x14D3, 0, (void*)0x0803AA80 }, { 0x14D4, 0, (void*)0x0803AB40 }, { 0x14D5, 0, (void*)0x0803AB80 }, - { 0x14D6, 0, (void*)0x0803ABC0 }, { 0x14D7, 0, (void*)0x0803AC30 }, { 0x14D8, 0, (void*)0x0803AC78 }, - { 0x14D9, 0, (void*)0x0803ACEC }, { 0x14DA, 0, (void*)0x0803AD64 }, { 0x14DB, 0, (void*)0x0803AD8C }, - { 0x14DC, 0, (void*)0x0803ADB8 }, { 0x14DD, 0, (void*)0x0803ADEC }, { 0x14DE, 0, (void*)0x0803AE40 }, - { 0x14DF, 0, (void*)0x0803AEAC }, { 0x14E0, 0, (void*)0x0803AEFC }, { 0x14E1, 0, (void*)0x0803AF58 }, - { 0x14E2, 0, (void*)0x0803AFDC }, { 0x14E3, 0, (void*)0x0803B018 }, { 0x14E4, 0, (void*)0x0803B044 }, - { 0x14E5, 0, (void*)0x0803B07C }, { 0x14E6, 0, (void*)0x0803B100 }, { 0x14E7, 0, (void*)0x0803B13C }, - { 0x14E8, 0, (void*)0x0803B19C }, { 0x14E9, 0, (void*)0x0803B220 }, { 0x14EA, 0, (void*)0x0803B2A0 }, - { 0x14EB, 0, (void*)0x0803B358 }, { 0x14EC, 0, (void*)0x0803B398 }, { 0x14ED, 0, (void*)0x0803B40C }, - { 0x14EE, 0, (void*)0x0803B518 }, { 0x14EF, 0, (void*)0x0803B5F8 }, { 0x14F0, 0, (void*)0x0803B63C }, - { 0x14F1, 0, (void*)0x0803B6A8 }, { 0x14F2, 0, (void*)0x0803B734 }, { 0x14F3, 0, (void*)0x0803B7B8 }, - { 0x14F4, 0, (void*)0x0803B834 }, { 0x14F5, 0, (void*)0x0803B910 }, { 0x14F6, 0, (void*)0x0803B984 }, - { 0x14F7, 0, (void*)0x0803B9F0 }, { 0x14F8, 0, (void*)0x0803BA80 }, { 0x14F9, 0, (void*)0x0803BAB8 }, - { 0x14FA, 0, (void*)0x0803BAF8 }, { 0x14FB, 0, (void*)0x0803BB60 }, { 0x14FC, 0, (void*)0x0803BB8C }, - { 0x1518, 0, (void*)0x0803BBFC }, { 0x1519, 0, (void*)0x0803BC5C }, { 0x151A, 0, (void*)0x0803BCB0 }, - { 0x151B, 0, (void*)0x0803BCC8 }, { 0x151C, 0, (void*)0x0803BCF8 }, { 0x151D, 0, (void*)0x0803BD44 }, - { 0x151E, 0, (void*)0x0803BDB8 }, { 0x151F, 0, (void*)0x0803BDFC }, { 0x1520, 0, (void*)0x0803BE9C }, - { 0x1521, 0, (void*)0x0803BF18 }, { 0x1522, 0, (void*)0x0803BF64 }, { 0x1523, 0, (void*)0x0803BF8C }, - { 0x1524, 0, (void*)0x0803BFA4 }, { 0x1525, 0, (void*)0x0803BFD8 }, { 0x1526, 0, (void*)0x0803BFF8 }, - { 0x1527, 0, (void*)0x0803C014 }, { 0x1528, 0, (void*)0x0803C068 }, { 0x1529, 0, (void*)0x0803C0EC }, - { 0x152A, 0, (void*)0x0803C174 }, { 0x152B, 0, (void*)0x0803C1CC }, { 0x152C, 0, (void*)0x0803C22C }, - { 0x152D, 0, (void*)0x0803C290 }, { 0x152E, 0, (void*)0x0803C314 }, { 0x152F, 0, (void*)0x0803C398 }, - { 0x1530, 0, (void*)0x0803C3F0 }, { 0x1531, 0, (void*)0x0803C454 }, { 0x1532, 0, (void*)0x0803C4DC }, - { 0x1533, 0, (void*)0x0803C518 }, { 0x1534, 0, (void*)0x0803C564 }, { 0x1535, 0, (void*)0x0803C5A4 }, - { 0x1536, 0, (void*)0x0803C5E4 }, { 0x1537, 0, (void*)0x0803C644 }, { 0x1538, 0, (void*)0x0803C6C8 }, - { 0x1539, 0, (void*)0x0803C744 }, { 0x153A, 0, (void*)0x0803C7E0 }, { 0x153B, 0, (void*)0x0803C80C }, - { 0x153C, 0, (void*)0x0803C84C }, { 0x153D, 0, (void*)0x0803C884 }, { 0x153E, 0, (void*)0x0803C89C }, - { 0x153F, 0, (void*)0x0803C8DC }, { 0x1540, 0, (void*)0x0803C908 }, { 0x1541, 0, (void*)0x0803C944 }, - { 0x1542, 0, (void*)0x0803C9A0 }, { 0x157C, 0, (void*)0x0803C9BC }, { 0x157D, 0, (void*)0x0803C9D4 }, - { 0x157E, 0, (void*)0x0803CA30 }, { 0x157F, 0, (void*)0x0803CA70 }, { 0x1580, 0, (void*)0x0803CAA0 }, - { 0x1581, 0, (void*)0x0803CAEC }, { 0x1582, 0, (void*)0x0803CB04 }, { 0x1583, 0, (void*)0x0803CB18 }, - { 0x1584, 0, (void*)0x0803CB30 }, { 0x1585, 0, (void*)0x0803CB64 }, { 0x1586, 0, (void*)0x0803CBD8 }, - { 0x1587, 0, (void*)0x0803CBF4 }, { 0x1588, 0, (void*)0x0803CC34 }, { 0x1589, 0, (void*)0x0803CC78 }, - { 0x158A, 0, (void*)0x0803CD14 }, { 0x158B, 0, (void*)0x0803CDA0 }, { 0x158C, 0, (void*)0x0803CDE0 }, - { 0x158D, 0, (void*)0x0803CE3C }, { 0x158E, 0, (void*)0x0803CEA8 }, { 0x158F, 0, (void*)0x0803CEE8 }, - { 0x1590, 0, (void*)0x0803CF30 }, { 0x1591, 0, (void*)0x0803CFA4 }, { 0x1592, 0, (void*)0x0803D050 }, - { 0x1593, 0, (void*)0x0803D0C8 }, { 0x1594, 0, (void*)0x0803D118 }, { 0x1595, 0, (void*)0x0803D168 }, - { 0x1596, 0, (void*)0x0803D1A8 }, { 0x1597, 0, (void*)0x0803D1F0 }, { 0x1598, 0, (void*)0x0803D228 }, - { 0x1599, 0, (void*)0x0803D290 }, { 0x159A, 0, (void*)0x0803D2FC }, { 0x159B, 0, (void*)0x0803D368 }, - { 0x159C, 0, (void*)0x0803D448 }, { 0x159D, 0, (void*)0x0803D4C0 }, { 0x159E, 0, (void*)0x0803D500 }, - { 0x159F, 0, (void*)0x0803D558 }, { 0x15A0, 0, (void*)0x0803D5B4 }, { 0x15A1, 0, (void*)0x0803D628 }, - { 0x15A2, 0, (void*)0x0803D730 }, { 0x15A3, 0, (void*)0x0803D798 }, { 0x15A4, 0, (void*)0x0803D818 }, - { 0x15A5, 0, (void*)0x0803D868 }, { 0x15A6, 0, (void*)0x0803D8C4 }, { 0x15A7, 0, (void*)0x0803D9AC }, - { 0x15A8, 0, (void*)0x0803D9FC }, { 0x15E0, 0, (void*)0x0803DA3C }, { 0x15E1, 0, (void*)0x0803DA80 }, - { 0x15E2, 0, (void*)0x0803DB14 }, { 0x15E3, 0, (void*)0x0803DB9C }, { 0x15E4, 0, (void*)0x0803DC1C }, - { 0x15E5, 0, (void*)0x0803DC70 }, { 0x15E6, 0, (void*)0x0803DCA8 }, { 0x15E7, 0, (void*)0x0803DCF8 }, - { 0x15E8, 0, (void*)0x0803DD5C }, { 0x15E9, 0, (void*)0x0803DE00 }, { 0x15EA, 0, (void*)0x0803DE5C }, - { 0x15EB, 0, (void*)0x0803DE84 }, { 0x15EC, 0, (void*)0x0803DED0 }, { 0x15ED, 0, (void*)0x0803DF34 }, - { 0x15EE, 0, (void*)0x0803DF64 }, { 0x15EF, 0, (void*)0x0803DF9C }, { 0x15F0, 0, (void*)0x0803DFBC }, - { 0x15F1, 0, (void*)0x0803E018 }, { 0x15F2, 0, (void*)0x0803E0B8 }, { 0x15F3, 0, (void*)0x0803E124 }, - { 0x15F4, 0, (void*)0x0803E178 }, { 0x15F5, 0, (void*)0x0803E1E0 }, { 0x15F6, 0, (void*)0x0803E298 }, - { 0x15F7, 0, (void*)0x0803E310 }, { 0x15F8, 0, (void*)0x0803E36C }, { 0x15F9, 0, (void*)0x0803E3D0 }, - { 0x15FA, 0, (void*)0x0803E420 }, { 0x15FB, 0, (void*)0x0803E454 }, { 0x15FC, 0, (void*)0x0803E488 }, - { 0x15FD, 0, (void*)0x0803E4E8 }, { 0x15FE, 0, (void*)0x0803E59C }, { 0x15FF, 0, (void*)0x0803E620 }, - { 0x1600, 0, (void*)0x0803E66C }, { 0x1601, 0, (void*)0x0803E70C }, { 0x1602, 0, (void*)0x0803E74C }, - { 0x1603, 0, (void*)0x0803E7A4 }, { 0x1604, 0, (void*)0x0803E7DC }, { 0x1605, 0, (void*)0x0803E804 }, - { 0x1606, 0, (void*)0x0803E864 }, { 0x1607, 0, (void*)0x0803E8E8 }, { 0x1608, 0, (void*)0x0803E930 }, - { 0x1609, 0, (void*)0x0803E9E4 }, { 0x160A, 0, (void*)0x0803EA4C }, { 0x160B, 0, (void*)0x0803EAB0 }, - { 0x160C, 0, (void*)0x0803EB18 }, { 0x160D, 0, (void*)0x0803EB58 }, { 0x160E, 0, (void*)0x0803EBA8 }, - { 0x160F, 0, (void*)0x0803EBFC }, { 0x1610, 0, (void*)0x0803EC9C }, { 0x1611, 0, (void*)0x0803ED14 }, - { 0x1612, 0, (void*)0x0803EE08 }, { 0x1613, 0, (void*)0x0803EE48 }, { 0x1614, 0, (void*)0x0803EEB0 }, - { 0x1615, 0, (void*)0x0803EEF0 }, { 0x1616, 0, (void*)0x0803EFAC }, { 0x1617, 0, (void*)0x0803F004 }, - { 0x1618, 0, (void*)0x0803F04C }, { 0x1619, 0, (void*)0x0803F078 }, { 0x161A, 0, (void*)0x0803F0E0 }, - { 0x161B, 0, (void*)0x0803F110 }, { 0x161C, 0, (void*)0x0803F15C }, { 0x161D, 0, (void*)0x0803F1EC }, - { 0x161E, 0, (void*)0x0803F264 }, { 0x161F, 0, (void*)0x0803F2CC }, { 0x1620, 0, (void*)0x0803F344 }, - { 0x1621, 0, (void*)0x0803F3A8 }, { 0x1622, 0, (void*)0x0803F3F4 }, { 0x1623, 0, (void*)0x0803F46C }, - { 0x1624, 0, (void*)0x0803F4AC }, { 0x1625, 0, (void*)0x0803F500 }, { 0x1626, 0, (void*)0x0803F608 }, - { 0x1627, 0, (void*)0x0803F66C }, { 0x1628, 0, (void*)0x0803F6E8 }, { 0x1629, 0, (void*)0x0803F718 }, - { 0x162A, 0, (void*)0x0803F760 }, { 0x162B, 0, (void*)0x0803F7C0 }, { 0x162C, 0, (void*)0x0803F87C }, - { 0x162D, 0, (void*)0x0803F8A8 }, { 0x162E, 0, (void*)0x0803F8EC }, { 0x162F, 0, (void*)0x0803F94C }, - { 0x1630, 0, (void*)0x0803F978 }, { 0x1631, 0, (void*)0x0803F9DC }, { 0x1632, 0, (void*)0x0803FA3C }, - { 0x1633, 0, (void*)0x0803FA78 }, { 0x1634, 0, (void*)0x0803FAC4 }, { 0x1635, 0, (void*)0x0803FB0C }, - { 0x1636, 0, (void*)0x0803FB5C }, { 0x1637, 0, (void*)0x0803FBCC }, { 0x1638, 0, (void*)0x0803FC50 }, - { 0x1644, 0, (void*)0x0803FC6C }, { 0x1645, 0, (void*)0x0803FD0C }, { 0x1646, 0, (void*)0x0803FD5C }, - { 0x1647, 0, (void*)0x0803FDC0 }, { 0x1648, 0, (void*)0x0803FE08 }, { 0x1649, 0, (void*)0x0803FE54 }, - { 0x164A, 0, (void*)0x0803FEB4 }, { 0x164B, 0, (void*)0x0803FF88 }, { 0x164C, 0, (void*)0x0803FFF4 }, - { 0x164D, 0, (void*)0x08040064 }, { 0x164E, 0, (void*)0x080400BC }, { 0x164F, 0, (void*)0x0804010C }, - { 0x1650, 0, (void*)0x08040174 }, { 0x1651, 0, (void*)0x0804019C }, { 0x1652, 0, (void*)0x08040208 }, - { 0x1653, 0, (void*)0x08040250 }, { 0x1654, 0, (void*)0x080402B0 }, { 0x1655, 0, (void*)0x080402CC }, - { 0x1656, 0, (void*)0x0804032C }, { 0x1657, 0, (void*)0x0804035C }, { 0x1658, 0, (void*)0x080403C0 }, - { 0x1659, 0, (void*)0x08040494 }, { 0x165A, 0, (void*)0x08040530 }, { 0x165B, 0, (void*)0x0804054C }, - { 0x165C, 0, (void*)0x080405AC }, { 0x165D, 0, (void*)0x080405E0 }, { 0x165E, 0, (void*)0x08040624 }, - { 0x165F, 0, (void*)0x0804070C }, { 0x1660, 0, (void*)0x08040798 }, { 0x1661, 0, (void*)0x080407C0 }, - { 0x1700, 0, (void*)0x08040848 }, { 0x1701, 0, (void*)0x080408E4 }, { 0x1702, 0, (void*)0x0804092C }, - { 0x1703, 0, (void*)0x08040988 }, { 0x1704, 0, (void*)0x080409D4 }, { 0x1705, 0, (void*)0x08040A28 }, - { 0x1706, 0, (void*)0x08040ABC }, { 0x1707, 0, (void*)0x08040B0C }, { 0x1708, 0, (void*)0x08040B50 }, - { 0x1709, 0, (void*)0x08040BA4 }, { 0x170A, 0, (void*)0x08040C18 }, { 0x170B, 0, (void*)0x08040C60 }, - { 0x170C, 0, (void*)0x08040C6C }, { 0x170D, 0, (void*)0x08040CC8 }, { 0x170E, 0, (void*)0x08040D38 }, - { 0x170F, 0, (void*)0x08040DBC }, { 0x1710, 0, (void*)0x08040E0C }, { 0x1711, 0, (void*)0x08040E84 }, - { 0x1712, 0, (void*)0x08040E90 }, { 0x1713, 0, (void*)0x08040EE8 }, { 0x1714, 0, (void*)0x08040F30 }, - { 0x1715, 0, (void*)0x08040F78 }, { 0x1716, 0, (void*)0x08040FD0 }, { 0x1717, 0, (void*)0x08041050 }, - { 0x1718, 0, (void*)0x08041084 }, { 0x1719, 0, (void*)0x080410E8 }, { 0x171A, 0, (void*)0x08041128 }, - { 0x171B, 0, (void*)0x08041170 }, { 0x171C, 0, (void*)0x080411BC }, { 0x171D, 0, (void*)0x080411C8 }, - { 0x171E, 0, (void*)0x0804122C }, { 0x171F, 0, (void*)0x0804125C }, { 0x1720, 0, (void*)0x080412A8 }, - { 0x1721, 0, (void*)0x080412E8 }, { 0x1722, 0, (void*)0x0804132C }, { 0x1723, 0, (void*)0x08041378 }, - { 0x1724, 0, (void*)0x080413C0 }, { 0x1725, 0, (void*)0x08041414 }, { 0x1726, 0, (void*)0x08041470 }, - { 0x1727, 0, (void*)0x0804147C }, { 0x1728, 0, (void*)0x08041488 }, { 0x1729, 0, (void*)0x080414D0 }, - { 0x172A, 0, (void*)0x08041530 }, { 0x172B, 0, (void*)0x08041588 }, { 0x172C, 0, (void*)0x080415E4 }, - { 0x172D, 0, (void*)0x08041640 }, { 0x172E, 0, (void*)0x08041698 }, { 0x172F, 0, (void*)0x080416FC }, - { 0x1730, 0, (void*)0x08041740 }, { 0x1731, 0, (void*)0x08041794 }, { 0x1732, 0, (void*)0x080417A0 }, - { 0x1733, 0, (void*)0x080417F4 }, { 0x1734, 0, (void*)0x08041848 }, { 0x1735, 0, (void*)0x0804189C }, - { 0x1736, 0, (void*)0x08041900 }, { 0x1737, 0, (void*)0x08041958 }, { 0x1738, 0, (void*)0x080419A8 }, - { 0x1739, 0, (void*)0x080419F4 }, { 0x173A, 0, (void*)0x08041A54 }, { 0x173B, 0, (void*)0x08041AA0 }, - { 0x173C, 0, (void*)0x08041AF8 }, { 0x173D, 0, (void*)0x08041B54 }, { 0x173E, 0, (void*)0x08041BA4 }, - { 0x173F, 0, (void*)0x08041BF4 }, { 0x1740, 0, (void*)0x08041C48 }, { 0x1741, 0, (void*)0x08041CAC }, - { 0x1742, 0, (void*)0x08041D08 }, { 0x1743, 0, (void*)0x08041D68 }, { 0x1744, 0, (void*)0x08041DB4 }, - { 0x1745, 0, (void*)0x08041DF8 }, { 0x1746, 0, (void*)0x08041E54 }, { 0x1747, 0, (void*)0x08041EB0 }, - { 0x1748, 0, (void*)0x08041F2C }, { 0x1749, 0, (void*)0x08041F78 }, { 0x1784, 0, (void*)0x08041FD0 }, - { 0x1785, 0, (void*)0x0804202C }, { 0x1786, 0, (void*)0x08042088 }, { 0x1787, 0, (void*)0x080420E4 }, - { 0x1788, 0, (void*)0x080420F0 }, { 0x1789, 0, (void*)0x0804214C }, { 0x178A, 0, (void*)0x080421B0 }, - { 0x178B, 0, (void*)0x080421F4 }, { 0x178C, 0, (void*)0x0804223C }, { 0x178D, 0, (void*)0x08042288 }, - { 0x178E, 0, (void*)0x080422CC }, { 0x178F, 0, (void*)0x08042314 }, { 0x1798, 0, (void*)0x08042360 }, - { 0x1799, 0, (void*)0x080423AC }, { 0x179A, 0, (void*)0x080423F4 }, { 0x179B, 0, (void*)0x08042440 }, - { 0x17AA, 0, (void*)0x08042490 }, { 0x17AC, 0, (void*)0x08042514 }, { 0x17AD, 0, (void*)0x08042568 }, - { 0x17AE, 0, (void*)0x080425C0 }, { 0x17AF, 0, (void*)0x0804262C }, { 0x1800, 0, (void*)0x080426AC }, - { 0x1801, 0, (void*)0x080426CC }, { 0x1802, 0, (void*)0x0804272C }, { 0x1803, 0, (void*)0x08042754 }, - { 0x1804, 0, (void*)0x08042784 }, { 0x1805, 0, (void*)0x080427E0 }, { 0x1806, 0, (void*)0x08042834 }, - { 0x1807, 0, (void*)0x08042870 }, { 0x1808, 0, (void*)0x080428D0 }, { 0x1809, 0, (void*)0x08042910 }, - { 0x180A, 0, (void*)0x0804293C }, { 0x180B, 0, (void*)0x08042968 }, { 0x180C, 0, (void*)0x08042990 }, - { 0x180D, 0, (void*)0x080429AC }, { 0x180E, 0, (void*)0x08042A04 }, { 0x180F, 0, (void*)0x08042A50 }, - { 0x1810, 0, (void*)0x08042A80 }, { 0x1811, 0, (void*)0x08042AB4 }, { 0x1812, 0, (void*)0x08042AF8 }, - { 0x1813, 0, (void*)0x08042B38 }, { 0x1814, 0, (void*)0x08042B6C }, { 0x1815, 0, (void*)0x08042BAC }, - { 0x1816, 0, (void*)0x08042C04 }, { 0x1817, 0, (void*)0x08042C4C }, { 0x1818, 0, (void*)0x08042C8C }, - { 0x1819, 0, (void*)0x08042CB8 }, { 0x181A, 0, (void*)0x08042CEC }, { 0x181B, 0, (void*)0x08042D28 }, - { 0x181C, 0, (void*)0x08042D34 }, { 0x181D, 0, (void*)0x08042D94 }, { 0x181E, 0, (void*)0x08042DD8 }, - { 0x181F, 0, (void*)0x08042DF0 }, { 0x1820, 0, (void*)0x08042E40 }, { 0x1821, 0, (void*)0x08042E7C }, - { 0x1822, 0, (void*)0x08042EB0 }, { 0x1823, 0, (void*)0x08042EE8 }, { 0x1824, 0, (void*)0x08042F20 }, - { 0x1883, 0, (void*)0x08042F2C }, { 0x1884, 0, (void*)0x08042F60 }, { 0x1885, 0, (void*)0x08042F9C }, - { 0x1886, 0, (void*)0x08043008 }, { 0x1887, 0, (void*)0x08043054 }, { 0x1888, 0, (void*)0x08043094 }, - { 0x1889, 0, (void*)0x080430E4 }, { 0x188A, 0, (void*)0x08043134 }, { 0x188B, 0, (void*)0x08043150 }, - { 0x188C, 0, (void*)0x0804318C }, { 0x188D, 0, (void*)0x080431E8 }, { 0x188E, 0, (void*)0x08043224 }, - { 0x188F, 0, (void*)0x0804326C }, { 0x1890, 0, (void*)0x08043298 }, { 0x1891, 0, (void*)0x080432D8 }, - { 0x1892, 0, (void*)0x0804332C }, { 0x1893, 0, (void*)0x08043378 }, { 0x1901, 0, (void*)0x080433B4 }, - { 0x1902, 0, (void*)0x0804341C }, { 0x1903, 0, (void*)0x08043484 }, { 0x1904, 0, (void*)0x08043508 }, - { 0x1905, 0, (void*)0x08043580 }, { 0x1906, 0, (void*)0x08043610 }, { 0x1907, 0, (void*)0x0804367C }, - { 0x1908, 0, (void*)0x08043710 }, { 0x1909, 0, (void*)0x08043784 }, { 0x190A, 0, (void*)0x0804380C }, - { 0x190B, 0, (void*)0x08043880 }, { 0x190C, 0, (void*)0x080438E8 }, { 0x190D, 0, (void*)0x08043948 }, - { 0x190E, 0, (void*)0x080439C4 }, { 0x190F, 0, (void*)0x08043A20 }, { 0x1910, 0, (void*)0x08043AA0 }, - { 0x1911, 0, (void*)0x08043B24 }, { 0x1912, 0, (void*)0x08043BA8 }, { 0x1913, 0, (void*)0x08043C30 }, - { 0x1914, 0, (void*)0x08043C9C }, { 0x1915, 0, (void*)0x08043CEC }, { 0x1916, 0, (void*)0x08043D50 }, - { 0x1917, 0, (void*)0x08043DD8 }, { 0x1918, 0, (void*)0x08043E40 }, { 0x1919, 0, (void*)0x08043EB0 }, - { 0x191A, 0, (void*)0x08043F24 }, { 0x191B, 0, (void*)0x08043FB0 }, { 0x191C, 0, (void*)0x0804401C }, - { 0x191D, 0, (void*)0x08044098 }, { 0x191E, 0, (void*)0x0804411C }, { 0x191F, 0, (void*)0x08044184 }, - { 0x1921, 0, (void*)0x080441E8 }, { 0x1922, 0, (void*)0x08044258 }, { 0x1923, 0, (void*)0x080442D4 }, - { 0x1924, 0, (void*)0x08044348 }, { 0x1925, 0, (void*)0x080443D0 }, { 0x1926, 0, (void*)0x08044458 }, - { 0x1927, 0, (void*)0x080444DC }, { 0x1928, 0, (void*)0x08044574 }, { 0x1929, 0, (void*)0x080445CC }, - { 0x192A, 0, (void*)0x08044630 }, { 0x192C, 0, (void*)0x080446AC }, { 0x192D, 0, (void*)0x0804471C }, - { 0x192E, 0, (void*)0x08044780 }, { 0x1930, 0, (void*)0x08044808 }, { 0x1931, 0, (void*)0x08044898 }, - { 0x1932, 0, (void*)0x08044910 }, { 0x1933, 0, (void*)0x0804498C }, { 0x1934, 0, (void*)0x08044A04 }, - { 0x1935, 0, (void*)0x08044A94 }, { 0x1937, 0, (void*)0x08044B10 }, { 0x1939, 0, (void*)0x08044B9C }, - { 0x193A, 0, (void*)0x08044C0C }, { 0x193B, 0, (void*)0x08044C18 }, { 0x193C, 0, (void*)0x08044C8C }, - { 0x1942, 0, (void*)0x08044D04 }, { 0x1944, 0, (void*)0x08044D6C }, { 0x1945, 0, (void*)0x08044DCC }, - { 0x1946, 0, (void*)0x08044E48 }, { 0x1947, 0, (void*)0x08044EAC }, { 0x1948, 0, (void*)0x08044F20 }, - { 0x1949, 0, (void*)0x08044F88 }, { 0x194A, 0, (void*)0x08045004 }, { 0x194B, 0, (void*)0x08045084 }, - { 0x194C, 0, (void*)0x080450F4 }, { 0x194D, 0, (void*)0x08045174 }, { 0x1950, 0, (void*)0x080451C8 }, - { 0x1951, 0, (void*)0x08045238 }, { 0x1952, 0, (void*)0x080452A0 }, { 0x1953, 0, (void*)0x08045310 }, - { 0x1954, 0, (void*)0x08045378 }, { 0x1955, 0, (void*)0x080453E8 }, { 0x1956, 0, (void*)0x08045458 }, - { 0x1957, 0, (void*)0x080454CC }, { 0x1958, 0, (void*)0x08045540 }, { 0x1959, 0, (void*)0x080455C4 }, - { 0x195A, 0, (void*)0x0804564C }, { 0x195B, 0, (void*)0x080456AC }, { 0x195C, 0, (void*)0x08045704 }, - { 0x195D, 0, (void*)0x0804576C }, { 0x195E, 0, (void*)0x080457E8 }, { 0x195F, 0, (void*)0x08045838 }, - { 0x1960, 0, (void*)0x0804589C }, { 0x1961, 0, (void*)0x08045918 }, { 0x1962, 0, (void*)0x08045988 }, - { 0x1963, 0, (void*)0x080459E4 }, { 0x1964, 0, (void*)0x08045A24 }, { 0x1B58, 0, (void*)0x08045ACC }, - { 0x1B59, 0, (void*)0x08045ADC }, { 0x1B5A, 0, (void*)0x08045B00 }, { 0x1B5B, 0, (void*)0x08045B20 }, - { 0x1B5C, 0, (void*)0x08045B2C }, { 0x1B5D, 0, (void*)0x08045B58 }, { 0x1B5E, 0, (void*)0x08045B7C }, - { 0x1B5F, 0, (void*)0x08045BAC }, { 0x1B60, 0, (void*)0x08045BD8 }, { 0x1B61, 0, (void*)0x08045BFC }, - { 0x1B62, 0, (void*)0x08045C18 }, { 0x1B63, 0, (void*)0x08045C3C }, { 0x1B64, 0, (void*)0x08045C60 }, - { 0x1B65, 0, (void*)0x08045C90 }, { 0x1B66, 0, (void*)0x08045CC0 }, { 0x1B67, 0, (void*)0x08045CEC }, - { 0x1B6A, 0, (void*)0x08045CF8 }, { 0x1B6B, 0, (void*)0x08045D28 }, { 0x1B72, 0, (void*)0x08045D58 }, - { 0x1B73, 0, (void*)0x08045D8C }, { 0x1B74, 0, (void*)0x08045DB8 }, { 0x1B75, 0, (void*)0x08045DEC }, - { 0x1B76, 0, (void*)0x08045E1C }, { 0x1B77, 0, (void*)0x08045E48 }, { 0x1B78, 0, (void*)0x08045E54 }, - { 0x1B79, 0, (void*)0x08045E80 }, { 0x1B7A, 0, (void*)0x08045EB0 }, { 0x1B7B, 0, (void*)0x08045ED8 }, - { 0x1B7C, 0, (void*)0x08045F08 }, { 0x1B7D, 0, (void*)0x08045F34 }, { 0x1B7E, 0, (void*)0x08045F40 }, - { 0x1B7F, 0, (void*)0x08045F74 }, { 0x1B80, 0, (void*)0x08045FA8 }, { 0x1B81, 0, (void*)0x08045FD4 }, - { 0x1B89, 0, (void*)0x08045FE0 }, { 0x1B8A, 0, (void*)0x08045FF0 }, { 0x1B8B, 0, (void*)0x08046038 }, - { 0x1B8C, 0, (void*)0x08046060 }, { 0x1B8D, 0, (void*)0x08046098 }, { 0x1B8E, 0, (void*)0x080460D4 }, - { 0x1B8F, 0, (void*)0x08046110 }, { 0x1B90, 0, (void*)0x08046150 }, { 0x1B91, 0, (void*)0x0804618C }, - { 0x1B92, 0, (void*)0x080461CC }, { 0x1B93, 0, (void*)0x08046208 }, { 0x1B94, 0, (void*)0x0804622C }, - { 0x1B95, 0, (void*)0x0804626C }, { 0x1B96, 0, (void*)0x080462A8 }, { 0x1B98, 0, (void*)0x080462B4 }, - { 0x1B9E, 0, (void*)0x08046300 }, { 0x1B9F, 0, (void*)0x08046374 }, { 0x1BA0, 0, (void*)0x080463FC }, - { 0x1BA1, 0, (void*)0x08046480 }, { 0x1BA2, 0, (void*)0x08046594 }, { 0x1BA4, 0, (void*)0x080465C4 }, - { 0x1BA5, 0, (void*)0x08046654 }, { 0x1BA6, 0, (void*)0x08046684 }, { 0x1BA7, 0, (void*)0x080466D4 }, - { 0x1BA8, 0, (void*)0x08046760 }, { 0x1BAC, 0, (void*)0x080467E8 }, { 0x1BB2, 0, (void*)0x08046848 }, - { 0x1BB3, 0, (void*)0x08046888 }, { 0x1BB4, 0, (void*)0x080468C4 }, { 0x1BB5, 0, (void*)0x08046904 }, - { 0x1BB6, 0, (void*)0x08046944 }, { 0x1C00, 0, (void*)0x08046984 }, { 0x1C01, 0, (void*)0x08046A4C }, - { 0x1C02, 0, (void*)0x08046AB8 }, { 0x1C03, 0, (void*)0x08046BA8 }, { 0x1C04, 0, (void*)0x08046C10 }, - { 0x1C05, 0, (void*)0x08046D68 }, { 0x1C06, 0, (void*)0x08046E44 }, { 0x1C07, 0, (void*)0x08046EAC }, - { 0x1C08, 0, (void*)0x08046F0C }, { 0x1C09, 0, (void*)0x08046F5C }, { 0x1C0A, 0, (void*)0x08046F94 }, - { 0x1C0B, 0, (void*)0x08047014 }, { 0x1C0C, 0, (void*)0x080470D4 }, { 0x1C0D, 0, (void*)0x08047118 }, - { 0x1C0E, 0, (void*)0x08047130 }, { 0x1C0F, 0, (void*)0x08047148 }, { 0x1C10, 0, (void*)0x08047164 }, - { 0x1C11, 0, (void*)0x0804717C }, { 0x1C12, 0, (void*)0x0804719C }, { 0x1C13, 0, (void*)0x080471BC }, - { 0x1C14, 0, (void*)0x080471D4 }, { 0x1C15, 0, (void*)0x080471F0 }, { 0x1C16, 0, (void*)0x08047214 }, - { 0x1C17, 0, (void*)0x0804730C }, { 0x1C18, 0, (void*)0x0804734C }, { 0x1D00, 0, (void*)0x080473A4 }, - { 0x1D01, 0, (void*)0x08047414 }, { 0x1D02, 0, (void*)0x08047524 }, { 0x1D03, 0, (void*)0x0804758C }, - { 0x1D04, 0, (void*)0x08047644 }, { 0x1D05, 0, (void*)0x08047678 }, { 0x1D06, 0, (void*)0x080476D0 }, - { 0x1D07, 0, (void*)0x080476F8 }, { 0x1D08, 0, (void*)0x08047728 }, { 0x1D09, 0, (void*)0x08047788 }, - { 0x1D0A, 0, (void*)0x080477C0 }, { 0x1D0B, 0, (void*)0x080477F4 }, { 0x1D0C, 0, (void*)0x08047808 }, - { 0x1D0D, 0, (void*)0x08047820 }, { 0x1D11, 0, (void*)0x08047844 }, { 0x1D12, 0, (void*)0x08047890 }, - { 0x1D13, 0, (void*)0x080478D8 }, { 0x1D14, 0, (void*)0x08047920 }, { 0x1D15, 0, (void*)0x0804796C }, - { 0x1D16, 0, (void*)0x080479B4 }, { 0x1D17, 0, (void*)0x080479FC }, { 0x1F40, 0, (void*)0x08047A20 }, - { 0x1F41, 0, (void*)0x08047ABC }, { 0x1F42, 0, (void*)0x08047B20 }, { 0x1F43, 0, (void*)0x08047B94 }, - { 0x1F44, 0, (void*)0x08047BD8 }, { 0x1F45, 0, (void*)0x08047C40 }, { 0x1F46, 0, (void*)0x08047CB4 }, - { 0x1F47, 0, (void*)0x08047D1C }, { 0x1F48, 0, (void*)0x08047D88 }, { 0x1F49, 0, (void*)0x08047DA8 }, - { 0x1F4A, 0, (void*)0x08047E48 }, { 0x1F4B, 0, (void*)0x08047F30 }, { 0x1F4C, 0, (void*)0x08047F88 }, - { 0x1F4D, 0, (void*)0x08048014 }, { 0x1F4E, 0, (void*)0x080480E0 }, { 0x1F4F, 0, (void*)0x0804819C }, - { 0x1F50, 0, (void*)0x08048280 }, { 0x1F51, 0, (void*)0x080482E4 }, { 0x1F52, 0, (void*)0x0804833C }, - { 0x1F53, 0, (void*)0x080483B8 }, { 0x1F54, 0, (void*)0x08048430 }, { 0x1F55, 0, (void*)0x080484AC }, - { 0x1F56, 0, (void*)0x080484F8 }, { 0x1F5F, 0, (void*)0x0804857C }, { 0x1F60, 0, (void*)0x0804859C }, - { 0x1F61, 0, (void*)0x080485D4 }, { 0x1F62, 0, (void*)0x08048604 }, { 0x1F63, 0, (void*)0x0804862C }, - { 0x1F64, 0, (void*)0x0804866C }, { 0x1F65, 0, (void*)0x080486A4 }, { 0x1F66, 0, (void*)0x080486E0 }, - { 0x1F67, 0, (void*)0x08048708 }, { 0x1F68, 0, (void*)0x08048774 }, { 0x1F69, 0, (void*)0x080487A4 }, - { 0x1F6A, 0, (void*)0x080487E0 }, { 0x1F6B, 0, (void*)0x08048810 }, { 0x1F6C, 0, (void*)0x08048864 }, - { 0x1F6D, 0, (void*)0x08048898 }, { 0x1F6E, 0, (void*)0x08048960 }, { 0x1F6F, 0, (void*)0x08048990 }, - { 0x1F70, 0, (void*)0x080489E8 }, { 0x1F71, 0, (void*)0x08048A44 }, { 0x1F72, 0, (void*)0x08048AB8 }, - { 0x1F73, 0, (void*)0x08048AE8 }, { 0x1F74, 0, (void*)0x08048B94 }, { 0x1F75, 0, (void*)0x08048BB0 }, - { 0x1FA4, 0, (void*)0x08048BD8 }, { 0x1FA5, 0, (void*)0x08048C14 }, { 0x1FA6, 0, (void*)0x08048CF8 }, - { 0x1FA7, 0, (void*)0x08048D40 }, { 0x1FA8, 0, (void*)0x08048D88 }, { 0x1FA9, 0, (void*)0x08048DF4 }, - { 0x1FAA, 0, (void*)0x08048E68 }, { 0x1FAB, 0, (void*)0x08048EE0 }, { 0x1FAC, 0, (void*)0x08048FB4 }, - { 0x1FAD, 0, (void*)0x08049034 }, { 0x1FAE, 0, (void*)0x08049068 }, { 0x1FAF, 0, (void*)0x080491B0 }, - { 0x1FB0, 0, (void*)0x0804927C }, { 0x1FB1, 0, (void*)0x080492C8 }, { 0x1FB2, 0, (void*)0x08049318 }, - { 0x1FB3, 0, (void*)0x08049384 }, { 0x1FB4, 0, (void*)0x08049424 }, { 0x1FB5, 0, (void*)0x0804951C }, - { 0x1FB6, 0, (void*)0x08049558 }, { 0x1FB7, 0, (void*)0x08049598 }, { 0x1FB8, 0, (void*)0x080495B8 }, - { 0x1FB9, 0, (void*)0x080495D0 }, { 0x1FBA, 0, (void*)0x080495E8 }, { 0x1FBB, 0, (void*)0x08049614 }, - { 0x1FBC, 0, (void*)0x0804963C }, { 0x1FBD, 0, (void*)0x08049688 }, { 0x1FBE, 0, (void*)0x080496DC }, - { 0x1FBF, 0, (void*)0x08049758 }, { 0x1FC0, 0, (void*)0x080497BC }, { 0x1FC1, 0, (void*)0x080497E4 }, - { 0x1FC2, 0, (void*)0x0804982C }, { 0x1FC3, 0, (void*)0x080498A0 }, { 0x1FC4, 0, (void*)0x08049920 }, - { 0x1FC5, 0, (void*)0x08049940 }, { 0x1FC6, 0, (void*)0x08049A0C }, { 0x1FC7, 0, (void*)0x08049A38 }, - { 0x1FC8, 0, (void*)0x08049AA0 }, { 0x1FC9, 0, (void*)0x08049AB8 }, { 0x1FCA, 0, (void*)0x08049AF0 }, - { 0x1FCB, 0, (void*)0x08049B74 }, { 0x1FCC, 0, (void*)0x08049BD0 }, { 0x1FCD, 0, (void*)0x08049C34 }, - { 0x1FCE, 0, (void*)0x08049D14 }, { 0x1FCF, 0, (void*)0x08049D70 }, { 0x1FD0, 0, (void*)0x08049DAC }, - { 0x1FD1, 0, (void*)0x08049E08 }, { 0x1FD2, 0, (void*)0x08049E24 }, { 0x1FD3, 0, (void*)0x08049E44 }, - { 0x1FD4, 0, (void*)0x08049E88 }, { 0x1FD5, 0, (void*)0x08049EB8 }, { 0x1FD6, 0, (void*)0x08049F00 }, - { 0x1FD7, 0, (void*)0x08049F3C }, { 0x1FD8, 0, (void*)0x08049F90 }, { 0x1FD9, 0, (void*)0x08049FC4 }, - { 0x1FDA, 0, (void*)0x0804A018 }, { 0x1FDB, 0, (void*)0x0804A050 }, { 0x1FDC, 0, (void*)0x0804A0BC }, - { 0x1FDD, 0, (void*)0x0804A0F0 }, { 0x1FDE, 0, (void*)0x0804A11C }, { 0x1FDF, 0, (void*)0x0804A14C }, - { 0x1FE0, 0, (void*)0x0804A1A0 }, { 0x1FE1, 0, (void*)0x0804A1D4 }, { 0x1FE2, 0, (void*)0x0804A210 }, - { 0x1FE3, 0, (void*)0x0804A244 }, { 0x1FE4, 0, (void*)0x0804A290 }, { 0x1FE5, 0, (void*)0x0804A2C8 }, - { 0x1FE6, 0, (void*)0x0804A334 }, { 0x1FE7, 0, (void*)0x0804A36C }, { 0x1FE8, 0, (void*)0x0804A3EC }, - { 0x1FE9, 0, (void*)0x0804A420 }, { 0x1FEA, 0, (void*)0x0804A484 }, { 0x1FEB, 0, (void*)0x0804A4B8 }, - { 0x1FEC, 0, (void*)0x0804A51C }, { 0x1FED, 0, (void*)0x0804A554 }, { 0x1FEE, 0, (void*)0x0804A59C }, - { 0x1FEF, 0, (void*)0x0804A5D0 }, { 0x1FF0, 0, (void*)0x0804A620 }, { 0x1FF1, 0, (void*)0x0804A658 }, - { 0x1FF2, 0, (void*)0x0804A6C0 }, { 0x1FF3, 0, (void*)0x0804A6F4 }, { 0x1FF4, 0, (void*)0x0804A74C }, - { 0x1FF5, 0, (void*)0x0804A788 }, { 0x1FF6, 0, (void*)0x0804A800 }, { 0x1FF7, 0, (void*)0x0804A834 }, - { 0x1FF8, 0, (void*)0x0804A888 }, { 0x1FF9, 0, (void*)0x0804A8B8 }, { 0x1FFA, 0, (void*)0x0804A908 }, - { 0x1FFB, 0, (void*)0x0804A940 }, { 0x1FFC, 0, (void*)0x0804A970 }, { 0x1FFD, 0, (void*)0x0804A9A4 }, - { 0x1FFE, 0, (void*)0x0804AA00 }, { 0x1FFF, 0, (void*)0x0804AA60 }, { 0x2000, 0, (void*)0x0804AAA0 }, - { 0x2001, 0, (void*)0x0804AACC }, { 0x2002, 0, (void*)0x0804AB00 }, { 0x2003, 0, (void*)0x0804AB60 }, - { 0x2004, 0, (void*)0x0804ABA0 }, { 0x2005, 0, (void*)0x0804ACE0 }, { 0x2006, 0, (void*)0x0804ADB4 }, - { 0x2007, 0, (void*)0x0804AE8C }, { 0x2008, 0, (void*)0x0804AEE0 }, { 0x2009, 0, (void*)0x0804AEF8 }, - { 0x200A, 0, (void*)0x0804AF10 }, { 0x200B, 0, (void*)0x0804AFAC }, { 0x200C, 0, (void*)0x0804B024 }, - { 0x200D, 0, (void*)0x0804B058 }, { 0x200E, 0, (void*)0x0804B0D0 }, { 0x200F, 0, (void*)0x0804B144 }, - { 0x2010, 0, (void*)0x0804B168 }, { 0x2011, 0, (void*)0x0804B1B4 }, { 0x2012, 0, (void*)0x0804B1F8 }, - { 0x2013, 0, (void*)0x0804B260 }, { 0x2014, 0, (void*)0x0804B298 }, { 0x2015, 0, (void*)0x0804B300 }, - { 0x2016, 0, (void*)0x0804B338 }, { 0x2017, 0, (void*)0x0804B350 }, { 0x201D, 0, (void*)0x0804B3B0 }, - { 0x201E, 0, (void*)0x0804B3F8 }, { 0x201F, 0, (void*)0x0804B508 }, { 0x2020, 0, (void*)0x0804B58C }, - { 0x2021, 0, (void*)0x0804B5F8 }, { 0x2022, 0, (void*)0x0804B68C }, { 0x2023, 0, (void*)0x0804B6E4 }, - { 0x2024, 0, (void*)0x0804B6F0 }, { 0x2026, 0, (void*)0x0804B6FC }, { 0x2027, 0, (void*)0x0804B71C }, - { 0x2028, 0, (void*)0x0804B744 }, { 0x2029, 0, (void*)0x0804B758 }, { 0x202A, 0, (void*)0x0804B770 }, - { 0x202B, 0, (void*)0x0804B7C4 }, { 0x202C, 0, (void*)0x0804B81C }, { 0x202D, 0, (void*)0x0804B860 }, - { 0x202E, 0, (void*)0x0804B8A8 }, { 0x202F, 0, (void*)0x0804B908 }, { 0x2030, 0, (void*)0x0804B93C }, - { 0x2031, 0, (void*)0x0804B9B8 }, { 0x2032, 0, (void*)0x0804BA20 }, { 0x2033, 0, (void*)0x0804BA9C }, - { 0x2034, 0, (void*)0x0804BAEC }, { 0x2035, 0, (void*)0x0804BB34 }, { 0x2036, 0, (void*)0x0804BB7C }, - { 0x2037, 0, (void*)0x0804BBAC }, { 0x2038, 0, (void*)0x0804BBDC }, { 0x2039, 0, (void*)0x0804BC20 }, - { 0x203A, 0, (void*)0x0804BC98 }, { 0x203B, 0, (void*)0x0804BCF0 }, { 0x203C, 0, (void*)0x0804BD40 }, - { 0x203D, 0, (void*)0x0804BD5C }, { 0x203E, 0, (void*)0x0804BDAC }, { 0x203F, 0, (void*)0x0804BE24 }, - { 0x2040, 0, (void*)0x0804BE4C }, { 0x2041, 0, (void*)0x0804BEB8 }, { 0x2042, 0, (void*)0x0804BEEC }, - { 0x2043, 0, (void*)0x0804BF08 }, { 0x2044, 0, (void*)0x0804BF38 }, { 0x2045, 0, (void*)0x0804BF74 }, - { 0x2046, 0, (void*)0x0804BFB4 }, { 0x2047, 0, (void*)0x0804C028 }, { 0x2048, 0, (void*)0x0804C08C }, - { 0x2049, 0, (void*)0x0804C0BC }, { 0x204A, 0, (void*)0x0804C0D8 }, { 0x204B, 0, (void*)0x0804C114 }, - { 0x204C, 0, (void*)0x0804C144 }, { 0x204D, 0, (void*)0x0804C180 }, { 0x204E, 0, (void*)0x0804C204 }, - { 0x206C, 0, (void*)0x0804C264 }, { 0x206D, 0, (void*)0x0804C2A8 }, { 0x206E, 0, (void*)0x0804C2F8 }, - { 0x206F, 0, (void*)0x0804C338 }, { 0x2070, 0, (void*)0x0804C384 }, { 0x2076, 0, (void*)0x0804C390 }, - { 0x2077, 0, (void*)0x0804C3C0 }, { 0x2078, 0, (void*)0x0804C404 }, { 0x2079, 0, (void*)0x0804C480 }, - { 0x2080, 0, (void*)0x0804C4C4 }, { 0x2081, 0, (void*)0x0804C5B4 }, { 0x2082, 0, (void*)0x0804C5FC }, - { 0x2083, 0, (void*)0x0804C630 }, { 0x208A, 0, (void*)0x0804C674 }, { 0x208B, 0, (void*)0x0804C6BC }, - { 0x208C, 0, (void*)0x0804C708 }, { 0x208D, 0, (void*)0x0804C7B4 }, { 0x208E, 0, (void*)0x0804C7FC }, - { 0x2093, 0, (void*)0x0804C8A4 }, { 0x2094, 0, (void*)0x0804C8C0 }, { 0x2095, 0, (void*)0x0804C8E8 }, - { 0x20B0, 0, (void*)0x0804C920 }, { 0x20B1, 0, (void*)0x0804C984 }, { 0x20B2, 0, (void*)0x0804CA38 }, - { 0x20B3, 0, (void*)0x0804CB34 }, { 0x20B4, 0, (void*)0x0804CC18 }, { 0x20B5, 0, (void*)0x0804CD10 }, - { 0x20B6, 0, (void*)0x0804CDD4 }, { 0x20B7, 0, (void*)0x0804CE8C }, { 0x20B8, 0, (void*)0x0804CF48 }, - { 0x20B9, 0, (void*)0x0804CFA4 }, { 0x20BA, 0, (void*)0x0804D018 }, { 0x20BB, 0, (void*)0x0804D084 }, - { 0x20BC, 0, (void*)0x0804D0EC }, { 0x20BD, 0, (void*)0x0804D158 }, { 0x20BE, 0, (void*)0x0804D1C0 }, - { 0x20BF, 0, (void*)0x0804D230 }, { 0x20C0, 0, (void*)0x0804D294 }, { 0x20C1, 0, (void*)0x0804D300 }, - { 0x20C2, 0, (void*)0x0804D380 }, { 0x20C3, 0, (void*)0x0804D3F8 }, { 0x20C4, 0, (void*)0x0804D460 }, - { 0x20C5, 0, (void*)0x0804D4AC }, { 0x20C6, 0, (void*)0x0804D52C }, { 0x20C7, 0, (void*)0x0804D590 }, - { 0x20D0, 0, (void*)0x0804D5FC }, { 0x20D1, 0, (void*)0x0804D654 }, { 0x20D2, 0, (void*)0x0804D6C8 }, - { 0x20D4, 0, (void*)0x0804D6EC }, { 0x20D5, 0, (void*)0x0804D75C }, { 0x20D6, 0, (void*)0x0804D7B4 }, - { 0x20D7, 0, (void*)0x0804D834 }, { 0x20D8, 0, (void*)0x0804D8B0 }, { 0x20D9, 0, (void*)0x0804D93C }, - { 0x20DA, 0, (void*)0x0804D99C }, { 0x20DB, 0, (void*)0x0804D9FC }, { 0x20DC, 0, (void*)0x0804DA74 }, - { 0x20DD, 0, (void*)0x0804DB20 }, { 0x20DE, 0, (void*)0x0804DBB0 }, { 0x20DF, 0, (void*)0x0804DC18 }, - { 0x20E0, 0, (void*)0x0804DC90 }, { 0x20E1, 0, (void*)0x0804DCFC }, { 0x20E2, 0, (void*)0x0804DD84 }, - { 0x20E3, 0, (void*)0x0804DE0C }, { 0x20E4, 0, (void*)0x0804DEA0 }, { 0x20E5, 0, (void*)0x0804DF10 }, - { 0x20E6, 0, (void*)0x0804DF78 }, { 0x20E7, 0, (void*)0x0804DFEC }, { 0x20F3, 0, (void*)0x0804E05C }, - { 0x20F7, 0, (void*)0x0804E0C0 }, { 0x20F8, 0, (void*)0x0804E134 }, { 0x20F9, 0, (void*)0x0804E1AC }, - { 0x2103, 0, (void*)0x0804E220 }, { 0x2104, 0, (void*)0x0804E288 }, { 0x2105, 0, (void*)0x0804E2CC }, - { 0x2106, 0, (void*)0x0804E320 }, { 0x2107, 0, (void*)0x0804E364 }, { 0x2108, 0, (void*)0x0804E3BC }, - { 0x2109, 0, (void*)0x0804E408 }, { 0x210A, 0, (void*)0x0804E458 }, { 0x210B, 0, (void*)0x0804E4B0 }, - { 0x210C, 0, (void*)0x0804E4EC }, { 0x210D, 0, (void*)0x0804E52C }, { 0x210E, 0, (void*)0x0804E578 }, - { 0x210F, 0, (void*)0x0804E5D0 }, { 0x2110, 0, (void*)0x0804E618 }, { 0x2111, 0, (void*)0x0804E660 }, - { 0x2112, 0, (void*)0x0804E6BC }, { 0x2113, 0, (void*)0x0804E70C }, { 0x2114, 0, (void*)0x0804E75C }, - { 0x2115, 0, (void*)0x0804E7A8 }, { 0x2116, 0, (void*)0x0804E7F0 }, { 0x2134, 0, (void*)0x0804E83C }, - { 0x2135, 0, (void*)0x0804E880 }, { 0x2136, 0, (void*)0x0804E8CC }, { 0x2137, 0, (void*)0x0804E91C }, - { 0x2138, 0, (void*)0x0804E96C }, { 0x2139, 0, (void*)0x0804E9B4 }, { 0x213A, 0, (void*)0x0804E9FC }, - { 0x213B, 0, (void*)0x0804EA38 }, { 0x213C, 0, (void*)0x0804EA88 }, { 0x213D, 0, (void*)0x0804EAD0 }, - { 0x213E, 0, (void*)0x0804EB28 }, { 0x213F, 0, (void*)0x0804EB80 }, { 0x2140, 0, (void*)0x0804EBD0 }, - { 0x2141, 0, (void*)0x0804EC1C }, { 0x2142, 0, (void*)0x0804EC60 }, { 0x2143, 0, (void*)0x0804ECAC }, - { 0x2144, 0, (void*)0x0804ECF0 }, { 0x2145, 0, (void*)0x0804ED40 }, { 0x2146, 0, (void*)0x0804ED88 }, - { 0x2147, 0, (void*)0x0804EDDC }, { 0x2152, 0, (void*)0x0804EE34 }, { 0x2153, 0, (void*)0x0804EE78 }, - { 0x2154, 0, (void*)0x0804EECC }, { 0x2156, 0, (void*)0x0804EF1C }, { 0x2157, 0, (void*)0x0804EF64 }, - { 0x2158, 0, (void*)0x0804EFC4 }, { 0x2159, 0, (void*)0x0804F014 }, { 0x215A, 0, (void*)0x0804F05C }, - { 0x215B, 0, (void*)0x0804F0C0 }, { 0x215D, 0, (void*)0x0804F124 }, { 0x215E, 0, (void*)0x0804F178 }, - { 0x215F, 0, (void*)0x0804F184 }, { 0x2160, 0, (void*)0x0804F1D8 }, { 0x2161, 0, (void*)0x0804F234 }, - { 0x2162, 0, (void*)0x0804F298 }, { 0x2163, 0, (void*)0x0804F2A4 }, { 0x2164, 0, (void*)0x0804F2F8 }, - { 0x2165, 0, (void*)0x0804F358 }, { 0x2166, 0, (void*)0x0804F3B0 }, { 0x2167, 0, (void*)0x0804F400 }, - { 0x2168, 0, (void*)0x0804F458 }, { 0x2169, 0, (void*)0x0804F4B0 }, { 0x216A, 0, (void*)0x0804F504 }, - { 0x216B, 0, (void*)0x0804F554 }, { 0x216C, 0, (void*)0x0804F5A0 }, { 0x216D, 0, (void*)0x0804F5F8 }, - { 0x216E, 0, (void*)0x0804F658 }, { 0x216F, 0, (void*)0x0804F6B8 }, { 0x2170, 0, (void*)0x0804F710 }, - { 0x2171, 0, (void*)0x0804F764 }, { 0x2172, 0, (void*)0x0804F7BC }, { 0x2173, 0, (void*)0x0804F814 }, - { 0x2174, 0, (void*)0x0804F870 }, { 0x2198, 0, (void*)0x0804F8CC }, { 0x2199, 0, (void*)0x0804F920 }, - { 0x219A, 0, (void*)0x0804F978 }, { 0x219B, 0, (void*)0x0804F9D0 }, { 0x219C, 0, (void*)0x0804FA2C }, - { 0x219D, 0, (void*)0x0804FA80 }, { 0x219E, 0, (void*)0x0804FAD0 }, { 0x219F, 0, (void*)0x0804FB28 }, - { 0x21A0, 0, (void*)0x0804FB80 }, { 0x21A1, 0, (void*)0x0804FBD8 }, { 0x21A2, 0, (void*)0x0804FC30 }, - { 0x21A3, 0, (void*)0x0804FC88 }, { 0x21A4, 0, (void*)0x0804FCD8 }, { 0x21A5, 0, (void*)0x0804FD30 }, - { 0x21A6, 0, (void*)0x0804FD84 }, { 0x21A7, 0, (void*)0x0804FDDC }, { 0x21A8, 0, (void*)0x0804FE34 }, - { 0x21A9, 0, (void*)0x0804FE88 }, { 0x21AA, 0, (void*)0x0804FED8 }, { 0x21AB, 0, (void*)0x0804FF30 }, - { 0x21AC, 0, (void*)0x0804FF84 }, { 0x21AD, 0, (void*)0x0804FFDC }, { 0x21AE, 0, (void*)0x08050038 }, - { 0x21AF, 0, (void*)0x08050094 }, { 0x21B0, 0, (void*)0x080500EC }, { 0x21B1, 0, (void*)0x08050140 }, - { 0x21B2, 0, (void*)0x08050198 }, { 0x21B3, 0, (void*)0x080501F4 }, { 0x21B4, 0, (void*)0x0805024C }, - { 0x21B5, 0, (void*)0x080502A4 }, { 0x21B6, 0, (void*)0x080502F8 }, { 0x21B7, 0, (void*)0x08050350 }, - { 0x21B8, 0, (void*)0x080503A8 }, { 0x21B9, 0, (void*)0x08050400 }, { 0x21BA, 0, (void*)0x0805045C }, - { 0x21CA, 0, (void*)0x080504AC }, { 0x21CB, 0, (void*)0x080504EC }, { 0x21CC, 0, (void*)0x08050528 }, - { 0x21CD, 0, (void*)0x08050580 }, { 0x21CE, 0, (void*)0x080505C8 }, { 0x21CF, 0, (void*)0x08050604 }, - { 0x21D0, 0, (void*)0x08050648 }, { 0x21D1, 0, (void*)0x08050680 }, { 0x21D2, 0, (void*)0x080506CC }, - { 0x21D3, 0, (void*)0x08050700 }, { 0x21D4, 0, (void*)0x0805075C }, { 0x21D5, 0, (void*)0x080507A8 }, - { 0x21D6, 0, (void*)0x080507F0 }, { 0x21D7, 0, (void*)0x08050840 }, { 0x21D8, 0, (void*)0x08050884 }, - { 0x21D9, 0, (void*)0x080508CC }, { 0x21DA, 0, (void*)0x08050910 }, { 0x21DB, 0, (void*)0x0805094C }, - { 0x21DC, 0, (void*)0x08050998 }, { 0x21DD, 0, (void*)0x080509D0 }, { 0x21FC, 0, (void*)0x08050A20 }, - { 0x21FD, 0, (void*)0x08050A50 }, { 0x21FE, 0, (void*)0x08050A74 }, { 0x21FF, 0, (void*)0x08050ABC }, - { 0x2200, 0, (void*)0x08050ADC }, { 0x2201, 0, (void*)0x08050AF0 }, { 0x2202, 0, (void*)0x08050B0C }, - { 0x2203, 0, (void*)0x08050B44 }, { 0x2204, 0, (void*)0x08050B74 }, { 0x2205, 0, (void*)0x08050B98 }, - { 0x2206, 0, (void*)0x08050BCC }, { 0x2207, 0, (void*)0x08050BF8 }, { 0x2208, 0, (void*)0x08050C48 }, - { 0x2209, 0, (void*)0x08050CB0 }, { 0x220A, 0, (void*)0x08050CC4 }, { 0x220B, 0, (void*)0x08050CE0 }, - { 0x220C, 0, (void*)0x08050D10 }, { 0x220D, 0, (void*)0x08050D44 }, { 0x220E, 0, (void*)0x08050D98 }, - { 0x220F, 0, (void*)0x08050DE0 }, { 0x2210, 0, (void*)0x08050E24 }, { 0x2211, 0, (void*)0x08050E44 }, - { 0x2212, 0, (void*)0x08050E78 }, { 0x2213, 0, (void*)0x08050E8C }, { 0x2214, 0, (void*)0x08050ECC }, - { 0x2215, 0, (void*)0x08050F14 }, { 0x2216, 0, (void*)0x08050F44 }, { 0x2217, 0, (void*)0x08050F6C }, - { 0x2218, 0, (void*)0x08050FB4 }, { 0x2219, 0, (void*)0x08050FDC }, { 0x221A, 0, (void*)0x0805100C }, - { 0x221B, 0, (void*)0x08051034 }, { 0x221C, 0, (void*)0x08051054 }, { 0x221D, 0, (void*)0x08051080 }, - { 0x221E, 0, (void*)0x080510A0 }, { 0x221F, 0, (void*)0x080510DC }, { 0x2220, 0, (void*)0x08051104 }, - { 0x2221, 0, (void*)0x08051138 }, { 0x2222, 0, (void*)0x0805114C }, { 0x2223, 0, (void*)0x0805117C }, - { 0x2224, 0, (void*)0x080511A8 }, { 0x2225, 0, (void*)0x080511E4 }, { 0x2226, 0, (void*)0x0805122C }, - { 0x2227, 0, (void*)0x08051258 }, { 0x2228, 0, (void*)0x080512AC }, { 0x2229, 0, (void*)0x080512D8 }, - { 0x222A, 0, (void*)0x08051338 }, { 0x222B, 0, (void*)0x08051374 }, { 0x2328, 0, (void*)0x080513C4 }, - { 0x2329, 0, (void*)0x08051410 }, { 0x232A, 0, (void*)0x08051454 }, { 0x232B, 0, (void*)0x080514B4 }, - { 0x232C, 0, (void*)0x08051514 }, { 0x232D, 0, (void*)0x08051564 }, { 0x232E, 0, (void*)0x080515A8 }, - { 0x232F, 0, (void*)0x080515E4 }, { 0x2330, 0, (void*)0x08051630 }, { 0x2331, 0, (void*)0x08051680 }, - { 0x2332, 0, (void*)0x08051700 }, { 0x2333, 0, (void*)0x08051750 }, { 0x2334, 0, (void*)0x080517AC }, - { 0x2335, 0, (void*)0x08051814 }, { 0x2336, 0, (void*)0x08051868 }, { 0x2337, 0, (void*)0x080518C8 }, - { 0x2338, 0, (void*)0x08051914 }, { 0x2339, 0, (void*)0x08051948 }, { 0x233A, 0, (void*)0x080519A4 }, - { 0x233B, 0, (void*)0x080519D8 }, { 0x233C, 0, (void*)0x08051A10 }, { 0x233D, 0, (void*)0x08051A70 }, - { 0x233E, 0, (void*)0x08051AA4 }, { 0x233F, 0, (void*)0x08051ADC }, { 0x2340, 0, (void*)0x08051B10 }, - { 0x2341, 0, (void*)0x08051B54 }, { 0x2342, 0, (void*)0x08051BC8 }, { 0x2343, 0, (void*)0x08051C38 }, - { 0x2344, 0, (void*)0x08051C70 }, { 0x2345, 0, (void*)0x08051CC0 }, { 0x2346, 0, (void*)0x08051CFC }, - { 0x2347, 0, (void*)0x08051D24 }, { 0x2348, 0, (void*)0x08051DA4 }, { 0x2349, 0, (void*)0x08051DE4 }, - { 0x234A, 0, (void*)0x08051E44 }, { 0x234B, 0, (void*)0x08051E84 }, { 0x234C, 0, (void*)0x08051EA4 }, - { 0x234D, 0, (void*)0x08051EC4 }, { 0x234E, 0, (void*)0x08051F04 }, { 0x234F, 0, (void*)0x08051F30 }, - { 0x2350, 0, (void*)0x08051F48 }, { 0x2351, 0, (void*)0x08051F7C }, { 0x2352, 0, (void*)0x08051FA8 }, - { 0x2353, 0, (void*)0x08051FC0 }, { 0x2354, 0, (void*)0x08051FE4 }, { 0x2355, 0, (void*)0x08052004 }, - { 0x2356, 0, (void*)0x08052020 }, { 0x2357, 0, (void*)0x08052048 }, { 0x2358, 0, (void*)0x080520AC }, - { 0x2359, 0, (void*)0x080520DC }, { 0x235A, 0, (void*)0x08052104 }, { 0x235B, 0, (void*)0x08052138 }, - { 0x235C, 0, (void*)0x0805215C }, { 0x235D, 0, (void*)0x08052188 }, { 0x235E, 0, (void*)0x080522B4 }, - { 0x235F, 0, (void*)0x080522DC }, { 0x2360, 0, (void*)0x08052334 }, { 0x2361, 0, (void*)0x080523A8 }, - { 0x2362, 0, (void*)0x08052400 }, { 0x2363, 0, (void*)0x08052450 }, { 0x2364, 0, (void*)0x0805250C }, - { 0x2365, 0, (void*)0x08052644 }, { 0x2366, 0, (void*)0x080526C0 }, { 0x2367, 0, (void*)0x08052718 }, - { 0x2368, 0, (void*)0x080527E4 }, { 0x2369, 0, (void*)0x080528E0 }, { 0x236A, 0, (void*)0x08052930 }, - { 0x236B, 0, (void*)0x08052A04 }, { 0x236C, 0, (void*)0x08052A40 }, { 0x236D, 0, (void*)0x08052A8C }, - { 0x236E, 0, (void*)0x08052ABC }, { 0x236F, 0, (void*)0x08052AD8 }, { 0x2370, 0, (void*)0x08052B34 }, - { 0x2371, 0, (void*)0x08052B64 }, { 0x2372, 0, (void*)0x08052BE0 }, { 0x2373, 0, (void*)0x08052BF8 }, - { 0x2374, 0, (void*)0x08052C3C }, { 0x2375, 0, (void*)0x08052C80 }, { 0x2376, 0, (void*)0x08052CE4 }, - { 0x2377, 0, (void*)0x08052D08 }, { 0x2378, 0, (void*)0x08052D54 }, { 0x2710, 0, (void*)0x08052D8C }, - { 0x2711, 0, (void*)0x08052E54 }, { 0x2712, 0, (void*)0x08052EA4 }, { 0x2713, 0, (void*)0x08053008 }, - { 0x2714, 0, (void*)0x0805305C }, { 0x2715, 0, (void*)0x080531A0 }, { 0x2716, 0, (void*)0x08053220 }, - { 0x2717, 0, (void*)0x08053284 }, { 0x2718, 0, (void*)0x080532BC }, { 0x2719, 0, (void*)0x08053300 }, - { 0x271A, 0, (void*)0x0805332C }, { 0x271B, 0, (void*)0x08053424 }, { 0x271C, 0, (void*)0x080534AC }, - { 0x271D, 0, (void*)0x08053524 }, { 0x271E, 0, (void*)0x0805358C }, { 0x271F, 0, (void*)0x08053608 }, - { 0x2720, 0, (void*)0x0805367C }, { 0x2721, 0, (void*)0x08053718 }, { 0x2722, 0, (void*)0x0805374C }, - { 0x2723, 0, (void*)0x080537A8 }, { 0x2724, 0, (void*)0x080537F4 }, { 0x2725, 0, (void*)0x08053850 }, - { 0x2726, 0, (void*)0x080538A8 }, { 0x2727, 0, (void*)0x08053914 }, { 0x2728, 0, (void*)0x08053974 }, - { 0x2729, 0, (void*)0x08053A34 }, { 0x272A, 0, (void*)0x08053A4C }, { 0x272B, 0, (void*)0x08053A90 }, - { 0x272C, 0, (void*)0x08053AB0 }, { 0x272D, 0, (void*)0x08053AF4 }, { 0x272E, 0, (void*)0x08053B3C }, - { 0x272F, 0, (void*)0x08053B9C }, { 0x2730, 0, (void*)0x08053BCC }, { 0x2731, 0, (void*)0x08053C04 }, - { 0x2732, 0, (void*)0x08053C70 }, { 0x2733, 0, (void*)0x08053CD8 }, { 0x2734, 0, (void*)0x08053D4C }, - { 0x2735, 0, (void*)0x08053DD4 }, { 0x2736, 0, (void*)0x08053E48 }, { 0x2737, 0, (void*)0x08053EA8 }, - { 0x2738, 0, (void*)0x08053F9C }, { 0x2739, 0, (void*)0x08054038 }, { 0x273A, 0, (void*)0x080540A0 }, - { 0x273B, 0, (void*)0x0805411C }, { 0x273C, 0, (void*)0x08054188 }, { 0x273D, 0, (void*)0x080541D0 }, - { 0x273E, 0, (void*)0x08054278 }, { 0x273F, 0, (void*)0x080542A0 }, { 0x2740, 0, (void*)0x0805432C }, - { 0x2741, 0, (void*)0x080543CC }, { 0x2742, 0, (void*)0x08054478 }, { 0x2743, 0, (void*)0x080544F8 }, - { 0x2744, 0, (void*)0x08054580 }, { 0x2745, 0, (void*)0x08054630 }, { 0x2746, 0, (void*)0x08054674 }, - { 0x2747, 0, (void*)0x080546C4 }, { 0x2748, 0, (void*)0x08054784 }, { 0x2749, 0, (void*)0x080547EC }, - { 0x274A, 0, (void*)0x0805483C }, { 0x274B, 0, (void*)0x0805489C }, { 0x274C, 0, (void*)0x08054924 }, - { 0x274D, 0, (void*)0x0805494C }, { 0x274E, 0, (void*)0x080549E0 }, { 0x274F, 0, (void*)0x08054A90 }, - { 0x2774, 0, (void*)0x08054B24 }, { 0x2775, 0, (void*)0x08054B7C }, { 0x2776, 0, (void*)0x08054C30 }, - { 0x2777, 0, (void*)0x08054C3C }, { 0x2778, 0, (void*)0x08054CD0 }, { 0x2779, 0, (void*)0x08054CDC }, - { 0x277A, 0, (void*)0x08054D00 }, { 0x277B, 0, (void*)0x08054DA4 }, { 0x277C, 0, (void*)0x08054EC8 }, - { 0x277D, 0, (void*)0x08054F54 }, { 0x277E, 0, (void*)0x08054FA0 }, { 0x277F, 0, (void*)0x08055004 }, - { 0x2780, 0, (void*)0x0805503C }, { 0x2781, 0, (void*)0x080550B0 }, { 0x2782, 0, (void*)0x08055110 }, - { 0x2783, 0, (void*)0x08055138 }, { 0x2784, 0, (void*)0x08055160 }, { 0x2785, 0, (void*)0x08055194 }, - { 0x2786, 0, (void*)0x080551E0 }, { 0x2787, 0, (void*)0x08055224 }, { 0x2788, 0, (void*)0x08055264 }, - { 0x2789, 0, (void*)0x080552A8 }, { 0x278A, 0, (void*)0x080552E8 }, { 0x278B, 0, (void*)0x08055310 }, - { 0x278C, 0, (void*)0x0805535C }, { 0x278D, 0, (void*)0x080553E0 }, { 0x278E, 0, (void*)0x08055424 }, - { 0x278F, 0, (void*)0x08055448 }, { 0x2790, 0, (void*)0x08055470 }, { 0x2791, 0, (void*)0x080554F0 }, - { 0x2792, 0, (void*)0x08055510 }, { 0x2793, 0, (void*)0x08055534 }, { 0x2794, 0, (void*)0x080555BC }, - { 0x2795, 0, (void*)0x080555FC }, { 0x2796, 0, (void*)0x0805565C }, { 0x2797, 0, (void*)0x08055688 }, - { 0x2798, 0, (void*)0x080556CC }, { 0x2799, 0, (void*)0x08055700 }, { 0x279A, 0, (void*)0x0805573C }, - { 0x279B, 0, (void*)0x0805576C }, { 0x279C, 0, (void*)0x080557B0 }, { 0x279D, 0, (void*)0x08055804 }, - { 0x279E, 0, (void*)0x08055858 }, { 0x279F, 0, (void*)0x080558DC }, { 0x27A0, 0, (void*)0x0805591C }, - { 0x27A1, 0, (void*)0x08055984 }, { 0x27A2, 0, (void*)0x080559C0 }, { 0x27A3, 0, (void*)0x08055A10 }, - { 0x27A4, 0, (void*)0x08055A38 }, { 0x27A5, 0, (void*)0x08055AB0 }, { 0x27A6, 0, (void*)0x08055AE8 }, - { 0x27A7, 0, (void*)0x08055B1C }, { 0x27A8, 0, (void*)0x08055B60 }, { 0x27A9, 0, (void*)0x08055BA8 }, - { 0x27AA, 0, (void*)0x08055BC0 }, { 0x27AB, 0, (void*)0x08055C10 }, { 0x27AC, 0, (void*)0x08055C34 }, - { 0x27AD, 0, (void*)0x08055CAC }, { 0x27AE, 0, (void*)0x08055CC4 }, { 0x27D8, 0, (void*)0x08055D0C }, - { 0x27D9, 0, (void*)0x08055D50 }, { 0x27DA, 0, (void*)0x08055D94 }, { 0x27DB, 0, (void*)0x08055DCC }, - { 0x27DC, 0, (void*)0x08055E10 }, { 0x27DD, 0, (void*)0x08055E50 }, { 0x27DE, 0, (void*)0x08055ED0 }, - { 0x27DF, 0, (void*)0x08055F14 }, { 0x27E0, 0, (void*)0x08055F70 }, { 0x27E1, 0, (void*)0x08056000 }, - { 0x27E2, 0, (void*)0x0805609C }, { 0x27E3, 0, (void*)0x080560DC }, { 0x27E4, 0, (void*)0x080560F8 }, - { 0x27E5, 0, (void*)0x08056128 }, { 0x27E6, 0, (void*)0x08056170 }, { 0x27E7, 0, (void*)0x08056220 }, - { 0x27E8, 0, (void*)0x0805627C }, { 0x27E9, 0, (void*)0x080562D8 }, { 0x27EA, 0, (void*)0x08056334 }, - { 0x27EB, 0, (void*)0x0805635C }, { 0x27EC, 0, (void*)0x080563B0 }, { 0x27ED, 0, (void*)0x080563D8 }, - { 0x27EE, 0, (void*)0x0805643C }, { 0x27EF, 0, (void*)0x08056468 }, { 0x27F0, 0, (void*)0x08056488 }, - { 0x27F1, 0, (void*)0x080564AC }, { 0x27F2, 0, (void*)0x080564F4 }, { 0x27F3, 0, (void*)0x0805653C }, - { 0x27F4, 0, (void*)0x08056570 }, { 0x27F5, 0, (void*)0x0805662C }, { 0x27F6, 0, (void*)0x0805668C }, - { 0x27F7, 0, (void*)0x080566B0 }, { 0x27F8, 0, (void*)0x080566E4 }, { 0x27F9, 0, (void*)0x08056708 }, - { 0x27FA, 0, (void*)0x08056734 }, { 0x283C, 0, (void*)0x0805678C }, { 0x283D, 0, (void*)0x080567C4 }, - { 0x2841, 0, (void*)0x080567FC }, { 0x2842, 0, (void*)0x08056840 }, { 0x2843, 0, (void*)0x08056878 }, - { 0x2844, 0, (void*)0x080568E0 }, { 0x2845, 0, (void*)0x0805696C }, { 0x2846, 0, (void*)0x080569BC }, - { 0x2847, 0, (void*)0x08056A18 }, { 0x2848, 0, (void*)0x08056A54 }, { 0x2849, 0, (void*)0x08056AB0 }, - { 0x284A, 0, (void*)0x08056AF4 }, { 0x284B, 0, (void*)0x08056B38 }, { 0x284C, 0, (void*)0x08056B88 }, - { 0x284D, 0, (void*)0x08056BCC }, { 0x284E, 0, (void*)0x08056C2C }, { 0x284F, 0, (void*)0x08056C7C }, - { 0x2850, 0, (void*)0x08056CA8 }, { 0x2851, 0, (void*)0x08056CF8 }, { 0x2852, 0, (void*)0x08056D24 }, - { 0x2853, 0, (void*)0x08056D68 }, { 0x2854, 0, (void*)0x08056DC0 }, { 0x2855, 0, (void*)0x08056E04 }, - { 0x2856, 0, (void*)0x08056E50 }, { 0x2857, 0, (void*)0x08056E98 }, { 0x2858, 0, (void*)0x08056EFC }, - { 0x2859, 0, (void*)0x08056F44 }, { 0x285A, 0, (void*)0x08056FA8 }, { 0x285B, 0, (void*)0x08056FE8 }, - { 0x285C, 0, (void*)0x08057014 }, { 0x285D, 0, (void*)0x0805705C }, { 0x285E, 0, (void*)0x08057088 }, - { 0x285F, 0, (void*)0x080570C8 }, { 0x2860, 0, (void*)0x080570FC }, { 0x2861, 0, (void*)0x08057114 }, - { 0x2862, 0, (void*)0x08057174 }, { 0x2863, 0, (void*)0x080571C0 }, { 0x2864, 0, (void*)0x0805722C }, - { 0x2865, 0, (void*)0x08057278 }, { 0x2866, 0, (void*)0x080572E4 }, { 0x2867, 0, (void*)0x08057328 }, - { 0x2868, 0, (void*)0x08057358 }, { 0x2869, 0, (void*)0x080573A4 }, { 0x286A, 0, (void*)0x08057410 }, - { 0x286B, 0, (void*)0x08057454 }, { 0x286C, 0, (void*)0x08057484 }, { 0x286D, 0, (void*)0x080574D0 }, - { 0x286E, 0, (void*)0x080574F8 }, { 0x286F, 0, (void*)0x0805753C }, { 0x2870, 0, (void*)0x080575A8 }, - { 0x2871, 0, (void*)0x080575E4 }, { 0x2872, 0, (void*)0x08057628 }, { 0x2873, 0, (void*)0x0805765C }, - { 0x2874, 0, (void*)0x080576B4 }, { 0x2875, 0, (void*)0x080576D0 }, { 0x2876, 0, (void*)0x08057728 }, - { 0x2877, 0, (void*)0x0805777C }, { 0x2878, 0, (void*)0x080577D4 }, { 0x2879, 0, (void*)0x08057828 }, - { 0x287A, 0, (void*)0x08057890 }, { 0x287B, 0, (void*)0x08057900 }, { 0x287C, 0, (void*)0x08057968 }, - { 0x287D, 0, (void*)0x080579B8 }, { 0x287E, 0, (void*)0x080579E8 }, { 0x287F, 0, (void*)0x08057A5C }, - { 0x2880, 0, (void*)0x08057AA8 }, { 0x2881, 0, (void*)0x08057B24 }, { 0x2882, 0, (void*)0x08057B5C }, - { 0x2883, 0, (void*)0x08057B94 }, { 0x2884, 0, (void*)0x08057BC8 }, { 0x2885, 0, (void*)0x08057BE0 }, - { 0x2886, 0, (void*)0x08057BF8 }, { 0x2887, 0, (void*)0x08057C24 }, { 0x2888, 0, (void*)0x08057C5C }, - { 0x2889, 0, (void*)0x08057C88 }, { 0x288A, 0, (void*)0x08057CB4 }, { 0x288B, 0, (void*)0x08057CD4 }, - { 0x28A0, 0, (void*)0x08057CF0 }, { 0x28A1, 0, (void*)0x08057D20 }, { 0x28A2, 0, (void*)0x08057D5C }, - { 0x28A3, 0, (void*)0x08057D94 }, { 0x28A4, 0, (void*)0x08057E80 }, { 0x28A5, 0, (void*)0x08057F64 }, - { 0x28A6, 0, (void*)0x08057FA8 }, { 0x28A7, 0, (void*)0x08058080 }, { 0x28A8, 0, (void*)0x080580B4 }, - { 0x28A9, 0, (void*)0x080580F4 }, { 0x28AA, 0, (void*)0x08058130 }, { 0x28AB, 0, (void*)0x08058160 }, - { 0x28AC, 0, (void*)0x080581EC }, { 0x28AD, 0, (void*)0x080582C0 }, { 0x28AF, 0, (void*)0x080582DC }, - { 0x28B0, 0, (void*)0x080582F8 }, { 0x28B1, 0, (void*)0x08058340 }, { 0x28B2, 0, (void*)0x080583A8 }, - { 0x28B3, 0, (void*)0x08058400 }, { 0x28B4, 0, (void*)0x08058488 }, { 0x28B5, 0, (void*)0x080584E8 }, - { 0x28B6, 0, (void*)0x08058524 }, { 0x28B7, 0, (void*)0x08058594 }, { 0x28B8, 0, (void*)0x080585F4 }, - { 0x28B9, 0, (void*)0x08058618 }, { 0x28BA, 0, (void*)0x0805864C }, { 0x28BB, 0, (void*)0x08058688 }, - { 0x28BC, 0, (void*)0x080586B8 }, { 0x28BD, 0, (void*)0x080586F8 }, { 0x28BE, 0, (void*)0x0805871C }, - { 0x28BF, 0, (void*)0x08058760 }, { 0x28C0, 0, (void*)0x0805878C }, { 0x28C1, 0, (void*)0x080587B4 }, - { 0x28C2, 0, (void*)0x0805881C }, { 0x28C3, 0, (void*)0x08058880 }, { 0x28C4, 0, (void*)0x080589EC }, - { 0x28C5, 0, (void*)0x08058A60 }, { 0x28C6, 0, (void*)0x08058A78 }, { 0x28C7, 0, (void*)0x08058AC0 }, - { 0x28C8, 0, (void*)0x08058AF4 }, { 0x28C9, 0, (void*)0x08058B54 }, { 0x28CA, 0, (void*)0x08058B9C }, - { 0x28CB, 0, (void*)0x08058BD4 }, { 0x28CC, 0, (void*)0x08058C24 }, { 0x28CD, 0, (void*)0x08058C58 }, - { 0x28CE, 0, (void*)0x08058C6C }, { 0x28CF, 0, (void*)0x08058C88 }, { 0x28D0, 0, (void*)0x08058CCC }, - { 0x28D1, 0, (void*)0x08058D1C }, { 0x28D2, 0, (void*)0x08058D4C }, { 0x28D3, 0, (void*)0x08058DA0 }, - { 0x28D4, 0, (void*)0x08058DF0 }, { 0x28D5, 0, (void*)0x08058E4C }, { 0x28D6, 0, (void*)0x08058EE8 }, - { 0x28D7, 0, (void*)0x08058F10 }, { 0x28D8, 0, (void*)0x08058F60 }, { 0x28D9, 0, (void*)0x0805901C }, - { 0x28DA, 0, (void*)0x08059030 }, { 0x28DB, 0, (void*)0x08059154 }, { 0x28DC, 0, (void*)0x08059184 }, - { 0x28DE, 0, (void*)0x080591A8 }, { 0x28DF, 0, (void*)0x080591E4 }, { 0x28E0, 0, (void*)0x08059220 }, - { 0x28E1, 0, (void*)0x08059260 }, { 0x28E2, 0, (void*)0x080592C8 }, { 0x28E3, 0, (void*)0x0805931C }, - { 0x28E4, 0, (void*)0x08059378 }, { 0x28E5, 0, (void*)0x080593A4 }, { 0x28E6, 0, (void*)0x080593B8 }, - { 0x28E7, 0, (void*)0x080593FC }, { 0x28E8, 0, (void*)0x08059420 }, { 0x28E9, 0, (void*)0x0805945C }, - { 0x28EA, 0, (void*)0x08059480 }, { 0x28EB, 0, (void*)0x080594D4 }, { 0x28EC, 0, (void*)0x08059564 }, - { 0x28ED, 0, (void*)0x080595B8 }, { 0x28EE, 0, (void*)0x080595F8 }, { 0x28EF, 0, (void*)0x08059640 }, - { 0x28F0, 0, (void*)0x080596F8 }, { 0x28F1, 0, (void*)0x08059754 }, { 0x28F2, 0, (void*)0x080597D4 }, - { 0x28F3, 0, (void*)0x08059814 }, { 0x28F4, 0, (void*)0x080599B0 }, { 0x28F5, 0, (void*)0x080599F8 }, - { 0x28F6, 0, (void*)0x08059AC0 }, { 0x28F7, 0, (void*)0x08059AEC }, { 0x28F8, 0, (void*)0x08059B70 }, - { 0x28F9, 0, (void*)0x08059BDC }, { 0x28FA, 0, (void*)0x08059C00 }, { 0x28FB, 0, (void*)0x08059C60 }, - { 0x28FC, 0, (void*)0x08059CBC }, { 0x28FD, 0, (void*)0x08059DA0 }, { 0x28FE, 0, (void*)0x08059DB0 }, - { 0x28FF, 0, (void*)0x08059E2C }, { 0x2900, 0, (void*)0x08059EC8 }, { 0x2901, 0, (void*)0x08059EF4 }, - { 0x2902, 0, (void*)0x08059F70 }, { 0x2903, 0, (void*)0x08059FD0 }, { 0x2904, 0, (void*)0x0805A04C }, - { 0x2905, 0, (void*)0x0805A24C }, { 0x2906, 0, (void*)0x0805A4F8 }, { 0x2907, 0, (void*)0x0805A584 }, - { 0x2908, 0, (void*)0x0805A5C0 }, { 0x2909, 0, (void*)0x0805A60C }, { 0x290A, 0, (void*)0x0805A640 }, - { 0x290B, 0, (void*)0x0805A6C8 }, { 0x290C, 0, (void*)0x0805A9C0 }, { 0x290D, 0, (void*)0x0805AD84 }, - { 0x290E, 0, (void*)0x0805ADF8 }, { 0x290F, 0, (void*)0x0805AE40 }, { 0x2910, 0, (void*)0x0805AE74 }, - { 0x2911, 0, (void*)0x0805AF50 }, { 0x2912, 0, (void*)0x0805AFCC }, { 0x2913, 0, (void*)0x0805B044 }, - { 0x2914, 0, (void*)0x0805B104 }, { 0x2915, 0, (void*)0x0805B1F8 }, { 0x2916, 0, (void*)0x0805B224 }, - { 0x2917, 0, (void*)0x0805B244 }, { 0x2918, 0, (void*)0x0805B2A0 }, { 0x2919, 0, (void*)0x0805B2D0 }, - { 0x291A, 0, (void*)0x0805B314 }, { 0x291B, 0, (void*)0x0805B354 }, { 0x291C, 0, (void*)0x0805B3B0 }, - { 0x291D, 0, (void*)0x0805B400 }, { 0x291E, 0, (void*)0x0805B454 }, { 0x291F, 0, (void*)0x0805B494 }, - { 0x2920, 0, (void*)0x0805B4EC }, { 0x2921, 0, (void*)0x0805B538 }, { 0x2922, 0, (void*)0x0805B58C }, - { 0x2923, 0, (void*)0x0805B600 }, { 0x2924, 0, (void*)0x0805B65C }, { 0x2925, 0, (void*)0x0805B738 }, - { 0x2926, 0, (void*)0x0805B770 }, { 0x2927, 0, (void*)0x0805B794 }, { 0x2928, 0, (void*)0x0805B7C8 }, - { 0x2929, 0, (void*)0x0805B7EC }, { 0x292A, 0, (void*)0x0805B814 }, { 0x292B, 0, (void*)0x0805B8C0 }, - { 0x292C, 0, (void*)0x0805B994 }, { 0x292D, 0, (void*)0x0805BA44 }, { 0x292E, 0, (void*)0x0805BB14 }, - { 0x292F, 0, (void*)0x0805BB74 }, { 0x2930, 0, (void*)0x0805BBEC }, { 0x2931, 0, (void*)0x0805BC40 }, - { 0x2932, 0, (void*)0x0805BCBC }, { 0x2933, 0, (void*)0x0805BD3C }, { 0x2934, 0, (void*)0x0805BDA4 }, - { 0x2935, 0, (void*)0x0805BDE0 }, { 0x2936, 0, (void*)0x0805BE20 }, { 0x2937, 0, (void*)0x0805BE90 }, - { 0x2938, 0, (void*)0x0805BEE8 }, { 0x2939, 0, (void*)0x0805BF5C }, { 0x293A, 0, (void*)0x0805BF80 }, - { 0x293B, 0, (void*)0x0805BFE4 }, { 0x293C, 0, (void*)0x0805C00C }, { 0x293D, 0, (void*)0x0805C094 }, - { 0x293E, 0, (void*)0x0805C0EC }, { 0x293F, 0, (void*)0x0805C168 }, { 0x2940, 0, (void*)0x0805C1EC }, - { 0x2941, 0, (void*)0x0805C258 }, { 0x2942, 0, (void*)0x0805C2DC }, { 0x2943, 0, (void*)0x0805C350 }, - { 0x2944, 0, (void*)0x0805C3B8 }, { 0x2945, 0, (void*)0x0805C3F8 }, { 0x2946, 0, (void*)0x0805C44C }, - { 0x2947, 0, (void*)0x0805C470 }, { 0x2948, 0, (void*)0x0805C4F0 }, { 0x2949, 0, (void*)0x0805C518 }, - { 0x294A, 0, (void*)0x0805C534 }, { 0x294B, 0, (void*)0x0805C54C }, { 0x294C, 0, (void*)0x0805C570 }, - { 0x294D, 0, (void*)0x0805C5A8 }, { 0x294E, 0, (void*)0x0805C680 }, { 0x294F, 0, (void*)0x0805C740 }, - { 0x2950, 0, (void*)0x0805C794 }, { 0x2951, 0, (void*)0x0805C7F4 }, { 0x2952, 0, (void*)0x0805C854 }, - { 0x2953, 0, (void*)0x0805C914 }, { 0x2954, 0, (void*)0x0805C940 }, { 0x2955, 0, (void*)0x0805C980 }, - { 0x2956, 0, (void*)0x0805C9DC }, { 0x2957, 0, (void*)0x0805CA08 }, { 0x2958, 0, (void*)0x0805CA2C }, - { 0x2959, 0, (void*)0x0805CA48 }, { 0x295A, 0, (void*)0x0805CA6C }, { 0x295B, 0, (void*)0x0805CAB4 }, - { 0x295C, 0, (void*)0x0805CB08 }, { 0x295D, 0, (void*)0x0805CB24 }, { 0x295E, 0, (void*)0x0805CB44 }, - { 0x295F, 0, (void*)0x0805CB60 }, { 0x2960, 0, (void*)0x0805CC3C }, { 0x2961, 0, (void*)0x0805CD14 }, - { 0x2962, 0, (void*)0x0805CD3C }, { 0x2968, 0, (void*)0x0805CE60 }, { 0x2969, 0, (void*)0x0805CE78 }, - { 0x296A, 0, (void*)0x0805CEF4 }, { 0x296B, 0, (void*)0x0805CF24 }, { 0x296C, 0, (void*)0x0805CF64 }, - { 0x296D, 0, (void*)0x0805CF9C }, { 0x296E, 0, (void*)0x0805CFB4 }, { 0x296F, 0, (void*)0x0805D018 }, - { 0x2970, 0, (void*)0x0805D08C }, { 0x2971, 0, (void*)0x0805D17C }, { 0x2972, 0, (void*)0x0805D1C4 }, - { 0x2973, 0, (void*)0x0805D234 }, { 0x2974, 0, (void*)0x0805D258 }, { 0x2975, 0, (void*)0x0805D2E4 }, - { 0x2976, 0, (void*)0x0805D314 }, { 0x2977, 0, (void*)0x0805D358 }, { 0x2978, 0, (void*)0x0805D3DC }, - { 0x2979, 0, (void*)0x0805D414 }, { 0x297A, 0, (void*)0x0805D458 }, { 0x29CC, 0, (void*)0x0805D4A8 }, - { 0x29CD, 0, (void*)0x0805D4C0 }, { 0x29CE, 0, (void*)0x0805D514 }, { 0x29CF, 0, (void*)0x0805D550 }, - { 0x29D0, 0, (void*)0x0805D580 }, { 0x29D1, 0, (void*)0x0805D5AC }, { 0x29D2, 0, (void*)0x0805D5D4 }, - { 0x29D3, 0, (void*)0x0805D620 }, { 0x29D4, 0, (void*)0x0805D724 }, { 0x29D5, 0, (void*)0x0805D824 }, - { 0x29D6, 0, (void*)0x0805D864 }, { 0x29D7, 0, (void*)0x0805D8A8 }, { 0x29D8, 0, (void*)0x0805D9A8 }, - { 0x29D9, 0, (void*)0x0805DAA4 }, { 0x29DA, 0, (void*)0x0805DAFC }, { 0x29DB, 0, (void*)0x0805DB3C }, - { 0x29DC, 0, (void*)0x0805DBA0 }, { 0x29DD, 0, (void*)0x0805DBDC }, { 0x29DE, 0, (void*)0x0805DC00 }, - { 0x29DF, 0, (void*)0x0805DC68 }, { 0x29E0, 0, (void*)0x0805DC94 }, { 0x29E1, 0, (void*)0x0805DCC0 }, - { 0x29E2, 0, (void*)0x0805DCE8 }, { 0x29E3, 0, (void*)0x0805DE80 }, { 0x29E4, 0, (void*)0x0805DEC0 }, - { 0x29E5, 0, (void*)0x0805DFAC }, { 0x29E6, 0, (void*)0x0805DFC8 }, { 0x29E7, 0, (void*)0x0805E00C }, - { 0x29E8, 0, (void*)0x0805E098 }, { 0x29E9, 0, (void*)0x0805E0DC }, { 0x29EA, 0, (void*)0x0805E1D0 }, - { 0x29EB, 0, (void*)0x0805E204 }, { 0x29EC, 0, (void*)0x0805E234 }, { 0x29ED, 0, (void*)0x0805E258 }, - { 0x29EE, 0, (void*)0x0805E2A4 }, { 0x29EF, 0, (void*)0x0805E2D4 }, { 0x29F0, 0, (void*)0x0805E314 }, - { 0x29F1, 0, (void*)0x0805E344 }, { 0x29F2, 0, (void*)0x0805E390 }, { 0x29F3, 0, (void*)0x0805E3EC }, - { 0x29F4, 0, (void*)0x0805E428 }, { 0x29F5, 0, (void*)0x0805E49C }, { 0x29F8, 0, (void*)0x0805E4D8 }, - { 0x29F9, 0, (void*)0x0805E530 }, { 0x29FA, 0, (void*)0x0805E56C }, { 0x29FB, 0, (void*)0x0805E5B8 }, - { 0x29FC, 0, (void*)0x0805E608 }, { 0x29FD, 0, (void*)0x0805E654 }, { 0x29FE, 0, (void*)0x0805E6C8 }, - { 0x29FF, 0, (void*)0x0805E700 }, { 0x2A00, 0, (void*)0x0805E7B4 }, { 0x2A01, 0, (void*)0x0805E7D0 }, - { 0x2A02, 0, (void*)0x0805E81C }, { 0x2A30, 0, (void*)0x0805E878 }, { 0x2A31, 0, (void*)0x0805E898 }, - { 0x2A32, 0, (void*)0x0805E8DC }, { 0x2A33, 0, (void*)0x0805E94C }, { 0x2A34, 0, (void*)0x0805EA04 }, - { 0x2A35, 0, (void*)0x0805EA90 }, { 0x2A36, 0, (void*)0x0805EB14 }, { 0x2A37, 0, (void*)0x0805EB4C }, - { 0x2A38, 0, (void*)0x0805EBD0 }, { 0x2A39, 0, (void*)0x0805EC28 }, { 0x2A3A, 0, (void*)0x0805EC40 }, - { 0x2A94, 0, (void*)0x0805EC78 }, { 0x2A95, 0, (void*)0x0805ECA4 }, { 0x2A96, 0, (void*)0x0805ECD0 }, - { 0x2A97, 0, (void*)0x0805EDEC }, { 0x2A98, 0, (void*)0x0805EF18 }, { 0x2A99, 0, (void*)0x0805EF50 }, - { 0x2A9A, 0, (void*)0x0805EFE0 }, { 0x2A9B, 0, (void*)0x0805F120 }, { 0x2A9C, 0, (void*)0x0805F254 }, - { 0x2A9D, 0, (void*)0x0805F30C }, { 0x2A9E, 0, (void*)0x0805F3CC }, { 0x2A9F, 0, (void*)0x0805F4B4 }, - { 0x2AA0, 0, (void*)0x0805F5D0 }, { 0x2AA1, 0, (void*)0x0805F604 }, { 0x2AA2, 0, (void*)0x0805F63C }, - { 0x2AA3, 0, (void*)0x0805F68C }, { 0x2AA4, 0, (void*)0x0805F6BC }, { 0x2AA5, 0, (void*)0x0805F71C }, - { 0x2AA6, 0, (void*)0x0805F760 }, { 0x2AA7, 0, (void*)0x0805F7E4 }, { 0x2AA8, 0, (void*)0x0805F81C }, - { 0x2AA9, 0, (void*)0x0805F834 }, { 0x2AAA, 0, (void*)0x0805F870 }, { 0x2AAB, 0, (void*)0x0805F888 }, - { 0x2AAC, 0, (void*)0x0805F8B0 }, { 0x2AAD, 0, (void*)0x0805F8D4 }, { 0x2AAE, 0, (void*)0x0805F944 }, - { 0x2AAF, 0, (void*)0x0805F988 }, { 0x2AB0, 0, (void*)0x0805F9B0 }, { 0x2AB1, 0, (void*)0x0805FA58 }, - { 0x2AB2, 0, (void*)0x0805FA6C }, { 0x2AB3, 0, (void*)0x0805FA80 }, { 0x2AB4, 0, (void*)0x0805FB0C }, - { 0x2AB5, 0, (void*)0x0805FB20 }, { 0x2AB6, 0, (void*)0x0805FB64 }, { 0x2AB7, 0, (void*)0x0805FB80 }, - { 0x2AB8, 0, (void*)0x0805FB9C }, { 0x2AB9, 0, (void*)0x0805FBF4 }, { 0x2ABA, 0, (void*)0x0805FC24 }, - { 0x2ABB, 0, (void*)0x0805FC88 }, { 0x2ABC, 0, (void*)0x0805FCB0 }, { 0x2ABD, 0, (void*)0x0805FCD8 }, - { 0x2ABE, 0, (void*)0x0805FDD8 }, { 0x2ABF, 0, (void*)0x0805FDFC }, { 0x2AC0, 0, (void*)0x0805FF50 }, - { 0x2AC1, 0, (void*)0x0805FF7C }, { 0x2AC2, 0, (void*)0x080600D0 }, { 0x2AC3, 0, (void*)0x080600EC }, - { 0x2AC4, 0, (void*)0x080601F8 }, { 0x2AC5, 0, (void*)0x0806022C }, { 0x2AC6, 0, (void*)0x08060250 }, - { 0x2AC7, 0, (void*)0x08060260 }, { 0x2AC8, 0, (void*)0x08060270 }, { 0x2AC9, 0, (void*)0x08060280 }, - { 0x2ACA, 0, (void*)0x080602E0 }, { 0x2ACB, 0, (void*)0x0806030C }, { 0x2ACC, 0, (void*)0x08060340 }, - { 0x2ACD, 0, (void*)0x080603A4 }, { 0x2ACE, 0, (void*)0x080603C0 }, { 0x2ACF, 0, (void*)0x0806047C }, - { 0x2AD0, 0, (void*)0x08060494 }, { 0x2AD1, 0, (void*)0x0806053C }, { 0x2AD2, 0, (void*)0x080605B0 }, - { 0x2AD3, 0, (void*)0x080605FC }, { 0x2AD4, 0, (void*)0x0806067C }, { 0x2AD5, 0, (void*)0x080606A0 }, - { 0x2AD6, 0, (void*)0x080606BC }, { 0x2AD7, 0, (void*)0x080606EC }, { 0x2AD8, 0, (void*)0x08060724 }, - { 0x2AD9, 0, (void*)0x08060748 }, { 0x2ADA, 0, (void*)0x08060794 }, { 0x2ADB, 0, (void*)0x08060814 }, - { 0x2ADC, 0, (void*)0x08060874 }, { 0x2ADD, 0, (void*)0x080608B4 }, { 0x2ADE, 0, (void*)0x080608D0 }, - { 0x2ADF, 0, (void*)0x08060960 }, { 0x2AE0, 0, (void*)0x08060A00 }, { 0x2AE1, 0, (void*)0x08060AA8 }, - { 0x2AE2, 0, (void*)0x08060AD4 }, { 0x2AE3, 0, (void*)0x08060B10 }, { 0x2AE4, 0, (void*)0x08060B74 }, - { 0x2AE5, 0, (void*)0x08060BD0 }, { 0x2AE6, 0, (void*)0x08060C6C }, { 0x2AEA, 0, (void*)0x08060CDC }, - { 0x2AEB, 0, (void*)0x08060D1C }, { 0x2AEC, 0, (void*)0x08060D70 }, { 0x2AED, 0, (void*)0x08060D98 }, - { 0x2AEE, 0, (void*)0x08060DB8 }, { 0x2AF8, 0, (void*)0x08060DC8 }, { 0x2AF9, 0, (void*)0x08060DE4 }, - { 0x2AFA, 0, (void*)0x08060EC8 }, { 0x2AFB, 0, (void*)0x08060FC0 }, { 0x2AFC, 0, (void*)0x080610CC }, - { 0x2AFD, 0, (void*)0x080611BC }, { 0x2AFE, 0, (void*)0x080611F4 }, { 0x2AFF, 0, (void*)0x080612EC }, - { 0x2B00, 0, (void*)0x080613FC }, { 0x2B01, 0, (void*)0x08061448 }, { 0x2B02, 0, (void*)0x08061470 }, - { 0x2B03, 0, (void*)0x080614D0 }, { 0x2B04, 0, (void*)0x08061504 }, { 0x2B05, 0, (void*)0x08061578 }, - { 0x2B06, 0, (void*)0x080615DC }, { 0x2B07, 0, (void*)0x08061658 }, { 0x2B08, 0, (void*)0x0806167C }, - { 0x2B09, 0, (void*)0x080616C0 }, { 0x2B0A, 0, (void*)0x08061714 }, { 0x2B0B, 0, (void*)0x08061750 }, - { 0x2B0C, 0, (void*)0x080617A8 }, { 0x2B0D, 0, (void*)0x080617D8 }, { 0x2B0E, 0, (void*)0x08061810 }, - { 0x2B0F, 0, (void*)0x08061890 }, { 0x2B10, 0, (void*)0x080619A0 }, { 0x2B11, 0, (void*)0x08061AD8 }, - { 0x2B12, 0, (void*)0x08061B44 }, { 0x2B13, 0, (void*)0x08061BA0 }, { 0x2B14, 0, (void*)0x08061C0C }, - { 0x2B15, 0, (void*)0x08061C44 }, { 0x2B16, 0, (void*)0x08061CE0 }, { 0x2B17, 0, (void*)0x08061D4C }, - { 0x2B18, 0, (void*)0x08061D70 }, { 0x2B19, 0, (void*)0x08061DD4 }, { 0x2B1A, 0, (void*)0x08061EB4 }, - { 0x2B1B, 0, (void*)0x08061F10 }, { 0x2B1C, 0, (void*)0x08061F88 }, { 0x2B1D, 0, (void*)0x08061FC4 }, - { 0x2B1E, 0, (void*)0x08061FEC }, { 0x2B1F, 0, (void*)0x08062024 }, { 0x2B20, 0, (void*)0x0806209C }, - { 0x2B21, 0, (void*)0x0806212C }, { 0x2B22, 0, (void*)0x08062164 }, { 0x2B23, 0, (void*)0x080621A8 }, - { 0x2B24, 0, (void*)0x0806229C }, { 0x2B25, 0, (void*)0x080622D8 }, { 0x2B26, 0, (void*)0x080622F8 }, - { 0x2B27, 0, (void*)0x08062350 }, { 0x2B28, 0, (void*)0x080623A0 }, { 0x2B29, 0, (void*)0x080623D0 }, - { 0x2B2A, 0, (void*)0x08062428 }, { 0x2B2B, 0, (void*)0x08062478 }, { 0x2B2C, 0, (void*)0x080624AC }, - { 0x2B2D, 0, (void*)0x08062500 }, { 0x2B2E, 0, (void*)0x08062550 }, { 0x2B2F, 0, (void*)0x08062580 }, - { 0x2B30, 0, (void*)0x080625D4 }, { 0x2B31, 0, (void*)0x08062624 }, { 0x2B32, 0, (void*)0x08062650 }, - { 0x2B33, 0, (void*)0x08062670 }, { 0x2B34, 0, (void*)0x080626B0 }, { 0x2B35, 0, (void*)0x080626DC }, - { 0x2B36, 0, (void*)0x080626FC }, { 0x2B37, 0, (void*)0x0806273C }, { 0x2B38, 0, (void*)0x080627D8 }, - { 0x2B39, 0, (void*)0x08062890 }, { 0x2B3A, 0, (void*)0x08062910 }, { 0x2B3B, 0, (void*)0x08062968 }, - { 0x2B3C, 0, (void*)0x080629A4 }, { 0x2B3D, 0, (void*)0x080629E0 }, { 0x2B3E, 0, (void*)0x08062A90 }, - { 0x2B3F, 0, (void*)0x08062AD8 }, { 0x2B40, 0, (void*)0x08062B34 }, { 0x2B5C, 0, (void*)0x08062B84 }, - { 0x2B5D, 0, (void*)0x08062C3C }, { 0x2B5E, 0, (void*)0x08062C68 }, { 0x2B5F, 0, (void*)0x08062C94 }, - { 0x2B60, 0, (void*)0x08062CE8 }, { 0x2B61, 0, (void*)0x08062D8C }, { 0x2B62, 0, (void*)0x08062E34 }, - { 0x2B63, 0, (void*)0x08062E84 }, { 0x2B64, 0, (void*)0x08062F18 }, { 0x2B65, 0, (void*)0x08062F50 }, - { 0x2B66, 0, (void*)0x08062F98 }, { 0x2B67, 0, (void*)0x08062FE0 }, { 0x32C8, 0, (void*)0x08063054 }, - { 0x32C9, 0, (void*)0x080630D8 }, { 0x32CA, 0, (void*)0x08063120 }, { 0x32CB, 0, (void*)0x08063184 }, - { 0x32CC, 0, (void*)0x080631E0 }, { 0x32CD, 0, (void*)0x08063210 }, { 0x32CE, 0, (void*)0x0806326C }, - { 0x32CF, 0, (void*)0x08063294 }, { 0x32D0, 0, (void*)0x080632B4 }, { 0x32D1, 0, (void*)0x08063300 }, - { 0x32D2, 0, (void*)0x08063338 }, { 0x32D3, 0, (void*)0x08063384 }, { 0x32D4, 0, (void*)0x080633B4 }, - { 0x332C, 0, (void*)0x080633E8 }, { 0x332D, 0, (void*)0x08063408 }, { 0x332E, 0, (void*)0x080634FC }, - { 0x332F, 0, (void*)0x0806356C }, { 0x3330, 0, (void*)0x08063594 }, { 0x3331, 0, (void*)0x080635AC }, - { 0x3332, 0, (void*)0x080635D0 }, { 0x3333, 0, (void*)0x08063618 }, { 0x3334, 0, (void*)0x0806369C }, - { 0x3335, 0, (void*)0x08063714 }, { 0x3336, 0, (void*)0x08063734 }, { 0x3337, 0, (void*)0x08063788 }, - { 0x3338, 0, (void*)0x080637AC }, { 0x3339, 0, (void*)0x080637CC }, { 0x333A, 0, (void*)0x08063838 }, - { 0x333B, 0, (void*)0x08063868 }, { 0x333C, 0, (void*)0x08063898 }, { 0x333D, 0, (void*)0x08063948 }, - { 0x333E, 0, (void*)0x08063988 }, { 0x333F, 0, (void*)0x080639AC }, { 0x3340, 0, (void*)0x08063A58 }, - { 0x3341, 0, (void*)0x08063AB0 }, { 0x3342, 0, (void*)0x08063B24 }, { 0x3343, 0, (void*)0x08063BBC }, - { 0x3344, 0, (void*)0x08063C28 }, { 0x3345, 0, (void*)0x08063CF0 }, { 0x3346, 0, (void*)0x08063D24 }, - { 0x3347, 0, (void*)0x08063D5C }, { 0x3348, 0, (void*)0x08063D8C }, { 0x3349, 0, (void*)0x08063DEC }, - { 0x334A, 0, (void*)0x08063E70 }, { 0x334B, 0, (void*)0x08063EA8 }, { 0x334C, 0, (void*)0x08063EC4 }, - { 0x334D, 0, (void*)0x08063FB4 }, { 0x334E, 0, (void*)0x08063FDC }, { 0x334F, 0, (void*)0x08064038 }, - { 0x3350, 0, (void*)0x08064058 }, { 0x3351, 0, (void*)0x0806408C }, { 0x3352, 0, (void*)0x080640B0 }, - { 0x3353, 0, (void*)0x080640E0 }, { 0x3354, 0, (void*)0x08064168 }, { 0x3355, 0, (void*)0x080641B4 }, - { 0x3356, 0, (void*)0x080641EC }, { 0x3357, 0, (void*)0x08064218 }, { 0x3358, 0, (void*)0x08064230 }, - { 0x3359, 0, (void*)0x08064264 }, { 0x335A, 0, (void*)0x08064298 }, { 0x335B, 0, (void*)0x080642F0 }, - { 0x335C, 0, (void*)0x08064354 }, { 0x335D, 0, (void*)0x0806437C }, { 0x335E, 0, (void*)0x080643B4 }, - { 0x335F, 0, (void*)0x080643E4 }, { 0x3360, 0, (void*)0x0806444C }, { 0x3361, 0, (void*)0x08064498 }, - { 0x3362, 0, (void*)0x080644EC }, { 0x3363, 0, (void*)0x0806453C }, { 0x3364, 0, (void*)0x08064564 }, - { 0x3365, 0, (void*)0x08064654 }, { 0x3366, 0, (void*)0x08064718 }, { 0x3367, 0, (void*)0x080647E4 }, - { 0x3368, 0, (void*)0x08064860 }, { 0x3369, 0, (void*)0x080648B8 }, { 0x336A, 0, (void*)0x08064988 }, - { 0x336B, 0, (void*)0x080649F4 }, { 0x336C, 0, (void*)0x08064A44 }, { 0x336D, 0, (void*)0x08064AA0 }, - { 0x336E, 0, (void*)0x08064AE8 }, { 0x336F, 0, (void*)0x08064B10 }, { 0x3370, 0, (void*)0x08064B64 }, - { 0x3371, 0, (void*)0x08064BBC }, { 0x3390, 0, (void*)0x08064BEC }, { 0x3391, 0, (void*)0x08064C24 }, - { 0x3392, 0, (void*)0x08064CE0 }, { 0x3393, 0, (void*)0x08064D4C }, { 0x3394, 0, (void*)0x08064DA0 }, - { 0x3395, 0, (void*)0x08064E04 }, { 0x3396, 0, (void*)0x08064F10 }, { 0x3397, 0, (void*)0x08064F84 }, - { 0x3398, 0, (void*)0x08064FBC }, { 0x3399, 0, (void*)0x08065070 }, { 0x339A, 0, (void*)0x080650DC }, - { 0x339B, 0, (void*)0x08065144 }, { 0x339C, 0, (void*)0x0806516C }, { 0x339D, 0, (void*)0x0806519C }, - { 0x339E, 0, (void*)0x080651D4 }, { 0x339F, 0, (void*)0x080651F0 }, { 0x33A0, 0, (void*)0x0806524C }, - { 0x33A1, 0, (void*)0x08065358 }, { 0x33A2, 0, (void*)0x080653CC }, { 0x33A3, 0, (void*)0x08065408 }, - { 0x33A4, 0, (void*)0x08065438 }, { 0x33A5, 0, (void*)0x08065470 }, { 0x33A6, 0, (void*)0x080654CC }, - { 0x33A7, 0, (void*)0x08065510 }, { 0x33A8, 0, (void*)0x0806555C }, { 0x33A9, 0, (void*)0x080655A0 }, - { 0x33AA, 0, (void*)0x080655C0 }, { 0x33AB, 0, (void*)0x08065600 }, { 0x33AC, 0, (void*)0x08065658 }, - { 0x33AD, 0, (void*)0x08065678 }, { 0x33AE, 0, (void*)0x08065710 }, { 0x33AF, 0, (void*)0x080657A8 }, - { 0x33B0, 0, (void*)0x080657D0 }, { 0x33B1, 0, (void*)0x080657E8 }, { 0x33B2, 0, (void*)0x08065860 }, - { 0x33B3, 0, (void*)0x080658E4 }, { 0x33B4, 0, (void*)0x08065930 }, { 0x33B5, 0, (void*)0x0806597C }, - { 0x33B6, 0, (void*)0x080659DC }, { 0x33B7, 0, (void*)0x08065A28 }, { 0x33B8, 0, (void*)0x08065ABC }, - { 0x33B9, 0, (void*)0x08065AE0 }, { 0x33BA, 0, (void*)0x08065B08 }, { 0x33BB, 0, (void*)0x08065B7C }, - { 0x33BC, 0, (void*)0x08065BD8 }, { 0x33BD, 0, (void*)0x08065C5C }, { 0x33BE, 0, (void*)0x08065C88 }, - { 0x33BF, 0, (void*)0x08065CCC }, { 0x33C0, 0, (void*)0x08065D30 }, { 0x33C1, 0, (void*)0x08065DD4 }, - { 0x33C2, 0, (void*)0x08065E24 }, { 0x33C3, 0, (void*)0x08065E84 }, { 0x33C4, 0, (void*)0x08065F4C }, - { 0x33C5, 0, (void*)0x08066024 }, { 0x33C6, 0, (void*)0x08066120 }, { 0x33C7, 0, (void*)0x08066144 }, - { 0x33C8, 0, (void*)0x08066200 }, { 0x33C9, 0, (void*)0x08066268 }, { 0x33CA, 0, (void*)0x0806629C }, - { 0x33CB, 0, (void*)0x080662D0 }, { 0x33CC, 0, (void*)0x0806630C }, { 0x33CD, 0, (void*)0x08066324 }, - { 0x33CE, 0, (void*)0x0806635C }, { 0x33CF, 0, (void*)0x0806637C }, { 0x33D0, 0, (void*)0x080663AC }, - { 0x33D1, 0, (void*)0x08066464 }, { 0x33D2, 0, (void*)0x08066578 }, { 0x33D3, 0, (void*)0x080665F4 }, - { 0x33D4, 0, (void*)0x0806665C }, { 0x33D5, 0, (void*)0x080666D0 }, { 0x33D6, 0, (void*)0x08066708 }, - { 0x33D7, 0, (void*)0x08066788 }, { 0x33D8, 0, (void*)0x080667D4 }, { 0x33D9, 0, (void*)0x08066834 }, - { 0x33F4, 0, (void*)0x080668FC }, { 0x33F5, 0, (void*)0x08066934 }, { 0x33F6, 0, (void*)0x080669DC }, - { 0x33F7, 0, (void*)0x08066A3C }, { 0x33F9, 0, (void*)0x08066B00 }, { 0x3458, 0, (void*)0x08066B40 }, - { 0x3459, 0, (void*)0x08066B60 }, { 0x345A, 0, (void*)0x08066BC0 }, { 0x345B, 0, (void*)0x08066C10 }, - { 0x345C, 0, (void*)0x08066C7C }, { 0x345D, 0, (void*)0x08066CB8 }, { 0x345E, 0, (void*)0x08066D20 }, - { 0x345F, 0, (void*)0x08066D90 }, { 0x3460, 0, (void*)0x08066E58 }, { 0x3461, 0, (void*)0x08066E9C }, - { 0x3462, 0, (void*)0x08066EE8 }, { 0x3463, 0, (void*)0x08066F38 }, { 0x3464, 0, (void*)0x08066F64 }, - { 0x3465, 0, (void*)0x08066FF8 }, { 0x3466, 0, (void*)0x080670A4 }, { 0x3467, 0, (void*)0x080670F0 }, - { 0x3468, 0, (void*)0x08067144 }, { 0x3469, 0, (void*)0x08067174 }, { 0x346A, 0, (void*)0x080671E8 }, - { 0x346B, 0, (void*)0x08067208 }, { 0x346C, 0, (void*)0x08067224 }, { 0x346D, 0, (void*)0x0806728C }, - { 0x346E, 0, (void*)0x0806731C }, { 0x346F, 0, (void*)0x0806739C }, { 0x3470, 0, (void*)0x08067400 }, - { 0x3471, 0, (void*)0x0806743C }, { 0x3472, 0, (void*)0x0806746C }, { 0x3473, 0, (void*)0x080674B0 }, - { 0x3474, 0, (void*)0x08067520 }, { 0x3475, 0, (void*)0x08067594 }, { 0x3476, 0, (void*)0x080675B8 }, - { 0x3477, 0, (void*)0x080675E0 }, { 0x3478, 0, (void*)0x08067618 }, { 0x3479, 0, (void*)0x08067648 }, - { 0x347A, 0, (void*)0x08067688 }, { 0x347B, 0, (void*)0x080676B0 }, { 0x347C, 0, (void*)0x080676F0 }, - { 0x347D, 0, (void*)0x08067760 }, { 0x347E, 0, (void*)0x080677A4 }, { 0x347F, 0, (void*)0x080677F4 }, - { 0x3480, 0, (void*)0x0806782C }, { 0x3481, 0, (void*)0x080678A0 }, { 0x3482, 0, (void*)0x080678C8 }, - { 0x3483, 0, (void*)0x080678F8 }, { 0x3484, 0, (void*)0x08067934 }, { 0x3485, 0, (void*)0x08067990 }, - { 0x3486, 0, (void*)0x080679E0 }, { 0x3487, 0, (void*)0x08067A18 }, { 0x3488, 0, (void*)0x08067A68 }, - { 0x3489, 0, (void*)0x08067AE8 }, { 0x348A, 0, (void*)0x08067B54 }, { 0x348B, 0, (void*)0x08067BBC }, - { 0x348C, 0, (void*)0x08067C0C }, { 0x348D, 0, (void*)0x08067C5C }, { 0x348E, 0, (void*)0x08067CB8 }, - { 0x348F, 0, (void*)0x08067D6C }, { 0x3490, 0, (void*)0x08067DE0 }, { 0x3491, 0, (void*)0x08067E2C }, - { 0x3492, 0, (void*)0x08067E80 }, { 0x3493, 0, (void*)0x08067EDC }, { 0x3494, 0, (void*)0x08067F20 }, - { 0x3495, 0, (void*)0x08067F44 }, { 0x3496, 0, (void*)0x08067F64 }, { 0x3497, 0, (void*)0x08067FEC }, - { 0x3498, 0, (void*)0x0806803C }, { 0x3499, 0, (void*)0x08068094 }, { 0x349A, 0, (void*)0x080680C8 }, - { 0x349B, 0, (void*)0x080680FC }, { 0x349C, 0, (void*)0x0806812C }, { 0x349D, 0, (void*)0x08068158 }, - { 0x349E, 0, (void*)0x08068180 }, { 0x349F, 0, (void*)0x080681C0 }, { 0x34A0, 0, (void*)0x08068224 }, - { 0x34A1, 0, (void*)0x08068278 }, { 0x34A2, 0, (void*)0x080682C0 }, { 0x34A3, 0, (void*)0x0806830C }, - { 0x34A4, 0, (void*)0x08068394 }, { 0x34A5, 0, (void*)0x080683F4 }, { 0x34A6, 0, (void*)0x08068430 }, - { 0x34A7, 0, (void*)0x08068498 }, { 0x34A8, 0, (void*)0x080684FC }, { 0x34A9, 0, (void*)0x08068544 }, - { 0x34AA, 0, (void*)0x08068564 }, { 0x34AB, 0, (void*)0x08068598 }, { 0x34AC, 0, (void*)0x0806860C }, - { 0x34AD, 0, (void*)0x08068640 }, { 0x34AE, 0, (void*)0x080686F4 }, { 0x34AF, 0, (void*)0x08068768 }, - { 0x34B0, 0, (void*)0x08068780 }, { 0x34B1, 0, (void*)0x080687E0 }, { 0x34B2, 0, (void*)0x080687F8 }, - { 0x34B3, 0, (void*)0x08068860 }, { 0x3520, 0, (void*)0x080688F4 }, { 0x3521, 0, (void*)0x08068958 }, - { 0x3522, 0, (void*)0x080689C8 }, { 0x3523, 0, (void*)0x08068A38 }, { 0x3524, 0, (void*)0x08068A88 }, - { 0x3525, 0, (void*)0x08068B04 }, { 0x3526, 0, (void*)0x08068B30 }, { 0x3527, 0, (void*)0x08068B7C }, - { 0x3528, 0, (void*)0x08068CA0 }, { 0x3529, 0, (void*)0x08068CF4 }, { 0x352A, 0, (void*)0x08068D1C }, - { 0x352B, 0, (void*)0x08068DB0 }, { 0x352C, 0, (void*)0x08068E28 }, { 0x352D, 0, (void*)0x08068E78 }, - { 0x352E, 0, (void*)0x08068F14 }, { 0x352F, 0, (void*)0x08068F78 }, { 0x3530, 0, (void*)0x08068FA0 }, - { 0x3531, 0, (void*)0x08069020 }, { 0x3532, 0, (void*)0x080690CC }, { 0x3533, 0, (void*)0x0806913C }, - { 0x3534, 0, (void*)0x080691B0 }, { 0x3535, 0, (void*)0x08069224 }, { 0x3536, 0, (void*)0x0806923C }, - { 0x3537, 0, (void*)0x08069284 }, { 0x3538, 0, (void*)0x080692D8 }, { 0x3539, 0, (void*)0x08069314 }, - { 0x353A, 0, (void*)0x08069358 }, { 0x353B, 0, (void*)0x08069390 }, { 0x353C, 0, (void*)0x080693E4 }, - { 0x353D, 0, (void*)0x08069434 }, { 0x353E, 0, (void*)0x08069490 }, { 0x353F, 0, (void*)0x080694C4 }, - { 0x3540, 0, (void*)0x08069524 }, { 0x3541, 0, (void*)0x0806957C }, { 0x3542, 0, (void*)0x080695C0 }, - { 0x3543, 0, (void*)0x08069608 }, { 0x3544, 0, (void*)0x08069668 }, { 0x3545, 0, (void*)0x080696DC }, - { 0x3546, 0, (void*)0x08069734 }, { 0x3548, 0, (void*)0x08069774 }, { 0x3549, 0, (void*)0x08069814 }, - { 0x354A, 0, (void*)0x080698A0 }, { 0x354B, 0, (void*)0x08069930 }, { 0x354C, 0, (void*)0x08069998 }, - { 0xFFFC, 0, (void*)0x080699C8 }, { 0xFFFD, 0, (void*)0x080699D4 }, { 0xFFFF, 0, NULL }, -}; - -MessageTableEntry D_801CFB08[46] = { - { 0x4E20, 0xB0, (void*)0x07000000 }, { 0x4E21, 0xB0, (void*)0x0700003C }, - { 0x4E22, 0xB0, (void*)0x07000094 }, { 0x4E23, 0xB0, (void*)0x070000F0 }, - { 0x4E24, 0xB0, (void*)0x07000140 }, { 0x4E25, 0xB0, (void*)0x0700019C }, - { 0x4E26, 0xB0, (void*)0x070001D8 }, { 0x4E27, 0xB0, (void*)0x07000248 }, - { 0x4E28, 0xB0, (void*)0x0700027C }, { 0x4E29, 0xB0, (void*)0x070002E0 }, - { 0x4E2A, 0xB0, (void*)0x0700033C }, { 0x4E2B, 0xB0, (void*)0x07000384 }, - { 0x4E2C, 0xB0, (void*)0x070003C8 }, { 0x4E2D, 0xB0, (void*)0x0700040C }, - { 0x4E2E, 0xB0, (void*)0x07000450 }, { 0x4E2F, 0xB0, (void*)0x070004A8 }, - { 0x4E30, 0xB0, (void*)0x07000504 }, { 0x4E31, 0xB0, (void*)0x07000564 }, - { 0x4E32, 0xB0, (void*)0x070005CC }, { 0x4E33, 0xB0, (void*)0x07000610 }, - { 0x4E34, 0xB0, (void*)0x07000654 }, { 0x4E35, 0xB0, (void*)0x07000698 }, - { 0x4E36, 0xB0, (void*)0x070006F8 }, { 0x4E37, 0xB0, (void*)0x07000750 }, - { 0x4E38, 0xB0, (void*)0x07000798 }, { 0x4E39, 0xB0, (void*)0x0700081C }, - { 0x4E3A, 0xB0, (void*)0x07000888 }, { 0x4E3B, 0xB0, (void*)0x07000924 }, - { 0x4E3C, 0xB0, (void*)0x070009B4 }, { 0x4E3D, 0xB0, (void*)0x070009E8 }, - { 0x4E3E, 0xB0, (void*)0x07000A78 }, { 0x4E3F, 0xB0, (void*)0x07000AB0 }, - { 0x4E40, 0xB0, (void*)0x07000B2C }, { 0x4E41, 0xB0, (void*)0x07000B54 }, - { 0x4E42, 0xB0, (void*)0x07000B7C }, { 0x4E43, 0xB0, (void*)0x07000BA4 }, - { 0x4E44, 0xB0, (void*)0x07000BCC }, { 0x4E45, 0xB0, (void*)0x07000BF4 }, - { 0x4E46, 0xB0, (void*)0x07000C1C }, { 0x4E47, 0xB0, (void*)0x07000C44 }, - { 0x4E48, 0xB0, (void*)0x07000C6C }, { 0x4E49, 0xB0, (void*)0x07000CEC }, - { 0x4E4A, 0xB0, (void*)0x07000D5C }, { 0x4E4B, 0xB0, (void*)0x07000DC8 }, - { 0x4E4C, 0xB0, (void*)0x07000E54 }, { 0xFFFF, 0, NULL }, -}; From fc309f5eaa7a5acdd7f3b4fa9b5b7beb025287d8 Mon Sep 17 00:00:00 2001 From: Archez Date: Sat, 22 Jun 2024 15:05:32 -0400 Subject: [PATCH 16/82] bump lus with ucode change (#708) --- CMakeLists.txt | 2 +- libultraship | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fcdb1001f..e606c1627 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ endif() set(GFX_DEBUG_DISASSEMBLER ON) # Tell LUS we're using F3DEX_GBI_2 (in a way that doesn't break libgfxd) -set(USE_F3DEX2 ON) +set(GBI_UCODE F3DEX_GBI_2) ################################################################################ # Set target arch type if empty. Visual studio solution generator provides it. diff --git a/libultraship b/libultraship index fccf181b4..5849d3a23 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit fccf181b449f82f3e6ae5cdc666319847f78e0a1 +Subproject commit 5849d3a23a18d0664cb04cc084fa120833b69353 From 120562952ca7c4fcfe1bcb312fb999bae4ebe954 Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 23 Jun 2024 14:51:57 -0400 Subject: [PATCH 17/82] bump lus with color combiner fixes (#711) --- libultraship | 2 +- .../Enhancements/GfxPatcher/AuthenticGfxPatches.cpp | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libultraship b/libultraship index 5849d3a23..31e9b009f 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 5849d3a23a18d0664cb04cc084fa120833b69353 +Subproject commit 31e9b009f94e7074a847c7954926cba354cd7c72 diff --git a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp index 78da2596a..3364ff86b 100644 --- a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp +++ b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp @@ -2,7 +2,6 @@ extern "C" { #include -#include "objects/object_uch/object_uch.h" #include "overlays/ovl_En_Syateki_Okuta/ovl_En_Syateki_Okuta.h" #include "overlays/ovl_Obj_Jgame_Light/ovl_Obj_Jgame_Light.h" @@ -11,15 +10,6 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); Gfx* ResourceMgr_LoadGfxByName(const char* path); } -void PatchAlienEyeBeams() { - // A bug in the Alien's eye beam DL is incorrectly referring to TEXEL1 in the color combiner when - // the texture is loaded into TEXEL0, causing the CC rendering whatever was last loaded into TEXEL1. - // Patching the instruction to TEXEL0 restores the effect as seen on hardware. - ResourceMgr_PatchGfxByName(gAlienEyeBeamDL, "AlienEyeBeamFix", 4, - gsDPSetCombineLERP(NOISE, 0, PRIMITIVE, 0, 0, 0, 0, ENVIRONMENT, COMBINED, 0, - PRIMITIVE_ALPHA, PRIMITIVE, COMBINED, 0, TEXEL0, 0)); -} - void PatchMiniGameCrossAndCircleSymbols() { // The X and O displayed in mini-games are incorrectly set to FMT_I instead of FMT_IA, // Fast3D throws an assert and does nothing as FMT_I with SIZ_16 is not a valid texture type. @@ -48,6 +38,5 @@ void PatchMiniGameCrossAndCircleSymbols() { // Applies required patches for authentic bugs to allow the game to play and render properly void GfxPatcher_ApplyNecessaryAuthenticPatches() { - PatchAlienEyeBeams(); PatchMiniGameCrossAndCircleSymbols(); } From a38b9daa6dbf30e8b3e39fb223e29a4531eb10c2 Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 23 Jun 2024 15:19:33 -0400 Subject: [PATCH 18/82] Add HUD Editor support for horse carrots (#704) --- mm/2s2h/BenGui/HudEditor.cpp | 3 +++ mm/2s2h/BenGui/HudEditor.h | 1 + mm/src/code/z_parameter.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/mm/2s2h/BenGui/HudEditor.cpp b/mm/2s2h/BenGui/HudEditor.cpp index 75b5ad58a..95202bbbf 100644 --- a/mm/2s2h/BenGui/HudEditor.cpp +++ b/mm/2s2h/BenGui/HudEditor.cpp @@ -17,6 +17,7 @@ HudEditorElement hudEditorElements[HUD_EDITOR_ELEMENT_MAX] = { HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_D_PAD, "D-Pad", "DPad", 271, 55, 255, 255, 255, 255), HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_MINIMAP, "Minimap", "Minimap", 295, 220, 0, 255, 255, 160), HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_START, "Start Button", "Start", 136, 17, 255, 130, 60, 255), + HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_CARROT, "Horse Carrots", "Carrots", 160, 64, 236, 92, 41, 255), HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_CLOCK, "Three Day Clock", "Clock", 160, 206, 255, 255, 255, 255), HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_HEARTS, "Hearts", "Hearts", 30, 26, 255, 70, 50, 255), HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_MAGIC_METER, "Magic", "Magic", 18, 34, 0, 200, 0, 255), @@ -206,6 +207,8 @@ void HudEditorWindow::DrawElement() { HUD_EDITOR_ELEMENT_MODE_MOVABLE_RIGHT); CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_START].modeCvar, HUD_EDITOR_ELEMENT_MODE_MOVABLE_RIGHT); + CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_CARROT].modeCvar, + HUD_EDITOR_ELEMENT_MODE_MOVABLE_43); CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_CLOCK].modeCvar, HUD_EDITOR_ELEMENT_MODE_MOVABLE_43); CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_HEARTS].modeCvar, diff --git a/mm/2s2h/BenGui/HudEditor.h b/mm/2s2h/BenGui/HudEditor.h index a022c95ff..0078a6ede 100644 --- a/mm/2s2h/BenGui/HudEditor.h +++ b/mm/2s2h/BenGui/HudEditor.h @@ -32,6 +32,7 @@ typedef enum { HUD_EDITOR_ELEMENT_D_PAD, HUD_EDITOR_ELEMENT_MINIMAP, HUD_EDITOR_ELEMENT_START, + HUD_EDITOR_ELEMENT_CARROT, HUD_EDITOR_ELEMENT_CLOCK, HUD_EDITOR_ELEMENT_HEARTS, HUD_EDITOR_ELEMENT_MAGIC_METER, diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index 42487add4..6a6297196 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -8025,9 +8025,34 @@ void Interface_DrawMinigameIcons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->aAlpha); } - gSPTextureRectangle(OVERLAY_DISP++, rectX << 2, rectY << 2, (rectX + 16) << 2, (rectY + 16) << 2, - G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + // #region 2S2H [Cosmetic] Hud Editor Carrots + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CARROT); + if (HudEditor_ShouldOverrideDraw()) { + // Derived from the original call to gSPTextureRectangle below + // Y pos set to 56 in override mode to ignore minigame state differences + s16 newX = rectX; + s16 newY = 56; + s16 newWidth = 16; + s16 newHeight = 16; + s16 dsdx = 512; + s16 dtdy = 512; + + if (HudEditor_IsActiveElementHidden()) { + break; + } + + HudEditor_ModifyDrawValues(&newX, &newY, &newWidth, &newHeight, &dsdx, &dtdy); + + gSPWideTextureRectangle(OVERLAY_DISP++, newX << 2, newY << 2, (newX + newWidth) << 2, + (newY + newHeight) << 2, G_TX_RENDERTILE, 0, 0, dsdx << 1, dtdy << 1); + } else { + // #endregion + gSPTextureRectangle(OVERLAY_DISP++, rectX << 2, rectY << 2, (rectX + 16) << 2, (rectY + 16) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } } + + hudEditorActiveElement = HUD_EDITOR_ELEMENT_NONE; } if (gSaveContext.minigameStatus == MINIGAME_STATUS_ACTIVE) { From 3ef3e7a2394a36ca00cf23cb0cd8abf617809084 Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Mon, 24 Jun 2024 18:46:58 -0600 Subject: [PATCH 19/82] [Enhancement] Fix Fierce Deity interactions with Bombers (#674) * Allow FD to talk to Bomber Jim. Adds comments to unknown data. * fd works with blue bombers and guard bomber * clang format --- .../overlays/actors/ovl_En_Bombers/z_en_bombers.c | 6 +++++- .../actors/ovl_En_Bombers2/z_en_bombers2.c | 6 ++++++ .../overlays/actors/ovl_En_Bomjima/z_en_bomjima.c | 14 ++++++++------ .../overlays/actors/ovl_En_Bomjima/z_en_bomjima.h | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/mm/src/overlays/actors/ovl_En_Bombers/z_en_bombers.c b/mm/src/overlays/actors/ovl_En_Bombers/z_en_bombers.c index a67886832..229cce497 100644 --- a/mm/src/overlays/actors/ovl_En_Bombers/z_en_bombers.c +++ b/mm/src/overlays/actors/ovl_En_Bombers/z_en_bombers.c @@ -257,7 +257,11 @@ void func_80C039A8(EnBombers* this, PlayState* play) { this->actor.textId = 0x744; } break; - + // #region 2S2H - Enhancements. Fierce Deity gets same dialog as Human without notebook + case PLAYER_FORM_FIERCE_DEITY: + this->actor.textId = 0x73D; + break; + // #endregion default: break; } diff --git a/mm/src/overlays/actors/ovl_En_Bombers2/z_en_bombers2.c b/mm/src/overlays/actors/ovl_En_Bombers2/z_en_bombers2.c index 92444c961..9b59ec40f 100644 --- a/mm/src/overlays/actors/ovl_En_Bombers2/z_en_bombers2.c +++ b/mm/src/overlays/actors/ovl_En_Bombers2/z_en_bombers2.c @@ -165,6 +165,9 @@ void func_80C04BA0(EnBombers2* this, PlayState* play) { player = GET_PLAYER(play); switch (player->transformation) { + // #region 2S2H - Enhancements. Fierce Deity gets same dialog as Goron and Zora + case PLAYER_FORM_FIERCE_DEITY: + // #endregion case PLAYER_FORM_GORON: case PLAYER_FORM_ZORA: this->textIdIndex = 1; @@ -233,6 +236,9 @@ void func_80C04D8C(EnBombers2* this, PlayState* play) { this->unk_28E = -0xFA0; break; + // #region 2S2H - Enhancements. Fierce Deity. + case PLAYER_FORM_FIERCE_DEITY: + // #endregion case PLAYER_FORM_GORON: case PLAYER_FORM_ZORA: this->unk_28E = -0x1770; diff --git a/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.c b/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.c index 4976e7822..891e0741d 100644 --- a/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.c +++ b/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.c @@ -84,19 +84,19 @@ static ColliderCylinderInit sCylinderInit = { { 10, 30, 0, { 0, 0, 0 } }, }; -u16 D_80C00A44[] = { 0x719, 0x71A, 0x71B, 0x708 }; +u16 D_80C00A44[] = { 0x719, 0x71A, 0x71B, 0x708 }; // text IDs before popping balloon -u16 D_80C00A4C[] = { 0x739, 0x73A, 0x73B, 0x000 }; +u16 D_80C00A4C[] = { 0x739, 0x73A, 0x73B, 0x000 }; // text IDs after popping balloon u16 D_80C00A54[] = { 0x739, 0x73A, 0x73B, 0x714, 0x709, 0x70A, 0x70B, 0x70C, 0x70D, 0x70E, 0x70F, 0x712, 0x713, -}; +}; // text IDs for Deku after popping balloon u16 D_80C00A70[] = { 0x739, 0x73A, 0x73B, 0x759, 0x753, 0x754, 0x755, 0x756, 0x70D, 0x757, 0x758, 0x712, 0x713, -}; +}; // text IDs for Human after popping balloon -u16 D_80C00A8C[] = { 0x736, 0x737, 0x738, 0x74E }; +u16 D_80C00A8C[] = { 0x736, 0x737, 0x738, 0x74E }; // text IDs after hide and seek typedef enum { /* -1 */ ENBOMJIMA_ANIM_NONE = -1, @@ -225,9 +225,11 @@ void func_80BFE32C(EnBomjima* this, PlayState* play, s32 arg2) { if (player->transformation == PLAYER_FORM_GORON) { this->unk_2C8 = 1; } - if (player->transformation == PLAYER_FORM_ZORA) { + // #region 2S2H - Enhancements. Fierce Deity gets same dialog as Zora + if (player->transformation == PLAYER_FORM_ZORA || player->transformation == PLAYER_FORM_FIERCE_DEITY) { this->unk_2C8 = 2; } + // #endregion switch (this->unk_2CA) { case 0: diff --git a/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.h b/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.h index 15b4b10fb..f288b70c1 100644 --- a/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.h +++ b/mm/src/overlays/actors/ovl_En_Bomjima/z_en_bomjima.h @@ -37,7 +37,7 @@ typedef struct EnBomjima { /* 0x2C2 */ s16 unk_2C2; /* 0x2C4 */ s16 cutsceneTimer; /* 0x2C6 */ s16 unk_2C6; - /* 0x2C8 */ s16 unk_2C8; + /* 0x2C8 */ s16 unk_2C8; //index into arrays of textIDs /* 0x2CA */ s16 unk_2CA; /* 0x2CC */ f32 animEndFrame; /* 0x2D0 */ f32 unk_2D0; From 2e4710c6c2d165de9ca8d4fe0eab29f2dbcfb110 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Mon, 24 Jun 2024 23:16:10 -0500 Subject: [PATCH 20/82] Tweaks to warp point (#666) * Tweaks to warp point * wait for console logo exit --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 1 - mm/2s2h/DeveloperTools/DeveloperTools.cpp | 1 + mm/2s2h/DeveloperTools/DeveloperTools.h | 2 + mm/2s2h/DeveloperTools/WarpPoint.cpp | 64 ++++++++++++++++--- mm/2s2h/DeveloperTools/WarpPoint.h | 6 -- mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp | 1 + mm/2s2h/Enhancements/Cutscenes/Cutscenes.h | 1 + .../Cutscenes/SkipToFileSelect.cpp | 33 ++++++++++ .../GameInteractor/GameInteractor.cpp | 4 ++ .../GameInteractor/GameInteractor.h | 2 + mm/include/variables.h | 1 + mm/src/code/game.c | 6 ++ .../overlays/gamestates/ovl_title/z_title.c | 13 ++-- 13 files changed, 109 insertions(+), 26 deletions(-) delete mode 100644 mm/2s2h/DeveloperTools/WarpPoint.h create mode 100644 mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 764d2ea65..37089aa7f 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -12,7 +12,6 @@ #include "2s2h/Enhancements/Graphics/PlayAsKafei.h" #include "2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h" #include "2s2h/DeveloperTools/DeveloperTools.h" -#include "2s2h/DeveloperTools/WarpPoint.h" #include "2s2h/Enhancements/Cheats/Cheats.h" #include "2s2h/Enhancements/Player/Player.h" #include "HudEditor.h" diff --git a/mm/2s2h/DeveloperTools/DeveloperTools.cpp b/mm/2s2h/DeveloperTools/DeveloperTools.cpp index fe0d9606d..316d851e5 100644 --- a/mm/2s2h/DeveloperTools/DeveloperTools.cpp +++ b/mm/2s2h/DeveloperTools/DeveloperTools.cpp @@ -155,4 +155,5 @@ void InitDeveloperTools() { RegisterPreventActorUpdateHooks(); RegisterPreventActorDrawHooks(); RegisterPreventActorInitHooks(); + RegisterWarpPoint(); } diff --git a/mm/2s2h/DeveloperTools/DeveloperTools.h b/mm/2s2h/DeveloperTools/DeveloperTools.h index 3723d75d6..93c361b99 100644 --- a/mm/2s2h/DeveloperTools/DeveloperTools.h +++ b/mm/2s2h/DeveloperTools/DeveloperTools.h @@ -11,6 +11,8 @@ void RegisterDebugSaveCreate(); void RegisterPreventActorUpdateHooks(); void RegisterPreventActorDrawHooks(); void RegisterPreventActorInitHooks(); +void RegisterWarpPoint(); +void RenderWarpPointSection(); void InitDeveloperTools(); #endif // DEVELOPER_TOOLS_H diff --git a/mm/2s2h/DeveloperTools/WarpPoint.cpp b/mm/2s2h/DeveloperTools/WarpPoint.cpp index cde2fb3e6..619d2ccfd 100644 --- a/mm/2s2h/DeveloperTools/WarpPoint.cpp +++ b/mm/2s2h/DeveloperTools/WarpPoint.cpp @@ -1,15 +1,16 @@ -#include "WarpPoint.h" - #include #include "2s2h/BenGui/UIWidgets.hpp" #include "window/gui/IconsFontAwesome4.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" #include "macros.h" #include "functions.h" +#include "overlays/gamestates/ovl_select/z_select.h" extern PlayState* gPlayState; extern SaveContext gSaveContext; +extern GameState* gGameState; } #define CV "gDeveloperTools.WarpPoint." @@ -27,6 +28,56 @@ std::unordered_map warpPointSceneList = { #undef DEFINE_SCENE #undef DEFINE_SCENE_UNSET +void Warp() { + Vec3f pos = { CVarGetFloat(CV "X", 0.0f), CVarGetFloat(CV "Y", 0.0f), CVarGetFloat(CV "Z", 0.0f) }; + s32 entrance = CVarGetInteger(CV "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0)); + + if (gPlayState == NULL) { + // If gPlayState is NULL, it means the the user opted into BootToWarpPoint and the game is starting up. This is + // a hidden cvar for developers, while it is extremely useful for quick testing and debugging, I am not 100% + // confident in it's stability and ability to initialize the game properly in all cases. So for now, I'm going + // to leave it as a hidden cvar. This is incompatible with the SkipToFileSelect enhancement. To enable it open + // the Console and type: `set gDeveloperTools.WarpPoint.BootToWarpPoint 1` + gSaveContext.gameMode = GAMEMODE_NORMAL; + Sram_InitNewSave(); + gSaveContext.sceneLayer = 0; + gSaveContext.save.time = CLOCK_TIME(8, 0); + gSaveContext.save.day = 1; + gSaveContext.save.cutsceneIndex = 0; + gSaveContext.save.playerForm = PLAYER_FORM_HUMAN; + gSaveContext.save.linkAge = 0; + gSaveContext.fileNum = 0xFF; + MapSelect_LoadGame((MapSelectState*)gGameState, CVarGetInteger(CV "Entrance", 0), 0); + } else { + // The else case, and the rest of this function is primarly relevant code copied from Play_SetRespawnData and + // func_80169EFC, minus the parts that copy scene flags to scene we are warping to (this is obviously + // undesireable) + gPlayState->nextEntrance = Entrance_Create(entrance >> 9, 0, entrance & 0xF); + gPlayState->transitionTrigger = TRANS_TRIGGER_START; + gPlayState->transitionType = TRANS_TYPE_INSTANT; + } + gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = Entrance_Create(entrance >> 9, 0, entrance & 0xF); + gSaveContext.respawn[RESPAWN_MODE_DOWN].roomIndex = CVarGetInteger(CV "Room", 0); + gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = pos; + gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = CVarGetFloat(CV "Rotation", 0.0f); + gSaveContext.respawn[RESPAWN_MODE_DOWN].playerParams = PLAYER_PARAMS(0xFF, PLAYER_INITMODE_D); + gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK_FAST; + gSaveContext.respawnFlag = -8; +} + +void RegisterWarpPoint() { + GameInteractor::Instance->RegisterGameHook([]() { + if (!CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0) && CVarGetInteger(CV "BootToWarpPoint", 0) && + CVarGetInteger(CV "Saved", 0)) { + // Normally called on console logo screen + gSaveContext.seqId = (u8)NA_BGM_DISABLED; + gSaveContext.ambienceId = AMBIENCE_ID_DISABLED; + gSaveContext.gameMode = GAMEMODE_TITLE_SCREEN; + Warp(); + } + }); +} + void RenderWarpPointSection() { if (gPlayState == NULL) return; @@ -60,14 +111,7 @@ void RenderWarpPointSection() { } ImGui::SameLine(); if (UIWidgets::Button("Warp", { .size = UIWidgets::Sizes::Inline })) { - Vec3f pos = { CVarGetFloat(CV "X", 0.0f), CVarGetFloat(CV "Y", 0.0f), CVarGetFloat(CV "Z", 0.0f) }; - - Play_SetRespawnData(&gPlayState->state, RESPAWN_MODE_DOWN, - CVarGetInteger(CV "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0)), - CVarGetInteger(CV "Room", 0), PLAYER_PARAMS(0xFF, PLAYER_INITMODE_D), &pos, - CVarGetFloat(CV "Rotation", 0.0f)); - func_80169EFC(&gPlayState->state); - gSaveContext.respawnFlag = -8; + Warp(); } } } diff --git a/mm/2s2h/DeveloperTools/WarpPoint.h b/mm/2s2h/DeveloperTools/WarpPoint.h deleted file mode 100644 index 5a6a10883..000000000 --- a/mm/2s2h/DeveloperTools/WarpPoint.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef DEVELOPER_TOOLS_WARP_POINT_H -#define DEVELOPER_TOOLS_WARP_POINT_H - -void RenderWarpPointSection(); - -#endif // DEVELOPER_TOOLS_WARP_POINT_H diff --git a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp index fe480a3f5..ecfc074bf 100644 --- a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp @@ -12,4 +12,5 @@ void RegisterCutscenes() { RegisterHideTitleCards(); RegisterSkipEntranceCutscenes(); RegisterSkipIntroSequence(); + RegisterSkipToFileSelect(); } diff --git a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h index fcd955512..cca8e49af 100644 --- a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h +++ b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h @@ -14,5 +14,6 @@ void RegisterSkipClockTowerOpen(); void RegisterHideTitleCards(); void RegisterSkipEntranceCutscenes(); void RegisterSkipIntroSequence(); +void RegisterSkipToFileSelect(); #endif // CUTSCENES_H diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp new file mode 100644 index 000000000..1b1e4e029 --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp @@ -0,0 +1,33 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "z64.h" +#include "z64game.h" +#include "overlays/gamestates/ovl_file_choose/z_file_select.h" +#include "overlays/gamestates/ovl_title/z_title.h" +extern SaveContext gSaveContext; +extern GameState* gGameState; +} + +void RegisterSkipToFileSelect() { + GameInteractor::Instance->RegisterGameHook([]() { + if (CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0)) { + ConsoleLogoState* consoleLogoState = (ConsoleLogoState*)gGameState; + + // Wait for the console logo to fade out + if (consoleLogoState->exit) { + // Normally the PRNG seed is set at least once from the title opening running Play_Init + // We need to call it manually before file select creates RNG values for new saves + Rand_Seed(osGetTime()); + // Normally called on console logo screen + gSaveContext.seqId = (u8)NA_BGM_DISABLED; + gSaveContext.ambienceId = AMBIENCE_ID_DISABLED; + gSaveContext.gameMode = GAMEMODE_TITLE_SCREEN; + + STOP_GAMESTATE(gGameState); + SET_NEXT_GAMESTATE(gGameState, FileSelect_Init, sizeof(FileSelectState)); + } + } + }); +} diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index ae7eda45d..d0d9e4218 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -19,6 +19,10 @@ void GameInteractor_ExecuteOnGameStateUpdate() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnConsoleLogoUpdate() { + GameInteractor::Instance->ExecuteHooks(); +} + void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx) { GameInteractor::Instance->ExecuteHooks(pauseCtx); } diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 8da2e5ea6..1b2fdb2e9 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -257,6 +257,7 @@ class GameInteractor { DEFINE_HOOK(OnGameStateMainFinish, ()); DEFINE_HOOK(OnGameStateDrawFinish, ()); DEFINE_HOOK(OnGameStateUpdate, ()); + DEFINE_HOOK(OnConsoleLogoUpdate, ()); DEFINE_HOOK(OnKaleidoUpdate, (PauseContext * pauseCtx)); DEFINE_HOOK(OnSaveInit, (s16 fileNum)); DEFINE_HOOK(BeforeEndOfCycleSave, ()); @@ -300,6 +301,7 @@ extern "C" { void GameInteractor_ExecuteOnGameStateMainFinish(); void GameInteractor_ExecuteOnGameStateDrawFinish(); void GameInteractor_ExecuteOnGameStateUpdate(); +void GameInteractor_ExecuteOnConsoleLogoUpdate(); void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx); void GameInteractor_ExecuteOnSaveInit(s16 fileNum); void GameInteractor_ExecuteBeforeEndOfCycleSave(); diff --git a/mm/include/variables.h b/mm/include/variables.h index 43d20b140..57fe03b94 100644 --- a/mm/include/variables.h +++ b/mm/include/variables.h @@ -1765,6 +1765,7 @@ extern u16 D_0F000000[]; // #region 2S2H [General] extern PlayState* gPlayState; +extern GameState* gGameState; // #endregion #ifdef __cplusplus diff --git a/mm/src/code/game.c b/mm/src/code/game.c index 1b349289c..7fb04a125 100644 --- a/mm/src/code/game.c +++ b/mm/src/code/game.c @@ -26,6 +26,10 @@ VisZbuf sGameVisZbuf; VisMono sGameVisMono; ViMode sGameViMode; +// #region 2S2H [General] Making gGameState available +GameState* gGameState; +// #endregion + void GameState_UpdateFramerateDivisors(s32 divisor) { gFramerateDivisor = divisor; gFramerateDivisorF = divisor; @@ -205,6 +209,7 @@ void GameState_Realloc(GameState* gameState, size_t size) { } void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* gfxCtx) { + gGameState = gameState; gameState->gfxCtx = gfxCtx; gameState->frames = 0; gameState->main = NULL; @@ -256,6 +261,7 @@ void GameState_Destroy(GameState* gameState) { ViMode_Destroy(&sGameViMode); THA_Destroy(&gameState->tha); GameAlloc_Cleanup(&gameState->alloc); + gGameState = NULL; } GameStateFunc GameState_GetInit(GameState* gameState) { diff --git a/mm/src/overlays/gamestates/ovl_title/z_title.c b/mm/src/overlays/gamestates/ovl_title/z_title.c index ed622dee7..dfc1c3160 100644 --- a/mm/src/overlays/gamestates/ovl_title/z_title.c +++ b/mm/src/overlays/gamestates/ovl_title/z_title.c @@ -11,9 +11,9 @@ #include "overlays/gamestates/ovl_opening/z_opening.h" #include "misc/nintendo_rogo_static/nintendo_rogo_static.h" -#include "overlays/gamestates/ovl_file_choose/z_file_select.h" #include "build.h" #include "BenPort.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #include #define dgShipLogoDL "__OTR__misc/nintendo_rogo_static/gShipLogoDL" @@ -200,16 +200,11 @@ void ConsoleLogo_Main(GameState* thisx) { gSaveContext.gameMode = GAMEMODE_TITLE_SCREEN; STOP_GAMESTATE(&this->state); - if (CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0)) { - // Normally the PRNG seed is set at least once from the title opening running Play_Init - // We need to call it manually before file select creates RNG values for new saves - Rand_Seed(osGetTime()); - SET_NEXT_GAMESTATE(&this->state, FileSelect_Init, sizeof(FileSelectState)); - } else { - SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init, sizeof(TitleSetupState)); - } + SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init, sizeof(TitleSetupState)); } + GameInteractor_ExecuteOnConsoleLogoUpdate(); + CLOSE_DISPS(this->state.gfxCtx); } From aa1b0108f41104f95779b5b6361293f81345556c Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Thu, 11 Jul 2024 19:44:08 -0600 Subject: [PATCH 21/82] [Enhancement] Preseve time speed during cycle reset (#658) * preseve time speed during cycle reset enhancement * clang format * update variable assignment Co-authored-by: Archez * add default value * better initial value --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 4 ++++ mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 37089aa7f..465ae3b8a 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -465,6 +465,10 @@ void DrawEnhancementsMenu() { { .tooltip = "Playing the Song Of Time will not reset the Sword back to Kokiri Sword." }); UIWidgets::CVarCheckbox("Do not reset Rupees", "gEnhancements.Cycle.DoNotResetRupees", { .tooltip = "Playing the Song Of Time will not reset the your rupees." }); + UIWidgets::CVarCheckbox( + "Do not reset Time Speed", "gEnhancements.Cycle.DoNotResetTimeSpeed", + { .tooltip = + "Playing the Song Of Time will not reset the current time speed set by Inverted Song of Time." }); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 0, 255)); ImGui::SeparatorText("Unstable"); diff --git a/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp index d1afedaac..9624d337b 100644 --- a/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp +++ b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp @@ -7,10 +7,13 @@ extern "C" { } SaveInfo saveInfoCopy; +s32 timeSpeedOffsetCopy = 0; void RegisterEndOfCycleSaveHooks() { - GameInteractor::Instance->RegisterGameHook( - []() { memcpy(&saveInfoCopy, &gSaveContext.save.saveInfo, sizeof(SaveInfo)); }); + GameInteractor::Instance->RegisterGameHook([]() { + memcpy(&saveInfoCopy, &gSaveContext.save.saveInfo, sizeof(SaveInfo)); + timeSpeedOffsetCopy = gSaveContext.save.timeSpeedOffset; + }); GameInteractor::Instance->RegisterGameHook([]() { if (CVarGetInteger("gEnhancements.Cycle.DoNotResetRupees", 0)) { @@ -77,5 +80,9 @@ void RegisterEndOfCycleSaveHooks() { SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_RAZOR); CUR_FORM_EQUIP(EQUIP_SLOT_B) = ITEM_SWORD_RAZOR; } + + if (CVarGetInteger("gEnhancements.Cycle.DoNotResetTimeSpeed", 0)) { + gSaveContext.save.timeSpeedOffset = timeSpeedOffsetCopy; + } }); } From 51af06463f536baae615289398469ed00c38e2d7 Mon Sep 17 00:00:00 2001 From: Captain Kitty Cat <68467449+Captainkittyca2@users.noreply.github.com> Date: Wed, 24 Jul 2024 04:39:25 +0300 Subject: [PATCH 22/82] Item drops 3D! (#633) * Initial 3D Item Drops Toggle * Use generic hooks and other tweaks * 3d drop fixes and changes * move slime item draw to VB hook; fix arrow GID * whitespacing --------- Co-authored-by: Garrett Cox Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 5 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + .../GameInteractor/GameInteractor.h | 1 + mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp | 185 ++++++++++++++++++ mm/2s2h/Enhancements/Graphics/3DItemDrops.h | 6 + .../overlays/actors/ovl_En_Slime/z_en_slime.c | 13 +- 7 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp create mode 100644 mm/2s2h/Enhancements/Graphics/3DItemDrops.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index eef6b1cd4..edf218909 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -8,6 +8,7 @@ #include #include #include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/Enhancements/Graphics/3DItemDrops.h" #include "2s2h/Enhancements/Graphics/MotionBlur.h" #include "2s2h/Enhancements/Graphics/PlayAsKafei.h" #include "2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h" @@ -537,6 +538,10 @@ void DrawEnhancementsMenu() { "model and texture on the boot logo start screen" }); UIWidgets::CVarCheckbox("Bow Reticle", "gEnhancements.Graphics.BowReticle", { .tooltip = "Gives the bow a reticle when you draw an arrow" }); + if (UIWidgets::CVarCheckbox("3D Item Drops", "gEnhancements.Graphics.3DItemDrops", + { .tooltip = "Makes item drops 3D" })) { + Register3DItemDrops(); + } UIWidgets::CVarCheckbox( "Disable Black Bar Letterboxes", "gEnhancements.Graphics.DisableBlackBars", { .tooltip = "Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be " diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 663f257c4..a5163d2aa 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -29,6 +29,7 @@ void InitEnhancements() { // Graphics RegisterDisableBlackBars(); + Register3DItemDrops(); // Masks RegisterFastTransformation(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 57c54f414..4d6dd518d 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -23,6 +23,7 @@ #include "Restorations/PowerCrouchStab.h" #include "Restorations/SideRoll.h" #include "Restorations/TatlISG.h" +#include "Graphics/3DItemDrops.h" #include "Graphics/PlayAsKafei.h" #include "Player/Player.h" #include "Songs/EnableSunsSong.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 1b2fdb2e9..365a0f182 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -55,6 +55,7 @@ typedef enum { GI_VB_FLIP_HOP_VARIABLE, GI_VB_DISABLE_LETTERBOX, GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, + GI_VB_DRAW_SLIME_BODY_ITEM, } GIVanillaBehavior; typedef enum { diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp new file mode 100644 index 000000000..f64312c63 --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp @@ -0,0 +1,185 @@ +#include "3DItemDrops.h" +#include "libultraship/libultraship.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "z64.h" +#include "functions.h" +#include "overlays/actors/ovl_En_Slime/z_en_slime.h" +extern PlayState* gPlayState; +void EnItem00_Draw(Actor* thisx, PlayState* play); +} + +bool ItemShouldSpinWhen3D(Actor* actor) { + EnItem00* enItem00 = (EnItem00*)actor; + + // Exclude actors that already have spin normally, or shouldn't spin ever + if ((actor->params <= ITEM00_RUPEE_RED) || ((actor->params == ITEM00_RECOVERY_HEART) && (enItem00->unk152 < 0)) || + (actor->params == ITEM00_HEART_PIECE) || (actor->params == ITEM00_HEART_CONTAINER) || + (actor->params == ITEM00_RUPEE_HUGE) || (actor->params == ITEM00_RUPEE_PURPLE) || + (actor->params == ITEM00_SHIELD_HERO) || (actor->params == ITEM00_MAP) || (actor->params == ITEM00_COMPASS)) { + return false; + } + + return true; +} + +void EnItem00_3DItemsDraw(Actor* actor, PlayState* play) { + EnItem00* enItem00 = (EnItem00*)actor; + + if (!(enItem00->unk14E & enItem00->unk150)) { + switch (enItem00->actor.params) { + case ITEM00_RUPEE_GREEN: + Matrix_Scale(25.0f, 25.0f, 25.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RUPEE_GREEN); + break; + case ITEM00_RUPEE_BLUE: + Matrix_Scale(25.0f, 25.0f, 25.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RUPEE_BLUE); + break; + case ITEM00_RUPEE_RED: + Matrix_Scale(25.0f, 25.0f, 25.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RUPEE_RED); + break; + case ITEM00_RUPEE_HUGE: + Matrix_Scale(17.5f, 17.5f, 17.5f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RUPEE_HUGE); + break; + case ITEM00_RUPEE_PURPLE: + Matrix_Scale(17.5f, 17.5f, 17.5f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RUPEE_PURPLE); + break; + case ITEM00_HEART_PIECE: + Matrix_Scale(16.0f, 16.0f, 16.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_HEART_PIECE); + break; + case ITEM00_HEART_CONTAINER: + Matrix_Scale(16.0f, 16.0f, 16.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_HEART_CONTAINER); + break; + case ITEM00_RECOVERY_HEART: + Matrix_Scale(16.0f, 16.0f, 16.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_RECOVERY_HEART); + break; + case ITEM00_BOMBS_A: + case ITEM00_BOMBS_B: + case ITEM00_BOMBS_0: + Matrix_Scale(8.0f, 8.0f, 8.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_BOMB); + break; + case ITEM00_ARROWS_10: + Matrix_Scale(7.0f, 7.0f, 7.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_ARROWS_SMALL); + break; + case ITEM00_ARROWS_30: + Matrix_Scale(7.0f, 7.0f, 7.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_ARROWS_MEDIUM); + break; + case ITEM00_ARROWS_40: + case ITEM00_ARROWS_50: + Matrix_Scale(7.0f, 7.0f, 7.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_ARROWS_LARGE); + break; + case ITEM00_MAGIC_JAR_SMALL: + Matrix_Scale(8.0f, 8.0f, 8.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_MAGIC_JAR_SMALL); + break; + case ITEM00_MAGIC_JAR_BIG: + Matrix_Scale(8.0f, 8.0f, 8.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_MAGIC_JAR_BIG); + break; + case ITEM00_DEKU_STICK: + Matrix_Scale(7.5f, 7.5f, 7.5f, MTXMODE_APPLY); + GetItem_Draw(play, GID_DEKU_STICK); + break; + case ITEM00_SMALL_KEY: + Matrix_Scale(8.0f, 8.0f, 8.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_KEY_SMALL); + break; + case ITEM00_DEKU_NUTS_1: + case ITEM00_DEKU_NUTS_10: + Matrix_Scale(9.0f, 9.0f, 9.0f, MTXMODE_APPLY); + GetItem_Draw(play, GID_DEKU_NUTS); + break; + case ITEM00_SHIELD_HERO: + GetItem_Draw(play, GID_SHIELD_HERO); + break; + case ITEM00_MAP: + GetItem_Draw(play, GID_DUNGEON_MAP); + break; + case ITEM00_COMPASS: + GetItem_Draw(play, GID_COMPASS); + break; + } + } +} + +void DrawSlime3DItem(GIVanillaBehavior _, bool* should, void* opt) { + *should = false; + EnSlime* slime = static_cast(opt); + + // Rotate 3D item with chu body + Matrix_RotateYS(slime->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_Scale(0.25f, 0.25f, 0.25f, MTXMODE_APPLY); + + switch (slime->actor.params) { + case EN_SLIME_TYPE_RED: + GetItem_Draw(gPlayState, GID_RECOVERY_HEART); + break; + case EN_SLIME_TYPE_GREEN: + GetItem_Draw(gPlayState, GID_MAGIC_JAR_SMALL); + break; + case EN_SLIME_TYPE_YELLOW: + GetItem_Draw(gPlayState, GID_ARROWS_SMALL); + break; + } +} + +void Register3DItemDrops() { + static HOOK_ID actorInitHookID = 0; + static HOOK_ID actorUpdateHookID = 0; + static HOOK_ID slimeVBHookID = 0; + GameInteractor::Instance->UnregisterGameHookForID(actorInitHookID); + GameInteractor::Instance->UnregisterGameHookForID(actorUpdateHookID); + GameInteractor::Instance->UnregisterGameHookForID(slimeVBHookID); + actorInitHookID = 0; + actorUpdateHookID = 0; + slimeVBHookID = 0; + + if (gPlayState != NULL) { + Actor* actor = gPlayState->actorCtx.actorLists[ACTORCAT_MISC].first; + + while (actor != NULL) { + if (actor->id == ACTOR_EN_ITEM00) { + if (CVarGetInteger("gEnhancements.Graphics.3DItemDrops", 0)) { + actor->draw = EnItem00_3DItemsDraw; + } else { + actor->draw = EnItem00_Draw; + + // Reset rotation for bill-boarded sprites + if (ItemShouldSpinWhen3D(actor)) { + actor->shape.rot.y = 0; + } + } + } + + actor = actor->next; + } + } + + if (!CVarGetInteger("gEnhancements.Graphics.3DItemDrops", 0)) { + return; + } + + actorInitHookID = GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_ITEM00, [](Actor* actor) { actor->draw = EnItem00_3DItemsDraw; }); + actorUpdateHookID = GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_ITEM00, [](Actor* actor) { + // Add spin to normally bill-boarded items + if (ItemShouldSpinWhen3D(actor)) { + actor->shape.rot.y += 0x3C0; + } + }); + slimeVBHookID = GameInteractor::Instance->RegisterGameHookForID( + GI_VB_DRAW_SLIME_BODY_ITEM, DrawSlime3DItem); +} diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.h b/mm/2s2h/Enhancements/Graphics/3DItemDrops.h new file mode 100644 index 000000000..2801aaac2 --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.h @@ -0,0 +1,6 @@ +#ifndef GRAPHICS_3D_ITEM_DROPS_H +#define GRAPHICS_3D_ITEM_DROPS_H + +void Register3DItemDrops(); + +#endif // GRAPHICS_3D_ITEM_DROPS_H diff --git a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c index ff1b3322e..fcc729cdd 100644 --- a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c +++ b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c @@ -7,6 +7,8 @@ #include "z_en_slime.h" #include "overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_200) #define THIS ((EnSlime*)thisx) @@ -1239,11 +1241,14 @@ void EnSlime_Draw(Actor* thisx, PlayState* play) { Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + (2000.0f * this->actor.scale.y), this->actor.world.pos.z, MTXMODE_NEW); - Matrix_Scale(0.03f, 0.03f, 0.03f, MTXMODE_APPLY); - gSPSegment(POLY_OPA_DISP++, 8, (uintptr_t)this->itemDropTex); - gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_OPA_DISP++, gItemDropDL); + if (GameInteractor_Should(GI_VB_DRAW_SLIME_BODY_ITEM, true, this)) { + Matrix_Scale(0.03f, 0.03f, 0.03f, MTXMODE_APPLY); + + gSPSegment(POLY_OPA_DISP++, 8, (uintptr_t)this->itemDropTex); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gItemDropDL); + } } Actor_DrawDamageEffects(play, &this->actor, this->bodyPartsPos, EN_SLIME_BODYPART_MAX, this->drawDmgEffScale, From d0caa0f78c8f17123007691e040700f29cfbcc1c Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:12:08 -0600 Subject: [PATCH 23/82] [Cheat] Stop time in Temples and Dungeons (#700) * add cheat to stop time in temples * better tooltip * adds option to stop time in dungeons * clean up * add other pirate fortress scenes * add new hook * update tooltips * rename hook * add clarification Co-authored-by: Archez * clean combobox --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 14 ++++ mm/2s2h/Enhancements/Cheats/TimeStop.cpp | 65 +++++++++++++++++++ mm/2s2h/Enhancements/Cheats/TimeStop.h | 6 ++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 7 ++ .../GameInteractor/GameInteractor.cpp | 7 ++ .../GameInteractor/GameInteractor.h | 2 + mm/2s2h/z_play_2SH.cpp | 4 ++ 8 files changed, 106 insertions(+) create mode 100644 mm/2s2h/Enhancements/Cheats/TimeStop.cpp create mode 100644 mm/2s2h/Enhancements/Cheats/TimeStop.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index edf218909..ba2b746e0 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -57,6 +57,12 @@ static const std::unordered_map alwaysWinDoggyraceOptions { ALWAYS_WIN_DOGGY_RACE_ALWAYS, "Always" }, }; +static const std::unordered_map timeStopOptions = { + { TIME_STOP_OFF, "Off" }, + { TIME_STOP_TEMPLES, "Temples" }, + { TIME_STOP_TEMPLES_DUNGEONS, "Temples + Mini Dungeons" }, +}; + namespace BenGui { std::shared_ptr> availableWindowBackends; std::unordered_map availableWindowBackendsMap; @@ -678,6 +684,14 @@ void DrawCheatsMenu() { { .tooltip = "Holding L makes you float into the air" })) { RegisterMoonJumpOnL(); } + UIWidgets::CVarCombobox( + "Stop Time in Dungeons", "gCheats.TempleTimeStop", timeStopOptions, + { .tooltip = "Stops time from advancing in selected areas. Requires a room change to update.\n\n" + "- Off: Vanilla behaviour.\n" + "- Temples: Stops time in Woodfall, Snowhead, Great Bay, and Stone Tower Temples.\n" + "- Temples + Mini Dungeons: In addition to the above temples, stops time in both Spider " + "Houses, Pirate's Fortress, Beneath the Well, Ancient Castle of Ikana, and Secret Shrine.", + .defaultIndex = TIME_STOP_OFF }); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Cheats/TimeStop.cpp b/mm/2s2h/Enhancements/Cheats/TimeStop.cpp new file mode 100644 index 000000000..fb12fc0b5 --- /dev/null +++ b/mm/2s2h/Enhancements/Cheats/TimeStop.cpp @@ -0,0 +1,65 @@ +#include +#include "BenPort.h" +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "Enhancements/Enhancements.h" + +extern "C" { +#include +#include +} + +void RegisterTimeStopInTemples() { + GameInteractor::Instance->RegisterGameHook([](s16 sceneId, s8 roomNum) { + uint8_t selectedOption = CVarGetInteger("gCheats.TempleTimeStop", TIME_STOP_OFF); + + switch (selectedOption) { + case TIME_STOP_TEMPLES_DUNGEONS: + switch (gPlayState->sceneId) { + // Swamp + Ocean Spider House + case SCENE_KINSTA1: + case SCENE_KINDAN2: + // Pirates' Fortress + case SCENE_KAIZOKU: + case SCENE_PIRATE: + case SCENE_TORIDE: + // Beneath the Well + case SCENE_REDEAD: + // Ancient Castle of Ikana + Igos's Lair + case SCENE_CASTLE: + case SCENE_IKNINSIDE: + // Secret Shrine + case SCENE_RANDOM: + R_TIME_SPEED = 0; + break; + default: + break; + } + // fallthrough + case TIME_STOP_TEMPLES: + switch (gPlayState->sceneId) { + // Woodfall Temple + Odolwa + case SCENE_MITURIN: + case SCENE_MITURIN_BS: + // Snowhead Temple + Goht + case SCENE_HAKUGIN: + case SCENE_HAKUGIN_BS: + // Great Bay Temple + Gyorg + case SCENE_SEA: + case SCENE_SEA_BS: + // Stone Tower Temple (+ inverted) + Twinmold + case SCENE_INISIE_N: + case SCENE_INISIE_R: + case SCENE_INISIE_BS: + R_TIME_SPEED = 0; + break; + default: + break; + } + break; + case TIME_STOP_OFF: + break; + default: + break; + } + }); +} diff --git a/mm/2s2h/Enhancements/Cheats/TimeStop.h b/mm/2s2h/Enhancements/Cheats/TimeStop.h new file mode 100644 index 000000000..a2729fe2d --- /dev/null +++ b/mm/2s2h/Enhancements/Cheats/TimeStop.h @@ -0,0 +1,6 @@ +#ifndef CHEATS_TIME_STOPS_H +#define CHEATS_TIME_STOPS_H + +void RegisterTimeStopInTemples(); + +#endif // CHEATS_TIME_STOPS_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index a5163d2aa..0f0867f8a 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -12,6 +12,7 @@ void InitEnhancements() { RegisterMoonJumpOnL(); RegisterUnbreakableRazorSword(); RegisterUnrestrictedItems(); + RegisterTimeStopInTemples(); // Clock RegisterTextBasedClock(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 4d6dd518d..dbdc7364a 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -11,6 +11,7 @@ #include "Cheats/Cheats.h" #include "Cheats/UnbreakableRazorSword.h" #include "Cheats/UnrestrictedItems.h" +#include "Cheats/TimeStop.h" #include "Cycle/EndOfCycle.h" #include "Equipment/SkipMagicArrowEquip.h" #include "Masks/BlastMaskKeg.h" @@ -37,6 +38,12 @@ enum AlwaysWinDoggyRaceOptions { ALWAYS_WIN_DOGGY_RACE_ALWAYS, }; +enum TimeStopOptions { + TIME_STOP_OFF, + TIME_STOP_TEMPLES, + TIME_STOP_TEMPLES_DUNGEONS, +}; + enum ClockTypeOptions { CLOCK_TYPE_ORIGINAL, CLOCK_TYPE_TEXT_BASED, diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index d0d9e4218..f27becaa0 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -57,6 +57,13 @@ void GameInteractor_ExecuteOnRoomInit(s16 sceneId, s8 roomNum) { GameInteractor::Instance->ExecuteHooksForFilter(sceneId, roomNum); } +void GameInteractor_ExecuteAfterRoomSceneCommands(s16 sceneId, s8 roomNum) { + SPDLOG_DEBUG("AfterRoomSceneCommands: sceneId: {}, roomNum: {}", sceneId, roomNum); + GameInteractor::Instance->ExecuteHooks(sceneId, roomNum); + GameInteractor::Instance->ExecuteHooksForID(sceneId, sceneId, roomNum); + GameInteractor::Instance->ExecuteHooksForFilter(sceneId, roomNum); +} + void GameInteractor_ExecuteOnPlayDestroy() { GameInteractor::Instance->ExecuteHooks(); } diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 365a0f182..41d5f99ab 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -267,6 +267,7 @@ class GameInteractor { DEFINE_HOOK(OnSceneInit, (s8 sceneId, s8 spawnNum)); DEFINE_HOOK(OnRoomInit, (s8 sceneId, s8 roomNum)); + DEFINE_HOOK(AfterRoomSceneCommands, (s8 sceneId, s8 roomNum)); DEFINE_HOOK(OnPlayDestroy, ()); DEFINE_HOOK(ShouldActorInit, (Actor * actor, bool* should)); @@ -311,6 +312,7 @@ void GameInteractor_ExecuteBeforeMoonCrashSaveReset(); void GameInteractor_ExecuteOnSceneInit(s16 sceneId, s8 spawnNum); void GameInteractor_ExecuteOnRoomInit(s16 sceneId, s8 roomNum); +void GameInteractor_ExecuteAfterRoomSceneCommands(s16 sceneId, s8 roomNum); void GameInteractor_ExecuteOnPlayDestroy(); bool GameInteractor_ShouldActorInit(Actor* actor); diff --git a/mm/2s2h/z_play_2SH.cpp b/mm/2s2h/z_play_2SH.cpp index 3432ab9e3..7cafb1ac5 100644 --- a/mm/2s2h/z_play_2SH.cpp +++ b/mm/2s2h/z_play_2SH.cpp @@ -3,6 +3,8 @@ #include "2s2h/resource/type/Scene.h" #include #include +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + extern "C" { #include "global.h" extern uintptr_t gSegments[NUM_SEGMENTS]; @@ -71,6 +73,8 @@ extern "C" s32 OTRfunc_800973FC(PlayState* play, RoomContext* roomCtx) { if (Environment_GetStormState(play) == STORM_STATE_OFF) { Environment_StopStormNatureAmbience(play); } + // Insert hook + GameInteractor_ExecuteAfterRoomSceneCommands(play->sceneId, roomCtx->curRoom.num); return 1; } From 0ec23b34ba71f410c04a28fc89a255a23adceebe Mon Sep 17 00:00:00 2001 From: mckinlee Date: Mon, 5 Aug 2024 15:18:52 -0400 Subject: [PATCH 24/82] [Enhancement] Pause Owl Warp (#620) * Add Pause Owl Warp Enhancement - **mm/2s2h/BenGui/BenMenuBar.cpp**: Updated menu to include new enhancement options. - **mm/2s2h/Enhancements/Enhancements.cpp**: Registered the new Pause Owl Warp enhancement. - **mm/2s2h/Enhancements/Enhancements.h**: Declared functions for the new enhancement. - **mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp**: Implemented the Pause Owl Warp functionality. - **mm/2s2h/Enhancements/Songs/PauseOwlWarp.h**: Header file for the Pause Owl Warp implementation. - **mm/include/functions.h**: Added function declarations related to the new enhancement. - **mm/src/overlays/kaleido_scope/ovl_kaleido_map.c**: Modified to support the new enhancement. - **mm/src/overlays/kaleido_scope/ovl_kaleido_scope_NES.c**: Modified to support the new enhancement. * ran clang-format script * Additional logic and bug fixes * Fix PauseOwlWarp cursor logic triggering on dungeon map -Added a check to ensure PauseOwlWarp's cursor logic is only triggered when not in a dungeon. * Add Song of Soaring check - To make it more in line with vanilla, you are now required to have the Song of Soaring to use this enhancement. * bug fix and ran clang-format script -My previous commit had a extra condition that wasn't needed that caused a bug where the world map points locations pointed to activated owl statues. * added more checks * Simplified complex conditional statements * possibly fix macos build issue? * index warping logic added * implement feedback from Archez * shot in the dark macos build fix? * how bout now? * revert back to previous commit * if this fixed the macos build issue it'll be thanks to cclark25... let's pray * add debugeditor check - thanks archez! * Moved debugEditor check to prevent triggering ALL pauseOwlWarp logic. wtf was I thinking earlier --- mm/2s2h/BenGui/BenMenuBar.cpp | 3 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp | 222 ++++++++++++++++++ mm/2s2h/Enhancements/Songs/PauseOwlWarp.h | 15 ++ mm/CMakeLists.txt | 1 + mm/include/functions.h | 2 + .../ovl_kaleido_scope/z_kaleido_map.c | 6 +- .../ovl_kaleido_scope/z_kaleido_scope_NES.c | 4 +- 9 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp create mode 100644 mm/2s2h/Enhancements/Songs/PauseOwlWarp.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index ba2b746e0..afdb52871 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -653,6 +653,9 @@ void DrawEnhancementsMenu() { { .tooltip = "Enables using the Dpad for Ocarina playback." }); UIWidgets::CVarCheckbox("Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput", { .tooltip = "Prevent dropping inputs when playing the ocarina quickly" }); + UIWidgets::CVarCheckbox("Pause Owl Warp", "gEnhancements.Songs.PauseOwlWarp", + { .tooltip = "Allows the player to use the pause menu map to owl warp instead of " + "having to play the Song of Soaring." }); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 0f0867f8a..1590e8a67 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -48,6 +48,7 @@ void InitEnhancements() { // Songs RegisterEnableSunsSong(); + RegisterPauseOwlWarp(); // Restorations RegisterPowerCrouchStab(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index dbdc7364a..da9a3a2bb 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -28,6 +28,7 @@ #include "Graphics/PlayAsKafei.h" #include "Player/Player.h" #include "Songs/EnableSunsSong.h" +#include "Songs/PauseOwlWarp.h" #include "Saving/SavingEnhancements.h" #include "Graphics/DisableBlackBars.h" #include "Modes/TimeMovesWhenYouMove.h" diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp new file mode 100644 index 000000000..a86c1b943 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp @@ -0,0 +1,222 @@ +#include "PauseOwlWarp.h" +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" + +extern f32 sPauseMenuVerticalOffset; +extern u16 sCursorPointsToOcarinaModes[]; +extern u16 sOwlWarpPauseItems[]; +extern u16 D_80AF343C[]; +extern s16 sInDungeonScene; +} + +extern "C" bool PauseOwlWarp_IsOwlWarpEnabled() { + return CVarGetInteger("gEnhancements.Songs.PauseOwlWarp", 0) && CHECK_QUEST_ITEM(QUEST_SONG_SOARING) && + gSaveContext.save.saveInfo.playerData.owlActivationFlags != 0 && + gPlayState->pauseCtx.debugEditor == DEBUG_EDITOR_NONE; +} + +static bool sIsConfirming = false; +static u16 sStickAdjTimer = 0; + +void ResetMessageContext() { + gPlayState->msgCtx.msgLength = 0; + gPlayState->msgCtx.msgMode = MSGMODE_NONE; +} + +void ClosePauseMenu(PauseContext* pauseCtx) { + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_NONE); + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_END; + gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL; + sIsConfirming = false; + Message_CloseTextbox(gPlayState); + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; +} + +void HandleConfirmingState(PauseContext* pauseCtx, Input* input) { + if (Message_ShouldAdvance(gPlayState)) { + ResetMessageContext(); + sIsConfirming = false; + if (gPlayState->msgCtx.choiceIndex == 0) { // Yes + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_NONE); + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + gPlayState->msgCtx.ocarinaMode = sCursorPointsToOcarinaModes[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + Audio_PlaySfx(NA_SE_SY_DECIDE); + Message_CloseTextbox(gPlayState); + sPauseMenuVerticalOffset = -6240.0f; + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + gPlayState->nextEntrance = D_80AF343C[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + gPlayState->transitionTrigger = TRANS_TRIGGER_START; + gPlayState->transitionType = TRANS_TYPE_FADE_WHITE; + } else { // No + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP); + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + Message_CloseTextbox(gPlayState); + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + ResetMessageContext(); + sIsConfirming = false; + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + Message_CloseTextbox(gPlayState); + } else if (CHECK_BTN_ALL(input->press.button, BTN_START)) { + ClosePauseMenu(pauseCtx); + } +} + +void UpdateCursorForOwlWarpPoints(PauseContext* pauseCtx) { + if (pauseCtx->cursorSpecialPos == 0) { + if (pauseCtx->stickAdjX > 30) { + pauseCtx->cursorShrinkRate = 4.0f; + sStickAdjTimer = 0; + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) { + KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT); + return; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } else if (pauseCtx->stickAdjX < -30) { + pauseCtx->cursorShrinkRate = 4.0f; + sStickAdjTimer = 0; + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < OWL_WARP_GREAT_BAY_COAST) { + KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT); + return; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } else { + sStickAdjTimer++; + } + } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && pauseCtx->stickAdjX > 30) { + KaleidoScope_MoveCursorFromSpecialPos(gPlayState); + for (int i = OWL_WARP_GREAT_BAY_COAST; i <= OWL_WARP_STONE_TOWER; i++) { + if (pauseCtx->worldMapPoints[i]) { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + KaleidoScope_UpdateWorldMapCursor(gPlayState); + KaleidoScope_UpdateNamePanel(gPlayState); + return; + } + } + KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT); + } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && pauseCtx->stickAdjX < -30) { + KaleidoScope_MoveCursorFromSpecialPos(gPlayState); + for (int i = OWL_WARP_STONE_TOWER; i >= OWL_WARP_GREAT_BAY_COAST; i--) { + if (pauseCtx->worldMapPoints[i]) { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + KaleidoScope_UpdateWorldMapCursor(gPlayState); + KaleidoScope_UpdateNamePanel(gPlayState); + return; + } + } + KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT); + } +} + +void HandlePauseOwlWarp(PauseContext* pauseCtx) { + // Initialize worldMapPoints based on owl activation flags + for (int i = OWL_WARP_STONE_TOWER; i >= OWL_WARP_GREAT_BAY_COAST; i--) { + pauseCtx->worldMapPoints[i] = (gSaveContext.save.saveInfo.playerData.owlActivationFlags >> i) & 1; + } + + // Special condition for when only the 15th owl statue is activated + if (gSaveContext.save.saveInfo.playerData.owlActivationFlags == (1 << 15)) { + for (int i = REGION_GREAT_BAY; i < REGION_MAX; i++) { + if ((gSaveContext.save.saveInfo.regionsVisited >> i) & 1) { + switch (i) { + case REGION_GREAT_BAY: + pauseCtx->worldMapPoints[OWL_WARP_GREAT_BAY_COAST] = true; + break; + case REGION_ZORA_HALL: + pauseCtx->worldMapPoints[OWL_WARP_ZORA_CAPE] = true; + break; + case REGION_ROMANI_RANCH: + pauseCtx->worldMapPoints[OWL_WARP_SNOWHEAD] = true; + break; + case REGION_DEKU_PALACE: + pauseCtx->worldMapPoints[OWL_WARP_MOUNTAIN_VILLAGE] = true; + break; + case REGION_WOODFALL: + pauseCtx->worldMapPoints[OWL_WARP_CLOCK_TOWN] = true; + break; + case REGION_CLOCK_TOWN: + pauseCtx->worldMapPoints[OWL_WARP_MILK_ROAD] = true; + break; + case REGION_SNOWHEAD: + pauseCtx->worldMapPoints[OWL_WARP_WOODFALL] = true; + break; + case REGION_IKANA_GRAVEYARD: + pauseCtx->worldMapPoints[OWL_WARP_SOUTHERN_SWAMP] = true; + break; + case REGION_IKANA_CANYON: + pauseCtx->worldMapPoints[OWL_WARP_IKANA_CANYON] = true; + break; + case REGION_GORON_VILLAGE: + pauseCtx->worldMapPoints[OWL_WARP_STONE_TOWER] = true; + break; + } + } + } + } + + // Ensure cursor starts at an activated point + if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + for (int i = OWL_WARP_GREAT_BAY_COAST; i <= OWL_WARP_STONE_TOWER; i++) { + if (pauseCtx->worldMapPoints[i]) { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; + break; + } + } + } + + Player* player = GET_PLAYER(gPlayState); + Input* input = &gPlayState->state.input[0]; + + if ((pauseCtx->state == PAUSE_STATE_MAIN && pauseCtx->pageIndex == PAUSE_MAP && pauseCtx->mapPageRoll == 0) || + sIsConfirming) { + if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { + ClosePauseMenu(pauseCtx); + } else if (CHECK_BTN_ALL(input->press.button, BTN_A) && !sIsConfirming) { + if (pauseCtx->cursorSpecialPos == 0 && pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + Audio_PlaySfx(NA_SE_SY_DECIDE); + Message_StartTextbox(gPlayState, 0x1B93, NULL); + sIsConfirming = true; + } + } else if (sIsConfirming) { + HandleConfirmingState(pauseCtx, input); + } else { + KaleidoScope_UpdateOwlWarpNamePanel(gPlayState); + } + + UpdateCursorForOwlWarpPoints(pauseCtx); + } +} + +void RegisterPauseOwlWarp() { + GameInteractor::Instance->RegisterGameHook([](PauseContext* pauseCtx) { + if (!sInDungeonScene && PauseOwlWarp_IsOwlWarpEnabled() && CHECK_QUEST_ITEM(QUEST_SONG_SOARING)) { + HandlePauseOwlWarp(pauseCtx); + } + }); +} \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h new file mode 100644 index 000000000..b6adfeab9 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h @@ -0,0 +1,15 @@ +#ifndef PAUSE_OWL_WARP_H +#define PAUSE_OWL_WARP_H + +#ifdef __cplusplus +extern "C" { +#endif + +void RegisterPauseOwlWarp(void); +bool PauseOwlWarp_IsOwlWarpEnabled(void); + +#ifdef __cplusplus +} +#endif + +#endif // PAUSE_OWL_WARP_H \ No newline at end of file diff --git a/mm/CMakeLists.txt b/mm/CMakeLists.txt index b03c9ff59..1f4a1f728 100644 --- a/mm/CMakeLists.txt +++ b/mm/CMakeLists.txt @@ -523,6 +523,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") $<$: #-Werror-implicit-function-declaration -Wno-incompatible-pointer-types + -Wno-int-conversion > $<$:-fpermissive> $<$: diff --git a/mm/include/functions.h b/mm/include/functions.h index 62ac3cb60..2388f8ca4 100644 --- a/mm/include/functions.h +++ b/mm/include/functions.h @@ -1328,6 +1328,8 @@ void osContGetReadData(OSContPad* pad); // #region 2S2H [Port] Previously unavailable functions, made available for porting void PadMgr_ThreadEntry(); void Heaps_Alloc(void); +void KaleidoScope_UpdateOwlWarpNamePanel(PlayState* play); +void KaleidoScope_UpdateNamePanel(PlayState* play); // #endregion // #region 2S2H [Port] New methods added for porting void AudioSeq_SetPortVolumeScale(u8 seqPlayerIndex, f32 volume); diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c index d0e23c839..ffa599dde 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c @@ -13,6 +13,8 @@ #include "BenPort.h" +#include "2s2h/Enhancements/Songs/PauseOwlWarp.h" + // 2S2H [Port] (and line 26) don't do pointer math and access the list of digits directly. extern const char* sCounterTextures[]; @@ -675,7 +677,7 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { Gfx_SetupDL42_Opa(play->state.gfxCtx); - if (!IS_PAUSE_STATE_OWLWARP) { + if (!IS_PAUSE_STATE_OWLWARP && !PauseOwlWarp_IsOwlWarpEnabled()) { // Browsing the world map regions on the pause menu gDPLoadTextureBlock(POLY_OPA_DISP++, gWorldMapDotTex, G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, @@ -846,7 +848,7 @@ void KaleidoScope_UpdateWorldMapCursor(PlayState* play) { s16 oldCursorPoint; if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && - (pauseCtx->pageIndex == PAUSE_MAP)) { + (pauseCtx->pageIndex == PAUSE_MAP) && !PauseOwlWarp_IsOwlWarpEnabled()) { pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE; oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index 5446f710c..79a7d2ef6 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -24,6 +24,8 @@ #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Songs/PauseOwlWarp.h" + // Page Textures (Background of Page): // Broken up into multiple textures. // Numbered by column/row. @@ -2901,7 +2903,7 @@ void KaleidoScope_UpdateCursorSize(PlayState* play) { case PAUSE_MAP: if (!sInDungeonScene) { - if (IS_PAUSE_STATE_OWLWARP) { + if (IS_PAUSE_STATE_OWLWARP || PauseOwlWarp_IsOwlWarpEnabled()) { pauseCtx->cursorX = sOwlWarpWorldMapCursorsX[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; pauseCtx->cursorY = sOwlWarpWorldMapCursorsY[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; } else { From 4a57bdbc5f429feacad94c06e3a05967f374fb70 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Fri, 9 Aug 2024 15:42:34 -0500 Subject: [PATCH 25/82] Add widescreen actor culling option (#652) --- mm/2s2h/BenGui/BenMenuBar.cpp | 9 ++++---- mm/src/code/z_actor.c | 42 ++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index afdb52871..cadc3bbe8 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -562,11 +562,10 @@ void DrawEnhancementsMenu() { { .tooltip = "Disables the distance check for scene geometry, allowing it to be drawn no matter how far " "away it is from the player. This may have unintended side effects." }); - // BENTODO: Not implemented yet - // UIWidgets::CVarCheckbox("Widescreen Actor Culling", - // "gEnhancements.Graphics.ActorCullingAccountsForWidescreen", - // { .tooltip = "Adjusts the culling planes to account for widescreen resolutions. " - // "This may have unintended side effects." }); + UIWidgets::CVarCheckbox("Widescreen Actor Culling", + "gEnhancements.Graphics.ActorCullingAccountsForWidescreen", + { .tooltip = "Adjusts the culling planes to account for widescreen resolutions. " + "This may have unintended side effects." }); if (UIWidgets::CVarSliderInt( "Increase Actor Draw Distance: %dx", "gEnhancements.Graphics.IncreaseActorDrawDistance", 1, 5, 1, { .tooltip = diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 2a967694b..8be769e81 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -23,6 +23,7 @@ #include #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/BenPort.h" // bss // FaultClient sActorFaultClient; // 2 funcs @@ -3084,24 +3085,38 @@ void Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projecte (projectedPos->z < ((actor->uncullZoneForward * drawMulti) + (actor->uncullZoneScale * drawMulti))); if (updateCheck || drawCheck) { - f32 phi_f12; - f32 phi_f2 = CLAMP_MIN(projectedW, 1.0f); - f32 phi_f14; - f32 phi_f16; + // Ensure the projected W value is at least 1.0 + f32 clampedProjectedW = CLAMP_MIN(projectedW, 1.0f); + f32 uncullZoneScaleDiagonal; + f32 uncullZoneScaleVertical; + f32 uncullZoneDownwardAdjusted; + // Adjust calculations if the field of view is not the default 60 degrees if (play->view.fovy != 60.0f) { - phi_f12 = actor->uncullZoneScale * play->projectionMtxFDiagonal.x * 0.76980036f; // sqrt(16/27) + uncullZoneScaleDiagonal = + actor->uncullZoneScale * play->projectionMtxFDiagonal.x * 0.76980036f; // sqrt(16/27) - phi_f14 = play->projectionMtxFDiagonal.y * 0.57735026f; // 1 / sqrt(3) - phi_f16 = actor->uncullZoneScale * phi_f14; - phi_f14 *= actor->uncullZoneDownward; + uncullZoneScaleVertical = play->projectionMtxFDiagonal.y * 0.57735026f; // 1 / sqrt(3) + uncullZoneDownwardAdjusted = actor->uncullZoneScale * uncullZoneScaleVertical; + uncullZoneScaleVertical *= actor->uncullZoneDownward; } else { - phi_f16 = phi_f12 = actor->uncullZoneScale; - phi_f14 = actor->uncullZoneDownward; + uncullZoneDownwardAdjusted = uncullZoneScaleDiagonal = actor->uncullZoneScale; + uncullZoneScaleVertical = actor->uncullZoneDownward; } - if (((fabsf(projectedPos->x) - phi_f12) < phi_f2) && ((-phi_f2 < (projectedPos->y + phi_f14))) && - ((projectedPos->y - phi_f16) < phi_f2)) { + if (CVarGetInteger("gEnhancements.Graphics.ActorCullingAccountsForWidescreen", 0)) { + float originalAspectRatio = 4.0f / 3.0f; + float currentAspectRatio = OTRGetAspectRatio(); + float aspectRatioMultiplier = MAX(currentAspectRatio / originalAspectRatio, 1.0f); + + clampedProjectedW *= aspectRatioMultiplier; + } + + bool isWithinHorizontalCullZone = ((fabsf(projectedPos->x) - uncullZoneScaleDiagonal) < clampedProjectedW); + bool isAboveBottomOfCullZone = ((-clampedProjectedW < (projectedPos->y + uncullZoneScaleVertical))); + bool isBelowTopOfCullZone = ((projectedPos->y - uncullZoneDownwardAdjusted) < clampedProjectedW); + + if (isWithinHorizontalCullZone && isAboveBottomOfCullZone && isBelowTopOfCullZone) { *shouldDraw = drawCheck; *shouldUpdate = updateCheck; } @@ -3148,7 +3163,8 @@ void Actor_DrawAll(PlayState* play, ActorContext* actorCtx) { bool shipShouldDraw = false; bool shipShouldUpdate = false; if (CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1) > 1 || - CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1) > 1) { + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1) > 1 || + CVarGetInteger("gEnhancements.Graphics.ActorCullingAccountsForWidescreen", 0)) { Ship_CalcShouldDrawAndUpdate(play, actor, &actor->projectedPos, actor->projectedW, &shipShouldDraw, &shipShouldUpdate); From 63ffddb67bdca966b91649cb29f6c810f7558a05 Mon Sep 17 00:00:00 2001 From: Archez Date: Wed, 14 Aug 2024 18:41:31 -0400 Subject: [PATCH 26/82] Bump LUS (#754) --- libultraship | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libultraship b/libultraship index 31e9b009f..3d2b4da8e 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 31e9b009f94e7074a847c7954926cba354cd7c72 +Subproject commit 3d2b4da8e327a6a096993996c5280c069a92c03f From 53faf37dc1d1472b372af27370d61e318f4351d7 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 18 Aug 2024 10:41:17 -0500 Subject: [PATCH 27/82] Add persistent bunny mask enhancement (#537) --- mm/2s2h/BenGui/BenMenuBar.cpp | 5 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + .../GameInteractor/GameInteractor.cpp | 17 ++ .../GameInteractor/GameInteractor.h | 13 +- .../Enhancements/Masks/PersistentMasks.cpp | 206 ++++++++++++++++++ mm/2s2h/Enhancements/Masks/PersistentMasks.h | 7 + mm/include/gfxprint.h | 8 + mm/include/z64.h | 2 - mm/src/code/z_player_lib.c | 3 + .../actors/ovl_player_actor/z_player.c | 33 +-- .../ovl_kaleido_scope/z_kaleido_mask.c | 29 ++- .../ovl_kaleido_scope/z_kaleido_scope_NES.c | 8 + 13 files changed, 305 insertions(+), 28 deletions(-) create mode 100644 mm/2s2h/Enhancements/Masks/PersistentMasks.cpp create mode 100644 mm/2s2h/Enhancements/Masks/PersistentMasks.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index cadc3bbe8..4a1dd56e9 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -593,6 +593,11 @@ void DrawEnhancementsMenu() { UIWidgets::CVarCheckbox("Fierce Deity's Mask Anywhere", "gEnhancements.Masks.FierceDeitysAnywhere", { .tooltip = "Allow using Fierce Deity's mask outside of boss rooms." }); UIWidgets::CVarCheckbox("No Blast Mask Cooldown", "gEnhancements.Masks.NoBlastMaskCooldown", {}); + if (UIWidgets::CVarCheckbox("Persistent Bunny Hood", "gEnhancements.Masks.PersistentBunnyHood.Enabled", + { .tooltip = "Permanantly toggle a speed boost from the bunny hood by pressing " + "'A' on it in the mask menu." })) { + UpdatePersistentMasksState(); + } ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 1590e8a67..ae30f2361 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -37,6 +37,7 @@ void InitEnhancements() { RegisterFierceDeityAnywhere(); RegisterBlastMaskKeg(); RegisterNoBlastMaskCooldown(); + RegisterPersistentMasks(); // Minigames RegisterAlwaysWinDoggyRace(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index da9a3a2bb..7aa780c7f 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -18,6 +18,7 @@ #include "Masks/FierceDeityAnywhere.h" #include "Masks/NoBlastMaskCooldown.h" #include "Masks/FastTransformation.h" +#include "Masks/PersistentMasks.h" #include "Minigames/AlwaysWinDoggyRace.h" #include "Cutscenes/Cutscenes.h" #include "Restorations/FlipHopVariable.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index f27becaa0..15f96126b 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -27,6 +27,17 @@ void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx) { GameInteractor::Instance->ExecuteHooks(pauseCtx); } +void GameInteractor_ExecuteBeforeKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex) { + GameInteractor::Instance->ExecuteHooks(pauseCtx, pauseIndex); + GameInteractor::Instance->ExecuteHooksForID(pauseIndex, pauseCtx, + pauseIndex); +} + +void GameInteractor_ExecuteAfterKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex) { + GameInteractor::Instance->ExecuteHooks(pauseCtx, pauseIndex); + GameInteractor::Instance->ExecuteHooksForID(pauseIndex, pauseCtx, pauseIndex); +} + void GameInteractor_ExecuteOnSaveInit(s16 fileNum) { GameInteractor::Instance->ExecuteHooks(fileNum); } @@ -123,6 +134,12 @@ void GameInteractor_ExecuteOnActorKill(Actor* actor) { GameInteractor::Instance->ExecuteHooksForFilter(actor); } +void GameInteractor_ExecuteOnPlayerPostLimbDraw(Player* player, s32 limbIndex) { + GameInteractor::Instance->ExecuteHooks(player, limbIndex); + GameInteractor::Instance->ExecuteHooksForID(limbIndex, player, limbIndex); + GameInteractor::Instance->ExecuteHooksForFilter(player, limbIndex); +} + void GameInteractor_ExecuteOnSceneFlagSet(s16 sceneId, FlagType flagType, u32 flag) { SPDLOG_DEBUG("OnSceneFlagSet: sceneId: {}, flagType: {}, flag: {}", sceneId, (u32)flagType, flag); GameInteractor::Instance->ExecuteHooks(sceneId, flagType, flag); diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 41d5f99ab..2ef0b487f 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -5,8 +5,6 @@ #include extern "C" { #endif -#include "z64actor.h" -#include "z64camera.h" #include "z64.h" #ifdef __cplusplus } @@ -48,6 +46,11 @@ typedef enum { GI_VB_SONG_AVAILABLE_TO_PLAY, GI_VB_USE_CUSTOM_CAMERA, GI_VB_DELETE_OWL_SAVE, + GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, + GI_VB_USE_ITEM_EQUIP_MASK, + GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, + GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, + GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, GI_VB_PLAY_TRANSITION_CS, GI_VB_TATL_INTERUPT_MSG3, GI_VB_TATL_INTERUPT_MSG6, @@ -260,6 +263,8 @@ class GameInteractor { DEFINE_HOOK(OnGameStateUpdate, ()); DEFINE_HOOK(OnConsoleLogoUpdate, ()); DEFINE_HOOK(OnKaleidoUpdate, (PauseContext * pauseCtx)); + DEFINE_HOOK(BeforeKaleidoDrawPage, (PauseContext * pauseCtx, u16 pauseIndex)); + DEFINE_HOOK(AfterKaleidoDrawPage, (PauseContext * pauseCtx, u16 pauseIndex)); DEFINE_HOOK(OnSaveInit, (s16 fileNum)); DEFINE_HOOK(BeforeEndOfCycleSave, ()); DEFINE_HOOK(AfterEndOfCycleSave, ()); @@ -277,6 +282,7 @@ class GameInteractor { DEFINE_HOOK(ShouldActorDraw, (Actor * actor, bool* should)); DEFINE_HOOK(OnActorDraw, (Actor * actor)); DEFINE_HOOK(OnActorKill, (Actor * actor)); + DEFINE_HOOK(OnPlayerPostLimbDraw, (Player * player, s32 limbIndex)); DEFINE_HOOK(OnSceneFlagSet, (s16 sceneId, FlagType flagType, u32 flag)); DEFINE_HOOK(OnSceneFlagUnset, (s16 sceneId, FlagType flagType, u32 flag)); @@ -305,6 +311,8 @@ void GameInteractor_ExecuteOnGameStateDrawFinish(); void GameInteractor_ExecuteOnGameStateUpdate(); void GameInteractor_ExecuteOnConsoleLogoUpdate(); void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx); +void GameInteractor_ExecuteBeforeKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex); +void GameInteractor_ExecuteAfterKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex); void GameInteractor_ExecuteOnSaveInit(s16 fileNum); void GameInteractor_ExecuteBeforeEndOfCycleSave(); void GameInteractor_ExecuteAfterEndOfCycleSave(); @@ -322,6 +330,7 @@ void GameInteractor_ExecuteOnActorUpdate(Actor* actor); bool GameInteractor_ShouldActorDraw(Actor* actor); void GameInteractor_ExecuteOnActorDraw(Actor* actor); void GameInteractor_ExecuteOnActorKill(Actor* actor); +void GameInteractor_ExecuteOnPlayerPostLimbDraw(Player* player, s32 limbIndex); void GameInteractor_ExecuteOnSceneFlagSet(s16 sceneId, FlagType flagType, u32 flag); void GameInteractor_ExecuteOnSceneFlagUnset(s16 sceneId, FlagType flagType, u32 flag); diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp new file mode 100644 index 000000000..92177f9be --- /dev/null +++ b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp @@ -0,0 +1,206 @@ +#include +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "Enhancements/FrameInterpolation/FrameInterpolation.h" + +extern "C" { +#include "z64.h" +#include "z64player.h" +#include "functions.h" +#include "macros.h" +#include "gfx.h" +#include "src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" +#include "assets/interface/parameter_static/parameter_static.h" + +void func_8082E1F0(Player* player, u16 sfxId); +void Player_DrawBunnyHood(PlayState* play); +extern PlayState* gPlayState; +extern const char* D_801C0B20[28]; +extern SaveContext gSaveContext; +} + +void UpdatePersistentMasksState() { + static Vtx* persistentMasksVtx; + static HOOK_ID beforePageDrawHook = 0; + static HOOK_ID onPlayerPostLimbDrawHook = 0; + GameInteractor::Instance->UnregisterGameHook(beforePageDrawHook); + GameInteractor::Instance->UnregisterGameHookForID(onPlayerPostLimbDrawHook); + + if (!CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { + CVarClear("gEnhancements.Masks.PersistentBunnyHood.State"); + return; + } + + // If the mask is equipped, unequip it + if (gSaveContext.save.equippedMask == PLAYER_MASK_BUNNY) { + gSaveContext.save.equippedMask = PLAYER_MASK_NONE; + CVarSetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 1); + + if (gPlayState != NULL) { + Player* player = GET_PLAYER(gPlayState); + player->prevMask = player->currentMask; + player->currentMask = PLAYER_MASK_NONE; + } + } + + // If they don't have the mask, clear the state + if (INV_CONTENT(ITEM_MASK_BUNNY) != ITEM_MASK_BUNNY) { + CVarClear("gEnhancements.Masks.PersistentBunnyHood.State"); + } + + // This hook draws the mask on the players head when it's active and they aren't in first person + onPlayerPostLimbDrawHook = GameInteractor::Instance->RegisterGameHookForID( + PLAYER_LIMB_HEAD, [](Player* player, s32 limbIndex) { + // Ensure they aren't in first person + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0) && + !(player->stateFlags1 & PLAYER_STATE1_100000)) { + OPEN_DISPS(gPlayState->state.gfxCtx); + Matrix_Push(); + Player_DrawBunnyHood(gPlayState); + gSPDisplayList(POLY_OPA_DISP++, + (Gfx*)D_801C0B20[PLAYER_MASK_BUNNY - 1]); // D_801C0B20 is an array of mask DLs + Matrix_Pop(); + CLOSE_DISPS(gPlayState->state.gfxCtx); + } + }); + + // This hook sets up the quad and draws the "active" blue border around the mask in the pause menu + beforePageDrawHook = GameInteractor::Instance->RegisterGameHookForID( + PAUSE_MASK, [](PauseContext* _, u16 __) { + GraphicsContext* gfxCtx = gPlayState->state.gfxCtx; + PauseContext* pauseCtx = &gPlayState->pauseCtx; + s16 i = 0; + s16 j = 0; + s16 k; + + OPEN_DISPS(gfxCtx); + + persistentMasksVtx = (Vtx*)GRAPH_ALLOC(gfxCtx, (4 * 4) * sizeof(Vtx)); + + if ((pauseCtx->state == PAUSE_STATE_MAIN)) { + s16 slot = SLOT_MASK_BUNNY - ITEM_NUM_SLOTS; + s16 slotX = slot % MASK_GRID_COLS; + s16 slotY = slot / MASK_GRID_COLS; + s16 initialX = 0 - (MASK_GRID_COLS * MASK_GRID_CELL_WIDTH) / 2; + s16 initialY = (MASK_GRID_ROWS * MASK_GRID_CELL_HEIGHT) / 2 - 6; + s16 vtxX = (initialX + (slotX * MASK_GRID_CELL_WIDTH)) + MASK_GRID_QUAD_MARGIN; + s16 vtxY = (initialY - (slotY * MASK_GRID_CELL_HEIGHT)) + pauseCtx->offsetY - MASK_GRID_QUAD_MARGIN; + persistentMasksVtx[i + 0].v.ob[0] = persistentMasksVtx[i + 2].v.ob[0] = + vtxX + MASK_GRID_SELECTED_QUAD_MARGIN; + persistentMasksVtx[i + 1].v.ob[0] = persistentMasksVtx[i + 3].v.ob[0] = + persistentMasksVtx[i + 0].v.ob[0] + MASK_GRID_SELECTED_QUAD_WIDTH; + persistentMasksVtx[i + 0].v.ob[1] = persistentMasksVtx[i + 1].v.ob[1] = + vtxY - MASK_GRID_SELECTED_QUAD_MARGIN; + + persistentMasksVtx[i + 2].v.ob[1] = persistentMasksVtx[i + 3].v.ob[1] = + persistentMasksVtx[i + 0].v.ob[1] - MASK_GRID_SELECTED_QUAD_HEIGHT; + + persistentMasksVtx[i + 0].v.ob[2] = persistentMasksVtx[i + 1].v.ob[2] = + persistentMasksVtx[i + 2].v.ob[2] = persistentMasksVtx[i + 3].v.ob[2] = 0; + + persistentMasksVtx[i + 0].v.flag = persistentMasksVtx[i + 1].v.flag = persistentMasksVtx[i + 2].v.flag = + persistentMasksVtx[i + 3].v.flag = 0; + + persistentMasksVtx[i + 0].v.tc[0] = persistentMasksVtx[i + 0].v.tc[1] = + persistentMasksVtx[i + 1].v.tc[1] = persistentMasksVtx[i + 2].v.tc[0] = 0; + + persistentMasksVtx[i + 1].v.tc[0] = persistentMasksVtx[i + 2].v.tc[1] = + persistentMasksVtx[i + 3].v.tc[0] = persistentMasksVtx[i + 3].v.tc[1] = + MASK_GRID_SELECTED_QUAD_TEX_SIZE * (1 << 5); + + persistentMasksVtx[i + 0].v.cn[0] = persistentMasksVtx[i + 1].v.cn[0] = + persistentMasksVtx[i + 2].v.cn[0] = persistentMasksVtx[i + 3].v.cn[0] = + persistentMasksVtx[i + 0].v.cn[1] = persistentMasksVtx[i + 1].v.cn[1] = + persistentMasksVtx[i + 2].v.cn[1] = persistentMasksVtx[i + 3].v.cn[1] = + persistentMasksVtx[i + 0].v.cn[2] = persistentMasksVtx[i + 1].v.cn[2] = + persistentMasksVtx[i + 2].v.cn[2] = persistentMasksVtx[i + 3].v.cn[2] = 255; + + persistentMasksVtx[i + 0].v.cn[3] = persistentMasksVtx[i + 1].v.cn[3] = + persistentMasksVtx[i + 2].v.cn[3] = persistentMasksVtx[i + 3].v.cn[3] = pauseCtx->alpha; + + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 100, 200, 255, 255); + gSPVertex(POLY_OPA_DISP++, (uintptr_t)persistentMasksVtx, 4, 0); + POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, (TexturePtr)gEquippedItemOutlineTex, 32, 32, 0); + } + } + + CLOSE_DISPS(gfxCtx); + }); +} + +void RegisterPersistentMasks() { + UpdatePersistentMasksState(); + + // Easiest way to handle things like loading into a different file, debug warping, etc. + GameInteractor::Instance->RegisterGameHook( + [](s8 sceneId, s8 spawnNum) { UpdatePersistentMasksState(); }); + + // Speed the player up when the bunny hood state is active + REGISTER_VB_SHOULD(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, { + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + *should = true; + } + }); + + // Overrides allowing them to equip a mask while transformed + REGISTER_VB_SHOULD(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, { + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && + *(PlayerItemAction*)opt == PLAYER_IA_MASK_BUNNY) { + *should = true; + } + }); + + // When they do equip the mask, prevent it and instead set our state + REGISTER_VB_SHOULD(GI_VB_USE_ITEM_EQUIP_MASK, { + PlayerMask* maskId = (PlayerMask*)opt; + Player* player = GET_PLAYER(gPlayState); + + if (*maskId == PLAYER_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { + *should = false; + + CVarSetInteger("gEnhancements.Masks.PersistentBunnyHood.State", + !CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)); + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + func_8082E1F0(player, NA_SE_PL_CHANGE_ARMS); + } else { + func_8082E1F0(player, NA_SE_PL_TAKE_OUT_SHIELD); + } + } + }); + + // Prevent the "equipped" white border from being drawn so ours shows instead (ours was drawn before it, so it's + // underneath) + REGISTER_VB_SHOULD(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, { + if (*(ItemId*)opt == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + *should = false; + } + }); + + // Typically when you are in a transformation all masks are dimmed on the C-Buttons + REGISTER_VB_SHOULD(GI_VB_ITEM_BE_RESTRICTED, { + if (*(ItemId*)opt == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { + *should = false; + } + }); + + // Override "A" press behavior on kaleido scope to toggle the mask state + REGISTER_VB_SHOULD(GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, { + ItemId* itemId = (ItemId*)opt; + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && *itemId == ITEM_MASK_BUNNY) { + *should = false; + CVarSetInteger("gEnhancements.Masks.PersistentBunnyHood.State", + !CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)); + if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + Audio_PlaySfx(NA_SE_SY_CAMERA_ZOOM_DOWN); + } else { + Audio_PlaySfx(NA_SE_SY_CAMERA_ZOOM_UP); + } + } else if (CVarGetInteger("gEnhancements.Masks.PersistentGreatFairyMask.Enabled", 0) && + *itemId == ITEM_MASK_GREAT_FAIRY) { + *should = false; + CVarSetInteger("gEnhancements.Masks.PersistentGreatFairyMask.State", + !CVarGetInteger("gEnhancements.Masks.PersistentGreatFairyMask.State", 0)); + } + }); +} diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.h b/mm/2s2h/Enhancements/Masks/PersistentMasks.h new file mode 100644 index 000000000..db441e7b8 --- /dev/null +++ b/mm/2s2h/Enhancements/Masks/PersistentMasks.h @@ -0,0 +1,7 @@ +#ifndef MASKS_PERSISTENT_MASKS_H +#define MASKS_PERSISTENT_MASKS_H + +void RegisterPersistentMasks(); +void UpdatePersistentMasksState(); + +#endif // MASKS_PERSISTENT_MASKS_H diff --git a/mm/include/gfxprint.h b/mm/include/gfxprint.h index f6c896c01..6fb8c0e30 100644 --- a/mm/include/gfxprint.h +++ b/mm/include/gfxprint.h @@ -1,6 +1,10 @@ #ifndef GFXPRINT_H #define GFXPRINT_H +#ifdef __cplusplus +#define this thisx +#endif + #include "color.h" #include "PR/gbi.h" #include "PR/ultratypes.h" @@ -61,4 +65,8 @@ s32 GfxPrint_Printf(GfxPrint* this, const char* fmt, ...); (void)0 // #endregion +#ifdef __cplusplus +#undef this +#endif + #endif diff --git a/mm/include/z64.h b/mm/include/z64.h index 64a8888c1..703edba0a 100644 --- a/mm/include/z64.h +++ b/mm/include/z64.h @@ -2,7 +2,6 @@ #define Z64_H #ifdef __cplusplus extern "C" { -#define this thisx #endif #include "libc/math.h" #include "libc/stdarg.h" @@ -308,6 +307,5 @@ typedef enum { // #ifdef __cplusplus } -#undef this #endif #endif diff --git a/mm/src/code/z_player_lib.c b/mm/src/code/z_player_lib.c index 01556acc8..2dca51ea7 100644 --- a/mm/src/code/z_player_lib.c +++ b/mm/src/code/z_player_lib.c @@ -43,6 +43,7 @@ // Assets for other actors #include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" void PlayerCall_Init(Actor* thisx, PlayState* play); void PlayerCall_Destroy(Actor* thisx, PlayState* play); @@ -4020,5 +4021,7 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList1, G Player_SetFeetPos(play, player, limbIndex); } + GameInteractor_ExecuteOnPlayerPostLimbDraw(player, limbIndex); + func_8012536C(); } diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index f3a173303..16e9c9ca7 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -4471,7 +4471,9 @@ void Player_UseItem(PlayState* play, Player* this, ItemId item) { (itemAction == PLAYER_IA_MASK_ZORA) || ((this->currentBoots >= PLAYER_BOOTS_ZORA_UNDERWATER) && (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)))) { s32 var_v1 = ((itemAction >= PLAYER_IA_MASK_MIN) && (itemAction <= PLAYER_IA_MASK_MAX) && - ((this->transformation != PLAYER_FORM_HUMAN) || (itemAction >= PLAYER_IA_MASK_GIANT))); + (!GameInteractor_Should(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, + this->transformation == PLAYER_FORM_HUMAN, &itemAction) || + (itemAction >= PLAYER_IA_MASK_GIANT))); CollisionPoly* sp5C; s32 sp58; f32 sp54; @@ -4531,20 +4533,23 @@ void Player_UseItem(PlayState* play, Player* this, ItemId item) { } else { Audio_PlaySfx(NA_SE_SY_ERROR); } - } else if ((this->transformation == PLAYER_FORM_HUMAN) && (itemAction >= PLAYER_IA_MASK_MIN) && - (itemAction < PLAYER_IA_MASK_GIANT)) { + } else if (GameInteractor_Should(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, this->transformation == PLAYER_FORM_HUMAN, + &itemAction) && + (itemAction >= PLAYER_IA_MASK_MIN) && (itemAction < PLAYER_IA_MASK_GIANT)) { PlayerMask maskId = GET_MASK_FROM_IA(itemAction); - // Handle wearable masks - this->prevMask = this->currentMask; - if (maskId == this->currentMask) { - this->currentMask = PLAYER_MASK_NONE; - func_8082E1F0(this, NA_SE_PL_TAKE_OUT_SHIELD); - } else { - this->currentMask = maskId; - func_8082E1F0(this, NA_SE_PL_CHANGE_ARMS); + if (GameInteractor_Should(GI_VB_USE_ITEM_EQUIP_MASK, true, &maskId)) { + // Handle wearable masks + this->prevMask = this->currentMask; + if (maskId == this->currentMask) { + this->currentMask = PLAYER_MASK_NONE; + func_8082E1F0(this, NA_SE_PL_TAKE_OUT_SHIELD); + } else { + this->currentMask = maskId; + func_8082E1F0(this, NA_SE_PL_CHANGE_ARMS); + } + gSaveContext.save.equippedMask = this->currentMask; } - gSaveContext.save.equippedMask = this->currentMask; } else if ((itemAction != this->heldItemAction) || ((this->heldActor == NULL) && (Player_ExplosiveFromIA(this, itemAction) > PLAYER_EXPLOSIVE_NONE))) { u8 nextAnimType; @@ -12193,7 +12198,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { this->actor.shape.face = ((play->gameplayFrames & 0x20) ? 0 : 3) + this->blinkInfo.eyeTexIndex; - if (this->currentMask == PLAYER_MASK_BUNNY) { + if (GameInteractor_Should(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { Player_UpdateBunnyEars(this); } @@ -14458,7 +14463,7 @@ void Player_Action_13(Player* this, PlayState* play) { Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play); - if (this->currentMask == PLAYER_MASK_BUNNY) { + if (GameInteractor_Should(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { speedTarget *= 1.5f; } diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c index 13583678c..7d6da43c4 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c @@ -210,8 +210,11 @@ void KaleidoScope_DrawMaskSelect(PlayState* play) { for (i = 0, j = MASK_NUM_SLOTS * 4; i < 3; i++, j += 4) { if (GET_CUR_FORM_BTN_ITEM(i + 1) != ITEM_NONE) { if (GET_CUR_FORM_BTN_SLOT(i + 1) >= ITEM_NUM_SLOTS) { - gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); - POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); + ItemId item = GET_CUR_FORM_BTN_ITEM(i + 1); + if (GameInteractor_Should(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { + gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); + POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); + } } } } @@ -220,8 +223,11 @@ void KaleidoScope_DrawMaskSelect(PlayState* play) { for (i = EQUIP_SLOT_D_RIGHT; i <= EQUIP_SLOT_D_UP; i++, j += 4) { if (DPAD_GET_CUR_FORM_BTN_ITEM(i) != ITEM_NONE) { if (DPAD_GET_CUR_FORM_BTN_SLOT(i) >= ITEM_NUM_SLOTS) { - gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); - POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); + ItemId item = DPAD_GET_CUR_FORM_BTN_ITEM(i); + if (GameInteractor_Should(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { + gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); + POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); + } } } } @@ -669,12 +675,15 @@ void KaleidoScope_UpdateMaskCursor(PlayState* play) { } else if ((pauseCtx->debugEditor == DEBUG_EDITOR_NONE) && (pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && CHECK_BTN_ALL(input->press.button, BTN_A) && (msgCtx->msgLength == 0)) { - // Give description on item through a message box - pauseCtx->itemDescriptionOn = true; - if (pauseCtx->cursorYIndex[PAUSE_MASK] < 2) { - func_801514B0(play, 0x1700 + pauseCtx->cursorItem[PAUSE_MASK], 3); - } else { - func_801514B0(play, 0x1700 + pauseCtx->cursorItem[PAUSE_MASK], 1); + if (GameInteractor_Should(GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, true, + &pauseCtx->cursorItem[PAUSE_MASK])) { + // Give description on item through a message box + pauseCtx->itemDescriptionOn = true; + if (pauseCtx->cursorYIndex[PAUSE_MASK] < 2) { + func_801514B0(play, 0x1700 + pauseCtx->cursorItem[PAUSE_MASK], 3); + } else { + func_801514B0(play, 0x1700 + pauseCtx->cursorItem[PAUSE_MASK], 1); + } } } } diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index 79a7d2ef6..f060ed01e 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -834,7 +834,9 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->itemPageVtx, sItemPageBgTextures); + GameInteractor_ExecuteBeforeKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); KaleidoScope_DrawItemSelect(play); + GameInteractor_ExecuteAfterKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); } break; @@ -855,6 +857,7 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->mapPageVtx, sMapPageBgTextures); + GameInteractor_ExecuteBeforeKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); if (sInDungeonScene) { KaleidoScope_DrawDungeonMap(play); Gfx_SetupDL42_Opa(gfxCtx); @@ -884,6 +887,7 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { KaleidoScope_DrawWorldMap(play); } + GameInteractor_ExecuteAfterKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); break; case PAUSE_QUEST: @@ -906,7 +910,9 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->questPageVtx, sQuestPageBgTextures); + GameInteractor_ExecuteBeforeKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); KaleidoScope_DrawQuestStatus(play); + GameInteractor_ExecuteAfterKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); break; case PAUSE_MASK: @@ -927,7 +933,9 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->maskPageVtx, sMaskPageBgTextures); + GameInteractor_ExecuteBeforeKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); KaleidoScope_DrawMaskSelect(play); + GameInteractor_ExecuteAfterKaleidoDrawPage(pauseCtx, pauseCtx->pageIndex); break; } } From b0ca99f18cbfd9c724020b23d7912443472f2ca9 Mon Sep 17 00:00:00 2001 From: Hoeloe Date: Sun, 18 Aug 2024 22:55:02 +0100 Subject: [PATCH 28/82] [Enhancement] MM3D style clock (#713) --- mm/2s2h/BenGui/BenMenuBar.cpp | 1 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 2 + mm/2s2h/Enhancements/Graphics/3DSClock.cpp | 350 ++++++++++++++++++ mm/2s2h/Enhancements/Graphics/3DSClock.h | 6 + mm/assets/2s2h_assets.h | 54 +++ .../gThreeDayClock3DSArrowTex.ia8.png | Bin 0 -> 15088 bytes .../gThreeDayClock3DSEdgeTex.ia8.png | Bin 0 -> 15731 bytes .../gThreeDayClock3DSFillTex.ia8.png | Bin 0 -> 15691 bytes ...ThreeDayClock3DSFinalHoursColonTex.ia8.png | Bin 0 -> 185 bytes ...hreeDayClock3DSFinalHoursDigit0Tex.ia8.png | Bin 0 -> 329 bytes ...hreeDayClock3DSFinalHoursDigit1Tex.ia8.png | Bin 0 -> 262 bytes ...hreeDayClock3DSFinalHoursDigit2Tex.ia8.png | Bin 0 -> 345 bytes ...hreeDayClock3DSFinalHoursDigit3Tex.ia8.png | Bin 0 -> 364 bytes ...hreeDayClock3DSFinalHoursDigit4Tex.ia8.png | Bin 0 -> 330 bytes ...hreeDayClock3DSFinalHoursDigit5Tex.ia8.png | Bin 0 -> 376 bytes ...hreeDayClock3DSFinalHoursDigit6Tex.ia8.png | Bin 0 -> 374 bytes ...hreeDayClock3DSFinalHoursDigit7Tex.ia8.png | Bin 0 -> 336 bytes ...hreeDayClock3DSFinalHoursDigit8Tex.ia8.png | Bin 0 -> 366 bytes ...hreeDayClock3DSFinalHoursDigit9Tex.ia8.png | Bin 0 -> 342 bytes ...gThreeDayClock3DSFinalHoursMoonTex.ia8.png | Bin 0 -> 3413 bytes .../gThreeDayClock3DSMiddleTex.ia8.png | Bin 0 -> 15485 bytes .../gThreeDayClock3DSSlowTimeTex.ia8.png | Bin 0 -> 242 bytes .../gThreeDayClock3DSTimeBackdropTex.ia8.png | Bin 0 -> 15159 bytes 24 files changed, 414 insertions(+) create mode 100644 mm/2s2h/Enhancements/Graphics/3DSClock.cpp create mode 100644 mm/2s2h/Enhancements/Graphics/3DSClock.h create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSArrowTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSEdgeTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFillTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursColonTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit0Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit1Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit2Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit3Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit4Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit5Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit6Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit7Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit8Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit9Tex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursMoonTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSMiddleTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSSlowTimeTex.ia8.png create mode 100644 mm/assets/custom/textures/parameter_static/gThreeDayClock3DSTimeBackdropTex.ia8.png diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 4a1dd56e9..9d5d00378 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -48,6 +48,7 @@ static std::unordered_map windowBackendsMap = static const std::unordered_map clockTypeOptions = { { CLOCK_TYPE_ORIGINAL, "Original" }, + { CLOCK_TYPE_3DS, "MM3D style" }, { CLOCK_TYPE_TEXT_BASED, "Text only" }, }; diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index ae30f2361..99c9a00c5 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -16,6 +16,7 @@ void InitEnhancements() { // Clock RegisterTextBasedClock(); + Register3DSClock(); // Cycle & Saving RegisterEndOfCycleSaveHooks(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 7aa780c7f..7da2ad77a 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -8,6 +8,7 @@ #include "Cheats/Infinite.h" #include "Dialogue/Dialogue.h" #include "Graphics/TextBasedClock.h" +#include "Graphics/3DSClock.h" #include "Cheats/Cheats.h" #include "Cheats/UnbreakableRazorSword.h" #include "Cheats/UnrestrictedItems.h" @@ -48,6 +49,7 @@ enum TimeStopOptions { enum ClockTypeOptions { CLOCK_TYPE_ORIGINAL, + CLOCK_TYPE_3DS, CLOCK_TYPE_TEXT_BASED, }; diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp new file mode 100644 index 000000000..b28db14bc --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp @@ -0,0 +1,350 @@ +#include +#include "2s2h/BenGui/HudEditor.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "misc/title_static/title_static.h" +#include "2s2h_assets.h" + +extern "C" { +#include +#include +#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" +#include "interface/parameter_static/parameter_static.h" + +extern PlayState* gPlayState; +Gfx* Gfx_DrawTexRectIA8(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop, + s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy); + +Gfx* Gfx_DrawTexRectIA8_DropShadow(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, + s16 rectTop, s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy, s16 r, s16 g, s16 b, + s16 a); + +Gfx* Gfx_DrawTexRectIA8_DropShadowOffset(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, + s16 rectLeft, s16 rectTop, s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy, + s16 r, s16 g, s16 b, s16 a, s32 masks, s32 rects); +} + +#define SECONDS_IN_THREE_DAYS (3 * 24 * 60 * 60) +#define SECONDS_IN_SIX_HOURS (6 * 60 * 60) +#define CLOCK_SECTION_HALFWIDTH 24 +#define CLOCK_SECTION_WIDTH 48 + +static TexturePtr sDigitTextures[] = { + (TexturePtr)gFinalHoursClockDigit0Tex, (TexturePtr)gFinalHoursClockDigit1Tex, (TexturePtr)gFinalHoursClockDigit2Tex, + (TexturePtr)gFinalHoursClockDigit3Tex, (TexturePtr)gFinalHoursClockDigit4Tex, (TexturePtr)gFinalHoursClockDigit5Tex, + (TexturePtr)gFinalHoursClockDigit6Tex, (TexturePtr)gFinalHoursClockDigit7Tex, (TexturePtr)gFinalHoursClockDigit8Tex, + (TexturePtr)gFinalHoursClockDigit9Tex, (TexturePtr)gFinalHoursClockColonTex, +}; + +static TexturePtr sFinalHoursDigitTextures[] = { + (TexturePtr)gThreeDayClock3DSFinalHoursDigit0Tex, (TexturePtr)gThreeDayClock3DSFinalHoursDigit1Tex, + (TexturePtr)gThreeDayClock3DSFinalHoursDigit2Tex, (TexturePtr)gThreeDayClock3DSFinalHoursDigit3Tex, + (TexturePtr)gThreeDayClock3DSFinalHoursDigit4Tex, (TexturePtr)gThreeDayClock3DSFinalHoursDigit5Tex, + (TexturePtr)gThreeDayClock3DSFinalHoursDigit6Tex, (TexturePtr)gThreeDayClock3DSFinalHoursDigit7Tex, + (TexturePtr)gThreeDayClock3DSFinalHoursDigit8Tex, (TexturePtr)gThreeDayClock3DSFinalHoursDigit9Tex, + (TexturePtr)gThreeDayClock3DSFinalHoursColonTex, +}; + +s16 finalHoursClockSlots[8]; + +void Register3DSClock() { + + REGISTER_VB_SHOULD(GI_VB_PREVENT_CLOCK_DISPLAY, { + if (CVarGetInteger("gEnhancements.Graphics.ClockType", CLOCK_TYPE_ORIGINAL) == CLOCK_TYPE_3DS) { + *should = true; + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + if (HudEditor_IsActiveElementHidden()) { + return; + } + + static s32 sPreviousTimeCheck = -1; + + if ((R_TIME_SPEED != 0) && + ((gPlayState->msgCtx.msgMode == MSGMODE_NONE) || + ((gPlayState->actorCtx.flags & ACTORCTX_FLAG_1) && !Play_InCsMode(gPlayState)) || + (gPlayState->msgCtx.msgMode == MSGMODE_NONE) || + ((gPlayState->msgCtx.currentTextId >= 0x100) && (gPlayState->msgCtx.currentTextId <= 0x200)) || + (gSaveContext.gameMode == GAMEMODE_END_CREDITS)) && + !FrameAdvance_IsEnabled(&gPlayState->state) && !Environment_IsTimeStopped() && + (gSaveContext.save.day <= 3)) { + + if ((gPlayState->pauseCtx.state == PAUSE_STATE_OFF) && + (gPlayState->pauseCtx.debugEditor == DEBUG_EDITOR_NONE)) { + + static s16 sThreeDayClockAlpha = 255; + + static s32 sFinalHoursIntro = 0; + + sThreeDayClockAlpha = gPlayState->interfaceCtx.aAlpha; + + OPEN_DISPS(gPlayState->state.gfxCtx); + s16 posX = 160; + s16 posY = 210; + + // Draw background of 3DS clock + // TODO: Replace this with matrix/vertex handling to avoid gaps when scaled + OVERLAY_DISP = Gfx_DrawTexRectIA8_DropShadow( + OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSEdgeTex, CLOCK_SECTION_HALFWIDTH * 3, 12, + posX - (CLOCK_SECTION_HALFWIDTH * 4), posY, CLOCK_SECTION_HALFWIDTH * 3, 12, 1 << 10, 1 << 10, + 255, 255, 255, sThreeDayClockAlpha); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8_DropShadow( + OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSMiddleTex, CLOCK_SECTION_WIDTH, 12, + posX - CLOCK_SECTION_HALFWIDTH, posY, CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10, 255, 255, 255, + sThreeDayClockAlpha); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8_DropShadowOffset( + OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSEdgeTex, CLOCK_SECTION_HALFWIDTH * 3, 12, + posX + CLOCK_SECTION_HALFWIDTH, posY, CLOCK_SECTION_HALFWIDTH * 3, 12, 1 << 10, 1 << 10, 255, + 255, 255, sThreeDayClockAlpha, 3, (CLOCK_SECTION_HALFWIDTH * 3) << 5); + + // Coloured day markers, which highlights the current day with its own colour + u16 fillalpha = 64; + if (gSaveContext.save.day <= 1) { + fillalpha = 255; + } + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 128, 255, (fillalpha * sThreeDayClockAlpha) / 255); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = + Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSFillTex, CLOCK_SECTION_WIDTH, 12, + posX - CLOCK_SECTION_WIDTH, posY, CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10); + + fillalpha = 64; + if (gSaveContext.save.day == 2) { + fillalpha = 255; + } + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 192, 0, (fillalpha * sThreeDayClockAlpha) / 255); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSFillTex, + CLOCK_SECTION_WIDTH, 12, posX - CLOCK_SECTION_HALFWIDTH, posY, + CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10); + + fillalpha = 64; + if (gSaveContext.save.day >= 3) { + fillalpha = 255; + } + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 64, 0, (fillalpha * sThreeDayClockAlpha) / 255); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSFillTex, + CLOCK_SECTION_WIDTH, 12, posX + CLOCK_SECTION_HALFWIDTH, posY, + CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10); + + // This next part is for the little arrow that shows what the current time is + + s32 timeUntilCrash = (s32)TIME_TO_SECONDS_F(TIME_UNTIL_MOON_CRASH); + + // This is a safety measure to delay skipping the arrow marker back a day on the frame before the + // day changes by just checking if time went backwards + if (sPreviousTimeCheck != -1 && sPreviousTimeCheck > SECONDS_IN_THREE_DAYS - timeUntilCrash) { + s32 trueTimeUntilCrash = timeUntilCrash; + timeUntilCrash = SECONDS_IN_THREE_DAYS - sPreviousTimeCheck; + sPreviousTimeCheck = SECONDS_IN_THREE_DAYS - trueTimeUntilCrash; + } else { + sPreviousTimeCheck = SECONDS_IN_THREE_DAYS - timeUntilCrash; + } + + // Compute the position of the arrow, and then draw it + s32 timeoffset = + std::max(std::min(3 * CLOCK_SECTION_WIDTH - + (timeUntilCrash * 3 * CLOCK_SECTION_WIDTH) / SECONDS_IN_THREE_DAYS, + 3 * CLOCK_SECTION_WIDTH), + 0); + + u16 counterX = posX - (CLOCK_SECTION_HALFWIDTH * 3) + timeoffset; + u16 counterY = posY - 4; + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 0, 0, sThreeDayClockAlpha); + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSArrowTex, 8, 8, + counterX - 4, posY + 4, 8, 8, 1 << 10, 1 << 10); + + u16 curMinutes = (s32)TIME_TO_MINUTES_F(gSaveContext.save.time) % 60; + u16 curHours = (s32)TIME_TO_MINUTES_F(gSaveContext.save.time) / 60; + + // Final hours timer + if ((CURRENT_DAY >= 4) || + ((CURRENT_DAY == 3) && (((void)0, gSaveContext.save.time) >= (CLOCK_TIME(0, 0) + 5)) && + (((void)0, gSaveContext.save.time) < CLOCK_TIME(6, 0)))) { + + // This all just gets the time to display in each number slot + s32 timeInSeconds = timeUntilCrash % 60; + s32 timeInMinutes = (timeUntilCrash / 60) % 60; + s32 timeInHours = (timeUntilCrash / 60) / 60; + + finalHoursClockSlots[0] = std::min(timeInHours / 10, 9); + finalHoursClockSlots[1] = timeInHours % 10; + finalHoursClockSlots[2] = 10; + finalHoursClockSlots[3] = timeInMinutes / 10; + finalHoursClockSlots[4] = timeInMinutes % 10; + finalHoursClockSlots[5] = 10; + + finalHoursClockSlots[6] = timeInSeconds / 10; + finalHoursClockSlots[7] = timeInSeconds % 10; + + u16 finalTimerSpacing = 8; + + u16 finalTimerPos = posX - finalTimerSpacing * 4 - finalTimerSpacing / 2; + s16 i; + + s32 percentToCrash = std::min(std::max((timeUntilCrash * 255) / SECONDS_IN_SIX_HOURS, 0), 255); + + // This is a lerp between yellow and red based on the remaining time + u16 finalHoursR1 = 255; + u16 finalHoursR2 = 255; + u16 finalHoursG1 = 0; + u16 finalHoursG2 = 255; + u16 finalHoursB1 = 0; + u16 finalHoursB2 = 0; + + u16 finalHoursR = + (((255 - percentToCrash) * finalHoursR1) + (percentToCrash * finalHoursR2)) / 255; + u16 finalHoursG = + (((255 - percentToCrash) * finalHoursG1) + (percentToCrash * finalHoursG2)) / 255; + u16 finalHoursB = + (((255 - percentToCrash) * finalHoursB1) + (percentToCrash * finalHoursB2)) / 255; + + // Controls the distance and speed modifier of the final hours clock intro animation + // finalHoursOffset controls the distance offset for the intro animation + // finalHoursModifier controls the speed of the intro animation - larger is slower + s32 finalHoursOffset = 10; + s32 finalHoursModifier = 2; + if (sFinalHoursIntro < finalHoursOffset * finalHoursModifier) { + sFinalHoursIntro++; + } + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, finalHoursR, finalHoursG, finalHoursB, + (sThreeDayClockAlpha * sFinalHoursIntro) / + (finalHoursOffset * finalHoursModifier)); + // This just loops through and draws all the numbers + for (i = 0; i < 8; i++) { + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8( + OVERLAY_DISP, sFinalHoursDigitTextures[finalHoursClockSlots[i]], 16, 16, finalTimerPos, + posY - 14 - finalHoursOffset + (sFinalHoursIntro / finalHoursModifier), 16, 16, 1 << 10, + 1 << 10); + finalTimerPos += finalTimerSpacing; + } + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8( + OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSFinalHoursMoonTex, 16, 16, posX - 8, + posY - 28 - finalHoursOffset + (sFinalHoursIntro / finalHoursModifier), 16, 16, 1 << 10, + 1 << 10); + } else { + + sFinalHoursIntro = 0; + + // Draw the current time in a small box + // TODO: Add scale slider to allow this box to be scaled independently of the main UI element + + // Draw the background box + if (gSaveContext.save.timeSpeedOffset == -2) { + u16 pulseTime = ((s32)TIME_TO_SECONDS_F(gSaveContext.save.time) % 120); + u16 pulse; + if (pulseTime < 60) { + pulse = (pulseTime * 255) / 60; + } else { + pulse = 255 - ((pulseTime - 60) * 255) / 60; + } + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, pulse, pulse, 0, sThreeDayClockAlpha / 2); + } else { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, sThreeDayClockAlpha / 2); + } + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSTimeBackdropTex, + CLOCK_SECTION_WIDTH, 16, counterX - CLOCK_SECTION_HALFWIDTH, + counterY - 4, CLOCK_SECTION_WIDTH, 16, 1 << 10, 1 << 10); + + counterX -= 8; + + // Draw the sun/moon next to the current time + TexturePtr daynightmarker; + if (curHours < 6 || curHours >= 18) { + daynightmarker = (TexturePtr)gThreeDayClockMoonHourTex; + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 200, 0, sThreeDayClockAlpha); + } else { + daynightmarker = (TexturePtr)gThreeDayClockSunHourTex; + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 64, 0, sThreeDayClockAlpha); + } + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, daynightmarker, 24, 24, counterX - 11, + counterY - 2, 12, 12, 1 << 11, 1 << 11); + if (!CVarGetInteger("gEnhancements.Graphics.24HoursClock", 0)) { + curHours %= 12; + if (curHours == 0) { + curHours = 12; + } + } + + u16 curTensHours = curHours / 10; + curHours %= 10; + + u16 curTensMinutes = curMinutes / 10; + curMinutes %= 10; + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, sThreeDayClockAlpha); + + // Inverted time + if (gSaveContext.save.timeSpeedOffset == -2) { + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = + Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSSlowTimeTex, 16, 16, + counterX + 8 + 20, counterY - 4, 16, 16, 1 << 10, 1 << 10); + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 64, 192, 255, sThreeDayClockAlpha); + } + + // Digital time + u16 timerSpacing = 6; + + if (curTensHours > 0 || CVarGetInteger("gEnhancements.Graphics.24HoursClock", 0)) { + timerSpacing = 4; + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, sDigitTextures[curTensHours], 8, 8, counterX, + counterY, 8, 8, 1 << 10, 1 << 10); + counterX += timerSpacing; + } + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, sDigitTextures[curHours], 8, 8, counterX, + counterY, 8, 8, 1 << 10, 1 << 10); + counterX += timerSpacing; + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, sDigitTextures[10], 8, 8, counterX, counterY, 8, + 8, 1 << 10, 1 << 10); + counterX += timerSpacing; + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, sDigitTextures[curTensMinutes], 8, 8, counterX, + counterY, 8, 8, 1 << 10, 1 << 10); + counterX += timerSpacing; + + HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); + OVERLAY_DISP = Gfx_DrawTexRectI8(OVERLAY_DISP, sDigitTextures[curMinutes], 8, 8, counterX, + counterY, 8, 8, 1 << 10, 1 << 10); + } + gDPPipeSync(OVERLAY_DISP++); + + CLOSE_DISPS(gPlayState->state.gfxCtx); + } else { + sPreviousTimeCheck = SECONDS_IN_THREE_DAYS - (s32)TIME_TO_SECONDS_F(TIME_UNTIL_MOON_CRASH); + } + } else { + sPreviousTimeCheck = SECONDS_IN_THREE_DAYS - (s32)TIME_TO_SECONDS_F(TIME_UNTIL_MOON_CRASH); + } + + hudEditorActiveElement = HUD_EDITOR_ELEMENT_NONE; + } + }); +} diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.h b/mm/2s2h/Enhancements/Graphics/3DSClock.h new file mode 100644 index 000000000..8a7dc143e --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.h @@ -0,0 +1,6 @@ +#ifndef MM3D_CLOCK_H +#define MM3D_CLOCK_H + +void Register3DSClock(); + +#endif // TEXT_BASED_CLOCK_H diff --git a/mm/assets/2s2h_assets.h b/mm/assets/2s2h_assets.h index e51647c4e..7a02cbe6e 100644 --- a/mm/assets/2s2h_assets.h +++ b/mm/assets/2s2h_assets.h @@ -59,6 +59,60 @@ static const ALIGN_ASSET(2) char gThreeDayClockHour24Tex[] = dgThreeDayClockHour #define dgEmptyTexture "__OTR__textures/virtual/gEmptyTexture" static const ALIGN_ASSET(2) char gEmptyTexture[] = dgEmptyTexture; +#define dgThreeDayClock3DSEdgeTex "__OTR__textures/parameter_static/gThreeDayClock3DSEdgeTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSEdgeTex[] = dgThreeDayClock3DSEdgeTex; + +#define dgThreeDayClock3DSMiddleTex "__OTR__textures/parameter_static/gThreeDayClock3DSMiddleTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSMiddleTex[] = dgThreeDayClock3DSMiddleTex; + +#define dgThreeDayClock3DSFillTex "__OTR__textures/parameter_static/gThreeDayClock3DSFillTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFillTex[] = dgThreeDayClock3DSFillTex; + +#define dgThreeDayClock3DSArrowTex "__OTR__textures/parameter_static/gThreeDayClock3DSArrowTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSArrowTex[] = dgThreeDayClock3DSArrowTex; + +#define dgThreeDayClock3DSTimeBackdropTex "__OTR__textures/parameter_static/gThreeDayClock3DSTimeBackdropTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSTimeBackdropTex[] = dgThreeDayClock3DSTimeBackdropTex; + +#define dgThreeDayClock3DSSlowTimeTex "__OTR__textures/parameter_static/gThreeDayClock3DSSlowTimeTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSSlowTimeTex[] = dgThreeDayClock3DSSlowTimeTex; + +#define dgThreeDayClock3DSFinalHoursMoonTex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursMoonTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursMoonTex[] = dgThreeDayClock3DSFinalHoursMoonTex; + +#define dgThreeDayClock3DSFinalHoursDigit0Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit0Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit0Tex[] = dgThreeDayClock3DSFinalHoursDigit0Tex; + +#define dgThreeDayClock3DSFinalHoursDigit1Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit1Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit1Tex[] = dgThreeDayClock3DSFinalHoursDigit1Tex; + +#define dgThreeDayClock3DSFinalHoursDigit2Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit2Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit2Tex[] = dgThreeDayClock3DSFinalHoursDigit2Tex; + +#define dgThreeDayClock3DSFinalHoursDigit3Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit3Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit3Tex[] = dgThreeDayClock3DSFinalHoursDigit3Tex; + +#define dgThreeDayClock3DSFinalHoursDigit4Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit4Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit4Tex[] = dgThreeDayClock3DSFinalHoursDigit4Tex; + +#define dgThreeDayClock3DSFinalHoursDigit5Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit5Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit5Tex[] = dgThreeDayClock3DSFinalHoursDigit5Tex; + +#define dgThreeDayClock3DSFinalHoursDigit6Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit6Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit6Tex[] = dgThreeDayClock3DSFinalHoursDigit6Tex; + +#define dgThreeDayClock3DSFinalHoursDigit7Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit7Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit7Tex[] = dgThreeDayClock3DSFinalHoursDigit7Tex; + +#define dgThreeDayClock3DSFinalHoursDigit8Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit8Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit8Tex[] = dgThreeDayClock3DSFinalHoursDigit8Tex; + +#define dgThreeDayClock3DSFinalHoursDigit9Tex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursDigit9Tex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursDigit9Tex[] = dgThreeDayClock3DSFinalHoursDigit9Tex; + +#define dgThreeDayClock3DSFinalHoursColonTex "__OTR__textures/parameter_static/gThreeDayClock3DSFinalHoursColonTex" +static const ALIGN_ASSET(2) char gThreeDayClock3DSFinalHoursColonTex[] = dgThreeDayClock3DSFinalHoursColonTex; + #define dgPauseSavePromptENGTex "__OTR__textures/icon_item_static/gPauseSavePromptENGTex" static const ALIGN_ASSET(2) char gPauseSavePromptENGTex[] = dgPauseSavePromptENGTex; diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSArrowTex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSArrowTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..7adecac9920041b50795fedce478678c8f3aa392 GIT binary patch literal 15088 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 literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFillTex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFillTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..100afdb6312ccd85f7b37058937f4d57c363a961 GIT binary patch literal 15691 zcmeAS@N?(olHy`uVBq!ia0y~yU@%}{VBq0kV_;xV*<}~Vz`(#+;1OBOz`!jG!i)^F z=14Fw*wki*M3hAM`dB6B=jtV<RP5H8|x+; z8yH!nCL1Q1C8mNsiK-pLXqWutQcybZbg_eE{FMCU%oHnlva&KtF*P+wGBMRPHZnKT zH8f03(@iq9G}BEnG_kNSvoteFu}p?pgk%_oMgB#Z>6v+nIY??ieo4tpu}U&cGfXv4 zG}bjsG_ue&N;R?2O)^VK)=f1`GB!*#u}m|wFojux#TX2$JTi+*@{1~wQW>no2u>|T z6@^LUWP(eOg2bZYR8YpWRf6SAc##81uMpA(oWZRUlR;&VT{0;7rl#2FqlhA$1E<~=_VN(CFz=`nxyI`CK;RR8mFcir6rlAni!j#z@ix` z7SX+kh-z>E<0*w80R~ou+Yr?7B%*+Xn2M?mxADmtiFxU%DR%lWpTPvswG8H%Bd$Dz z1PpmGhgR}Kj2hB02Z>MAG7(nJVwRych&sVJKPSJ)H$NrS&e%pDn=m5fAnAgY{Em6a zsh|S77_|fdHw~Q<(@{l1SqWNRV6UH&lFU=m(o$1(jSZ8a^^=8VqJeIjVTwtTsYQxO ziiIJ>qv%BrL=@FVWbfc}uT4s_Ra$;gZeodDW^Q77s(wLUx{W?U5GepattBh}qRiC1 zl0_fT__ZQSqiaRz49&|du``0& zh9-=p3)G~u0;h)Hg2d!hJ2O*LV^bS_bYXNI0htx4IT0?Ixv6=@nfZBkCKgaV=n_~p zMj|vC8X;>$l7MQ2L@`o70i3uXqCqZhc3d|4;O-5ms{@vTSJkv)KpjRa<00mbS^^0N zBFWLsqfNH`Eljs_Qz0R>Su z8eEWYAd(ynE+PX8qHHv{AmKnHIT~C<1{6fuXmCNofk<*RxQGlWh_cb(f`kK+qqrn9U2O`PQ;36`hAj(FA3la`QlB2;zWI#cbjRqGa9Ec=GgNw+3f+!meE=V{K zNsa~=kpTr!HX2-za3GQ#4K5-B3ZiT@xFF#`Bsm&fLqG_5gAYrWuw6b2?rv{(cmI7pdiXdg9{Q4M3SSyMPxuhl#K=#Bpiq&M}v#V zfPyF+4K7GH5J}<F!Nq_$Tw?7=f=ELJG(^Hjjg?X`@ z#G?jQFY^m0{;);OKJT=CLe$k44ofy`glX=O&z)SNm6YH6<3NTgA5*3Yx!Qn0K4=i$c|7`6}a&swyfq512nV2VPyZ zs&vc#xqJ;`onl4_x=Z)`T+w}5IVH)}xOwJ9-b35&KWA1F%DTy4b?)cRy}{CqoDN?- oCT6HH^R0i+uuYI%{vnePtIWNld&`6v7#J8lUHx3vIVCg!0Be##i2wiq literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit0Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit0Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..e72e0ebb46812441d6d9f5809dc5df4e0e402c71 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z{u?B z;uvDld$xC@*Wm<_R(lf#$$tlrI{p_wVQi7|iE-0Y)pfxsia0OGvFx~XKqM8VEsHKbn2>AlZyQs>LgkHr80 literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit1Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit1Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..cf6b069e230f250c8ed269f51b77e731afdffa7b GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z;M9R z#WBR9_v{2)u0sw2Zt_YkA&qww_ok$NWUy>#|G*<=c000yG4TAPII)||9uAixm)|VX z;W7JZ=q4bqqjUJ3c|O~}nLDrTx)L=#Q9{rDuT8L5tc%N>;z=qex4wS3Wa+k3n{wtq z-^sLM)vE2m$_ibJwi>2A+{>=O(bRv1aa-oBt{|^9TZ2Sg-*a4^cI%jBIdfm3%>K96 zwlOydZ;)PeTa@9!eqITe+k9~m+4HsPCipZnD||If=8-8__x^hzm;FOVW>^3K literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit2Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit2Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..490226fa2c2f3d112b75dc2364d703d63f25ca3f GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z$onL z;uvDldv>C2R!e|LEB_?7M~6>oiEYalE@bxnZ>CVTZR4gBM{IpQnh9Lu-O(x_UB6st zwnLC7Tk{gTOg9O&)@8Gqx9^-@{I2{yvtF1}$J+P57r+0#SRmDZ(0i{q9=MgxlMC7IiS(W00AoqUhWz1l6W82?VTmQ|wugJkPYuV2Dl3B|t#oHd%$+%Bia&6YOT;T)U4Y!Xn zXg}h$YuRj_(+QDcGRGSe zC6+(_Z7MKZ_|4~AIzkLT7y=k~*uDNQlPb944$rjF6*2UngDHf Bl9vDg literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit3Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit3Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..75f6e24b207eede355753b673e369b940550e131 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z^LZw z;uvDldv=0h_Mrfg*7E@qc-GIj>sTOsk?$Sj|Hj$Q*WJx_ZxyjBKlef*c1~>0_D7d) zo|^12%U)q=;E|=#AB#JKHJ8nnzw_|kY0Ej)OE({tFy?4V5NA1fPQv)d`idP9Iu?)S z9F{QFQCSzZdh*vQUWfJ97vFxn>Hhn|bAc;E)LeNw9?z)T-@nA%^Y+II9*5OeZ;5dx zs^0ag(wOR1zW8DWtAMNEzW3|7<`yoA(W{sFe<8 z+tJTuW}khwJZ$yec_tYqQt=F)lN4ThUdpnX%M`Hwx_!4wL{v88iA_B^rx`X}dsKPv z(~`y|)t;XXcswspG4bU*Ea3UMCcH!2)7bNg>FMk44ofy`glX=O&z{uk1 z;uvDldv&6r_u&8$H~voVZDrg`qqmu?F5&9uo5{7vDa}!^{etHHMbXRrUizk44ofy`glX=O&z-Z*@ z;uvDldvuba_hAQ_qw_nPuV0W>Nw#<3-;_G}fNxn@vAENL30GH^6rEx(c*XwWfkNpQ z?Hei!oToLdYkalf#?q6;1|3JXyn)L-=~>dY{X0{#-e| z>CcR_Y0pnT{gk$PaZuJlUW>lZ_ukyk=URO=D=_rx!wMTWnd1x$nyNad57pS!XPHL0 z&sxS%5WD`Z#?pDS!_RN(xtsUBXu1K1qS5)!T5Cfsui&`Cw-4pKDV0-+$kKKTd?Tdy#_Y zuYLZCN0L`JCQ1Zrsx~Vm%zJ+3^BhM30SBfBYpyPM#&p1T-?IZ%^?TM8UbgRGEMYjY jYaeUD_UvExKXLv^o*Og$`?sqM3=9mOu6{1-oD!M<+M%o` literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit6Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit6Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..d1dd11b1fc6d7be8664a7c687dad134f91696324 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z-Zv< z;uvDldv>C2_Mrfgw)>YH_8gYA5{+v2K5|fT_k#k({YnpHKIzNsDi?orZR_Oyi(8~i zc9eLuFVdQ&MBb@076uxFaQ7m literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit7Tex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursDigit7Tex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..0793f0f11dc57d5e6a049e6da6c39e2f5d01f644 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z{ut4 z;uvDldvv0r_mKjLWA*R$ZzwKJOid6zxAm!aa)O}Fb>AlM&k=?l2Xnr1#|WuOn5>n^ zIqvW#cz?s&vgA9*vIQRA*m+p=@6q<>mGjx-e&lbvbtu8W;)~7uD9x>VSDE{6KCwwh z=k%w%$FA2)pI>iydGUfokkN$G%b!M)U&>c{4pvyvjkmSwJ5q@nj)&w@FQ rfzi)Qa<|x-#_9tMWxu!m*PZ`qcfNOz-^-&63=9mOu6{1-oD!Mk44ofy`glX=O&z^LKr z;uvDldv@abyygIrWBb=MDXdf2!OOa>k$uGj)d^c$mPa<_INg0?u(`H%=}up*fEi2M z9D;+df0+H!XYY*{^O(Fhi>w-$xo6~we_^}s+#)6XzTC$pExi7 X*kEz-e)Uua1_lOCS3j3^P6k44ofy`glX=O&z$oD9 z;uvDldv=0h)?o($SNkQC5~QbZj1pyQ=2O_9b>AUeU{`DP{e!1CH)+-q<*^()jbzdhO&h-jh^RJev%U-Lu|fDZ}@r=v-pY%^oSf zri9mX7QeQ-WTNUDyldTIOLqa5+l~$*uBHuJ#XLO@MR6aZ@D{G6{C`>ltPGkI!b` zeRtjW2gzqxm+PEnSh1>W)hdP)n|RKD_B+hy;XmnH<-Fi&s;QBao?A}(cKw!yuIk=z y`Z1rM`uFnhXSkov=3m8$Li&42U1@|w@zvcaR$vz~#0fx*+&&t;ucLK6VW7>;BB literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursMoonTex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSFinalHoursMoonTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..5c4a60916c2d9df05ad6d9e15780c9457052bb2d GIT binary patch literal 3413 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!t|tTLUQ0|GMgOY(~|@(UC^ zot+g5it^Jkb5a=?JUZu2D-Q{|F4lg2Z+X?ivj!rX&hPi~D(p31dC4VlhGc>UGoP`^ zM#V);g03zsqK-{UY&~sC8X*zuBV#5f+rteWc5-=N zd?pJ2P~vDXFF&HqVBWi@`9;Zx|DLm^9u)7m#L{`A>Fmjr&K&_qR^Dvl*;wm#E0~WCmj+W#R~()rcc&= z6s>g4M|4@C>z^>0*~b#om>QHi-!k!OdmdS)r1tT!(;b&RA`CK`AGQ1bcd^cqY5WnC z_fm3aOD&h%&9(P-i;3Q~ z;>5MIZP%{3Jv){bFZybK-ap^Y>fIjeo9w^yEc#lz@$c05DqDu0$iUpPnvF-_vo1(B zX881d{|ys1z&EhsY+v;d~~7o-^z~vg%9HAA2w*2eBfbm#iEXai&F|K zI~SFGz7fM{KG*&Er+>l1{}XS_-(qoHDNxFeF>8(C1gQl~Pp;cFED~T8Dt6ey{P&`H zeT{{{{yiL5JCE-Cuk+&m=0mBER432=VR=qhrRSW`r_EyDkDM1;z{u#qq!qxR<-q)c zNjZTpr@^*>P40j=OOt^BYZ#-L2UBJP|0YMf8ysB@oHrQDnzI79r5uDa7}XuvEqL`B zPCu~P!I;;~p1{)6{5*ke594P6mPAD(mqrnVP!DdShBJz6PdF+a{snM|upV{n6yO(f z`guWZ1&dbus)bf7IDg4mvBoy6b85a|n;|l*sjmIrVGf_Bl^cxK@XkKKbA$C;^Wg_m z3zYUqoonWP__jbahF`w<_CxLur9aGUnC#or1sener53eGDDoWP<#bszk)@@7jdRyT zuO)Jsj=LtrJyA1i@=<;tAR)r)>MptPP2jy1Pc_7{OtWNHiG=oAHD$SfU68lPEzo#{ ze}+*MXKuqb=idvIFLu7jDG}TybhjhVIo|2MTmRzw2?i2UZtTg;ACI{tPBP3kSUThH zjIcA6XB5(SjJuB}iEdzvV9!yQ)+w6My`g&J@eR*6INvCI6D=dSyvz7_<)cM~HZhFr zgvv$A#mrk~A2|DX>4&Ha>l%f5z2}cke<=MS_6Or1i@JFVz84fN1P*bWZ0T*$a^ij{ z^ic7k=tPeY^;<&CoiUHtl0-jReB>&e@}p11`I7q1iAf$#m&z_BUaGugdr8}9<{IBJ zHTTJ^Pu@OJ`{ep5`BOA!SIfqhewOH@y)L~jyN^sb!tJ?d$+RWiPqa?job)<5c@p!a z%Rv>Ixtivh%dS|hlv)`abU0}9C6P?ymkuvYUIx8fd?|dXdg=zFTSjt5IWwJRIva_n z9@F4(ZGPmI7-$wKr7>OOaR^Un`zvSPWzz!oFa8#so|2lPn|e64I3+vf{E5B`0<+A{ zwomiYUOacf-GzIn2Tv=W`1nNb}=_O>ax* z%JrXIpJs~A>e}qJ$*c8LTNbWWJip;y!HtfTCrMLMujH6y`51pQ*E4u$P?xwUQz&=SP>!JwO zh}?~@w*AV;O+LFlZ{xg87q@h7zL{=(W`R+Y#L^z^Z5h$wx4&*%o_qghYzWu2Dv-MZ#Z`+U8zd!$7&U%1xALDK&IlaqK z$D*$Zaxm30m9yG$UE++A{gP~;W}&e|?MG%uq(_}czJ{ua*_VtLvkk6q*tCKDbm?^N z>E-R-ZO2>8ThF`haG&Dd<1))-UGE;br4mPbU-cYwYj-zyJHPHj#K!8Q6+NLofoJAU zwbCvQi;G>lL#y=a%!rc_X>U$il*G8)xwwP>j6<4jvDrQKy7)glr+c@yf1UI8%(?{s zLK%yvb2?etTRyd%bZI{l+ZpWX=Q-8$a*TPN>G#x4ppWV;!O69T6gZn~BC_1#tD8vD9rwJAG|HU~S1{`L9FS=u_gb#Y{0 zq-kXS=EIx)pLsn0Q1q+lYw`A{eorc&)$V57+O~C>b-ZqU^1l~R)3=tsUQqh+^{(sL zYxHC6_Z`eWJh8W>S5vxP%RpB{zhbXuQgHafqK9pVHlB@}J-b__>xb*%=r`N18G9x2*w{LLYk-p^A{#C{6pWTzKwhvJcy}zz- zZRXwOTk>!3+xhp+UuX6?{9CSQU7vPkpZy8jitXoCuiG29d*3I4X93q1F6Vv7yZ64) zzTB*k9G%QR6*I~!o_L&?I8SZ%vSo|C+)vMXn3nkY%ElSV=KG5OuiJcd#nN?CuSFHf z$cW3;f2+Ooz1;7|+!uByEpC2lzQ+IimPYQ;w*l38zkS?;j(ensJb$2hKlpC!x7b{J zss9x}w%mF-%Xm}zsdGZ-#OB3XOfS#-R&(sl*e@^9RGAr)g) zQFbEp#UbDCv#00(ytAvW`sUk%)~Da!k?oU|+j)AQb*28-d#8U#et#~XQ_)cu@yFv; z;M3%#$G_UY{(HwN$+jr%O6`{So-Zb|C$HJ~e1FQnPlL!0nt6TSD?V;Ps?-FM$Jf5!QL4Sxf^2EI?euD;)&U;L7o*gsb08K3{CmW!1# zFfd*7ba4!^=v6EcDJx3aS0xg?^w{!qQclJ$tk9kBPn=kRqN3m zNAosX>^}OA$9r4UHtuCxPRc*%KXp`zb0rI_E>l;AioVpR!+TOvK7YFFlr~|m;I~7% z@1D-7eo)l+V5$+%+E)kjA}2-wZ%Z-`oZ?BmCcI@3?v z&!01=rp8y~uz{WGjT#?q+)_dI+D`sz< zwMECf%u4p=%aSFjk(=VypLScUc==_Cz6@XV{7Nnd6RE$76Fv6CMnzq!+ACMLU*7j} zfCy`7=*!oy55Fu4S{o)QCnuJ-{rAea_22XI^EYcX+<*T+xvnnmNs*=3QlVMPHg4P2 zcKfXxhvVw2N^|`_fBACc!Ucii;^KLS4=Smwn{)rwezLyya7`8;|mc**d^#|)s_gos}q4}|DZ^hoYB~z9J zX}){+uH*RQ7rXp+->s`lGLWb-wy=<3o-uD;T2>a9rs~EBp6RDsSFQ5#^INn^tGl~f zqwCPWe|F;H;xX~@|8*IXHb&&v)WonfJI?V_H#Ro*@$pHx{cUsCq5vH+OKa=Jx8Eks zQahRyC?_jx8NzUSQ{AVZHT&PZd$%k1c3O3{bZF@OwOTAeURqPRUY1C?21dlj=0;EZ z`dVCmiq}$|508KS+ErFutSl!dCm}0)^l6b|%YvIZMFj;70!_WWygRpVzkcrd=lhH+ z=F3h!n^w!$zIflJO^f<^dR`FVdQ&MBb@02FANF8}}l literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSMiddleTex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSMiddleTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..ca0376fe02966716c028cc329f30f2e26e079c0d GIT binary patch literal 15485 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 literal 0 HcmV?d00001 diff --git a/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSTimeBackdropTex.ia8.png b/mm/assets/custom/textures/parameter_static/gThreeDayClock3DSTimeBackdropTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..57d4f97dfbcb5cc4bf115c33a8637bc88b612284 GIT binary patch literal 15159 zcmeAS@N?(olHy`uVBq!ia0y~yU@%}{U=ZM7V_;wiSodcm0|NtRfk$L90|U1(2s1Lw znj^u$VEHC9B%&n3*T*V3KUXg?B|j-uuOhdA0R(L9D+&^mvr|hHl2X$%^K6yg@7}MZ zkeOnu6mIHk;9KCFnvv;IRg@ZBP$9xMK*2e`C{@8!&rCPj(AYx3+)~fb)Y8JpL`T8M zz|c(Jz*67PMAyL3%D~dfz)%4Sl166{V!vDrJtASalYcxR#aR z*I67=S&*t9lv~HM!ZY(y^2>`gZS>K#AmSTgTB=K8NvfTZfsu)>ftjw6 zNr;h=m5G^^p@B9iVHzMA0#S)(hHq*~VoG93A~B|*s6{s?KP5A*k|8(WNxf$XqcL&n`CNf zrki4DVqsxsX=ajQnGCZC$uJCy{EITvGxHL2kko+ul9HKXWtnJXYG7<)p=)N6Vxeo8 zVv?krXkuuhn_^^`oSI~6k(6p?0}T(i4=?IUPMGSIDqk#LJ*_Cs&E^E8lFTHkPuT*wc$2CIU_MIJvGHnAC`b& z0_a+>#~efyHD|$cD`rl#NlCU!%P-1JEV0YXO-xVKFUU)`(MJd(?6g6YLC*O(`9;3@ zDXDhGHu~6vk#vD7CoBJ=%+$P+L~!mjw9&^9LsuUG%I!I&VD;uk1_lNO`i3A9sufup zU27zMt;o{oS`j)!^D;~9jG(rm2_xwO)u2}3zz8l#Oir~kGc`3fwb4fxM%NLLS&^C( z;gXq~npd2epJ!)c0o8*pfmLH9LZhJ>vPL8cs76RqKx&qO^EgB_$i>Z$%SIpEngq2h z!BX&&kyZ?-!)RqZ#N1I!AmKnHIT~C<1{6fuXmCNofk<*RxQGlWh_cb(f`kK+qqrn9U2O`PQ;36`hAj(FA3la`QlB2;zWI#cbjRqGa9Ec=GgNw+3f+!meE=V{K zNsa~=kpTr!HX2-za3GQ#4K5-B3ZiT@xFF#`Bsm&fLqG_5gAYrWuw6b2?rv{(cmI7pdiXdg9{Q4M3SSyMPxuhl#K=#Bpiq&M}v#V zfPyF+4K7GH5J`>(7m)!4Q8pS}kZ>T991Sia0}7&SG`Jw)KqNUDTto&GMA>L?LBfGZ zax}Pz3@C`Q(cprF1Ciuta1j|$5M`sm1qlZtNxZ?uh1kNGnwMg$RIX%iXLmznD+2?A zLb6AYF9SoBDg#49GXulV{|pQbFBuq04Hy_+B``2p&0t^<&z}^3)Qy3G;i#vJV@SoV zH`5Hc4jTxteE-CJSH9=3X6d@8m)2imZ~C9|W=Y`IOc4(Ut`%0ZD<1xm*8rE6Rg>NRQU%V4i;j>c74tp1^?9F3Ywr>4Xwt>rwDIV+>$Q@rtc zW6xt^jb}eS@iuq-6qq#il-QyUnO7Ur{C=+1E#Zvddb6rZ;>4LxIf4;;zPAfX92aDG zr|W9Ar~8a$`Zl|{#q(XwwtQhI`s_N%`t7FlwtdGmujgN}&}U#^`2U}o;klE{u8Y5H SCNeNEFnGH9xvX Date: Sun, 18 Aug 2024 18:04:25 -0400 Subject: [PATCH 29/82] Implement save backups and better invalid json detection (#749) --- mm/2s2h/SaveManager/SaveManager.cpp | 92 +++++++++++++++++++++-------- mm/src/code/z_sram_NES.c | 4 -- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/mm/2s2h/SaveManager/SaveManager.cpp b/mm/2s2h/SaveManager/SaveManager.cpp index d816972f6..a841ca439 100644 --- a/mm/2s2h/SaveManager/SaveManager.cpp +++ b/mm/2s2h/SaveManager/SaveManager.cpp @@ -12,10 +12,12 @@ extern "C" { #include "src/overlays/gamestates/ovl_file_choose/z_file_select.h" extern FileSelectState* gFileSelectState; + +u16 Sram_CalcChecksum(void* data, size_t count); } // This entire thing is temporary until we have a more robust save system that -// supports backwards compatability, migrations, threaded saving, save sections, etc. +// supports backwards compatibility, migrations, threaded saving, save sections, etc. typedef enum FlashSlotFile { /* -1 */ FLASH_SLOT_FILE_UNAVAILABLE = -1, /* 0 */ FLASH_SLOT_FILE_1_NEW_CYCLE, @@ -66,20 +68,20 @@ const std::unordered_map> migrati }; int SaveManager_MigrateSave(nlohmann::json& j) { - int version = j.value("version", 0); - - if (version > CURRENT_SAVE_VERSION) { - SPDLOG_ERROR("Save version is greater than current version"); - return -1; - } - - if (version >= 4 && !j.contains("newCycleSave") && !j.contains("owlSave")) { - SPDLOG_ERROR("Save file is missing newCycleSave and owlSave"); - return -1; - } - try { - while (version < CURRENT_SAVE_VERSION) { + int version = j.value("version", 0); + + if (version > (int)CURRENT_SAVE_VERSION) { + SPDLOG_ERROR("Save version is greater than current version"); + return -1; + } + + if (version >= 4 && !j.contains("newCycleSave") && !j.contains("owlSave")) { + SPDLOG_ERROR("Save file is missing newCycleSave and owlSave"); + return -1; + } + + while (version < (int)CURRENT_SAVE_VERSION) { if (migrations.contains(version)) { auto migration = migrations.at(version); if (version < 4) { @@ -98,6 +100,9 @@ int SaveManager_MigrateSave(nlohmann::json& j) { version = j["version"] = version + 1; } return 0; + } catch (std::exception& e) { + SPDLOG_ERROR("Failed to migrate save file: {}", e.what()); + return -1; } catch (...) { SPDLOG_ERROR("Failed to migrate save file"); return -1; @@ -156,6 +161,7 @@ void SaveManager_MoveInvalidSaveFile(std::filesystem::path fileName, std::string std::filesystem::rename(filePath, backupFilePath); } + SPDLOG_INFO("{}", message.c_str()); auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); gui->GetGameOverlay()->TextDrawNotification(30.0f, true, message.c_str()); } catch (...) { SPDLOG_ERROR("Failed to move invalid save file"); } @@ -235,7 +241,7 @@ bool SaveManager_HandleFileDropped(std::string filePath) { nlohmann::json j; try { fileStream >> j; - } catch (nlohmann::json::parse_error& e) { return false; } + } catch (nlohmann::json::exception& e) { return false; } if (!j.contains("type") || j["type"] != "2S2H_SAVE") { return false; @@ -292,6 +298,14 @@ extern "C" void SaveManager_SysFlashrom_WriteData(u8* saveBuffer, u32 pageNum, u return; } + // A new cycle save with the "special" page count means that both the regular slot and the backup slot should be + // saved together. We replicate that here by running the save again on the matching backup slot + if ((flashSlotFile == FLASH_SLOT_FILE_1_NEW_CYCLE || flashSlotFile == FLASH_SLOT_FILE_2_NEW_CYCLE) && + pageCount == (u32)gFlashSpecialSaveNumPages[flashSlotFile]) { + SaveManager_SysFlashrom_WriteData(saveBuffer, gFlashSaveStartPages[flashSlotFile + 1], + gFlashSaveNumPages[flashSlotFile + 1]); + } + switch (flashSlotFile) { case FLASH_SLOT_FILE_1_NEW_CYCLE_BACKUP: case FLASH_SLOT_FILE_2_NEW_CYCLE_BACKUP: @@ -402,10 +416,17 @@ extern "C" s32 SaveManager_SysFlashrom_ReadData(void* saveBuffer, u32 pageNum, u return result; } - SaveOptions saveOptions = j; + try { + SaveOptions saveOptions = j; - memcpy(saveBuffer, &saveOptions, sizeof(SaveOptions)); - return 0; + memcpy(saveBuffer, &saveOptions, sizeof(SaveOptions)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse global settings json: {}", je.what()); + SaveManager_MoveInvalidSaveFile( + fileName, "Failed to parse global settings json, the original file has been backed up."); + return -1; + } } bool isOwlSave = @@ -434,18 +455,41 @@ extern "C" s32 SaveManager_SysFlashrom_ReadData(void* saveBuffer, u32 pageNum, u return -1; } - SaveContext saveContext = j["owlSave"]; + try { + SaveContext saveContext = j["owlSave"]; - memcpy(saveBuffer, &saveContext, offsetof(SaveContext, fileNum)); - return 0; + // Recompute the checksum in case the save was edited externally or a migration changed it + // By doing this we sacrifice "real" checksum verification of the save, + saveContext.save.saveInfo.checksum = 0; + saveContext.save.saveInfo.checksum = Sram_CalcChecksum(&saveContext, offsetof(SaveContext, fileNum)); + + memcpy(saveBuffer, &saveContext, offsetof(SaveContext, fileNum)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse owl save json: {}", je.what()); + SaveManager_MoveInvalidSaveFile(fileName, + "Failed to parse save json, the original file has been backed up."); + return -1; + } } else { if (!j.contains("newCycleSave")) { return -1; } - Save save = j["newCycleSave"]["save"]; + try { + Save save = j["newCycleSave"]["save"]; - memcpy(saveBuffer, &save, sizeof(Save)); - return 0; + // Recompute the checksum, see message above + save.saveInfo.checksum = 0; + save.saveInfo.checksum = Sram_CalcChecksum(&save, sizeof(Save)); + + memcpy(saveBuffer, &save, sizeof(Save)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse new cycle save json: {}", je.what()); + SaveManager_MoveInvalidSaveFile(fileName, + "Failed to parse save json, the original file has been backed up."); + return -1; + } } } diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index 2174b4e00..77977d9cb 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -690,10 +690,6 @@ void Sram_IncrementDay(void) { } u16 Sram_CalcChecksum(void* data, size_t count) { - // #region 2S2H [Port] I'm not really sure what this is doing or how to port it, for now always return the same - return 1; - // #endregion - u8* dataPtr = data; u16 chkSum = 0; From d74699740e889ee2e492ec15327ccc45f781e1ab Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:24:14 -0400 Subject: [PATCH 30/82] [Enhancement] Instant Recall (#589) * Instant Recall * clang it * Moved to Category "Equipment" * pr review feedback --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 7 ++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + .../Enhancements/Equipment/InstantRecall.cpp | 42 +++++++++++++++++++ .../Enhancements/Equipment/InstantRecall.h | 6 +++ 5 files changed, 57 insertions(+) create mode 100644 mm/2s2h/Enhancements/Equipment/InstantRecall.cpp create mode 100644 mm/2s2h/Enhancements/Equipment/InstantRecall.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 9d5d00378..c52df59a1 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -515,6 +515,12 @@ void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Equipment")) { UIWidgets::CVarCheckbox("Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", { .tooltip = "Removes the animation for equipping Magic Arrows." }); + + UIWidgets::CVarCheckbox( + "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", + { .tooltip = + "Pressing B will instantly recall the fin boomerang back to Zora Link after they are thrown." }); + ImGui::EndMenu(); } @@ -618,6 +624,7 @@ void DrawEnhancementsMenu() { } ImGui::EndMenu(); } + if (UIWidgets::BeginMenu("Player")) { UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.Player.ClimbSpeed", 1, 5, 1, { .tooltip = "Increases the speed at which Link climbs vines and ladders." }); diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 99c9a00c5..d0c3cd939 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -28,6 +28,7 @@ void InitEnhancements() { // Equipment RegisterSkipMagicArrowEquip(); + RegisterInstantRecall(); // Graphics RegisterDisableBlackBars(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 7da2ad77a..c69692e49 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -28,6 +28,7 @@ #include "Restorations/TatlISG.h" #include "Graphics/3DItemDrops.h" #include "Graphics/PlayAsKafei.h" +#include "Equipment/InstantRecall.h" #include "Player/Player.h" #include "Songs/EnableSunsSong.h" #include "Songs/PauseOwlWarp.h" diff --git a/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp new file mode 100644 index 000000000..dad419353 --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp @@ -0,0 +1,42 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" +#include "InstantRecall.h" +#include "src/overlays/actors/ovl_En_Boom/z_en_boom.h" + +extern "C" { +extern PlayState* gPlayState; +} + +static HOOK_ID onActorUpdateHookId = 0; + +void Player_ReturnBoomerangs() { + Player* player = GET_PLAYER(gPlayState); + + if (player == NULL) { + return; + } + + EnBoom* boomerangs = (EnBoom*)player->boomerangActor; + + // Kill both boomerangs + if (boomerangs != NULL) { + Actor_Kill(&boomerangs->actor); + if (boomerangs->actor.child != NULL) { + Actor_Kill(boomerangs->actor.child); + } + } +} + +void RegisterInstantRecall() { + GameInteractor::Instance->UnregisterGameHookForID(onActorUpdateHookId); + onActorUpdateHookId = 0; + + onActorUpdateHookId = GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_BOOM, [](Actor* outerActor) { + if (CVarGetInteger("gEnhancements.PlayerActions.InstantRecall", 0)) { + if (CHECK_BTN_ALL(gPlayState->state.input->press.button, BTN_B)) { + Player_ReturnBoomerangs(); + } + } + }); +} diff --git a/mm/2s2h/Enhancements/Equipment/InstantRecall.h b/mm/2s2h/Enhancements/Equipment/InstantRecall.h new file mode 100644 index 000000000..4dd58d4fc --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/InstantRecall.h @@ -0,0 +1,6 @@ +#ifndef EQUIPMENT_INSTAND_RECALL_H +#define EQUIPMENT_INSTAND_RECALL_H + +void RegisterInstantRecall(); + +#endif // EQUIPMENT_INSTAND_RECALL_H From 0c2a51c9f4e57e5c9528ed5713bc038db5b4f1c4 Mon Sep 17 00:00:00 2001 From: Archez Date: Fri, 23 Aug 2024 17:19:41 -0400 Subject: [PATCH 31/82] Various custom asset support (#756) * use asset paths for better custom asset support * fix keyframe animation timings * display title cards as a full texture * asset support for gfxprint * support pause menu overworld map * fix more resources that need to be loaded * pr feedback --- mm/2s2h/BenPort.cpp | 2 +- mm/2s2h/BenPort.h | 1 + mm/include/PR/os_convert.h | 8 +- mm/include/macros.h | 4 +- mm/src/boot/O2/gfxprint.c | 77 ++++++++++++++----- mm/src/code/c_keyframe.c | 61 +++++++-------- mm/src/code/z_actor.c | 4 +- mm/src/code/z_bgcheck.c | 10 +++ mm/src/code/z_fcurve_data_skelanime.c | 11 +++ mm/src/code/z_lib.c | 10 +-- mm/src/code/z_player_lib.c | 4 +- mm/src/code/z_skelanime.c | 27 +++++-- mm/src/code/z_skin_awb.c | 7 ++ .../overlays/actors/ovl_Boss_01/z_boss_01.c | 4 +- .../actors/ovl_Demo_Effect/z_demo_effect.c | 4 +- .../actors/ovl_Demo_Syoten/z_demo_syoten.c | 4 +- .../z_eff_kamejima_wave.c | 4 +- .../actors/ovl_Eff_Lastday/z_eff_lastday.c | 4 +- .../actors/ovl_En_Dy_Extra/z_en_dy_extra.c | 4 +- .../overlays/actors/ovl_En_Fall/z_en_fall.c | 4 +- .../overlays/actors/ovl_En_Fall2/z_en_fall2.c | 4 +- .../ovl_kaleido_scope/z_kaleido_map.c | 68 ++++++++++++---- 22 files changed, 232 insertions(+), 94 deletions(-) diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 5009eb2ce..a63e696ab 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -476,7 +476,7 @@ extern "C" void InitOTR() { OTRMessage_Init(); OTRAudio_Init(); - // OTRExtScanner(); + OTRExtScanner(); GameInteractor::Instance->RegisterGameHook(Ben_ProcessDroppedFiles); diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h index 6babb7c31..6aa243e42 100644 --- a/mm/2s2h/BenPort.h +++ b/mm/2s2h/BenPort.h @@ -102,6 +102,7 @@ void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size); void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size); uint64_t GetPerfCounter(); +bool ResourceMgr_IsAltAssetsEnabled(); struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime); void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime); void ResourceMgr_ClearSkeletons(); diff --git a/mm/include/PR/os_convert.h b/mm/include/PR/os_convert.h index 76a984fbd..0db39c970 100644 --- a/mm/include/PR/os_convert.h +++ b/mm/include/PR/os_convert.h @@ -3,6 +3,10 @@ #include "libc/stdint.h" +#include + +#if 0 + #define OS_CLOCK_RATE 62500000LL #define OS_CPU_COUNTER (OS_CLOCK_RATE*3/4) @@ -12,12 +16,14 @@ #define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL)) #define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL)) -#define OS_K0_TO_PHYSICAL(x) (x) +#define OS_K0_TO_PHYSICAL(x) (u32)(((char*)(x)-0x80000000)) #define OS_K1_TO_PHYSICAL(x) (u32)(((char*)(x)-0xA0000000)) #define OS_PHYSICAL_TO_K0(x) (void*)(((u32)(x)+0x80000000)) #define OS_PHYSICAL_TO_K1(x) (void*)(((u32)(x)+0xA0000000)) +#endif + #define OS_MSEC_TO_CYCLES(n) OS_USEC_TO_CYCLES((n) * 1000) #define OS_SEC_TO_CYCLES(n) OS_MSEC_TO_CYCLES((n) * 1000) diff --git a/mm/include/macros.h b/mm/include/macros.h index 0ed8d52fd..456e5df50 100644 --- a/mm/include/macros.h +++ b/mm/include/macros.h @@ -25,8 +25,8 @@ #define RDRAM_CACHED KSEG0 -#define PHYSICAL_TO_VIRTUAL(addr) (addr) //((uintptr_t)(addr) + RDRAM_CACHED) -#define SEGMENTED_TO_K0(addr) (addr) //(void*)((gSegments[SEGMENT_NUMBER(addr)] + K0BASE) + SEGMENT_OFFSET(addr)) +#define PHYSICAL_TO_VIRTUAL(addr) (addr) // ((uintptr_t)(addr) + RDRAM_CACHED) +#define SEGMENTED_TO_K0(addr) (addr) // (void*)((gSegments[SEGMENT_NUMBER(addr)] + K0BASE) + SEGMENT_OFFSET(addr)) #define GET_ACTIVE_CAM(play) ((play)->cameraPtrs[(play)->activeCamId]) diff --git a/mm/src/boot/O2/gfxprint.c b/mm/src/boot/O2/gfxprint.c index c123bb0eb..4fa0c8804 100644 --- a/mm/src/boot/O2/gfxprint.c +++ b/mm/src/boot/O2/gfxprint.c @@ -1,5 +1,24 @@ #include "global.h" +#include "2s2h/BenPort.h" +#include "align_asset_macro.h" + +// #region 2S2H [HD Textures] +#define drGfxPrintFontData "__OTR__textures/font/sGfxPrintFontData" +static const ALIGN_ASSET(2) char rGfxPrintFontData[] = drGfxPrintFontData; + +#define drGfxPrintFontDataAlt "__OTR__alt/textures/font/sGfxPrintFontData" +static const ALIGN_ASSET(2) char rGfxPrintFontDataAlt[] = drGfxPrintFontDataAlt; + +bool sHasArchiveTexture = false; + +// Checks if we have a gfx font as a resource in an archive, which needs to be rendered differently +bool GfxPrint_HasArchiveTexture() { + return ResourceMgr_FileExists(rGfxPrintFontData) || + (ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileExists(rGfxPrintFontDataAlt)); +} +// #endregion + #define GFXP_FLAG_HIRAGANA (1 << 0) #define GFXP_FLAG_RAINBOW (1 << 1) #define GFXP_FLAG_SHADOW (1 << 2) @@ -144,8 +163,18 @@ void GfxPrint_Setup(GfxPrint* this) { G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | G_RM_XLU_SURF | G_RM_XLU_SURF2); gDPSetCombineMode(this->dList++, G_CC_DECALRGBA, G_CC_DECALRGBA); - gDPLoadTextureBlock_4b(this->dList++, sGfxPrintFontData, G_IM_FMT_CI, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + + // 2S2H [HD Textures] Font data from an archive has 4 times the width as the letter columns are side by side + if (sHasArchiveTexture) { + gDPLoadTextureBlock_4b(this->dList++, rGfxPrintFontData, G_IM_FMT_CI, width * 4, height, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + } else { + gDPLoadTextureBlock_4b(this->dList++, sGfxPrintFontData, G_IM_FMT_CI, width, height, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + } + gDPLoadTLUT(this->dList++, 64, 256, sGfxPrintFontTLUT); for (i = 1; i < 4; i++) { @@ -156,17 +185,18 @@ void GfxPrint_Setup(GfxPrint* this) { gDPSetColor(this->dList++, G_SETPRIMCOLOR, this->color.rgba); - // BENTODO: CRASH + // #region 2S2H [Port] Rainbow disabled until LUS supports multiple palettes and tiles // gDPLoadMultiTile_4b(this->dList++, sGfxPrintRainbowData, 0, 1, G_IM_FMT_CI, 2, 8, 0, 0, 1, 7, 4, // G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 1, 3, G_TX_NOLOD, G_TX_NOLOD); // gDPLoadTLUT(this->dList++, 16, 320, sGfxPrintRainbowTLUT); - for (i = 1; i < 4; i++) { - gDPSetTile(this->dList++, G_IM_FMT_CI, G_IM_SIZ_4b, 1, 0, i * 2 + 1, 4, G_TX_NOMIRROR | G_TX_WRAP, 3, - G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 1, G_TX_NOLOD); - gDPSetTileSize(this->dList++, i * 2 + 1, 0, 0, 4, 28); - } + // for (i = 1; i < 4; i++) { + // gDPSetTile(this->dList++, G_IM_FMT_CI, G_IM_SIZ_4b, 1, 0, i * 2 + 1, 4, G_TX_NOMIRROR | G_TX_WRAP, 3, + // G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 1, G_TX_NOLOD); + // gDPSetTileSize(this->dList++, i * 2 + 1, 0, 0, 4, 28); + // } + // #endregion } void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a) { @@ -201,7 +231,7 @@ void GfxPrint_PrintCharImpl(GfxPrint* this, u8 c) { this->flags &= ~GFXP_FLAG_UPDATE; gDPPipeSync(this->dList++); - // BENTODO: CRASH HERE + // 2S2H [Port] Rainbow disabled until LUS supports multiple palettes and tiles if (this->flags & GFXP_FLAG_RAINBOW && false) { gDPSetTextureLUT(this->dList++, G_TT_RGBA16); gDPSetCycleType(this->dList++, G_CYC_2CYCLE); @@ -215,17 +245,27 @@ void GfxPrint_PrintCharImpl(GfxPrint* this, u8 c) { } } + // 2S2H [HD Textures] The font data is normally 4 sets of 2 columns overlayed on top of each other with + // different CI palette values. Custom font data from archives instead are all 4 sets laid out side by side. + // This means we have to compute an additional offset value that represents which of the 4 sets a letter is from. + u16 assetOffsetX = 0; + if (sHasArchiveTexture) { + // Multiplied by the offset of 2 columns before added with the original value below + assetOffsetX = (c & 0x3) * (256 * 2); + tile = 0; + } + if (this->flags & GFXP_FLAG_SHADOW) { gDPSetColor(this->dList++, G_SETPRIMCOLOR, 0); gSPTextureRectangle(this->dList++, this->posX + 4, this->posY + 4, this->posX + 4 + 32, this->posY + 4 + 32, - tile, s << 6, t << 8, 1 << 10, 1 << 10); + tile, assetOffsetX + (s << 6), t << 8, 1 << 10, 1 << 10); gDPSetColor(this->dList++, G_SETPRIMCOLOR, this->color.rgba); } - gSPTextureRectangle(this->dList++, this->posX, this->posY, this->posX + 32, this->posY + 32, tile, s << 6, t << 8, - 1 << 10, 1 << 10); + gSPTextureRectangle(this->dList++, this->posX, this->posY, this->posX + 32, this->posY + 32, tile, + assetOffsetX + (s << 6), t << 8, 1 << 10, 1 << 10); this->posX += 32; } @@ -265,14 +305,12 @@ void GfxPrint_PrintChar(GfxPrint* this, u8 c) { this->flags &= ~GFXP_FLAG_HIRAGANA; break; case GFXP_RAINBOW_ON_CHAR: - // BENTODO: CRASH - // this->flags |= GFXP_FLAG_RAINBOW; - // this->flags |= GFXP_FLAG_UPDATE; + this->flags |= GFXP_FLAG_RAINBOW; + this->flags |= GFXP_FLAG_UPDATE; break; case GFXP_RAINBOW_OFF_CHAR: - // BENTODO: CRASH - // this->flags &= ~GFXP_FLAG_RAINBOW; - // this->flags |= GFXP_FLAG_UPDATE; + this->flags &= ~GFXP_FLAG_RAINBOW; + this->flags |= GFXP_FLAG_UPDATE; break; case GFXP_UNUSED_CHAR: default: @@ -320,6 +358,9 @@ void GfxPrint_Init(GfxPrint* this) { this->flags &= ~GFXP_FLAG_RAINBOW; this->flags |= GFXP_FLAG_SHADOW; this->flags |= GFXP_FLAG_UPDATE; + + // 2S2H [HD Textures] Track whether we have a archive font for the life of this printer + sHasArchiveTexture = GfxPrint_HasArchiveTexture(); } void GfxPrint_Destroy(GfxPrint* this) { diff --git a/mm/src/code/c_keyframe.c b/mm/src/code/c_keyframe.c index e2eb41772..3ef5a87df 100644 --- a/mm/src/code/c_keyframe.c +++ b/mm/src/code/c_keyframe.c @@ -123,20 +123,17 @@ void Keyframe_ResetFlex(KFSkelAnimeFlex* kfSkelAnime) { // cKF_SkeletonInfo_R_ct void Keyframe_InitFlex(KFSkelAnimeFlex* kfSkelAnime, KeyFrameSkeleton* skeleton, KeyFrameAnimation* animation, Vec3s* jointTable, Vec3s* morphTable, UnkKeyframeCallback* callbacks) { + if (ResourceMgr_OTRSigCheck(skeleton)) { + skeleton = (KeyFrameSkeleton*)ResourceMgr_LoadKeyFrameSkelByName(skeleton); + } + if (ResourceMgr_OTRSigCheck(animation)) { + animation = (KeyFrameAnimation*)ResourceMgr_LoadKeyFrameAnimByName(animation); + } + Keyframe_ResetFlex(kfSkelAnime); FrameCtrl_Init(&kfSkelAnime->frameCtrl); - KeyFrameSkeleton* skel = skeleton; - KeyFrameAnimation* anim = animation; - - if (ResourceMgr_OTRSigCheck(skel)) { - skel = (KeyFrameSkeleton*)ResourceMgr_LoadKeyFrameSkelByName(skeleton); - } - if (ResourceMgr_OTRSigCheck(anim)) { - anim = (KeyFrameAnimation*)ResourceMgr_LoadKeyFrameAnimByName(animation); - } - - kfSkelAnime->skeleton = skel; - kfSkelAnime->animation = anim; + kfSkelAnime->skeleton = (KeyFrameSkeleton*)Lib_SegmentedToVirtual(skeleton); + kfSkelAnime->animation = (KeyFrameAnimation*)Lib_SegmentedToVirtual(animation); kfSkelAnime->jointTable = jointTable; kfSkelAnime->morphTable = morphTable; kfSkelAnime->callbacks = callbacks; @@ -187,20 +184,22 @@ void Keyframe_FlexPlayLoopWithMorph(KFSkelAnimeFlex* kfSkelAnime, KeyFrameAnimat void Keyframe_FlexChangeAnim(KFSkelAnimeFlex* kfSkelAnime, KeyFrameSkeleton* skeleton, KeyFrameAnimation* animation, f32 startTime, f32 endTime, f32 t, f32 speed, f32 morphFrames, s32 animMode) { - kfSkelAnime->morphFrames = morphFrames; - if (ResourceMgr_OTRSigCheck(skeleton)) { skeleton = ResourceMgr_LoadKeyFrameSkelByName(skeleton); } - - if (kfSkelAnime->skeleton != skeleton) { - kfSkelAnime->skeleton = skeleton; - } - if (ResourceMgr_OTRSigCheck(animation)) { animation = ResourceMgr_LoadKeyFrameAnimByName(animation); + // Overwrite the end time after fetching the animation data as the parent caller most likely + // passed in garbage data from the "fake" animation pointer (casted from resource string) + endTime = animation->duration; } - kfSkelAnime->animation = animation; + + kfSkelAnime->morphFrames = morphFrames; + + if (kfSkelAnime->skeleton != skeleton) { + kfSkelAnime->skeleton = (KeyFrameSkeleton*)Lib_SegmentedToVirtual(skeleton); + } + kfSkelAnime->animation = (KeyFrameAnimation*)Lib_SegmentedToVirtual(animation); FrameCtrl_SetProperties(&kfSkelAnime->frameCtrl, startTime, endTime, kfSkelAnime->animation->duration, t, speed, animMode); @@ -211,7 +210,7 @@ void Keyframe_FlexChangeAnimQuick(KFSkelAnimeFlex* kfSkelAnime, KeyFrameAnimatio animation = ResourceMgr_LoadKeyFrameAnimByName(animation); } - kfSkelAnime->animation = animation; + kfSkelAnime->animation = (KeyFrameAnimation*)Lib_SegmentedToVirtual(animation); kfSkelAnime->frameCtrl.duration = kfSkelAnime->animation->duration; } @@ -559,19 +558,17 @@ void Keyframe_ResetStandard(KFSkelAnime* kfSkelAnime) { void Keyframe_InitStandard(KFSkelAnime* kfSkelAnime, KeyFrameSkeleton* skeleton, KeyFrameAnimation* animation, Vec3s* jointTable, Vec3s* morphTable) { - Keyframe_ResetStandard(kfSkelAnime); - FrameCtrl_Init(&kfSkelAnime->frameCtrl); - if (ResourceMgr_OTRSigCheck(animation)) { animation = ResourceMgr_LoadKeyFrameAnimByName(animation); } - if (ResourceMgr_OTRSigCheck(skeleton)) { skeleton = ResourceMgr_LoadKeyFrameSkelByName(skeleton); } - kfSkelAnime->skeleton = skeleton; - kfSkelAnime->animation = animation; + Keyframe_ResetStandard(kfSkelAnime); + FrameCtrl_Init(&kfSkelAnime->frameCtrl); + kfSkelAnime->skeleton = (KeyFrameSkeleton*)Lib_SegmentedToVirtual(skeleton); + kfSkelAnime->animation = (KeyFrameAnimation*)Lib_SegmentedToVirtual(animation); kfSkelAnime->jointTable = jointTable; kfSkelAnime->morphTable = morphTable; } @@ -626,18 +623,16 @@ void Keyframe_StandardPlayLoopWithMorph(KFSkelAnime* kfSkelAnime, KeyFrameAnimat void Keyframe_StandardChangeAnim(KFSkelAnime* kfSkelAnime, KeyFrameSkeleton* skeleton, KeyFrameAnimation* animation, f32 startTime, f32 endTime, f32 t, f32 speed, f32 morphFrames, s32 animMode, Vec3s* rotOffsetsTable) { - kfSkelAnime->morphFrames = morphFrames; - if (ResourceMgr_OTRSigCheck(animation)) { animation = ResourceMgr_LoadKeyFrameAnimByName(animation); } - if (ResourceMgr_OTRSigCheck(skeleton)) { skeleton = ResourceMgr_LoadKeyFrameSkelByName(skeleton); } - kfSkelAnime->skeleton = skeleton; - kfSkelAnime->animation = animation; + kfSkelAnime->morphFrames = morphFrames; + kfSkelAnime->skeleton = (KeyFrameSkeleton*)Lib_SegmentedToVirtual(skeleton); + kfSkelAnime->animation = (KeyFrameAnimation*)Lib_SegmentedToVirtual(animation); FrameCtrl_SetProperties(&kfSkelAnime->frameCtrl, startTime, endTime, kfSkelAnime->animation->duration, t, speed, animMode); @@ -649,7 +644,7 @@ void Keyframe_StandardChangeAnimQuick(KFSkelAnime* kfSkelAnime, KeyFrameAnimatio animation = ResourceMgr_LoadKeyFrameAnimByName(animation); } - kfSkelAnime->animation = animation; + kfSkelAnime->animation = Lib_SegmentedToVirtual(animation); kfSkelAnime->frameCtrl.duration = kfSkelAnime->animation->duration; } diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 8be769e81..34c987a83 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -967,7 +967,9 @@ void TitleCard_Draw(GameState* gameState, TitleCardContext* titleCtx) { OPEN_DISPS(gameState->gfxCtx); if (width * height > TMEM_SIZE) { - height = TMEM_SIZE / width; + // 2S2H [HD Textures] Commenting out the below so that we can render the full texture in one rectangle, + // as we are not restricted to the console TMEM limit + // height = TMEM_SIZE / width; } titleSecondY = titleY + (height * 4); diff --git a/mm/src/code/z_bgcheck.c b/mm/src/code/z_bgcheck.c index 783f2c4cc..4b1992e94 100644 --- a/mm/src/code/z_bgcheck.c +++ b/mm/src/code/z_bgcheck.c @@ -6,6 +6,8 @@ #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include +#include "2s2h/BenPort.h" + #define DYNA_RAYCAST_FLOORS 1 #define DYNA_RAYCAST_WALLS 2 #define DYNA_RAYCAST_CEILINGS 4 @@ -3965,6 +3967,10 @@ s32 BgCheck_SphVsFirstDynaPoly(CollisionContext* colCtx, u16 xpFlags, CollisionP * SEGMENTED_TO_K0 CollisionHeader members */ void CollisionHeader_SegmentedToVirtual(CollisionHeader* colHeader) { + if (ResourceMgr_OTRSigCheck(colHeader)) { + colHeader = ResourceMgr_LoadColByName(colHeader); + } + colHeader->vtxList = Lib_SegmentedToVirtual(colHeader->vtxList); colHeader->polyList = Lib_SegmentedToVirtual(colHeader->polyList); if (colHeader->surfaceTypeList) { @@ -3982,6 +3988,10 @@ void CollisionHeader_SegmentedToVirtual(CollisionHeader* colHeader) { * Convert CollisionHeader Segmented to Virtual addressing */ void CollisionHeader_GetVirtual(CollisionHeader* colHeader, CollisionHeader** dest) { + if (ResourceMgr_OTRSigCheck(colHeader)) { + colHeader = ResourceMgr_LoadColByName(colHeader); + } + *dest = Lib_SegmentedToVirtual(colHeader); CollisionHeader_SegmentedToVirtual(*dest); } diff --git a/mm/src/code/z_fcurve_data_skelanime.c b/mm/src/code/z_fcurve_data_skelanime.c index 669e01348..0de1d9d1c 100644 --- a/mm/src/code/z_fcurve_data_skelanime.c +++ b/mm/src/code/z_fcurve_data_skelanime.c @@ -28,6 +28,8 @@ #include "global.h" #include "z64curve.h" +#include "2s2h/BenPort.h" + void SkelCurve_Clear(SkelCurve* skelCurve) { skelCurve->limbCount = 0; skelCurve->skeleton = NULL; @@ -46,6 +48,10 @@ void SkelCurve_Clear(SkelCurve* skelCurve) { */ s32 SkelCurve_Init(PlayState* play, SkelCurve* skelCurve, CurveSkeletonHeader* skeletonHeaderSeg, CurveAnimationHeader* animation) { + if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) { + skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, NULL); + } + SkelCurveLimb** limbs; CurveSkeletonHeader* skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); @@ -103,6 +109,11 @@ s32 SkelCurve_Update(PlayState* play, SkelCurve* skelCurve) { s32 vecType; animation = Lib_SegmentedToVirtual(skelCurve->animation); + + if (ResourceMgr_OTRSigCheck(animation)) { + animation = ResourceMgr_LoadAnimByName(animation); + } + knotCounts = Lib_SegmentedToVirtual(animation->knotCounts); startKnot = Lib_SegmentedToVirtual(animation->interpolationData); constantData = Lib_SegmentedToVirtual(animation->constantData); diff --git a/mm/src/code/z_lib.c b/mm/src/code/z_lib.c index dfc5c0c09..b2ff2c086 100644 --- a/mm/src/code/z_lib.c +++ b/mm/src/code/z_lib.c @@ -1,6 +1,5 @@ #include "global.h" #include -#include "BenPort.h" f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; @@ -677,11 +676,12 @@ f32 Math_Vec3f_StepTo(Vec3f* start, Vec3f* target, f32 speed) { void Lib_Nop801004FC(void) { } +// 2S2H [Port] For the port, resources aren't loaded into memory addresses like on console. +// Instead we deal with resource strings and leave systems to deal with pointers later (renderer, etc). +// We've modified the macros used below and similar ones to just return what its given (noop). + void* Lib_SegmentedToVirtual(void* ptr) { - if (ResourceMgr_OTRSigCheck(ptr)) { - return ResourceGetDataByName(ptr); // SEGMENTED_TO_VIRTUAL(ptr); - } - return ptr; + return SEGMENTED_TO_K0(ptr); } void* Lib_SegmentedToVirtualNull(void* ptr) { diff --git a/mm/src/code/z_player_lib.c b/mm/src/code/z_player_lib.c index 2dca51ea7..71947ca65 100644 --- a/mm/src/code/z_player_lib.c +++ b/mm/src/code/z_player_lib.c @@ -43,6 +43,8 @@ // Assets for other actors #include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" + +#include "2s2h/BenPort.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" void PlayerCall_Init(Actor* thisx, PlayState* play); @@ -2128,7 +2130,7 @@ void Player_DrawZoraShield(PlayState* play, Player* player) { Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); // clang-format off - vtx = Lib_SegmentedToVirtual(&object_link_zora_Vtx_011210); phi_a0 = Lib_SegmentedToVirtual(&object_link_zora_U8_011710); + vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&object_link_zora_Vtx_011210)); phi_a0 = (u8*)ResourceMgr_LoadArrayByName(Lib_SegmentedToVirtual(&object_link_zora_U8_011710)); // clang-format on // ARRAY_COUNT(object_link_zora_Vtx_011210) diff --git a/mm/src/code/z_skelanime.c b/mm/src/code/z_skelanime.c index 0e459de8e..924d368f9 100644 --- a/mm/src/code/z_skelanime.c +++ b/mm/src/code/z_skelanime.c @@ -628,6 +628,7 @@ void SkelAnime_DrawTransformFlexOpa(PlayState* play, void** skeleton, Vec3s* joi void SkelAnime_GetFrameData(AnimationHeader* animation, s32 frame, s32 limbCount, Vec3s* frameTable) { if (ResourceMgr_OTRSigCheck(animation)) animation = ResourceMgr_LoadAnimByName(animation); + AnimationHeader* animHeader = Lib_SegmentedToVirtual(animation); JointIndex* jointIndices = Lib_SegmentedToVirtual(animHeader->jointIndices); s16* frameData = Lib_SegmentedToVirtual(animHeader->frameData); @@ -649,6 +650,7 @@ void SkelAnime_GetFrameData(AnimationHeader* animation, s32 frame, s32 limbCount s16 Animation_GetLength(void* animation) { if (ResourceMgr_OTRSigCheck(animation)) animation = ResourceMgr_LoadAnimByName(animation); + AnimationHeaderCommon* common = Lib_SegmentedToVirtual(animation); return common->frameCount; @@ -657,6 +659,7 @@ s16 Animation_GetLength(void* animation) { s16 Animation_GetLastFrame(void* animation) { if (ResourceMgr_OTRSigCheck(animation)) animation = ResourceMgr_LoadAnimByName(animation); + AnimationHeaderCommon* common = Lib_SegmentedToVirtual(animation); return (u16)common->frameCount - 1; @@ -1017,6 +1020,7 @@ void AnimationContext_SetLoadFrame(PlayState* play, PlayerAnimationHeader* anima if (entry != NULL) { if (ResourceMgr_OTRSigCheck(animation) != 0) animation = ResourceMgr_LoadAnimByName(animation); + PlayerAnimationHeader* playerAnimHeader = Lib_SegmentedToVirtual(animation); Vec3s* ram = frameTable; @@ -1227,8 +1231,10 @@ void SkelAnime_InitPlayer(PlayState* play, SkelAnime* skelAnime, FlexSkeletonHea s32 headerJointCount; s32 limbCount; size_t allocSize; + if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg) != 0) skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, skelAnime); + skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); headerJointCount = skeletonHeader->sh.limbCount; skelAnime->initFlags = flags; @@ -1566,10 +1572,11 @@ s32 PlayerAnimation_OnFrame(SkelAnime* skelAnime, f32 frame) { void SkelAnime_Init(PlayState* play, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg, AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { SkeletonHeader* skeletonHeader; + if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, NULL); - skeletonHeader = skeletonHeaderSeg; + skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->limbCount + 1; skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->segment); if (jointTable == NULL) { @@ -1590,10 +1597,13 @@ void SkelAnime_Init(PlayState* play, SkelAnime* skelAnime, SkeletonHeader* skele */ void SkelAnime_InitFlex(PlayState* play, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { - FlexSkeletonHeader* skeletonHeader; - if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) + if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) { skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, NULL); - skeletonHeader = skeletonHeaderSeg; + } + + FlexSkeletonHeader* skeletonHeader; + + skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->sh.limbCount + 1; skelAnime->dListCount = skeletonHeader->dListCount; skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->sh.segment); @@ -1617,10 +1627,13 @@ void SkelAnime_InitFlex(PlayState* play, SkelAnime* skelAnime, FlexSkeletonHeade */ void SkelAnime_InitSkin(GameState* gameState, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg, AnimationHeader* animation) { - SkeletonHeader* skeletonHeader; - if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) + if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) { skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, NULL); - skeletonHeader = skeletonHeaderSeg; + } + + SkeletonHeader* skeletonHeader; + + skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->limbCount + 1; skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->segment); skelAnime->jointTable = ZeldaArena_Malloc(sizeof(*skelAnime->jointTable) * skelAnime->limbCount); diff --git a/mm/src/code/z_skin_awb.c b/mm/src/code/z_skin_awb.c index edbcef05f..ab2f4dc3a 100644 --- a/mm/src/code/z_skin_awb.c +++ b/mm/src/code/z_skin_awb.c @@ -1,6 +1,8 @@ #include "global.h" #include "z64skin.h" +#include "2s2h/BenPort.h" + void Skin_Setup(Skin* skin) { skin->skeletonHeader = NULL; skin->limbCount = 0; @@ -48,6 +50,11 @@ void Skin_Init(GameState* gameState, Skin* skin, SkeletonHeader* skeletonHeader, s32 limbCount; s32 i; SkinLimb** skeleton; + + if (ResourceMgr_OTRSigCheck(skeletonHeader)) { + skeletonHeader = ResourceMgr_LoadSkeletonByName(skeletonHeader, NULL); + } + SkeletonHeader* virtSkelHeader = Lib_SegmentedToVirtual(skeletonHeader); skin->limbCount = virtSkelHeader->limbCount; diff --git a/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c b/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c index 2970e0c4e..3d8bec6e3 100644 --- a/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c +++ b/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c @@ -34,6 +34,8 @@ #include "overlays/actors/ovl_En_Tanron1/z_en_tanron1.h" #include "overlays/actors/ovl_Item_B_Heart/z_item_b_heart.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((Boss01*)thisx) @@ -2612,7 +2614,7 @@ void Boss01_DrawSwordTrail(Boss01* this, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - vtx = Lib_SegmentedToVirtual(&gOdolwaSwordTrailVtx); + vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&gOdolwaSwordTrailVtx)); for (i = 0; i < ARRAY_COUNT(sSwordTrailOuterVertexIndices); i++) { vtx[sSwordTrailOuterVertexIndices[i]].v.ob[0] = cosf((i * M_PI) / sSwordTrailAngularRangeDivisor) * 200.0f; diff --git a/mm/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c b/mm/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c index d4bc604eb..9ea94c899 100644 --- a/mm/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c +++ b/mm/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c @@ -8,6 +8,8 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_efc_tw/object_efc_tw.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((DemoEffect*)thisx) @@ -164,7 +166,7 @@ void DemoEffect_SetupTimewarp(DemoEffect* this, PlayState* play) { void DemoEffect_SetPerVertexAlpha(f32 alphaScale) { static u8 sAlphaTypes[] = { 1, 1, 2, 0, 1, 1, 2, 0, 1, 2, 0, 2, 1, 0, 1, 0, 2, 0, 2, 2, 0 }; - Vtx* vtx = Lib_SegmentedToVirtual(gTimewarpVtx); + Vtx* vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(gTimewarpVtx)); s32 i; u8 alphas[3]; diff --git a/mm/src/overlays/actors/ovl_Demo_Syoten/z_demo_syoten.c b/mm/src/overlays/actors/ovl_Demo_Syoten/z_demo_syoten.c index e8e553d37..1c5598d7c 100644 --- a/mm/src/overlays/actors/ovl_Demo_Syoten/z_demo_syoten.c +++ b/mm/src/overlays/actors/ovl_Demo_Syoten/z_demo_syoten.c @@ -7,6 +7,8 @@ #include "z_demo_syoten.h" #include "objects/object_syoten/object_syoten.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((DemoSyoten*)thisx) @@ -200,7 +202,7 @@ void func_80C168D0(DemoSyoten* this, PlayState* play) { } void func_80C16974(f32 arg0) { - Vtx* vtx = Lib_SegmentedToVirtual(&object_syotenVtx_0018C0); + Vtx* vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&object_syotenVtx_0018C0)); u8 sp20[3]; s32 i; diff --git a/mm/src/overlays/actors/ovl_Eff_Kamejima_Wave/z_eff_kamejima_wave.c b/mm/src/overlays/actors/ovl_Eff_Kamejima_Wave/z_eff_kamejima_wave.c index 5e5ca289e..f0066d06f 100644 --- a/mm/src/overlays/actors/ovl_Eff_Kamejima_Wave/z_eff_kamejima_wave.c +++ b/mm/src/overlays/actors/ovl_Eff_Kamejima_Wave/z_eff_kamejima_wave.c @@ -7,6 +7,8 @@ #include "z_eff_kamejima_wave.h" #include "objects/object_kamejima/object_kamejima.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10) #define THIS ((EffKamejimaWave*)thisx) @@ -137,7 +139,7 @@ void EffKamejimaWave_Update(Actor* thisx, PlayState* play) { } void EffKamejimaWave_SetVtxAlpha(u8 alpha) { - Vtx* vtx = Lib_SegmentedToVirtual(&gTurtleWaveVtx); + Vtx* vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&gTurtleWaveVtx)); vtx[2].v.cn[3] = alpha; vtx[6].v.cn[3] = alpha; diff --git a/mm/src/overlays/actors/ovl_Eff_Lastday/z_eff_lastday.c b/mm/src/overlays/actors/ovl_Eff_Lastday/z_eff_lastday.c index 8acaddf9b..57f670607 100644 --- a/mm/src/overlays/actors/ovl_Eff_Lastday/z_eff_lastday.c +++ b/mm/src/overlays/actors/ovl_Eff_Lastday/z_eff_lastday.c @@ -7,6 +7,8 @@ #include "z_eff_lastday.h" #include "objects/object_lastday/object_lastday.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((EffLastday*)thisx) @@ -224,7 +226,7 @@ void EffLastday_Update(Actor* thisx, PlayState* play) { } void EffLastday_SetVtxAlpha(s16 alpha) { - Vtx* vtx = Lib_SegmentedToVirtual(object_lastday_Vtx_000000); + Vtx* vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(object_lastday_Vtx_000000)); vtx[0].v.cn[3] = alpha; vtx[3].v.cn[3] = alpha; diff --git a/mm/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c b/mm/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c index 2d81ef052..88a8174b9 100644 --- a/mm/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c +++ b/mm/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c @@ -7,6 +7,8 @@ #include "z_en_dy_extra.h" #include "objects/object_dy_obj/object_dy_obj.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((EnDyExtra*)thisx) @@ -102,7 +104,7 @@ void EnDyExtra_Draw(Actor* thisx, PlayState* play) { s32 pad; EnDyExtra* this = THIS; GraphicsContext* gfxCtx = play->state.gfxCtx; - Vtx* vertices = Lib_SegmentedToVirtual(gGreatFairySpiralBeamVtx); + Vtx* vertices = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(gGreatFairySpiralBeamVtx)); s32 i; u8 alphas[3]; diff --git a/mm/src/overlays/actors/ovl_En_Fall/z_en_fall.c b/mm/src/overlays/actors/ovl_En_Fall/z_en_fall.c index 961765c63..6d8cbddfd 100644 --- a/mm/src/overlays/actors/ovl_En_Fall/z_en_fall.c +++ b/mm/src/overlays/actors/ovl_En_Fall/z_en_fall.c @@ -22,6 +22,8 @@ #include "objects/object_lodmoon/object_lodmoon.h" #include "objects/object_moonston/object_moonston.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((EnFall*)thisx) @@ -581,7 +583,7 @@ static u8 sAlphaTableIndices[] = { void EnFall_Fireball_SetPerVertexAlpha(f32 fireballAlpha) { s32 pad; u8 perVertexAlphaTable[5]; - Vtx* vertices = Lib_SegmentedToVirtual(gMoonFireballVtx); + Vtx* vertices = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(gMoonFireballVtx)); s32 i; if (fireballAlpha > 1.0f) { diff --git a/mm/src/overlays/actors/ovl_En_Fall2/z_en_fall2.c b/mm/src/overlays/actors/ovl_En_Fall2/z_en_fall2.c index 4d10f82bd..c4ff4f292 100644 --- a/mm/src/overlays/actors/ovl_En_Fall2/z_en_fall2.c +++ b/mm/src/overlays/actors/ovl_En_Fall2/z_en_fall2.c @@ -7,6 +7,8 @@ #include "z_en_fall2.h" #include "objects/object_fall2/object_fall2.h" +#include "2s2h/BenPort.h" + #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) #define THIS ((EnFall2*)thisx) @@ -62,7 +64,7 @@ static u8 sAlphaTableIndices[] = { }; void func_80C1B724(f32 arg0) { - Vtx* vertex = Lib_SegmentedToVirtual(object_fall2_Vtx_005F10); + Vtx* vertex = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(object_fall2_Vtx_005F10)); u8 perVertexAlphaTable[6]; s32 i; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c index ffa599dde..7915bbab6 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c @@ -556,7 +556,7 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { if ((pauseCtx->pageIndex == PAUSE_MAP) && (pauseCtx->state == PAUSE_STATE_MAIN) && ((pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) || (pauseCtx->mainState == PAUSE_MAIN_STATE_EQUIP_ITEM)) && YREG(6) && (pauseCtx->state != PAUSE_STATE_SAVEPROMPT) && !IS_PAUSE_STATE_GAMEOVER) { - char* tex = ResourceMgr_LoadTexOrDListByName(gWorldMapImageTex); + // Draw the world map image flat // Because it is flat, the texture is loaded by filling it in 8 rows at a time. // 8 is chosen because it is smaller than `TMEM_SIZE / 2 / textureWidth` and divides the texture's height. @@ -574,9 +574,19 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { // Process the 128 rows of pixels for gWorldMapImageTex, 8 rows at a time over 16 iterations // Loop over yPos (t), textureIndex (j) for (t = 62, j = 0; j < 16; j++, t += 8) { - gDPLoadTextureBlock(POLY_OPA_DISP++, &tex[j * (WORLD_MAP_IMAGE_WIDTH * 8)], G_IM_FMT_CI, G_IM_SIZ_8b, - WORLD_MAP_IMAGE_WIDTH, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + // 2S2H [Port][HD Textures] Here and below we use LoadMultTile and SetTileSize to allow us to pass the + // resource path to the renderer and calculate the tile offset after the renderer loads it + /* + gDPLoadTextureBlock(POLY_OPA_DISP++, (u8*)gWorldMapImageTex + j * (WORLD_MAP_IMAGE_WIDTH * 8), G_IM_FMT_CI, + G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + */ + gDPLoadMultiTile(POLY_OPA_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, + WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_HEIGHT, 0, j * 8, WORLD_MAP_IMAGE_WIDTH - 1, + (j + 1) * 8 - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPSetTileSize(POLY_OPA_DISP++, G_TX_RENDERTILE, 0, 0, (WORLD_MAP_IMAGE_WIDTH - 1) << G_TEXTURE_IMAGE_FRAC, + (8 - 1) << G_TEXTURE_IMAGE_FRAC); rectLeft = 51 << 2; rectRight = rectLeft + (WORLD_MAP_IMAGE_WIDTH << 2); @@ -610,12 +620,19 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { // Process the first 72 rows of pixels for gWorldMapImageTex, 9 rows at a time over 8 iterations // Loop over quadIndex of this loop (i), quadIndex of the entire texture (k), vtxIndex (j) - char* tex = ResourceMgr_LoadTexOrDListByName(gWorldMapImageTex); for (i = 0, k = 0, j = 0; i < 8; i++, k++, j += 4) { - gDPLoadTextureBlock(POLY_OPA_DISP++, &tex[k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT)], - G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, - G_TX_NOLOD, G_TX_NOLOD); + /* + gDPLoadTextureBlock( + POLY_OPA_DISP++, (u8*)gWorldMapImageTex + k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT), + G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + */ + gDPLoadMultiTile(POLY_OPA_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, + WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_HEIGHT, 0, k * 9, WORLD_MAP_IMAGE_WIDTH - 1, + (k + 1) * 9 - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPSetTileSize(POLY_OPA_DISP++, G_TX_RENDERTILE, 0, 0, (WORLD_MAP_IMAGE_WIDTH - 1) << G_TEXTURE_IMAGE_FRAC, + (9 - 1) << G_TEXTURE_IMAGE_FRAC); gSP1Quadrangle(POLY_OPA_DISP++, j, j + 2, j + 3, j + 1, 0); } @@ -627,19 +644,36 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { // Process the next 54 rows of pixels for gWorldMapImageTex, 9 rows at a time over 6 iterations // Loop over quadIndex of this loop (i), quadIndex of the entire texture (k), vtxIndex (j) for (i = 0, j = 0; i < 6; i++, k++, j += 4) { - gDPLoadTextureBlock(POLY_OPA_DISP++, &tex[k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT)], - G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, - G_TX_NOLOD, G_TX_NOLOD); + /* + gDPLoadTextureBlock( + POLY_OPA_DISP++, (u8*)gWorldMapImageTex + k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT), + G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + */ + gDPLoadMultiTile(POLY_OPA_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, + WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_HEIGHT, 0, k * 9, WORLD_MAP_IMAGE_WIDTH - 1, + (k + 1) * 9 - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPSetTileSize(POLY_OPA_DISP++, G_TX_RENDERTILE, 0, 0, (WORLD_MAP_IMAGE_WIDTH - 1) << G_TEXTURE_IMAGE_FRAC, + (9 - 1) << G_TEXTURE_IMAGE_FRAC); gSP1Quadrangle(POLY_OPA_DISP++, j, j + 2, j + 3, j + 1, 0); } // Process the last 2 rows of pixels for gWorldMapImageTex - gDPLoadTextureBlock(POLY_OPA_DISP++, &tex[k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT)], - G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, - WORLD_MAP_IMAGE_HEIGHT % WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + /* + gDPLoadTextureBlock( + POLY_OPA_DISP++, (u8*)gWorldMapImageTex + k * (WORLD_MAP_IMAGE_WIDTH * WORLD_MAP_IMAGE_FRAG_HEIGHT), + G_IM_FMT_CI, G_IM_SIZ_8b, WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_HEIGHT % WORLD_MAP_IMAGE_FRAG_HEIGHT, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + */ + gDPLoadMultiTile(POLY_OPA_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, + WORLD_MAP_IMAGE_WIDTH, WORLD_MAP_IMAGE_HEIGHT, 0, k * 9, WORLD_MAP_IMAGE_WIDTH - 1, + (k * 9 + 2) - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPSetTileSize(POLY_OPA_DISP++, G_TX_RENDERTILE, 0, 0, (WORLD_MAP_IMAGE_WIDTH - 1) << G_TEXTURE_IMAGE_FRAC, + (2 - 1) << G_TEXTURE_IMAGE_FRAC); + gSP1Quadrangle(POLY_OPA_DISP++, j, j + 2, j + 3, j + 1, 0); } From 136a928883ac4ef3efc5bba48b48a047fc1a1de0 Mon Sep 17 00:00:00 2001 From: Mothstery <158694305+Mothstery@users.noreply.github.com> Date: Sat, 24 Aug 2024 09:22:30 -0700 Subject: [PATCH 32/82] [Enhancement] Custom Zora Egg Count (#624) * initial commit of relevant files * attempt to appease clang formatting * fix edge case of marine researcher dialogue being wrong with low egg counts * refactored to better use hooks and no longer touch main mm code directly * undo GameInteractor.h changes * removed useless egg checks, only need the researcher * trigger remote build * removing useless includes leftover from the old approach. * move UIWidgets for egg into existing section --- mm/2s2h/BenGui/BenMenuBar.cpp | 2 ++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp | 38 +++++++++++++++++++++ mm/2s2h/Enhancements/Songs/ZoraEggCount.h | 6 ++++ 5 files changed, 48 insertions(+) create mode 100644 mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp create mode 100644 mm/2s2h/Enhancements/Songs/ZoraEggCount.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index c52df59a1..c01729ab0 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -668,6 +668,8 @@ void DrawEnhancementsMenu() { UIWidgets::CVarCheckbox("Pause Owl Warp", "gEnhancements.Songs.PauseOwlWarp", { .tooltip = "Allows the player to use the pause menu map to owl warp instead of " "having to play the Song of Soaring." }); + UIWidgets::CVarSliderInt("Zora Eggs For Bossa Nova", "gEnhancements.Songs.ZoraEggCount", 1, 7, 7, + { .tooltip = "The number of eggs required to unlock new wave bossa nova." }); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index d0c3cd939..2acb6db07 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -52,6 +52,7 @@ void InitEnhancements() { // Songs RegisterEnableSunsSong(); RegisterPauseOwlWarp(); + RegisterZoraEggCount(); // Restorations RegisterPowerCrouchStab(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index c69692e49..20ef77abc 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -32,6 +32,7 @@ #include "Player/Player.h" #include "Songs/EnableSunsSong.h" #include "Songs/PauseOwlWarp.h" +#include "Songs/ZoraEggCount.h" #include "Saving/SavingEnhancements.h" #include "Graphics/DisableBlackBars.h" #include "Modes/TimeMovesWhenYouMove.h" diff --git a/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp new file mode 100644 index 000000000..af03c56fe --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp @@ -0,0 +1,38 @@ +#include "ZoraEggCount.h" +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "src/overlays/actors/ovl_En_Mk/z_en_mk.h" +} + +const uint32_t MAX_EGGS = 7; + +void RegisterZoraEggCount() { + // marine researcher, his actor update call is more consistent than the eggs + GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_MK, [](Actor* outerActor) { + static uint32_t enMkUpdateHook = 0; + static uint32_t enMkKillHook = 0; + GameInteractor::Instance->UnregisterGameHookForPtr(enMkUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enMkKillHook); + enMkUpdateHook = 0; + enMkKillHook = 0; + + enMkUpdateHook = GameInteractor::Instance->RegisterGameHookForPtr( + (uintptr_t)outerActor, [](Actor* actor) { + // complete quest if you have enough eggs + if (gSaveContext.save.saveInfo.permanentSceneFlags[SCENE_LABO].unk_14 != MAX_EGGS && + CVarGetInteger("gEnhancements.Songs.ZoraEggCount", MAX_EGGS) <= + gSaveContext.save.saveInfo.permanentSceneFlags[SCENE_LABO].unk_14) { + gSaveContext.save.saveInfo.permanentSceneFlags[SCENE_LABO].unk_14 = MAX_EGGS; + } + }); + enMkKillHook = + GameInteractor::Instance->RegisterGameHook([](s8 sceneId, s8 spawnNum) { + GameInteractor::Instance->UnregisterGameHook(enMkUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enMkKillHook); + enMkUpdateHook = 0; + enMkKillHook = 0; + }); + }); +} \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Songs/ZoraEggCount.h b/mm/2s2h/Enhancements/Songs/ZoraEggCount.h new file mode 100644 index 000000000..35ac5ed60 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/ZoraEggCount.h @@ -0,0 +1,6 @@ +#ifndef VARIABLE_ZORA_EGG_COUNT_H +#define VARIABLE_ZORA_EGG_COUNT_H + +void RegisterZoraEggCount(); + +#endif // VARIABLE_ZORA_EGG_COUNT_H \ No newline at end of file From 13035d72a4c8a21b760ce1e72bf7d24bb4f3ec3e Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 30 Aug 2024 11:46:04 -0700 Subject: [PATCH 33/82] Change recommended build tools from 142 to 143, minimum VS to 2022. (#762) --- docs/BUILDING.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 24cd73f45..8feb79ec3 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -6,7 +6,7 @@ Requires: * At least 8GB of RAM (machines with 4GB have seen complier failures) * Visual Studio 2022 Community Edition with the C++ feature set * One of the Windows SDKs that comes with Visual Studio, for example the current Windows 10 version 10.0.19041.0 - * The `MSVC v142 - VS 2019 C++ build tools` component of Visual Studio + * The `MSVC v143 - VS 2022 C++ build tools` component of Visual Studio * Python 3 (can be installed manually or as part of Visual Studio) * Git (can be installed manually or as part of Visual Studio) * Cmake (can be installed via chocolatey or manually) @@ -14,12 +14,9 @@ Requires: During installation, check the "Desktop development with C++" feature set: ![image](https://user-images.githubusercontent.com/30329717/183511274-d11aceea-7900-46ec-acb6-3f2cc110021a.png) -Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v142 toolset. +Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v143 toolset. This is often done by default. -You can also find the v142 toolset by searching through the individual components tab: - -![image](https://user-images.githubusercontent.com/30329717/183521169-ead6a73b-a1bf-4e99-aab8-441746d8f08e.png) -While you're there, you can also install Python 3 and Git if needed. +It is recommended that you install Python and Git standalone, the install process in VS Installer has given some issues in the past. 1. Clone the 2 Ship 2 Harkinian repository @@ -33,9 +30,7 @@ _Note: Instructions assume using powershell_ cd 2ship2harkinian # Setup cmake project -& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -# or for VS2019 -& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) # Extract assets & generate OTR (run this anytime you need to regenerate OTR) & 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssets # --config Release (if you're packaging) # Compile project @@ -60,9 +55,7 @@ With the cmake build system you have two options for working on the project: To develop using Visual Studio you only need to use cmake to generate the solution file: ```powershell # Generates 2s2h.sln at `build/x64` for Visual Studio 2022 -& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 -# or for Visual Studio 2019 -& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 ``` #### Visual Studio Code or another editor From ea8809ddd0ec211386d882399bdb78f43714656e Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:41:16 -0600 Subject: [PATCH 34/82] Allow non-ascii characters in filepath on Windows (#743) --- mm/src/code/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/src/code/main.c b/mm/src/code/main.c index 046fd99e4..d221326fe 100644 --- a/mm/src/code/main.c +++ b/mm/src/code/main.c @@ -1,6 +1,7 @@ #ifdef _WIN32 #include #include +#include #endif #include "audiomgr.h" @@ -66,6 +67,8 @@ void SDL_main(int argc, char** argv /* void* arg*/) { #ifndef _DEBUG ShowWindow(GetConsoleWindow(), SW_HIDE); #endif + // Allow non-ascii characters for Windows + setlocale(LC_ALL, ".UTF8"); #endif // _WIN32 InitOTR(); From 185e761f78a05ba7ac1e9988d3c09362b9ef4a11 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:00:11 -0400 Subject: [PATCH 35/82] [Enhancement] Fierce Deity Anchored Backwalk Animation (#670) * Add Fierce Deity anchored backwalk enhancement * adjust ztarget hook to clamp speed instead of modifying animation frame logic --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 4 ++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 +++ mm/2s2h/Enhancements/Enhancements.h | 1 + .../Fixes/FierceDeityZTargetMovement.cpp | 21 +++++++++++++++++++ mm/2s2h/Enhancements/Fixes/Fixes.h | 6 ++++++ .../GameInteractor/GameInteractor.h | 1 + .../actors/ovl_player_actor/z_player.c | 3 +++ 7 files changed, 39 insertions(+) create mode 100644 mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp create mode 100644 mm/2s2h/Enhancements/Fixes/Fixes.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index c01729ab0..75251fccf 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -529,6 +529,10 @@ void DrawEnhancementsMenu() { { .tooltip = "Fixes a missing gDPSetEnvColor, which causes the ammo count to be " "the wrong color prior to obtaining magic or other conditions." }); + UIWidgets::CVarCheckbox("Fix Fierce Deity Z-Target movement", + "gEnhancements.Fixes.FierceDeityZTargetMovement", + { .tooltip = "Fixes Fierce Deity movement being choppy when Z-targeting" }); + UIWidgets::CVarCheckbox("Fix Hess and Weirdshot Crash", "gEnhancements.Fixes.HessCrash", { .tooltip = "Fixes a crash that can occur when performing a HESS or Weirdshot.", .defaultValue = true }); diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 2acb6db07..6d14e8388 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -30,6 +30,9 @@ void InitEnhancements() { RegisterSkipMagicArrowEquip(); RegisterInstantRecall(); + // Fixes + RegisterFierceDeityZTargetMovement(); + // Graphics RegisterDisableBlackBars(); Register3DItemDrops(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 20ef77abc..84ad3b1f5 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -15,6 +15,7 @@ #include "Cheats/TimeStop.h" #include "Cycle/EndOfCycle.h" #include "Equipment/SkipMagicArrowEquip.h" +#include "Fixes/Fixes.h" #include "Masks/BlastMaskKeg.h" #include "Masks/FierceDeityAnywhere.h" #include "Masks/NoBlastMaskCooldown.h" diff --git a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp new file mode 100644 index 000000000..50c291912 --- /dev/null +++ b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp @@ -0,0 +1,21 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "variables.h" +} + +void RegisterFierceDeityZTargetMovement() { + REGISTER_VB_SHOULD(GI_VB_ZTARGET_SPEED_CHECK, { + Player* player = GET_PLAYER(gPlayState); + float* speedArg = (float*)opt; + + // If the player is Fierce Deity and targeting, + if (player->lockOnActor != NULL && player->transformation == PLAYER_FORM_FIERCE_DEITY && + CVarGetInteger("gEnhancements.Fixes.FierceDeityZTargetMovement", 0)) { + // 6.0f is the maximum speed of Zora/Goron/Deku link, whereas FD can be up to 10 + // Clamping to 6.0 keeps z target movement similar to other transformations + *speedArg = CLAMP_MAX(*speedArg, 6.0f); + } + }); +} diff --git a/mm/2s2h/Enhancements/Fixes/Fixes.h b/mm/2s2h/Enhancements/Fixes/Fixes.h new file mode 100644 index 000000000..5e61df6f1 --- /dev/null +++ b/mm/2s2h/Enhancements/Fixes/Fixes.h @@ -0,0 +1,6 @@ +#ifndef ENHANCEMENTS_FIXES_H +#define ENHANCEMENTS_FIXES_H + +void RegisterFierceDeityZTargetMovement(); + +#endif // ENHANCEMENTS_FIXES_H diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 2ef0b487f..a076e8f2a 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -59,6 +59,7 @@ typedef enum { GI_VB_DISABLE_LETTERBOX, GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, GI_VB_DRAW_SLIME_BODY_ITEM, + GI_VB_ZTARGET_SPEED_CHECK, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 16e9c9ca7..36df61bc9 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -9595,6 +9595,9 @@ s32 func_8083E404(Player* this, f32 arg1, s16 arg2) { func_8083C62C(this, func_800B7128(this) || func_8082EF20(this)); } + // Using Should hook, but ignoring return value, to be able to modify the speed argument + GameInteractor_Should(GI_VB_ZTARGET_SPEED_CHECK, false, &arg1); + temp_fv1 = fabsf(sp1C) / 0x8000; if (((SQ(temp_fv1) * 50.0f) + 6.0f) < arg1) { return 1; From 466a716222eda597bd8e702f09e7163d4ef2e42e Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 8 Sep 2024 18:27:36 -0400 Subject: [PATCH 36/82] Add restoration for woodfall mountain cleared state (#765) * Add restoration for woodfall mountain cleared state * enum --- mm/2s2h/BenGui/BenMenuBar.cpp | 8 +++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 1 + .../Enhancements/Restorations/Restorations.h | 6 ++++ .../WoodfallMountainAppearance.cpp | 31 +++++++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 mm/2s2h/Enhancements/Restorations/Restorations.h create mode 100644 mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 75251fccf..009f6c075 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -656,6 +656,14 @@ void DrawEnhancementsMenu() { UIWidgets::CVarCheckbox("Tatl ISG", "gEnhancements.Restorations.TatlISG", { .tooltip = "Restores Navi ISG from OOT, but now with Tatl." }); + if (UIWidgets::CVarCheckbox( + "Woodfall Mountain Appearance", "gEnhancements.Restorations.WoodfallMountainAppearance", + { .tooltip = "Restores the appearance of Woodfall mountain to not look poisoned " + "when viewed from Termina Field after clearing Woodfall Temple\n\n" + "Requires a scene reload to take effect" })) { + RegisterWoodfallMountainAppearance(); + } + ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 6d14e8388..0e014d318 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -62,6 +62,7 @@ void InitEnhancements() { RegisterSideRoll(); RegisterTatlISG(); RegisterVariableFlipHop(); + RegisterWoodfallMountainAppearance(); // Cutscenes RegisterCutscenes(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 84ad3b1f5..4e51dfac7 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -25,6 +25,7 @@ #include "Cutscenes/Cutscenes.h" #include "Restorations/FlipHopVariable.h" #include "Restorations/PowerCrouchStab.h" +#include "Restorations/Restorations.h" #include "Restorations/SideRoll.h" #include "Restorations/TatlISG.h" #include "Graphics/3DItemDrops.h" diff --git a/mm/2s2h/Enhancements/Restorations/Restorations.h b/mm/2s2h/Enhancements/Restorations/Restorations.h new file mode 100644 index 000000000..8b2a722e6 --- /dev/null +++ b/mm/2s2h/Enhancements/Restorations/Restorations.h @@ -0,0 +1,6 @@ +#ifndef ENHANCEMENTS_RESTORATIONS_H +#define ENHANCEMENTS_RESTORATIONS_H + +void RegisterWoodfallMountainAppearance(); + +#endif // ENHANCEMENTS_RESTORATIONS_H diff --git a/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp new file mode 100644 index 000000000..12a546d26 --- /dev/null +++ b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp @@ -0,0 +1,31 @@ + +#include +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include "z64save.h" +#include "overlays/actors/ovl_Bg_Breakwall/z_bg_breakwall.h" +} + +typedef enum { + /* 2 */ BGBREAKWALL_F_2 = 3, // Poisoned Woodfall Mountain + /* 3 */ BGBREAKWALL_F_3 = 3, // Spring Woodfall Mountain +} BgBreakwallParamEx; + +void RegisterWoodfallMountainAppearance() { + static HOOK_ID breakwallInitID = 0; + GameInteractor::Instance->UnregisterGameHookForID(breakwallInitID); + breakwallInitID = 0; + + if (!CVarGetInteger("gEnhancements.Restorations.WoodfallMountainAppearance", 0)) { + return; + } + + breakwallInitID = GameInteractor::Instance->RegisterGameHookForID( + ACTOR_BG_BREAKWALL, [](Actor* actor) { + if (BGBREAKWALL_GET_F(actor) == BGBREAKWALL_F_2 && + CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE)) { + actor->params = (actor->params & 0xFFF0) | BGBREAKWALL_F_3; + } + }); +} From 6ff3be97de804ea2fd190f91650fb4acbeb2a74e Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 8 Sep 2024 18:45:54 -0400 Subject: [PATCH 37/82] fix some actor shadow textures not updating (#758) --- mm/src/code/z_sub_s.c | 2 ++ mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c | 2 ++ mm/src/overlays/actors/ovl_Boss_07/z_boss_07.c | 2 ++ mm/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c | 2 ++ mm/src/overlays/actors/ovl_En_Kanban/z_en_kanban.c | 1 + mm/src/overlays/actors/ovl_En_Sda/z_en_sda.c | 2 ++ 6 files changed, 11 insertions(+) diff --git a/mm/src/code/z_sub_s.c b/mm/src/code/z_sub_s.c index f2c5666cd..f6c97422d 100644 --- a/mm/src/code/z_sub_s.c +++ b/mm/src/code/z_sub_s.c @@ -1009,6 +1009,8 @@ void SubS_DrawShadowTex(Actor* actor, GameState* gameState, u8* tex) { OPEN_DISPS(gfxCtx); + gSPInvalidateTexCache(POLY_OPA_DISP++, tex); + Gfx_SetupDL25_Opa(gfxCtx); gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, 100); gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); diff --git a/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c b/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c index 3d8bec6e3..89fcfe343 100644 --- a/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c +++ b/mm/src/overlays/actors/ovl_Boss_01/z_boss_01.c @@ -3108,6 +3108,8 @@ void Boss01_DrawShadowTex(u8* tex, Boss01* this, PlayState* play) { OPEN_DISPS(gfxCtx); + gSPInvalidateTexCache(POLY_OPA_DISP++, tex); + Gfx_SetupDL25_Opa(play->state.gfxCtx); alpha = (400.0f - this->actor.world.pos.y) * (1.0f / 400.0f); diff --git a/mm/src/overlays/actors/ovl_Boss_07/z_boss_07.c b/mm/src/overlays/actors/ovl_Boss_07/z_boss_07.c index 603c8e157..8648cfa5c 100644 --- a/mm/src/overlays/actors/ovl_Boss_07/z_boss_07.c +++ b/mm/src/overlays/actors/ovl_Boss_07/z_boss_07.c @@ -2935,6 +2935,8 @@ void Boss07_Wrath_DrawShadowTex(u8* shadowTex, Boss07* this, PlayState* play) { OPEN_DISPS(gfxCtx); + gSPInvalidateTexCache(POLY_OPA_DISP++, shadowTex); + Gfx_SetupDL25_Opa(play->state.gfxCtx); phi_f0 = (400.0f - this->actor.world.pos.y) * 0.0025f; phi_f0 = CLAMP_MIN(phi_f0, 0.0f); diff --git a/mm/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c b/mm/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c index 3dfbc2fbd..7c6d30eb8 100644 --- a/mm/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c +++ b/mm/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c @@ -3066,6 +3066,8 @@ void BossHakugin_DrawShadowTex(u8* tex, BossHakugin* this, PlayState* play) { OPEN_DISPS(gfxCtx); + gSPInvalidateTexCache(POLY_OPA_DISP++, tex); + Gfx_SetupDL25_Opa(play->state.gfxCtx); alpha = (400.0f - this->actor.world.pos.y) * (1.0f / 400.0f); diff --git a/mm/src/overlays/actors/ovl_En_Kanban/z_en_kanban.c b/mm/src/overlays/actors/ovl_En_Kanban/z_en_kanban.c index 9f6e7f77a..c5e6c9fdd 100644 --- a/mm/src/overlays/actors/ovl_En_Kanban/z_en_kanban.c +++ b/mm/src/overlays/actors/ovl_En_Kanban/z_en_kanban.c @@ -1043,6 +1043,7 @@ void EnKanban_Draw(Actor* thisx, PlayState* play) { } } + gSPInvalidateTexCache(POLY_XLU_DISP++, shadowTex); gSPSegment(POLY_XLU_DISP++, 0x08, Lib_SegmentedToVirtual(shadowTex)); gSPDisplayList(POLY_XLU_DISP++, gEnKanban_D_80957DE0); } diff --git a/mm/src/overlays/actors/ovl_En_Sda/z_en_sda.c b/mm/src/overlays/actors/ovl_En_Sda/z_en_sda.c index c0afae600..d6a796651 100644 --- a/mm/src/overlays/actors/ovl_En_Sda/z_en_sda.c +++ b/mm/src/overlays/actors/ovl_En_Sda/z_en_sda.c @@ -324,6 +324,8 @@ void func_80947668(u8* shadowTexture, Player* player, PlayState* play) { OPEN_DISPS(gfxCtx); + gSPInvalidateTexCache(POLY_XLU_DISP++, shadowTexture); + Gfx_SetupDL44_Xlu(play->state.gfxCtx); gDPSetPrimColor(POLY_XLU_DISP++, 0x00, 0x00, 0, 0, 0, (BREG(52) + 50)); From bbfa903a99260ecfb0100da536b815842df2b1f4 Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 8 Sep 2024 18:54:11 -0400 Subject: [PATCH 38/82] fix more incorrect dpad handling for hud updates (#764) --- mm/src/code/z_parameter.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index de76c5641..464d0e2ed 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -2376,6 +2376,14 @@ void Interface_UpdateButtonsPart2(PlayState* play) { } } + // #region 2S2H [Dpad] + for (s16 j = EQUIP_SLOT_D_RIGHT; j <= EQUIP_SLOT_D_UP; j++) { + if (gSaveContext.shipSaveContext.dpad.status[j] == BTN_ENABLED) { + gSaveContext.shipSaveContext.dpad.status[j] = BTN_DISABLED; + } + } + // #endregion + Interface_SetHudVisibility(HUD_VISIBILITY_B); } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_82_08)) { // Swordsman's log minigame @@ -2385,6 +2393,14 @@ void Interface_UpdateButtonsPart2(PlayState* play) { } } + // #region 2S2H [Dpad] + for (s16 j = EQUIP_SLOT_D_RIGHT; j <= EQUIP_SLOT_D_UP; j++) { + if (gSaveContext.shipSaveContext.dpad.status[j] == BTN_ENABLED) { + gSaveContext.shipSaveContext.dpad.status[j] = BTN_DISABLED; + } + } + // #endregion + Interface_SetHudVisibility(HUD_VISIBILITY_A_B_HEARTS_MAGIC_MINIMAP); } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_84_20)) { // Related to moon child @@ -2460,7 +2476,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { gSaveContext.buttonStatus[i] = BTN_DISABLED; } // #region 2S2H [Dpad] - for (s16 j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++) { + for (s16 j = EQUIP_SLOT_D_RIGHT; j <= EQUIP_SLOT_D_UP; j++) { if (gSaveContext.shipSaveContext.dpad.status[j] == BTN_ENABLED) { restoreHudVisibility = true; } From 4d1ddff798abba6fa2f2035cccf81d6f48598bec Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:01:02 -0600 Subject: [PATCH 39/82] Fix some Fierce Diety interactions in Clock Town (#730) * fix fd town archery softlock * allow FD to leave town --- mm/src/overlays/actors/ovl_En_Stop_heishi/z_en_stop_heishi.c | 5 +++++ mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/mm/src/overlays/actors/ovl_En_Stop_heishi/z_en_stop_heishi.c b/mm/src/overlays/actors/ovl_En_Stop_heishi/z_en_stop_heishi.c index f31e7bf70..fd135719d 100644 --- a/mm/src/overlays/actors/ovl_En_Stop_heishi/z_en_stop_heishi.c +++ b/mm/src/overlays/actors/ovl_En_Stop_heishi/z_en_stop_heishi.c @@ -405,6 +405,11 @@ void func_80AE7F34(EnStopheishi* this, PlayState* play) { case PLAYER_FORM_GORON: phi_a2 = 2; break; + + // 2SH2 [FD Enhancement] - Guard treats FD as if Human has already talked + case PLAYER_FORM_FIERCE_DEITY: + phi_a2 = 1; + break; } if (((phi_a2 == 1) || (phi_a2 == 2) || (phi_a2 == 3)) && diff --git a/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c b/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c index 0a0e723f2..57dba44ff 100644 --- a/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c +++ b/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c @@ -587,6 +587,9 @@ void EnSyatekiMan_Town_StartIntroTextbox(EnSyatekiMan* this, PlayState* play) { } break; + // 2SH2 [FD Enhancement] Don't allow playing town archery with FD becuase Swamp prevents FD archery by default. + // Get Goron's "quite the build" text + case PLAYER_FORM_FIERCE_DEITY: case PLAYER_FORM_GORON: if (CURRENT_DAY != 3) { if (!(this->talkFlags & TALK_FLAG_TOWN_HAS_SPOKEN_WITH_GORON)) { From a5059beaebc376309a099ec92162a4ef201eca55 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 12 Sep 2024 14:32:09 -0400 Subject: [PATCH 40/82] fix enum value for woodfall restoration (#769) --- .../Enhancements/Restorations/WoodfallMountainAppearance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp index 12a546d26..ce1d6f774 100644 --- a/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp +++ b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp @@ -8,7 +8,7 @@ extern "C" { } typedef enum { - /* 2 */ BGBREAKWALL_F_2 = 3, // Poisoned Woodfall Mountain + /* 2 */ BGBREAKWALL_F_2 = 2, // Poisoned Woodfall Mountain /* 3 */ BGBREAKWALL_F_3 = 3, // Spring Woodfall Mountain } BgBreakwallParamEx; From 137ca0de12e43c29ea634dd4b3896c5b8ec6c956 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 12 Sep 2024 16:32:19 -0400 Subject: [PATCH 41/82] fix zora magic shield alpha (#768) --- OTRExporter | 2 +- libultraship | 2 +- mm/2s2h/BenPort.cpp | 19 +++++++++++++++++ mm/2s2h/BenPort.h | 1 + mm/2s2h/resource/importer/ArrayFactory.cpp | 24 +++++++++++++++++++++- mm/src/code/z_player_lib.c | 6 +++++- 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/OTRExporter b/OTRExporter index 375489d5f..854685155 160000 --- a/OTRExporter +++ b/OTRExporter @@ -1 +1 @@ -Subproject commit 375489d5f1f5fa4b9144ac9669c411e3b149f32a +Subproject commit 854685155a6addaf72ec2415ac481a08ace9f9ce diff --git a/libultraship b/libultraship index 3d2b4da8e..7a88bfc08 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 3d2b4da8e327a6a096993996c5280c069a92c03f +Subproject commit 7a88bfc08cbe44fd682b8f6f66b9d32d44b699bc diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index a63e696ab..10a567c68 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -1080,6 +1080,25 @@ extern "C" size_t ResourceMgr_GetArraySizeByName(const char* path) { return res->Scalars.size(); } + +// Loads U8 data from an Array resource into an externally managed buffer, or mallocs a new buffer +// if the passed in a nullptr. This malloced buffer must be freed by the caller. +extern "C" u8* ResourceMgr_LoadArrayByNameAsU8(const char* path, u8* buffer) { + auto res = std::static_pointer_cast(GetResourceByName(path)); + + if (buffer == nullptr) { + buffer = (u8*)malloc(sizeof(u8) * res->Scalars.size()); + } + + for (size_t i = 0; i < res->Scalars.size(); i++) { + buffer[i] = res->Scalars[i].u8; + } + + return buffer; +} + +// Loads Vec3s data from an Array resource. +// mallocs a new buffer that must be freed by the caller. extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) { auto res = std::static_pointer_cast(GetResourceByName(path)); diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h index 6aa243e42..81b5975b3 100644 --- a/mm/2s2h/BenPort.h +++ b/mm/2s2h/BenPort.h @@ -87,6 +87,7 @@ Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc); Gfx* ResourceMgr_LoadGfxByName(const char* path); void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); +u8* ResourceMgr_LoadArrayByNameAsU8(const char* path, u8* buffer); char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path); char* ResourceMgr_LoadArrayByName(const char* path); size_t ResourceMgr_GetArraySizeByName(const char* path); diff --git a/mm/2s2h/resource/importer/ArrayFactory.cpp b/mm/2s2h/resource/importer/ArrayFactory.cpp index 9772da149..5ed029e97 100644 --- a/mm/2s2h/resource/importer/ArrayFactory.cpp +++ b/mm/2s2h/resource/importer/ArrayFactory.cpp @@ -43,12 +43,34 @@ std::shared_ptr ResourceFactoryBinaryArrayV0::ReadResource(std: ScalarData data; switch (array->ArrayScalarType) { + case ScalarType::ZSCALAR_S8: + data.s8 = reader->ReadInt8(); + break; + case ScalarType::ZSCALAR_U8: + case ScalarType::ZSCALAR_X8: + data.u8 = reader->ReadUByte(); + break; case ScalarType::ZSCALAR_S16: data.s16 = reader->ReadInt16(); break; case ScalarType::ZSCALAR_U16: + case ScalarType::ZSCALAR_X16: data.u16 = reader->ReadUInt16(); break; + case ScalarType::ZSCALAR_S32: + data.s32 = reader->ReadInt32(); + break; + case ScalarType::ZSCALAR_U32: + case ScalarType::ZSCALAR_X32: + data.u32 = reader->ReadUInt32(); + break; + case ScalarType::ZSCALAR_S64: + data.s64 = reader->ReadInt64(); + break; + case ScalarType::ZSCALAR_U64: + case ScalarType::ZSCALAR_X64: + data.u64 = reader->ReadUInt64(); + break; default: // OTRTODO: IMPLEMENT OTHER TYPES! break; @@ -61,4 +83,4 @@ std::shared_ptr ResourceFactoryBinaryArrayV0::ReadResource(std: return array; } -} // namespace SOH \ No newline at end of file +} // namespace SOH diff --git a/mm/src/code/z_player_lib.c b/mm/src/code/z_player_lib.c index 71947ca65..e90fda727 100644 --- a/mm/src/code/z_player_lib.c +++ b/mm/src/code/z_player_lib.c @@ -2124,13 +2124,17 @@ void Player_DrawZoraShield(PlayState* play, Player* player) { f32 scale = player->unk_B62 * (10.0f / 51.0f); s32 i; + // 2S2H [Port] Graph allocated buffer to be used with ResourceMgr_LoadArrayByNameAsU8 to avoid + // needing to use malloc/free with Scalar based Array resources + u8* alphaU8Buffer = GRAPH_ALLOC(play->state.gfxCtx, 80 * sizeof(u8)); + OPEN_DISPS(play->state.gfxCtx); AnimatedMat_DrawXlu(play, Lib_SegmentedToVirtual(&object_link_zora_Matanimheader_012A80)); Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); // clang-format off - vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&object_link_zora_Vtx_011210)); phi_a0 = (u8*)ResourceMgr_LoadArrayByName(Lib_SegmentedToVirtual(&object_link_zora_U8_011710)); + vtx = ResourceMgr_LoadVtxByName(Lib_SegmentedToVirtual(&object_link_zora_Vtx_011210)); phi_a0 = ResourceMgr_LoadArrayByNameAsU8(Lib_SegmentedToVirtual(&object_link_zora_U8_011710), alphaU8Buffer); // clang-format on // ARRAY_COUNT(object_link_zora_Vtx_011210) From 25887952c9aa3f2bda76c8e05202c44a77c80e91 Mon Sep 17 00:00:00 2001 From: Archez Date: Fri, 13 Sep 2024 10:10:59 -0400 Subject: [PATCH 42/82] [Enhancement] Actor Nametags (#746) * add new GI hooks * move collision viewer to draw hook * actor viewer tweaks; prevent crash when actors are killed * add ShipUtils * add actor name tags * add debug name tags to actor viewer * fixes * headers? * cleanup actor viewer * Add more options for actor name tags * headers * headers * ditch fmt::join cause linux package managers use old spdlog/fmt * just a little more cleanup --- mm/2s2h/DeveloperTools/ActorViewer.cpp | 331 +++++++++++----- mm/2s2h/DeveloperTools/ActorViewer.h | 2 +- mm/2s2h/DeveloperTools/CollisionViewer.cpp | 13 +- .../GameInteractor/GameInteractor.cpp | 11 + .../GameInteractor/GameInteractor.h | 4 + mm/2s2h/Enhancements/NameTag/NameTag.cpp | 358 ++++++++++++++++++ mm/2s2h/Enhancements/NameTag/NameTag.h | 39 ++ mm/2s2h/ShipUtils.cpp | 56 +++ mm/2s2h/ShipUtils.h | 19 + mm/src/code/z_actor.c | 3 + mm/src/code/z_kanfont.c | 2 +- mm/src/code/z_play.c | 5 +- 12 files changed, 731 insertions(+), 112 deletions(-) create mode 100644 mm/2s2h/Enhancements/NameTag/NameTag.cpp create mode 100644 mm/2s2h/Enhancements/NameTag/NameTag.h create mode 100644 mm/2s2h/ShipUtils.cpp create mode 100644 mm/2s2h/ShipUtils.h diff --git a/mm/2s2h/DeveloperTools/ActorViewer.cpp b/mm/2s2h/DeveloperTools/ActorViewer.cpp index 5d87962a2..3a514785c 100644 --- a/mm/2s2h/DeveloperTools/ActorViewer.cpp +++ b/mm/2s2h/DeveloperTools/ActorViewer.cpp @@ -1,7 +1,17 @@ #include "ActorViewer.h" #include "2s2h/BenGui/UIWidgets.hpp" -#include "global.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/NameTag/NameTag.h" +#include +#include +#include +#include + +extern "C" { +#include "z64actor.h" +#include "functions.h" +#include "variables.h" +} typedef struct ActorInfo { u16 id; @@ -10,14 +20,8 @@ typedef struct ActorInfo { Vec3s rot; } ActorInfo; -typedef enum Method { - LIST, - TARGET, - HOLD, -} Method; - -std::array acMapping = { "Switch", "Background", "Player", "Explosive", "NPC", "Enemy", - "Prop", "Item/Action", "Misc.", "Boss", "Door", "Chest" }; +std::array acMapping = { "Switch", "Background", "Player", "Explosive", "NPC", "Enemy", + "Prop", "Item/Action", "Misc.", "Boss", "Door", "Chest" }; #define DEFINE_ACTOR(name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _humanName }, #define DEFINE_ACTOR_INTERNAL(_name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _humanName }, @@ -31,13 +35,33 @@ std::unordered_map actorDescriptions = { #undef DEFINE_ACTOR_INTERNAL #undef DEFINE_ACTOR_UNSET +#define DEFINE_ACTOR(name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _debugName }, +#define DEFINE_ACTOR_INTERNAL(_name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _debugName }, +#define DEFINE_ACTOR_UNSET(_enumValue) { _enumValue, "Unset" }, + +std::unordered_map actorDebugNames = { +#include "tables/actor_table.h" +}; + +#undef DEFINE_ACTOR +#undef DEFINE_ACTOR_INTERNAL +#undef DEFINE_ACTOR_UNSET + +#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer" +#define CVAR_ACTOR_NAME_TAGS(val) "gDeveloperTools.ActorNameTags." val + std::string GetActorDescription(u16 actorNum) { return actorDescriptions.contains(actorNum) ? actorDescriptions[actorNum] : "???"; } +std::string GetActorDebugName(u16 actorNum) { + return actorDebugNames.contains(actorNum) ? actorDebugNames[actorNum] : "???"; +} + std::vector GetCurrentSceneActors() { - if (!gPlayState) + if (!gPlayState) { return {}; + } std::vector sceneActors; for (size_t category = ACTORCAT_SWITCH; category < ACTORCAT_MAX; category++) { @@ -52,29 +76,104 @@ std::vector GetCurrentSceneActors() { return sceneActors; } -static bool needs_reset = false; - -static Actor* display{}; -static Actor* fetch; +static Actor* selectedActor = nullptr; static ActorInfo newActor; -static std::vector list; +static s16 lastSceneId = -1; +static std::string comboBoxLabel = "Please select"; -static s16 lastSceneId = 0; -static s16 newActorId = 0; -static u8 category = 0; -static s8 method = -1; -static std::string filler = "Please select"; static HOOK_ID preventActorDrawHookId = 0; static HOOK_ID preventActorUpdateHookId = 0; +static HOOK_ID actorDeleteHookID = 0; void ResetVariables() { - display = fetch = {}; - newActor = {}; - filler = "Please select"; + selectedActor = nullptr; + comboBoxLabel = "Please select"; GameInteractor::Instance->UnregisterGameHookForPtr(preventActorDrawHookId); GameInteractor::Instance->UnregisterGameHookForPtr(preventActorUpdateHookId); + GameInteractor::Instance->UnregisterGameHook(actorDeleteHookID); preventActorDrawHookId = 0; preventActorUpdateHookId = 0; + actorDeleteHookID = 0; +} + +void SetSelectedActor(Actor* actor) { + ResetVariables(); + selectedActor = actor; + + actorDeleteHookID = GameInteractor::Instance->RegisterGameHookForPtr( + (uintptr_t)selectedActor, [](Actor* _) { ResetVariables(); }); +} + +void ActorViewer_AddTagForActor(Actor* actor) { + if (!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)) { + return; + } + + std::vector parts; + + if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0)) { + parts.push_back(GetActorDebugName(actor->id)); + } + if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0)) { + parts.push_back(GetActorDescription(actor->id)); + } + if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0)) { + parts.push_back(acMapping[actor->category]); + } + if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0)) { + parts.push_back(fmt::format("0x{:04X} ({})", (u16)actor->params, actor->params)); + } + + std::string tag = ""; + for (size_t i = 0; i < parts.size(); i++) { + if (i != 0) { + tag += "\n"; + } + tag += parts.at(i); + } + + bool withZBuffer = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("WithZBuffer"), 0); + + NameTag_RegisterForActorWithOptions(actor, tag.c_str(), + { .tag = DEBUG_ACTOR_NAMETAG_TAG, .noZBuffer = !withZBuffer }); +} + +void ActorViewer_AddTagForAllActors() { + if (gPlayState == nullptr) { + return; + } + + for (size_t i = 0; i < ARRAY_COUNT(gPlayState->actorCtx.actorLists); i++) { + ActorListEntry currList = gPlayState->actorCtx.actorLists[i]; + Actor* currAct = currList.first; + while (currAct != nullptr) { + ActorViewer_AddTagForActor(currAct); + currAct = currAct->next; + } + } +} + +void ActorViewer_RegisterNameTagHooks() { + static HOOK_ID actorInitHookID = 0; + GameInteractor::Instance->UnregisterGameHook(actorInitHookID); + actorInitHookID = 0; + + if (!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)) { + return; + } + + actorInitHookID = + GameInteractor::Instance->RegisterGameHook(ActorViewer_AddTagForActor); +} + +void ActorViewerWindow::UpdateElement() { + static bool lastVisibleState = mIsVisible; + + if (!mIsVisible && lastVisibleState != mIsVisible) { + ResetVariables(); + } + + lastVisibleState = mIsVisible; } void ActorViewerWindow::DrawElement() { @@ -85,55 +184,97 @@ void ActorViewerWindow::DrawElement() { } if (gPlayState != nullptr) { - needs_reset = lastSceneId != gPlayState->sceneId; - if (needs_reset) { + if (lastSceneId != gPlayState->sceneId) { ResetVariables(); lastSceneId = gPlayState->sceneId; - needs_reset = false; } - if (ImGui::BeginCombo("Actor", filler.c_str())) { - if (gPlayState != nullptr) { - list = GetCurrentSceneActors(); - lastSceneId = gPlayState->sceneId; + if (ImGui::BeginChild("options", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { + bool toggled = false; + bool optionChange = false; + + ImGui::SeparatorText("Options"); + + toggled = UIWidgets::CVarCheckbox("Actor Name Tags", CVAR_ACTOR_NAME_TAGS("Enabled"), + { .tooltip = "Adds \"name tags\" above actors for identification" }); + + ImGui::SameLine(); + + UIWidgets::Button("Display Items", { .tooltip = "Click to add display items on the name tags" }); + + if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonLeft | ImGuiPopupFlags_NoReopen)) { + optionChange |= UIWidgets::CVarCheckbox("ID", CVAR_ACTOR_NAME_TAGS("DisplayID")); + optionChange |= UIWidgets::CVarCheckbox("Description", CVAR_ACTOR_NAME_TAGS("DisplayDescription")); + optionChange |= UIWidgets::CVarCheckbox("Category", CVAR_ACTOR_NAME_TAGS("DisplayCategory")); + optionChange |= UIWidgets::CVarCheckbox("Params", CVAR_ACTOR_NAME_TAGS("DisplayParams")); + + ImGui::EndPopup(); } - if (!list.empty()) { - u8 count = 0; - u8 prev_category = 0xff; - for (size_t i = 0; i < list.size(); i++) { - std::string label = acMapping[list[i]->category]; - if (list[i]->category != prev_category) { - prev_category = list[i]->category; - count = 1; + + optionChange |= UIWidgets::CVarCheckbox( + "Name tags with Z-Buffer", CVAR_ACTOR_NAME_TAGS("WithZBuffer"), + { .tooltip = "Allow name tags to be obstructed when behind geometry and actors" }); + + if (toggled || optionChange) { + bool tagsEnabled = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0); + bool noOptionsEnabled = !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0) && + !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0) && + !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0) && + !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0); + + // Save the user an extra click and prevent adding "empty" tags by enabling, + // disabling, or setting an option based on what changed + if (tagsEnabled && noOptionsEnabled) { + if (toggled) { + CVarSetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 1); } else { - count++; + CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0); } - label += " " + std::to_string(count) + ": " + GetActorDescription(list[i]->id); - if (ImGui::Selectable(label.c_str())) { - method = LIST; - display = list[i]; - newActorId = i; - filler = label; - GameInteractor::Instance->UnregisterGameHookForPtr( - preventActorDrawHookId); - GameInteractor::Instance->UnregisterGameHookForPtr( - preventActorUpdateHookId); - preventActorDrawHookId = 0; - preventActorUpdateHookId = 0; - break; + } else if (optionChange && !tagsEnabled && !noOptionsEnabled) { + CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 1); + } + + ActorViewer_RegisterNameTagHooks(); + NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG); + ActorViewer_AddTagForAllActors(); + } + } + ImGui::EndChild(); + + if (ImGui::TreeNode("Select existing Actor")) { + if (ImGui::BeginCombo("Actor", comboBoxLabel.c_str())) { + auto list = GetCurrentSceneActors(); + lastSceneId = gPlayState->sceneId; + + if (!list.empty()) { + u8 count = 0; + u8 prev_category = 0xff; + for (size_t i = 0; i < list.size(); i++) { + std::string label = acMapping[list[i]->category]; + if (list[i]->category != prev_category) { + prev_category = list[i]->category; + count = 1; + } else { + count++; + } + label += " " + std::to_string(count) + ": " + GetActorDescription(list[i]->id); + if (ImGui::Selectable(label.c_str())) { + SetSelectedActor(list[i]); + comboBoxLabel = label; + + break; + } } } + ImGui::EndCombo(); } - ImGui::EndCombo(); - } - if (ImGui::TreeNode("Selected Actor")) { - if (display != nullptr) { + if (selectedActor != nullptr) { ImGui::BeginGroup(); - ImGui::Text("ID: %hd", display->id); - ImGui::Text("Description: %s", GetActorDescription(display->id).c_str()); - ImGui::Text("Category: %s", acMapping[display->category]); - ImGui::Text("Params: %hd", display->params); + ImGui::Text("ID: %hd", selectedActor->id); + ImGui::Text("Description: %s", GetActorDescription(selectedActor->id).c_str()); + ImGui::Text("Category: %s", acMapping[selectedActor->category]); + ImGui::Text("Params: %hd", selectedActor->params); ImGui::EndGroup(); ImGui::BeginGroup(); @@ -147,7 +288,7 @@ void ActorViewerWindow::DrawElement() { if (ImGui::Button("Stop Drawing", ImVec2(ImGui::GetFontSize() * 10, 0))) { preventActorDrawHookId = GameInteractor::Instance->RegisterGameHookForPtr( - (uintptr_t)display, [](Actor* _, bool* result) { *result = false; }); + (uintptr_t)selectedActor, [](Actor* _, bool* result) { *result = false; }); } } ImGui::SameLine(); @@ -161,7 +302,7 @@ void ActorViewerWindow::DrawElement() { if (ImGui::Button("Stop Updating", ImVec2(ImGui::GetFontSize() * 10, 0))) { preventActorUpdateHookId = GameInteractor::Instance->RegisterGameHookForPtr( - (uintptr_t)display, [](Actor* _, bool* result) { *result = false; }); + (uintptr_t)selectedActor, [](Actor* _, bool* result) { *result = false; }); } } ImGui::EndGroup(); @@ -170,88 +311,71 @@ void ActorViewerWindow::DrawElement() { ImGui::BeginGroup(); ImGui::Text("Actor Position"); - ImGui::InputScalar("x", ImGuiDataType_Float, &display->world.pos.x); + ImGui::InputScalar("x", ImGuiDataType_Float, &selectedActor->world.pos.x); ImGui::SameLine(); - ImGui::InputScalar("y", ImGuiDataType_Float, &display->world.pos.y); + ImGui::InputScalar("y", ImGuiDataType_Float, &selectedActor->world.pos.y); ImGui::SameLine(); - ImGui::InputScalar("z", ImGuiDataType_Float, &display->world.pos.z); + ImGui::InputScalar("z", ImGuiDataType_Float, &selectedActor->world.pos.z); ImGui::EndGroup(); ImGui::BeginGroup(); ImGui::Text("Actor Rotation"); - ImGui::InputScalar("rx", ImGuiDataType_S16, &display->world.rot.x); + ImGui::InputScalar("rx", ImGuiDataType_S16, &selectedActor->world.rot.x); ImGui::SameLine(); - ImGui::InputScalar("ry", ImGuiDataType_S16, &display->world.rot.y); + ImGui::InputScalar("ry", ImGuiDataType_S16, &selectedActor->world.rot.y); ImGui::SameLine(); - ImGui::InputScalar("rz", ImGuiDataType_S16, &display->world.rot.z); + ImGui::InputScalar("rz", ImGuiDataType_S16, &selectedActor->world.rot.z); ImGui::EndGroup(); ImGui::PopItemWidth(); ImGui::PushItemWidth(ImGui::GetFontSize() * 5); - if ((display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) && - display->colChkInfo.health > 0) { - ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health); + if ((selectedActor->category == ACTORCAT_BOSS || selectedActor->category == ACTORCAT_ENEMY) && + selectedActor->colChkInfo.health > 0) { + ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &selectedActor->colChkInfo.health); } ImGui::PopItemWidth(); ImGui::BeginGroup(); ImGui::Text("Flags"); - UIWidgets::DrawFlagArray32("flags", display->flags); + UIWidgets::DrawFlagArray32("flags", selectedActor->flags); ImGui::EndGroup(); ImGui::BeginGroup(); ImGui::Text("BG Check"); - UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags); + UIWidgets::DrawFlagArray16("bgCheckFlags", selectedActor->bgCheckFlags); ImGui::EndGroup(); } - if (UIWidgets::Button("Refresh")) { - list = GetCurrentSceneActors(); - display = list[newActorId]; - } - if (UIWidgets::Button("Go to Actor")) { Player* player = GET_PLAYER(gPlayState); - if (display != nullptr) { - Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos); - Math_Vec3f_Copy(&player->actor.home.pos, &display->world.pos); + if (selectedActor != nullptr) { + Math_Vec3f_Copy(&player->actor.world.pos, &selectedActor->world.pos); + Math_Vec3f_Copy(&player->actor.home.pos, &selectedActor->world.pos); } } if (UIWidgets::Button("Fetch: Target", { .tooltip = "Grabs actor with target arrow above it." })) { Player* player = GET_PLAYER(gPlayState); - fetch = player->lockOnActor; - if (fetch != nullptr) { - display = fetch; - category = fetch->category; - list = GetCurrentSceneActors(); - method = TARGET; - } else { - display = {}; + if (player->lockOnActor != nullptr) { + SetSelectedActor(player->lockOnActor); } } if (UIWidgets::Button("Fetch: Held", { .tooltip = "Grabs actor Link is currently holding." })) { Player* player = GET_PLAYER(gPlayState); - fetch = player->heldActor; - if (fetch != nullptr) { - display = fetch; - category = fetch->category; - list = GetCurrentSceneActors(); - method = HOLD; - } else { - display = {}; + if (player->heldActor != nullptr) { + SetSelectedActor(player->heldActor); } } - if (UIWidgets::Button("Kill", { .color = UIWidgets::Colors::Red }) && display != nullptr && - display->id != ACTOR_PLAYER) { - Actor_Kill(display); + if (UIWidgets::Button("Kill", { .color = UIWidgets::Colors::Red }) && selectedActor != nullptr && + selectedActor->id != ACTOR_PLAYER) { + Actor_Kill(selectedActor); } ImGui::TreePop(); } - if (ImGui::TreeNode("New...")) { + if (ImGui::TreeNode("Spawn new Actor")) { ImGui::PushItemWidth(ImGui::GetFontSize() * 10); ImU16 one = 1; @@ -299,8 +423,8 @@ void ActorViewerWindow::DrawElement() { } if (UIWidgets::Button("Spawn as Child", { .color = UIWidgets::Colors::Green })) { - Actor* parent = display; - if (parent != nullptr) { + Actor* parent = selectedActor; + if (parent != nullptr && parent->child == nullptr) { Actor_SpawnAsChild(&gPlayState->actorCtx, parent, gPlayState, newActor.id, newActor.pos.x, newActor.pos.y, newActor.pos.z, newActor.rot.x, newActor.rot.y, newActor.rot.z, newActor.params); @@ -322,4 +446,5 @@ void ActorViewerWindow::DrawElement() { } void ActorViewerWindow::InitElement() { + ActorViewer_RegisterNameTagHooks(); } diff --git a/mm/2s2h/DeveloperTools/ActorViewer.h b/mm/2s2h/DeveloperTools/ActorViewer.h index a93a9b68c..9fa9c0eb1 100644 --- a/mm/2s2h/DeveloperTools/ActorViewer.h +++ b/mm/2s2h/DeveloperTools/ActorViewer.h @@ -8,5 +8,5 @@ class ActorViewerWindow : public Ship::GuiWindow { void InitElement() override; void DrawElement() override; - void UpdateElement() override{}; + void UpdateElement() override; }; diff --git a/mm/2s2h/DeveloperTools/CollisionViewer.cpp b/mm/2s2h/DeveloperTools/CollisionViewer.cpp index 884425fb0..758ade313 100644 --- a/mm/2s2h/DeveloperTools/CollisionViewer.cpp +++ b/mm/2s2h/DeveloperTools/CollisionViewer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" extern "C" { #include @@ -300,11 +301,6 @@ void CreateSphereData() { sphereGfx.push_back(gsSPEndDisplayList()); } -void CollisionViewerWindow::InitElement() { - CreateCylinderData(); - CreateSphereData(); -} - // Initializes the display list for a ColRenderSetting void InitGfx(std::vector& gfx, ColRenderSetting setting) { uint32_t rm; @@ -736,3 +732,10 @@ extern "C" void DrawCollisionViewer() { CLOSE_DISPS(gPlayState->state.gfxCtx); } + +void CollisionViewerWindow::InitElement() { + CreateCylinderData(); + CreateSphereData(); + + GameInteractor::Instance->RegisterGameHook(DrawCollisionViewer); +} diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index 15f96126b..059e9db11 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -75,6 +75,10 @@ void GameInteractor_ExecuteAfterRoomSceneCommands(s16 sceneId, s8 roomNum) { GameInteractor::Instance->ExecuteHooksForFilter(sceneId, roomNum); } +void GameInteractor_ExecuteOnPlayDrawWorldEnd() { + GameInteractor::Instance->ExecuteHooks(); +} + void GameInteractor_ExecuteOnPlayDestroy() { GameInteractor::Instance->ExecuteHooks(); } @@ -134,6 +138,13 @@ void GameInteractor_ExecuteOnActorKill(Actor* actor) { GameInteractor::Instance->ExecuteHooksForFilter(actor); } +void GameInteractor_ExecuteOnActorDestroy(Actor* actor) { + GameInteractor::Instance->ExecuteHooks(actor); + GameInteractor::Instance->ExecuteHooksForID(actor->id, actor); + GameInteractor::Instance->ExecuteHooksForPtr((uintptr_t)actor, actor); + GameInteractor::Instance->ExecuteHooksForFilter(actor); +} + void GameInteractor_ExecuteOnPlayerPostLimbDraw(Player* player, s32 limbIndex) { GameInteractor::Instance->ExecuteHooks(player, limbIndex); GameInteractor::Instance->ExecuteHooksForID(limbIndex, player, limbIndex); diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index a076e8f2a..8caf4fb5c 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -274,6 +274,7 @@ class GameInteractor { DEFINE_HOOK(OnSceneInit, (s8 sceneId, s8 spawnNum)); DEFINE_HOOK(OnRoomInit, (s8 sceneId, s8 roomNum)); DEFINE_HOOK(AfterRoomSceneCommands, (s8 sceneId, s8 roomNum)); + DEFINE_HOOK(OnPlayDrawWorldEnd, ()); DEFINE_HOOK(OnPlayDestroy, ()); DEFINE_HOOK(ShouldActorInit, (Actor * actor, bool* should)); @@ -283,6 +284,7 @@ class GameInteractor { DEFINE_HOOK(ShouldActorDraw, (Actor * actor, bool* should)); DEFINE_HOOK(OnActorDraw, (Actor * actor)); DEFINE_HOOK(OnActorKill, (Actor * actor)); + DEFINE_HOOK(OnActorDestroy, (Actor * actor)); DEFINE_HOOK(OnPlayerPostLimbDraw, (Player * player, s32 limbIndex)); DEFINE_HOOK(OnSceneFlagSet, (s16 sceneId, FlagType flagType, u32 flag)); @@ -322,6 +324,7 @@ void GameInteractor_ExecuteBeforeMoonCrashSaveReset(); void GameInteractor_ExecuteOnSceneInit(s16 sceneId, s8 spawnNum); void GameInteractor_ExecuteOnRoomInit(s16 sceneId, s8 roomNum); void GameInteractor_ExecuteAfterRoomSceneCommands(s16 sceneId, s8 roomNum); +void GameInteractor_ExecuteOnPlayDrawWorldEnd(); void GameInteractor_ExecuteOnPlayDestroy(); bool GameInteractor_ShouldActorInit(Actor* actor); @@ -331,6 +334,7 @@ void GameInteractor_ExecuteOnActorUpdate(Actor* actor); bool GameInteractor_ShouldActorDraw(Actor* actor); void GameInteractor_ExecuteOnActorDraw(Actor* actor); void GameInteractor_ExecuteOnActorKill(Actor* actor); +void GameInteractor_ExecuteOnActorDestroy(Actor* actor); void GameInteractor_ExecuteOnPlayerPostLimbDraw(Player* player, s32 limbIndex); void GameInteractor_ExecuteOnSceneFlagSet(s16 sceneId, FlagType flagType, u32 flag); diff --git a/mm/2s2h/Enhancements/NameTag/NameTag.cpp b/mm/2s2h/Enhancements/NameTag/NameTag.cpp new file mode 100644 index 000000000..f20016c0a --- /dev/null +++ b/mm/2s2h/Enhancements/NameTag/NameTag.cpp @@ -0,0 +1,358 @@ +#include "NameTag.h" +#include +#include +#include +#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/ShipUtils.h" + +extern "C" { +#include "z64.h" +#include "macros.h" +#include "functions.h" +#include "variables.h" +#include "interface/message_static/message_static.h" +extern PlayState* gPlayState; +} + +typedef struct { + Actor* actor; + std::string text; // Original text + std::string processedText; // Text filtered for supported font textures + const char* tag; // Tag identifier + Color_RGBA8 textColor; // Text color override. Global color is used if alpha is 0 + int16_t height; // Textbox height + int16_t width; // Textbox width + int16_t yOffset; // Addition Y offset + uint8_t noZBuffer; // Allow rendering over geometry + Mtx* mtx; // Allocated Mtx for rendering + Vtx* vtx; // Allocated Vtx for rendering +} NameTag; + +static std::vector nameTags; +static std::vector nameTagDl; + +void NameTag_RegisterHooks(); + +void FreeNameTag(NameTag* nameTag) { + if (nameTag->vtx != nullptr) { + free(nameTag->vtx); + nameTag->vtx = nullptr; + } + if (nameTag->mtx != nullptr) { + free(nameTag->mtx); + nameTag->mtx = nullptr; + } +} + +void DrawNameTag(PlayState* play, const NameTag* nameTag) { + if (nameTag->actor == nullptr || nameTag->actor->draw == nullptr || !nameTag->actor->isDrawn || + nameTag->vtx == nullptr || nameTag->mtx == nullptr) { + return; + } + + // Name tag is too far away to meaningfully read, don't bother rendering it + if (nameTag->actor->xyzDistToPlayerSq > 440000.0f) { + return; + } + + // Fade out name tags that are far away + float alpha = 1.0f; + if (nameTag->actor->xyzDistToPlayerSq > 360000.0f) { + alpha = (440000.0f - nameTag->actor->xyzDistToPlayerSq) / 80000.0f; + } + + float scale = 75.0f / 100.f; + + size_t numChar = nameTag->processedText.length(); + // No text to render + if (numChar == 0) { + return; + } + + Color_RGBA8 textboxColor = { 0, 0, 0, 80 }; + Color_RGBA8 textColor = { 255, 255, 255, 255 }; + + // BENTODO: Cosmetic editor support + // if (CVarGetInteger(CVAR_COSMETIC("HUD.NameTagActorBackground.Changed"), 0)) { + // textboxColor = CVarGetColor(CVAR_COSMETIC("HUD.NameTagActorBackground.Value"), textboxColor); + // } + // if (CVarGetInteger(CVAR_COSMETIC("HUD.NameTagActorText.Changed"), 0)) { + // textColor = CVarGetColor(CVAR_COSMETIC("HUD.NameTagActorText.Value"), textColor); + // } + + FrameInterpolation_RecordOpenChild(nameTag->actor, 10000); + + // Prefer the highest between world position and focus position if targetable + float posY = nameTag->actor->world.pos.y; + if (nameTag->actor->flags & ACTOR_FLAG_TARGETABLE) { + posY = std::max(posY, nameTag->actor->focus.pos.y); + } + + posY += nameTag->yOffset + 16; + + // Set position, billboard effect, scale (with mirror mode), then center nametag + Matrix_Translate(nameTag->actor->world.pos.x, posY, nameTag->actor->world.pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + // BENTODO: Apply mirror world flipping to X scale + Matrix_Scale(scale, -scale, 1.0f, MTXMODE_APPLY); + Matrix_Translate(-(float)nameTag->width / 2, -nameTag->height, 0, MTXMODE_APPLY); + Matrix_ToMtx(nameTag->mtx); + + nameTagDl.push_back(gsSPMatrix(nameTag->mtx, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW)); + + // textbox + nameTagDl.push_back(gsSPVertex(nameTag->vtx, 4, 0)); + nameTagDl.push_back(gsDPSetPrimColor(0, 0, textboxColor.r, textboxColor.g, textboxColor.b, textboxColor.a * alpha)); + + // Multi-instruction macro, need to insert all to the dl buffer + Gfx textboxTexture[] = { gsDPLoadTextureBlock_4b(gMessageDefaultBackgroundTex, G_IM_FMT_I, 128, 64, 0, G_TX_MIRROR, + G_TX_NOMIRROR, 7, 0, G_TX_NOLOD, G_TX_NOLOD) }; + nameTagDl.insert(nameTagDl.end(), std::begin(textboxTexture), std::end(textboxTexture)); + + nameTagDl.push_back(gsSP1Quadrangle(0, 2, 3, 1, 0)); + + // text + if (nameTag->textColor.a == 0) { + nameTagDl.push_back(gsDPSetPrimColor(0, 0, textColor.r, textColor.g, textColor.b, textColor.a * alpha)); + } else { + nameTagDl.push_back(gsDPSetPrimColor(0, 0, nameTag->textColor.r, nameTag->textColor.g, nameTag->textColor.b, + nameTag->textColor.a * alpha)); + } + + for (size_t i = 0, vtxGroup = 0; i < numChar; i++) { + // A maximum of 64 Vtx can be loaded at once by gSPVertex, or basically 16 characters + // handle loading groups of 16 chars at a time until there are no more left to load + if (i % 16 == 0) { + size_t numVtxToLoad = std::min(numChar - i, 16) * 4; + nameTagDl.push_back(gsSPVertex(&(nameTag->vtx)[4 + (vtxGroup * 16 * 4)], numVtxToLoad, 0)); + vtxGroup++; + } + + if (nameTag->processedText[i] != '\n') { + TexturePtr texture = Ship_GetCharFontTextureNES(nameTag->processedText[i]); + int16_t vertexStart = 4 * (i % 16); + + // Multi-instruction macro, need to insert all to the dl buffer + Gfx charTexture[] = { gsDPLoadTextureBlock_4b( + texture, G_IM_FMT_I, FONT_CHAR_TEX_WIDTH, FONT_CHAR_TEX_HEIGHT, 0, G_TX_NOMIRROR | G_TX_CLAMP, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD) }; + nameTagDl.insert(nameTagDl.end(), std::begin(charTexture), std::end(charTexture)); + + nameTagDl.push_back(gsSP1Quadrangle(vertexStart, vertexStart + 2, vertexStart + 3, vertexStart + 1, 0)); + } + } + + nameTagDl.push_back(gsSPPopMatrix(G_MTX_MODELVIEW)); + + FrameInterpolation_RecordCloseChild(); +} + +// Draw all the name tags by leveraging a system heap buffer for majority of the graphics commands +void DrawNameTags() { + if (gPlayState == nullptr || nameTags.size() == 0) { + return; + } + + nameTagDl.clear(); + + OPEN_DISPS(gPlayState->state.gfxCtx); + + // Setup before rendering name tags + POLY_XLU_DISP = Gfx_SetupDL39(POLY_XLU_DISP); + + nameTagDl.push_back(gsDPSetAlphaCompare(G_AC_NONE)); + nameTagDl.push_back( + gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0)); + + bool zbufferEnabled = false; + + // Add all the name tags + for (const auto& nameTag : nameTags) { + // Toggle ZBuffer mode based on last state and next tag + if (zbufferEnabled == nameTag.noZBuffer) { + if (nameTag.noZBuffer) { + nameTagDl.push_back(gsSPClearGeometryMode(G_ZBUFFER)); + zbufferEnabled = false; + } else { + nameTagDl.push_back(gsSPSetGeometryMode(G_ZBUFFER)); + zbufferEnabled = true; + } + } + + DrawNameTag(gPlayState, &nameTag); + } + + // End the display list buffer + nameTagDl.push_back(gsSPEndDisplayList()); + + gSPDisplayList(POLY_XLU_DISP++, nameTagDl.data()); + + CLOSE_DISPS(gPlayState->state.gfxCtx); +} + +void UpdateNameTags() { + // Leveraging ZBuffer above allows the name tags to be obscured by OPA surfaces based on depth. + // However, XLU surfaces do not calculate depth with regards to other XLU surfaces. + // With multiple name tags, a tag can only obscure other tags based on draw order. + // Here we sort the tags so that actors further away from the camera are ordered first. + std::sort(nameTags.begin(), nameTags.end(), [](NameTag a, NameTag b) { + if (a.actor == nullptr || b.actor == nullptr) { + return true; + } + + f32 aDistToCamera = Actor_WorldDistXZToPoint(a.actor, &gPlayState->mainCamera.eye); + f32 bDistToCamera = Actor_WorldDistXZToPoint(b.actor, &gPlayState->mainCamera.eye); + + return aDistToCamera > bDistToCamera; + }); +} + +extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options) { + // BENTODO: Handle mapping UTF-8 special chars to font equivalent + std::string processedText = std::string(text); + + // Strip out unsupported characters + // 188 is max supported texture for the in-game font system, + // and filter anything less than a space but not the newline or nul characters + processedText.erase( + std::remove_if(processedText.begin(), processedText.end(), + [](const char& c) { return (uint8_t)c > 188 || (c < ' ' && c != '\n' && c != '\0'); }), + processedText.end()); + + size_t numChar = processedText.length(); + int16_t numLines = 1; + int16_t offsetX = 0; + int16_t maxOffsetX = 0; + + // 4 vertex per character plus one extra group of 4 for the textbox + Vtx* vertices = (Vtx*)calloc(sizeof(Vtx[4]), numChar + 1); + + // Set all the char vtx first to get the total size for the textbox + for (size_t i = 0; i < numChar; i++) { + if (processedText[i] == '\n') { + offsetX = 0; + numLines++; + } + + int16_t charWidth = Ship_GetCharFontWidthNES(processedText[i]); + + Ship_CreateQuadVertexGroup(&(vertices)[(i + 1) * 4], offsetX, (numLines - 1) * 16, charWidth, 16, 0); + offsetX += charWidth; + + if (offsetX > maxOffsetX) { + maxOffsetX = offsetX; + } + } + + // Vtx for textbox, add +/- 4 in all directions + int16_t height = (numLines * 16) + 8; + int16_t width = maxOffsetX + 8; + Ship_CreateQuadVertexGroup(vertices, -4, -4, width, height, 0); + + // Update the texture coordinates to consume the full textbox texture size (including mirror region) + vertices[1].v.tc[0] = 256 << 5; + vertices[2].v.tc[1] = 64 << 5; + vertices[3].v.tc[0] = 256 << 5; + vertices[3].v.tc[1] = 64 << 5; + + NameTag nameTag; + nameTag.actor = actor; + nameTag.text = std::string(text); + nameTag.processedText = processedText; + nameTag.tag = options.tag; + nameTag.textColor = options.textColor; + nameTag.height = height; + nameTag.width = width; + nameTag.yOffset = options.yOffset; + nameTag.noZBuffer = options.noZBuffer; + nameTag.mtx = new Mtx(); + nameTag.vtx = vertices; + + nameTags.push_back(nameTag); + + NameTag_RegisterHooks(); +} + +extern "C" void NameTag_RegisterForActor(Actor* actor, const char* text) { + NameTag_RegisterForActorWithOptions(actor, text, {}); +} + +extern "C" void NameTag_RemoveAllForActor(Actor* actor) { + for (auto it = nameTags.begin(); it != nameTags.end();) { + if (it->actor == actor) { + FreeNameTag(&(*it)); + it = nameTags.erase(it); + } else { + it++; + } + } + + NameTag_RegisterHooks(); +} + +extern "C" void NameTag_RemoveAllByTag(const char* tag) { + for (auto it = nameTags.begin(); it != nameTags.end();) { + if (it->tag != nullptr && strcmp(it->tag, tag) == 0) { + FreeNameTag(&(*it)); + it = nameTags.erase(it); + } else { + it++; + } + } + + NameTag_RegisterHooks(); +} + +void RemoveAllNameTags() { + for (auto& nameTag : nameTags) { + FreeNameTag(&nameTag); + } + + nameTags.clear(); + + NameTag_RegisterHooks(); +} + +void NameTag_RegisterHooks() { + static HOOK_ID gameStatUpdateHookID = 0; + static HOOK_ID drawHookID = 0; + static HOOK_ID playDestroyHookID = 0; + static HOOK_ID actorDestroyHookID = 0; + static bool sRegisteredHooks = false; + + // Hooks already (un)registered based on nametags + if ((nameTags.size() > 0) == sRegisteredHooks) { + return; + } + + GameInteractor::Instance->UnregisterGameHook(gameStatUpdateHookID); + GameInteractor::Instance->UnregisterGameHook(drawHookID); + GameInteractor::Instance->UnregisterGameHook(playDestroyHookID); + GameInteractor::Instance->UnregisterGameHook(actorDestroyHookID); + gameStatUpdateHookID = 0; + drawHookID = 0; + playDestroyHookID = 0; + actorDestroyHookID = 0; + sRegisteredHooks = false; + + if (nameTags.size() == 0) { + return; + } + + sRegisteredHooks = true; + + // Reorder tags every frame to mimic depth rendering + gameStatUpdateHookID = + GameInteractor::Instance->RegisterGameHook(UpdateNameTags); + + // Render name tags at the end of the Play World drawing + drawHookID = GameInteractor::Instance->RegisterGameHook(DrawNameTags); + + // Remove all name tags on play state destroy as all actors are removed anyways + playDestroyHookID = GameInteractor::Instance->RegisterGameHook(RemoveAllNameTags); + + // Remove all name tags for actor on destroy + actorDestroyHookID = + GameInteractor::Instance->RegisterGameHook(NameTag_RemoveAllForActor); +} diff --git a/mm/2s2h/Enhancements/NameTag/NameTag.h b/mm/2s2h/Enhancements/NameTag/NameTag.h new file mode 100644 index 000000000..da6a22caf --- /dev/null +++ b/mm/2s2h/Enhancements/NameTag/NameTag.h @@ -0,0 +1,39 @@ +#ifndef NAMETAG_H +#define NAMETAG_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "z64actor.h" +#ifdef __cplusplus +} +#endif + +typedef struct { + const char* tag; // Tag identifier to filter/remove multiple tags + int16_t yOffset; // Additional Y offset to apply for the name tag + Color_RGBA8 textColor; // Text color override. Global color is used if alpha is 0 + uint8_t noZBuffer; // Allow rendering over geometry +} NameTagOptions; + +// Register required hooks for nametags on startup +void NameTag_RegisterHooks(); + +#ifdef __cplusplus +extern "C" { +#endif + +// Registers a name tag to an actor with additional options applied +void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options); +// Registers a name tag to an actor. Multiple name tags can exist for the same actor +void NameTag_RegisterForActor(Actor* actor, const char* text); +// Remove all name tags registered to a specific actor +void NameTag_RemoveAllForActor(Actor* actor); +// Remove all name tags that share the same tag identifier +void NameTag_RemoveAllByTag(const char* tag); + +#ifdef __cplusplus +} +#endif + +#endif // NAMETAG_H diff --git a/mm/2s2h/ShipUtils.cpp b/mm/2s2h/ShipUtils.cpp new file mode 100644 index 000000000..5d50eb62e --- /dev/null +++ b/mm/2s2h/ShipUtils.cpp @@ -0,0 +1,56 @@ +#include "ShipUtils.h" +#include +#include "PR/ultratypes.h" +#include "assets/2s2h_assets.h" + +extern "C" { +#include "macros.h" + +extern f32 sNESFontWidths[160]; +extern const char* fontTbl[156]; +} + +// Build vertex coordinates for a quad command +// In order of top left, top right, bottom left, then bottom right +// Supports flipping the texture horizontally +extern "C" void Ship_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH) { + vtxList[0].v.ob[0] = xStart; + vtxList[0].v.ob[1] = yStart; + vtxList[0].v.tc[0] = (flippedH ? width : 0) << 5; + vtxList[0].v.tc[1] = 0 << 5; + + vtxList[1].v.ob[0] = xStart + width; + vtxList[1].v.ob[1] = yStart; + vtxList[1].v.tc[0] = (flippedH ? width * 2 : width) << 5; + vtxList[1].v.tc[1] = 0 << 5; + + vtxList[2].v.ob[0] = xStart; + vtxList[2].v.ob[1] = yStart + height; + vtxList[2].v.tc[0] = (flippedH ? width : 0) << 5; + vtxList[2].v.tc[1] = height << 5; + + vtxList[3].v.ob[0] = xStart + width; + vtxList[3].v.ob[1] = yStart + height; + vtxList[3].v.tc[0] = (flippedH ? width * 2 : width) << 5; + vtxList[3].v.tc[1] = height << 5; +} + +extern "C" f32 Ship_GetCharFontWidthNES(u8 character) { + u8 adjustedChar = character - ' '; + + if (adjustedChar >= ARRAY_COUNTU(sNESFontWidths)) { + return 0.0f; + } + + return sNESFontWidths[adjustedChar]; +} + +extern "C" TexturePtr Ship_GetCharFontTextureNES(u8 character) { + u8 adjustedChar = character - ' '; + + if (adjustedChar >= ARRAY_COUNTU(sNESFontWidths)) { + return (TexturePtr)gEmptyTexture; + } + + return (TexturePtr)fontTbl[adjustedChar]; +} diff --git a/mm/2s2h/ShipUtils.h b/mm/2s2h/ShipUtils.h new file mode 100644 index 000000000..f30c39aac --- /dev/null +++ b/mm/2s2h/ShipUtils.h @@ -0,0 +1,19 @@ +#ifndef SHIP_UTILS_H +#define SHIP_UTILS_H + +#include +#include "PR/ultratypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void Ship_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH); +f32 Ship_GetCharFontWidthNES(u8 character); +TexturePtr Ship_GetCharFontTextureNES(u8 character); + +#ifdef __cplusplus +} +#endif + +#endif // SHIP_UTILS_H diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 34c987a83..65f9c9bac 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -3649,6 +3649,9 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { Actor* newHead; ActorOverlay* overlayEntry = actor->overlayEntry; + // Execute before actor memory is freed + GameInteractor_ExecuteOnActorDestroy(actor); + if ((player != NULL) && (actor == player->lockOnActor)) { Player_Untarget(player); Camera_ChangeMode(Play_GetCamera(play, Play_GetActiveCamId(play)), CAM_MODE_NORMAL); diff --git a/mm/src/code/z_kanfont.c b/mm/src/code/z_kanfont.c index 760ffc312..facf63d9a 100644 --- a/mm/src/code/z_kanfont.c +++ b/mm/src/code/z_kanfont.c @@ -5,7 +5,7 @@ #include // #region 2S2H [Port] Asset tables we can pull from instead of from ROM -static const char* fontTbl[] = { +const char* fontTbl[156] = { gMsgChar20SpaceTex, gMsgChar21ExclamationMarkTex, gMsgChar22QuotationMarkTex, diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index 535b0c312..024c0fe12 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -1514,8 +1514,9 @@ void Play_DrawMain(PlayState* this) { } } - // Draw collision before the PostWorldDraw label so that collision is not drawn during pause - DrawCollisionViewer(); + // Draw Enhancements that need to be placed in the world. This happens before the PostWorldDraw + // so that they aren't drawn when the pause menu is up (e.g. collision viewer, actor name tags) + GameInteractor_ExecuteOnPlayDrawWorldEnd(); PostWorldDraw: if (1) { From 1475e6af7bb828b68aedbef71af2b1cc1e057279 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 19 Sep 2024 18:47:28 -0700 Subject: [PATCH 43/82] Fix 3ds clock fill texture position (#772) --- mm/2s2h/Enhancements/Graphics/3DSClock.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp index b28db14bc..a88551db7 100644 --- a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp @@ -112,7 +112,8 @@ void Register3DSClock() { HudEditor_SetActiveElement(HUD_EDITOR_ELEMENT_CLOCK); OVERLAY_DISP = Gfx_DrawTexRectIA8(OVERLAY_DISP, (TexturePtr)gThreeDayClock3DSFillTex, CLOCK_SECTION_WIDTH, 12, - posX - CLOCK_SECTION_WIDTH, posY, CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10); + posX - CLOCK_SECTION_HALFWIDTH - CLOCK_SECTION_WIDTH, posY, + CLOCK_SECTION_WIDTH, 12, 1 << 10, 1 << 10); fillalpha = 64; if (gSaveContext.save.day == 2) { From b1eea9ca76d82e16139c35eb8f64ed56d53030a5 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 26 Sep 2024 12:39:05 -0400 Subject: [PATCH 44/82] Use variadic arguments with GameInteractor_Should (#766) * PoC of using variadic arguments with GameInteractor_Should * va_list boilerplate in SHOULD macro * drop opt arg in favor of variadic arg changes * account for default type promotion * remove demo code --- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 2 +- mm/2s2h/Enhancements/Camera/FreeLook.cpp | 2 +- .../MiscInteractions/SkipTatlInterrupts.cpp | 4 +-- .../Fixes/FierceDeityZTargetMovement.cpp | 2 +- .../GameInteractor/GameInteractor.cpp | 28 +++++++++++++------ .../GameInteractor/GameInteractor.h | 13 +++++++-- mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp | 10 ++++--- .../Enhancements/Masks/PersistentMasks.cpp | 13 +++++---- mm/2s2h/Enhancements/Player/ClimbSpeed.cpp | 2 +- mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp | 2 +- mm/src/code/z_demo.c | 7 ++--- mm/src/code/z_parameter.c | 6 ++-- mm/src/code/z_shrink_window.c | 2 +- mm/src/code/z_sram_NES.c | 2 +- mm/src/code/z_view.c | 2 +- .../actors/ovl_En_Racedog/z_en_racedog.c | 2 +- .../actors/ovl_player_actor/z_player.c | 16 +++++------ 17 files changed, 68 insertions(+), 47 deletions(-) diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index c166576ce..38b9bf6db 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -232,7 +232,7 @@ void RegisterDebugCam() { if (CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0)) { freeCamVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, { - Camera* camera = static_cast(opt); + Camera* camera = va_arg(args, Camera*); Camera_DebugCam(camera); *should = false; }); diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.cpp b/mm/2s2h/Enhancements/Camera/FreeLook.cpp index 8a1533c4b..9ddbb5968 100644 --- a/mm/2s2h/Enhancements/Camera/FreeLook.cpp +++ b/mm/2s2h/Enhancements/Camera/FreeLook.cpp @@ -173,7 +173,7 @@ void RegisterCameraFreeLook() { if (CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0)) { freeLookCameraVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, { - Camera* camera = static_cast(opt); + Camera* camera = va_arg(args, Camera*); switch (sCameraSettings[camera->setting].cameraModes[camera->mode].funcId) { case CAM_FUNC_NORMAL0: case CAM_FUNC_NORMAL1: diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp index a56590c5e..8794d14e5 100644 --- a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp @@ -26,7 +26,7 @@ void RegisterSkipTatlInterrupts() { // General interupt REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG3, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { - Actor* actor = static_cast(opt); + Actor* actor = va_arg(args, Actor*); *should = false; if (ELFMSG3_GET_SWITCH_FLAG(actor) != 0x7F) { Flags_SetSwitch(gPlayState, ELFMSG3_GET_SWITCH_FLAG(actor)); @@ -38,7 +38,7 @@ void RegisterSkipTatlInterrupts() { // General interupt 2 (the flags were directly copied from the original code) REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG6, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { - Actor* actor = static_cast(opt); + Actor* actor = va_arg(args, Actor*); *should = false; switch (actor->textId) { case 0x224: diff --git a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp index 50c291912..816b6e7cc 100644 --- a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp +++ b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp @@ -8,7 +8,7 @@ extern "C" { void RegisterFierceDeityZTargetMovement() { REGISTER_VB_SHOULD(GI_VB_ZTARGET_SPEED_CHECK, { Player* player = GET_PLAYER(gPlayState); - float* speedArg = (float*)opt; + float* speedArg = va_arg(args, float*); // If the player is Fierce Deity and targeting, if (player->lockOnActor != NULL && player->transformation == PLAYER_FORM_FIERCE_DEITY && diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index 059e9db11..aea90a0a9 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -230,15 +230,25 @@ void GameInteractor_ExecuteOnItemGive(u8 item) { GameInteractor::Instance->ExecuteHooksForFilter(item); } -bool GameInteractor_Should(GIVanillaBehavior flag, bool result, void* opt) { - GameInteractor::Instance->ExecuteHooks(flag, &result, opt); - GameInteractor::Instance->ExecuteHooksForID(flag, flag, &result, opt); - if (opt != nullptr) { - GameInteractor::Instance->ExecuteHooksForPtr((uintptr_t)opt, flag, - &result, opt); - } - GameInteractor::Instance->ExecuteHooksForFilter(flag, &result, opt); - return result; +bool GameInteractor_Should(GIVanillaBehavior flag, uint32_t result, ...) { + // Only the external function can use the Variadic Function syntax + // To pass the va args to the next caller must be done using va_list and reading the args into it + // Because there can be N subscribers registered to each template call, the subscribers will be responsible for + // creating a copy of this va_list to avoid incrementing the original pointer between calls + va_list args; + va_start(args, result); + + // Because of default argument promotion, even though our incoming "result" is just a bool, it needs to be typed as + // an int to be permitted to be used in `va_start`, otherwise it is undefined behavior. + // Here we downcast back to a bool for our actual hook handlers + bool boolResult = static_cast(result); + + GameInteractor::Instance->ExecuteHooks(flag, &boolResult, args); + GameInteractor::Instance->ExecuteHooksForID(flag, flag, &boolResult, args); + GameInteractor::Instance->ExecuteHooksForFilter(flag, &boolResult, args); + + va_end(args); + return boolResult; } // Returns 1 or -1 based on a number of factors like CVars or other game states. diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 8caf4fb5c..e884782b0 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -1,6 +1,8 @@ #ifndef GAME_INTERACTOR_H #define GAME_INTERACTOR_H +#include + #ifdef __cplusplus #include extern "C" { @@ -303,7 +305,7 @@ class GameInteractor { DEFINE_HOOK(ShouldItemGive, (u8 item, bool* should)); DEFINE_HOOK(OnItemGive, (u8 item)); - DEFINE_HOOK(ShouldVanillaBehavior, (GIVanillaBehavior flag, bool* should, void* optionalArg)); + DEFINE_HOOK(ShouldVanillaBehavior, (GIVanillaBehavior flag, bool* should, va_list originalArgs)); }; extern "C" { @@ -353,10 +355,15 @@ void GameInteractor_ExecuteOnOpenText(u16 textId); bool GameInteractor_ShouldItemGive(u8 item); void GameInteractor_ExecuteOnItemGive(u8 item); -bool GameInteractor_Should(GIVanillaBehavior flag, bool result, void* optionalArg); +bool GameInteractor_Should(GIVanillaBehavior flag, uint32_t result, ...); #define REGISTER_VB_SHOULD(flag, body) \ GameInteractor::Instance->RegisterGameHookForID( \ - flag, [](GIVanillaBehavior _, bool* should, void* opt) body) + flag, [](GIVanillaBehavior _, bool* should, va_list originalArgs) { \ + va_list args; \ + va_copy(args, originalArgs); \ + body; \ + va_end(args); \ + }) int GameInteractor_InvertControl(GIInvertType type); uint32_t GameInteractor_Dpad(GIDpadType type, uint32_t buttonCombo); diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp index f64312c63..0e52ca467 100644 --- a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp @@ -114,9 +114,9 @@ void EnItem00_3DItemsDraw(Actor* actor, PlayState* play) { } } -void DrawSlime3DItem(GIVanillaBehavior _, bool* should, void* opt) { +void DrawSlime3DItem(Actor* actor, bool* should) { *should = false; - EnSlime* slime = static_cast(opt); + EnSlime* slime = (EnSlime*)actor; // Rotate 3D item with chu body Matrix_RotateYS(slime->actor.shape.rot.y, MTXMODE_APPLY); @@ -180,6 +180,8 @@ void Register3DItemDrops() { actor->shape.rot.y += 0x3C0; } }); - slimeVBHookID = GameInteractor::Instance->RegisterGameHookForID( - GI_VB_DRAW_SLIME_BODY_ITEM, DrawSlime3DItem); + slimeVBHookID = REGISTER_VB_SHOULD(GI_VB_DRAW_SLIME_BODY_ITEM, { + Actor* actor = va_arg(args, Actor*); + DrawSlime3DItem(actor, should); + }); } diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp index 92177f9be..281a6bec4 100644 --- a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp +++ b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp @@ -145,15 +145,16 @@ void RegisterPersistentMasks() { // Overrides allowing them to equip a mask while transformed REGISTER_VB_SHOULD(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, { + PlayerItemAction* itemAction = va_arg(args, PlayerItemAction*); if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && - *(PlayerItemAction*)opt == PLAYER_IA_MASK_BUNNY) { + *itemAction == PLAYER_IA_MASK_BUNNY) { *should = true; } }); // When they do equip the mask, prevent it and instead set our state REGISTER_VB_SHOULD(GI_VB_USE_ITEM_EQUIP_MASK, { - PlayerMask* maskId = (PlayerMask*)opt; + PlayerMask* maskId = va_arg(args, PlayerMask*); Player* player = GET_PLAYER(gPlayState); if (*maskId == PLAYER_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { @@ -172,21 +173,23 @@ void RegisterPersistentMasks() { // Prevent the "equipped" white border from being drawn so ours shows instead (ours was drawn before it, so it's // underneath) REGISTER_VB_SHOULD(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, { - if (*(ItemId*)opt == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { + ItemId* itemId = va_arg(args, ItemId*); + if (*itemId == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { *should = false; } }); // Typically when you are in a transformation all masks are dimmed on the C-Buttons REGISTER_VB_SHOULD(GI_VB_ITEM_BE_RESTRICTED, { - if (*(ItemId*)opt == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { + ItemId* itemId = va_arg(args, ItemId*); + if (*itemId == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { *should = false; } }); // Override "A" press behavior on kaleido scope to toggle the mask state REGISTER_VB_SHOULD(GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, { - ItemId* itemId = (ItemId*)opt; + ItemId* itemId = va_arg(args, ItemId*); if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && *itemId == ITEM_MASK_BUNNY) { *should = false; CVarSetInteger("gEnhancements.Masks.PersistentBunnyHood.State", diff --git a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp index 1a6c624d1..c1c4102f9 100644 --- a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp +++ b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp @@ -4,7 +4,7 @@ void RegisterClimbSpeed() { REGISTER_VB_SHOULD(GI_VB_SET_CLIMB_SPEED, { if (CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1) > 1) { - f32* speed = static_cast(opt); + f32* speed = va_arg(args, f32*); *speed *= CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1); } }); diff --git a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp index e3dcfe00c..92a60751b 100644 --- a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp +++ b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp @@ -7,7 +7,7 @@ extern "C" { void RegisterEnableSunsSong() { REGISTER_VB_SHOULD(GI_VB_SONG_AVAILABLE_TO_PLAY, { - uint8_t* songIndex = static_cast(opt); + uint8_t* songIndex = va_arg(args, uint8_t*); // If the enhancement is on, and the currently played song is Sun's Song, set it to be available to be played. if (CVarGetInteger("gEnhancements.Songs.EnableSunsSong", 0) && *songIndex == OCARINA_SONG_SUNS) { *should = true; diff --git a/mm/src/code/z_demo.c b/mm/src/code/z_demo.c index 700b26a72..5fd5c8ed1 100644 --- a/mm/src/code/z_demo.c +++ b/mm/src/code/z_demo.c @@ -1545,7 +1545,7 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { } else if (!CHECK_CS_SPAWN_FLAG_WEEKEVENTREG(play->csCtx.scriptList[scriptIndex].spawnFlags)) { // Entrance cutscenes that only run once SET_CS_SPAWN_FLAG_WEEKEVENTREG(play->csCtx.scriptList[scriptIndex].spawnFlags); - if (GameInteractor_Should(GI_VB_PLAY_ENTRANCE_CS, true, NULL)) { + if (GameInteractor_Should(GI_VB_PLAY_ENTRANCE_CS, true)) { CutsceneManager_Start(csId, NULL); } // The title card will be used by the cs misc command if necessary. @@ -1561,8 +1561,7 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { if ((gSaveContext.respawnFlag == 0) || (gSaveContext.respawnFlag == -2)) { scene = play->loadedScene; - if ((scene->titleTextId != 0) && - GameInteractor_Should(GI_VB_SHOW_TITLE_CARD, gSaveContext.showTitleCard, NULL)) { + if ((scene->titleTextId != 0) && GameInteractor_Should(GI_VB_SHOW_TITLE_CARD, gSaveContext.showTitleCard)) { if ((Entrance_GetTransitionFlags(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer)) & 0x4000) != 0) { @@ -1581,7 +1580,7 @@ void func_800EDDB0(PlayState* play) { LUSLOG_INFO("Cutscene_HandleConditionalTriggers: entrance: %d, cutsceneIndex: 0x%X", gSaveContext.save.entrance, gSaveContext.save.cutsceneIndex); - if (!GameInteractor_Should(GI_VB_PLAY_TRANSITION_CS, true, NULL)) { + if (!GameInteractor_Should(GI_VB_PLAY_TRANSITION_CS, true)) { return; } } diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index 464d0e2ed..bf3faab58 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -2823,7 +2823,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && (play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) && (play->sceneId != SCENE_LAST_BS); - if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult, NULL)) { + if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { if (gSaveContext.buttonStatus[i] != BTN_DISABLED) { gSaveContext.buttonStatus[i] = BTN_DISABLED; restoreHudVisibility = true; @@ -2970,7 +2970,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && (play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) && (play->sceneId != SCENE_LAST_BS); - if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult, NULL)) { + if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { if (gSaveContext.shipSaveContext.dpad.status[j] != BTN_DISABLED) { gSaveContext.shipSaveContext.dpad.status[j] = BTN_DISABLED; restoreHudVisibility = true; @@ -6151,7 +6151,7 @@ void Interface_DrawClock(PlayState* play) { s16 finalHoursClockSlots[8]; s16 index; - if (GameInteractor_Should(GI_VB_PREVENT_CLOCK_DISPLAY, false, NULL)) { + if (GameInteractor_Should(GI_VB_PREVENT_CLOCK_DISPLAY, false)) { return; } diff --git a/mm/src/code/z_shrink_window.c b/mm/src/code/z_shrink_window.c index bca613366..df48b893d 100644 --- a/mm/src/code/z_shrink_window.c +++ b/mm/src/code/z_shrink_window.c @@ -80,7 +80,7 @@ void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { s8 letterboxSize = sShrinkWindowPtr->letterboxSize; s8 pillarboxSize = sShrinkWindowPtr->pillarboxSize; - if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false, NULL)) { + if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false)) { return; } diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index 77977d9cb..09c2a19c7 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -1373,7 +1373,7 @@ void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { fileNum = gSaveContext.fileNum; // Remove Owl saves on save continue - if (GameInteractor_Should(GI_VB_DELETE_OWL_SAVE, true, 0)) { + if (GameInteractor_Should(GI_VB_DELETE_OWL_SAVE, true)) { func_80147314(sramCtx, fileNum); } } diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 1e01a9cbc..8fedc585f 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -160,7 +160,7 @@ void View_ApplyLetterbox(View* view) { s32 lrx; s32 lry; - if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false, NULL)) { + if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false)) { return; } diff --git a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c index d49470f13..30649608d 100644 --- a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c +++ b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c @@ -519,7 +519,7 @@ void EnRacedog_UpdateSpeed(EnRacedog* this) { // Cap the speed of the dog, or always max it out with the 'Always Win Doggy Race' enhancement. bool vanillaCondition = this->actor.speed > 7.5f; - if (GameInteractor_Should(GI_VB_DOGGY_RACE_SET_MAX_SPEED, vanillaCondition, NULL)) { + if (GameInteractor_Should(GI_VB_DOGGY_RACE_SET_MAX_SPEED, vanillaCondition)) { this->actor.speed = 7.5f; } } else { diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 36df61bc9..c728cd4fe 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -3814,7 +3814,7 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { if (bomb != NULL) { bomb->timer = 0; - if (GameInteractor_Should(GI_VB_SET_BLAST_MASK_COOLDOWN_TIMER, true, NULL)) { + if (GameInteractor_Should(GI_VB_SET_BLAST_MASK_COOLDOWN_TIMER, true)) { this->blastMaskTimer = 310; } } @@ -6720,7 +6720,7 @@ void func_80836AD8(PlayState* play, Player* this) { } void func_80836B3C(PlayState* play, Player* this, f32 arg2) { - if (GameInteractor_Should(GI_VB_PATCH_SIDEROLL, true, NULL)) { + if (GameInteractor_Should(GI_VB_PATCH_SIDEROLL, true)) { this->currentYaw = this->actor.shape.rot.y; this->actor.world.rot.y = this->actor.shape.rot.y; } @@ -7814,7 +7814,7 @@ s32 Player_ActionChange_4(Player* this, PlayState* play) { // !CutsceneManager_IsNext(CS_ID_GLOBAL_TALK), which is what prevented Tatl ISG from // working bool vanillaCondition = !CutsceneManager_IsNext(CS_ID_GLOBAL_TALK); - if (GameInteractor_Should(GI_VB_TATL_CONVERSATION_AVAILABLE, vanillaCondition, NULL) || + if (GameInteractor_Should(GI_VB_TATL_CONVERSATION_AVAILABLE, vanillaCondition) || !CHECK_BTN_ALL(sPlayerControlInput->press.button, BTN_CUP)) { return false; } @@ -10098,7 +10098,7 @@ s32 func_8083FD80(Player* this, PlayState* play) { if (!Player_IsGoronOrDeku(this) && (Player_GetMeleeWeaponHeld(this) != PLAYER_MELEEWEAPON_NONE) && (this->transformation != PLAYER_FORM_ZORA) && sPlayerUseHeldItem) { //! Calling this function sets the meleeWeaponQuads' damage properties correctly, patching "Power Crouch Stab". - if (GameInteractor_Should(GI_VB_PATCH_POWER_CROUCH_STAB, true, NULL)) { + if (GameInteractor_Should(GI_VB_PATCH_POWER_CROUCH_STAB, true)) { func_8083375C(this, PLAYER_MWA_STAB_1H); } Player_AnimationPlayOnce(play, this, &gPlayerAnim_link_normal_defense_kiru); @@ -10145,7 +10145,7 @@ s32 func_8083FF30(PlayState* play, Player* this) { s32 func_8083FFEC(PlayState* play, Player* this) { if (this->heldItemAction == PLAYER_IA_SWORD_RAZOR) { if (gSaveContext.save.saveInfo.playerData.swordHealth > 0) { - if (GameInteractor_Should(GI_VB_LOWER_RAZOR_SWORD_DURABILITY, true, NULL)) { + if (GameInteractor_Should(GI_VB_LOWER_RAZOR_SWORD_DURABILITY, true)) { gSaveContext.save.saveInfo.playerData.swordHealth--; } if (gSaveContext.save.saveInfo.playerData.swordHealth <= 0) { @@ -11255,7 +11255,7 @@ void Player_SetDoAction(PlayState* play, Player* this) { } if (doActionA != DO_ACTION_PUTAWAY) { - if (GameInteractor_Should(GI_VB_RESET_PUTAWAY_TIMER, true, NULL)) { + if (GameInteractor_Should(GI_VB_RESET_PUTAWAY_TIMER, true)) { this->putAwayCountdown = 20; } } else if (this->putAwayCountdown != 0) { @@ -14894,7 +14894,7 @@ void Player_Action_25(Player* this, PlayState* play) { Math_StepToF(&this->unk_B10[1], 0.0f, this->unk_B10[0]); } } else { - if (GameInteractor_Should(GI_VB_FLIP_HOP_VARIABLE, true, NULL)) { + if (GameInteractor_Should(GI_VB_FLIP_HOP_VARIABLE, true)) { func_8083CBC4(this, speedTarget, yawTarget, 1.0f, 0.05f, 0.1f, 0xC8); } } @@ -18283,7 +18283,7 @@ void Player_Action_86(Player* this, PlayState* play) { struct_8085D910* sp4C = D_8085D910; s32 sp48 = false; - if (GameInteractor_Should(GI_VB_PREVENT_MASK_TRANSFORMATION_CS, false, NULL)) + if (GameInteractor_Should(GI_VB_PREVENT_MASK_TRANSFORMATION_CS, false)) return; func_808323C0(this, play->playerCsIds[PLAYER_CS_ID_MASK_TRANSFORMATION]); From f33f994adc743d16c1246691f6a619df80599af1 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Tue, 1 Oct 2024 11:15:16 -0500 Subject: [PATCH 45/82] Update pr-artifacts for node20 (#784) --- .github/workflows/pr-artifacts.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-artifacts.yml b/.github/workflows/pr-artifacts.yml index 52ec62826..2d41a47c5 100644 --- a/.github/workflows/pr-artifacts.yml +++ b/.github/workflows/pr-artifacts.yml @@ -12,7 +12,7 @@ jobs: if: ${{ github.event.workflow_run.event == 'pull_request' }} steps: - id: 'pr-number' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: result-encoding: string script: | @@ -36,7 +36,7 @@ jobs: return prNumber; - id: 'artifacts-text' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: result-encoding: string script: | @@ -54,7 +54,7 @@ jobs: return acc; }, '### Build Artifacts'); - id: 'add-to-pr' - uses: garrettjoecox/pr-section@3.1.0 + uses: garrettjoecox/pr-section@4.0.0 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' pr-number: ${{ steps.pr-number.outputs.result }} From 200aaf7be8b0165ea40191776b8e843d4940be8d Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 1 Oct 2024 12:15:30 -0400 Subject: [PATCH 46/82] bump lus (#782) --- libultraship | 2 +- mm/2s2h/BenPort.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libultraship b/libultraship index 7a88bfc08..4160fa0aa 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 7a88bfc08cbe44fd682b8f6f66b9d32d44b699bc +Subproject commit 4160fa0aa07d3946cbed5e397c54e6260f67dc5a diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 10a567c68..57dd9fb65 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -147,7 +147,9 @@ OTRGlobals::OTRGlobals() { OOT_PAL_GC, OOT_PAL_GC_DBG1, OOT_PAL_GC_DBG2 }; // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) context = - Ship::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json", archiveFiles, {}, 3); + Ship::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json", archiveFiles, {}, 3, + { .SampleRate = 44100, .SampleLength = 1024, .DesiredBuffered = 2480 }); + prevAltAssets = CVarGetInteger("gAltAssets", 0); context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets); From 75bc685360debc9ce4d4b8473b5a330d15909cd0 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 1 Oct 2024 15:32:03 -0400 Subject: [PATCH 47/82] Fix pr-artifacts fetch script after version update (#786) --- .github/workflows/pr-artifacts.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-artifacts.yml b/.github/workflows/pr-artifacts.yml index 2d41a47c5..32cf6fb07 100644 --- a/.github/workflows/pr-artifacts.yml +++ b/.github/workflows/pr-artifacts.yml @@ -20,8 +20,9 @@ jobs: const pullHeadSHA = '${{github.event.workflow_run.head_sha}}'; const pullUserId = ${{github.event.sender.id}}; const prNumber = await (async () => { - const pulls = await github.rest.pulls.list({owner, repo}); - for await (const {data} of github.paginate.iterator(pulls)) { + for await (const { data } of github.paginate.iterator( + github.rest.pulls.list, { owner, repo } + )) { for (const pull of data) { if (pull.head.sha === pullHeadSHA && pull.user.id === pullUserId) { return pull.number; From 71c2c94ece12c664fe54f9959cce40776ba36dcd Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 2 Oct 2024 17:25:26 -0700 Subject: [PATCH 48/82] Modern menu (#701) * Start the framework. * Start header bar. * Header buttons now toggle. Sections show accordingly. Basic audio section done. Needs subdividing for sane widget widths. * Add fonts and multiple sizes. Add graphics settings to menu. * Finalized fonts, more sizes. * Modularized the menu structure. Has an errant EndChild somewhere. * Finished first step modularization. Parameterized menu height. * Some adaptive menu size. * Moved all enhancements over and organized. Tried to add button option for sidebar entries. * Finished Enhancements Menu. Sidebar window button still broken (can't reference window variables properly, not drawing in the right place). * Developer Tools header started. Menu now pops out with a checkbox in Developer Tools. Menu sizing works for smaller game sizes. Popout docking disabled. Port bool added for disallowing popout regardless of cvar. * Better auto-sizing. Columns collapse to 1 below 800 window width, and scroll. * Move inside of HudEditorWindow::DrawElement to DrawContents, and call DrawContents from DrawElement. * Menu resizability complete. Menu popout complete. Menu popout position/size is retained when popped in. Apply HUD editor changes, draw contents in menu if window is closed. All child sizes properly calculated. SidebarEntry drawing separated into its own custom element. * Split header entries into separate widget. Header now dynamically sized and shows scrollbar when necessary. * Modify EventLog to be drawable with the DrawContents setup. Prevent menu from covering other windows (always in back). * Add reset, close menu, and quit buttons to the header. * Fix reset and quit button placement. * Swap Actor Viewer, Collision Viewer, Save Editor to DrawContents concept. Change reset icon to FA_ICON_UNDO (single arrow) and quit icon to FA_ICON_POWER_OFF. Add button to close menu button tooltip, add parentheses to button for reset tooltip. * Custom InputEditorWindow to work with menu. Fix LUS references in Menu.cpp for Window backend changes. Implement gamepad navigation and forced cursor visibility checkboxes. Toggle cursor visibility according to menu status and forced visibility CVar. * clang-format * Swap std for fmt (runner build error). Ensure cursor visibility is restored if started in full screen with the menu open. * Oops, still had #include * Swap to LUS GetMenu() functionality. Add option to hide "F1 to open enhancements menu" text at startup if menus aren't open. * Remove last vestiges of pre-LUS-menu functionality. * cleanup * Adapt to GuiElement, GuiWindow changes on the menu support PR. * LUS PR bump. Adapt to cursor visibility changes in LUS. Adapt to menu toggle changes in LUS. Fix input editor not hiding in menu when popped out. * Add new enhancements and cheats to Modern Menu from rebase. * clang * Apply Graphics Menu Lag Fix to Menu structure. * Remove unnecessary window children to simplify controller navigation. * clang * Add `UpdateWindowBackendObjects()` call to backend combobox. * Rebase to latest develop. Remove redundant window backend stuff that exists now in BenMenuBar. * Search Enhancement (#2) * 90% complete, Commit for review. * Updated remaining Menu Entries, Reverted Backends and other Window Buttons for now. Motion Blur copied to Search Menu. * Did I mention I dislike this clang thing? lol * Updating MotionBlur options and reverting soem things. * Integrates .disabled and .disabledTooltip to the constructors. Allows for multiple qualifications to be checked against for disabling widgets and for setting the tooltip accordingly. * Updated Disabled Reasoning * Better Disabled State registration system * Clean up from testing * Expand WidgetOptions to be able to handle string and float values. bool and uint32_t are handled through int32_t. Numerous renames. Added several data structures to allow for dynamic updating of CVars for DisableOptions, as well as dynamic evaluation of status with enumerated conditions (less than, greater than, equal to). Added menuThemeIndex variable to store state of menu theme selection instead of having all the individual calls to CVarGetInteger for it. Updated once per frame. * Changed color vector to map with enum as key and UIWidget::Colors as the value. More renames. Moved float slider values into case block. * Add Color_RGB8 and Color_RGBA8 to CVarVariant in preparation for adding color widgets to menu item system. Not happy it required comparison operator overrides, but it is what it is. * Changed disable conditions to lambdas. * Convert Stats and Collision Viewer to menu item system. Swap out DisableOption vector for activeDisables and a lambda function for evaluating disabled and hidden. Set the precedent to still use the DisableInfo system. * Add DisableOption for both camera settings being off. Put Debug Camera in Free Look column, disable common widgets for both cameras, hide widgets specific to either if off. * Moved more widgets to MenuItem system. Some need proper initialization routines because of Ship::Context references. * Convert menu items to nested vector setup. Remove MenuItem enum. Add menu item location display to search results. * Partial removal of SidebarEntryIndex enum. * Finish removing SidebarEntryIndex. Rework drawing code to handle the change back to direct vector access. Add tooltips to search. * Fix Graphics enhancements section title. * Copy added menu items to modern menu system. * clang * Add some documentation for the menu system components. * Revert change to std::map * `size_t` because GCC has to be happy * Fixed HUD Editor Widescreen mode not displaying the sliders properly. Changed all windows to full-section-width display. * Revert changes to MotionBlur.cpp * Add non-CVar variants of checkbox, combobox, and the sliders. Fix motion blur functionality with new non-CVar widgets. * Add non-CVar variants of checkbox, combobox, and the sliders. Fix motion blur functionality with those non-CVar widgets. Add size and labelPosition to widgetOptions, implemented on button and checkbox/combobox/sliders. Change window popout buttons to inline size type. * Rename SearchMenu.h to SearchableMenuItems.h and move to BenGui folder. * Forgot to change the include XD * Change `modifierFunc` to `preFunc`, updated documentation for that and including `postFunc`. * Modify code to require variable for non-CVar widget initialization when necessary. Check for `valuePointer` being nullptr, and preventing widget drawing with a debug assert and error log entry. Remove all `has_variant` calls and wrap entire widget type switch in `SearchMenuGetItem` with a try/catch on `std::bad_variant_access` with another error log and debug assert. * More review changes. * Implement `isPercentage`, `format`, and `showButtons` for sliders. Pull values of those over from menubar. Add documentation on `widgetOptions` for those and others added for previous review changes. Move Fast Magic Arrow and Instant Fin Recall to Gameplay section. * Modify header and sidebar "buttons" to match theming of regular buttons. * Add precision clamping to SliderFloat value. At least 1.0 seems to be consistent at "100%". Change IR slider to be percentage. * Mention weirdness with SDL and pad menu button in controller nav tooltip. * Move Menu files to 2s2h/BenGui. * Add Warp Points to Developer Tools. Make "Press F1" prompt show only when a menu isn't registered. * clang * Make search input take focus when search menu is open. * Forgot include. * Global search (#3) * Restore Sidebar search entry, but lock it behind a checkbox in Settings. Dynamically adds or removes the sidebar entry, and header search is toggled inversely. * Make menu toggle its visibility when using the button in the menu to close. Couldn't handle Alt+F4 without a hook I didn't want to add. Remove unneeded commented code. --------- Co-authored-by: Caladius Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenGui.cpp | 31 +- mm/2s2h/BenGui/BenGui.hpp | 2 + mm/2s2h/BenGui/BenInputEditorWindow.cpp | 1671 ++++++++++++++++ mm/2s2h/BenGui/BenInputEditorWindow.h | 90 + mm/2s2h/BenGui/BenMenuBar.cpp | 6 +- mm/2s2h/BenGui/BenMenuBar.h | 1 + mm/2s2h/BenGui/HudEditor.cpp | 12 +- mm/2s2h/BenGui/Menu.cpp | 471 +++++ mm/2s2h/BenGui/Menu.h | 31 + mm/2s2h/BenGui/SearchableMenuItems.h | 1705 +++++++++++++++++ mm/2s2h/BenGui/UIWidgets.cpp | 48 +- mm/2s2h/BenGui/UIWidgets.hpp | 3 + mm/2s2h/BenPort.cpp | 46 +- mm/2s2h/BenPort.h | 8 + mm/2s2h/DeveloperTools/ActorViewer.cpp | 7 - mm/2s2h/DeveloperTools/CollisionViewer.cpp | 8 - mm/2s2h/DeveloperTools/DeveloperTools.h | 2 + mm/2s2h/DeveloperTools/EventLog.cpp | 8 - mm/2s2h/DeveloperTools/SaveEditor.cpp | 8 - mm/2s2h/DeveloperTools/WarpPoint.cpp | 53 +- .../custom/fonts/Inconsolata-Regular.ttf | Bin 0 -> 101752 bytes mm/assets/custom/fonts/Montserrat-Regular.ttf | Bin 0 -> 197624 bytes 22 files changed, 4123 insertions(+), 88 deletions(-) create mode 100644 mm/2s2h/BenGui/BenInputEditorWindow.cpp create mode 100644 mm/2s2h/BenGui/BenInputEditorWindow.h create mode 100644 mm/2s2h/BenGui/Menu.cpp create mode 100644 mm/2s2h/BenGui/Menu.h create mode 100644 mm/2s2h/BenGui/SearchableMenuItems.h create mode 100644 mm/assets/custom/fonts/Inconsolata-Regular.ttf create mode 100644 mm/assets/custom/fonts/Montserrat-Regular.ttf diff --git a/mm/2s2h/BenGui/BenGui.cpp b/mm/2s2h/BenGui/BenGui.cpp index b41e537e0..dfc57bf34 100644 --- a/mm/2s2h/BenGui/BenGui.cpp +++ b/mm/2s2h/BenGui/BenGui.cpp @@ -27,7 +27,6 @@ std::shared_ptr mBenMenuBar; std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; -std::shared_ptr mInputEditorWindow; std::shared_ptr mGfxDebuggerWindow; std::shared_ptr mSaveEditorWindow; @@ -35,6 +34,8 @@ std::shared_ptr mHudEditorWindow; std::shared_ptr mActorViewerWindow; std::shared_ptr mCollisionViewerWindow; std::shared_ptr mEventLogWindow; +std::shared_ptr mBenMenu; +std::shared_ptr mBenInputEditorWindow; void SetupGuiElements() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); @@ -47,7 +48,7 @@ void SetupGuiElements() { mBenMenuBar = std::make_shared(CVAR_MENU_BAR_OPEN, CVarGetInteger(CVAR_MENU_BAR_OPEN, 0)); gui->SetMenuBar(std::reinterpret_pointer_cast(mBenMenuBar)); - if (gui->GetMenuBar() && !gui->GetMenuBar()->IsVisible()) { + if (!gui->GetMenuBar() && !CVarGetInteger("gSettings.DisableMenuShortcutNotify", 0)) { #if defined(__SWITCH__) || defined(__WIIU__) gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press - to access enhancements menu"); #else @@ -55,6 +56,9 @@ void SetupGuiElements() { #endif } + mBenMenu = std::make_shared("gWindows.Menu", "Settings Menu"); + gui->SetMenu(mBenMenu); + mStatsWindow = gui->GetGuiWindow("Stats"); if (mStatsWindow == nullptr) { SPDLOG_ERROR("Could not find stats window"); @@ -65,37 +69,38 @@ void SetupGuiElements() { SPDLOG_ERROR("Could not find console window"); } - mInputEditorWindow = gui->GetGuiWindow("Input Editor"); - if (mInputEditorWindow == nullptr) { - SPDLOG_ERROR("Could not find input editor window"); - } - mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow"); if (mGfxDebuggerWindow == nullptr) { SPDLOG_ERROR("Could not find input GfxDebuggerWindow"); } - mSaveEditorWindow = std::make_shared("gWindows.SaveEditor", "Save Editor"); + mBenInputEditorWindow = std::make_shared("gWindows.BenInputEditor", "2S2H Input Editor"); + gui->AddGuiWindow(mBenInputEditorWindow); + + mSaveEditorWindow = std::make_shared("gWindows.SaveEditor", "Save Editor", ImVec2(480, 600)); gui->AddGuiWindow(mSaveEditorWindow); - mHudEditorWindow = std::make_shared("gWindows.HudEditor", "Hud Editor"); + mHudEditorWindow = std::make_shared("gWindows.HudEditor", "HUD Editor", ImVec2(480, 600)); gui->AddGuiWindow(mHudEditorWindow); - mActorViewerWindow = std::make_shared("gWindows.ActorViewer", "Actor Viewer"); + mActorViewerWindow = std::make_shared("gWindows.ActorViewer", "Actor Viewer", ImVec2(520, 600)); gui->AddGuiWindow(mActorViewerWindow); - mCollisionViewerWindow = std::make_shared("gWindows.CollisionViewer", "Collision Viewer"); + mCollisionViewerWindow = + std::make_shared("gWindows.CollisionViewer", "Collision Viewer", ImVec2(390, 475)); gui->AddGuiWindow(mCollisionViewerWindow); - mEventLogWindow = std::make_shared("gWindows.EventLog", "Event Log"); + mEventLogWindow = std::make_shared("gWindows.EventLog", "Event Log", ImVec2(520, 600)); gui->AddGuiWindow(mEventLogWindow); + gui->SetPadBtnTogglesMenu(); } void Destroy() { mBenMenuBar = nullptr; + mBenMenu = nullptr; mStatsWindow = nullptr; mConsoleWindow = nullptr; - mInputEditorWindow = nullptr; + mBenInputEditorWindow = nullptr; mGfxDebuggerWindow = nullptr; mCollisionViewerWindow = nullptr; mEventLogWindow = nullptr; diff --git a/mm/2s2h/BenGui/BenGui.hpp b/mm/2s2h/BenGui/BenGui.hpp index e5017c217..b292b9c3d 100644 --- a/mm/2s2h/BenGui/BenGui.hpp +++ b/mm/2s2h/BenGui/BenGui.hpp @@ -7,6 +7,8 @@ #include "DeveloperTools/ActorViewer.h" #include "DeveloperTools/CollisionViewer.h" #include "DeveloperTools/EventLog.h" +#include "BenInputEditorWindow.h" +#include "Menu.h" namespace BenGui { void SetupHooks(); diff --git a/mm/2s2h/BenGui/BenInputEditorWindow.cpp b/mm/2s2h/BenGui/BenInputEditorWindow.cpp new file mode 100644 index 000000000..8e3b4334e --- /dev/null +++ b/mm/2s2h/BenGui/BenInputEditorWindow.cpp @@ -0,0 +1,1671 @@ +#include "BenInputEditorWindow.h" +#include "Context.h" +#include "Gui.h" +#include "utils/StringHelper.h" +#include "public/bridge/consolevariablebridge.h" +#include "controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToButtonMapping.h" + +#define SCALE_IMGUI_SIZE(value) ((value / 13.0f) * ImGui::GetFontSize()) + +BenInputEditorWindow::~BenInputEditorWindow() { + SPDLOG_TRACE("destruct input editor window"); +} + +void BenInputEditorWindow::InitElement() { + mGameInputBlockTimer = INT32_MAX; + mMappingInputBlockTimer = INT32_MAX; + mRumbleTimer = INT32_MAX; + mRumbleMappingToTest = nullptr; + mInputEditorPopupOpen = false; + + mButtonsBitmasks = { BTN_A, BTN_B, BTN_START, BTN_L, BTN_R, BTN_Z, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT }; + mDpadBitmasks = { BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT }; + + mDeviceIndexVisiblity.clear(); + mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard] = true; + mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Blue] = true; + for (auto index = 1; index < Ship::ShipDeviceIndex::Max; index++) { + mDeviceIndexVisiblity[static_cast(index)] = false; + } +} + +#define INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID 95237929 +void BenInputEditorWindow::UpdateElement() { + if (mRumbleTimer != INT32_MAX) { + mRumbleTimer--; + if (mRumbleMappingToTest != nullptr) { + mRumbleMappingToTest->StartRumble(); + } + if (mRumbleTimer <= 0) { + if (mRumbleMappingToTest != nullptr) { + mRumbleMappingToTest->StopRumble(); + } + mRumbleTimer = INT32_MAX; + mRumbleMappingToTest = nullptr; + } + } + + if (mInputEditorPopupOpen && ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId)) { + Ship::Context::GetInstance()->GetControlDeck()->BlockGameInput(INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID); + + // continue to block input for a third of a second after getting the mapping + mGameInputBlockTimer = ImGui::GetIO().Framerate / 3; + + if (mMappingInputBlockTimer != INT32_MAX) { + mMappingInputBlockTimer--; + if (mMappingInputBlockTimer <= 0) { + mMappingInputBlockTimer = INT32_MAX; + } + } + + Ship::Context::GetInstance()->GetWindow()->GetGui()->BlockImGuiGamepadNavigation(); + } else { + if (mGameInputBlockTimer != INT32_MAX) { + mGameInputBlockTimer--; + if (mGameInputBlockTimer <= 0) { + Ship::Context::GetInstance()->GetControlDeck()->UnblockGameInput( + INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID); + mGameInputBlockTimer = INT32_MAX; + } + } + + if (Ship::Context::GetInstance()->GetWindow()->GetGui()->ImGuiGamepadNavigationEnabled()) { + mMappingInputBlockTimer = ImGui::GetIO().Framerate / 3; + } else { + mMappingInputBlockTimer = INT32_MAX; + } + + Ship::Context::GetInstance()->GetWindow()->GetGui()->UnblockImGuiGamepadNavigation(); + } +} + +void BenInputEditorWindow::DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone, bool gyro) { + ImGui::BeginChild(label, ImVec2(gyro ? SCALE_IMGUI_SIZE(78) : SCALE_IMGUI_SIZE(96), SCALE_IMGUI_SIZE(85)), false); + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + gyro ? SCALE_IMGUI_SIZE(10) : SCALE_IMGUI_SIZE(18), + ImGui::GetCursorPos().y + gyro ? SCALE_IMGUI_SIZE(10) : 0)); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + + const ImVec2 cursorScreenPosition = ImGui::GetCursorScreenPos(); + + // Draw the border box + float borderSquareLeft = cursorScreenPosition.x + SCALE_IMGUI_SIZE(2.0f); + float borderSquareTop = cursorScreenPosition.y + SCALE_IMGUI_SIZE(2.0f); + float borderSquareSize = SCALE_IMGUI_SIZE(65.0f); + drawList->AddRect(ImVec2(borderSquareLeft, borderSquareTop), + ImVec2(borderSquareLeft + borderSquareSize, borderSquareTop + borderSquareSize), + ImColor(100, 100, 100, 255), 0.0f, 0, 1.5f); + + // Draw the gate background + float cardinalRadius = SCALE_IMGUI_SIZE(22.5f); + float diagonalRadius = SCALE_IMGUI_SIZE(22.5f * (69.0f / 85.0f)); + + ImVec2 joystickCenterpoint = ImVec2(cursorScreenPosition.x + cardinalRadius + SCALE_IMGUI_SIZE(12), + cursorScreenPosition.y + cardinalRadius + SCALE_IMGUI_SIZE(11)); + drawList->AddQuadFilled(joystickCenterpoint, + ImVec2(joystickCenterpoint.x - diagonalRadius, joystickCenterpoint.y + diagonalRadius), + ImVec2(joystickCenterpoint.x, joystickCenterpoint.y + cardinalRadius), + ImVec2(joystickCenterpoint.x + diagonalRadius, joystickCenterpoint.y + diagonalRadius), + ImColor(130, 130, 130, 255)); + drawList->AddQuadFilled(joystickCenterpoint, + ImVec2(joystickCenterpoint.x + diagonalRadius, joystickCenterpoint.y + diagonalRadius), + ImVec2(joystickCenterpoint.x + cardinalRadius, joystickCenterpoint.y), + ImVec2(joystickCenterpoint.x + diagonalRadius, joystickCenterpoint.y - diagonalRadius), + ImColor(130, 130, 130, 255)); + drawList->AddQuadFilled(joystickCenterpoint, + ImVec2(joystickCenterpoint.x + diagonalRadius, joystickCenterpoint.y - diagonalRadius), + ImVec2(joystickCenterpoint.x, joystickCenterpoint.y - cardinalRadius), + ImVec2(joystickCenterpoint.x - diagonalRadius, joystickCenterpoint.y - diagonalRadius), + ImColor(130, 130, 130, 255)); + drawList->AddQuadFilled(joystickCenterpoint, + ImVec2(joystickCenterpoint.x - diagonalRadius, joystickCenterpoint.y - diagonalRadius), + ImVec2(joystickCenterpoint.x - cardinalRadius, joystickCenterpoint.y), + ImVec2(joystickCenterpoint.x - diagonalRadius, joystickCenterpoint.y + diagonalRadius), + ImColor(130, 130, 130, 255)); + + // Draw the joystick position indicator + ImVec2 joystickIndicatorDistanceFromCenter = ImVec2(0, 0); + if ((stick.x * stick.x + stick.y * stick.y) > (deadzone * deadzone)) { + joystickIndicatorDistanceFromCenter = + ImVec2((stick.x * (cardinalRadius / 85.0f)), -(stick.y * (cardinalRadius / 85.0f))); + } + float indicatorRadius = SCALE_IMGUI_SIZE(5.0f); + drawList->AddCircleFilled(ImVec2(joystickCenterpoint.x + joystickIndicatorDistanceFromCenter.x, + joystickCenterpoint.y + joystickIndicatorDistanceFromCenter.y), + indicatorRadius, ImColor(34, 51, 76, 255), 7); + + if (!gyro) { + ImGui::SetCursorPos( + ImVec2(ImGui::GetCursorPos().x - SCALE_IMGUI_SIZE(8), ImGui::GetCursorPos().y + SCALE_IMGUI_SIZE(72))); + ImGui::Text("X:%3d, Y:%3d", static_cast(stick.x), static_cast(stick.y)); + } + ImGui::EndChild(); +} + +#define CHIP_COLOR_N64_GREY ImVec4(0.4f, 0.4f, 0.4f, 1.0f) +#define CHIP_COLOR_N64_BLUE ImVec4(0.176f, 0.176f, 0.5f, 1.0f) +#define CHIP_COLOR_N64_GREEN ImVec4(0.0f, 0.294f, 0.0f, 1.0f) +#define CHIP_COLOR_N64_YELLOW ImVec4(0.5f, 0.314f, 0.0f, 1.0f) +#define CHIP_COLOR_N64_RED ImVec4(0.392f, 0.0f, 0.0f, 1.0f) + +#define BUTTON_COLOR_KEYBOARD_BEIGE ImVec4(0.651f, 0.482f, 0.357f, 0.5f) +#define BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED ImVec4(0.651f, 0.482f, 0.357f, 1.0f) + +#define BUTTON_COLOR_GAMEPAD_BLUE ImVec4(0.0f, 0.255f, 0.976f, 0.5f) +#define BUTTON_COLOR_GAMEPAD_BLUE_HOVERED ImVec4(0.0f, 0.255f, 0.976f, 1.0f) + +#define BUTTON_COLOR_GAMEPAD_RED ImVec4(0.976f, 0.0f, 0.094f, 0.5f) +#define BUTTON_COLOR_GAMEPAD_RED_HOVERED ImVec4(0.976f, 0.0f, 0.094f, 1.0f) + +#define BUTTON_COLOR_GAMEPAD_ORANGE ImVec4(0.976f, 0.376f, 0.0f, 0.5f) +#define BUTTON_COLOR_GAMEPAD_ORANGE_HOVERED ImVec4(0.976f, 0.376f, 0.0f, 1.0f) + +#define BUTTON_COLOR_GAMEPAD_GREEN ImVec4(0.0f, 0.5f, 0.0f, 0.5f) +#define BUTTON_COLOR_GAMEPAD_GREEN_HOVERED ImVec4(0.0f, 0.5f, 0.0f, 1.0f) + +#define BUTTON_COLOR_GAMEPAD_PURPLE ImVec4(0.431f, 0.369f, 0.706f, 0.5f) +#define BUTTON_COLOR_GAMEPAD_PURPLE_HOVERED ImVec4(0.431f, 0.369f, 0.706f, 1.0f) + +void BenInputEditorWindow::GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor, + ImVec4& buttonHoveredColor) { + switch (lusIndex) { + case Ship::ShipDeviceIndex::Keyboard: + buttonColor = BUTTON_COLOR_KEYBOARD_BEIGE; + buttonHoveredColor = BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED; + break; + case Ship::ShipDeviceIndex::Blue: + buttonColor = BUTTON_COLOR_GAMEPAD_BLUE; + buttonHoveredColor = BUTTON_COLOR_GAMEPAD_BLUE_HOVERED; + break; + case Ship::ShipDeviceIndex::Red: + buttonColor = BUTTON_COLOR_GAMEPAD_RED; + buttonHoveredColor = BUTTON_COLOR_GAMEPAD_RED_HOVERED; + break; + case Ship::ShipDeviceIndex::Orange: + buttonColor = BUTTON_COLOR_GAMEPAD_ORANGE; + buttonHoveredColor = BUTTON_COLOR_GAMEPAD_ORANGE_HOVERED; + break; + case Ship::ShipDeviceIndex::Green: + buttonColor = BUTTON_COLOR_GAMEPAD_GREEN; + buttonHoveredColor = BUTTON_COLOR_GAMEPAD_GREEN_HOVERED; + break; + default: + buttonColor = BUTTON_COLOR_GAMEPAD_PURPLE; + buttonHoveredColor = BUTTON_COLOR_GAMEPAD_PURPLE_HOVERED; + } +} + +void BenInputEditorWindow::DrawInputChip(const char* buttonName, ImVec4 color = CHIP_COLOR_N64_GREY) { + ImGui::BeginDisabled(); + ImGui::PushStyleColor(ImGuiCol_Button, color); + ImGui::Button(buttonName, ImVec2(SCALE_IMGUI_SIZE(50.0f), 0)); + ImGui::PopStyleColor(); + ImGui::EndDisabled(); +} + +void BenInputEditorWindow::DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask) { + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("addButtonMappingPopup##%d-%d", port, bitmask); + if (ImGui::Button(StringHelper::Sprintf("%s###addButtonMappingButton%d-%d", ICON_FA_PLUS, port, bitmask).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), 0.0f))) { + ImGui::OpenPopup(popupId.c_str()); + }; + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button,\nmove any axis,\nor press any key\nto add mapping"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + // todo: figure out why optional params (using id = "" in the definition) wasn't working + if (mMappingInputBlockTimer == INT32_MAX && Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetButton(bitmask) + ->AddOrEditButtonMappingFromRawPress(bitmask, "")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id) { + auto mapping = Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetButton(bitmask) + ->GetButtonMappingById(id); + if (mapping == nullptr) { + return; + } + if (!mDeviceIndexVisiblity[mapping->GetShipDeviceIndex()]) { + return; + } + + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); + std::string icon = ""; + switch (mapping->GetMappingType()) { + case MAPPING_TYPE_GAMEPAD: + icon = ICON_FA_GAMEPAD; + break; + case MAPPING_TYPE_KEYBOARD: + icon = ICON_FA_KEYBOARD_O; + break; + case MAPPING_TYPE_UNKNOWN: + icon = ICON_FA_BUG; + break; + } + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + auto physicalInputDisplayName = + StringHelper::Sprintf("%s %s", icon.c_str(), mapping->GetPhysicalInputName().c_str()); + GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + auto popupId = StringHelper::Sprintf("editButtonMappingPopup##%s", id.c_str()); + if (ImGui::Button( + StringHelper::Sprintf("%s###editButtonMappingButton%s", physicalInputDisplayName.c_str(), id.c_str()) + .c_str(), + ImVec2(ImGui::CalcTextSize(physicalInputDisplayName.c_str()).x + SCALE_IMGUI_SIZE(12.0f), 0.0f))) { + ImGui::OpenPopup(popupId.c_str()); + } + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) { + ImGui::SetTooltip(mapping->GetPhysicalDeviceName().c_str()); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button,\nmove any axis,\nor press any key\nto edit mapping"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + if (mMappingInputBlockTimer == INT32_MAX && Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetButton(bitmask) + ->AddOrEditButtonMappingFromRawPress(bitmask, id)) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + ImGui::PopStyleVar(); + ImGui::SameLine(0, 0); + + auto sdlAxisDirectionToButtonMapping = std::dynamic_pointer_cast(mapping); + auto indexMapping = Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetDeviceIndexMappingFromShipDeviceIndex(mapping->GetShipDeviceIndex()); + auto sdlIndexMapping = std::dynamic_pointer_cast(indexMapping); + + if (sdlIndexMapping != nullptr && sdlAxisDirectionToButtonMapping != nullptr) { + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("editAxisThresholdPopup##%s", id.c_str()); + if (ImGui::Button(StringHelper::Sprintf("%s###editAxisThresholdButton%s", ICON_FA_COG, id.c_str()).c_str(), + ImVec2(ImGui::CalcTextSize(ICON_FA_COG).x + SCALE_IMGUI_SIZE(10.0f), 0.0f))) { + ImGui::OpenPopup(popupId.c_str()); + } + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) { + ImGui::SetTooltip("Edit axis threshold"); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Axis Threshold\n\nThe extent to which the joystick\nmust be moved or the trigger\npressed to " + "initiate the assigned\nbutton action.\n\n"); + + if (sdlAxisDirectionToButtonMapping->AxisIsStick()) { + ImGui::Text("Stick axis threshold:"); + + int32_t stickAxisThreshold = sdlIndexMapping->GetStickAxisThresholdPercentage(); + if (stickAxisThreshold == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Stick Axis Threshold%s", id.c_str()).c_str())) { + sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold - 1); + sdlIndexMapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (stickAxisThreshold == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Stick Axis Threshold%s", id.c_str()).c_str(), + &stickAxisThreshold, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold); + sdlIndexMapping->SaveToConfig(); + } + ImGui::SameLine(0.0f, 0.0f); + if (stickAxisThreshold == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Stick Axis Threshold%s", id.c_str()).c_str())) { + sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold + 1); + sdlIndexMapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (stickAxisThreshold == 100) { + ImGui::EndDisabled(); + } + } + + if (sdlAxisDirectionToButtonMapping->AxisIsTrigger()) { + ImGui::Text("Trigger axis threshold:"); + + int32_t triggerAxisThreshold = sdlIndexMapping->GetTriggerAxisThresholdPercentage(); + if (triggerAxisThreshold == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Trigger Axis Threshold%s", id.c_str()).c_str())) { + sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold - 1); + sdlIndexMapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (triggerAxisThreshold == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Trigger Axis Threshold%s", id.c_str()).c_str(), + &triggerAxisThreshold, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold); + sdlIndexMapping->SaveToConfig(); + } + ImGui::SameLine(0.0f, 0.0f); + if (triggerAxisThreshold == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Trigger Axis Threshold%s", id.c_str()).c_str())) { + sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold + 1); + sdlIndexMapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (triggerAxisThreshold == 100) { + ImGui::EndDisabled(); + } + } + + if (ImGui::Button("Close")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + ImGui::PopStyleVar(); + ImGui::SameLine(0, 0); + } + + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + if (ImGui::Button(StringHelper::Sprintf("%s###removeButtonMappingButton%s", ICON_FA_TIMES, id.c_str()).c_str(), + ImVec2(ImGui::CalcTextSize(ICON_FA_TIMES).x + SCALE_IMGUI_SIZE(10.0f), 0.0f))) { + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetButton(bitmask) + ->ClearButtonMapping(id); + }; + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + + ImGui::SameLine(0, SCALE_IMGUI_SIZE(4.0f)); +} + +void BenInputEditorWindow::DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask, + ImVec4 color = CHIP_COLOR_N64_GREY) { + ImGui::NewLine(); + ImGui::SameLine(SCALE_IMGUI_SIZE(32.0f)); + DrawInputChip(buttonName, color); + ImGui::SameLine(SCALE_IMGUI_SIZE(86.0f)); + for (auto id : mBitmaskToMappingIds[port][bitmask]) { + DrawButtonLineEditMappingButton(port, bitmask, id); + } + DrawButtonLineAddMappingButton(port, bitmask); +} + +void BenInputEditorWindow::DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, + Ship::Direction direction) { + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("addStickDirectionMappingPopup##%d-%d-%d", port, stick, direction); + if (ImGui::Button( + StringHelper::Sprintf("%s###addStickDirectionMappingButton%d-%d-%d", ICON_FA_PLUS, port, stick, direction) + .c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), 0.0f))) { + ImGui::OpenPopup(popupId.c_str()); + }; + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button,\nmove any axis,\nor press any key\nto add mapping"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + if (stick == Ship::LEFT) { + if (mMappingInputBlockTimer == INT32_MAX && + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetLeftStick() + ->AddOrEditAxisDirectionMappingFromRawPress(direction, "")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + } else { + if (mMappingInputBlockTimer == INT32_MAX && + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRightStick() + ->AddOrEditAxisDirectionMappingFromRawPress(direction, "")) { + ImGui::CloseCurrentPopup(); + } + } + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, + Ship::Direction direction, std::string id) { + std::shared_ptr mapping = nullptr; + if (stick == Ship::LEFT) { + mapping = Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetLeftStick() + ->GetAxisDirectionMappingById(direction, id); + } else { + mapping = Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRightStick() + ->GetAxisDirectionMappingById(direction, id); + } + + if (mapping == nullptr) { + return; + } + if (!mDeviceIndexVisiblity[mapping->GetShipDeviceIndex()]) { + return; + } + + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); + std::string icon = ""; + switch (mapping->GetMappingType()) { + case MAPPING_TYPE_GAMEPAD: + icon = ICON_FA_GAMEPAD; + break; + case MAPPING_TYPE_KEYBOARD: + icon = ICON_FA_KEYBOARD_O; + break; + case MAPPING_TYPE_UNKNOWN: + icon = ICON_FA_BUG; + break; + } + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + auto physicalInputDisplayName = + StringHelper::Sprintf("%s %s", icon.c_str(), mapping->GetPhysicalInputName().c_str()); + GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + auto popupId = StringHelper::Sprintf("editStickDirectionMappingPopup##%s", id.c_str()); + if (ImGui::Button( + StringHelper::Sprintf("%s###editStickDirectionMappingButton%s", physicalInputDisplayName.c_str(), + id.c_str()) + .c_str(), + ImVec2(ImGui::CalcTextSize(physicalInputDisplayName.c_str()).x + SCALE_IMGUI_SIZE(12.0f), 0.0f))) { + ImGui::OpenPopup(popupId.c_str()); + } + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) { + ImGui::SetTooltip(mapping->GetPhysicalDeviceName().c_str()); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button,\nmove any axis,\nor press any key\nto edit mapping"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + + if (stick == Ship::LEFT) { + if (mMappingInputBlockTimer == INT32_MAX && + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetLeftStick() + ->AddOrEditAxisDirectionMappingFromRawPress(direction, id)) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + } else { + if (mMappingInputBlockTimer == INT32_MAX && + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRightStick() + ->AddOrEditAxisDirectionMappingFromRawPress(direction, id)) { + ImGui::CloseCurrentPopup(); + } + } + ImGui::EndPopup(); + } + + ImGui::PopStyleVar(); + ImGui::SameLine(0, 0); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + if (ImGui::Button( + StringHelper::Sprintf("%s###removeStickDirectionMappingButton%s", ICON_FA_TIMES, id.c_str()).c_str(), + ImVec2(ImGui::CalcTextSize(ICON_FA_TIMES).x + SCALE_IMGUI_SIZE(10.0f), 0.0f))) { + if (stick == Ship::LEFT) { + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetLeftStick() + ->ClearAxisDirectionMapping(direction, id); + } else { + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRightStick() + ->ClearAxisDirectionMapping(direction, id); + } + }; + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + ImGui::SameLine(0, SCALE_IMGUI_SIZE(4.0f)); +} + +void BenInputEditorWindow::DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, + Ship::Direction direction, ImVec4 color = CHIP_COLOR_N64_GREY) { + ImGui::NewLine(); + ImGui::SameLine(); + ImGui::BeginDisabled(); + ImGui::PushStyleColor(ImGuiCol_Button, color); + ImGui::Button(axisDirectionName, ImVec2(SCALE_IMGUI_SIZE(26.0f), 0)); + ImGui::PopStyleColor(); + ImGui::EndDisabled(); + ImGui::SameLine(0.0f, SCALE_IMGUI_SIZE(4.0f)); + for (auto id : mStickDirectionToMappingIds[port][stick][direction]) { + DrawStickDirectionLineEditMappingButton(port, stick, direction, id); + } + DrawStickDirectionLineAddMappingButton(port, stick, direction); +} + +void BenInputEditorWindow::DrawStickSection(uint8_t port, uint8_t stick, int32_t id, + ImVec4 color = CHIP_COLOR_N64_GREY) { + static int8_t sX, sY; + std::shared_ptr controllerStick = nullptr; + if (stick == Ship::LEFT) { + controllerStick = Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetLeftStick(); + } else { + controllerStick = Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetRightStick(); + } + controllerStick->Process(sX, sY); + DrawAnalogPreview(StringHelper::Sprintf("##AnalogPreview%d", id).c_str(), ImVec2(sX, sY)); + + ImGui::SameLine(); + ImGui::BeginGroup(); + DrawStickDirectionLine(ICON_FA_ARROW_UP, port, stick, Ship::UP, color); + DrawStickDirectionLine(ICON_FA_ARROW_DOWN, port, stick, Ship::DOWN, color); + DrawStickDirectionLine(ICON_FA_ARROW_LEFT, port, stick, Ship::LEFT, color); + DrawStickDirectionLine(ICON_FA_ARROW_RIGHT, port, stick, Ship::RIGHT, color); + ImGui::EndGroup(); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode(StringHelper::Sprintf("Analog Stick Options##%d", id).c_str())) { + ImGui::Text("Sensitivity:"); + + int32_t sensitivityPercentage = controllerStick->GetSensitivityPercentage(); + if (sensitivityPercentage == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Sensitivity%d", id).c_str())) { + controllerStick->SetSensitivity(sensitivityPercentage - 1); + } + ImGui::PopButtonRepeat(); + if (sensitivityPercentage == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Sensitivity%d", id).c_str(), &sensitivityPercentage, 0, 200, + "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + controllerStick->SetSensitivity(sensitivityPercentage); + } + ImGui::SameLine(0.0f, 0.0f); + if (sensitivityPercentage == 200) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Sensitivity%d", id).c_str())) { + controllerStick->SetSensitivity(sensitivityPercentage + 1); + } + ImGui::PopButtonRepeat(); + if (sensitivityPercentage == 200) { + ImGui::EndDisabled(); + } + if (!controllerStick->SensitivityIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button(StringHelper::Sprintf("Reset to Default###resetStickSensitivity%d", id).c_str())) { + controllerStick->ResetSensitivityToDefault(); + } + } + + ImGui::Text("Deadzone:"); + + int32_t deadzonePercentage = controllerStick->GetDeadzonePercentage(); + if (deadzonePercentage == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Deadzone%d", id).c_str())) { + controllerStick->SetDeadzone(deadzonePercentage - 1); + } + ImGui::PopButtonRepeat(); + if (deadzonePercentage == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Deadzone%d", id).c_str(), &deadzonePercentage, 0, 100, "%d%%", + ImGuiSliderFlags_AlwaysClamp)) { + controllerStick->SetDeadzone(deadzonePercentage); + } + ImGui::SameLine(0.0f, 0.0f); + if (deadzonePercentage == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Deadzone%d", id).c_str())) { + controllerStick->SetDeadzone(deadzonePercentage + 1); + } + ImGui::PopButtonRepeat(); + if (deadzonePercentage == 100) { + ImGui::EndDisabled(); + } + if (!controllerStick->DeadzoneIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button(StringHelper::Sprintf("Reset to Default###resetStickDeadzone%d", id).c_str())) { + controllerStick->ResetDeadzoneToDefault(); + } + } + + ImGui::Text("Notch Snap Angle:"); + int32_t notchSnapAngle = controllerStick->GetNotchSnapAngle(); + if (notchSnapAngle == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##NotchProximityThreshold%d", id).c_str())) { + controllerStick->SetNotchSnapAngle(notchSnapAngle - 1); + } + ImGui::PopButtonRepeat(); + if (notchSnapAngle == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##NotchProximityThreshold%d", id).c_str(), ¬chSnapAngle, 0, 45, + "%d°", ImGuiSliderFlags_AlwaysClamp)) { + controllerStick->SetNotchSnapAngle(notchSnapAngle); + } + ImGui::SameLine(0.0f, 0.0f); + if (notchSnapAngle == 45) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##NotchProximityThreshold%d", id).c_str())) { + controllerStick->SetNotchSnapAngle(notchSnapAngle + 1); + } + ImGui::PopButtonRepeat(); + if (notchSnapAngle == 45) { + ImGui::EndDisabled(); + } + if (!controllerStick->NotchSnapAngleIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button(StringHelper::Sprintf("Reset to Default###resetStickSnap%d", id).c_str())) { + controllerStick->ResetNotchSnapAngleToDefault(); + } + } + + ImGui::TreePop(); + } +} + +void BenInputEditorWindow::UpdateBitmaskToMappingIds(uint8_t port) { + // todo: do we need this now that ControllerButton exists? + + for (auto [bitmask, button] : + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetAllButtons()) { + for (auto [id, mapping] : button->GetAllButtonMappings()) { + // using a vector here instead of a set because i want newly added mappings + // to go to the end of the list instead of autosorting + if (std::find(mBitmaskToMappingIds[port][bitmask].begin(), mBitmaskToMappingIds[port][bitmask].end(), id) == + mBitmaskToMappingIds[port][bitmask].end()) { + mBitmaskToMappingIds[port][bitmask].push_back(id); + } + } + } +} + +void BenInputEditorWindow::UpdateStickDirectionToMappingIds(uint8_t port) { + // todo: do we need this? + for (auto stick : + { std::make_pair>( + Ship::LEFT, Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetLeftStick()), + std::make_pair>( + Ship::RIGHT, + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetRightStick()) }) { + for (auto direction : { Ship::LEFT, Ship::RIGHT, Ship::UP, Ship::DOWN }) { + for (auto [id, mapping] : stick.second->GetAllAxisDirectionMappingByDirection(direction)) { + // using a vector here instead of a set because i want newly added mappings + // to go to the end of the list instead of autosorting + if (std::find(mStickDirectionToMappingIds[port][stick.first][direction].begin(), + mStickDirectionToMappingIds[port][stick.first][direction].end(), + id) == mStickDirectionToMappingIds[port][stick.first][direction].end()) { + mStickDirectionToMappingIds[port][stick.first][direction].push_back(id); + } + } + } + } +} + +void BenInputEditorWindow::DrawRemoveRumbleMappingButton(uint8_t port, std::string id) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + if (ImGui::Button(StringHelper::Sprintf("%s###removeRumbleMapping%s", ICON_FA_TIMES, id.c_str()).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetRumble()->ClearRumbleMapping(id); + } + ImGui::PopStyleVar(); +} + +void BenInputEditorWindow::DrawAddRumbleMappingButton(uint8_t port) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("addRumbleMappingPopup##%d", port); + if (ImGui::Button(StringHelper::Sprintf("%s###addRumbleMapping%d", ICON_FA_PLUS, port).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + ImGui::OpenPopup(popupId.c_str()); + } + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button\nor move any axis\nto add rumble device"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + + if (mMappingInputBlockTimer == INT32_MAX && Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRumble() + ->AddRumbleMappingFromRawPress()) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +bool BenInputEditorWindow::TestingRumble() { + return mRumbleTimer != INT32_MAX; +} + +void BenInputEditorWindow::DrawRumbleSection(uint8_t port) { + for (auto [id, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetRumble() + ->GetAllRumbleMappings()) { + ImGui::AlignTextToFramePadding(); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor); + // begin hackaround https://github.com/ocornut/imgui/issues/282#issuecomment-123763192 + // spaces to have background color for text in a tree node + std::string spaces = ""; + for (size_t i = 0; i < mapping->GetPhysicalDeviceName().length(); i++) { + spaces += " "; + } + auto open = ImGui::TreeNode(StringHelper::Sprintf("%s###Rumble%s", spaces.c_str(), id.c_str()).c_str()); + ImGui::SameLine(); + ImGui::SetCursorPosX(SCALE_IMGUI_SIZE(30.0f)); + // end hackaround + + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::Button(mapping->GetPhysicalDeviceName().c_str()); + ImGui::PopStyleColor(); + ImGui::PopItemFlag(); + + DrawRemoveRumbleMappingButton(port, id); + ImGui::SameLine(); + if (ImGui::Button( + StringHelper::Sprintf("%s###rumbleTestButton%s", TestingRumble() ? "Stop" : "Test", id.c_str()) + .c_str())) { + if (mRumbleTimer != INT32_MAX) { + mRumbleTimer = INT32_MAX; + mRumbleMappingToTest->StopRumble(); + mRumbleMappingToTest = nullptr; + } else { + mRumbleTimer = ImGui::GetIO().Framerate; + mRumbleMappingToTest = mapping; + } + } + if (open) { + ImGui::Text("Small Motor Intensity:"); + + int32_t smallMotorIntensity = mapping->GetHighFrequencyIntensityPercentage(); + if (smallMotorIntensity == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Small Motor Intensity%s", id.c_str()).c_str())) { + mapping->SetHighFrequencyIntensity(smallMotorIntensity - 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (smallMotorIntensity == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Small Motor Intensity%s", id.c_str()).c_str(), + &smallMotorIntensity, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + mapping->SetHighFrequencyIntensity(smallMotorIntensity); + mapping->SaveToConfig(); + } + ImGui::SameLine(0.0f, 0.0f); + if (smallMotorIntensity == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Small Motor Intensity%s", id.c_str()).c_str())) { + mapping->SetHighFrequencyIntensity(smallMotorIntensity + 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (smallMotorIntensity == 100) { + ImGui::EndDisabled(); + } + if (!mapping->HighFrequencyIntensityIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button(StringHelper::Sprintf("Reset to Default###resetHighFrequencyIntensity%s", id.c_str()) + .c_str())) { + mapping->ResetHighFrequencyIntensityToDefault(); + } + } + + ImGui::Text("Large Motor Intensity:"); + + int32_t largeMotorIntensity = mapping->GetLowFrequencyIntensityPercentage(); + if (largeMotorIntensity == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##Large Motor Intensity%s", id.c_str()).c_str())) { + mapping->SetLowFrequencyIntensity(largeMotorIntensity - 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (largeMotorIntensity == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##Large Motor Intensity%s", id.c_str()).c_str(), + &largeMotorIntensity, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + mapping->SetLowFrequencyIntensity(largeMotorIntensity); + mapping->SaveToConfig(); + } + ImGui::SameLine(0.0f, 0.0f); + if (largeMotorIntensity == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##Large Motor Intensity%s", id.c_str()).c_str())) { + mapping->SetLowFrequencyIntensity(largeMotorIntensity + 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (largeMotorIntensity == 100) { + ImGui::EndDisabled(); + } + if (!mapping->LowFrequencyIntensityIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button( + StringHelper::Sprintf("Reset to Default###resetLowFrequencyIntensity%s", id.c_str()).c_str())) { + mapping->ResetLowFrequencyIntensityToDefault(); + } + } + ImGui::Dummy(ImVec2(0, SCALE_IMGUI_SIZE(20))); + + ImGui::TreePop(); + } + } + + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Add rumble device"); + DrawAddRumbleMappingButton(port); +} + +void BenInputEditorWindow::DrawRemoveLEDMappingButton(uint8_t port, std::string id) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + if (ImGui::Button(StringHelper::Sprintf("%s###removeLEDMapping%s", ICON_FA_TIMES, id.c_str()).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetLED()->ClearLEDMapping(id); + } + ImGui::PopStyleVar(); +} + +void BenInputEditorWindow::DrawAddLEDMappingButton(uint8_t port) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("addLEDMappingPopup##%d", port); + if (ImGui::Button(StringHelper::Sprintf("%s###addLEDMapping%d", ICON_FA_PLUS, port).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + ImGui::OpenPopup(popupId.c_str()); + } + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button\nor move any axis\nto add LED device"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + + if (mMappingInputBlockTimer == INT32_MAX && Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetLED() + ->AddLEDMappingFromRawPress()) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawLEDSection(uint8_t port) { + for (auto [id, mapping] : + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetLED()->GetAllLEDMappings()) { + ImGui::AlignTextToFramePadding(); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + auto open = ImGui::TreeNode( + StringHelper::Sprintf("%s##LED%s", mapping->GetPhysicalDeviceName().c_str(), id.c_str()).c_str()); + DrawRemoveLEDMappingButton(port, id); + if (open) { + ImGui::AlignTextToFramePadding(); + ImGui::Text("LED Color:"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(80.0f)); + int32_t colorSource = mapping->GetColorSource(); + if (ImGui::Combo(StringHelper::Sprintf("###ledColorSource%s", mapping->GetLEDMappingId().c_str()).c_str(), + &colorSource, "Off\0Set\0Game\0\0")) { + mapping->SetColorSource(colorSource); + }; + if (mapping->GetColorSource() == LED_COLOR_SOURCE_SET) { + ImGui::SameLine(); + ImVec4 color = { mapping->GetSavedColor().r / 255.0f, mapping->GetSavedColor().g / 255.0f, + mapping->GetSavedColor().b / 255.0f, 1.0f }; + if (ImGui::ColorEdit3( + StringHelper::Sprintf("###ledSavedColor%s", mapping->GetLEDMappingId().c_str()).c_str(), + (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) { + mapping->SetSavedColor( + Color_RGB8({ static_cast(color.x * 255.0), static_cast(color.y * 255.0), + static_cast(color.z * 255.0) })); + } + } + ImGui::TreePop(); + } + } + + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Add LED device"); + DrawAddLEDMappingButton(port); +} + +void BenInputEditorWindow::DrawRemoveGyroMappingButton(uint8_t port, std::string id) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + if (ImGui::Button(StringHelper::Sprintf("%s###removeGyroMapping%s", ICON_FA_TIMES, id.c_str()).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetGyro()->ClearGyroMapping(); + } + ImGui::PopStyleVar(); +} + +void BenInputEditorWindow::DrawAddGyroMappingButton(uint8_t port) { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f)); + auto popupId = StringHelper::Sprintf("addGyroMappingPopup##%d", port); + if (ImGui::Button(StringHelper::Sprintf("%s###addGyroMapping%d", ICON_FA_PLUS, port).c_str(), + ImVec2(SCALE_IMGUI_SIZE(20.0f), SCALE_IMGUI_SIZE(20.0f)))) { + ImGui::OpenPopup(popupId.c_str()); + } + ImGui::PopStyleVar(); + + if (ImGui::BeginPopup(popupId.c_str())) { + mInputEditorPopupOpen = true; + ImGui::Text("Press any button\nor move any axis\nto add gyro device"); + if (ImGui::Button("Cancel")) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + + if (mMappingInputBlockTimer == INT32_MAX && Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(port) + ->GetGyro() + ->SetGyroMappingFromRawPress()) { + mInputEditorPopupOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawGyroSection(uint8_t port) { + auto mapping = + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetGyro()->GetGyroMapping(); + if (mapping != nullptr) { + auto id = mapping->GetGyroMappingId(); + ImGui::AlignTextToFramePadding(); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + ImGui::BulletText(mapping->GetPhysicalDeviceName().c_str()); + DrawRemoveGyroMappingButton(port, id); + + static float sPitch, sYaw = 0.0f; + mapping->UpdatePad(sPitch, sYaw); + + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x, ImGui::GetCursorPos().y - SCALE_IMGUI_SIZE(8))); + // to find a reasonable scaling factor gyro values + // I tried to find the maximum value reported by shaking + // a PS5 controller as hard as I could without worrying about breaking it + // the max I found for both pitch and yaw was ~21 + // the preview window expects values in an n64 analog stick range (-85 to 85) + // so I decided to multiply these by 85/21 + DrawAnalogPreview(StringHelper::Sprintf("###GyroPreview%s", id.c_str()).c_str(), + ImVec2(sYaw * (85.0f / 21.0f), sPitch * (85.0f / 21.0f)), 0.0f, true); + ImGui::SameLine(); + ImGui::SetCursorPos( + ImVec2(ImGui::GetCursorPos().x + SCALE_IMGUI_SIZE(8), ImGui::GetCursorPos().y + SCALE_IMGUI_SIZE(8))); + + ImGui::BeginGroup(); + ImGui::Text("Sensitivity:"); + + int32_t sensitivity = mapping->GetSensitivityPercent(); + if (sensitivity == 0) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("-##GyroSensitivity%s", id.c_str()).c_str())) { + mapping->SetSensitivity(sensitivity - 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (sensitivity == 0) { + ImGui::EndDisabled(); + } + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f)); + if (ImGui::SliderInt(StringHelper::Sprintf("##GyroSensitivity%s", id.c_str()).c_str(), &sensitivity, 0, 100, + "%d%%", ImGuiSliderFlags_AlwaysClamp)) { + mapping->SetSensitivity(sensitivity); + mapping->SaveToConfig(); + } + ImGui::SameLine(0.0f, 0.0f); + if (sensitivity == 100) { + ImGui::BeginDisabled(); + } + ImGui::PushButtonRepeat(true); + if (ImGui::Button(StringHelper::Sprintf("+##GyroSensitivity%s", id.c_str()).c_str())) { + mapping->SetSensitivity(sensitivity + 1); + mapping->SaveToConfig(); + } + ImGui::PopButtonRepeat(); + if (sensitivity == 100) { + ImGui::EndDisabled(); + } + + if (!mapping->SensitivityIsDefault()) { + ImGui::SameLine(); + if (ImGui::Button(StringHelper::Sprintf("Reset to Default###resetGyroSensitivity%s", id.c_str()).c_str())) { + mapping->ResetSensitivityToDefault(); + } + } + + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x, ImGui::GetCursorPos().y + SCALE_IMGUI_SIZE(8))); + if (ImGui::Button("Recalibrate")) { + mapping->Recalibrate(); + mapping->SaveToConfig(); + } + ImGui::EndGroup(); + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x, ImGui::GetCursorPos().y - SCALE_IMGUI_SIZE(8))); + } else { + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Add gyro device"); + DrawAddGyroMappingButton(port); + } +} + +void BenInputEditorWindow::DrawButtonDeviceIcons(uint8_t portIndex, std::set bitmasks) { + std::set allLusDeviceIndices; + allLusDeviceIndices.insert(Ship::ShipDeviceIndex::Keyboard); + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappingsFromConfig()) { + allLusDeviceIndices.insert(lusIndex); + } + + std::vector> lusDeviceIndiciesWithMappings; + for (auto lusIndex : allLusDeviceIndices) { + for (auto [bitmask, button] : + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetAllButtons()) { + if (!bitmasks.contains(bitmask)) { + continue; + } + + if (button->HasMappingsForShipDeviceIndex(lusIndex)) { + for (auto [id, mapping] : button->GetAllButtonMappings()) { + if (mapping->GetShipDeviceIndex() == lusIndex) { + lusDeviceIndiciesWithMappings.push_back( + std::pair(lusIndex, mapping->PhysicalDeviceIsConnected())); + break; + } + } + break; + } + } + } + + for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) { + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::SameLine(); + if (lusIndex == Ship::ShipDeviceIndex::Keyboard) { + ImGui::SmallButton(ICON_FA_KEYBOARD_O); + } else { + ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } +} + +void BenInputEditorWindow::DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick) { + std::set allLusDeviceIndices; + allLusDeviceIndices.insert(Ship::ShipDeviceIndex::Keyboard); + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappingsFromConfig()) { + allLusDeviceIndices.insert(lusIndex); + } + + std::vector> lusDeviceIndiciesWithMappings; + for (auto lusIndex : allLusDeviceIndices) { + auto controllerStick = + stick == Ship::Stick::LEFT_STICK + ? Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetLeftStick() + : Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetRightStick(); + if (controllerStick->HasMappingsForShipDeviceIndex(lusIndex)) { + for (auto [direction, mappings] : controllerStick->GetAllAxisDirectionMappings()) { + bool foundMapping = false; + for (auto [id, mapping] : mappings) { + if (mapping->GetShipDeviceIndex() == lusIndex) { + foundMapping = true; + lusDeviceIndiciesWithMappings.push_back( + std::pair(lusIndex, mapping->PhysicalDeviceIsConnected())); + break; + } + } + if (foundMapping) { + break; + } + } + } + } + + for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) { + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::SameLine(); + if (lusIndex == Ship::ShipDeviceIndex::Keyboard) { + ImGui::SmallButton(ICON_FA_KEYBOARD_O); + } else { + ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } +} + +void BenInputEditorWindow::DrawRumbleDeviceIcons(uint8_t portIndex) { + std::set allLusDeviceIndices; + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappingsFromConfig()) { + allLusDeviceIndices.insert(lusIndex); + } + + std::vector> lusDeviceIndiciesWithMappings; + for (auto lusIndex : allLusDeviceIndices) { + if (Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->GetRumble() + ->HasMappingsForShipDeviceIndex(lusIndex)) { + for (auto [id, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->GetRumble() + ->GetAllRumbleMappings()) { + if (mapping->GetShipDeviceIndex() == lusIndex) { + lusDeviceIndiciesWithMappings.push_back( + std::pair(lusIndex, mapping->PhysicalDeviceIsConnected())); + break; + } + } + } + } + + for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) { + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::SameLine(); + ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } +} + +void BenInputEditorWindow::DrawGyroDeviceIcons(uint8_t portIndex) { + auto mapping = + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetGyro()->GetGyroMapping(); + if (mapping == nullptr) { + return; + } + + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::SameLine(); + ImGui::SmallButton(mapping->PhysicalDeviceIsConnected() ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); +} + +void BenInputEditorWindow::DrawLEDDeviceIcons(uint8_t portIndex) { + std::set allLusDeviceIndices; + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappingsFromConfig()) { + allLusDeviceIndices.insert(lusIndex); + } + + std::vector> lusDeviceIndiciesWithMappings; + for (auto lusIndex : allLusDeviceIndices) { + if (Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->GetRumble() + ->HasMappingsForShipDeviceIndex(lusIndex)) { + for (auto [id, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->GetLED() + ->GetAllLEDMappings()) { + if (mapping->GetShipDeviceIndex() == lusIndex) { + lusDeviceIndiciesWithMappings.push_back( + std::pair(lusIndex, mapping->PhysicalDeviceIsConnected())); + break; + } + } + } + } + + for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) { + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + ImGui::SameLine(); + ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } +} + +void BenInputEditorWindow::DrawDeviceVisibilityButtons() { + std::map> indexMappings; + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappingsFromConfig()) { + auto sdlIndexMapping = std::static_pointer_cast(mapping); + if (sdlIndexMapping == nullptr) { + continue; + } + + indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), -1 }; + } + + for (auto [lusIndex, mapping] : + Ship::Context::GetInstance()->GetControlDeck()->GetDeviceIndexMappingManager()->GetAllDeviceIndexMappings()) { + auto sdlIndexMapping = std::static_pointer_cast(mapping); + if (sdlIndexMapping == nullptr) { + continue; + } + + indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), sdlIndexMapping->GetSDLDeviceIndex() }; + } + + auto keyboardButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto keyboardButtonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex::Keyboard, keyboardButtonColor, keyboardButtonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, keyboardButtonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, keyboardButtonHoveredColor); + bool keyboardVisible = mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard]; + if (ImGui::Button(StringHelper::Sprintf("%s %s Keyboard", keyboardVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH, + ICON_FA_KEYBOARD_O) + .c_str())) { + mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard] = !keyboardVisible; + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + + for (auto [lusIndex, info] : indexMappings) { + auto [name, sdlIndex] = info; + bool connected = sdlIndex != -1; + + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + bool visible = mDeviceIndexVisiblity[lusIndex]; + if (ImGui::Button( + StringHelper::Sprintf("%s %s %s (%s)", visible ? ICON_FA_EYE : ICON_FA_EYE_SLASH, + connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN, name.c_str(), + connected ? StringHelper::Sprintf("SDL %d", sdlIndex).c_str() : "Disconnected") + .c_str())) { + mDeviceIndexVisiblity[lusIndex] = !visible; + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } +} + +void BenInputEditorWindow::DrawClearAllButton(uint8_t portIndex) { + if (ImGui::Button("Clear All", ImGui::CalcTextSize("Clear All") * 2)) { + ImGui::OpenPopup("Clear All##clearAllPopup"); + } + if (ImGui::BeginPopupModal("Clear All##clearAllPopup", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("This will clear all mappings for port %d.\n\nContinue?", portIndex + 1); + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Clear All")) { + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->ClearAllMappings(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawPortTab(uint8_t portIndex) { + if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d###port%d", portIndex + 1, portIndex).c_str())) { + DrawPortTabContents(portIndex); + ImGui::EndTabItem(); + } +} + +void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) { + DrawClearAllButton(portIndex); + DrawSetDefaultsButton(portIndex); + if (!Ship::Context::GetInstance()->GetControlDeck()->IsSinglePlayerMappingMode()) { + ImGui::SameLine(); + if (ImGui::Button("Reorder controllers")) { + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Controller Reordering")->Show(); + } + } + DrawDeviceVisibilityButtons(); + + UpdateBitmaskToMappingIds(portIndex); + UpdateStickDirectionToMappingIds(portIndex); + + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + + if (ImGui::CollapsingHeader("Buttons", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + DrawButtonDeviceIcons(portIndex, mButtonsBitmasks); + DrawButtonLine("A", portIndex, BTN_A, CHIP_COLOR_N64_BLUE); + DrawButtonLine("B", portIndex, BTN_B, CHIP_COLOR_N64_GREEN); + DrawButtonLine("Start", portIndex, BTN_START, CHIP_COLOR_N64_RED); + DrawButtonLine("L", portIndex, BTN_L); + DrawButtonLine("R", portIndex, BTN_R); + DrawButtonLine("Z", portIndex, BTN_Z); + DrawButtonLine(StringHelper::Sprintf("C %s", ICON_FA_ARROW_UP).c_str(), portIndex, BTN_CUP, + CHIP_COLOR_N64_YELLOW); + DrawButtonLine(StringHelper::Sprintf("C %s", ICON_FA_ARROW_DOWN).c_str(), portIndex, BTN_CDOWN, + CHIP_COLOR_N64_YELLOW); + DrawButtonLine(StringHelper::Sprintf("C %s", ICON_FA_ARROW_LEFT).c_str(), portIndex, BTN_CLEFT, + CHIP_COLOR_N64_YELLOW); + DrawButtonLine(StringHelper::Sprintf("C %s", ICON_FA_ARROW_RIGHT).c_str(), portIndex, BTN_CRIGHT, + CHIP_COLOR_N64_YELLOW); + } else { + DrawButtonDeviceIcons(portIndex, mButtonsBitmasks); + } + + if (ImGui::CollapsingHeader("D-Pad", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + DrawButtonDeviceIcons(portIndex, mDpadBitmasks); + DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_UP).c_str(), portIndex, BTN_DUP); + DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_DOWN).c_str(), portIndex, BTN_DDOWN); + DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_LEFT).c_str(), portIndex, BTN_DLEFT); + DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_RIGHT).c_str(), portIndex, BTN_DRIGHT); + } else { + DrawButtonDeviceIcons(portIndex, mDpadBitmasks); + } + + if (ImGui::CollapsingHeader("Analog Stick", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + DrawAnalogStickDeviceIcons(portIndex, Ship::LEFT_STICK); + DrawStickSection(portIndex, Ship::LEFT, 0); + } else { + DrawAnalogStickDeviceIcons(portIndex, Ship::LEFT_STICK); + } + + if (ImGui::CollapsingHeader("Additional (\"Right\") Stick")) { + DrawAnalogStickDeviceIcons(portIndex, Ship::RIGHT_STICK); + DrawStickSection(portIndex, Ship::RIGHT, 1, CHIP_COLOR_N64_YELLOW); + } else { + DrawAnalogStickDeviceIcons(portIndex, Ship::RIGHT_STICK); + } + + if (ImGui::CollapsingHeader("Rumble")) { + DrawRumbleDeviceIcons(portIndex); + DrawRumbleSection(portIndex); + } else { + DrawRumbleDeviceIcons(portIndex); + } + + if (ImGui::CollapsingHeader("Gyro")) { + DrawGyroDeviceIcons(portIndex); + DrawGyroSection(portIndex); + } else { + DrawGyroDeviceIcons(portIndex); + } + + if (ImGui::CollapsingHeader("LEDs")) { + DrawLEDDeviceIcons(portIndex); + DrawLEDSection(portIndex); + } else { + DrawLEDDeviceIcons(portIndex); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); +} + +void BenInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) { + ImGui::SameLine(); + auto popupId = StringHelper::Sprintf("setDefaultsPopup##%d", portIndex); + if (ImGui::Button(StringHelper::Sprintf("Set Defaults##%d", portIndex).c_str(), + ImVec2(ImGui::CalcTextSize("Set Defaults") * 2))) { + ImGui::OpenPopup(popupId.c_str()); + } + + if (ImGui::BeginPopup(popupId.c_str())) { + std::map> indexMappings; + for (auto [lusIndex, mapping] : Ship::Context::GetInstance() + ->GetControlDeck() + ->GetDeviceIndexMappingManager() + ->GetAllDeviceIndexMappings()) { + auto sdlIndexMapping = std::static_pointer_cast(mapping); + if (sdlIndexMapping == nullptr) { + continue; + } + + indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), sdlIndexMapping->GetSDLDeviceIndex() }; + } + + bool shouldClose = false; + ImGui::PushStyleColor(ImGuiCol_Button, BUTTON_COLOR_KEYBOARD_BEIGE); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED); + if (ImGui::Button(StringHelper::Sprintf("%s Keyboard", ICON_FA_KEYBOARD_O).c_str())) { + ImGui::OpenPopup("Set Defaults for Keyboard"); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + if (ImGui::BeginPopupModal("Set Defaults for Keyboard", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("This will clear all existing mappings for\nKeyboard on port %d.\n\nContinue?", portIndex + 1); + if (ImGui::Button("Cancel")) { + shouldClose = true; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Set defaults")) { + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->ClearAllMappingsForDevice(Ship::ShipDeviceIndex::Keyboard); + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->AddDefaultMappings( + Ship::ShipDeviceIndex::Keyboard); + shouldClose = true; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + for (auto [lusIndex, info] : indexMappings) { + auto [name, sdlIndex] = info; + + auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button); + auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); + GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor); + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor); + if (ImGui::Button(StringHelper::Sprintf("%s %s (%s)", ICON_FA_GAMEPAD, name.c_str(), + StringHelper::Sprintf("SDL %d", sdlIndex).c_str()) + .c_str())) { + ImGui::OpenPopup(StringHelper::Sprintf("Set Defaults for %s", name.c_str()).c_str()); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + if (ImGui::BeginPopupModal(StringHelper::Sprintf("Set Defaults for %s", name.c_str()).c_str(), NULL, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("This will clear all existing mappings for\n%s (SDL %d) on port %d.\n\nContinue?", + name.c_str(), sdlIndex, portIndex + 1); + if (ImGui::Button("Cancel")) { + shouldClose = true; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Set defaults")) { + Ship::Context::GetInstance() + ->GetControlDeck() + ->GetControllerByPort(portIndex) + ->ClearAllMappingsForDevice(lusIndex); + Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->AddDefaultMappings( + lusIndex); + shouldClose = true; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + + if (ImGui::Button("Cancel") || shouldClose) { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } +} + +void BenInputEditorWindow::DrawFullContents() { + ImGui::BeginTabBar("##ControllerConfigPortTabs"); + for (uint8_t i = 0; i < 4; i++) { + DrawPortTab(i); + } + ImGui::EndTabBar(); +} + +void BenInputEditorWindow::DrawElement() { + DrawFullContents(); +} diff --git a/mm/2s2h/BenGui/BenInputEditorWindow.h b/mm/2s2h/BenGui/BenInputEditorWindow.h new file mode 100644 index 000000000..adb1b8be8 --- /dev/null +++ b/mm/2s2h/BenGui/BenInputEditorWindow.h @@ -0,0 +1,90 @@ +#pragma once + +#include "stdint.h" +#include "window/gui/GuiWindow.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include +#include +#include +#include +#include +#include "controller/controldevice/controller/Controller.h" + +class BenInputEditorWindow : public Ship::GuiWindow { + public: + using Ship::GuiWindow::GuiWindow; + ~BenInputEditorWindow(); + + void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading); + + void DrawInputChip(const char* buttonName, ImVec4 color); + void DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone = 0, bool gyro = false); + void DrawControllerSchema(); + bool TestingRumble(); + void DrawFullContents(); + void DrawPortTabContents(uint8_t portIndex); + + protected: + void InitElement() override; + void DrawElement() override; + void UpdateElement() override; + + private: + void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, Ship::Direction direction, + ImVec4 color); + void DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask, ImVec4 color); + void DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id); + void DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask); + + void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction, + std::string id); + void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction); + void DrawStickSection(uint8_t port, uint8_t stick, int32_t id, ImVec4 color); + + void DrawRumbleSection(uint8_t port); + void DrawRemoveRumbleMappingButton(uint8_t port, std::string id); + void DrawAddRumbleMappingButton(uint8_t port); + + void DrawLEDSection(uint8_t port); + void DrawRemoveLEDMappingButton(uint8_t port, std::string id); + void DrawAddLEDMappingButton(uint8_t port); + + void DrawGyroSection(uint8_t port); + void DrawRemoveGyroMappingButton(uint8_t port, std::string id); + void DrawAddGyroMappingButton(uint8_t port); + + int32_t mGameInputBlockTimer; + int32_t mMappingInputBlockTimer; + int32_t mRumbleTimer; + std::shared_ptr mRumbleMappingToTest; + + // mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... } + std::unordered_map>> mBitmaskToMappingIds; + + // mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... } + std::unordered_map>>> + mStickDirectionToMappingIds; + + void UpdateBitmaskToMappingIds(uint8_t port); + void UpdateStickDirectionToMappingIds(uint8_t port); + + void GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor, + ImVec4& buttonHoveredColor); + void DrawPortTab(uint8_t portIndex); + std::set mButtonsBitmasks; + std::set mDpadBitmasks; + void DrawButtonDeviceIcons(uint8_t portIndex, std::set bitmasks); + void DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick); + void DrawRumbleDeviceIcons(uint8_t portIndex); + void DrawGyroDeviceIcons(uint8_t portIndex); + void DrawLEDDeviceIcons(uint8_t portIndex); + bool mInputEditorPopupOpen; + void DrawSetDefaultsButton(uint8_t portIndex); + void DrawClearAllButton(uint8_t portIndex); + + std::map mDeviceIndexVisiblity; + void DrawDeviceVisibilityButtons(); +}; diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 009f6c075..1a9ca3822 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -153,7 +153,7 @@ void DrawBenMenu() { } } -extern std::shared_ptr mInputEditorWindow; +extern std::shared_ptr mBenInputEditorWindow; void DrawSettingsMenu() { if (UIWidgets::BeginMenu("Settings")) { @@ -312,8 +312,8 @@ void DrawSettingsMenu() { // #region 2S2H [Todo] None of this works yet /* if (UIWidgets::BeginMenu("Controller")) { */ - if (mInputEditorWindow) { - UIWidgets::WindowButton("Controller Mapping", "gWindows.InputEditor", mInputEditorWindow); + if (mBenInputEditorWindow) { + UIWidgets::WindowButton("Controller Mapping", "gWindows.InputEditor", mBenInputEditorWindow); } /* #ifndef __SWITCH__ diff --git a/mm/2s2h/BenGui/BenMenuBar.h b/mm/2s2h/BenGui/BenMenuBar.h index 7f509f8fb..7342a0101 100644 --- a/mm/2s2h/BenGui/BenMenuBar.h +++ b/mm/2s2h/BenGui/BenMenuBar.h @@ -7,6 +7,7 @@ #include "DeveloperTools/ActorViewer.h" #include "DeveloperTools/CollisionViewer.h" #include "DeveloperTools/EventLog.h" +#include "BenInputEditorWindow.h" namespace BenGui { class BenMenuBar : public Ship::GuiMenuBar { diff --git a/mm/2s2h/BenGui/HudEditor.cpp b/mm/2s2h/BenGui/HudEditor.cpp index 95202bbbf..a14926542 100644 --- a/mm/2s2h/BenGui/HudEditor.cpp +++ b/mm/2s2h/BenGui/HudEditor.cpp @@ -167,12 +167,6 @@ enum Presets { }; void HudEditorWindow::DrawElement() { - ImGui::SetNextWindowSize(ImVec2(480, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Hud Editor", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::End(); - return; - } - static HudEditor::Presets preset = HudEditor::Presets::VANILLA; if (UIWidgets::Combobox("Preset", &preset, presetNames)) { for (int i = HUD_EDITOR_ELEMENT_B; i < HUD_EDITOR_ELEMENT_MAX; i++) { @@ -252,7 +246,9 @@ void HudEditorWindow::DrawElement() { } if (CVarGetInteger(hudEditorElements[i].modeCvar, HUD_EDITOR_ELEMENT_MODE_VANILLA) >= HUD_EDITOR_ELEMENT_MODE_MOVABLE_43) { - if (ImGui::BeginTable("##table", 3, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoBordersInBody)) { + if (ImGui::BeginTable("##table", 3, + ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoBordersInBody | + ImGuiTableFlags_SizingStretchSame)) { ImGui::TableNextColumn(); UIWidgets::CVarSliderInt("X", hudEditorElements[i].xCvar, -10, 330, hudEditorElements[i].defaultX, { @@ -279,6 +275,4 @@ void HudEditorWindow::DrawElement() { } ImGui::PopID(); } - - ImGui::End(); } diff --git a/mm/2s2h/BenGui/Menu.cpp b/mm/2s2h/BenGui/Menu.cpp new file mode 100644 index 000000000..c788bcc58 --- /dev/null +++ b/mm/2s2h/BenGui/Menu.cpp @@ -0,0 +1,471 @@ +#include "Menu.h" +#include "BenPort.h" +#include "BenGui.hpp" +#include "UIWidgets.hpp" +#include "graphic/Fast3D/gfx_rendering_api.h" +#include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/Enhancements/Graphics/MotionBlur.h" +#include "2s2h/Enhancements/Graphics/PlayAsKafei.h" +#include "2s2h/DeveloperTools/DeveloperTools.h" +#include "window/gui/GuiMenuBar.h" +#include "window/gui/GuiElement.h" +#include "DeveloperTools/SaveEditor.h" +#include "DeveloperTools/ActorViewer.h" +#include "DeveloperTools/CollisionViewer.h" +#include "DeveloperTools/EventLog.h" +#include "HudEditor.h" + +#include "SearchableMenuItems.h" + +extern "C" { +#include "z64.h" +#include "functions.h" +extern PlayState* gPlayState; +} +std::vector windowTypeSizes = { {} }; + +namespace BenGui { + +extern std::shared_ptr mHudEditorWindow; +extern std::shared_ptr mStatsWindow; +extern std::shared_ptr mConsoleWindow; +extern std::shared_ptr mGfxDebuggerWindow; +extern std::shared_ptr mSaveEditorWindow; +extern std::shared_ptr mActorViewerWindow; +extern std::shared_ptr mCollisionViewerWindow; +extern std::shared_ptr mEventLogWindow; +extern std::shared_ptr mBenInputEditorWindow; + +extern std::shared_ptr> availableWindowBackends; +extern std::unordered_map availableWindowBackendsMap; +extern Ship::WindowBackend configWindowBackend; +extern void UpdateWindowBackendObjects(); + +// BENTODO: Not implemented yet +// UIWidgets::CVarCheckbox("Widescreen Actor Culling", +// "gEnhancements.Graphics.ActorCullingAccountsForWidescreen", +// { .tooltip = "Adjusts the culling planes to account for widescreen resolutions. " +// "This may have unintended side effects." }); + +// if (gPlayState != NULL) { +// ImGui::Separator(); +// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_ENABLE); +// if (gPlayState->frameAdvCtx.enabled) { +// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_SINGLE); +// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_HOLD); +// if (ImGui::IsItemActive()) { +// CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); +// } +// } +// } +// ImGui::PushStyleColor(ImGuiCol_Button, menuTheme[menuThemeIndex]); +// RenderWarpPointSection(); +// ImGui::PopStyleColor(1); +//} + +BenMenu::BenMenu(const std::string& consoleVariable, const std::string& name) : GuiWindow(consoleVariable, name) { +} + +void BenMenu::InitElement() { + popped = CVarGetInteger("gSettings.Menu.Popout", 0); + poppedSize.x = CVarGetInteger("gSettings.Menu.PoppedWidth", 1280); + poppedSize.y = CVarGetInteger("gSettings.Menu.PoppedHeight", 800); + poppedPos.x = CVarGetInteger("gSettings.Menu.PoppedPos.x", 0); + poppedPos.y = CVarGetInteger("gSettings.Menu.PoppedPos.y", 0); + AddSettings(); + AddEnhancements(); + AddDevTools(); + + menuEntries = { { "Settings", settingsSidebar, "gSettings.Menu.SettingsSidebarIndex" }, + { "Enhancements", enhancementsSidebar, "gSettings.Menu.EnhancementsSidebarIndex" }, + { "Developer Tools", devToolsSidebar, "gSettings.Menu.DevToolsSidebarIndex" } }; + + UpdateWindowBackendObjects(); +} + +void BenMenu::UpdateElement() { +} + +bool ModernMenuSidebarEntry(std::string label) { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = ImGui::GetStyle(); + ImVec2 pos = window->DC.CursorPos; + const ImGuiID sidebarId = window->GetID(std::string(label + "##Sidebar").c_str()); + ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true); + pos.y += style.FramePadding.y; + pos.x = window->WorkRect.GetCenter().x - labelSize.x / 2; + ImRect bb = { pos - style.FramePadding, pos + labelSize + style.FramePadding }; + ImGui::ItemSize(bb, style.FramePadding.y); + ImGui::ItemAdd(bb, sidebarId); + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(bb, sidebarId, &hovered, &held); + if (pressed) { + ImGui::MarkItemEdited(sidebarId); + } + window->DrawList->AddRectFilled(pos - style.FramePadding, pos + labelSize + style.FramePadding, + ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button), + 3.0f); + UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true); + return pressed; +} + +bool ModernMenuHeaderEntry(std::string label) { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = ImGui::GetStyle(); + ImVec2 pos = window->DC.CursorPos; + const ImGuiID headerId = window->GetID(std::string(label + "##Header").c_str()); + ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true); + ImRect bb = { pos, pos + labelSize + style.FramePadding * 2 }; + ImGui::ItemSize(bb, style.FramePadding.y); + ImGui::ItemAdd(bb, headerId); + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(bb, headerId, &hovered, &held); + window->DrawList->AddRectFilled(bb.Min, bb.Max, + ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button), + 3.0f); + pos += style.FramePadding; + UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true); + return pressed; +} + +void BenMenu::Draw() { + if (!IsVisible()) { + return; + } + DrawElement(); + // Sync up the IsVisible flag if it was changed by ImGui + SyncVisibilityConsoleVariable(); +} + +void BenMenu::DrawElement() { + for (auto& [reason, info] : disabledMap) { + info.active = info.evaluation(info); + } + menuThemeIndex = static_cast(CVarGetInteger("gSettings.MenuTheme", 3)); + + windowHeight = ImGui::GetMainViewport()->WorkSize.y; + windowWidth = ImGui::GetMainViewport()->WorkSize.x; + auto windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; + bool popout = CVarGetInteger("gSettings.Menu.Popout", 0) && allowPopout; + if (popout) { + windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDocking; + } + if (popout != popped) { + if (popout) { + windowHeight = poppedSize.y; + windowWidth = poppedSize.x; + ImGui::SetNextWindowSize({ static_cast(windowWidth), static_cast(windowHeight) }, + ImGuiCond_Always); + ImGui::SetNextWindowPos(poppedPos, ImGuiCond_Always); + } else if (popped) { + CVarSetFloat("gSettings.Menu.PoppedWidth", poppedSize.x); + CVarSetFloat("gSettings.Menu.PoppedHeight", poppedSize.y); + CVarSave(); + } + } + popped = popout; + auto windowCond = ImGuiCond_Always; + if (!popout) { + ImGui::SetNextWindowSize({ static_cast(windowWidth), static_cast(windowHeight) }, windowCond); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), windowCond, { 0.5f, 0.5f }); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + } + if (!ImGui::Begin("Main Menu", NULL, windowFlags | ImGuiWindowFlags_NoBringToFrontOnFocus)) { + if (!popout) { + ImGui::PopStyleVar(); + } + ImGui::End(); + return; + } + if (popped != popout) { + if (!popout) { + ImGui::PopStyleVar(); + } + CVarSetInteger("gSettings.Menu.Popout", popped); + CVarSetFloat("gSettings.Menu.PoppedWidth", poppedSize.x); + CVarSetFloat("gSettings.Menu.PoppedHeight", poppedSize.y); + CVarSetFloat("gSettings.Menu.PoppedPos.x", poppedSize.x); + CVarSetFloat("gSettings.Menu.PoppedPos.y", poppedSize.y); + CVarSave(); + ImGui::End(); + return; + } + ImGui::PushFont(OTRGlobals::Instance->fontStandardLargest); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = ImGui::GetStyle(); + windowHeight = window->WorkRect.GetHeight(); + windowWidth = window->WorkRect.GetWidth(); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f)); + auto sectionCount = menuEntries.size(); + const char* headerCvar = "gSettings.Menu.SelectedHeader"; + uint8_t headerIndex = CVarGetInteger(headerCvar, 0); + ImVec2 pos = window->DC.CursorPos; + float centerX = pos.x + windowWidth / 2 - (style.ItemSpacing.x * (sectionCount + 1)); + std::vector headerSizes; + float headerWidth = 200.0f + style.ItemSpacing.x; + for (int i = 0; i < sectionCount; i++) { + ImVec2 size = ImGui::CalcTextSize(menuEntries.at(i).label.c_str()); + headerSizes.push_back(size); + headerWidth += size.x + style.FramePadding.x * 2; + if (i + 1 < sectionCount) { + headerWidth += style.ItemSpacing.x; + } + } + ImVec2 menuSize = { std::fminf(1280, windowWidth), std::fminf(800, windowHeight) }; + pos += window->WorkRect.GetSize() / 2 - menuSize / 2; + ImGui::SetNextWindowPos(pos); + ImGui::BeginChild("Menu Block", menuSize, + ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar); + + std::vector sidebar; + float headerHeight = headerSizes.at(0).y + style.FramePadding.y * 2; + ImVec2 buttonSize = ImGui::CalcTextSize(ICON_FA_TIMES_CIRCLE) + style.FramePadding * 2; + bool scrollbar = false; + if (headerWidth > menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3) { + headerHeight += style.ScrollbarSize; + scrollbar = true; + } + if (UIWidgets::Button(ICON_FA_TIMES_CIRCLE, { .size = UIWidgets::Sizes::Inline, .tooltip = "Close Menu (Esc)" })) { + ToggleVisibility(); + } + ImGui::SameLine(); + ImGui::SetNextWindowSizeConstraints({ 0, headerHeight }, { headerWidth, headerHeight }); + ImVec2 headerSelSize = { menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3, headerHeight }; + if (scrollbar) { + headerSelSize.y += style.ScrollbarSize; + } + bool autoFocus = CVarGetInteger("gSettings.SearchAutofocus", 0); + bool headerSearch = !CVarGetInteger("gSettings.SidebarSearch", 0); + ImGui::BeginChild("Header Selection", headerSelSize, + ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_HorizontalScrollbar); + for (int i = 0; i < sectionCount; i++) { + auto entry = menuEntries.at(i); + uint8_t nextIndex = i; + UIWidgets::PushStyleButton(menuTheme[menuThemeIndex]); + if (headerIndex != i) { + ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 }); + } + if (ModernMenuHeaderEntry(entry.label)) { + if (autoFocus) { + menuSearch.Clear(); + } + CVarSetInteger(headerCvar, i); + CVarSave(); + nextIndex = i; + } + if (headerIndex != i) { + ImGui::PopStyleColor(); + } + UIWidgets::PopStyleButton(); + if (headerIndex == i) { + sidebar = entry.sidebarEntries; + } + if (i + 1 < sectionCount) { + ImGui::SameLine(); + } + if (nextIndex != i) { + headerIndex = nextIndex; + } + } + std::string menuSearchText = ""; + if (headerSearch) { + ImGui::SameLine(); + if (autoFocus && ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() && + !ImGui::IsMouseClicked(0)) { + ImGui::SetKeyboardFocusHere(0); + } + ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0, 0, 0, 0 }); + menuSearch.Draw("##search", 200.0f); + menuSearchText = menuSearch.InputBuf; + if (menuSearchText.length() < 1) { + ImGui::SameLine(headerWidth - 200.0f + style.ItemSpacing.x); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Search..."); + } + ImGui::PopStyleColor(); + } + ImGui::EndChild(); + ImGui::SameLine(menuSize.x - (buttonSize.x * 2) - style.ItemSpacing.x); + if (UIWidgets::Button(ICON_FA_UNDO, { .color = UIWidgets::Colors::Red, + .size = UIWidgets::Sizes::Inline, + .tooltip = "Reset" +#ifdef __APPLE__ + " (Command-R)" +#elif !defined(__SWITCH__) && !defined(__WIIU__) + " (Ctrl+R)" +#else + "" +#endif + })) { + std::reinterpret_pointer_cast( + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) + ->Dispatch("reset"); + } + ImGui::SameLine(); + if (UIWidgets::Button( + ICON_FA_POWER_OFF, + { .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline, .tooltip = "Quit 2S2H" })) { + if (!popped) { + ToggleVisibility(); + } + Ship::Context::GetInstance()->GetWindow()->Close(); + } + ImGui::PopStyleVar(); + + pos.y += headerHeight + style.ItemSpacing.y; + pos.x = centerX - menuSize.x / 2 + (style.ItemSpacing.x * (sectionCount + 1)); + window->DrawList->AddRectFilled(pos, pos + ImVec2{ menuSize.x, 4 }, ImGui::GetColorU32({ 255, 255, 255, 255 }), + true, style.WindowRounding); + pos.y += style.ItemSpacing.y; + float sectionHeight = menuSize.y - headerHeight - 4 - style.ItemSpacing.y * 2; + float columnHeight = sectionHeight - style.ItemSpacing.y * 4; + ImGui::SetNextWindowPos(pos + style.ItemSpacing * 2); + float sidebarWidth = 200 - style.ItemSpacing.x; + + const char* sidebarCvar = menuEntries.at(headerIndex).sidebarCvar; + + uint8_t sectionIndex = CVarGetInteger(sidebarCvar, 0); + if (sectionIndex > sidebar.size() - 1) + sectionIndex = sidebar.size() - 1; + if (sectionIndex < 0) + sectionIndex = 0; + float sectionCenterX = pos.x + (sidebarWidth / 2); + float topY = pos.y; + ImGui::SetNextWindowSizeConstraints({ sidebarWidth, 0 }, { sidebarWidth, columnHeight }); + ImGui::BeginChild((menuEntries.at(headerIndex).label + " Section").c_str(), { sidebarWidth, columnHeight * 3 }, + ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoTitleBar); + for (size_t i = 0; i < sidebar.size(); i++) { + auto sidebarEntry = sidebar.at(i); + uint8_t nextIndex = i; + UIWidgets::PushStyleButton(menuTheme[menuThemeIndex]); + if (sectionIndex != i) { + ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 }); + } + if (ModernMenuSidebarEntry(sidebarEntry.label)) { + if (autoFocus) { + menuSearch.Clear(); + } + CVarSetInteger(sidebarCvar, i); + CVarSave(); + nextIndex = i; + } + if (sectionIndex != i) { + ImGui::PopStyleColor(); + } + UIWidgets::PopStyleButton(); + if (nextIndex != i) { + sectionIndex = i; + } + } + ImGui::EndChild(); + + ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger); + pos = ImVec2{ sectionCenterX + (sidebarWidth / 2), topY } + style.ItemSpacing * 2; + window->DrawList->AddRectFilled(pos, pos + ImVec2{ 4, sectionHeight - style.FramePadding.y * 2 }, + ImGui::GetColorU32({ 255, 255, 255, 255 }), true, style.WindowRounding); + pos.x += 4 + style.ItemSpacing.x; + ImGui::SetNextWindowPos(pos + style.ItemSpacing); + float sectionWidth = menuSize.x - sidebarWidth - 4 - style.ItemSpacing.x * 4; + std::string sectionMenuId = sidebar.at(sectionIndex).label + " Settings"; + int columns = sidebar.at(sectionIndex).columnCount; + size_t columnFuncs = sidebar.at(sectionIndex).columnWidgets.size(); + if (windowWidth < 800) { + columns = 1; + } + float columnWidth = (sectionWidth - style.ItemSpacing.x * columns) / columns; + bool useColumns = columns > 1; + if (!useColumns || (headerSearch && menuSearchText.length() > 0)) { + ImGui::SameLine(); + ImGui::SetNextWindowSizeConstraints({ sectionWidth, 0 }, { sectionWidth, columnHeight }); + ImGui::BeginChild(sectionMenuId.c_str(), { sectionWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY, + ImGuiWindowFlags_NoTitleBar); + } + if (headerSearch && menuSearchText.length() > 0) { + ImGui::BeginChild("Search Results"); + int searchCount = 0; + for (auto& [menuLabel, menuSidebar, cvar] : menuEntries) { + for (auto& sidebar : menuSidebar) { + for (auto& widgets : sidebar.columnWidgets) { + int column = 1; + for (auto& info : widgets) { + if (info.widgetType == WIDGET_SEPARATOR || info.widgetType == WIDGET_SEPARATOR_TEXT || + info.isHidden) { + continue; + } + std::string widgetStr = std::string(info.widgetName) + std::string(info.widgetTooltip); + std::transform(menuSearchText.begin(), menuSearchText.end(), menuSearchText.begin(), ::tolower); + menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), + menuSearchText.end()); + std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower); + widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end()); + if (widgetStr.find(menuSearchText) != std::string::npos) { + SearchMenuGetItem(info); + searchCount++; + ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::Colors::Gray); + std::string origin = fmt::format(" ({} -> {}, Clmn {})", menuLabel, sidebar.label, column); + ImGui::Text("%s", origin.c_str()); + ImGui::PopStyleColor(); + } + } + column++; + } + } + } + + if (searchCount == 0) { + ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("No results found").x) / 2); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "No results found"); + ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("Clear Search").x) / 2 - 10.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + if (UIWidgets::Button("Clear Search", { .size = UIWidgets::Sizes::Inline })) { + menuSearch.Clear(); + } + } + + ImGui::EndChild(); + } else { + for (int i = 0; i < columnFuncs; i++) { + std::string sectionId = fmt::format("{} Column {}", sectionMenuId, i); + if (useColumns) { + ImGui::SetNextWindowSizeConstraints({ columnWidth, 0 }, { columnWidth, columnHeight }); + ImGui::BeginChild(sectionId.c_str(), { columnWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY, + ImGuiWindowFlags_NoTitleBar); + } + for (auto& entry : sidebar.at(sectionIndex).columnWidgets.at(i)) { + SearchMenuGetItem(entry); + } + if (useColumns) { + ImGui::EndChild(); + } + if (i < columns - 1) { + ImGui::SameLine(); + } + } + } + if (!useColumns || menuSearchText.length() > 0) { + ImGui::EndChild(); + } + ImGui::PopFont(); + ImGui::PopFont(); + + if (!popout) { + ImGui::PopStyleVar(); + } + ImGui::EndChild(); + if (popout) { + poppedSize = ImGui::GetWindowSize(); + poppedPos = ImGui::GetWindowPos(); + } + ImGui::End(); +} +} // namespace BenGui diff --git a/mm/2s2h/BenGui/Menu.h b/mm/2s2h/BenGui/Menu.h new file mode 100644 index 000000000..ddfb2a57e --- /dev/null +++ b/mm/2s2h/BenGui/Menu.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "UIWidgets.hpp" + +namespace BenGui { +class BenMenu : public Ship::GuiWindow { + public: + using Ship::GuiWindow::GuiWindow; + + BenMenu(const std::string& consoleVariable, const std::string& name); + + void InitElement() override; + void DrawElement() override; + void UpdateElement() override; + void Draw() override; + + protected: + ImVec2 mOriginalSize; + std::string mName; + uint32_t mWindowFlags; + + private: + bool allowPopout = true; // PortNote: should be set to false on small screen ports + bool popped; + ImVec2 poppedSize; + ImVec2 poppedPos; + float windowHeight; + float windowWidth; +}; +} // namespace BenGui \ No newline at end of file diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h new file mode 100644 index 000000000..a8d8c846f --- /dev/null +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -0,0 +1,1705 @@ +#include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/DeveloperTools/DeveloperTools.h" +#include "2s2h/Enhancements/Graphics/3DItemDrops.h" +#include "UIWidgets.hpp" +#include "BenMenuBar.h" +#include "macros.h" +#include "variables.h" +#include +#include + +extern "C" { +#include "functions.h" +extern PlayState* gPlayState; +} + +typedef enum { + COLOR_WHITE, + COLOR_GRAY, + COLOR_DARK_GRAY, + COLOR_INDIGO, + COLOR_RED, + COLOR_DARK_RED, + COLOR_LIGHT_GREEN, + COLOR_GREEN, + COLOR_DARK_GREEN, + COLOR_YELLOW, +} ColorOption; + +typedef enum { + DISABLE_FOR_CAMERAS_OFF, + DISABLE_FOR_DEBUG_CAM_ON, + DISABLE_FOR_DEBUG_CAM_OFF, + DISABLE_FOR_FREE_LOOK_ON, + DISABLE_FOR_FREE_LOOK_OFF, + DISABLE_FOR_AUTO_SAVE_OFF, + DISABLE_FOR_NULL_PLAY_STATE, + DISABLE_FOR_DEBUG_MODE_OFF, + DISABLE_FOR_NO_VSYNC, + DISABLE_FOR_NO_WINDOWED_FULLSCREEN, + DISABLE_FOR_NO_MULTI_VIEWPORT, + DISABLE_FOR_NOT_DIRECTX, + DISABLE_FOR_DIRECTX, + DISABLE_FOR_MATCH_REFRESH_RATE_ON, + DISABLE_FOR_MOTION_BLUR_MODE, + DISABLE_FOR_MOTION_BLUR_OFF, + DISABLE_FOR_FRAME_ADVANCE_OFF, + DISABLE_FOR_WARP_POINT_NOT_SET +} DisableOption; + +struct widgetInfo; +struct disabledInfo; +using VoidFunc = void (*)(); +using DisableInfoFunc = bool (*)(disabledInfo&); +using DisableVec = std::vector; +using WidgetFunc = void (*)(widgetInfo&); +std::string disabledTempTooltip; +const char* disabledTooltip; +bool disabledValue = false; +ColorOption menuThemeIndex = COLOR_INDIGO; +const ImVec4 COLOR_NONE = { 0, 0, 0, 0 }; + +typedef enum { + WIDGET_CHECKBOX, + WIDGET_COMBOBOX, + WIDGET_SLIDER_INT, + WIDGET_SLIDER_FLOAT, + WIDGET_CVAR_CHECKBOX, + WIDGET_CVAR_COMBOBOX, + WIDGET_CVAR_SLIDER_INT, + WIDGET_CVAR_SLIDER_FLOAT, + WIDGET_BUTTON, + WIDGET_COLOR_24, // color picker without alpha + WIDGET_COLOR_32, // color picker with alpha + WIDGET_SEARCH, + WIDGET_SEPARATOR, + WIDGET_SEPARATOR_TEXT, + WIDGET_TEXT, + WIDGET_WINDOW_BUTTON, + WIDGET_AUDIO_BACKEND, // needed because of special operations that can't be handled easily with the normal combobox + // widget + WIDGET_VIDEO_BACKEND // same as above +} WidgetType; + +typedef enum { + MOTION_BLUR_DYNAMIC, + MOTION_BLUR_ALWAYS_OFF, + MOTION_BLUR_ALWAYS_ON, +} MotionBlurOption; + +typedef enum { + DEBUG_LOG_TRACE, + DEBUG_LOG_DEBUG, + DEBUG_LOG_INFO, + DEBUG_LOG_WARN, + DEBUG_LOG_ERROR, + DEBUG_LOG_CRITICAL, + DEBUG_LOG_OFF, +} DebugLogOption; + +// holds the widget values for a widget, contains all CVar types available from LUS. int32_t is used for boolean +// evaluation +using CVarVariant = std::variant; + +// contains various information used to display specific types of widgets +// `min` and `max` are usually only used by sliders +// `defaultVariant` can be used by all widgetTypes, but defaults to 0, "", 0.0f, and white respectively, so only needed +// when you want to change those defaults +// `comboBoxOptions` is the list of dropdown options to be added to a dropdown. +// this needs to be a map of int32_t to const char*, but can also be enum values +// `valuePointer` is used for non-CVar sliders to track current widgetValue +// `size` applies only to buttons, determines whether it stretches to fill its current container or only fits its text +// `color` can be used in any way, depending on the widget. color pickers (COLOR_24 and COLOR_32) will eventually +// use this for storing its current value; WIDGET_SEPARATOR_TEXT uses this to change the text color `windowName` +// is used when using WIDGET_WINDOW_BUTTON, which optionally draws windows, like Stats, in the menu with a button +// to pop the window out of the main menu overlay +// `windowName` is what is displayed and searched for `windowButton` type and window interactions +// `labelPosition` applies to checkbox, combobox and button types. specifies label orientation compared to widget body +// `sameLine` allows widgets to be displayed on the same line as the previously registered widget +// the next three only apply to sliders. `showButtons` shows or hides the +/- buttons on either side of a slider +// `format` specifies how info is displayed within the slider +// `isPercentage` toggles the float slider's value being multiplied by 100 to show percentages instead of direct floats +struct WidgetOptions { + CVarVariant min; + CVarVariant max; + CVarVariant defaultVariant; + std::unordered_map comboBoxOptions; + std::variant valuePointer; + ImVec2 size = UIWidgets::Sizes::Fill; + ImVec4 color = COLOR_NONE; + const char* windowName = ""; + UIWidgets::LabelPosition labelPosition = UIWidgets::LabelPosition::None; + bool sameLine = false; + bool showButtons = true; + const char* format = "%f"; + bool isPercentage = false; +}; + +bool operator==(Color_RGB8 const& l, Color_RGB8 const& r) noexcept { + return l.r == r.r && l.g == r.g && l.b == r.b; +} + +bool operator==(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept { + return l.r == r.r && l.g == r.g && l.b == r.b && l.a == r.a; +} + +bool operator<(Color_RGB8 const& l, Color_RGB8 const& r) noexcept { + return (l.r < r.r && l.g <= r.g && l.b <= r.b) || (l.r <= r.r && l.g < r.g && l.b <= r.b) || + (l.r <= r.r && l.g <= r.g && l.b < r.b); +} + +bool operator<(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept { + return (l.r < r.r && l.g <= r.g && l.b <= r.b && l.a <= r.a) || + (l.r <= r.r && l.g < r.g && l.b <= r.b && l.a <= r.a) || + (l.r <= r.r && l.g <= r.g && l.b < r.b && l.a <= r.a) || + (l.r <= r.r && l.g <= r.g && l.b <= r.b && l.a < r.a); +} + +bool operator>(Color_RGB8 const& l, Color_RGB8 const& r) noexcept { + return (l.r > r.r && l.g >= r.g && l.b >= r.b) || (l.r >= r.r && l.g > r.g && l.b >= r.b) || + (l.r >= r.r && l.g >= r.g && l.b > r.b); +} + +bool operator>(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept { + return (l.r > r.r && l.g >= r.g && l.b >= r.b && l.a >= r.a) || + (l.r >= r.r && l.g > r.g && l.b >= r.b && l.a >= r.a) || + (l.r >= r.r && l.g >= r.g && l.b > r.b && l.a >= r.a) || + (l.r >= r.r && l.g >= r.g && l.b >= r.b && l.a > r.a); +} + +std::unordered_map menuTheme = { { COLOR_WHITE, UIWidgets::Colors::White }, + { COLOR_GRAY, UIWidgets::Colors::Gray }, + { COLOR_DARK_GRAY, UIWidgets::Colors::DarkGray }, + { COLOR_INDIGO, UIWidgets::Colors::Indigo }, + { COLOR_RED, UIWidgets::Colors::Red }, + { COLOR_DARK_RED, UIWidgets::Colors::DarkRed }, + { COLOR_LIGHT_GREEN, UIWidgets::Colors::LightGreen }, + { COLOR_GREEN, UIWidgets::Colors::Green }, + { COLOR_DARK_GREEN, UIWidgets::Colors::DarkGreen }, + { COLOR_YELLOW, UIWidgets::Colors::Yellow } }; + +// All the info needed for display and search of all widgets in the menu. WidgetName is the label displayed, +// `widgetCVar` is the string representation of the CVar used to store the widget value +// `widgetTooltip` is what is displayed when hovering (except when disabled, more on that later) +// `widgetType` is the WidgetType for the widget, which is what determines how the information is used in the draw +// function. all of the preceding are required parts for every widget except for the special widgets (backend dropdowns, +// separators, etc) various parts of widgetOptions are required depending on what widget type you're using +// `widgetCallback` is a lambda used for running code on widget change +// `preFunc` is a lambda called before drawing code starts. It can be used to determine a widget's status, +// whether disabled or hidden, as well as update pointers for non-CVar widget types. +// `postFunc` is a lambda called after all drawing code is finished, for reacting to states other than +// widgets having been changed, like holding buttons. +// All three lambdas accept a `widgetInfo` pointer in case it needs information on the widget for these operations +// `activeDisables` is a vector of DisableOptions for specifying what reasons a widget is disabled, which are displayed +// in the disabledTooltip for the widget. Can display multiple reasons. Handling the reasons is done in `modifierFunc`. +// It is recommended to utilize `disabledInfo`/`DisableReason` to list out all reasons for disabling and isHidden so +// the info can be shown. +// `isHidden` just prevents the widget from being drawn under whatever circumstances you specify in the `modifierFunc` +struct widgetInfo { + std::string widgetName; // Used by all widgets + const char* widgetCVar; // Used by all widgets except + const char* widgetTooltip; + WidgetType widgetType; + WidgetOptions widgetOptions; + WidgetFunc widgetCallback = nullptr; + WidgetFunc preFunc = nullptr; + WidgetFunc postFunc = nullptr; + DisableVec activeDisables = {}; + bool isHidden = false; +}; + +// `disabledInfo` holds information on reasons for hiding or disabling a widget, as well as an evaluation lambda that +// is run once per frame to update its status (this is done to prevent dozens of redundant CVarGets in each frame loop) +// `evaluation` returns a bool which can be determined by whatever code you want that changes its status +// `reason` is the text displayed in the disabledTooltip when a widget is disabled by a particular DisableReason +// `active` is what's referenced when determining disabled status for a widget that uses this This can also be used to +// hold reasons to hide widgets so taht their evaluations are also only run once per frame +struct disabledInfo { + DisableInfoFunc evaluation; + const char* reason; + bool active = false; + int32_t value = 0; +}; + +// Contains the name displayed in the sidebar (label), the number of columns to use in drawing (columnCount; for visual +// separation, 1-3), and nested vectors of the widgets, grouped by column (columnWidgets). The number of widget vectors +// added to the column groups does not need to match the specified columnCount, e.g. you can have one vector added to +// the sidebar, but still separate the window into 3 columns and display only in the first column +struct SidebarEntry { + std::string label; + uint32_t columnCount; + std::vector> columnWidgets; +}; + +// Contains entries for what's listed in the header at the top, including the name displayed on the top bar (label), +// a vector of the SidebarEntries for that header entry, and the name of the cvar used to track what sidebar entry is +// the last viewed for that header. +struct MainMenuEntry { + std::string label; + std::vector sidebarEntries; + const char* sidebarCvar; +}; +extern std::unordered_map warpPointSceneList; +extern void Warp(); + +namespace BenGui { +extern std::shared_ptr> availableWindowBackends; +extern std::unordered_map availableWindowBackendsMap; +extern Ship::WindowBackend configWindowBackend; +extern void UpdateWindowBackendObjects(); + +std::vector menuEntries; +static ImGuiTextFilter menuSearch; +std::vector settingsSidebar; +std::vector enhancementsSidebar; +std::vector devToolsSidebar; +uint8_t searchSidebarIndex = 0; +SidebarEntry searchSidebarEntry = { + "Search", + 1, + { { { "Menu Theme", "", "Searches all menus for the given text, including tooltips.", WIDGET_SEARCH } } } +}; + +static std::map disabledMap = { + { DISABLE_FOR_CAMERAS_OFF, + { [](disabledInfo& info) -> bool { + return !CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0) && + !CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0); + }, + "Both Debug Camera and Free Look are Disabled" } }, + { DISABLE_FOR_DEBUG_CAM_ON, + { [](disabledInfo& info) -> bool { return CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0); }, + "Debug Camera is Enabled" } }, + { DISABLE_FOR_DEBUG_CAM_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0); }, + "Debug Camera is Disabled" } }, + { DISABLE_FOR_FREE_LOOK_ON, + { [](disabledInfo& info) -> bool { return CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0); }, + "Free Look is Enabled" } }, + { DISABLE_FOR_FREE_LOOK_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0); }, + "Free Look is Disabled" } }, + { DISABLE_FOR_AUTO_SAVE_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Saving.Autosave", 0); }, + "AutoSave is Disabled" } }, + { DISABLE_FOR_NULL_PLAY_STATE, + { [](disabledInfo& info) -> bool { return gPlayState == NULL; }, "Save Not Loaded" } }, + { DISABLE_FOR_DEBUG_MODE_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gDeveloperTools.DebugEnabled", 0); }, + "Debug Mode is Disabled" } }, + { DISABLE_FOR_NO_VSYNC, + { [](disabledInfo& info) -> bool { return !Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync(); }, + "Disabling VSync not supported" } }, + { DISABLE_FOR_NO_WINDOWED_FULLSCREEN, + { [](disabledInfo& info) -> bool { + return !Ship::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen(); + }, + "Windowed Fullscreen not supported" } }, + { DISABLE_FOR_NO_MULTI_VIEWPORT, + { [](disabledInfo& info) -> bool { + return !Ship::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports(); + }, + "Multi-viewports not supported" } }, + { DISABLE_FOR_NOT_DIRECTX, + { [](disabledInfo& info) -> bool { + return Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() != + Ship::WindowBackend::FAST3D_DXGI_DX11; + }, + "Available Only on DirectX" } }, + { DISABLE_FOR_DIRECTX, + { [](disabledInfo& info) -> bool { + return Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == + Ship::WindowBackend::FAST3D_DXGI_DX11; + }, + "Not Available on DirectX" } }, + { DISABLE_FOR_MATCH_REFRESH_RATE_ON, + { [](disabledInfo& info) -> bool { return CVarGetInteger("gMatchRefreshRate", 0); }, + "Match Refresh Rate is Enabled" } }, + { DISABLE_FOR_MOTION_BLUR_MODE, + { [](disabledInfo& info) -> bool { + info.value = CVarGetInteger("gEnhancements.Graphics.MotionBlur.Mode", 0); + return !info.value; + }, + "Motion Blur Mode mismatch" } }, + { DISABLE_FOR_MOTION_BLUR_OFF, + { [](disabledInfo& info) -> bool { return !R_MOTION_BLUR_ENABLED; }, "Motion Blur is Disabled" } }, + { DISABLE_FOR_FRAME_ADVANCE_OFF, + { [](disabledInfo& info) -> bool { return !(gPlayState != nullptr && gPlayState->frameAdvCtx.enabled); }, + "Frame Advance is Disabled" } }, + { DISABLE_FOR_WARP_POINT_NOT_SET, + { [](disabledInfo& info) -> bool { return !CVarGetInteger(WARP_POINT_CVAR "Saved", 0); }, + "Warp Point Not Saved" } } +}; + +std::unordered_map menuThemeOptions = { + { COLOR_WHITE, "White" }, + { COLOR_GRAY, "Gray" }, + { COLOR_DARK_GRAY, "Dark Gray" }, + { COLOR_INDIGO, "Indigo" }, + { COLOR_RED, "Red" }, + { COLOR_DARK_RED, "Dark Red" }, + { COLOR_LIGHT_GREEN, "Light Green" }, + { COLOR_GREEN, "Green" }, + { COLOR_DARK_GREEN, "Dark Green" }, + { COLOR_YELLOW, "Yellow" }, +}; + +static const std::unordered_map alwaysWinDoggyraceOptions = { + { ALWAYS_WIN_DOGGY_RACE_OFF, "Off" }, + { ALWAYS_WIN_DOGGY_RACE_MASKOFTRUTH, "When owning Mask of Truth" }, + { ALWAYS_WIN_DOGGY_RACE_ALWAYS, "Always" }, +}; + +static const std::unordered_map clockTypeOptions = { + { CLOCK_TYPE_ORIGINAL, "Original" }, + { CLOCK_TYPE_3DS, "MM3D style" }, + { CLOCK_TYPE_TEXT_BASED, "Text only" }, +}; + +static const std::unordered_map textureFilteringMap = { + { FILTER_THREE_POINT, "Three-Point" }, + { FILTER_LINEAR, "Linear" }, + { FILTER_NONE, "None" }, +}; + +static const std::unordered_map motionBlurOptions = { + { MOTION_BLUR_DYNAMIC, "Dynamic (default)" }, + { MOTION_BLUR_ALWAYS_OFF, "Always Off" }, + { MOTION_BLUR_ALWAYS_ON, "Always On" }, +}; + +static const std::unordered_map debugSaveOptions = { + { DEBUG_SAVE_INFO_COMPLETE, "100\% save" }, + { DEBUG_SAVE_INFO_VANILLA_DEBUG, "Vanilla debug save" }, + { DEBUG_SAVE_INFO_NONE, "Empty save" }, +}; + +static const std::unordered_map logLevels = { + { DEBUG_LOG_TRACE, "Trace" }, { DEBUG_LOG_DEBUG, "Debug" }, { DEBUG_LOG_INFO, "Info" }, + { DEBUG_LOG_WARN, "Warn" }, { DEBUG_LOG_ERROR, "Error" }, { DEBUG_LOG_CRITICAL, "Critical" }, + { DEBUG_LOG_OFF, "Off" }, +}; + +static const std::unordered_map audioBackendsMap = { + { Ship::AudioBackend::WASAPI, "Windows Audio Session API" }, + { Ship::AudioBackend::SDL, "SDL" }, +}; + +static std::unordered_map windowBackendsMap = { + { Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" }, + { Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL" }, + { Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" }, +}; + +static const std::unordered_map timeStopOptions = { + { TIME_STOP_OFF, "Off" }, + { TIME_STOP_TEMPLES, "Temples" }, + { TIME_STOP_TEMPLES_DUNGEONS, "Temples + Mini Dungeons" }, +}; + +void FreeLookPitchMinMax() { + f32 maxY = CVarGetFloat("gEnhancements.Camera.FreeLook.MaxPitch", 72.0f); + f32 minY = CVarGetFloat("gEnhancements.Camera.FreeLook.MinPitch", -49.0f); + CVarSetFloat("gEnhancements.Camera.FreeLook.MaxPitch", std::max(maxY, minY)); + CVarSetFloat("gEnhancements.Camera.FreeLook.MinPitch", std::min(maxY, minY)); +} + +void AddSettings() { + // General Settings + settingsSidebar.push_back( + { "General", + 3, + { { + { "Menu Theme", + "gSettings.MenuTheme", + "Changes the Theme of the Menu Widgets.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = menuThemeOptions } }, +#if not defined(__SWITCH__) and not defined(__WIIU__) + { "Menubar Controller Navigation", CVAR_IMGUI_CONTROLLER_NAV, + "Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: " + "This will disable game inputs while the menu is visible.\n\nD-pad to move between " + "items, A to select, B to move up in scope. DEV NOTE: SDL is weird currently, pad button only " + "works with menubar open.", + WIDGET_CVAR_CHECKBOX }, + { "Cursor Always Visible", + "gSettings.CursorVisibility", + "Makes the cursor always visible, even in full screen.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { + Ship::Context::GetInstance()->GetWindow()->SetForceCursorVisibility( + CVarGetInteger("gSettings.CursorVisibility", 0)); + } }, +#endif + { "Open App Files Folder", + "", + "Opens the folder that contains the save and mods folders, etc.", + WIDGET_BUTTON, + {}, + [](widgetInfo& info) { + std::string filesPath = Ship::Context::GetInstance()->GetAppDirectoryPath(); + SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); + } }, + { "Search In Sidebar", + "gSettings.SidebarSearch", + "Displays the Search menu as a sidebar entry in Settings instead of in the header.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { + if (CVarGetInteger("gSettings.SidebarSearch", 0)) { + menuEntries[0].sidebarEntries.insert(menuEntries[0].sidebarEntries.begin() + searchSidebarIndex, + searchSidebarEntry); + CVarSetInteger(menuEntries[0].sidebarCvar, CVarGetInteger(menuEntries[0].sidebarCvar, 0) + 1); + } else { + menuEntries[0].sidebarEntries.erase(menuEntries[0].sidebarEntries.begin() + searchSidebarIndex); + CVarSetInteger(menuEntries[0].sidebarCvar, CVarGetInteger(menuEntries[0].sidebarCvar, 0) - 1); + } + } }, + { "Search Input Autofocus", "gSettings.SearchAutofocus", + "Search input box gets autofocus when visible. Does not affect using other widgets.", + WIDGET_CVAR_CHECKBOX }, + } } }); + // Audio Settings + settingsSidebar.push_back( + { "Audio", + 3, + { { { "Master Volume: %.0f%%", + "gSettings.Audio.MasterVolume", + "Adjust overall sound volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true } }, + { "Main Music Volume: %.0f%%", + "gSettings.Audio.MainMusicVolume", + "Adjust the Background Music volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + AudioSeq_SetPortVolumeScale(SEQ_PLAYER_BGM_MAIN, + CVarGetFloat("gSettings.Audio.MainMusicVolume", 1.0f)); + } }, + { "Sub Music Volume: %.0f%%", + "gSettings.Audio.SubMusicVolume", + "Adjust the Sub Music volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + AudioSeq_SetPortVolumeScale(SEQ_PLAYER_BGM_SUB, + CVarGetFloat("gSettings.Audio.SubMusicVolume", 1.0f)); + } }, + { "Sound Effects Volume: %.0f%%", + "gSettings.Audio.SoundEffectsVolume", + "Adjust the Sound Effects volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + AudioSeq_SetPortVolumeScale(SEQ_PLAYER_SFX, + CVarGetFloat("gSettings.Audio.SoundEffectsVolume", 1.0f)); + } }, + { "Fanfare Volume: %.0f%%", + "gSettings.Audio.FanfareVolume", + "Adjust the Fanfare volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + AudioSeq_SetPortVolumeScale(SEQ_PLAYER_FANFARE, + CVarGetFloat("gSettings.Audio.FanfareVolume", 1.0f)); + } }, + { "Ambience Volume: %.0f%%", + "gSettings.Audio.AmbienceVolume", + "Adjust the Ambient Sound volume.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, + .max = 100.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + AudioSeq_SetPortVolumeScale(SEQ_PLAYER_AMBIENCE, + CVarGetFloat("gSettings.Audio.AmbienceVolume", 1.0f)); + } }, + { "Audio API", NULL, "Sets the audio API used by the game. Requires a relaunch to take effect.", + WIDGET_AUDIO_BACKEND } } } }); + // Graphics Settings + static int32_t maxFps; + const char* tooltip = ""; + if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { + maxFps = 360; + tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " + "purely visual and does not impact game logic, execution of glitches etc.\n\nA higher target " + "FPS than your monitor's refresh rate will waste resources, and might give a worse result."; + } else { + maxFps = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " + "purely visual and does not impact game logic, execution of glitches etc."; + } + settingsSidebar.push_back( + { "Graphics", + 3, + { { { "Toggle Fullscreen", + "gSettings.Fullscreen", + "Toggles Fullscreen On/Off.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { Ship::Context::GetInstance()->GetWindow()->ToggleFullscreen(); } }, +#ifndef __APPLE__ + { "Internal Resolution: %.0f%%", + CVAR_INTERNAL_RESOLUTION, + "Multiplies your output resolution by the value inputted, as a more intensive but effective " + "form of anti-aliasing.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 50.0f, + .max = 200.0f, + .defaultVariant = 100.0f, + .showButtons = false, + .format = "", + .isPercentage = true }, + [](widgetInfo& info) { + Ship::Context::GetInstance()->GetWindow()->SetResolutionMultiplier( + CVarGetFloat(CVAR_INTERNAL_RESOLUTION, 1)); + } }, +#endif +#ifndef __WIIU__ + { "Anti-aliasing (MSAA): %d", + CVAR_MSAA_VALUE, + "Activates MSAA (multi-sample anti-aliasing) from 2x up to 8x, to smooth the edges of rendered " + "geometry.\n" + "Higher sample count will result in smoother edges on models, but may reduce performance.", + WIDGET_CVAR_SLIDER_INT, + { 1, 8, 1 }, + [](widgetInfo& info) { + Ship::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger(CVAR_MSAA_VALUE, 1)); + } }, +#endif + + { "Current FPS: %d", + "gInterpolationFPS", + tooltip, + WIDGET_CVAR_SLIDER_INT, + { 20, maxFps, 20 }, + [](widgetInfo& info) { + int32_t defaultVariant = std::get(info.widgetOptions.defaultVariant); + if (CVarGetInteger(info.widgetCVar, defaultVariant) == defaultVariant) { + info.widgetName = "Current FPS: Original (%d)"; + } else { + info.widgetName = "Current FPS: %d"; + } + }, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_MATCH_REFRESH_RATE_ON).active) + info.activeDisables.push_back(DISABLE_FOR_MATCH_REFRESH_RATE_ON); + } }, + { "Match Refresh Rate", + "", + "Matches interpolation value to the current game's window refresh rate.", + WIDGET_BUTTON, + {}, + [](widgetInfo& info) { + int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + if (hz >= 20 && hz <= 360) { + CVarSetInteger("gInterpolationFPS", hz); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NOT_DIRECTX).active; } }, + { "Match Refresh Rate", + "gMatchRefreshRate", + "Matches interpolation value to the current game's window refresh rate.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DIRECTX).active; } }, + { "Jitter fix : >= % d FPS", + "gExtraLatencyThreshold", + "When Interpolation FPS setting is at least this threshold, add one frame of input " + "lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the " + "CPU to work on one frame while GPU works on the previous frame.\nThis setting " + "should be used when your computer is too slow to do CPU + GPU work in time.", + WIDGET_CVAR_SLIDER_INT, + { 0, 360, 80 }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NOT_DIRECTX).active; } }, + { "Renderer API (Needs reload)", NULL, "Sets the renderer API used by the game.", WIDGET_VIDEO_BACKEND }, + { "Enable Vsync", + CVAR_VSYNC_ENABLED, + "Enables Vsync.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NO_VSYNC).active; } }, + { "Windowed Fullscreen", + CVAR_SDL_WINDOWED_FULLSCREEN, + "Enables Windowed Fullscreen Mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NO_WINDOWED_FULLSCREEN).active; } }, + { "Allow multi-windows", + CVAR_ENABLE_MULTI_VIEWPORTS, + "Allows multiple windows to be opened at once. Requires a reload to take effect.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NO_MULTI_VIEWPORT).active; } }, + { "Texture Filter (Needs reload)", + CVAR_TEXTURE_FILTER, + "Sets the applied Texture Filtering.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = textureFilteringMap } } } } }); + // Input Editor + settingsSidebar.push_back({ "Input Editor", + 1, + { { { "Popout Input Editor", + "gWindows.BenInputEditor", + "Enables the separate Input Editor window.", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "2S2H Input Editor" } } } } }); +} +int32_t motionBlurStrength; + +void AddEnhancements() { + // Camera Snap Fix + enhancementsSidebar.push_back( + { "Camera", + 3, + { { { .widgetName = "Fixes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Fix Targetting Camera Snap", + "gEnhancements.Camera.FixTargettingCameraSnap", + "Fixes the camera snap that occurs when you are moving and press the targetting button.", + WIDGET_CVAR_CHECKBOX, + {} } }, + // Camera Enhancements + { { .widgetName = "Cameras", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Free Look", + "gEnhancements.Camera.FreeLook.Enable", + "Enables free look camera control\nNote: You must remap C buttons off of the right " + "stick in the controller config menu, and map the camera stick to the right stick.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterCameraFreeLook(); }, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_DEBUG_CAM_ON).active) + info.activeDisables.push_back(DISABLE_FOR_DEBUG_CAM_ON); + } }, + { "Camera Distance: %d", + "gEnhancements.Camera.FreeLook.MaxCameraDistance", + "Maximum Camera Distance for Free Look.", + WIDGET_CVAR_SLIDER_INT, + { 100, 900, 185 }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_FREE_LOOK_OFF).active; } }, + { "Camera Transition Speed: %d", + "gEnhancements.Camera.FreeLook.TransitionSpeed", + "Can someone help me?", + WIDGET_CVAR_SLIDER_INT, + { 1, 900, 25 }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_FREE_LOOK_OFF).active; } }, + { "Max Camera Height Angle: %.0f\xC2\xB0", + "gEnhancements.Camera.FreeLook.MaxPitch", + "Maximum Height of the Camera.", + WIDGET_CVAR_SLIDER_FLOAT, + { -8900.0f, 8900.0f, 7200.0f }, + [](widgetInfo& info) { FreeLookPitchMinMax(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_FREE_LOOK_OFF).active; } }, + { "Min Camera Height Angle: %.0f\xC2\xB0", + "gEnhancements.Camera.FreeLook.MinPitch", + "Minimum Height of the Camera.", + WIDGET_CVAR_SLIDER_FLOAT, + { -8900.0f, 8900.0f, -4900.0f }, + [](widgetInfo& info) { FreeLookPitchMinMax(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_FREE_LOOK_OFF).active; } }, + { "Debug Camera", + "gEnhancements.Camera.DebugCam.Enable", + "Enables free camera control.", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { RegisterDebugCam(); }), + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_FREE_LOOK_ON).active) { + info.activeDisables.push_back(DISABLE_FOR_FREE_LOOK_ON); + } + } }, + { "Invert Camera X Axis", + "gEnhancements.Camera.RightStick.InvertXAxis", + "Inverts the Camera X Axis", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_CAMERAS_OFF).active) { + info.activeDisables.push_back(DISABLE_FOR_CAMERAS_OFF); + } + } }, + { "Invert Camera Y Axis", + "gEnhancements.Camera.RightStick.InvertYAxis", + "Inverts the Camera Y Axis", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_CAMERAS_OFF).active) { + info.activeDisables.push_back(DISABLE_FOR_CAMERAS_OFF); + } + } }, + { "Third-Person Horizontal Sensitivity: %.0f", + "gEnhancements.Camera.RightStick.CameraSensitivity.X", + "Adjust the Sensitivity of the x axis when in Third Person.", + WIDGET_CVAR_SLIDER_FLOAT, + { 1.0f, 500.0f, 100.0f }, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_CAMERAS_OFF).active) { + info.activeDisables.push_back(DISABLE_FOR_CAMERAS_OFF); + } + } }, + { "Third-Person Vertical Sensitivity: %.0f", + "gEnhancements.Camera.RightStick.CameraSensitivity.Y", + "Adjust the Sensitivity of the x axis when in Third Person.", + WIDGET_CVAR_SLIDER_FLOAT, + { 1.0f, 500.0f, 100.0f }, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_CAMERAS_OFF).active) { + info.activeDisables.push_back(DISABLE_FOR_CAMERAS_OFF); + } + } }, + { "Enable Roll (6\xC2\xB0 of Freedom)", + "gEnhancements.Camera.DebugCam.6DOF", + "This allows for all six degrees of movement with the camera, NOTE: Yaw will work " + "differently in this system, instead rotating around the focal point" + ", rather than a polar axis.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_CAM_OFF).active; } }, + { "Camera Speed: %.0f", + "gEnhancements.Camera.DebugCam.CameraSpeed", + "Adjusts the speed of the Camera.", + WIDGET_CVAR_SLIDER_FLOAT, + { 10.0f, 300.0f, 50.0f }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_CAM_OFF).active; } } } } }); + // Cheats + enhancementsSidebar.push_back( + { "Cheats", + 3, + { { { "Infinite Health", "gCheats.InfiniteHealth", "Always have full Hearts.", WIDGET_CVAR_CHECKBOX, {} }, + { "Infinite Magic", "gCheats.InfiniteMagic", "Always have full Magic.", WIDGET_CVAR_CHECKBOX, {} }, + { "Infinite Rupees", "gCheats.InfiniteRupees", "Always have a full Wallet.", WIDGET_CVAR_CHECKBOX, {} }, + { "Infinite Consumables", "gCheats.InfiniteConsumables", + "Always have max Consumables, you must have collected the consumables first.", WIDGET_CVAR_CHECKBOX }, + { "Longer Deku Flower Glide", + "gCheats.LongerFlowerGlide", + "Allows Deku Link to glide longer, no longer dropping after a certain distance.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterLongerFlowerGlide(); } }, + { "No Clip", "gCheats.NoClip", "Allows Link to phase through collision.", WIDGET_CVAR_CHECKBOX }, + { "Unbreakable Razor Sword", "gCheats.UnbreakableRazorSword", + "Allows to Razor Sword to be used indefinitely without dulling its blade.", WIDGET_CVAR_CHECKBOX }, + { "Unrestricted Items", "gCheats.UnrestrictedItems", "Allows all Forms to use all Items.", + WIDGET_CVAR_CHECKBOX }, + { "Moon Jump on L", + "gCheats.MoonJumpOnL", + "Holding L makes you float into the air.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterMoonJumpOnL(); } }, + { "Stop Time in Dungeons", + "gCheats.TempleTimeStop", + "Stops time from advancing in selected areas. Requires a room change to update.\n\n" + "- Off: Vanilla behaviour.\n" + "- Temples: Stops time in Woodfall, Snowhead, Great Bay, and Stone Tower Temples.\n" + "- Temples + Mini Dungeons: In addition to the above temples, stops time in both Spider " + "Houses, Pirate's Fortress, Beneath the Well, Ancient Castle of Ikana, and Secret Shrine.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = timeStopOptions } } } } }); + // Gameplay Enhancements + enhancementsSidebar.push_back( + { "Gameplay", + 3, + { { { .widgetName = "Player", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Fast Deku Flower Launch", + "gEnhancements.Player.FastFlowerLaunch", + "Speeds up the time it takes to be able to get maximum height from launching out of a deku flower", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { RegisterFastFlowerLaunch(); }) }, + { "Instant Putaway", "gEnhancements.Player.InstantPutaway", + "Allows Link to instantly puts away held item without waiting.", WIDGET_CVAR_CHECKBOX }, + { "Climb speed", + "gEnhancements.PlayerMovement.ClimbSpeed", + "Increases the speed at which Link climbs vines and ladders.", + WIDGET_CVAR_SLIDER_INT, + { 1, 5, 1 } }, + { "Dpad Equips", "gEnhancements.Dpad.DpadEquips", "Allows you to equip items to your d-pad", + WIDGET_CVAR_CHECKBOX }, + { "Always Win Doggy Race", + "gEnhancements.Minigames.AlwaysWinDoggyRace", + "Makes the Doggy Race easier to win.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = alwaysWinDoggyraceOptions } }, + { "Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", + "Removes the animation for equipping Magic Arrows.", WIDGET_CVAR_CHECKBOX }, + { "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", + "Pressing B will instantly recall the fin boomerang back to Zora Link after they are thrown.", + WIDGET_CVAR_CHECKBOX } }, + { { .widgetName = "Modes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Play as Kafei", "gModes.PlayAsKafei", "Requires scene reload to take effect.", WIDGET_CVAR_CHECKBOX }, + { "Time Moves when you Move", + "gModes.TimeMovesWhenYouMove", + "Time only moves when Link is not standing still.", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { RegisterTimeMovesWhenYouMove(); }) } }, + { { .widgetName = "Saving", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Persistent Owl Saves", "gEnhancements.Saving.PersistentOwlSaves", + "Continuing a save will not remove the owl save. Playing Song of " + "Time, allowing the moon to crash or finishing the " + "game will remove the owl save and become the new last save.", + WIDGET_CVAR_CHECKBOX }, + { "Pause Menu Save", "gEnhancements.Saving.PauseSave", + "Re-introduce the pause menu save system. Pressing B in the pause menu will give you the " + "option to create a persistent Owl Save from your current location.\n\nWhen loading back " + "into the game, you will be placed either at the entrance of the dungeon you saved in, or " + "in South Clock Town.", + WIDGET_CVAR_CHECKBOX }, + { "Autosave", + "gEnhancements.Saving.Autosave", + "Automatically create a persistent Owl Save on the chosen interval.\n\nWhen loading " + "back into the game, you will be placed either at the entrance of the dungeon you " + "saved in, or in South Clock Town.", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { RegisterAutosave(); }) }, + { "Autosave Interval: %d minutes", + "gEnhancements.Saving.AutosaveInterval", + "Sets the interval between Autosaves.", + WIDGET_CVAR_SLIDER_INT, + { 1, 60, 5 }, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_AUTO_SAVE_OFF).active) { + info.activeDisables.push_back(DISABLE_FOR_AUTO_SAVE_OFF); + } + } }, + { .widgetName = "Time Cycle", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Do not reset Bottle content", "gEnhancements.Cycle.DoNotResetBottleContent", + "Playing the Song Of Time will not reset the bottles' content.", WIDGET_CVAR_CHECKBOX }, + { "Do not reset Consumables", "gEnhancements.Cycle.DoNotResetConsumables", + "Playing the Song Of Time will not reset the consumables.", WIDGET_CVAR_CHECKBOX }, + { "Do not reset Razor Sword", "gEnhancements.Cycle.DoNotResetRazorSword", + "Playing the Song Of Time will not reset the Sword back to Kokiri Sword.", WIDGET_CVAR_CHECKBOX }, + { "Do not reset Rupees", "gEnhancements.Cycle.DoNotResetRupees", + "Playing the Song Of Time will not reset the your rupees.", WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Unstable", + .widgetType = WIDGET_SEPARATOR_TEXT, + .widgetOptions = { .color = UIWidgets::Colors::Yellow } }, + { "Disable Save Delay", "gEnhancements.Saving.DisableSaveDelay", + "Removes the arbitrary 2 second timer for saving from the original game. This is known to " + "cause issues when attempting the 0th Day Glitch", + WIDGET_CVAR_CHECKBOX } } } }); + // Graphics Enhancements + enhancementsSidebar.push_back( + { "Graphics", + 3, + { { { .widgetName = "Clock", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Clock Type", + "gEnhancements.Graphics.ClockType", + "Swaps between Graphical and Text only Clock types.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = clockTypeOptions } }, + { "24 Hours Clock", "gEnhancements.Graphics.24HoursClock", "Changes from a 12 Hour to a 24 Hour Clock", + WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Motion Blur", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Motion Blur Mode", + "gEnhancements.Graphics.MotionBlur.Mode", + "Selects the Mode for Motion Blur.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = motionBlurOptions, .labelPosition = UIWidgets::LabelPosition::None } }, + { "Interpolate", + "gEnhancements.Graphics.MotionBlur.Interpolate", + "Change motion blur capture to also happen on interpolated frames instead of only on game frames.\n" + "This notably reduces the overall motion blur strength but smooths out the trails.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_MOTION_BLUR_MODE).value == 1; } }, + { "On/Off", + "", + "Enables Motion Blur.", + WIDGET_CHECKBOX, + { .valuePointer = (bool*)&R_MOTION_BLUR_ENABLED }, + nullptr, + [](widgetInfo& info) { + info.widgetOptions.valuePointer = (bool*)&R_MOTION_BLUR_ENABLED; + info.isHidden = disabledMap.at(DISABLE_FOR_MOTION_BLUR_MODE).value != 0; + } }, + { "Strength", + "gEnhancements.Graphics.MotionBlur.Strength", + "Motion Blur strength.", + WIDGET_CVAR_SLIDER_INT, + { 0, 255, 180 }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_MOTION_BLUR_MODE).value != 2; } }, + { "Strength", + "", + "Motion Blur strength.", + WIDGET_SLIDER_INT, + { 0, 255, 180, {}, &motionBlurStrength }, + [](widgetInfo& info) { R_MOTION_BLUR_ALPHA = motionBlurStrength; }, + [](widgetInfo& info) { + motionBlurStrength = R_MOTION_BLUR_ALPHA; + info.isHidden = disabledMap.at(DISABLE_FOR_MOTION_BLUR_MODE).value != 0 || + disabledMap.at(DISABLE_FOR_MOTION_BLUR_OFF).active; + } }, + { .widgetName = "Other", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "3D Item Drops", + "gEnhancements.Graphics.3DItemDrops", + "Makes item drops 3D", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { Register3DItemDrops(); } }, + { "Authentic Logo", "gEnhancements.Graphics.AuthenticLogo", + "Hide the game version and build details and display the authentic " + "model and texture on the boot logo start screen", + WIDGET_CVAR_CHECKBOX }, + { "Bow Reticle", "gEnhancements.Graphics.BowReticle", "Gives the bow a reticle when you draw an arrow.", + WIDGET_CVAR_CHECKBOX }, + { "Disable Black Bar Letterboxes", "gEnhancements.Graphics.DisableBlackBars", + "Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be " + "minor visual glitches that were covered up by the black bars\nPlease disable this " + "setting before reporting a bug.", + WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Unstable", + .widgetType = WIDGET_SEPARATOR_TEXT, + .widgetOptions = { .color = UIWidgets::Colors::Yellow } }, + { "Disable Scene Geometry Distance Check", "gEnhancements.Graphics.DisableSceneGeometryDistanceCheck", + "Disables the distance check for scene geometry, allowing it to be drawn no matter how far " + "away it is from the player. This may have unintended side effects.", + WIDGET_CVAR_CHECKBOX }, + { "Widescreen Actor Culling", "gEnhancements.Graphics.ActorCullingAccountsForWidescreen", + "Adjusts the culling planes to account for widescreen resolutions. " + "This may have unintended side effects.", + WIDGET_CVAR_CHECKBOX }, + { "Increase Actor Draw Distance: %dx", + "gEnhancements.Graphics.IncreaseActorDrawDistance", + "Increase the range in which Actors are drawn. This may have unintended side effects.", + WIDGET_CVAR_SLIDER_INT, + { 1, 5, 1 }, + [](widgetInfo& info) { + CVarSetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", + MIN(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1), + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1))); + } }, + { "Increase Actor Update Distance: %dx", + "gEnhancements.Graphics.IncreaseActorUpdateDistance", + "Increase the range in which Actors are updated. This may have unintended side effects.", + WIDGET_CVAR_SLIDER_INT, + { 1, 5, 1 }, + [](widgetInfo& info) { + CVarSetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", + MAX(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1), + CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1))); + } } } } }); + enhancementsSidebar.push_back( + { "Items/Songs", + 3, + { // Mask Enhancements + { { .widgetName = "Masks", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Blast Mask has Powder Keg Force", "gEnhancements.Masks.BlastMaskKeg", + "Blast Mask can also destroy objects only the Powder Keg can.", WIDGET_CVAR_CHECKBOX }, + { "Fast Transformation", "gEnhancements.Masks.FastTransformation", + "Removes the delay when using transormation masks.", WIDGET_CVAR_CHECKBOX }, + { "Fierce Deity's Mask Anywhere", "gEnhancements.Masks.FierceDeitysAnywhere", + "Allow using Fierce Deity's mask outside of boss rooms.", WIDGET_CVAR_CHECKBOX }, + { "Persistent Bunny Hood", + "gEnhancements.Masks.PersistentBunnyHood.Enabled", + "Permanantly toggle a speed boost from the bunny hood by pressing " + "'A' on it in the mask menu.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { UpdatePersistentMasksState(); } }, + { "No Blast Mask Cooldown", "gEnhancements.Masks.NoBlastMaskCooldown", + "Eliminates the Cooldown between Blast Mask usage.", WIDGET_CVAR_CHECKBOX } }, + // Song Enhancements + { { .widgetName = "Ocarina", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Enable Sun's Song", "gEnhancements.Songs.EnableSunsSong", + "Enables the partially implemented Sun's Song. RIGHT-DOWN-UP-RIGHT-DOWN-UP to play it. " + "This song will make time move very fast until either Link moves to a different scene, " + "or when the time switches to a new time period.", + WIDGET_CVAR_CHECKBOX }, + { "Dpad Ocarina", "gEnhancements.Playback.DpadOcarina", "Enables using the Dpad for Ocarina playback.", + WIDGET_CVAR_CHECKBOX }, + { "Pause Owl Warp", "gEnhancements.Songs.PauseOwlWarp", + "Allows the player to use the pause menu map to owl warp instead of " + "having to play the Song of Soaring.", + WIDGET_CVAR_CHECKBOX }, + { "Zora Eggs For Bossa Nova", + "gEnhancements.Songs.ZoraEggCount", + "The number of eggs required to unlock new wave bossa nova.", + WIDGET_CVAR_SLIDER_INT, + { 1, 7, 7 } }, + { "Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput", + "Prevent dropping inputs when playing the ocarina quickly.", WIDGET_CVAR_CHECKBOX } } } }); + enhancementsSidebar.push_back( + { "Time Savers", + 3, + { // Cutscene Skips + { { .widgetName = "Cutscenes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Hide Title Cards", "gEnhancements.Cutscenes.HideTitleCards", "Hides Title Cards when entering areas.", + WIDGET_CVAR_CHECKBOX }, + { "Skip Entrance Cutscenes", "gEnhancements.Cutscenes.SkipEntranceCutscenes", + "Skip cutscenes that occur when first entering a new area.", WIDGET_CVAR_CHECKBOX }, + { "Skip to File Select", "gEnhancements.Cutscenes.SkipToFileSelect", + "Skip the opening title sequence and go straight to the file select menu after boot.", + WIDGET_CVAR_CHECKBOX }, + { "Skip Intro Sequence", "gEnhancements.Cutscenes.SkipIntroSequence", + "When starting a game you will be taken straight to South Clock Town as Deku Link.", + WIDGET_CVAR_CHECKBOX }, + { "Skip Story Cutscenes", "gEnhancements.Cutscenes.SkipStoryCutscenes", + "Disclaimer: This doesn't do much yet, we will be progressively adding more skips over time.", + WIDGET_CVAR_CHECKBOX }, + { "Skip Misc Interactions", "gEnhancements.Cutscenes.SkipMiscInteractions", + "Disclaimer: This doesn't do much yet, we will be progressively adding more skips over time.", + WIDGET_CVAR_CHECKBOX } }, + // Dialogue Enhancements + { { .widgetName = "Dialogue", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Fast Bank Selection", "gEnhancements.Dialogue.FastBankSelection", + "Pressing the Z or R buttons while the Deposit/Withdrawl Rupees dialogue is open will set " + "the Rupees to Links current Rupees or 0 respectively.", + WIDGET_CVAR_CHECKBOX }, + { "Fast Text", "gEnhancements.Dialogue.FastText", + "Speeds up text rendering, and enables holding of B progress to next message.", + WIDGET_CVAR_CHECKBOX } } } }); + enhancementsSidebar.push_back( + { "Fixes", + 3, + { // Fixes + { { .widgetName = "Fixes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Fix Ammo Count Color", "gFixes.FixAmmoCountEnvColor", + "Fixes a missing gDPSetEnvColor, which causes the ammo count to be " + "the wrong color prior to obtaining magic or other conditions.", + WIDGET_CVAR_CHECKBOX }, + { "Fix Fierce Deity Z-Target movement", "gEnhancements.Fixes.FierceDeityZTargetMovement", + "Fixes Fierce Deity movement being choppy when Z-targeting", WIDGET_CVAR_CHECKBOX }, + { "Fix Hess and Weirdshot Crash", "gEnhancements.Fixes.HessCrash", + "Fixes a crash that can occur when performing a HESS or Weirdshot.", WIDGET_CVAR_CHECKBOX }, + { "Fix Text Control Characters", "gEnhancements.Fixes.ControlCharacters", + "Fixes certain control characters not functioning properly " + "depending on their position within the text.", + WIDGET_CVAR_CHECKBOX } } } }); + enhancementsSidebar.push_back( + { "Restorations", + 3, + { // Restorations + { { .widgetName = "Restorations", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Constant Distance Backflips and Sidehops", "gEnhancements.Restorations.ConstantFlipsHops", + "Backflips and Sidehops travel a constant distance as they did in OoT.", WIDGET_CVAR_CHECKBOX }, + { "Power Crouch Stab", "gEnhancements.Restorations.PowerCrouchStab", + "Crouch stabs will use the power of Link's previous melee attack, as is in MM JP 1.0 and OoT.", + WIDGET_CVAR_CHECKBOX }, + { "Side Rolls", "gEnhancements.Restorations.SideRoll", "Restores side rolling from OoT.", + WIDGET_CVAR_CHECKBOX }, + { "Tatl ISG", "gEnhancements.Restorations.TatlISG", "Restores Navi ISG from OoT, but now with Tatl.", + WIDGET_CVAR_CHECKBOX }, + { "Woodfall Mountain Appearance", + "gEnhancements.Restorations.WoodfallMountainAppearance", + "Restores the appearance of Woodfall mountain to not look poisoned " + "when viewed from Termina Field after clearing Woodfall Temple\n\n" + "Requires a scene reload to take effect", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterWoodfallMountainAppearance(); } } } } }); + enhancementsSidebar.push_back({ "HUD Editor", + 1, + { // HUD Editor + { { "Popout HUD Editor", + "gWindows.HudEditor", + "Enables the HUD Editor window, allowing you to modify your HUD", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "HUD Editor" } } } } }); +} + +void AddDevTools() { + devToolsSidebar.push_back( + { "General", + 3, + { { { "Popout Menu", "gSettings.Menu.Popout", "Changes the menu display from overlay to windowed.", + WIDGET_CVAR_CHECKBOX }, + { "Set Warp Point", + "", + "Creates warp point that you can teleport to later", + WIDGET_BUTTON, + {}, + [](widgetInfo& info) { + Player* player = GET_PLAYER(gPlayState); + + CVarSetInteger(WARP_POINT_CVAR "Entrance", gSaveContext.save.entrance); + CVarSetInteger(WARP_POINT_CVAR "Room", gPlayState->roomCtx.curRoom.num); + CVarSetFloat(WARP_POINT_CVAR "X", player->actor.world.pos.x); + CVarSetFloat(WARP_POINT_CVAR "Y", player->actor.world.pos.y); + CVarSetFloat(WARP_POINT_CVAR "Z", player->actor.world.pos.z); + CVarSetFloat(WARP_POINT_CVAR "Rotation", player->actor.shape.rot.y); + CVarSetInteger(WARP_POINT_CVAR "Saved", 1); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active; } }, + { "Scene Room ID", + "", + "", + WIDGET_TEXT, + {}, + nullptr, + [](widgetInfo& info) { + u32 sceneId = Entrance_GetSceneIdAbsolute( + CVarGetInteger(WARP_POINT_CVAR "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0))); + info.widgetName = fmt::format("{} Room {}", warpPointSceneList[sceneId], + CVarGetInteger(WARP_POINT_CVAR "Room", 0)); + info.isHidden = disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active || + disabledMap.at(DISABLE_FOR_WARP_POINT_NOT_SET).active; + } }, + { ICON_FA_TIMES, + "", + "Clear warp point", + WIDGET_BUTTON, + { .size = UIWidgets::Sizes::Inline, .sameLine = true }, + [](widgetInfo& info) { + CVarClear(WARP_POINT_CVAR "Entrance"); + CVarClear(WARP_POINT_CVAR "Room"); + CVarClear(WARP_POINT_CVAR "X"); + CVarClear(WARP_POINT_CVAR "Y"); + CVarClear(WARP_POINT_CVAR "Z"); + CVarClear(WARP_POINT_CVAR "Rotation"); + CVarClear(WARP_POINT_CVAR "Saved"); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + }, + [](widgetInfo& info) { + info.isHidden = disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active || + disabledMap.at(DISABLE_FOR_WARP_POINT_NOT_SET).active; + } }, + { "Warp", + "", + "Teleport to the set warp point", + WIDGET_BUTTON, + { .size = UIWidgets::Sizes::Inline, .sameLine = true }, + [](widgetInfo& info) { Warp(); }, + [](widgetInfo& info) { + info.isHidden = disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active || + disabledMap.at(DISABLE_FOR_WARP_POINT_NOT_SET).active; + } } }, + { { "Debug Mode", + "gDeveloperTools.DebugEnabled", + "Enables Debug Mode, allowing you to select maps with L + R + Z.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { + if (!CVarGetInteger("gDeveloperTools.DebugEnabled", 0)) { + CVarClear("gDeveloperTools.DebugSaveFileMode"); + CVarClear("gDeveloperTools.PreventActorUpdate"); + CVarClear("gDeveloperTools.PreventActorDraw"); + CVarClear("gDeveloperTools.PreventActorInit"); + CVarClear("gDeveloperTools.DisableObjectDependency"); + if (gPlayState != NULL) { + gPlayState->frameAdvCtx.enabled = false; + } + RegisterDebugSaveCreate(); + RegisterPreventActorUpdateHooks(); + RegisterPreventActorDrawHooks(); + RegisterPreventActorInitHooks(); + } + } }, + { "Better Map Select", + "gDeveloperTools.BetterMapSelect.Enabled", + "Overrides the original map select with a translated, more user-friendly version.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Debug Save File Mode", + "gDeveloperTools.DebugSaveFileMode", + "Change the behavior of creating saves while debug mode is enabled:\n\n" + "- Empty Save: The default 3 heart save file in first cycle\n" + "- Vanilla Debug Save: Uses the title screen save info (8 hearts, all items and masks)\n" + "- 100\% Save: All items, equipment, mask, quast status and bombers notebook complete", + WIDGET_CVAR_COMBOBOX, + { 0, 0, 0, debugSaveOptions }, + [](widgetInfo& info) { RegisterDebugSaveCreate(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Prevent Actor Update", + "gDeveloperTools.PreventActorUpdate", + "Prevents Actors from updating.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterPreventActorUpdateHooks(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Prevent Actor Draw", + "gDeveloperTools.PreventActorDraw", + "Prevents Actors from drawing.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterPreventActorDrawHooks(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Prevent Actor Init", + "gDeveloperTools.PreventActorInit", + "Prevents Actors from initializing.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterPreventActorInitHooks(); }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Disable Object Dependency", + "gDeveloperTools.DisableObjectDependency", + "Disables dependencies when loading objects.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Log Level", + "gDeveloperTools.LogLevel", + "The log level determines which messages are printed to the " + "console. This does not affect the log file output", + WIDGET_CVAR_COMBOBOX, + { 0, 0, 0, logLevels }, + [](widgetInfo& info) { + Ship::Context::GetInstance()->GetLogger()->set_level( + (spdlog::level::level_enum)CVarGetInteger("gDeveloperTools.LogLevel", 1)); + }, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; } }, + { "Frame Advance", + "", + "This allows you to advance through the game one frame at a time on command. " + "To advance a frame, hold Z and tap R on the second controller. Holding Z " + "and R will advance a frame every half second. You can also use the buttons below.", + WIDGET_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { + info.isHidden = disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active || + disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; + if (gPlayState != nullptr) { + info.widgetOptions.valuePointer = (bool*)&gPlayState->frameAdvCtx.enabled; + } else { + info.widgetOptions.valuePointer = (bool*)nullptr; + } + } }, + { "Advance 1", + "", + "Advance 1 frame.", + WIDGET_BUTTON, + { .size = UIWidgets::Sizes::Inline }, + [](widgetInfo& info) { CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); }, + [](widgetInfo& info) { + info.isHidden = disabledMap.at(DISABLE_FOR_FRAME_ADVANCE_OFF).active || + disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; + } }, + { "Advance (Hold)", + "", + "Advance frames while the button is held.", + WIDGET_BUTTON, + { .size = UIWidgets::Sizes::Inline, .sameLine = true }, + nullptr, + [](widgetInfo& info) { + info.isHidden = disabledMap.at(DISABLE_FOR_FRAME_ADVANCE_OFF).active || + disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; + }, + [](widgetInfo& info) { + if (ImGui::IsItemActive()) { + CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); + } + } } } } }); + // dev tools windows + devToolsSidebar.push_back({ "Collision Viewer", + 1, + { { { "Popout Collision Viewer", + "gWindows.CollisionViewer", + "Makes collision visible on screen", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Collision Viewer" } } } } }); + devToolsSidebar.push_back( + { "Stats", + 1, + { { { "Popout Stats", + "gOpenWindows.Stats", + "Shows the stats window, with your FPS and frametimes, and the OS you're playing on", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Stats" } } } } }); + devToolsSidebar.push_back( + { "Console", + 1, + { { { "Popout Console", + "gOpenWindows.Console", + "Enables the console window, allowing you to input commands. Type help for some examples", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Console" } } } } }); + devToolsSidebar.push_back( + { "Gfx Debugger", + 1, + { { { "Popout Gfx Debugger", + "gOpenWindows.GfxDebugger", + "Enables the Gfx Debugger window, allowing you to input commands, type help for some examples", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "GfxDebuggerWindow" } } } } }); + devToolsSidebar.push_back({ "Save Editor", + 1, + { { { "Popout Save Editor", + "gWindows.SaveEditor", + "Enables the Save Editor window, allowing you to edit your save file", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Save Editor" } } } } }); + devToolsSidebar.push_back({ "Actor Viewer", + 1, + { { { "Popout Actor Viewer", + "gWindows.ActorViewer", + "Enables the Actor Viewer window, allowing you to view actors in the world.", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Actor Viewer" } } } } }); + devToolsSidebar.push_back({ "Event Log", + 1, + { { { "Popout Event Log", + "gWindows.EventLog", + "Enables the event log window", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Event Log" } } } } }); +} + +void SearchMenuGetItem(widgetInfo& widget) { + disabledTempTooltip = "This setting is disabled because: \n\n"; + disabledValue = false; + disabledTooltip = " "; + + if (widget.preFunc != nullptr) { + widget.activeDisables.clear(); + widget.isHidden = false; + widget.preFunc(widget); + if (widget.isHidden) { + return; + } + if (!widget.activeDisables.empty()) { + disabledValue = true; + for (auto option : widget.activeDisables) { + disabledTempTooltip += std::string("- ") + disabledMap.at(option).reason + std::string("\n"); + } + disabledTooltip = disabledTempTooltip.c_str(); + } + } + + if (widget.widgetOptions.sameLine) { + ImGui::SameLine(); + } + + try { + switch (widget.widgetType) { + case WIDGET_CHECKBOX: { + bool* pointer = std::get(widget.widgetOptions.valuePointer); + if (pointer == nullptr) { + SPDLOG_ERROR("Checkbox Widget requires a value pointer, currently nullptr"); + assert(false); + return; + } + if (UIWidgets::Checkbox( + widget.widgetName.c_str(), pointer, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .labelPosition = widget.widgetOptions.labelPosition == UIWidgets::LabelPosition::None + ? UIWidgets::LabelPosition::Near + : widget.widgetOptions.labelPosition })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + } + } break; + case WIDGET_CVAR_CHECKBOX: + if (UIWidgets::CVarCheckbox( + widget.widgetName.c_str(), widget.widgetCVar, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .defaultValue = static_cast(std::get(widget.widgetOptions.defaultVariant)), + .labelPosition = widget.widgetOptions.labelPosition == UIWidgets::LabelPosition::None + ? UIWidgets::LabelPosition::Near + : widget.widgetOptions.labelPosition })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + }; + break; + case WIDGET_AUDIO_BACKEND: { + auto currentAudioBackend = Ship::Context::GetInstance()->GetAudio()->GetAudioBackend(); + if (UIWidgets::Combobox( + "Audio API", ¤tAudioBackend, audioBackendsMap, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = + Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1, + .disabledTooltip = "Only one audio API is available on this platform." })) { + Ship::Context::GetInstance()->GetAudio()->SetAudioBackend(currentAudioBackend); + } + } break; + case WIDGET_VIDEO_BACKEND: { + if (UIWidgets::Combobox( + "Renderer API (Needs reload)", &configWindowBackend, availableWindowBackendsMap, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = availableWindowBackends->size() <= 1, + .disabledTooltip = "Only one renderer API is available on this platform." })) { + Ship::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", + static_cast(configWindowBackend)); + Ship::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", + windowBackendsMap.at(configWindowBackend)); + Ship::Context::GetInstance()->GetConfig()->Save(); + UpdateWindowBackendObjects(); + } + } break; + case WIDGET_SEPARATOR: + ImGui::Separator(); + break; + case WIDGET_SEPARATOR_TEXT: + if (widget.widgetOptions.color != COLOR_NONE) { + ImGui::PushStyleColor(ImGuiCol_Text, widget.widgetOptions.color); + } + ImGui::SeparatorText(widget.widgetName.c_str()); + if (widget.widgetOptions.color != COLOR_NONE) { + ImGui::PopStyleColor(); + } + break; + case WIDGET_TEXT: + ImGui::AlignTextToFramePadding(); + ImGui::Text(widget.widgetName.c_str()); + break; + case WIDGET_COMBOBOX: { + int32_t* pointer = std::get(widget.widgetOptions.valuePointer); + if (pointer == nullptr) { + SPDLOG_ERROR("Combobox Widget requires a value pointer, currently nullptr"); + assert(false); + return; + } + if (UIWidgets::Combobox( + widget.widgetName.c_str(), pointer, widget.widgetOptions.comboBoxOptions, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .labelPosition = widget.widgetOptions.labelPosition == UIWidgets::LabelPosition::None + ? UIWidgets::LabelPosition::Above + : widget.widgetOptions.labelPosition })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + }; + } break; + case WIDGET_CVAR_COMBOBOX: + if (UIWidgets::CVarCombobox( + widget.widgetName.c_str(), widget.widgetCVar, widget.widgetOptions.comboBoxOptions, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .defaultIndex = static_cast(std::get(widget.widgetOptions.defaultVariant)), + .labelPosition = widget.widgetOptions.labelPosition == UIWidgets::LabelPosition::None + ? UIWidgets::LabelPosition::Above + : widget.widgetOptions.labelPosition })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + } + break; + case WIDGET_SLIDER_INT: { + int32_t* pointer = std::get(widget.widgetOptions.valuePointer); + if (pointer == nullptr) { + SPDLOG_ERROR("int32 Slider Widget requires a value pointer, currently nullptr"); + assert(false); + return; + } + if (UIWidgets::SliderInt(widget.widgetName.c_str(), pointer, + std::get(widget.widgetOptions.min), + std::get(widget.widgetOptions.max), + { + .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + }; + } break; + case WIDGET_SLIDER_FLOAT: { + float floatMin = (std::get(widget.widgetOptions.min) / 100); + float floatMax = (std::get(widget.widgetOptions.max) / 100); + float floatDefault = (std::get(widget.widgetOptions.defaultVariant) / 100); + float* pointer = std::get(widget.widgetOptions.valuePointer); + + if (pointer == nullptr) { + SPDLOG_ERROR("float Slider Widget requires a value pointer, currently nullptr"); + assert(false); + return; + } + if (UIWidgets::SliderFloat(widget.widgetName.c_str(), pointer, floatMin, floatMax, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .showButtons = widget.widgetOptions.showButtons, + .format = widget.widgetOptions.format, + .isPercentage = widget.widgetOptions.isPercentage })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + } + } break; + case WIDGET_CVAR_SLIDER_INT: + if (UIWidgets::CVarSliderInt(widget.widgetName.c_str(), widget.widgetCVar, + std::get(widget.widgetOptions.min), + std::get(widget.widgetOptions.max), + std::get(widget.widgetOptions.defaultVariant), + { + .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + }; + break; + case WIDGET_CVAR_SLIDER_FLOAT: { + float floatMin = (std::get(widget.widgetOptions.min) / 100); + float floatMax = (std::get(widget.widgetOptions.max) / 100); + float floatDefault = (std::get(widget.widgetOptions.defaultVariant) / 100); + if (UIWidgets::CVarSliderFloat(widget.widgetName.c_str(), widget.widgetCVar, floatMin, floatMax, + floatDefault, + { .color = menuTheme[menuThemeIndex], + .tooltip = widget.widgetTooltip, + .disabled = disabledValue, + .disabledTooltip = disabledTooltip, + .showButtons = widget.widgetOptions.showButtons, + .format = widget.widgetOptions.format, + .isPercentage = widget.widgetOptions.isPercentage })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + } + } break; + case WIDGET_BUTTON: + if (UIWidgets::Button(widget.widgetName.c_str(), + { menuTheme[menuThemeIndex], widget.widgetOptions.size, widget.widgetTooltip, + disabledValue, disabledTooltip })) { + if (widget.widgetCallback != nullptr) { + widget.widgetCallback(widget); + } + } + break; + case WIDGET_WINDOW_BUTTON: { + if (widget.widgetOptions.windowName == nullptr || widget.widgetOptions.windowName[0] == '\0') { + std::string msg = + fmt::format("Error drawing window contents for {}: windowName not defined", widget.widgetName); + SPDLOG_ERROR(msg.c_str()); + break; + } + auto window = + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow(widget.widgetOptions.windowName); + if (!window) { + std::string msg = fmt::format("Error drawing window contents: windowName {} does not exist", + widget.widgetOptions.windowName); + SPDLOG_ERROR(msg.c_str()); + break; + } + UIWidgets::WindowButton(widget.widgetName.c_str(), widget.widgetCVar, window, + { .size = widget.widgetOptions.size, .tooltip = widget.widgetTooltip }); + if (!window->IsVisible()) { + window->DrawElement(); + } + } break; + case WIDGET_SEARCH: { + if (ImGui::Button("Clear")) { + menuSearch.Clear(); + } + ImGui::SameLine(); + if (CVarGetInteger("gSettings.SearchAutofocus", 0) && + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() && + !ImGui::IsMouseClicked(0)) { + ImGui::SetKeyboardFocusHere(0); + } + menuSearch.Draw(); + std::string menuSearchText(menuSearch.InputBuf); + + if (menuSearchText == "") { + ImGui::Text("Start typing to see results."); + return; + } + ImGui::BeginChild("Search Results"); + for (auto& [menuLabel, menuSidebar, cvar] : menuEntries) { + for (auto& sidebar : menuSidebar) { + for (auto& widgets : sidebar.columnWidgets) { + int column = 1; + for (auto& info : widgets) { + if (info.widgetType == WIDGET_SEARCH || info.widgetType == WIDGET_SEPARATOR || + info.widgetType == WIDGET_SEPARATOR_TEXT || info.isHidden) { + continue; + } + std::string widgetStr = std::string(info.widgetName) + std::string(info.widgetTooltip); + std::transform(menuSearchText.begin(), menuSearchText.end(), menuSearchText.begin(), + ::tolower); + menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), + menuSearchText.end()); + std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower); + widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end()); + if (widgetStr.find(menuSearchText) != std::string::npos) { + SearchMenuGetItem(info); + ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::Colors::Gray); + std::string origin = + fmt::format(" ({} -> {}, Clmn {})", menuLabel, sidebar.label, column); + ImGui::Text("%s", origin.c_str()); + ImGui::PopStyleColor(); + } + } + column++; + } + } + } + ImGui::EndChild(); + } break; + default: + break; + } + if (widget.postFunc != nullptr) { + widget.postFunc(widget); + } + } catch (const std::bad_variant_access& e) { + SPDLOG_ERROR("Failed to draw menu item \"{}\" due to: {}", widget.widgetName, e.what()); + assert(false); + } +} +} // namespace BenGui diff --git a/mm/2s2h/BenGui/UIWidgets.cpp b/mm/2s2h/BenGui/UIWidgets.cpp index c50aceae7..632aac6b0 100644 --- a/mm/2s2h/BenGui/UIWidgets.cpp +++ b/mm/2s2h/BenGui/UIWidgets.cpp @@ -1,6 +1,7 @@ #include "UIWidgets.hpp" #define IMGUI_DEFINE_MATH_OPERATORS #include +#include #include #include #include @@ -389,6 +390,46 @@ bool CVarSliderInt(const char* label, const char* cvarName, int32_t min, int32_t return dirty; } +void ClampFloat(float* value, float min, float max, float step) { + int ticks = 0; + float increment = 1.0f; + if (step < 1.0f) { + ticks++; + increment = 0.1f; + } + if (step < 0.1f) { + ticks++; + increment = 0.01f; + } + if (step < 0.01f) { + ticks++; + increment = 0.001f; + } + if (step < 0.001f) { + ticks++; + increment = 0.0001f; + } + if (step < 0.0001f) { + ticks++; + increment = 0.00001f; + } + if (step < 0.00001f) { + ticks++; + increment = 0.000001f; + } + int factor = 1 * std::pow(10, ticks); + if (*value < min) { + *value = min; + } else if (*value > max) { + *value = max; + } else { + *value = std::round(*value * factor) / factor; + std::stringstream ss; + ss << std::setprecision(ticks) << std::setiosflags(std::ios_base::fixed) << *value; + *value = std::stof(ss.str()); + } +} + bool SliderFloat(const char* label, float* value, float min, float max, const FloatSliderOptions& options) { bool dirty = false; std::string invisibleLabelStr = "##" + std::string(label); @@ -414,8 +455,7 @@ bool SliderFloat(const char* label, float* value, float min, float max, const Fl if (options.showButtons) { if (Button("-", { .color = options.color, .size = Sizes::Inline }) && *value > min) { *value -= options.step; - if (*value < min) - *value = min; + ClampFloat(value, min, max, options.step); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); dirty = true; } @@ -427,6 +467,7 @@ bool SliderFloat(const char* label, float* value, float min, float max, const Fl if (ImGui::SliderScalar(invisibleLabel, ImGuiDataType_Float, &valueToDisplay, &minToDisplay, &maxToDisplay, options.format, options.flags)) { *value = options.isPercentage ? valueToDisplay / 100.0f : valueToDisplay; + ClampFloat(value, min, max, options.step); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); dirty = true; } @@ -435,8 +476,7 @@ bool SliderFloat(const char* label, float* value, float min, float max, const Fl ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (Button("+", { .color = options.color, .size = Sizes::Inline }) && *value < max) { *value += options.step; - if (*value > max) - *value = max; + ClampFloat(value, min, max, options.step); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); dirty = true; } diff --git a/mm/2s2h/BenGui/UIWidgets.hpp b/mm/2s2h/BenGui/UIWidgets.hpp index 506d10912..90357360d 100644 --- a/mm/2s2h/BenGui/UIWidgets.hpp +++ b/mm/2s2h/BenGui/UIWidgets.hpp @@ -12,6 +12,8 @@ namespace UIWidgets { + using SectionFunc = void(*)(); + struct TextFilters { static int FilterNumbers(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("1234567890", (char)data->EventChar)) { @@ -97,6 +99,7 @@ namespace UIWidgets { void PushStyleCheckbox(const ImVec4& color = Colors::Indigo); void PopStyleCheckbox(); + void RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash); bool Checkbox(const char* label, bool* v, const CheckboxOptions& options = {}); bool CVarCheckbox(const char* label, const char* cvarName, const CheckboxOptions& options = {}); diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 57dd9fb65..26113a1d2 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -15,6 +15,7 @@ #include "z64animation.h" #include "z64bgcheck.h" #include +#include #ifdef _WIN32 #include #else @@ -95,6 +96,8 @@ CrowdControl* CrowdControl::Instance; #include "2s2h/resource/importer/BackgroundFactory.h" #include "2s2h/resource/importer/TextureAnimationFactory.h" #include "2s2h/resource/importer/KeyFrameFactory.h" +#include "window/gui/resource/Font.h" +#include "window/gui/resource/FontFactory.h" OTRGlobals* OTRGlobals::Instance; GameInteractor* GameInteractor::Instance; @@ -279,6 +282,14 @@ OTRGlobals::OTRGlobals() { } } #endif + + fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf"); + fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf"); + fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf"); + fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf"); + fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf"); + fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf"); + ImGui::GetIO().FontDefault = fontMono; } OTRGlobals::~OTRGlobals() { @@ -310,6 +321,37 @@ struct ExtensionEntry { std::string ext; }; +ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) { + auto mImGuiIo = &ImGui::GetIO(); + ImFont* font; + if (fontPath == "") { + ImFontConfig fontCfg = ImFontConfig(); + fontCfg.OversampleH = fontCfg.OversampleV = 1; + fontCfg.PixelSnapH = true; + fontCfg.SizePixels = size; + font = mImGuiIo->Fonts->AddFontDefault(&fontCfg); + } else { + auto initData = std::make_shared(); + initData->Format = RESOURCE_FORMAT_BINARY; + initData->Type = static_cast(RESOURCE_TYPE_FONT); + initData->ResourceVersion = 0; + initData->Path = fontPath; + std::shared_ptr fontData = std::static_pointer_cast( + Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData)); + font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size); + } + // FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly + float iconFontSize = size * 2.0f / 3.0f; + static const ImWchar sIconsRanges[] = { ICON_MIN_FA, ICON_MAX_16_FA, 0 }; + ImFontConfig iconsConfig; + iconsConfig.MergeMode = true; + iconsConfig.PixelSnapH = true; + iconsConfig.GlyphMinAdvanceX = iconFontSize; + mImGuiIo->Fonts->AddFontFromMemoryCompressedBase85TTF(fontawesome_compressed_data_base85, iconFontSize, + &iconsConfig, sIconsRanges); + return font; +} + extern "C" void OTRMessage_Init(); extern "C" void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len); @@ -1475,9 +1517,9 @@ extern "C" void OTRControllerCallback(uint8_t rumble) { Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(0)->GetLED()->SetLEDColor( GetColorForControllerLED()); - static std::shared_ptr controllerConfigWindow = nullptr; + static std::shared_ptr controllerConfigWindow = nullptr; if (controllerConfigWindow == nullptr) { - controllerConfigWindow = std::dynamic_pointer_cast( + controllerConfigWindow = std::dynamic_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Input Editor")); // TODO: Add SoH Controller Config window rumble testing to upstream LUS config window // note: the current implementation may not be desired in LUS, as "true" rumble support diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h index 81b5975b3..1bad7f7af 100644 --- a/mm/2s2h/BenPort.h +++ b/mm/2s2h/BenPort.h @@ -24,6 +24,13 @@ class OTRGlobals { public: static OTRGlobals* Instance; + ImFont* fontStandard; + ImFont* fontStandardLarger; + ImFont* fontStandardLargest; + ImFont* fontMono; + ImFont* fontMonoLarger; + ImFont* fontMonoLargest; + std::shared_ptr context; OTRGlobals(); @@ -35,6 +42,7 @@ class OTRGlobals { std::shared_ptr> ListFiles(std::string path); private: + ImFont* CreateFontWithSize(float size, std::string fontPath = ""); void CheckSaveFile(size_t sramSize) const; bool hasMasterQuest; bool hasOriginal; diff --git a/mm/2s2h/DeveloperTools/ActorViewer.cpp b/mm/2s2h/DeveloperTools/ActorViewer.cpp index 3a514785c..a3542960e 100644 --- a/mm/2s2h/DeveloperTools/ActorViewer.cpp +++ b/mm/2s2h/DeveloperTools/ActorViewer.cpp @@ -177,12 +177,6 @@ void ActorViewerWindow::UpdateElement() { } void ActorViewerWindow::DrawElement() { - ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Actor Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::End(); - return; - } - if (gPlayState != nullptr) { if (lastSceneId != gPlayState->sceneId) { ResetVariables(); @@ -442,7 +436,6 @@ void ActorViewerWindow::DrawElement() { } else { ImGui::Text("Playstate needed for actors!"); } - ImGui::End(); } void ActorViewerWindow::InitElement() { diff --git a/mm/2s2h/DeveloperTools/CollisionViewer.cpp b/mm/2s2h/DeveloperTools/CollisionViewer.cpp index 758ade313..efbc9f77a 100644 --- a/mm/2s2h/DeveloperTools/CollisionViewer.cpp +++ b/mm/2s2h/DeveloperTools/CollisionViewer.cpp @@ -42,12 +42,6 @@ static std::vector sphereVtx; // Draws the ImGui window for the collision viewer void CollisionViewerWindow::DrawElement() { - ImGui::SetNextWindowSize(ImVec2(390, 475), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Collision Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::End(); - return; - } - UIWidgets::CVarCheckbox("Enabled", "gCollisionViewer.Enabled"); ImGui::SameLine(); @@ -113,8 +107,6 @@ void CollisionViewerWindow::DrawElement() { { 192, 0, 192, 255 }); ImGui::EndDisabled(); - - ImGui::End(); } // Calculates the normal for a triangle at the 3 specified points diff --git a/mm/2s2h/DeveloperTools/DeveloperTools.h b/mm/2s2h/DeveloperTools/DeveloperTools.h index 93c361b99..ffcac49f5 100644 --- a/mm/2s2h/DeveloperTools/DeveloperTools.h +++ b/mm/2s2h/DeveloperTools/DeveloperTools.h @@ -1,6 +1,8 @@ #ifndef DEVELOPER_TOOLS_H #define DEVELOPER_TOOLS_H +#define WARP_POINT_CVAR "gDeveloperTools.WarpPoint." + enum DebugSaveInfo { DEBUG_SAVE_INFO_NONE, DEBUG_SAVE_INFO_VANILLA_DEBUG, diff --git a/mm/2s2h/DeveloperTools/EventLog.cpp b/mm/2s2h/DeveloperTools/EventLog.cpp index f4dd1772d..2cd60f733 100644 --- a/mm/2s2h/DeveloperTools/EventLog.cpp +++ b/mm/2s2h/DeveloperTools/EventLog.cpp @@ -259,12 +259,6 @@ void RegisterEventLogHooks() { } void EventLogWindow::DrawElement() { - ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Event Log", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::End(); - return; - } - if (UIWidgets::CVarCheckbox("Enable", "gEventLog.Enabled")) { RegisterEventLogHooks(); } @@ -384,8 +378,6 @@ void EventLogWindow::DrawElement() { ImGui::EndTable(); } - - ImGui::End(); } void EventLogWindow::InitElement() { diff --git a/mm/2s2h/DeveloperTools/SaveEditor.cpp b/mm/2s2h/DeveloperTools/SaveEditor.cpp index e8aa2ddfa..8d6811628 100644 --- a/mm/2s2h/DeveloperTools/SaveEditor.cpp +++ b/mm/2s2h/DeveloperTools/SaveEditor.cpp @@ -1949,12 +1949,6 @@ void DrawFlagsTab() { } void SaveEditorWindow::DrawElement() { - ImGui::SetNextWindowSize(ImVec2(480, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Save Editor", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::End(); - return; - } - if (ImGui::BeginTabBar("SaveContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { if (ImGui::BeginTabItem("General")) { DrawGeneralTab(); @@ -1998,8 +1992,6 @@ void SaveEditorWindow::DrawElement() { ImGui::EndTabBar(); } - - ImGui::End(); } const char* textureLoad[8] = { gDungeonStrayFairyWoodfallIconTex, diff --git a/mm/2s2h/DeveloperTools/WarpPoint.cpp b/mm/2s2h/DeveloperTools/WarpPoint.cpp index 619d2ccfd..bb556eeb6 100644 --- a/mm/2s2h/DeveloperTools/WarpPoint.cpp +++ b/mm/2s2h/DeveloperTools/WarpPoint.cpp @@ -2,6 +2,7 @@ #include "2s2h/BenGui/UIWidgets.hpp" #include "window/gui/IconsFontAwesome4.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/DeveloperTools/DeveloperTools.h" extern "C" { #include "z64.h" @@ -13,8 +14,6 @@ extern SaveContext gSaveContext; extern GameState* gGameState; } -#define CV "gDeveloperTools.WarpPoint." - // 2S2H Added columns to scene table: entranceSceneId, betterMapSelectIndex, humanName #define DEFINE_SCENE(_name, enumValue, _textId, _drawConfig, _restrictionFlags, _persistentCycleFlags, \ _entranceSceneId, _betterMapSelectIndex, humanName) \ @@ -29,8 +28,9 @@ std::unordered_map warpPointSceneList = { #undef DEFINE_SCENE_UNSET void Warp() { - Vec3f pos = { CVarGetFloat(CV "X", 0.0f), CVarGetFloat(CV "Y", 0.0f), CVarGetFloat(CV "Z", 0.0f) }; - s32 entrance = CVarGetInteger(CV "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0)); + Vec3f pos = { CVarGetFloat(WARP_POINT_CVAR "X", 0.0f), CVarGetFloat(WARP_POINT_CVAR "Y", 0.0f), + CVarGetFloat(WARP_POINT_CVAR "Z", 0.0f) }; + s32 entrance = CVarGetInteger(WARP_POINT_CVAR "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0)); if (gPlayState == NULL) { // If gPlayState is NULL, it means the the user opted into BootToWarpPoint and the game is starting up. This is @@ -47,7 +47,7 @@ void Warp() { gSaveContext.save.playerForm = PLAYER_FORM_HUMAN; gSaveContext.save.linkAge = 0; gSaveContext.fileNum = 0xFF; - MapSelect_LoadGame((MapSelectState*)gGameState, CVarGetInteger(CV "Entrance", 0), 0); + MapSelect_LoadGame((MapSelectState*)gGameState, CVarGetInteger(WARP_POINT_CVAR "Entrance", 0), 0); } else { // The else case, and the rest of this function is primarly relevant code copied from Play_SetRespawnData and // func_80169EFC, minus the parts that copy scene flags to scene we are warping to (this is obviously @@ -57,9 +57,9 @@ void Warp() { gPlayState->transitionType = TRANS_TYPE_INSTANT; } gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = Entrance_Create(entrance >> 9, 0, entrance & 0xF); - gSaveContext.respawn[RESPAWN_MODE_DOWN].roomIndex = CVarGetInteger(CV "Room", 0); + gSaveContext.respawn[RESPAWN_MODE_DOWN].roomIndex = CVarGetInteger(WARP_POINT_CVAR "Room", 0); gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = pos; - gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = CVarGetFloat(CV "Rotation", 0.0f); + gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = CVarGetFloat(WARP_POINT_CVAR "Rotation", 0.0f); gSaveContext.respawn[RESPAWN_MODE_DOWN].playerParams = PLAYER_PARAMS(0xFF, PLAYER_INITMODE_D); gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK_FAST; gSaveContext.respawnFlag = -8; @@ -67,8 +67,8 @@ void Warp() { void RegisterWarpPoint() { GameInteractor::Instance->RegisterGameHook([]() { - if (!CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0) && CVarGetInteger(CV "BootToWarpPoint", 0) && - CVarGetInteger(CV "Saved", 0)) { + if (!CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0) && + CVarGetInteger(WARP_POINT_CVAR "BootToWarpPoint", 0) && CVarGetInteger(WARP_POINT_CVAR "Saved", 0)) { // Normally called on console logo screen gSaveContext.seqId = (u8)NA_BGM_DISABLED; gSaveContext.ambienceId = AMBIENCE_ID_DISABLED; @@ -85,28 +85,29 @@ void RenderWarpPointSection() { if (UIWidgets::Button("Set Warp Point")) { Player* player = GET_PLAYER(gPlayState); - CVarSetInteger(CV "Entrance", gSaveContext.save.entrance); - CVarSetInteger(CV "Room", gPlayState->roomCtx.curRoom.num); - CVarSetFloat(CV "X", player->actor.world.pos.x); - CVarSetFloat(CV "Y", player->actor.world.pos.y); - CVarSetFloat(CV "Z", player->actor.world.pos.z); - CVarSetFloat(CV "Rotation", player->actor.shape.rot.y); - CVarSetInteger(CV "Saved", 1); + CVarSetInteger(WARP_POINT_CVAR "Entrance", gSaveContext.save.entrance); + CVarSetInteger(WARP_POINT_CVAR "Room", gPlayState->roomCtx.curRoom.num); + CVarSetFloat(WARP_POINT_CVAR "X", player->actor.world.pos.x); + CVarSetFloat(WARP_POINT_CVAR "Y", player->actor.world.pos.y); + CVarSetFloat(WARP_POINT_CVAR "Z", player->actor.world.pos.z); + CVarSetFloat(WARP_POINT_CVAR "Rotation", player->actor.shape.rot.y); + CVarSetInteger(WARP_POINT_CVAR "Saved", 1); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } - if (CVarGetInteger(CV "Saved", 0)) { - u32 sceneId = Entrance_GetSceneIdAbsolute(CVarGetInteger(CV "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0))); + if (CVarGetInteger(WARP_POINT_CVAR "Saved", 0)) { + u32 sceneId = + Entrance_GetSceneIdAbsolute(CVarGetInteger(WARP_POINT_CVAR "Entrance", ENTRANCE(SOUTH_CLOCK_TOWN, 0))); ImGui::AlignTextToFramePadding(); - ImGui::Text("%s Room %d", warpPointSceneList[sceneId], CVarGetInteger(CV "Room", 0)); + ImGui::Text("%s Room %d", warpPointSceneList[sceneId], CVarGetInteger(WARP_POINT_CVAR "Room", 0)); ImGui::SameLine(); if (UIWidgets::Button(ICON_FA_TIMES, { .size = UIWidgets::Sizes::Inline })) { - CVarClear(CV "Entrance"); - CVarClear(CV "Room"); - CVarClear(CV "X"); - CVarClear(CV "Y"); - CVarClear(CV "Z"); - CVarClear(CV "Rotation"); - CVarClear(CV "Saved"); + CVarClear(WARP_POINT_CVAR "Entrance"); + CVarClear(WARP_POINT_CVAR "Room"); + CVarClear(WARP_POINT_CVAR "X"); + CVarClear(WARP_POINT_CVAR "Y"); + CVarClear(WARP_POINT_CVAR "Z"); + CVarClear(WARP_POINT_CVAR "Rotation"); + CVarClear(WARP_POINT_CVAR "Saved"); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } ImGui::SameLine(); diff --git a/mm/assets/custom/fonts/Inconsolata-Regular.ttf b/mm/assets/custom/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d1241516bc2357fadd283371e34055d9b1cc89a8 GIT binary patch literal 101752 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 literal 0 HcmV?d00001 From c474a82a94db5ad2fb97dcc55db2b491906a653f Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 2 Oct 2024 22:44:36 -0500 Subject: [PATCH 49/82] Mirror Mode (#535) * Mirror mode initial version * Update mm/src/code/z_actor.c Co-authored-by: Archez * mirror mode support for minimaps and dungeon pause map * mirror mode support overworld pause map and song of soaring * mirror mode support for various remaining things * mirror mode support pause warp enhancement * Add searchable menu item --------- Co-authored-by: Archez Co-authored-by: Archez --- mm/2s2h/BenGui/BenMenuBar.cpp | 8 + mm/2s2h/BenGui/SearchableMenuItems.h | 14 +- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 2 +- .../GameInteractor/GameInteractor.cpp | 12 +- .../GameInteractor/GameInteractor.h | 8 + mm/2s2h/Enhancements/NameTag/NameTag.cpp | 6 +- mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp | 134 ++++++++++------- mm/include/functions.h | 1 + mm/include/z64view.h | 1 + mm/src/audio/lib/synthesis.c | 6 +- mm/src/code/z_actor.c | 4 + mm/src/code/z_kankyo.c | 3 + mm/src/code/z_lib.c | 4 + mm/src/code/z_map_disp.c | 60 +++++++- mm/src/code/z_parameter.c | 8 + mm/src/code/z_play.c | 17 +++ mm/src/code/z_view.c | 41 ++++++ mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c | 12 ++ .../actors/ovl_En_Gakufu/z_en_gakufu.c | 5 + .../overlays/actors/ovl_En_Horse/z_en_horse.c | 3 + .../overlays/actors/ovl_En_Ossan/z_en_ossan.c | 12 ++ .../overlays/actors/ovl_En_Sob1/z_en_sob1.c | 12 ++ mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c | 12 ++ .../actors/ovl_player_actor/z_player.c | 30 ++-- .../ovl_kaleido_scope/z_kaleido_map.c | 139 +++++++++++++++++- .../ovl_kaleido_scope/z_kaleido_scope_NES.c | 6 +- 26 files changed, 487 insertions(+), 73 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 1a9ca3822..c2639b214 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -626,6 +626,14 @@ void DrawEnhancementsMenu() { if (UIWidgets::CVarCheckbox("Time Moves When You Move", "gModes.TimeMovesWhenYouMove")) { RegisterTimeMovesWhenYouMove(); } + if (UIWidgets::CVarCheckbox("Mirrored World", "gModes.MirroredWorld.Mode")) { + if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) { + CVarSetInteger("gModes.MirroredWorld.State", 1); + } else { + CVarClear("gModes.MirroredWorld.State"); + } + } + ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index a8d8c846f..a14843174 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -878,7 +878,19 @@ void AddEnhancements() { "Time only moves when Link is not standing still.", WIDGET_CVAR_CHECKBOX, {}, - ([](widgetInfo& info) { RegisterTimeMovesWhenYouMove(); }) } }, + ([](widgetInfo& info) { RegisterTimeMovesWhenYouMove(); }) }, + { "Mirrored World", + "gModes.MirroredWorld.Mode", + "Mirrors the world horizontally.", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { + if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) { + CVarSetInteger("gModes.MirroredWorld.State", 1); + } else { + CVarClear("gModes.MirroredWorld.State"); + } + }) } }, { { .widgetName = "Saving", .widgetType = WIDGET_SEPARATOR_TEXT }, { "Persistent Owl Saves", "gEnhancements.Saving.PersistentOwlSaves", "Continuing a save will not remove the owl save. Playing Song of " diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index 38b9bf6db..eafcaf5ba 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -172,7 +172,7 @@ void Camera_DebugCam(Camera* camera) { if (CVarGetInteger("gEnhancements.Camera.DebugCam.6DOF", 0)) { camera->roll += (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DLEFT) - CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DRIGHT)) * - 1200.0f * camSpeed; + 1200.0f * camSpeed * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X); } else { camera->roll = Camera_ScaledStepToCeilS(0, camera->roll, 0.1f, 5); } diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index aea90a0a9..fbaf19930 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -268,16 +268,24 @@ int GameInteractor_InvertControl(GIInvertType type) { break; } - /* // Invert all X axis inputs if the Mirrored World mode is enabled if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { switch (type) { case GI_INVERT_CAMERA_RIGHT_STICK_X: + case GI_INVERT_MOVEMENT_X: + case GI_INVERT_FIRST_PERSON_AIM_X: + case GI_INVERT_SHIELD_X: + case GI_INVERT_SHOP_X: + case GI_INVERT_HORSE_X: + case GI_INVERT_ZORA_SWIM_X: + case GI_INVERT_DEBUG_DPAD_X: + case GI_INVERT_TELESCOPE_X: result *= -1; break; + default: + break; } } - */ /* if (CrowdControl::State::InvertedInputs) { diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index e884782b0..c17be750c 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -67,6 +67,14 @@ typedef enum { typedef enum { GI_INVERT_CAMERA_RIGHT_STICK_X, GI_INVERT_CAMERA_RIGHT_STICK_Y, + GI_INVERT_MOVEMENT_X, + GI_INVERT_FIRST_PERSON_AIM_X, + GI_INVERT_SHIELD_X, + GI_INVERT_SHOP_X, + GI_INVERT_HORSE_X, + GI_INVERT_ZORA_SWIM_X, + GI_INVERT_DEBUG_DPAD_X, + GI_INVERT_TELESCOPE_X, } GIInvertType; typedef enum { diff --git a/mm/2s2h/Enhancements/NameTag/NameTag.cpp b/mm/2s2h/Enhancements/NameTag/NameTag.cpp index f20016c0a..19432377b 100644 --- a/mm/2s2h/Enhancements/NameTag/NameTag.cpp +++ b/mm/2s2h/Enhancements/NameTag/NameTag.cpp @@ -31,6 +31,7 @@ typedef struct { static std::vector nameTags; static std::vector nameTagDl; +static bool sMirrorWorldActive = false; void NameTag_RegisterHooks(); @@ -94,8 +95,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) { // Set position, billboard effect, scale (with mirror mode), then center nametag Matrix_Translate(nameTag->actor->world.pos.x, posY, nameTag->actor->world.pos.z, MTXMODE_NEW); Matrix_ReplaceRotation(&play->billboardMtxF); - // BENTODO: Apply mirror world flipping to X scale - Matrix_Scale(scale, -scale, 1.0f, MTXMODE_APPLY); + Matrix_Scale(scale * (sMirrorWorldActive ? -1.0f : 1.0f), -scale, 1.0f, MTXMODE_APPLY); Matrix_Translate(-(float)nameTag->width / 2, -nameTag->height, 0, MTXMODE_APPLY); Matrix_ToMtx(nameTag->mtx); @@ -206,6 +206,8 @@ void UpdateNameTags() { return aDistToCamera > bDistToCamera; }); + + sMirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0); } extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options) { diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp index a86c1b943..b3f591680 100644 --- a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp @@ -66,71 +66,101 @@ void HandleConfirmingState(PauseContext* pauseCtx, Input* input) { } } +// This is a variation of KaleidoScope_UpdateWorldMapCursor that deals with the warp points instead of region points +// and supports mirror mode void UpdateCursorForOwlWarpPoints(PauseContext* pauseCtx) { - if (pauseCtx->cursorSpecialPos == 0) { - if (pauseCtx->stickAdjX > 30) { + if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && + (pauseCtx->pageIndex == PAUSE_MAP)) { + InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx; + s16 oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + bool mirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0); + bool goingLeft = pauseCtx->stickAdjX < -30; + bool goingRight = pauseCtx->stickAdjX > 30; + + // Handle moving off page buttons + if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && goingRight) { + pauseCtx->cursorSpecialPos = 0; + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = mirrorWorldActive ? OWL_WARP_STONE_TOWER + 1 : REGION_NONE; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && goingLeft) { + pauseCtx->cursorSpecialPos = 0; + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = mirrorWorldActive ? REGION_NONE : OWL_WARP_STONE_TOWER + 1; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + + // Handle updating cursor color and A button action + if (pauseCtx->cursorSpecialPos == 0) { + pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_BLUE; + + if (gSaveContext.buttonStatus[EQUIP_SLOT_A] == BTN_DISABLED) { + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED; + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); + } + if (!sIsConfirming && interfaceCtx->aButtonHorseDoAction != DO_ACTION_WARP) { + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP); + } + } else { + pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE; + + if (gSaveContext.buttonStatus[EQUIP_SLOT_A] != BTN_DISABLED) { + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED; + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); + } + if (interfaceCtx->aButtonHorseDoAction != DO_ACTION_INFO) { + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_INFO); + } + } + + // Handle mirror mode flip and starting cursor movement + if (pauseCtx->cursorSpecialPos == 0 && (goingLeft || goingRight)) { pauseCtx->cursorShrinkRate = 4.0f; - sStickAdjTimer = 0; + + if (mirrorWorldActive) { + goingLeft = !goingLeft; + goingRight = !goingRight; + } + } + + // Actually move the cursor + if (goingRight) { do { pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++; if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) { - KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT); - return; + KaleidoScope_MoveCursorToSpecialPos(gPlayState, mirrorWorldActive ? PAUSE_CURSOR_PAGE_LEFT + : PAUSE_CURSOR_PAGE_RIGHT); + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + break; } } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); - if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { - pauseCtx->cursorItem[PAUSE_MAP] = - sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; - pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; - Audio_PlaySfx(NA_SE_SY_CURSOR); - } - } else if (pauseCtx->stickAdjX < -30) { - pauseCtx->cursorShrinkRate = 4.0f; - sStickAdjTimer = 0; + } else if (goingLeft) { do { pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--; - if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < OWL_WARP_GREAT_BAY_COAST) { - KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT); - return; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] <= REGION_NONE) { + KaleidoScope_MoveCursorToSpecialPos(gPlayState, mirrorWorldActive ? PAUSE_CURSOR_PAGE_RIGHT + : PAUSE_CURSOR_PAGE_LEFT); + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + break; } } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); - if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { - pauseCtx->cursorItem[PAUSE_MAP] = - sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; - pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; - Audio_PlaySfx(NA_SE_SY_CURSOR); - } - } else { - sStickAdjTimer++; } - } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && pauseCtx->stickAdjX > 30) { - KaleidoScope_MoveCursorFromSpecialPos(gPlayState); - for (int i = OWL_WARP_GREAT_BAY_COAST; i <= OWL_WARP_STONE_TOWER; i++) { - if (pauseCtx->worldMapPoints[i]) { - pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; - pauseCtx->cursorItem[PAUSE_MAP] = - sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; - pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; - KaleidoScope_UpdateWorldMapCursor(gPlayState); - KaleidoScope_UpdateNamePanel(gPlayState); - return; - } + + // Updates name panel and cursor slot + if (pauseCtx->cursorSpecialPos == 0) { + // Offset from `ITEM_MAP_POINT_GREAT_BAY` is to get the correct ordering in `map_name_static` + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + // Used as cursor vtxIndex + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; } - KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT); - } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && pauseCtx->stickAdjX < -30) { - KaleidoScope_MoveCursorFromSpecialPos(gPlayState); - for (int i = OWL_WARP_STONE_TOWER; i >= OWL_WARP_GREAT_BAY_COAST; i--) { - if (pauseCtx->worldMapPoints[i]) { - pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; - pauseCtx->cursorItem[PAUSE_MAP] = - sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; - pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; - KaleidoScope_UpdateWorldMapCursor(gPlayState); - KaleidoScope_UpdateNamePanel(gPlayState); - return; - } + + if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + } + if (oldCursorPoint != pauseCtx->cursorPoint[PAUSE_WORLD_MAP]) { + Audio_PlaySfx(NA_SE_SY_CURSOR); } - KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT); } } @@ -219,4 +249,4 @@ void RegisterPauseOwlWarp() { HandlePauseOwlWarp(pauseCtx); } }); -} \ No newline at end of file +} diff --git a/mm/include/functions.h b/mm/include/functions.h index 2388f8ca4..c4d91709f 100644 --- a/mm/include/functions.h +++ b/mm/include/functions.h @@ -1330,6 +1330,7 @@ void PadMgr_ThreadEntry(); void Heaps_Alloc(void); void KaleidoScope_UpdateOwlWarpNamePanel(PlayState* play); void KaleidoScope_UpdateNamePanel(PlayState* play); +void SkinMatrix_Clear(MtxF* mf); // #endregion // #region 2S2H [Port] New methods added for porting void AudioSeq_SetPortVolumeScale(u8 seqPlayerIndex, f32 volume); diff --git a/mm/include/z64view.h b/mm/include/z64view.h index 19bb4492c..a1ff7cd5c 100644 --- a/mm/include/z64view.h +++ b/mm/include/z64view.h @@ -41,6 +41,7 @@ typedef struct View { /* 0x15C */ u16 perspNorm; // used to normalize the projection matrix /* 0x160 */ u32 flags; // bit 3: Render to an orthographic perspective /* 0x164 */ s32 unk164; + /* */ Mtx* shipMirrorProjectionPtr; } View; // size = 0x168 #define VIEW_VIEWING (1 << 0) diff --git a/mm/src/audio/lib/synthesis.c b/mm/src/audio/lib/synthesis.c index 8cd0805be..951d52f21 100644 --- a/mm/src/audio/lib/synthesis.c +++ b/mm/src/audio/lib/synthesis.c @@ -867,7 +867,11 @@ Acmd* AudioSynth_ProcessSamples(s16* aiBuf, s32 numSamplesPerUpdate, Acmd* cmd, } size = numSamplesPerUpdate * SAMPLE_SIZE; - aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, size); + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + aInterleave(cmd++, DMEM_TEMP, DMEM_RIGHT_CH, DMEM_LEFT_CH, size); + } else { + aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, size); + } if (gAudioCustomSynthFunction != NULL) { cmd = gAudioCustomSynthFunction(cmd, 2 * size, updateIndex); diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 65f9c9bac..ac9add966 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -1402,6 +1402,10 @@ void func_800B6F20(PlayState* play, Input* input, f32 magnitude, s16 baseYaw) { s16 relativeYaw = baseYaw - Camera_GetInputDirYaw(GET_ACTIVE_CAM(play)); input->cur.stick_x = -Math_SinS(relativeYaw) * magnitude; + // 2S2H [Enhancement] Allow inverting the X axis with GI, primarily for mirror mode, + // otherwise link moves in the opposite direction and likely get soft locked, and + // kafei turns the wrong direction as he paths. + input->cur.stick_x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); input->rel.stick_x = input->cur.stick_x; input->cur.stick_y = Math_CosS(relativeYaw) * magnitude; input->rel.stick_y = input->cur.stick_y; diff --git a/mm/src/code/z_kankyo.c b/mm/src/code/z_kankyo.c index efeb6084f..f8c6a02a0 100644 --- a/mm/src/code/z_kankyo.c +++ b/mm/src/code/z_kankyo.c @@ -3326,6 +3326,9 @@ void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) { if ((scale >= 1.0f) && (imgX > -adjustedXBounds) && (imgX < adjustedXBounds) && (imgY > -1.0f) && (imgY < 1.0f)) { + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + imgX *= -1.0f; + } // #endregion imgX = (imgX * (SCREEN_WIDTH / 2)) + (SCREEN_WIDTH / 2); imgY = (imgY * -(SCREEN_HEIGHT / 2)) + (SCREEN_HEIGHT / 2); diff --git a/mm/src/code/z_lib.c b/mm/src/code/z_lib.c index b2ff2c086..5ca4d4f7a 100644 --- a/mm/src/code/z_lib.c +++ b/mm/src/code/z_lib.c @@ -1,5 +1,7 @@ #include "global.h" #include +#include "BenPort.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; @@ -223,12 +225,14 @@ void Lib_GetControlStickData(f32* outMagnitude, s16* outAngle, Input* input) { f32 y = input->rel.stick_y; f32 magnitude; + x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); magnitude = sqrtf(SQ(x) + SQ(y)); *outMagnitude = (60.0f < magnitude) ? 60.0f : magnitude; if (magnitude > 0.0f) { x = input->cur.stick_x; y = input->cur.stick_y; + x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); *outAngle = Math_Atan2S_XY(y, -x); } else { *outAngle = 0; diff --git a/mm/src/code/z_map_disp.c b/mm/src/code/z_map_disp.c index e7a0197ae..6f2ce25fb 100644 --- a/mm/src/code/z_map_disp.c +++ b/mm/src/code/z_map_disp.c @@ -156,6 +156,31 @@ static const char* sMapGrandTextures[] = { map_grand_static_Blob_034BB0, map_grand_static_Blob_034F50, }; +static bool sMirrorWorldActive = false; +static u16 sOriginalMapDataRoomFlags[32] = { 0 }; + +s32 Ship_MapModifyPosMirrorMode(s32 pos, s32 offset) { + if (sMirrorWorldActive) { + pos -= offset; + pos *= -1; + pos += offset; + } + return pos; +} + +void Ship_MapDispUpdateMirrorMode() { + sMirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0); + + for (s32 i = 0; i < sSceneNumRooms; i++) { + sMapDataRooms[i].flags = sOriginalMapDataRoomFlags[i]; + + if (sMirrorWorldActive) { + // Toggle the bit in case the scene already has this flag set, this way the map is still "flipped" visually + sMapDataRooms[i].flags ^= MAP_DATA_ROOM_FLIP_X; + } + } +} + // BENTODO, can we just set dest insetead of doing a memcpy? void MapDisp_GetMapITexture(void* dst, s32 mapCompactId) { s32 mapSize = MapDisp_GetSizeOfMapITex(mapCompactId); @@ -414,6 +439,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) { sMapDisp.minimapCurY - sMapDisp.minimapBaseY + texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { // #region 2S2H [Cosmetic] Hud Editor override actor values and use them below @@ -449,6 +477,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) { if (MapDisp_IsDataRotated(play)) { compassRot += 0x7FFF; } + if (sMirrorWorldActive) { + compassRot *= -1; + } Matrix_RotateYF(compassRot / 10.0f, MTXMODE_APPLY); Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); // #region 2S2H [Cosmetic] Hud Editor yellow compass matrix scale on x and z @@ -586,6 +617,9 @@ void MapDisp_Minimap_DrawDoorActor(PlayState* play, Actor* actor) { texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { OPEN_DISPS(play->state.gfxCtx); @@ -893,6 +927,8 @@ void MapDisp_InitMapData(PlayState* play, void* segmentAddress) { for (i = 0; i < sSceneNumRooms; i++) { sMapDataRooms[i] = *mapDataRooms++; + // 2S2H [Enhancement] Track original flags to that we can make modifications mid-scene + sOriginalMapDataRoomFlags[i] = sMapDataRooms[i].flags; } sMapDataScene.rooms = sMapDataRooms; @@ -996,6 +1032,7 @@ void MapDisp_Update(PlayState* play) { s16 targetY; if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0)) { + Ship_MapDispUpdateMirrorMode(); // #region 2S2H [Cosmetic] Hud Editor minimap base position // This value is used to determine the relative positioning for all the other elements MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; @@ -1161,6 +1198,8 @@ void MapDisp_SwapRooms(s16 nextRoom) { (f32)prevOffsetY); } + sMapDisp.minimapPrevX = Ship_MapModifyPosMirrorMode(sMapDisp.minimapPrevX, offsetX - prevOffsetX); + sMapDisp.minimapCurX = minimapBaseX - sMapDisp.minimapPrevX; sMapDisp.minimapCurY = minimapBaseY - sMapDisp.minimapPrevY; } @@ -1243,6 +1282,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot) (sMapDisp.minimapCurY - sMapDisp.minimapBaseY) + texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { // 2S2H [Cosmetic] Hud Editor red compass position @@ -1264,6 +1306,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot) if (MapDisp_IsDataRotated(play)) { rot += 0x7FFF; } + if (sMirrorWorldActive) { + rot *= -1; + } Matrix_RotateYF(rot / 10.0f, MTXMODE_APPLY); Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); // #region 2S2H [Cosmetic] Hud Editor red compass scale the matrix in x and z @@ -1642,7 +1687,10 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) { offsetX = ((texWidth / 2) - offsetX) + (texWidth / 2); - s = (texWidth - 1) << 5; + // 2S2H [Port] The width originally was subtracted by 1, but this caused the flipped texture to overflow on + // the edge. There are no vanilla scenes that leverage this, so its possibly an authentic bug. + // Removing it will allow the texture to display correctly for things like Mirror Mode. + s = (texWidth - 0) << 5; dsdx = 0xFC00; } else { s = 0; @@ -1665,6 +1713,8 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 texPosY = ((mapDataRoom->centerZ - (f32)sMapDisp.sceneMidZ) * scaleFrac - offsetY) + ((viewHeight / two) + viewY); + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / two) + viewX)); + if (i == play->roomCtx.curRoom.num) { if (Map_IsInBossScene(play)) { gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 1, @@ -1781,6 +1831,8 @@ void MapDisp_DrawChests(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s3 texPosY = (s32)((((mapDataChests[i].z - (f32)sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + ((viewHeight / 2) + viewY)); + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -1833,6 +1885,9 @@ void MapDisp_DrawRoomExits(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, ((viewWidth / 2) + viewX); texPosY = ((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac + ((viewHeight / 2) + viewY); + + texPosX = Ship_MapModifyPosMirrorMode(texPosX, ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, ((texPosX - 1) << 2), ((texPosY - 1) << 2), ((texPosX + 1) << 2), ((texPosY + 1) << 2), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); @@ -1894,6 +1949,9 @@ void MapDisp_DrawBossIcon(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, ((viewWidth / 2) + viewX); texPosY = ((((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + ((viewHeight / 2) + viewY); + + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index bf3faab58..da73d18fb 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -8610,7 +8610,15 @@ void Interface_Draw(PlayState* play) { Map_DrawMinimap(play); if ((R_PAUSE_BG_PRERENDER_STATE != 2) && (R_PAUSE_BG_PRERENDER_STATE != 3)) { + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + } Target_Draw(&play->actorCtx.targetCtx, play); + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.projectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + } } Gfx_SetupDL39_Overlay(play->state.gfxCtx); diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index 024c0fe12..80492c22e 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -1248,6 +1248,18 @@ void Play_DrawMain(PlayState* this) { View_Apply(&this->view, 0xF); + // Setup mirror mode matrix handling when we are not drawing kaleido + if (R_PAUSE_BG_PRERENDER_STATE <= PAUSE_BG_PRERENDER_SETUP && CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + gSPMatrix(POLY_OPA_DISP++, this->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPMatrix(POLY_XLU_DISP++, this->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPMatrix(POLY_OPA_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + gSPMatrix(POLY_XLU_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + } + // The billboard matrix temporarily stores the viewing matrix Matrix_MtxToMtxF(&this->view.viewing, &this->billboardMtxF); Matrix_MtxToMtxF(&this->view.projection, &this->viewProjectionMtxF); @@ -1523,6 +1535,11 @@ void Play_DrawMain(PlayState* this) { Play_PostWorldDraw(this); } } + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + } } SkipPostWorldDraw: diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 8fedc585f..83801471b 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -325,6 +325,7 @@ s32 View_ApplyPerspective(View* view) { s32 height; Vp* vp; Mtx* projection; + Mtx* projectionFlipped; Mtx* viewing; GraphicsContext* gfxCtx = view->gfxCtx; @@ -342,13 +343,26 @@ s32 View_ApplyPerspective(View* view) { // Perspective projection projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; width = view->viewport.rightX - view->viewport.leftX; height = view->viewport.bottomY - view->viewport.topY; aspect = (f32)width / (f32)height; guPerspective(projection, &view->perspNorm, view->fovy, aspect, view->zNear, view->zFar, view->scale); + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + MtxF flipF; + SkinMatrix_Clear(&flipF); + flipF.xx = -1.0; + MtxF projectionF; + Matrix_MtxToMtxF(projection, &projectionF); + SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + Matrix_MtxFToMtx(&projectionF, projectionFlipped); + } + view->projection = *projection; View_StepDistortion(view, projection); @@ -450,6 +464,7 @@ s32 View_ApplyPerspective(View* view) { s32 View_ApplyOrtho(View* view) { Vp* vp; Mtx* projection; + Mtx* projectionFlipped; GraphicsContext* gfxCtx = view->gfxCtx; OPEN_DISPS(gfxCtx); @@ -465,11 +480,23 @@ s32 View_ApplyOrtho(View* view) { gSPViewport(OVERLAY_DISP++, vp); projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f, view->zNear, view->zFar, view->scale); + // if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + // MtxF flipF; + // SkinMatrix_Clear(&flipF); + // flipF.xx = -1.0; + // MtxF projectionF; + // Matrix_MtxToMtxF(projection, &projectionF); + // SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + // Matrix_MtxFToMtx(&projectionF, projectionFlipped); + // } + view->projection = *projection; gSPMatrix(POLY_OPA_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); @@ -486,6 +513,7 @@ s32 View_ApplyOrtho(View* view) { s32 View_ApplyOrthoToOverlay(View* view) { Vp* vp; Mtx* projection; + Mtx* projectionFlipped; GraphicsContext* gfxCtx; gfxCtx = view->gfxCtx; @@ -509,10 +537,23 @@ s32 View_ApplyOrthoToOverlay(View* view) { gSPViewport(OVERLAY_DISP++, vp); projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f, view->zNear, view->zFar, view->scale); + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + MtxF flipF; + SkinMatrix_Clear(&flipF); + flipF.xx = -1.0; + MtxF projectionF; + Matrix_MtxToMtxF(projection, &projectionF); + SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + Matrix_MtxFToMtx(&projectionF, projectionFlipped); + } + view->projection = *projection; gSPMatrix(OVERLAY_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); diff --git a/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c b/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c index 5cd3ce2a6..7ea427bd0 100644 --- a/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c +++ b/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c @@ -6,6 +6,7 @@ #include "z_en_fsn.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) @@ -452,6 +453,10 @@ void EnFsn_UpdateCursorPos(EnFsn* this, PlayState* play) { this->cursorPos.x = x + xOffset; this->cursorPos.y = y + yOffset; this->cursorPos.z = 1.2f; + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x; + } } s32 EnFsn_FacingShopkeeperDialogResult(EnFsn* this, PlayState* play) { @@ -509,6 +514,8 @@ void EnFsn_UpdateJoystickInputState(EnFsn* this, PlayState* play) { s8 stickX = CONTROLLER1(&play->state)->rel.stick_x; s8 stickY = CONTROLLER1(&play->state)->rel.stick_y; + stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X); + if (this->stickAccumX == 0) { if ((stickX > 30) || (stickX < -30)) { this->stickAccumX = stickX; @@ -1602,6 +1609,11 @@ void EnFsn_DrawStickDirectionPrompts(EnFsn* this, PlayState* play) { s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled; s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled; + if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) { + drawStickLeftPrompt = !drawStickLeftPrompt; + drawStickRightPrompt = !drawStickRightPrompt; + } + OPEN_DISPS(play->state.gfxCtx); if (drawStickRightPrompt || drawStickLeftPrompt) { diff --git a/mm/src/overlays/actors/ovl_En_Gakufu/z_en_gakufu.c b/mm/src/overlays/actors/ovl_En_Gakufu/z_en_gakufu.c index af3069c51..d67e751d5 100644 --- a/mm/src/overlays/actors/ovl_En_Gakufu/z_en_gakufu.c +++ b/mm/src/overlays/actors/ovl_En_Gakufu/z_en_gakufu.c @@ -267,6 +267,11 @@ void EnGakufu_Draw(Actor* thisx, PlayState* play) { gDPPipeSync(POLY_XLU_DISP++); gSPSegment(POLY_XLU_DISP++, 0x02, play->interfaceCtx.parameterSegment); + // Invert the whole music staff, so the notes appear correctly in mirrored world + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + Matrix_Scale(-1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + } + for (i = 0; (i < ARRAY_COUNT(this->buttonIndex)) && (this->buttonIndex[i] != OCARINA_BTN_INVALID); i++) { Matrix_Push(); Matrix_Translate(30 * i - 105, sOcarinaBtnWallYOffsets[this->buttonIndex[i]] * 7.5f, 1.0f, MTXMODE_APPLY); diff --git a/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c index a0066f376..a6e7fec72 100644 --- a/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c +++ b/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c @@ -12,6 +12,7 @@ #include "overlays/actors/ovl_Obj_Um/z_obj_um.h" #include "overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.h" #include "objects/object_horse_link_child/object_horse_link_child.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) @@ -3691,6 +3692,8 @@ void EnHorse_UpdateStick(EnHorse* this, PlayState* play) { this->lastStick = this->curStick; this->curStick.x = input->rel.stick_x; this->curStick.z = input->rel.stick_y; + + this->curStick.x *= GameInteractor_InvertControl(GI_INVERT_HORSE_X); } void EnHorse_ResolveCollision(EnHorse* this, PlayState* play, CollisionPoly* colPoly) { diff --git a/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c b/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c index dd24fbe43..3e15732da 100644 --- a/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c +++ b/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c @@ -6,6 +6,7 @@ #include "z_en_ossan.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) @@ -298,6 +299,10 @@ void EnOssan_UpdateCursorPos(PlayState* play, EnOssan* this) { Actor_GetScreenPos(play, &this->items[this->cursorIndex]->actor, &x, &y); this->cursorPos.x = x; this->cursorPos.y = y; + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x; + } } void EnOssan_EndInteraction(PlayState* play, EnOssan* this) { @@ -465,6 +470,8 @@ void EnOssan_UpdateJoystickInputState(PlayState* play, EnOssan* this) { s8 stickX = CONTROLLER1(&play->state)->rel.stick_x; s8 stickY = CONTROLLER1(&play->state)->rel.stick_y; + stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X); + this->moveHorizontal = this->moveVertical = false; if (this->stickAccumX == 0) { @@ -1680,6 +1687,11 @@ void EnOssan_DrawStickDirectionPrompts(PlayState* play, EnOssan* this) { s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled; s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled; + if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) { + drawStickLeftPrompt = !drawStickLeftPrompt; + drawStickRightPrompt = !drawStickRightPrompt; + } + (void)"../z_en_oB1.c"; OPEN_DISPS(play->state.gfxCtx); diff --git a/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c b/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c index 761d2f468..13c1eb329 100644 --- a/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c +++ b/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c @@ -8,6 +8,7 @@ #include "objects/object_mastergolon/object_mastergolon.h" #include "objects/object_masterzoora/object_masterzoora.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) @@ -456,6 +457,10 @@ void EnSob1_UpdateCursorPos(PlayState* play, EnSob1* this) { this->cursorPos.x = x + xOffset; this->cursorPos.y = y + yOffset; this->cursorPos.z = 1.2f; + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x; + } } void EnSob1_EndInteraction(PlayState* play, EnSob1* this) { @@ -584,6 +589,8 @@ void EnSob1_UpdateJoystickInputState(PlayState* play, EnSob1* this) { s8 stickX = CONTROLLER1(&play->state)->rel.stick_x; s8 stickY = CONTROLLER1(&play->state)->rel.stick_y; + stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X); + if (this->stickAccumX == 0) { if ((stickX > 30) || (stickX < -30)) { this->stickAccumX = stickX; @@ -1579,6 +1586,11 @@ void EnSob1_DrawStickDirectionPrompt(PlayState* play, EnSob1* this) { s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled; s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled; + if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) { + drawStickLeftPrompt = !drawStickLeftPrompt; + drawStickRightPrompt = !drawStickRightPrompt; + } + (void)"../z_en_soB1.c"; OPEN_DISPS(play->state.gfxCtx); diff --git a/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c b/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c index 08b977732..40eda53bf 100644 --- a/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c +++ b/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c @@ -7,6 +7,7 @@ #include "z_en_trt.h" #include "objects/object_trt/object_trt.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY) @@ -166,6 +167,10 @@ void EnTrt_UpdateCursorPos(PlayState* play, EnTrt* this) { this->cursorPos.x = x + xOffset; this->cursorPos.y = y + yOffset; this->cursorPos.z = 1.2f; + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x; + } } void EnTrt_SetupGetMushroomCutscene(EnTrt* this) { @@ -273,6 +278,8 @@ void EnTrt_UpdateJoystickInputState(PlayState* play, EnTrt* this) { s8 stickX = CONTROLLER1(&play->state)->rel.stick_x; s8 stickY = CONTROLLER1(&play->state)->rel.stick_y; + stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X); + if (this->stickAccumX == 0) { if ((stickX > 30) || (stickX < -30)) { this->stickAccumX = stickX; @@ -1657,6 +1664,11 @@ void EnTrt_DrawStickDirectionPrompt(PlayState* play, EnTrt* this) { s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled; s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled; + if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) { + drawStickLeftPrompt = !drawStickLeftPrompt; + drawStickRightPrompt = !drawStickRightPrompt; + } + (void)"../z_en_trt.c"; OPEN_DISPS(play->state.gfxCtx); diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index c728cd4fe..11863f312 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -8330,6 +8330,7 @@ void func_8083A98C(Actor* thisx, PlayState* play2) { // Yaw: shape.rot.y is used as a fixed starting position inputX = sPlayerControlInput->rel.stick_x * -4; + inputX *= GameInteractor_InvertControl(GI_INVERT_TELESCOPE_X); // Start from current position: no input -> no change newYaw = thisx->focus.rot.y - thisx->shape.rot.y; // Add input, clamped to prevent turning too fast @@ -12562,9 +12563,9 @@ s32 Player_UpdateNoclip(Player* this, PlayState* play) { if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DDOWN)) { angle = temp + 0x8000; } else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DLEFT)) { - angle = temp + 0x4000; + angle = temp + 0x4000 * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X); } else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DRIGHT)) { - angle = temp - 0x4000; + angle = temp - 0x4000 * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X); } this->actor.world.pos.x += speed * Math_SinS(angle); @@ -13006,12 +13007,15 @@ void Player_Destroy(Actor* thisx, PlayState* play) { s32 func_80847190(PlayState* play, Player* this, s32 arg2) { s32 pad; s16 var_s0; + s32 stickX = sPlayerControlInput->rel.stick_x; + + stickX *= GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_AIM_X); if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) { var_s0 = sPlayerControlInput->rel.stick_y * 0xF0; Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E); - var_s0 = sPlayerControlInput->rel.stick_x * -0x10; + var_s0 = stickX * -0x10; var_s0 = CLAMP(var_s0, -0xBB8, 0xBB8); this->actor.focus.rot.y += var_s0; } else { @@ -13028,8 +13032,7 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) { } var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y; - temp3 = ((sPlayerControlInput->rel.stick_x >= 0) ? 1 : -1) * - (s32)((1.0f - Math_CosS(sPlayerControlInput->rel.stick_x * 0xC8)) * -1500.0f); + temp3 = ((stickX >= 0) ? 1 : -1) * (s32)((1.0f - Math_CosS(stickX * 0xC8)) * -1500.0f); var_s0 += temp3; this->actor.focus.rot.y = CLAMP(var_s0, -0x4AAA, 0x4AAA) + this->actor.shape.rot.y; @@ -14630,6 +14633,7 @@ void Player_Action_18(Player* this, PlayState* play) { s16 var_a2; s16 var_a3; + xStick *= GameInteractor_InvertControl(GI_INVERT_SHIELD_X); var_a1 = (yStick * Math_CosS(temp_a0)) + (Math_SinS(temp_a0) * xStick); temp_ft5 = (xStick * Math_CosS(temp_a0)) - (Math_SinS(temp_a0) * yStick); @@ -16006,6 +16010,8 @@ void Player_Action_50(Player* this, PlayState* play) { PlayerAnimationHeader* anim1; PlayerAnimationHeader* anim2; + xStick *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); + this->fallStartHeight = this->actor.world.pos.y; this->stateFlags2 |= PLAYER_STATE2_40; @@ -16564,11 +16570,14 @@ void func_80850BA8(Player* this) { void func_80850BF8(Player* this, f32 arg1) { f32 temp_fv0; s16 temp_ft0; + s8 stickX = sPlayerControlInput->rel.stick_x; + + stickX *= GameInteractor_InvertControl(GI_INVERT_ZORA_SWIM_X); Math_AsymStepToF(&this->unk_B48, arg1, 1.0f, (fabsf(this->unk_B48) * 0.01f) + 0.4f); - temp_fv0 = Math_CosS(sPlayerControlInput->rel.stick_x * 0x10E); + temp_fv0 = Math_CosS(stickX * 0x10E); - temp_ft0 = (((sPlayerControlInput->rel.stick_x >= 0) ? 1 : -1) * (1.0f - temp_fv0) * -1100.0f); + temp_ft0 = (((stickX >= 0) ? 1 : -1) * (1.0f - temp_fv0) * -1100.0f); temp_ft0 = CLAMP(temp_ft0, -0x1F40, 0x1F40); this->currentYaw += temp_ft0; @@ -16585,6 +16594,9 @@ void Player_Action_56(Player* this, PlayState* play) { s16 sp3E; s16 sp3C; s16 sp3A; + s8 stickX = sPlayerControlInput->rel.stick_x; + + stickX *= GameInteractor_InvertControl(GI_INVERT_ZORA_SWIM_X); this->stateFlags2 |= PLAYER_STATE2_20; @@ -16634,7 +16646,7 @@ void Player_Action_56(Player* this, PlayState* play) { } } - Math_SmoothStepToS(&this->unk_B86[1], sPlayerControlInput->rel.stick_x * 0xC8, 0xA, 0x3E8, 0x64); + Math_SmoothStepToS(&this->unk_B86[1], stickX * 0xC8, 0xA, 0x3E8, 0x64); Math_SmoothStepToS(&this->unk_B8E, this->unk_B86[1], IREG(40) + 1, IREG(41), IREG(42)); } else if (this->unk_B86[0] == 0) { PlayerAnimation_Update(play, &this->skelAnime); @@ -16662,7 +16674,7 @@ void Player_Action_56(Player* this, PlayState* play) { Math_SmoothStepToS(&this->unk_AAA, sp3E, 4, 0xFA0, 0x190); // X - sp42 = sPlayerControlInput->rel.stick_x * 0x64; + sp42 = stickX * 0x64; if (Math_ScaledStepToS(&this->unk_B8A, sp42, 0x384) && (sp42 == 0)) { Math_SmoothStepToS(&this->unk_B86[1], 0, 4, 0x5DC, 0x64); Math_SmoothStepToS(&this->unk_B8E, this->unk_B86[1], IREG(44) + 1, IREG(45), IREG(46)); diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c index 7915bbab6..9ae8cb101 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c @@ -550,6 +550,18 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { OPEN_DISPS(play->state.gfxCtx); + // Use matrix scaling to flip the entire overworld map for mirror world + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + // Invert culling to counter act the matrix flip + gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + Matrix_Push(); + // We need to shift the matrix a little to the left before flipping it so that it aligns in the same spot + Matrix_Translate(-2.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Matrix_Scale(-1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + Matrix_Pop(); + } + KaleidoScope_SetCursorVtxPos(pauseCtx, pauseCtx->cursorSlot[PAUSE_MAP] * 4, pauseCtx->mapPageVtx); // Draw the world map image @@ -852,14 +864,24 @@ void KaleidoScope_DrawWorldMap(PlayState* play) { gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - POLY_OPA_DISP = - Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16, sWorldMapCursorsRectLeft[n], - sWorldMapCursorsRectTop[n], 16, 16, 1 << 10, 1 << 10); + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + POLY_OPA_DISP = Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16, + (SCREEN_WIDTH - sWorldMapCursorsRectLeft[n] - 16 - 1), + sWorldMapCursorsRectTop[n], 16, 16, 1 << 10, 1 << 10); + } else { + POLY_OPA_DISP = Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16, + sWorldMapCursorsRectLeft[n], sWorldMapCursorsRectTop[n], 16, 16, + 1 << 10, 1 << 10); + } } } gDPPipeSync(POLY_OPA_DISP++); + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + } + CLOSE_DISPS(play->state.gfxCtx); } @@ -876,11 +898,122 @@ u16 sOwlWarpPauseItems[] = { ITEM_MAP_POINT_STONE_TOWER, // OWL_WARP_STONE_TOWER }; +// 2S2H [Enhancement] Same as KaleidoScope_UpdateWorldMapCursor but with behavior and controls inverted to account for +// mirrored world being used +void Ship_UpdateWorldMapCursorMirrorWorld(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + s16 oldCursorPoint; + + bool goingLeft = pauseCtx->stickAdjX < -30; + bool goingRight = pauseCtx->stickAdjX > 30; + + if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && + (pauseCtx->pageIndex == PAUSE_MAP) && !PauseOwlWarp_IsOwlWarpEnabled()) { + pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE; + oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + + if (gSaveContext.buttonStatus[EQUIP_SLOT_A] != BTN_DISABLED) { + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED; + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); + } + + if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && goingRight) { + pauseCtx->cursorSpecialPos = 0; + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = REGION_MAX; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && goingLeft) { + pauseCtx->cursorSpecialPos = 0; + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = REGION_NONE; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + + if (pauseCtx->cursorSpecialPos == 0 && (goingLeft || goingRight)) { + pauseCtx->cursorShrinkRate = 4.0f; + goingLeft = !goingLeft; + goingRight = !goingRight; + } + + if (goingRight) { + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] >= REGION_MAX) { + KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_LEFT); + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + break; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + } else if (goingLeft) { + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] <= REGION_NONE) { + KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_RIGHT); + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + break; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + } + + if (pauseCtx->cursorSpecialPos == 0) { + pauseCtx->cursorItem[PAUSE_MAP] = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + // Used as cursor vtxIndex + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + } + + if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE; + } + if (oldCursorPoint != pauseCtx->cursorPoint[PAUSE_WORLD_MAP]) { + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } else if (pauseCtx->state == PAUSE_STATE_OWLWARP_SELECT) { + pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_BLUE; + oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + + if (goingLeft || goingRight) { + pauseCtx->cursorShrinkRate = 4.0f; + goingLeft = !goingLeft; + goingRight = !goingRight; + } + + if (goingRight) { + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = OWL_WARP_GREAT_BAY_COAST; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + } else if (goingLeft) { + do { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--; + if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < OWL_WARP_GREAT_BAY_COAST) { + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = OWL_WARP_STONE_TOWER; + } + } while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]); + } + + // Offset from `ITEM_MAP_POINT_GREAT_BAY` is to get the correct ordering in `map_name_static` + pauseCtx->cursorItem[PAUSE_MAP] = + sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY; + // Used as cursor vtxIndex + pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + + if (oldCursorPoint != pauseCtx->cursorPoint[PAUSE_WORLD_MAP]) { + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } +} + void KaleidoScope_UpdateWorldMapCursor(PlayState* play) { static u16 sStickAdjTimer = 0; // unused timer that counts up every frame. Resets on reading a stickAdj. PauseContext* pauseCtx = &play->pauseCtx; s16 oldCursorPoint; + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + Ship_UpdateWorldMapCursorMirrorWorld(play); + return; + } + if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && (pauseCtx->pageIndex == PAUSE_MAP) && !PauseOwlWarp_IsOwlWarpEnabled()) { pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index f060ed01e..4bcb9ed18 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -2918,13 +2918,17 @@ void KaleidoScope_UpdateCursorSize(PlayState* play) { pauseCtx->cursorX = sWorldMapCursorsX[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; pauseCtx->cursorY = sWorldMapCursorsY[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; } - if (!IS_PAUSE_STATE_OWLWARP) { + if (!IS_PAUSE_STATE_OWLWARP && !PauseOwlWarp_IsOwlWarpEnabled()) { pauseCtx->cursorHeight = 10.0f; pauseCtx->cursorWidth = 10.0f; } else { pauseCtx->cursorHeight = 15.0f; pauseCtx->cursorWidth = 15.0f; } + // Flip the position of the cursor with an additional offset to align with flipped map points + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + pauseCtx->cursorX = (pauseCtx->cursorX * -1.0) + 5.0f; + } } else { pauseCtx->cursorX = sDungeonMapCursorsX[pauseCtx->cursorPoint[PAUSE_MAP]]; pauseCtx->cursorY = sDungeonMapCursorsY[pauseCtx->cursorPoint[PAUSE_MAP]]; From f31674a12e7f886d1212c1cf9e1b00ff2dad3535 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 3 Oct 2024 15:02:51 -0500 Subject: [PATCH 50/82] Add fix for ikana great fairy fountain color (#788) --- mm/2s2h/BenGui/BenMenuBar.cpp | 4 ++++ mm/2s2h/BenGui/SearchableMenuItems.h | 4 ++++ mm/src/code/z_kankyo.c | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index c2639b214..962132b5f 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -541,6 +541,10 @@ void DrawEnhancementsMenu() { { .tooltip = "Fixes certain control characters not functioning properly " "depending on their position within the text." }); + UIWidgets::CVarCheckbox("Fix Ikana Great Fairy Fountain Color", "gFixes.FixIkanaGreatFairyFountainColor", + { .tooltip = "Fixes a bug that results in the Ikana Great Fairy fountain looking " + "green instead of yellow, this was fixed in the EU version" }); + ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index a14843174..2cf52494f 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1127,6 +1127,10 @@ void AddEnhancements() { { "Fix Text Control Characters", "gEnhancements.Fixes.ControlCharacters", "Fixes certain control characters not functioning properly " "depending on their position within the text.", + WIDGET_CVAR_CHECKBOX }, + { "Fix Ikana Great Fairy Fountain Color", "gFixes.FixIkanaGreatFairyFountainColor", + "Fixes a bug that results in the Ikana Great Fairy fountain looking green instead of yellow, this was " + "fixed in the EU version", WIDGET_CVAR_CHECKBOX } } } }); enhancementsSidebar.push_back( { "Restorations", diff --git a/mm/src/code/z_kankyo.c b/mm/src/code/z_kankyo.c index f8c6a02a0..86d8abb27 100644 --- a/mm/src/code/z_kankyo.c +++ b/mm/src/code/z_kankyo.c @@ -723,7 +723,9 @@ void Environment_Init(PlayState* play2, EnvironmentContext* envCtx, s32 arg2) { if (gSaveContext.retainWeatherMode || (gSaveContext.respawnFlag != 0)) { switch ((u32)gWeatherMode) { case WEATHER_MODE_2: - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE) && + (!CVarGetInteger("gFixes.FixIkanaGreatFairyFountainColor", 0) || + (play->sceneId != SCENE_YOUSEI_IZUMI))) { play->skyboxId = SKYBOX_3; envCtx->lightConfig = 5; envCtx->changeLightNextConfig = 5; From d3933591b50061f6d3688d73e60b8771a6fce7e7 Mon Sep 17 00:00:00 2001 From: Archez Date: Fri, 4 Oct 2024 15:30:10 -0400 Subject: [PATCH 51/82] Simplify Pause Warp confirming logic and message handling (#793) --- mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp | 108 +++++--------------- 1 file changed, 28 insertions(+), 80 deletions(-) diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp index b3f591680..35f27f4f2 100644 --- a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp @@ -18,51 +18,32 @@ extern "C" bool PauseOwlWarp_IsOwlWarpEnabled() { gPlayState->pauseCtx.debugEditor == DEBUG_EDITOR_NONE; } -static bool sIsConfirming = false; -static u16 sStickAdjTimer = 0; - -void ResetMessageContext() { - gPlayState->msgCtx.msgLength = 0; - gPlayState->msgCtx.msgMode = MSGMODE_NONE; -} - -void ClosePauseMenu(PauseContext* pauseCtx) { - Interface_SetAButtonDoAction(gPlayState, DO_ACTION_NONE); - Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); - gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_END; - gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL; - sIsConfirming = false; - Message_CloseTextbox(gPlayState); - pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; -} - void HandleConfirmingState(PauseContext* pauseCtx, Input* input) { if (Message_ShouldAdvance(gPlayState)) { - ResetMessageContext(); - sIsConfirming = false; if (gPlayState->msgCtx.choiceIndex == 0) { // Yes Interface_SetAButtonDoAction(gPlayState, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + sPauseMenuVerticalOffset = -6240.0f; Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); gPlayState->msgCtx.ocarinaMode = sCursorPointsToOcarinaModes[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; Audio_PlaySfx(NA_SE_SY_DECIDE); + Message_CloseTextbox(gPlayState); - sPauseMenuVerticalOffset = -6240.0f; - pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + gPlayState->nextEntrance = D_80AF343C[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; gPlayState->transitionTrigger = TRANS_TRIGGER_START; gPlayState->transitionType = TRANS_TYPE_FADE_WHITE; } else { // No Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP); - Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); Message_CloseTextbox(gPlayState); + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + pauseCtx->itemDescriptionOn = false; } - } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { - ResetMessageContext(); - sIsConfirming = false; - Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + } else if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { + Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP); Message_CloseTextbox(gPlayState); - } else if (CHECK_BTN_ALL(input->press.button, BTN_START)) { - ClosePauseMenu(pauseCtx); + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + pauseCtx->itemDescriptionOn = false; } } @@ -97,7 +78,7 @@ void UpdateCursorForOwlWarpPoints(PauseContext* pauseCtx) { gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; Interface_SetHudVisibility(HUD_VISIBILITY_ALL); } - if (!sIsConfirming && interfaceCtx->aButtonHorseDoAction != DO_ACTION_WARP) { + if (interfaceCtx->aButtonHorseDoAction != DO_ACTION_WARP) { Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP); } } else { @@ -172,46 +153,16 @@ void HandlePauseOwlWarp(PauseContext* pauseCtx) { // Special condition for when only the 15th owl statue is activated if (gSaveContext.save.saveInfo.playerData.owlActivationFlags == (1 << 15)) { - for (int i = REGION_GREAT_BAY; i < REGION_MAX; i++) { + for (int i = REGION_GREAT_BAY; i < REGION_STONE_TOWER; i++) { if ((gSaveContext.save.saveInfo.regionsVisited >> i) & 1) { - switch (i) { - case REGION_GREAT_BAY: - pauseCtx->worldMapPoints[OWL_WARP_GREAT_BAY_COAST] = true; - break; - case REGION_ZORA_HALL: - pauseCtx->worldMapPoints[OWL_WARP_ZORA_CAPE] = true; - break; - case REGION_ROMANI_RANCH: - pauseCtx->worldMapPoints[OWL_WARP_SNOWHEAD] = true; - break; - case REGION_DEKU_PALACE: - pauseCtx->worldMapPoints[OWL_WARP_MOUNTAIN_VILLAGE] = true; - break; - case REGION_WOODFALL: - pauseCtx->worldMapPoints[OWL_WARP_CLOCK_TOWN] = true; - break; - case REGION_CLOCK_TOWN: - pauseCtx->worldMapPoints[OWL_WARP_MILK_ROAD] = true; - break; - case REGION_SNOWHEAD: - pauseCtx->worldMapPoints[OWL_WARP_WOODFALL] = true; - break; - case REGION_IKANA_GRAVEYARD: - pauseCtx->worldMapPoints[OWL_WARP_SOUTHERN_SWAMP] = true; - break; - case REGION_IKANA_CANYON: - pauseCtx->worldMapPoints[OWL_WARP_IKANA_CANYON] = true; - break; - case REGION_GORON_VILLAGE: - pauseCtx->worldMapPoints[OWL_WARP_STONE_TOWER] = true; - break; - } + pauseCtx->worldMapPoints[i] = true; } } } - // Ensure cursor starts at an activated point - if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + // Ensure cursor starts at an activated point and is not on the broken stone tower region point + if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] || + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) { for (int i = OWL_WARP_GREAT_BAY_COAST; i <= OWL_WARP_STONE_TOWER; i++) { if (pauseCtx->worldMapPoints[i]) { pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i; @@ -220,26 +171,23 @@ void HandlePauseOwlWarp(PauseContext* pauseCtx) { } } - Player* player = GET_PLAYER(gPlayState); Input* input = &gPlayState->state.input[0]; - if ((pauseCtx->state == PAUSE_STATE_MAIN && pauseCtx->pageIndex == PAUSE_MAP && pauseCtx->mapPageRoll == 0) || - sIsConfirming) { - if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { - ClosePauseMenu(pauseCtx); - } else if (CHECK_BTN_ALL(input->press.button, BTN_A) && !sIsConfirming) { - if (pauseCtx->cursorSpecialPos == 0 && pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { - Audio_PlaySfx(NA_SE_SY_DECIDE); - Message_StartTextbox(gPlayState, 0x1B93, NULL); - sIsConfirming = true; - } - } else if (sIsConfirming) { + if (pauseCtx->state == PAUSE_STATE_MAIN && pauseCtx->pageIndex == PAUSE_MAP && pauseCtx->mapPageRoll == 0) { + if (pauseCtx->itemDescriptionOn) { HandleConfirmingState(pauseCtx, input); } else { - KaleidoScope_UpdateOwlWarpNamePanel(gPlayState); - } + UpdateCursorForOwlWarpPoints(pauseCtx); - UpdateCursorForOwlWarpPoints(pauseCtx); + if (CHECK_BTN_ALL(input->press.button, BTN_A) && pauseCtx->cursorSpecialPos == 0 && + pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) { + pauseCtx->itemDescriptionOn = true; + Audio_PlaySfx(NA_SE_SY_DECIDE); + // Use Kaleido's open text variant that sets the dark black message box + func_801514B0(gPlayState, 0x1B93, 3); + gPlayState->msgCtx.choiceIndex = 0; + } + } } } From 8e0b482b239f6136e3dcccc3bb411a92ba38795c Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 5 Oct 2024 09:25:10 -0500 Subject: [PATCH 52/82] Fix crash when search contains only spaces (#795) --- mm/2s2h/BenGui/Menu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/2s2h/BenGui/Menu.cpp b/mm/2s2h/BenGui/Menu.cpp index c788bcc58..f83d59c80 100644 --- a/mm/2s2h/BenGui/Menu.cpp +++ b/mm/2s2h/BenGui/Menu.cpp @@ -287,6 +287,7 @@ void BenMenu::DrawElement() { ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0, 0, 0, 0 }); menuSearch.Draw("##search", 200.0f); menuSearchText = menuSearch.InputBuf; + menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), menuSearchText.end()); if (menuSearchText.length() < 1) { ImGui::SameLine(headerWidth - 200.0f + style.ItemSpacing.x); ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Search..."); @@ -403,8 +404,6 @@ void BenMenu::DrawElement() { } std::string widgetStr = std::string(info.widgetName) + std::string(info.widgetTooltip); std::transform(menuSearchText.begin(), menuSearchText.end(), menuSearchText.begin(), ::tolower); - menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), - menuSearchText.end()); std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower); widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end()); if (widgetStr.find(menuSearchText) != std::string::npos) { From da04b7f859a3b8bbed11e9aed367053d023eb236 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 5 Oct 2024 10:02:53 -0500 Subject: [PATCH 53/82] Change GI_VB_ to VB_ (#798) --- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 2 +- mm/2s2h/Enhancements/Camera/FreeLook.cpp | 2 +- .../Cheats/UnbreakableRazorSword.cpp | 2 +- .../Enhancements/Cheats/UnrestrictedItems.cpp | 2 +- .../Enhancements/Cutscenes/HideTitleCards.cpp | 2 +- .../MiscInteractions/SkipTatlInterrupts.cpp | 6 +- .../Cutscenes/SkipEntranceCutscenes.cpp | 2 +- .../Cutscenes/SkipIntroSequence.cpp | 2 +- .../StoryCutscenes/SkipClockTowerOpen.cpp | 4 +- .../Fixes/FierceDeityZTargetMovement.cpp | 2 +- .../GameInteractor/GameInteractor.h | 60 +++++++++---------- mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp | 2 +- mm/2s2h/Enhancements/Graphics/3DSClock.cpp | 2 +- .../Graphics/DisableBlackBars.cpp | 2 +- .../Enhancements/Graphics/TextBasedClock.cpp | 2 +- .../Enhancements/Masks/FastTransformation.cpp | 2 +- .../Masks/FierceDeityAnywhere.cpp | 2 +- .../Masks/NoBlastMaskCooldown.cpp | 2 +- .../Enhancements/Masks/PersistentMasks.cpp | 12 ++-- .../Minigames/AlwaysWinDoggyRace.cpp | 2 +- mm/2s2h/Enhancements/Player/ClimbSpeed.cpp | 2 +- .../Enhancements/Player/InstantPutaway.cpp | 2 +- .../Restorations/FlipHopVariable.cpp | 2 +- .../Restorations/PowerCrouchStab.cpp | 2 +- .../Enhancements/Restorations/SideRoll.cpp | 2 +- mm/2s2h/Enhancements/Restorations/TatlISG.cpp | 2 +- .../Saving/SavingEnhancements.cpp | 2 +- mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp | 2 +- mm/src/audio/code_8019AF00.c | 2 +- mm/src/code/z_camera.c | 2 +- mm/src/code/z_demo.c | 6 +- mm/src/code/z_message.c | 2 +- mm/src/code/z_parameter.c | 14 ++--- mm/src/code/z_shrink_window.c | 2 +- mm/src/code/z_sram_NES.c | 2 +- mm/src/code/z_view.c | 2 +- .../overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c | 2 +- .../overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c | 2 +- .../actors/ovl_En_Racedog/z_en_racedog.c | 2 +- .../overlays/actors/ovl_En_Slime/z_en_slime.c | 2 +- .../overlays/actors/ovl_En_Test4/z_en_test4.c | 2 +- .../actors/ovl_player_actor/z_player.c | 30 +++++----- .../ovl_kaleido_scope/z_kaleido_item.c | 2 +- .../ovl_kaleido_scope/z_kaleido_mask.c | 7 +-- 44 files changed, 105 insertions(+), 106 deletions(-) diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index eafcaf5ba..9ec56343a 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -231,7 +231,7 @@ void RegisterDebugCam() { } if (CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0)) { - freeCamVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, { + freeCamVBHookId = REGISTER_VB_SHOULD(VB_USE_CUSTOM_CAMERA, { Camera* camera = va_arg(args, Camera*); Camera_DebugCam(camera); *should = false; diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.cpp b/mm/2s2h/Enhancements/Camera/FreeLook.cpp index 9ddbb5968..ade91b987 100644 --- a/mm/2s2h/Enhancements/Camera/FreeLook.cpp +++ b/mm/2s2h/Enhancements/Camera/FreeLook.cpp @@ -172,7 +172,7 @@ void RegisterCameraFreeLook() { } if (CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0)) { - freeLookCameraVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, { + freeLookCameraVBHookId = REGISTER_VB_SHOULD(VB_USE_CUSTOM_CAMERA, { Camera* camera = va_arg(args, Camera*); switch (sCameraSettings[camera->setting].cameraModes[camera->mode].funcId) { case CAM_FUNC_NORMAL0: diff --git a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp b/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp index 28c13f147..8f6b31247 100644 --- a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp +++ b/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterUnbreakableRazorSword() { - REGISTER_VB_SHOULD(GI_VB_LOWER_RAZOR_SWORD_DURABILITY, { + REGISTER_VB_SHOULD(VB_LOWER_RAZOR_SWORD_DURABILITY, { if (CVarGetInteger("gCheats.UnbreakableRazorSword", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp b/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp index 8262bc258..4eb871901 100644 --- a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp +++ b/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterUnrestrictedItems() { - REGISTER_VB_SHOULD(GI_VB_ITEM_BE_RESTRICTED, { + REGISTER_VB_SHOULD(VB_ITEM_BE_RESTRICTED, { if (CVarGetInteger("gCheats.UnrestrictedItems", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp b/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp index 70f473c27..203b5d6a4 100644 --- a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterHideTitleCards() { - REGISTER_VB_SHOULD(GI_VB_SHOW_TITLE_CARD, { + REGISTER_VB_SHOULD(VB_SHOW_TITLE_CARD, { if (CVarGetInteger("gEnhancements.Cutscenes.HideTitleCards", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp index 8794d14e5..062fdf073 100644 --- a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp @@ -15,7 +15,7 @@ void Actor_Kill(Actor* actor); void RegisterSkipTatlInterrupts() { // First time entering Clock Town Interupt - REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { if (gSaveContext.save.entrance == ENTRANCE(SOUTH_CLOCK_TOWN, 0) && gSaveContext.save.cutsceneIndex == 0 && !CHECK_WEEKEVENTREG(WEEKEVENTREG_59_04) && CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0)) { @@ -24,7 +24,7 @@ void RegisterSkipTatlInterrupts() { }); // General interupt - REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG3, { + REGISTER_VB_SHOULD(VB_TATL_INTERUPT_MSG3, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { Actor* actor = va_arg(args, Actor*); *should = false; @@ -36,7 +36,7 @@ void RegisterSkipTatlInterrupts() { }); // General interupt 2 (the flags were directly copied from the original code) - REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG6, { + REGISTER_VB_SHOULD(VB_TATL_INTERUPT_MSG6, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { Actor* actor = va_arg(args, Actor*); *should = false; diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp index 83c924bee..94e6e1623 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterSkipEntranceCutscenes() { - REGISTER_VB_SHOULD(GI_VB_PLAY_ENTRANCE_CS, { + REGISTER_VB_SHOULD(VB_PLAY_ENTRANCE_CS, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipEntranceCutscenes", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp index b698d138a..fb396c05a 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp @@ -8,7 +8,7 @@ extern SaveContext gSaveContext; } void RegisterSkipIntroSequence() { - REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { // Intro cutscene if (!(gSaveContext.save.entrance == ENTRANCE(CUTSCENE, 0) && gSaveContext.save.cutsceneIndex == 0)) return; diff --git a/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp index 37876cb4d..f6259713a 100644 --- a/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp @@ -10,14 +10,14 @@ extern PlayState* gPlayState; void RegisterSkipClockTowerOpen() { // This will handle skipping if you are around the Clock Town area, but not directly in south clock town - REGISTER_VB_SHOULD(GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, { + REGISTER_VB_SHOULD(VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, { if (CVarGetInteger("gEnhancements.Cutscenes.SkipStoryCutscenes", 0)) { *should = false; } }); // This will handle skipping if you are directly in South Clock Town - REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { if ((gSaveContext.save.entrance == ENTRANCE(SOUTH_CLOCK_TOWN, 0) || gSaveContext.save.entrance == ENTRANCE(TERMINA_FIELD, 0)) && gSaveContext.save.cutsceneIndex == 0xFFF1 && diff --git a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp index 816b6e7cc..a84dcd55f 100644 --- a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp +++ b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp @@ -6,7 +6,7 @@ extern "C" { } void RegisterFierceDeityZTargetMovement() { - REGISTER_VB_SHOULD(GI_VB_ZTARGET_SPEED_CHECK, { + REGISTER_VB_SHOULD(VB_ZTARGET_SPEED_CHECK, { Player* player = GET_PLAYER(gPlayState); float* speedArg = va_arg(args, float*); diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index c17be750c..d73e763ae 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -32,36 +32,36 @@ typedef enum { typedef enum { // Vanilla condition: gSaveContext.showTitleCard - GI_VB_SHOW_TITLE_CARD, - GI_VB_PLAY_ENTRANCE_CS, - GI_VB_DISABLE_FD_MASK, - GI_VB_DOGGY_RACE_SET_MAX_SPEED, - GI_VB_LOWER_RAZOR_SWORD_DURABILITY, - GI_VB_SET_BLAST_MASK_COOLDOWN_TIMER, - GI_VB_PATCH_POWER_CROUCH_STAB, - GI_VB_PATCH_SIDEROLL, - GI_VB_TATL_CONVERSATION_AVAILABLE, - GI_VB_PREVENT_MASK_TRANSFORMATION_CS, - GI_VB_RESET_PUTAWAY_TIMER, - GI_VB_SET_CLIMB_SPEED, - GI_VB_PREVENT_CLOCK_DISPLAY, - GI_VB_SONG_AVAILABLE_TO_PLAY, - GI_VB_USE_CUSTOM_CAMERA, - GI_VB_DELETE_OWL_SAVE, - GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, - GI_VB_USE_ITEM_EQUIP_MASK, - GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, - GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, - GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, - GI_VB_PLAY_TRANSITION_CS, - GI_VB_TATL_INTERUPT_MSG3, - GI_VB_TATL_INTERUPT_MSG6, - GI_VB_ITEM_BE_RESTRICTED, - GI_VB_FLIP_HOP_VARIABLE, - GI_VB_DISABLE_LETTERBOX, - GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, - GI_VB_DRAW_SLIME_BODY_ITEM, - GI_VB_ZTARGET_SPEED_CHECK, + VB_SHOW_TITLE_CARD, + VB_PLAY_ENTRANCE_CS, + VB_DISABLE_FD_MASK, + VB_DOGGY_RACE_SET_MAX_SPEED, + VB_LOWER_RAZOR_SWORD_DURABILITY, + VB_SET_BLAST_MASK_COOLDOWN_TIMER, + VB_PATCH_POWER_CROUCH_STAB, + VB_PATCH_SIDEROLL, + VB_TATL_CONVERSATION_AVAILABLE, + VB_PREVENT_MASK_TRANSFORMATION_CS, + VB_RESET_PUTAWAY_TIMER, + VB_SET_CLIMB_SPEED, + VB_PREVENT_CLOCK_DISPLAY, + VB_SONG_AVAILABLE_TO_PLAY, + VB_USE_CUSTOM_CAMERA, + VB_DELETE_OWL_SAVE, + VB_CONSIDER_BUNNY_HOOD_EQUIPPED, + VB_USE_ITEM_EQUIP_MASK, + VB_KALEIDO_DISPLAY_ITEM_TEXT, + VB_USE_ITEM_CONSIDER_LINK_HUMAN, + VB_DRAW_ITEM_EQUIPPED_OUTLINE, + VB_PLAY_TRANSITION_CS, + VB_TATL_INTERUPT_MSG3, + VB_TATL_INTERUPT_MSG6, + VB_ITEM_BE_RESTRICTED, + VB_FLIP_HOP_VARIABLE, + VB_DISABLE_LETTERBOX, + VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, + VB_DRAW_SLIME_BODY_ITEM, + VB_ZTARGET_SPEED_CHECK, } GIVanillaBehavior; typedef enum { diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp index 0e52ca467..f72031e86 100644 --- a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp @@ -180,7 +180,7 @@ void Register3DItemDrops() { actor->shape.rot.y += 0x3C0; } }); - slimeVBHookID = REGISTER_VB_SHOULD(GI_VB_DRAW_SLIME_BODY_ITEM, { + slimeVBHookID = REGISTER_VB_SHOULD(VB_DRAW_SLIME_BODY_ITEM, { Actor* actor = va_arg(args, Actor*); DrawSlime3DItem(actor, should); }); diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp index a88551db7..04fa1efc7 100644 --- a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp @@ -50,7 +50,7 @@ s16 finalHoursClockSlots[8]; void Register3DSClock() { - REGISTER_VB_SHOULD(GI_VB_PREVENT_CLOCK_DISPLAY, { + REGISTER_VB_SHOULD(VB_PREVENT_CLOCK_DISPLAY, { if (CVarGetInteger("gEnhancements.Graphics.ClockType", CLOCK_TYPE_ORIGINAL) == CLOCK_TYPE_3DS) { *should = true; diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp index 21466d732..f98b8e68f 100644 --- a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp +++ b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp @@ -3,7 +3,7 @@ #include "DisableBlackBars.h" void RegisterDisableBlackBars() { - REGISTER_VB_SHOULD(GI_VB_DISABLE_LETTERBOX, { + REGISTER_VB_SHOULD(VB_DISABLE_LETTERBOX, { if (CVarGetInteger("gEnhancements.Graphics.DisableBlackBars", 0)) { *should = true; } diff --git a/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp b/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp index 70b70ccc2..4b8058cdc 100644 --- a/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp @@ -13,7 +13,7 @@ extern PlayState* gPlayState; } void RegisterTextBasedClock() { - REGISTER_VB_SHOULD(GI_VB_PREVENT_CLOCK_DISPLAY, { + REGISTER_VB_SHOULD(VB_PREVENT_CLOCK_DISPLAY, { if (CVarGetInteger("gEnhancements.Graphics.ClockType", CLOCK_TYPE_ORIGINAL) == CLOCK_TYPE_TEXT_BASED) { *should = true; diff --git a/mm/2s2h/Enhancements/Masks/FastTransformation.cpp b/mm/2s2h/Enhancements/Masks/FastTransformation.cpp index 734a30f29..ac9ccc633 100644 --- a/mm/2s2h/Enhancements/Masks/FastTransformation.cpp +++ b/mm/2s2h/Enhancements/Masks/FastTransformation.cpp @@ -16,7 +16,7 @@ void TransitionFade_SetColor(void* thisx, u32 color); } void RegisterFastTransformation() { - REGISTER_VB_SHOULD(GI_VB_PREVENT_MASK_TRANSFORMATION_CS, { + REGISTER_VB_SHOULD(VB_PREVENT_MASK_TRANSFORMATION_CS, { if (CVarGetInteger("gEnhancements.Masks.FastTransformation", 0)) { *should = true; Player* player = GET_PLAYER(gPlayState); diff --git a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp b/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp index cf14f605b..7eaff3775 100644 --- a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp +++ b/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterFierceDeityAnywhere() { - REGISTER_VB_SHOULD(GI_VB_DISABLE_FD_MASK, { + REGISTER_VB_SHOULD(VB_DISABLE_FD_MASK, { if (CVarGetInteger("gEnhancements.Masks.FierceDeitysAnywhere", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp b/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp index 4fb62749a..59a138b16 100644 --- a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp +++ b/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterNoBlastMaskCooldown() { - REGISTER_VB_SHOULD(GI_VB_SET_BLAST_MASK_COOLDOWN_TIMER, { + REGISTER_VB_SHOULD(VB_SET_BLAST_MASK_COOLDOWN_TIMER, { if (CVarGetInteger("gEnhancements.Masks.NoBlastMaskCooldown", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp index 281a6bec4..317f37789 100644 --- a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp +++ b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp @@ -137,14 +137,14 @@ void RegisterPersistentMasks() { [](s8 sceneId, s8 spawnNum) { UpdatePersistentMasksState(); }); // Speed the player up when the bunny hood state is active - REGISTER_VB_SHOULD(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, { + REGISTER_VB_SHOULD(VB_CONSIDER_BUNNY_HOOD_EQUIPPED, { if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { *should = true; } }); // Overrides allowing them to equip a mask while transformed - REGISTER_VB_SHOULD(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, { + REGISTER_VB_SHOULD(VB_USE_ITEM_CONSIDER_LINK_HUMAN, { PlayerItemAction* itemAction = va_arg(args, PlayerItemAction*); if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && *itemAction == PLAYER_IA_MASK_BUNNY) { @@ -153,7 +153,7 @@ void RegisterPersistentMasks() { }); // When they do equip the mask, prevent it and instead set our state - REGISTER_VB_SHOULD(GI_VB_USE_ITEM_EQUIP_MASK, { + REGISTER_VB_SHOULD(VB_USE_ITEM_EQUIP_MASK, { PlayerMask* maskId = va_arg(args, PlayerMask*); Player* player = GET_PLAYER(gPlayState); @@ -172,7 +172,7 @@ void RegisterPersistentMasks() { // Prevent the "equipped" white border from being drawn so ours shows instead (ours was drawn before it, so it's // underneath) - REGISTER_VB_SHOULD(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, { + REGISTER_VB_SHOULD(VB_DRAW_ITEM_EQUIPPED_OUTLINE, { ItemId* itemId = va_arg(args, ItemId*); if (*itemId == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.State", 0)) { *should = false; @@ -180,7 +180,7 @@ void RegisterPersistentMasks() { }); // Typically when you are in a transformation all masks are dimmed on the C-Buttons - REGISTER_VB_SHOULD(GI_VB_ITEM_BE_RESTRICTED, { + REGISTER_VB_SHOULD(VB_ITEM_BE_RESTRICTED, { ItemId* itemId = va_arg(args, ItemId*); if (*itemId == ITEM_MASK_BUNNY && CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0)) { *should = false; @@ -188,7 +188,7 @@ void RegisterPersistentMasks() { }); // Override "A" press behavior on kaleido scope to toggle the mask state - REGISTER_VB_SHOULD(GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, { + REGISTER_VB_SHOULD(VB_KALEIDO_DISPLAY_ITEM_TEXT, { ItemId* itemId = va_arg(args, ItemId*); if (CVarGetInteger("gEnhancements.Masks.PersistentBunnyHood.Enabled", 0) && *itemId == ITEM_MASK_BUNNY) { *should = false; diff --git a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp b/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp index 2121476aa..d20fbcda2 100644 --- a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp +++ b/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp @@ -9,7 +9,7 @@ extern u8 gItemSlots[77]; } void RegisterAlwaysWinDoggyRace() { - REGISTER_VB_SHOULD(GI_VB_DOGGY_RACE_SET_MAX_SPEED, { + REGISTER_VB_SHOULD(VB_DOGGY_RACE_SET_MAX_SPEED, { uint8_t selectedOption = CVarGetInteger("gEnhancements.Minigames.AlwaysWinDoggyRace", 0); if (selectedOption == ALWAYS_WIN_DOGGY_RACE_ALWAYS || (selectedOption == ALWAYS_WIN_DOGGY_RACE_MASKOFTRUTH && (INV_CONTENT(ITEM_MASK_TRUTH) == ITEM_MASK_TRUTH))) { diff --git a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp index c1c4102f9..66994cfdb 100644 --- a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp +++ b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterClimbSpeed() { - REGISTER_VB_SHOULD(GI_VB_SET_CLIMB_SPEED, { + REGISTER_VB_SHOULD(VB_SET_CLIMB_SPEED, { if (CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1) > 1) { f32* speed = va_arg(args, f32*); *speed *= CVarGetInteger("gEnhancements.Player.ClimbSpeed", 1); diff --git a/mm/2s2h/Enhancements/Player/InstantPutaway.cpp b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp index 24530aca7..8fb05a893 100644 --- a/mm/2s2h/Enhancements/Player/InstantPutaway.cpp +++ b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterInstantPutaway() { - REGISTER_VB_SHOULD(GI_VB_RESET_PUTAWAY_TIMER, { + REGISTER_VB_SHOULD(VB_RESET_PUTAWAY_TIMER, { if (CVarGetInteger("gEnhancements.Player.InstantPutaway", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp b/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp index d2a4d49d1..465002902 100644 --- a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp +++ b/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterVariableFlipHop() { - REGISTER_VB_SHOULD(GI_VB_FLIP_HOP_VARIABLE, { + REGISTER_VB_SHOULD(VB_FLIP_HOP_VARIABLE, { if (CVarGetInteger("gEnhancements.Restorations.ConstantFlipsHops", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp b/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp index 273008f9f..81d951737 100644 --- a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp +++ b/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterPowerCrouchStab() { - REGISTER_VB_SHOULD(GI_VB_PATCH_POWER_CROUCH_STAB, { + REGISTER_VB_SHOULD(VB_PATCH_POWER_CROUCH_STAB, { if (CVarGetInteger("gEnhancements.Restorations.PowerCrouchStab", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Restorations/SideRoll.cpp b/mm/2s2h/Enhancements/Restorations/SideRoll.cpp index 81362b0aa..6de0241d6 100644 --- a/mm/2s2h/Enhancements/Restorations/SideRoll.cpp +++ b/mm/2s2h/Enhancements/Restorations/SideRoll.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterSideRoll() { - REGISTER_VB_SHOULD(GI_VB_PATCH_SIDEROLL, { + REGISTER_VB_SHOULD(VB_PATCH_SIDEROLL, { if (CVarGetInteger("gEnhancements.Restorations.SideRoll", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Restorations/TatlISG.cpp b/mm/2s2h/Enhancements/Restorations/TatlISG.cpp index 6c32120c2..07e091df2 100644 --- a/mm/2s2h/Enhancements/Restorations/TatlISG.cpp +++ b/mm/2s2h/Enhancements/Restorations/TatlISG.cpp @@ -2,7 +2,7 @@ #include "Enhancements/GameInteractor/GameInteractor.h" void RegisterTatlISG() { - REGISTER_VB_SHOULD(GI_VB_TATL_CONVERSATION_AVAILABLE, { + REGISTER_VB_SHOULD(VB_TATL_CONVERSATION_AVAILABLE, { if (CVarGetInteger("gEnhancements.Restorations.TatlISG", 0)) { *should = false; } diff --git a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp index 6591d38b0..5bc1328a9 100644 --- a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp +++ b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp @@ -147,7 +147,7 @@ void HandleAutoSave() { } void RegisterSavingEnhancements() { - REGISTER_VB_SHOULD(GI_VB_DELETE_OWL_SAVE, { + REGISTER_VB_SHOULD(VB_DELETE_OWL_SAVE, { if (CVarGetInteger("gEnhancements.Saving.PersistentOwlSaves", 0) || gSaveContext.save.shipSaveInfo.pauseSaveEntrance != -1) { *should = false; diff --git a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp index 92a60751b..6e50bdfd8 100644 --- a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp +++ b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp @@ -6,7 +6,7 @@ extern "C" { } void RegisterEnableSunsSong() { - REGISTER_VB_SHOULD(GI_VB_SONG_AVAILABLE_TO_PLAY, { + REGISTER_VB_SHOULD(VB_SONG_AVAILABLE_TO_PLAY, { uint8_t* songIndex = va_arg(args, uint8_t*); // If the enhancement is on, and the currently played song is Sun's Song, set it to be available to be played. if (CVarGetInteger("gEnhancements.Songs.EnableSunsSong", 0) && *songIndex == OCARINA_SONG_SUNS) { diff --git a/mm/src/audio/code_8019AF00.c b/mm/src/audio/code_8019AF00.c index 7f9e75cde..3600f8c81 100644 --- a/mm/src/audio/code_8019AF00.c +++ b/mm/src/audio/code_8019AF00.c @@ -2555,7 +2555,7 @@ void AudioOcarina_CheckSongsWithoutMusicStaff(void) { for (songIndex = sFirstOcarinaSongIndex; songIndex < sLastOcarinaSongIndex; songIndex++) { // Checks to see if the song is available to be played bool vanillaCondition = (u32)sOcarinaAvailableSongFlags & (1 << songIndex); - if (GameInteractor_Should(GI_VB_SONG_AVAILABLE_TO_PLAY, vanillaCondition, &songIndex)) { + if (GameInteractor_Should(VB_SONG_AVAILABLE_TO_PLAY, vanillaCondition, &songIndex)) { // Loops through all possible starting indices? // Loops through the notes of the song? for (j = 0, k = 0; (j < gOcarinaSongButtons[songIndex].numButtons) && (k == 0) && diff --git a/mm/src/code/z_camera.c b/mm/src/code/z_camera.c index f0b9cdb47..a42dcde2a 100644 --- a/mm/src/code/z_camera.c +++ b/mm/src/code/z_camera.c @@ -7554,7 +7554,7 @@ Vec3s Camera_Update(Camera* camera) { } // Call the camera update function - if (GameInteractor_Should(GI_VB_USE_CUSTOM_CAMERA, true, camera)) { + if (GameInteractor_Should(VB_USE_CUSTOM_CAMERA, true, camera)) { sCameraUpdateHandlers[sCameraSettings[camera->setting].cameraModes[camera->mode].funcId](camera); } diff --git a/mm/src/code/z_demo.c b/mm/src/code/z_demo.c index 5fd5c8ed1..e9a24432a 100644 --- a/mm/src/code/z_demo.c +++ b/mm/src/code/z_demo.c @@ -1545,7 +1545,7 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { } else if (!CHECK_CS_SPAWN_FLAG_WEEKEVENTREG(play->csCtx.scriptList[scriptIndex].spawnFlags)) { // Entrance cutscenes that only run once SET_CS_SPAWN_FLAG_WEEKEVENTREG(play->csCtx.scriptList[scriptIndex].spawnFlags); - if (GameInteractor_Should(GI_VB_PLAY_ENTRANCE_CS, true)) { + if (GameInteractor_Should(VB_PLAY_ENTRANCE_CS, true)) { CutsceneManager_Start(csId, NULL); } // The title card will be used by the cs misc command if necessary. @@ -1561,7 +1561,7 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { if ((gSaveContext.respawnFlag == 0) || (gSaveContext.respawnFlag == -2)) { scene = play->loadedScene; - if ((scene->titleTextId != 0) && GameInteractor_Should(GI_VB_SHOW_TITLE_CARD, gSaveContext.showTitleCard)) { + if ((scene->titleTextId != 0) && GameInteractor_Should(VB_SHOW_TITLE_CARD, gSaveContext.showTitleCard)) { if ((Entrance_GetTransitionFlags(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer)) & 0x4000) != 0) { @@ -1580,7 +1580,7 @@ void func_800EDDB0(PlayState* play) { LUSLOG_INFO("Cutscene_HandleConditionalTriggers: entrance: %d, cutsceneIndex: 0x%X", gSaveContext.save.entrance, gSaveContext.save.cutsceneIndex); - if (!GameInteractor_Should(GI_VB_PLAY_TRANSITION_CS, true)) { + if (!GameInteractor_Should(VB_PLAY_TRANSITION_CS, true)) { return; } } diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c index c8183d70d..48d29c4d6 100644 --- a/mm/src/code/z_message.c +++ b/mm/src/code/z_message.c @@ -4589,7 +4589,7 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { AudioOcarina_SetOcarinaDisableTimer(0, 20); Message_CloseTextbox(play); play->msgCtx.ocarinaMode = OCARINA_MODE_PLAYED_FULL_EVAN_SONG; - } else if (GameInteractor_Should(GI_VB_SONG_AVAILABLE_TO_PLAY, vanillaOwnedSongCheck, + } else if (GameInteractor_Should(VB_SONG_AVAILABLE_TO_PLAY, vanillaOwnedSongCheck, &msgCtx->ocarinaStaff->state)) { sLastPlayedSong = msgCtx->ocarinaStaff->state; msgCtx->lastPlayedSong = msgCtx->ocarinaStaff->state; diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index da73d18fb..2e3734a7e 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -2782,8 +2782,8 @@ void Interface_UpdateButtonsPart2(PlayState* play) { for (i = EQUIP_SLOT_C_LEFT; i <= EQUIP_SLOT_C_RIGHT; i++) { // Individual C button ItemId itemId = GET_CUR_FORM_BTN_ITEM(i); - if (GameInteractor_Should(GI_VB_ITEM_BE_RESTRICTED, - !gPlayerFormItemRestrictions[GET_PLAYER_FORM][itemId], &itemId)) { + if (GameInteractor_Should(VB_ITEM_BE_RESTRICTED, !gPlayerFormItemRestrictions[GET_PLAYER_FORM][itemId], + &itemId)) { // Item not usable in current playerForm if (gSaveContext.buttonStatus[i] != BTN_DISABLED) { gSaveContext.buttonStatus[i] = BTN_DISABLED; @@ -2823,7 +2823,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && (play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) && (play->sceneId != SCENE_LAST_BS); - if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { + if (GameInteractor_Should(VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { if (gSaveContext.buttonStatus[i] != BTN_DISABLED) { gSaveContext.buttonStatus[i] = BTN_DISABLED; restoreHudVisibility = true; @@ -2929,8 +2929,8 @@ void Interface_UpdateButtonsPart2(PlayState* play) { for (s16 j = EQUIP_SLOT_D_RIGHT; j <= EQUIP_SLOT_D_UP; j++) { // Individual D button ItemId itemId = DPAD_GET_CUR_FORM_BTN_ITEM(j); - if (GameInteractor_Should(GI_VB_ITEM_BE_RESTRICTED, - !gPlayerFormItemRestrictions[GET_PLAYER_FORM][itemId], &itemId)) { + if (GameInteractor_Should(VB_ITEM_BE_RESTRICTED, !gPlayerFormItemRestrictions[GET_PLAYER_FORM][itemId], + &itemId)) { // Item not usable in current playerForm if (gSaveContext.shipSaveContext.dpad.status[j] != BTN_DISABLED) { gSaveContext.shipSaveContext.dpad.status[j] = BTN_DISABLED; @@ -2970,7 +2970,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && (play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) && (play->sceneId != SCENE_LAST_BS); - if (GameInteractor_Should(GI_VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { + if (GameInteractor_Should(VB_DISABLE_FD_MASK, vanillaSceneConditionResult)) { if (gSaveContext.shipSaveContext.dpad.status[j] != BTN_DISABLED) { gSaveContext.shipSaveContext.dpad.status[j] = BTN_DISABLED; restoreHudVisibility = true; @@ -6151,7 +6151,7 @@ void Interface_DrawClock(PlayState* play) { s16 finalHoursClockSlots[8]; s16 index; - if (GameInteractor_Should(GI_VB_PREVENT_CLOCK_DISPLAY, false)) { + if (GameInteractor_Should(VB_PREVENT_CLOCK_DISPLAY, false)) { return; } diff --git a/mm/src/code/z_shrink_window.c b/mm/src/code/z_shrink_window.c index df48b893d..2e36948db 100644 --- a/mm/src/code/z_shrink_window.c +++ b/mm/src/code/z_shrink_window.c @@ -80,7 +80,7 @@ void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { s8 letterboxSize = sShrinkWindowPtr->letterboxSize; s8 pillarboxSize = sShrinkWindowPtr->pillarboxSize; - if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false)) { + if (GameInteractor_Should(VB_DISABLE_LETTERBOX, false)) { return; } diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index 09c2a19c7..ed6212a8f 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -1373,7 +1373,7 @@ void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { fileNum = gSaveContext.fileNum; // Remove Owl saves on save continue - if (GameInteractor_Should(GI_VB_DELETE_OWL_SAVE, true)) { + if (GameInteractor_Should(VB_DELETE_OWL_SAVE, true)) { func_80147314(sramCtx, fileNum); } } diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 83801471b..1b1e35214 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -160,7 +160,7 @@ void View_ApplyLetterbox(View* view) { s32 lrx; s32 lry; - if (GameInteractor_Should(GI_VB_DISABLE_LETTERBOX, false)) { + if (GameInteractor_Should(VB_DISABLE_LETTERBOX, false)) { return; } diff --git a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c index 479ac0b11..8a25910eb 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c @@ -106,7 +106,7 @@ void func_80A2CF7C(ElfMsg3* this, PlayState* play) { EnElf* tatl = (EnElf*)player->tatlActor; if (GameInteractor_Should( - GI_VB_TATL_INTERUPT_MSG3, + VB_TATL_INTERUPT_MSG3, (((((player->tatlActor != NULL) && (fabsf(player->actor.world.pos.x - this->actor.world.pos.x) < (100.0f * this->actor.scale.x))) && (this->actor.world.pos.y <= player->actor.world.pos.y)) && diff --git a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c index 20af2ff5f..c77db2dbf 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c @@ -238,7 +238,7 @@ void ElfMsg6_Destroy(Actor* thisx, PlayState* play) { s32 func_80BA1C00(ElfMsg6* this) { return GameInteractor_Should( - GI_VB_TATL_INTERUPT_MSG6, + VB_TATL_INTERUPT_MSG6, ((this->actor.xzDistToPlayer < (100.0f * this->actor.scale.x)) && ((this->actor.playerHeightRel >= 0.0f) && (this->actor.playerHeightRel < (100.0f * this->actor.scale.y)))), this); diff --git a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c index 30649608d..4a3d1c5d9 100644 --- a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c +++ b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c @@ -519,7 +519,7 @@ void EnRacedog_UpdateSpeed(EnRacedog* this) { // Cap the speed of the dog, or always max it out with the 'Always Win Doggy Race' enhancement. bool vanillaCondition = this->actor.speed > 7.5f; - if (GameInteractor_Should(GI_VB_DOGGY_RACE_SET_MAX_SPEED, vanillaCondition)) { + if (GameInteractor_Should(VB_DOGGY_RACE_SET_MAX_SPEED, vanillaCondition)) { this->actor.speed = 7.5f; } } else { diff --git a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c index fcc729cdd..76ac1efd6 100644 --- a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c +++ b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c @@ -1242,7 +1242,7 @@ void EnSlime_Draw(Actor* thisx, PlayState* play) { Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + (2000.0f * this->actor.scale.y), this->actor.world.pos.z, MTXMODE_NEW); - if (GameInteractor_Should(GI_VB_DRAW_SLIME_BODY_ITEM, true, this)) { + if (GameInteractor_Should(VB_DRAW_SLIME_BODY_ITEM, true, this)) { Matrix_Scale(0.03f, 0.03f, 0.03f, MTXMODE_APPLY); gSPSegment(POLY_OPA_DISP++, 8, (uintptr_t)this->itemDropTex); diff --git a/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c b/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c index fb9a88f3b..a8c11c517 100644 --- a/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c +++ b/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c @@ -444,7 +444,7 @@ void func_80A42AB8(EnTest4* this, PlayState* play) { if (CURRENT_DAY == 3) { if ((this->nextBellTime == CLOCK_TIME(0, 0)) && - (GameInteractor_Should(GI_VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, + (GameInteractor_Should(VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, gSaveContext.save.saveInfo.inventory.items[SLOT_OCARINA] == ITEM_NONE, this) || (play->sceneId == SCENE_CLOCKTOWER))) { diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 11863f312..3ce8993dc 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -3814,7 +3814,7 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { if (bomb != NULL) { bomb->timer = 0; - if (GameInteractor_Should(GI_VB_SET_BLAST_MASK_COOLDOWN_TIMER, true)) { + if (GameInteractor_Should(VB_SET_BLAST_MASK_COOLDOWN_TIMER, true)) { this->blastMaskTimer = 310; } } @@ -4471,7 +4471,7 @@ void Player_UseItem(PlayState* play, Player* this, ItemId item) { (itemAction == PLAYER_IA_MASK_ZORA) || ((this->currentBoots >= PLAYER_BOOTS_ZORA_UNDERWATER) && (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)))) { s32 var_v1 = ((itemAction >= PLAYER_IA_MASK_MIN) && (itemAction <= PLAYER_IA_MASK_MAX) && - (!GameInteractor_Should(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, + (!GameInteractor_Should(VB_USE_ITEM_CONSIDER_LINK_HUMAN, this->transformation == PLAYER_FORM_HUMAN, &itemAction) || (itemAction >= PLAYER_IA_MASK_GIANT))); CollisionPoly* sp5C; @@ -4533,12 +4533,12 @@ void Player_UseItem(PlayState* play, Player* this, ItemId item) { } else { Audio_PlaySfx(NA_SE_SY_ERROR); } - } else if (GameInteractor_Should(GI_VB_USE_ITEM_CONSIDER_LINK_HUMAN, this->transformation == PLAYER_FORM_HUMAN, + } else if (GameInteractor_Should(VB_USE_ITEM_CONSIDER_LINK_HUMAN, this->transformation == PLAYER_FORM_HUMAN, &itemAction) && (itemAction >= PLAYER_IA_MASK_MIN) && (itemAction < PLAYER_IA_MASK_GIANT)) { PlayerMask maskId = GET_MASK_FROM_IA(itemAction); - if (GameInteractor_Should(GI_VB_USE_ITEM_EQUIP_MASK, true, &maskId)) { + if (GameInteractor_Should(VB_USE_ITEM_EQUIP_MASK, true, &maskId)) { // Handle wearable masks this->prevMask = this->currentMask; if (maskId == this->currentMask) { @@ -6720,7 +6720,7 @@ void func_80836AD8(PlayState* play, Player* this) { } void func_80836B3C(PlayState* play, Player* this, f32 arg2) { - if (GameInteractor_Should(GI_VB_PATCH_SIDEROLL, true)) { + if (GameInteractor_Should(VB_PATCH_SIDEROLL, true)) { this->currentYaw = this->actor.shape.rot.y; this->actor.world.rot.y = this->actor.shape.rot.y; } @@ -7814,7 +7814,7 @@ s32 Player_ActionChange_4(Player* this, PlayState* play) { // !CutsceneManager_IsNext(CS_ID_GLOBAL_TALK), which is what prevented Tatl ISG from // working bool vanillaCondition = !CutsceneManager_IsNext(CS_ID_GLOBAL_TALK); - if (GameInteractor_Should(GI_VB_TATL_CONVERSATION_AVAILABLE, vanillaCondition) || + if (GameInteractor_Should(VB_TATL_CONVERSATION_AVAILABLE, vanillaCondition) || !CHECK_BTN_ALL(sPlayerControlInput->press.button, BTN_CUP)) { return false; } @@ -9597,7 +9597,7 @@ s32 func_8083E404(Player* this, f32 arg1, s16 arg2) { } // Using Should hook, but ignoring return value, to be able to modify the speed argument - GameInteractor_Should(GI_VB_ZTARGET_SPEED_CHECK, false, &arg1); + GameInteractor_Should(VB_ZTARGET_SPEED_CHECK, false, &arg1); temp_fv1 = fabsf(sp1C) / 0x8000; if (((SQ(temp_fv1) * 50.0f) + 6.0f) < arg1) { @@ -10099,7 +10099,7 @@ s32 func_8083FD80(Player* this, PlayState* play) { if (!Player_IsGoronOrDeku(this) && (Player_GetMeleeWeaponHeld(this) != PLAYER_MELEEWEAPON_NONE) && (this->transformation != PLAYER_FORM_ZORA) && sPlayerUseHeldItem) { //! Calling this function sets the meleeWeaponQuads' damage properties correctly, patching "Power Crouch Stab". - if (GameInteractor_Should(GI_VB_PATCH_POWER_CROUCH_STAB, true)) { + if (GameInteractor_Should(VB_PATCH_POWER_CROUCH_STAB, true)) { func_8083375C(this, PLAYER_MWA_STAB_1H); } Player_AnimationPlayOnce(play, this, &gPlayerAnim_link_normal_defense_kiru); @@ -10146,7 +10146,7 @@ s32 func_8083FF30(PlayState* play, Player* this) { s32 func_8083FFEC(PlayState* play, Player* this) { if (this->heldItemAction == PLAYER_IA_SWORD_RAZOR) { if (gSaveContext.save.saveInfo.playerData.swordHealth > 0) { - if (GameInteractor_Should(GI_VB_LOWER_RAZOR_SWORD_DURABILITY, true)) { + if (GameInteractor_Should(VB_LOWER_RAZOR_SWORD_DURABILITY, true)) { gSaveContext.save.saveInfo.playerData.swordHealth--; } if (gSaveContext.save.saveInfo.playerData.swordHealth <= 0) { @@ -11256,7 +11256,7 @@ void Player_SetDoAction(PlayState* play, Player* this) { } if (doActionA != DO_ACTION_PUTAWAY) { - if (GameInteractor_Should(GI_VB_RESET_PUTAWAY_TIMER, true)) { + if (GameInteractor_Should(VB_RESET_PUTAWAY_TIMER, true)) { this->putAwayCountdown = 20; } } else if (this->putAwayCountdown != 0) { @@ -12202,7 +12202,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { this->actor.shape.face = ((play->gameplayFrames & 0x20) ? 0 : 3) + this->blinkInfo.eyeTexIndex; - if (GameInteractor_Should(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { + if (GameInteractor_Should(VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { Player_UpdateBunnyEars(this); } @@ -14469,7 +14469,7 @@ void Player_Action_13(Player* this, PlayState* play) { Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play); - if (GameInteractor_Should(GI_VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { + if (GameInteractor_Should(VB_CONSIDER_BUNNY_HOOD_EQUIPPED, this->currentMask == PLAYER_MASK_BUNNY, this)) { speedTarget *= 1.5f; } @@ -14898,7 +14898,7 @@ void Player_Action_25(Player* this, PlayState* play) { Math_StepToF(&this->unk_B10[1], 0.0f, this->unk_B10[0]); } } else { - if (GameInteractor_Should(GI_VB_FLIP_HOP_VARIABLE, true)) { + if (GameInteractor_Should(VB_FLIP_HOP_VARIABLE, true)) { func_8083CBC4(this, speedTarget, yawTarget, 1.0f, 0.05f, 0.1f, 0xC8); } } @@ -16036,7 +16036,7 @@ void Player_Action_50(Player* this, PlayState* play) { var_fv1 = -1.0f; } - if (GameInteractor_Should(GI_VB_SET_CLIMB_SPEED, true, &var_fv1)) { + if (GameInteractor_Should(VB_SET_CLIMB_SPEED, true, &var_fv1)) { this->skelAnime.playSpeed = var_fv1 * var_fv0; } @@ -18295,7 +18295,7 @@ void Player_Action_86(Player* this, PlayState* play) { struct_8085D910* sp4C = D_8085D910; s32 sp48 = false; - if (GameInteractor_Should(GI_VB_PREVENT_MASK_TRANSFORMATION_CS, false)) + if (GameInteractor_Should(VB_PREVENT_MASK_TRANSFORMATION_CS, false)) return; func_808323C0(this, play->playerCsIds[PLAYER_CS_ID_MASK_TRANSFORMATION]); diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c index 1bb67221f..5e91c8e7e 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c @@ -327,7 +327,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { // but this matches the behavior of the original code u16 itemId = gSaveContext.save.saveInfo.inventory.items[i]; u8 itemRestricted = GameInteractor_Should( - GI_VB_ITEM_BE_RESTRICTED, !gPlayerFormItemRestrictions[GET_PLAYER_FORM][(s32)itemId], &itemId); + VB_ITEM_BE_RESTRICTED, !gPlayerFormItemRestrictions[GET_PLAYER_FORM][(s32)itemId], &itemId); if (itemRestricted) { gDPSetGrayscaleColor(POLY_OPA_DISP++, 109, 109, 109, 255); gSPGrayscale(POLY_OPA_DISP++, true); diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c index 7d6da43c4..140ba179a 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c @@ -211,7 +211,7 @@ void KaleidoScope_DrawMaskSelect(PlayState* play) { if (GET_CUR_FORM_BTN_ITEM(i + 1) != ITEM_NONE) { if (GET_CUR_FORM_BTN_SLOT(i + 1) >= ITEM_NUM_SLOTS) { ItemId item = GET_CUR_FORM_BTN_ITEM(i + 1); - if (GameInteractor_Should(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { + if (GameInteractor_Should(VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); } @@ -224,7 +224,7 @@ void KaleidoScope_DrawMaskSelect(PlayState* play) { if (DPAD_GET_CUR_FORM_BTN_ITEM(i) != ITEM_NONE) { if (DPAD_GET_CUR_FORM_BTN_SLOT(i) >= ITEM_NUM_SLOTS) { ItemId item = DPAD_GET_CUR_FORM_BTN_ITEM(i); - if (GameInteractor_Should(GI_VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { + if (GameInteractor_Should(VB_DRAW_ITEM_EQUIPPED_OUTLINE, true, &item)) { gSPVertex(POLY_OPA_DISP++, &pauseCtx->maskVtx[j], 4, 0); POLY_OPA_DISP = Gfx_DrawTexQuadIA8(POLY_OPA_DISP, gEquippedItemOutlineTex, 32, 32, 0); } @@ -675,8 +675,7 @@ void KaleidoScope_UpdateMaskCursor(PlayState* play) { } else if ((pauseCtx->debugEditor == DEBUG_EDITOR_NONE) && (pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) && CHECK_BTN_ALL(input->press.button, BTN_A) && (msgCtx->msgLength == 0)) { - if (GameInteractor_Should(GI_VB_KALEIDO_DISPLAY_ITEM_TEXT, true, - &pauseCtx->cursorItem[PAUSE_MASK])) { + if (GameInteractor_Should(VB_KALEIDO_DISPLAY_ITEM_TEXT, true, &pauseCtx->cursorItem[PAUSE_MASK])) { // Give description on item through a message box pauseCtx->itemDescriptionOn = true; if (pauseCtx->cursorYIndex[PAUSE_MASK] < 2) { From d9d6dbdf51fab429bcb7d16cad1233149eb81d56 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 5 Oct 2024 10:06:49 -0500 Subject: [PATCH 54/82] Remove unnecessary headers in favor of directory headers (#800) --- mm/2s2h/BenGui/BenMenuBar.cpp | 6 --- mm/2s2h/BenGui/Menu.cpp | 2 - mm/2s2h/BenGui/SearchableMenuItems.h | 1 - mm/2s2h/Enhancements/Camera/Camera.h | 8 ++++ .../Camera/CameraInterpolationFixes.cpp | 2 +- .../Camera/CameraInterpolationFixes.h | 6 --- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 1 - mm/2s2h/Enhancements/Camera/DebugCam.h | 6 --- mm/2s2h/Enhancements/Camera/FreeLook.cpp | 1 - mm/2s2h/Enhancements/Camera/FreeLook.h | 6 --- mm/2s2h/Enhancements/Cheats/Cheats.h | 5 +++ mm/2s2h/Enhancements/Cheats/Infinite.cpp | 1 - mm/2s2h/Enhancements/Cheats/Infinite.h | 6 --- mm/2s2h/Enhancements/Cheats/MoonJump.cpp | 1 - mm/2s2h/Enhancements/Cheats/MoonJump.h | 6 --- mm/2s2h/Enhancements/Cheats/TimeStop.h | 6 --- .../Cheats/UnbreakableRazorSword.h | 6 --- .../Enhancements/Cheats/UnrestrictedItems.h | 6 --- mm/2s2h/Enhancements/Cycle/Cycle.h | 6 +++ mm/2s2h/Enhancements/Cycle/EndOfCycle.h | 6 --- .../Dialogue/FastBankSelection.cpp | 3 ++ mm/2s2h/Enhancements/Enhancements.h | 44 +++++-------------- mm/2s2h/Enhancements/Equipment/Equipment.h | 7 +++ .../Enhancements/Equipment/InstantRecall.cpp | 3 +- .../Enhancements/Equipment/InstantRecall.h | 6 --- .../Equipment/SkipMagicArrowEquip.cpp | 4 +- .../Equipment/SkipMagicArrowEquip.h | 6 --- mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp | 1 - mm/2s2h/Enhancements/Graphics/3DItemDrops.h | 6 --- mm/2s2h/Enhancements/Graphics/3DSClock.h | 6 --- .../Graphics/DisableBlackBars.cpp | 1 - .../Enhancements/Graphics/DisableBlackBars.h | 6 --- mm/2s2h/Enhancements/Graphics/Graphics.h | 23 ++++++++++ mm/2s2h/Enhancements/Graphics/MotionBlur.cpp | 1 - mm/2s2h/Enhancements/Graphics/MotionBlur.h | 18 -------- mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp | 1 - mm/2s2h/Enhancements/Graphics/PlayAsKafei.h | 8 ---- .../Enhancements/Graphics/TextBasedClock.h | 6 --- mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp | 2 +- mm/2s2h/Enhancements/Masks/BlastMaskKeg.h | 6 --- .../Enhancements/Masks/FastTransformation.h | 6 --- .../Enhancements/Masks/FierceDeityAnywhere.h | 6 --- mm/2s2h/Enhancements/Masks/Masks.h | 11 +++++ .../Enhancements/Masks/NoBlastMaskCooldown.h | 6 --- mm/2s2h/Enhancements/Masks/PersistentMasks.h | 7 --- .../Minigames/AlwaysWinDoggyRace.h | 6 --- mm/2s2h/Enhancements/Minigames/Minigames.h | 6 +++ mm/2s2h/Enhancements/Modes/Modes.h | 6 +++ .../Modes/TimeMovesWhenYouMove.cpp | 1 - .../Enhancements/Modes/TimeMovesWhenYouMove.h | 6 --- .../Enhancements/Player/FastFlowerLaunch.cpp | 1 - .../Restorations/FlipHopVariable.h | 6 --- .../Restorations/PowerCrouchStab.h | 6 --- .../Enhancements/Restorations/Restorations.h | 4 ++ mm/2s2h/Enhancements/Restorations/SideRoll.h | 6 --- mm/2s2h/Enhancements/Restorations/TatlISG.h | 6 --- mm/2s2h/Enhancements/Songs/EnableSunsSong.h | 6 --- mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp | 1 - mm/2s2h/Enhancements/Songs/PauseOwlWarp.h | 15 ------- mm/2s2h/Enhancements/Songs/Songs.h | 18 ++++++++ mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp | 1 - mm/2s2h/Enhancements/Songs/ZoraEggCount.h | 6 --- mm/src/code/z_camera.c | 2 +- mm/src/code/z_play.c | 2 +- .../ovl_kaleido_scope/z_kaleido_map.c | 2 +- .../ovl_kaleido_scope/z_kaleido_scope_NES.c | 2 +- 66 files changed, 117 insertions(+), 274 deletions(-) create mode 100644 mm/2s2h/Enhancements/Camera/Camera.h delete mode 100644 mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.h delete mode 100644 mm/2s2h/Enhancements/Camera/DebugCam.h delete mode 100644 mm/2s2h/Enhancements/Camera/FreeLook.h delete mode 100644 mm/2s2h/Enhancements/Cheats/Infinite.h delete mode 100644 mm/2s2h/Enhancements/Cheats/MoonJump.h delete mode 100644 mm/2s2h/Enhancements/Cheats/TimeStop.h delete mode 100644 mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.h delete mode 100644 mm/2s2h/Enhancements/Cheats/UnrestrictedItems.h create mode 100644 mm/2s2h/Enhancements/Cycle/Cycle.h delete mode 100644 mm/2s2h/Enhancements/Cycle/EndOfCycle.h create mode 100644 mm/2s2h/Enhancements/Equipment/Equipment.h delete mode 100644 mm/2s2h/Enhancements/Equipment/InstantRecall.h delete mode 100644 mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h delete mode 100644 mm/2s2h/Enhancements/Graphics/3DItemDrops.h delete mode 100644 mm/2s2h/Enhancements/Graphics/3DSClock.h delete mode 100644 mm/2s2h/Enhancements/Graphics/DisableBlackBars.h create mode 100644 mm/2s2h/Enhancements/Graphics/Graphics.h delete mode 100644 mm/2s2h/Enhancements/Graphics/MotionBlur.h delete mode 100644 mm/2s2h/Enhancements/Graphics/PlayAsKafei.h delete mode 100644 mm/2s2h/Enhancements/Graphics/TextBasedClock.h delete mode 100644 mm/2s2h/Enhancements/Masks/BlastMaskKeg.h delete mode 100644 mm/2s2h/Enhancements/Masks/FastTransformation.h delete mode 100644 mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.h create mode 100644 mm/2s2h/Enhancements/Masks/Masks.h delete mode 100644 mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.h delete mode 100644 mm/2s2h/Enhancements/Masks/PersistentMasks.h delete mode 100644 mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.h create mode 100644 mm/2s2h/Enhancements/Minigames/Minigames.h create mode 100644 mm/2s2h/Enhancements/Modes/Modes.h delete mode 100644 mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h delete mode 100644 mm/2s2h/Enhancements/Restorations/FlipHopVariable.h delete mode 100644 mm/2s2h/Enhancements/Restorations/PowerCrouchStab.h delete mode 100644 mm/2s2h/Enhancements/Restorations/SideRoll.h delete mode 100644 mm/2s2h/Enhancements/Restorations/TatlISG.h delete mode 100644 mm/2s2h/Enhancements/Songs/EnableSunsSong.h delete mode 100644 mm/2s2h/Enhancements/Songs/PauseOwlWarp.h create mode 100644 mm/2s2h/Enhancements/Songs/Songs.h delete mode 100644 mm/2s2h/Enhancements/Songs/ZoraEggCount.h diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 962132b5f..e8f7d7352 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -8,13 +8,7 @@ #include #include #include "2s2h/Enhancements/Enhancements.h" -#include "2s2h/Enhancements/Graphics/3DItemDrops.h" -#include "2s2h/Enhancements/Graphics/MotionBlur.h" -#include "2s2h/Enhancements/Graphics/PlayAsKafei.h" -#include "2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h" #include "2s2h/DeveloperTools/DeveloperTools.h" -#include "2s2h/Enhancements/Cheats/Cheats.h" -#include "2s2h/Enhancements/Player/Player.h" #include "HudEditor.h" extern "C" { diff --git a/mm/2s2h/BenGui/Menu.cpp b/mm/2s2h/BenGui/Menu.cpp index f83d59c80..9727b58ed 100644 --- a/mm/2s2h/BenGui/Menu.cpp +++ b/mm/2s2h/BenGui/Menu.cpp @@ -4,8 +4,6 @@ #include "UIWidgets.hpp" #include "graphic/Fast3D/gfx_rendering_api.h" #include "2s2h/Enhancements/Enhancements.h" -#include "2s2h/Enhancements/Graphics/MotionBlur.h" -#include "2s2h/Enhancements/Graphics/PlayAsKafei.h" #include "2s2h/DeveloperTools/DeveloperTools.h" #include "window/gui/GuiMenuBar.h" #include "window/gui/GuiElement.h" diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 2cf52494f..95785d296 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1,6 +1,5 @@ #include "2s2h/Enhancements/Enhancements.h" #include "2s2h/DeveloperTools/DeveloperTools.h" -#include "2s2h/Enhancements/Graphics/3DItemDrops.h" #include "UIWidgets.hpp" #include "BenMenuBar.h" #include "macros.h" diff --git a/mm/2s2h/Enhancements/Camera/Camera.h b/mm/2s2h/Enhancements/Camera/Camera.h new file mode 100644 index 000000000..54a035dff --- /dev/null +++ b/mm/2s2h/Enhancements/Camera/Camera.h @@ -0,0 +1,8 @@ +#ifndef CAMERA_H +#define CAMERA_H + +void RegisterCameraInterpolationFixes(); +void RegisterDebugCam(); +void RegisterCameraFreeLook(); + +#endif // CAMERA_H diff --git a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp b/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp index cb02a2143..ac73872bd 100644 --- a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp +++ b/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp @@ -1,4 +1,4 @@ -#include "CameraInterpolationFixes.h" +#include "Camera.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" #include "CameraUtils.h" diff --git a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.h b/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.h deleted file mode 100644 index f159e197e..000000000 --- a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CAMERA_INTERPOLATE_FIXES_H -#define CAMERA_INTERPOLATE_FIXES_H - -void RegisterCameraInterpolationFixes(); - -#endif // CAMERA_INTERPOLATE_FIXES_H diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index 9ec56343a..f5bcc0d7b 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -1,4 +1,3 @@ -#include "DebugCam.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" #include "CameraUtils.h" diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.h b/mm/2s2h/Enhancements/Camera/DebugCam.h deleted file mode 100644 index c61a12695..000000000 --- a/mm/2s2h/Enhancements/Camera/DebugCam.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef FREE_CAM_H -#define FREE_CAM_H - -void RegisterDebugCam(); - -#endif // FREE_CAM_H diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.cpp b/mm/2s2h/Enhancements/Camera/FreeLook.cpp index ade91b987..265edd5ee 100644 --- a/mm/2s2h/Enhancements/Camera/FreeLook.cpp +++ b/mm/2s2h/Enhancements/Camera/FreeLook.cpp @@ -1,4 +1,3 @@ -#include "FreeLook.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" #include "CameraUtils.h" diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.h b/mm/2s2h/Enhancements/Camera/FreeLook.h deleted file mode 100644 index 96c236fc1..000000000 --- a/mm/2s2h/Enhancements/Camera/FreeLook.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef FREE_LOOK_H -#define FREE_LOOK_H - -void RegisterCameraFreeLook(); - -#endif // FREE_LOOK_H diff --git a/mm/2s2h/Enhancements/Cheats/Cheats.h b/mm/2s2h/Enhancements/Cheats/Cheats.h index 497f5e2c5..f89dc877c 100644 --- a/mm/2s2h/Enhancements/Cheats/Cheats.h +++ b/mm/2s2h/Enhancements/Cheats/Cheats.h @@ -1,6 +1,11 @@ #ifndef CHEATS_H #define CHEATS_H +void RegisterInfiniteCheats(); void RegisterLongerFlowerGlide(); +void RegisterMoonJumpOnL(); +void RegisterTimeStopInTemples(); +void RegisterUnbreakableRazorSword(); +void RegisterUnrestrictedItems(); #endif // CHEATS_H diff --git a/mm/2s2h/Enhancements/Cheats/Infinite.cpp b/mm/2s2h/Enhancements/Cheats/Infinite.cpp index ff542feab..308a43c80 100644 --- a/mm/2s2h/Enhancements/Cheats/Infinite.cpp +++ b/mm/2s2h/Enhancements/Cheats/Infinite.cpp @@ -1,4 +1,3 @@ -#include "Infinite.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" #include "variables.h" diff --git a/mm/2s2h/Enhancements/Cheats/Infinite.h b/mm/2s2h/Enhancements/Cheats/Infinite.h deleted file mode 100644 index 7bdffc6cc..000000000 --- a/mm/2s2h/Enhancements/Cheats/Infinite.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEATS_INFINITE_H -#define CHEATS_INFINITE_H - -void RegisterInfiniteCheats(); - -#endif // CHEATS_INFINITE_H diff --git a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp index bc12b95bb..2c406ef7e 100644 --- a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp +++ b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp @@ -1,4 +1,3 @@ -#include "MoonJump.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" #include "variables.h" diff --git a/mm/2s2h/Enhancements/Cheats/MoonJump.h b/mm/2s2h/Enhancements/Cheats/MoonJump.h deleted file mode 100644 index 5f2727e82..000000000 --- a/mm/2s2h/Enhancements/Cheats/MoonJump.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEATS_MOONJUMP_H -#define CHEATS_MOONJUMP_H - -void RegisterMoonJumpOnL(); - -#endif // CHEATS_MOONJUMP_H diff --git a/mm/2s2h/Enhancements/Cheats/TimeStop.h b/mm/2s2h/Enhancements/Cheats/TimeStop.h deleted file mode 100644 index a2729fe2d..000000000 --- a/mm/2s2h/Enhancements/Cheats/TimeStop.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEATS_TIME_STOPS_H -#define CHEATS_TIME_STOPS_H - -void RegisterTimeStopInTemples(); - -#endif // CHEATS_TIME_STOPS_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.h b/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.h deleted file mode 100644 index 84c9f18aa..000000000 --- a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEATS_UNBREAKABLE_RAZOR_SWORD_H -#define CHEATS_UNBREAKABLE_RAZOR_SWORD_H - -void RegisterUnbreakableRazorSword(); - -#endif // CHEATS_UNBREAKABLE_RAZOR_SWORD_H diff --git a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.h b/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.h deleted file mode 100644 index 94c3381bb..000000000 --- a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEATS_UNRESTRICTED_ITEMS_H -#define CHEATS_UNRESTRICTED_ITEMS_H - -void RegisterUnrestrictedItems(); - -#endif // CHEATS_UNRESTRICTED_ITEMS_H diff --git a/mm/2s2h/Enhancements/Cycle/Cycle.h b/mm/2s2h/Enhancements/Cycle/Cycle.h new file mode 100644 index 000000000..612ff1991 --- /dev/null +++ b/mm/2s2h/Enhancements/Cycle/Cycle.h @@ -0,0 +1,6 @@ +#ifndef CYCLE_H +#define CYCLE_H + +void RegisterEndOfCycleSaveHooks(); + +#endif // CYCLE_H diff --git a/mm/2s2h/Enhancements/Cycle/EndOfCycle.h b/mm/2s2h/Enhancements/Cycle/EndOfCycle.h deleted file mode 100644 index 57e4dfec0..000000000 --- a/mm/2s2h/Enhancements/Cycle/EndOfCycle.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CYCLES_END_H -#define CYCLES_END_H - -void RegisterEndOfCycleSaveHooks(); - -#endif // CYCLES_END_H diff --git a/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp index 1035fb398..c9f72647d 100644 --- a/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp +++ b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp @@ -1,9 +1,12 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { #include "z64.h" #include "global.h" #include "overlays/actors/ovl_En_Ginko_Man/z_en_ginko_man.h" +} static const char zeroRupees[3] = { '0', '0', '0' }; diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 4e51dfac7..8ec82aa36 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -1,43 +1,21 @@ #ifndef ENHANCEMENTS_H #define ENHANCEMENTS_H -#include "Camera/CameraInterpolationFixes.h" -#include "Camera/DebugCam.h" -#include "Camera/FreeLook.h" -#include "Cheats/MoonJump.h" -#include "Cheats/Infinite.h" -#include "Dialogue/Dialogue.h" -#include "Graphics/TextBasedClock.h" -#include "Graphics/3DSClock.h" +#include "Camera/Camera.h" #include "Cheats/Cheats.h" -#include "Cheats/UnbreakableRazorSword.h" -#include "Cheats/UnrestrictedItems.h" -#include "Cheats/TimeStop.h" -#include "Cycle/EndOfCycle.h" -#include "Equipment/SkipMagicArrowEquip.h" -#include "Fixes/Fixes.h" -#include "Masks/BlastMaskKeg.h" -#include "Masks/FierceDeityAnywhere.h" -#include "Masks/NoBlastMaskCooldown.h" -#include "Masks/FastTransformation.h" -#include "Masks/PersistentMasks.h" -#include "Minigames/AlwaysWinDoggyRace.h" #include "Cutscenes/Cutscenes.h" -#include "Restorations/FlipHopVariable.h" -#include "Restorations/PowerCrouchStab.h" -#include "Restorations/Restorations.h" -#include "Restorations/SideRoll.h" -#include "Restorations/TatlISG.h" -#include "Graphics/3DItemDrops.h" -#include "Graphics/PlayAsKafei.h" -#include "Equipment/InstantRecall.h" +#include "Cycle/Cycle.h" +#include "Dialogue/Dialogue.h" +#include "Equipment/Equipment.h" +#include "Fixes/Fixes.h" +#include "Graphics/Graphics.h" +#include "Masks/Masks.h" +#include "Minigames/Minigames.h" +#include "Modes/Modes.h" #include "Player/Player.h" -#include "Songs/EnableSunsSong.h" -#include "Songs/PauseOwlWarp.h" -#include "Songs/ZoraEggCount.h" +#include "Restorations/Restorations.h" #include "Saving/SavingEnhancements.h" -#include "Graphics/DisableBlackBars.h" -#include "Modes/TimeMovesWhenYouMove.h" +#include "Songs/Songs.h" enum AlwaysWinDoggyRaceOptions { ALWAYS_WIN_DOGGY_RACE_OFF, diff --git a/mm/2s2h/Enhancements/Equipment/Equipment.h b/mm/2s2h/Enhancements/Equipment/Equipment.h new file mode 100644 index 000000000..ca23748c9 --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/Equipment.h @@ -0,0 +1,7 @@ +#ifndef EQUIPMENT_H +#define EQUIPMENT_H + +void RegisterInstantRecall(); +void RegisterSkipMagicArrowEquip(); + +#endif // EQUIPMENT_H diff --git a/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp index dad419353..eabbb7662 100644 --- a/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp +++ b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp @@ -1,9 +1,8 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" -#include "InstantRecall.h" -#include "src/overlays/actors/ovl_En_Boom/z_en_boom.h" extern "C" { +#include "src/overlays/actors/ovl_En_Boom/z_en_boom.h" extern PlayState* gPlayState; } diff --git a/mm/2s2h/Enhancements/Equipment/InstantRecall.h b/mm/2s2h/Enhancements/Equipment/InstantRecall.h deleted file mode 100644 index 4dd58d4fc..000000000 --- a/mm/2s2h/Enhancements/Equipment/InstantRecall.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef EQUIPMENT_INSTAND_RECALL_H -#define EQUIPMENT_INSTAND_RECALL_H - -void RegisterInstantRecall(); - -#endif // EQUIPMENT_INSTAND_RECALL_H diff --git a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp index 299748061..52c0f1064 100644 --- a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp +++ b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp @@ -1,9 +1,9 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" -#include "z64.h" -#include "src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" extern "C" { +#include "z64.h" +#include "src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" extern s16 sEquipState; extern s16 sEquipAnimTimer; } diff --git a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h deleted file mode 100644 index 2c96b97b9..000000000 --- a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H -#define EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H - -void RegisterSkipMagicArrowEquip(); - -#endif // EQUIPMENT_SKIP_MAGIC_ARROW_EQUIP_H diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp index f72031e86..acf93cda9 100644 --- a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp @@ -1,4 +1,3 @@ -#include "3DItemDrops.h" #include "libultraship/libultraship.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.h b/mm/2s2h/Enhancements/Graphics/3DItemDrops.h deleted file mode 100644 index 2801aaac2..000000000 --- a/mm/2s2h/Enhancements/Graphics/3DItemDrops.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef GRAPHICS_3D_ITEM_DROPS_H -#define GRAPHICS_3D_ITEM_DROPS_H - -void Register3DItemDrops(); - -#endif // GRAPHICS_3D_ITEM_DROPS_H diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.h b/mm/2s2h/Enhancements/Graphics/3DSClock.h deleted file mode 100644 index 8a7dc143e..000000000 --- a/mm/2s2h/Enhancements/Graphics/3DSClock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MM3D_CLOCK_H -#define MM3D_CLOCK_H - -void Register3DSClock(); - -#endif // TEXT_BASED_CLOCK_H diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp index f98b8e68f..c14532842 100644 --- a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp +++ b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp @@ -1,6 +1,5 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" -#include "DisableBlackBars.h" void RegisterDisableBlackBars() { REGISTER_VB_SHOULD(VB_DISABLE_LETTERBOX, { diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h deleted file mode 100644 index fc5be3b3c..000000000 --- a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef GRAPHICS_DISABLE_BLACK_BARS_H -#define GRAPHICS_DISABLE_BLACK_BARS_H - -void RegisterDisableBlackBars(); - -#endif // GRAPHICS_DISABLE_BLACK_BARS_H diff --git a/mm/2s2h/Enhancements/Graphics/Graphics.h b/mm/2s2h/Enhancements/Graphics/Graphics.h new file mode 100644 index 000000000..917c6aa74 --- /dev/null +++ b/mm/2s2h/Enhancements/Graphics/Graphics.h @@ -0,0 +1,23 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +void Register3DItemDrops(); +void Register3DSClock(); +void RegisterDisableBlackBars(); +void MotionBlur_RenderMenuOptions(); +void RegisterPlayAsKafei(); +void RegisterTextBasedClock(); + +#ifdef __cplusplus +#include + +extern "C" { +#endif + +void MotionBlur_Override(u8* status, s32* alpha); + +#ifdef __cplusplus +}; +#endif + +#endif // GRAPHICS_H diff --git a/mm/2s2h/Enhancements/Graphics/MotionBlur.cpp b/mm/2s2h/Enhancements/Graphics/MotionBlur.cpp index d7afd78e1..0c4dc1c0a 100644 --- a/mm/2s2h/Enhancements/Graphics/MotionBlur.cpp +++ b/mm/2s2h/Enhancements/Graphics/MotionBlur.cpp @@ -1,4 +1,3 @@ -#include "MotionBlur.h" #include #include "2s2h/BenGui/UIWidgets.hpp" diff --git a/mm/2s2h/Enhancements/Graphics/MotionBlur.h b/mm/2s2h/Enhancements/Graphics/MotionBlur.h deleted file mode 100644 index 0719d0c17..000000000 --- a/mm/2s2h/Enhancements/Graphics/MotionBlur.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef MOTION_BLUR_H -#define MOTION_BLUR_H - -void MotionBlur_RenderMenuOptions(); - -#ifdef __cplusplus -#include - -extern "C" { -#endif - -void MotionBlur_Override(u8* status, s32* alpha); - -#ifdef __cplusplus -}; -#endif - -#endif // MOTION_BLUR_H diff --git a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp b/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp index 9c69d6704..a00159c16 100644 --- a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp +++ b/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp @@ -1,4 +1,3 @@ -#include "PlayAsKafei.h" #include "libultraship/libultraship.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" diff --git a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.h b/mm/2s2h/Enhancements/Graphics/PlayAsKafei.h deleted file mode 100644 index 0a6cd18e0..000000000 --- a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef GRAPHICS_PLAY_AS_KAFEI_H -#define GRAPHICS_PLAY_AS_KAFEI_H - -void RegisterPlayAsKafei(); -void UpdatePlayAsKafeiSkeletons(); -void UpdatePlayAsKafeiOther(); - -#endif // GRAPHICS_PLAY_AS_KAFEI_H diff --git a/mm/2s2h/Enhancements/Graphics/TextBasedClock.h b/mm/2s2h/Enhancements/Graphics/TextBasedClock.h deleted file mode 100644 index c85ba9450..000000000 --- a/mm/2s2h/Enhancements/Graphics/TextBasedClock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef TEXT_BASED_CLOCK_H -#define TEXT_BASED_CLOCK_H - -void RegisterTextBasedClock(); - -#endif // TEXT_BASED_CLOCK_H diff --git a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp index b883822ec..ee8a87a83 100644 --- a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp +++ b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp @@ -1,10 +1,10 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" -#include "global.h" static uint32_t bombType; extern "C" { +#include "global.h" #include "overlays/actors/ovl_En_Bom/z_en_bom.h" EquipSlot func_8082FDC4(void); } diff --git a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h deleted file mode 100644 index a32a4726b..000000000 --- a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef EQUIPMENT_BLAST_MASK_KEG_H -#define EQUIPMENT_BLAST_MASK_KEG_H - -void RegisterBlastMaskKeg(); - -#endif // EQUIPMENT_BLAST_MASK_KEG_H diff --git a/mm/2s2h/Enhancements/Masks/FastTransformation.h b/mm/2s2h/Enhancements/Masks/FastTransformation.h deleted file mode 100644 index 6820c3c9a..000000000 --- a/mm/2s2h/Enhancements/Masks/FastTransformation.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MASKS_FAST_TRANSFORMATION_H -#define MASKS_FAST_TRANSFORMATION_H - -void RegisterFastTransformation(); - -#endif // MASKS_FAST_TRANSFORMATION_H diff --git a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.h b/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.h deleted file mode 100644 index ee5b87e4d..000000000 --- a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MASKS_FD_ANYWHERE_H -#define MASKS_FD_ANYWHERE_H - -void RegisterFierceDeityAnywhere(); - -#endif // MASKS_FD_ANYWHERE_H diff --git a/mm/2s2h/Enhancements/Masks/Masks.h b/mm/2s2h/Enhancements/Masks/Masks.h new file mode 100644 index 000000000..f65949ef0 --- /dev/null +++ b/mm/2s2h/Enhancements/Masks/Masks.h @@ -0,0 +1,11 @@ +#ifndef MASKS_H +#define MASKS_H + +void RegisterBlastMaskKeg(); +void RegisterFastTransformation(); +void RegisterFierceDeityAnywhere(); +void RegisterNoBlastMaskCooldown(); +void RegisterPersistentMasks(); +void UpdatePersistentMasksState(); + +#endif // MASKS_H diff --git a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.h b/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.h deleted file mode 100644 index ed2a85efc..000000000 --- a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef NO_BLAST_MASK_COOLDOWN_H -#define NO_BLAST_MASK_COOLDOWN_H - -void RegisterNoBlastMaskCooldown(); - -#endif // NO_BLAST_MASK_COOLDOWN_H diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.h b/mm/2s2h/Enhancements/Masks/PersistentMasks.h deleted file mode 100644 index db441e7b8..000000000 --- a/mm/2s2h/Enhancements/Masks/PersistentMasks.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef MASKS_PERSISTENT_MASKS_H -#define MASKS_PERSISTENT_MASKS_H - -void RegisterPersistentMasks(); -void UpdatePersistentMasksState(); - -#endif // MASKS_PERSISTENT_MASKS_H diff --git a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.h b/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.h deleted file mode 100644 index 90318122d..000000000 --- a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MINIGAMES_ALWAYS_WIN_DOGGY_RACE_H -#define MINIGAMES_ALWAYS_WIN_DOGGY_RACE_H - -void RegisterAlwaysWinDoggyRace(); - -#endif // MINIGAMES_ALWAYS_WIN_DOGGY_RACE_H diff --git a/mm/2s2h/Enhancements/Minigames/Minigames.h b/mm/2s2h/Enhancements/Minigames/Minigames.h new file mode 100644 index 000000000..f7b02c094 --- /dev/null +++ b/mm/2s2h/Enhancements/Minigames/Minigames.h @@ -0,0 +1,6 @@ +#ifndef MINIGAMES_H +#define MINIGAMES_H + +void RegisterAlwaysWinDoggyRace(); + +#endif // MINIGAMES_H diff --git a/mm/2s2h/Enhancements/Modes/Modes.h b/mm/2s2h/Enhancements/Modes/Modes.h new file mode 100644 index 000000000..f46466f1a --- /dev/null +++ b/mm/2s2h/Enhancements/Modes/Modes.h @@ -0,0 +1,6 @@ +#ifndef MODES_H +#define MODES_H + +void RegisterTimeMovesWhenYouMove(); + +#endif // MODES_H diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp index 8c56f8b8c..0ed98c051 100644 --- a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp +++ b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp @@ -1,4 +1,3 @@ -#include "TimeMovesWhenYouMove.h" #include "libultraship/libultraship.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h deleted file mode 100644 index 15532cd21..000000000 --- a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MODES_TIME_MOVES_WHEN_YOU_MOVE_H -#define MODES_TIME_MOVES_WHEN_YOU_MOVE_H - -void RegisterTimeMovesWhenYouMove(); - -#endif // MODES_TIME_MOVES_WHEN_YOU_MOVE_H diff --git a/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp index 50c2fe185..07bac7321 100644 --- a/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp +++ b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp @@ -1,6 +1,5 @@ #include #include "Enhancements/GameInteractor/GameInteractor.h" -#include "spdlog/spdlog.h" extern "C" { #include "macros.h" diff --git a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.h b/mm/2s2h/Enhancements/Restorations/FlipHopVariable.h deleted file mode 100644 index 570424213..000000000 --- a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef RESTORATIONS_FLIP_HOP_VARIABLE_H -#define RESTORATIONS_FLIP_HOP_VARIABLE_H - -void RegisterVariableFlipHop(); - -#endif // RESTORATIONS_FLIP_HOP_VARIABLE_H diff --git a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.h b/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.h deleted file mode 100644 index 64747487f..000000000 --- a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef RESTORATIONS_POWER_CROUCH_STAB_H -#define RESTORATIONS_POWER_CROUCH_STAB_H - -void RegisterPowerCrouchStab(); - -#endif // RESTORATIONS_POWER_CROUCH_STAB_H diff --git a/mm/2s2h/Enhancements/Restorations/Restorations.h b/mm/2s2h/Enhancements/Restorations/Restorations.h index 8b2a722e6..667a3866d 100644 --- a/mm/2s2h/Enhancements/Restorations/Restorations.h +++ b/mm/2s2h/Enhancements/Restorations/Restorations.h @@ -1,6 +1,10 @@ #ifndef ENHANCEMENTS_RESTORATIONS_H #define ENHANCEMENTS_RESTORATIONS_H +void RegisterVariableFlipHop(); +void RegisterPowerCrouchStab(); +void RegisterSideRoll(); +void RegisterTatlISG(); void RegisterWoodfallMountainAppearance(); #endif // ENHANCEMENTS_RESTORATIONS_H diff --git a/mm/2s2h/Enhancements/Restorations/SideRoll.h b/mm/2s2h/Enhancements/Restorations/SideRoll.h deleted file mode 100644 index f0fe430e0..000000000 --- a/mm/2s2h/Enhancements/Restorations/SideRoll.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef RESTORATIONS_SIDEROLL_H -#define RESTORATIONS_SIDEROLL_H - -void RegisterSideRoll(); - -#endif // RESTORATIONS_SIDEROLL_H diff --git a/mm/2s2h/Enhancements/Restorations/TatlISG.h b/mm/2s2h/Enhancements/Restorations/TatlISG.h deleted file mode 100644 index d1ed5afd6..000000000 --- a/mm/2s2h/Enhancements/Restorations/TatlISG.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef RESTORATIONS_TATL_ISG_H -#define RESTORATIONS_TATL_ISG_H - -void RegisterTatlISG(); - -#endif // RESTORATIONS_TATL_ISG_H diff --git a/mm/2s2h/Enhancements/Songs/EnableSunsSong.h b/mm/2s2h/Enhancements/Songs/EnableSunsSong.h deleted file mode 100644 index 6ce2b5342..000000000 --- a/mm/2s2h/Enhancements/Songs/EnableSunsSong.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SONGS_ENABLE_SUNS_SONG_H -#define SONGS_ENABLE_SUNS_SONG_H - -void RegisterEnableSunsSong(); - -#endif // SONGS_ENABLE_SUNS_SONG_H diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp index 35f27f4f2..f1c7ea2ca 100644 --- a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp @@ -1,4 +1,3 @@ -#include "PauseOwlWarp.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h deleted file mode 100644 index b6adfeab9..000000000 --- a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef PAUSE_OWL_WARP_H -#define PAUSE_OWL_WARP_H - -#ifdef __cplusplus -extern "C" { -#endif - -void RegisterPauseOwlWarp(void); -bool PauseOwlWarp_IsOwlWarpEnabled(void); - -#ifdef __cplusplus -} -#endif - -#endif // PAUSE_OWL_WARP_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Songs/Songs.h b/mm/2s2h/Enhancements/Songs/Songs.h new file mode 100644 index 000000000..22469f29e --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/Songs.h @@ -0,0 +1,18 @@ +#ifndef SONGS_H +#define SONGS_H + +void RegisterEnableSunsSong(); +void RegisterZoraEggCount(); +void RegisterPauseOwlWarp(); + +#ifdef __cplusplus +extern "C" { +#endif + +bool PauseOwlWarp_IsOwlWarpEnabled(void); + +#ifdef __cplusplus +} +#endif + +#endif // SONGS_H diff --git a/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp index af03c56fe..f15354bfe 100644 --- a/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp +++ b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp @@ -1,4 +1,3 @@ -#include "ZoraEggCount.h" #include #include "Enhancements/GameInteractor/GameInteractor.h" diff --git a/mm/2s2h/Enhancements/Songs/ZoraEggCount.h b/mm/2s2h/Enhancements/Songs/ZoraEggCount.h deleted file mode 100644 index 35ac5ed60..000000000 --- a/mm/2s2h/Enhancements/Songs/ZoraEggCount.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef VARIABLE_ZORA_EGG_COUNT_H -#define VARIABLE_ZORA_EGG_COUNT_H - -void RegisterZoraEggCount(); - -#endif // VARIABLE_ZORA_EGG_COUNT_H \ No newline at end of file diff --git a/mm/src/code/z_camera.c b/mm/src/code/z_camera.c index a42dcde2a..7b02ea02a 100644 --- a/mm/src/code/z_camera.c +++ b/mm/src/code/z_camera.c @@ -64,7 +64,7 @@ Vec3f D_801EDDE0; Vec3f D_801EDDF0; #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" -#include "2s2h/Enhancements/Camera/FreeLook.h" +#include "2s2h/Enhancements/Camera/Camera.h" // Camera will reload its paramData. Usually that means setting the read-only data from what is stored in // CameraModeValue arrays. Although sometimes some read-write data is reset as well diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index 80492c22e..56f132219 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -37,7 +37,7 @@ u8 sMotionBlurStatus; #include "BenPort.h" #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "2s2h/Enhancements/Graphics/MotionBlur.h" +#include "2s2h/Enhancements/Graphics/Graphics.h" #include "2s2h/DeveloperTools/CollisionViewer.h" #include "2s2h/framebuffer_effects.h" #include diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c index 9ae8cb101..dcb50ae76 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c @@ -13,7 +13,7 @@ #include "BenPort.h" -#include "2s2h/Enhancements/Songs/PauseOwlWarp.h" +#include "2s2h/Enhancements/Songs/Songs.h" // 2S2H [Port] (and line 26) don't do pointer math and access the list of digits directly. extern const char* sCounterTextures[]; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index 4bcb9ed18..2b7c35156 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -24,7 +24,7 @@ #include "2s2h/Enhancements/GameInteractor/GameInteractor.h" -#include "2s2h/Enhancements/Songs/PauseOwlWarp.h" +#include "2s2h/Enhancements/Songs/Songs.h" // Page Textures (Background of Page): // Broken up into multiple textures. From 4c670ad342790123372c97924ed3255cc4a9e8c9 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 5 Oct 2024 10:13:31 -0500 Subject: [PATCH 55/82] Use glob_recurse across all of 2s2h/ (#797) * Use glob_recurse across all of 2s2h/ * Update mm/CMakeLists.txt Co-authored-by: Archez * Remove old source_group calls --------- Co-authored-by: Archez --- mm/CMakeLists.txt | 116 +++++----------------------------------------- 1 file changed, 12 insertions(+), 104 deletions(-) diff --git a/mm/CMakeLists.txt b/mm/CMakeLists.txt index 1f4a1f728..4640ff349 100644 --- a/mm/CMakeLists.txt +++ b/mm/CMakeLists.txt @@ -119,9 +119,13 @@ list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/ultra source_group("include" FILES ${Header_Files__include}) # }}} -# m (root) -file(GLOB soh__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/*.c" "2s2h/*.cpp" "2s2h/*.h" "2s2h/*.hpp") -source_group("2s2h" FILES ${soh__}) +file(GLOB_RECURSE ship__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/*.c" "2s2h/*.cpp" "2s2h/*.h" "2s2h/*.hpp") +# Create source groups that match the real file directory paths +foreach(source IN LISTS ship__) + get_filename_component(source_path "${source}" PATH) + string(REPLACE "/" "\\" source_path_adjusted "${source_path}") + source_group("${source_path_adjusted}" FILES "${source}") +endforeach() file(GLOB_RECURSE libultra_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/PR/*.h" @@ -131,112 +135,22 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set_source_files_properties(2s2h/BenPort.cpp PROPERTIES COMPILE_FLAGS "/utf-8") endif() -# 2s2h/DeveloperTools {{{ -file(GLOB_RECURSE soh__DeveloperTools RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - "2s2h/DeveloperTools/*.h" - "2s2h/DeveloperTools/*.c" - "2s2h/DeveloperTools/*.cpp" - "2s2h/DeveloperTools/*.hpp" -) -# }}} - -# soh/config {{{ -#file(GLOB_RECURSE soh__config RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} -# "soh/config/*.h" -# "soh/config/*.cpp" -#) -# }}} - -# soh/enhancements {{{ -file(GLOB_RECURSE soh__Enhancements RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - "2s2h/Enhancements/*.c" - "2s2h/Enhancements/*.cpp" - "2s2h/Enhancements/*.h" - "2s2h/Enhancements/*.hpp" - "2s2h/Enhancements/*_extern.inc" - "2s2h/Enhancements/*.mm" -) - -file(GLOB_RECURSE soh__BenGui RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - "2s2h/BenGui/*.c" - "2s2h/BenGui/*.cpp" - "2s2h/BenGui/*.h" - "2s2h/BenGui/*.hpp" -) - -file(GLOB_RECURSE soh__SaveManager RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - "2s2h/SaveManager/*.c" - "2s2h/SaveManager/*.cpp" - "2s2h/SaveManager/*.h" - "2s2h/SaveManager/*.hpp" -) - -#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/gamecommand.h") -#list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/gfx.*") - -# handle crowd control removals -#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs") -#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak") -#if (!BUILD_CROWD_CONTROL) -# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*") -#endif() - -# handle speechsynthesizer removals -#if (CMAKE_SYSTEM_NAME STREQUAL "Windows") -# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/Darwin*") -#elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") -# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/SAPI*") -#else() -# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/(Darwin|SAPI).*") -#endif() - -#source_group("soh\\Enhancements" REGULAR_EXPRESSION "soh/Enhancements/*") -#source_group("soh\\Enhancements\\audio" REGULAR_EXPRESSION "soh/Enhancements/audio/*") -# source_group("2s2h\\Enhancements\\interpolation" REGULAR_EXPRESSION "2s2h/Enhancements/interpolation/*") -#source_group("soh\\Enhancements\\cosmetics" REGULAR_EXPRESSION "soh/Enhancements/cosmetics/*") -#source_group("soh\\Enhancements\\crowd-control" REGULAR_EXPRESSION "soh/Enhancements/crowd-control/*") -#source_group("soh\\Enhancements\\custom-message" REGULAR_EXPRESSION "soh/Enhancements/custom-message/*") -#source_group("soh\\Enhancements\\debugger" REGULAR_EXPRESSION "soh/Enhancements/debugger/*") -#source_group("soh\\Enhancements\\game-interactor" REGULAR_EXPRESSION "soh/Enhancements/game-interactor/*") -#source_group("soh\\Enhancements\\item-tables" REGULAR_EXPRESSION "soh/Enhancements/item-tables/*") -#source_group("soh\\Enhancements\\randomizer" REGULAR_EXPRESSION "soh/Enhancements/randomizer/*") -#source_group("soh\\Enhancements\\randomizer\\3drando" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/*") -#source_group("soh\\Enhancements\\randomizer\\3drando\\hint_list" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/hint_list/*") -#source_group("soh\\Enhancements\\randomizer\\3drando\\location_access" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/location_access/*") -#source_group("soh\\Enhancements\\speechsynthesizer" REGULAR_EXPRESSION "soh/Enhancements/speechsynthesizer/*") -#source_group("soh\\Enhancements\\tts" REGULAR_EXPRESSION "soh/Enhancements/tts/*") - -#if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") -# set_source_files_properties(soh/Enhancements/tts/tts.cpp PROPERTIES COMPILE_FLAGS "/utf-8") -#endif() -# }}} +list(FILTER ship__ EXCLUDE REGEX "2s2h/Extractor/*") if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") - # 2s2h/Extractor {{{ - file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + file(GLOB_RECURSE ship__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/Extractor/*.c" "2s2h/Extractor/*.cpp" "2s2h/Extractor/*.h" "2s2h/Extractor/*.hpp" ) - # }}} else() - file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + file(GLOB_RECURSE ship__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/Extractor/*.h" "2s2h/Extractor/*.hpp" ) -# }}} endif() -# 2s2h/resource {{{ -file(GLOB_RECURSE soh__Resource RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/resource/*.cpp" "2s2h/resource/*.h") - -source_group("2s2h\\resource\\type" REGULAR_EXPRESSION "2s2h/resource/type/*") -source_group("2s2h\\resource\\type\\scenecommand" REGULAR_EXPRESSION "2s2h/resource/type/scenecommand/*") -source_group("2s2h\\resource\\importer" REGULAR_EXPRESSION "2s2h/resource/importer/*") -source_group("2s2h\\resource\\importer\\scenecommand" REGULAR_EXPRESSION "2s2h/resource/importer/scenecommand/*") -# }}} - # src (decomp) {{{ file(GLOB_RECURSE src__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.c" "src/*.h") @@ -277,15 +191,9 @@ source_group("src\\overlays\\misc" REGULAR_EXPRESSION "src/overlays/misc/*") set(ALL_FILES ${Header_Files} ${Header_Files__include} - ${soh__} + ${ship__} ${libultra_headers} - ${soh__DeveloperTools} -# ${soh__config} - ${soh__Enhancements} - ${soh__BenGui} - ${soh__SaveManager} - ${soh__Extractor} - ${soh__Resource} + ${ship__Extractor} ${src__} ) From a93f011253177647cf227669d51df201282c90f6 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 5 Oct 2024 10:33:10 -0500 Subject: [PATCH 56/82] Move GameInteractor & NameTag src up to root of 2s2h (#799) --- mm/2s2h/BenPort.cpp | 4 ++-- mm/2s2h/DeveloperTools/ActorViewer.cpp | 4 ++-- mm/2s2h/DeveloperTools/CollisionViewer.cpp | 2 +- mm/2s2h/DeveloperTools/DeveloperTools.cpp | 2 +- mm/2s2h/DeveloperTools/EventLog.cpp | 2 +- mm/2s2h/DeveloperTools/SaveEditor.cpp | 2 +- mm/2s2h/DeveloperTools/WarpPoint.cpp | 2 +- mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp | 4 ++-- mm/2s2h/Enhancements/Camera/DebugCam.cpp | 2 +- mm/2s2h/Enhancements/Camera/FreeLook.cpp | 2 +- mm/2s2h/Enhancements/Cheats/Infinite.cpp | 2 +- mm/2s2h/Enhancements/Cheats/MoonJump.cpp | 2 +- mm/2s2h/Enhancements/Cheats/TimeStop.cpp | 4 ++-- mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp | 2 +- mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp | 2 +- mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp | 2 +- .../Cutscenes/MiscInteractions/SkipDekuSalesman.cpp | 2 +- .../Cutscenes/MiscInteractions/SkipScarecrowDance.cpp | 2 +- .../Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp | 2 +- mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp | 2 +- mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp | 2 +- mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp | 2 +- .../Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp | 2 +- mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp | 2 +- mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp | 2 +- mm/2s2h/Enhancements/Equipment/InstantRecall.cpp | 2 +- mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp | 2 +- mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp | 2 +- mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp | 2 +- mm/2s2h/Enhancements/Graphics/3DSClock.cpp | 2 +- mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp | 2 +- mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp | 2 +- mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp | 2 +- mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp | 2 +- mm/2s2h/Enhancements/Masks/FastTransformation.cpp | 2 +- mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp | 2 +- mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp | 2 +- mm/2s2h/Enhancements/Masks/PersistentMasks.cpp | 4 ++-- mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp | 4 ++-- mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp | 2 +- mm/2s2h/Enhancements/Player/ClimbSpeed.cpp | 2 +- mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp | 2 +- mm/2s2h/Enhancements/Player/InstantPutaway.cpp | 2 +- mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp | 2 +- mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp | 2 +- mm/2s2h/Enhancements/Restorations/SideRoll.cpp | 2 +- mm/2s2h/Enhancements/Restorations/TatlISG.cpp | 2 +- .../Enhancements/Restorations/WoodfallMountainAppearance.cpp | 2 +- mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp | 2 +- mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp | 2 +- mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp | 2 +- mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp | 2 +- mm/2s2h/{Enhancements => }/GameInteractor/GameInteractor.cpp | 0 mm/2s2h/{Enhancements => }/GameInteractor/GameInteractor.h | 0 mm/2s2h/{Enhancements => }/NameTag/NameTag.cpp | 2 +- mm/2s2h/{Enhancements => }/NameTag/NameTag.h | 0 mm/2s2h/z_play_2SH.cpp | 2 +- mm/2s2h/z_scene_2SH.cpp | 2 +- mm/src/audio/code_8019AF00.c | 2 +- mm/src/code/game.c | 2 +- mm/src/code/z_actor.c | 2 +- mm/src/code/z_camera.c | 2 +- mm/src/code/z_demo.c | 2 +- mm/src/code/z_lib.c | 2 +- mm/src/code/z_message.c | 2 +- mm/src/code/z_parameter.c | 2 +- mm/src/code/z_play.c | 2 +- mm/src/code/z_player_lib.c | 2 +- mm/src/code/z_shrink_window.c | 2 +- mm/src/code/z_sram_NES.c | 2 +- mm/src/code/z_view.c | 2 +- mm/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c | 2 +- mm/src/overlays/actors/ovl_Boss_02/z_boss_02.c | 2 +- mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c | 2 +- mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c | 2 +- mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c | 2 +- mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c | 2 +- mm/src/overlays/actors/ovl_En_Ja/z_en_ja.c | 2 +- mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c | 2 +- mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c | 2 +- mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c | 2 +- mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c | 2 +- mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c | 2 +- mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c | 2 +- mm/src/overlays/actors/ovl_player_actor/z_player.c | 2 +- mm/src/overlays/gamestates/ovl_title/z_title.c | 2 +- .../overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c | 2 +- .../overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c | 2 +- .../kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c | 2 +- 89 files changed, 92 insertions(+), 92 deletions(-) rename mm/2s2h/{Enhancements => }/GameInteractor/GameInteractor.cpp (100%) rename mm/2s2h/{Enhancements => }/GameInteractor/GameInteractor.h (100%) rename mm/2s2h/{Enhancements => }/NameTag/NameTag.cpp (99%) rename mm/2s2h/{Enhancements => }/NameTag/NameTag.h (100%) diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 26113a1d2..0c3c9dda8 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -49,8 +49,8 @@ CrowdControl* CrowdControl::Instance; #include #include -#include "Enhancements/GameInteractor/GameInteractor.h" -#include "Enhancements/Enhancements.h" +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Enhancements.h" #include "2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h" #include "2s2h/DeveloperTools/DebugConsole.h" #include "2s2h/DeveloperTools/DeveloperTools.h" diff --git a/mm/2s2h/DeveloperTools/ActorViewer.cpp b/mm/2s2h/DeveloperTools/ActorViewer.cpp index a3542960e..545a10d9d 100644 --- a/mm/2s2h/DeveloperTools/ActorViewer.cpp +++ b/mm/2s2h/DeveloperTools/ActorViewer.cpp @@ -1,7 +1,7 @@ #include "ActorViewer.h" #include "2s2h/BenGui/UIWidgets.hpp" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" -#include "2s2h/Enhancements/NameTag/NameTag.h" +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/NameTag/NameTag.h" #include #include #include diff --git a/mm/2s2h/DeveloperTools/CollisionViewer.cpp b/mm/2s2h/DeveloperTools/CollisionViewer.cpp index efbc9f77a..6e6dd56e8 100644 --- a/mm/2s2h/DeveloperTools/CollisionViewer.cpp +++ b/mm/2s2h/DeveloperTools/CollisionViewer.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/DeveloperTools/DeveloperTools.cpp b/mm/2s2h/DeveloperTools/DeveloperTools.cpp index 316d851e5..5dd04fe61 100644 --- a/mm/2s2h/DeveloperTools/DeveloperTools.cpp +++ b/mm/2s2h/DeveloperTools/DeveloperTools.cpp @@ -1,7 +1,7 @@ #include "DeveloperTools.h" #include "BenPort.h" #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "macros.h" diff --git a/mm/2s2h/DeveloperTools/EventLog.cpp b/mm/2s2h/DeveloperTools/EventLog.cpp index 2cd60f733..6eacb3b03 100644 --- a/mm/2s2h/DeveloperTools/EventLog.cpp +++ b/mm/2s2h/DeveloperTools/EventLog.cpp @@ -6,7 +6,7 @@ #include #include "2s2h/BenGui/UIWidgets.hpp" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/DeveloperTools/SaveEditor.cpp b/mm/2s2h/DeveloperTools/SaveEditor.cpp index 8d6811628..1853abe3d 100644 --- a/mm/2s2h/DeveloperTools/SaveEditor.cpp +++ b/mm/2s2h/DeveloperTools/SaveEditor.cpp @@ -1,6 +1,6 @@ #include "SaveEditor.h" #include "2s2h/BenGui/UIWidgets.hpp" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "interface/icon_item_dungeon_static/icon_item_dungeon_static.h" #include "archives/icon_item_24_static/icon_item_24_static_yar.h" diff --git a/mm/2s2h/DeveloperTools/WarpPoint.cpp b/mm/2s2h/DeveloperTools/WarpPoint.cpp index bb556eeb6..fa0de177e 100644 --- a/mm/2s2h/DeveloperTools/WarpPoint.cpp +++ b/mm/2s2h/DeveloperTools/WarpPoint.cpp @@ -1,7 +1,7 @@ #include #include "2s2h/BenGui/UIWidgets.hpp" #include "window/gui/IconsFontAwesome4.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/DeveloperTools/DeveloperTools.h" extern "C" { diff --git a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp b/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp index ac73872bd..f411f7aeb 100644 --- a/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp +++ b/mm/2s2h/Enhancements/Camera/CameraInterpolationFixes.cpp @@ -1,8 +1,8 @@ #include "Camera.h" #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "CameraUtils.h" -#include "Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Camera/DebugCam.cpp b/mm/2s2h/Enhancements/Camera/DebugCam.cpp index f5bcc0d7b..4b1c1a6ba 100644 --- a/mm/2s2h/Enhancements/Camera/DebugCam.cpp +++ b/mm/2s2h/Enhancements/Camera/DebugCam.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "CameraUtils.h" extern "C" { diff --git a/mm/2s2h/Enhancements/Camera/FreeLook.cpp b/mm/2s2h/Enhancements/Camera/FreeLook.cpp index 265edd5ee..3431f4abb 100644 --- a/mm/2s2h/Enhancements/Camera/FreeLook.cpp +++ b/mm/2s2h/Enhancements/Camera/FreeLook.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "CameraUtils.h" extern "C" { diff --git a/mm/2s2h/Enhancements/Cheats/Infinite.cpp b/mm/2s2h/Enhancements/Cheats/Infinite.cpp index 308a43c80..92a75fda2 100644 --- a/mm/2s2h/Enhancements/Cheats/Infinite.cpp +++ b/mm/2s2h/Enhancements/Cheats/Infinite.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "variables.h" void RegisterInfiniteCheats() { diff --git a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp index 2c406ef7e..a41edc9b1 100644 --- a/mm/2s2h/Enhancements/Cheats/MoonJump.cpp +++ b/mm/2s2h/Enhancements/Cheats/MoonJump.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "variables.h" static HOOK_ID moonJumpOnLGameStateUpdateHookId = 0; diff --git a/mm/2s2h/Enhancements/Cheats/TimeStop.cpp b/mm/2s2h/Enhancements/Cheats/TimeStop.cpp index fb12fc0b5..bae6edf37 100644 --- a/mm/2s2h/Enhancements/Cheats/TimeStop.cpp +++ b/mm/2s2h/Enhancements/Cheats/TimeStop.cpp @@ -1,7 +1,7 @@ #include #include "BenPort.h" -#include "Enhancements/GameInteractor/GameInteractor.h" -#include "Enhancements/Enhancements.h" +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Enhancements.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp b/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp index 8f6b31247..da03acf23 100644 --- a/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp +++ b/mm/2s2h/Enhancements/Cheats/UnbreakableRazorSword.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterUnbreakableRazorSword() { REGISTER_VB_SHOULD(VB_LOWER_RAZOR_SWORD_DURABILITY, { diff --git a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp b/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp index 4eb871901..385102a48 100644 --- a/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp +++ b/mm/2s2h/Enhancements/Cheats/UnrestrictedItems.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterUnrestrictedItems() { REGISTER_VB_SHOULD(VB_ITEM_BE_RESTRICTED, { diff --git a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp b/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp index 203b5d6a4..e7ba6cce4 100644 --- a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterHideTitleCards() { REGISTER_VB_SHOULD(VB_SHOW_TITLE_CARD, { diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp index 5317a27a0..37de2200f 100644 --- a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp index 467c2fee1..9b11baa44 100644 --- a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp index 062fdf073..f753865f3 100644 --- a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define ELFMSG3_GET_SWITCH_FLAG(thisx) (((thisx)->params & 0x7F00) >> 8) diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp index 94e6e1623..f53d37a2f 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterSkipEntranceCutscenes() { REGISTER_VB_SHOULD(VB_PLAY_ENTRANCE_CS, { diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp index fb396c05a..031639236 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp index 1b1e4e029..3904a6572 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipToFileSelect.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp index f6259713a..277235afa 100644 --- a/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp index c0c23d8e7..d10a04348 100644 --- a/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp +++ b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp index c9f72647d..879fafc75 100644 --- a/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp +++ b/mm/2s2h/Enhancements/Dialogue/FastBankSelection.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp index eabbb7662..5ed46406c 100644 --- a/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp +++ b/mm/2s2h/Enhancements/Equipment/InstantRecall.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "src/overlays/actors/ovl_En_Boom/z_en_boom.h" diff --git a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp index 52c0f1064..e5e68cfc2 100644 --- a/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp +++ b/mm/2s2h/Enhancements/Equipment/SkipMagicArrowEquip.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp index a84dcd55f..e359d76a5 100644 --- a/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp +++ b/mm/2s2h/Enhancements/Fixes/FierceDeityZTargetMovement.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "variables.h" diff --git a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp index acf93cda9..e5b4de102 100644 --- a/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DItemDrops.cpp @@ -1,5 +1,5 @@ #include "libultraship/libultraship.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp index 04fa1efc7..ba5abb48e 100644 --- a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp @@ -1,6 +1,6 @@ #include #include "2s2h/BenGui/HudEditor.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/Enhancements.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #include "misc/title_static/title_static.h" diff --git a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp index c14532842..67eb5cf7a 100644 --- a/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp +++ b/mm/2s2h/Enhancements/Graphics/DisableBlackBars.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterDisableBlackBars() { REGISTER_VB_SHOULD(VB_DISABLE_LETTERBOX, { diff --git a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp b/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp index a00159c16..a07a50fa0 100644 --- a/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp +++ b/mm/2s2h/Enhancements/Graphics/PlayAsKafei.cpp @@ -1,5 +1,5 @@ #include "libultraship/libultraship.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp b/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp index 4b8058cdc..517d2b7f2 100644 --- a/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/TextBasedClock.cpp @@ -1,6 +1,6 @@ #include #include "2s2h/BenGui/HudEditor.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/Enhancements.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" diff --git a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp index ee8a87a83..74c2a0337 100644 --- a/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp +++ b/mm/2s2h/Enhancements/Masks/BlastMaskKeg.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" static uint32_t bombType; diff --git a/mm/2s2h/Enhancements/Masks/FastTransformation.cpp b/mm/2s2h/Enhancements/Masks/FastTransformation.cpp index ac9ccc633..0e970a841 100644 --- a/mm/2s2h/Enhancements/Masks/FastTransformation.cpp +++ b/mm/2s2h/Enhancements/Masks/FastTransformation.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp b/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp index 7eaff3775..f779e04ff 100644 --- a/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp +++ b/mm/2s2h/Enhancements/Masks/FierceDeityAnywhere.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterFierceDeityAnywhere() { REGISTER_VB_SHOULD(VB_DISABLE_FD_MASK, { diff --git a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp b/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp index 59a138b16..45a967a48 100644 --- a/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp +++ b/mm/2s2h/Enhancements/Masks/NoBlastMaskCooldown.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterNoBlastMaskCooldown() { REGISTER_VB_SHOULD(VB_SET_BLAST_MASK_COOLDOWN_TIMER, { diff --git a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp index 317f37789..5e6704475 100644 --- a/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp +++ b/mm/2s2h/Enhancements/Masks/PersistentMasks.cpp @@ -1,7 +1,7 @@ #include #include -#include "Enhancements/GameInteractor/GameInteractor.h" -#include "Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" extern "C" { #include "z64.h" diff --git a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp b/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp index d20fbcda2..9f7ed23ad 100644 --- a/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp +++ b/mm/2s2h/Enhancements/Minigames/AlwaysWinDoggyRace.cpp @@ -1,6 +1,6 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" -#include "Enhancements/Enhancements.h" +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Enhancements.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp index 0ed98c051..98ec35ecd 100644 --- a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp +++ b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp @@ -1,5 +1,5 @@ #include "libultraship/libultraship.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "macros.h" diff --git a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp index 66994cfdb..65ee403c8 100644 --- a/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp +++ b/mm/2s2h/Enhancements/Player/ClimbSpeed.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterClimbSpeed() { REGISTER_VB_SHOULD(VB_SET_CLIMB_SPEED, { diff --git a/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp index 07bac7321..9d9e8d042 100644 --- a/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp +++ b/mm/2s2h/Enhancements/Player/FastFlowerLaunch.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "macros.h" diff --git a/mm/2s2h/Enhancements/Player/InstantPutaway.cpp b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp index 8fb05a893..2afd233a9 100644 --- a/mm/2s2h/Enhancements/Player/InstantPutaway.cpp +++ b/mm/2s2h/Enhancements/Player/InstantPutaway.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterInstantPutaway() { REGISTER_VB_SHOULD(VB_RESET_PUTAWAY_TIMER, { diff --git a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp b/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp index 465002902..08669ccdc 100644 --- a/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp +++ b/mm/2s2h/Enhancements/Restorations/FlipHopVariable.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterVariableFlipHop() { REGISTER_VB_SHOULD(VB_FLIP_HOP_VARIABLE, { diff --git a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp b/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp index 81d951737..60e8ed006 100644 --- a/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp +++ b/mm/2s2h/Enhancements/Restorations/PowerCrouchStab.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterPowerCrouchStab() { REGISTER_VB_SHOULD(VB_PATCH_POWER_CROUCH_STAB, { diff --git a/mm/2s2h/Enhancements/Restorations/SideRoll.cpp b/mm/2s2h/Enhancements/Restorations/SideRoll.cpp index 6de0241d6..1e71f228b 100644 --- a/mm/2s2h/Enhancements/Restorations/SideRoll.cpp +++ b/mm/2s2h/Enhancements/Restorations/SideRoll.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterSideRoll() { REGISTER_VB_SHOULD(VB_PATCH_SIDEROLL, { diff --git a/mm/2s2h/Enhancements/Restorations/TatlISG.cpp b/mm/2s2h/Enhancements/Restorations/TatlISG.cpp index 07e091df2..2b19fe0e8 100644 --- a/mm/2s2h/Enhancements/Restorations/TatlISG.cpp +++ b/mm/2s2h/Enhancements/Restorations/TatlISG.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void RegisterTatlISG() { REGISTER_VB_SHOULD(VB_TATL_CONVERSATION_AVAILABLE, { diff --git a/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp index ce1d6f774..b65df0c45 100644 --- a/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp +++ b/mm/2s2h/Enhancements/Restorations/WoodfallMountainAppearance.cpp @@ -1,6 +1,6 @@ #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "z64save.h" diff --git a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp index 5bc1328a9..22fa326f7 100644 --- a/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp +++ b/mm/2s2h/Enhancements/Saving/SavingEnhancements.cpp @@ -1,6 +1,6 @@ #include #include "BenPort.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp index 6e50bdfd8..8165b1f21 100644 --- a/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp +++ b/mm/2s2h/Enhancements/Songs/EnableSunsSong.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include diff --git a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp index f1c7ea2ca..841556565 100644 --- a/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp +++ b/mm/2s2h/Enhancements/Songs/PauseOwlWarp.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" diff --git a/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp index f15354bfe..92adaaa5d 100644 --- a/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp +++ b/mm/2s2h/Enhancements/Songs/ZoraEggCount.cpp @@ -1,5 +1,5 @@ #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "src/overlays/actors/ovl_En_Mk/z_en_mk.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/GameInteractor/GameInteractor.cpp similarity index 100% rename from mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp rename to mm/2s2h/GameInteractor/GameInteractor.cpp diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h similarity index 100% rename from mm/2s2h/Enhancements/GameInteractor/GameInteractor.h rename to mm/2s2h/GameInteractor/GameInteractor.h diff --git a/mm/2s2h/Enhancements/NameTag/NameTag.cpp b/mm/2s2h/NameTag/NameTag.cpp similarity index 99% rename from mm/2s2h/Enhancements/NameTag/NameTag.cpp rename to mm/2s2h/NameTag/NameTag.cpp index 19432377b..211883bcf 100644 --- a/mm/2s2h/Enhancements/NameTag/NameTag.cpp +++ b/mm/2s2h/NameTag/NameTag.cpp @@ -3,7 +3,7 @@ #include #include #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/ShipUtils.h" extern "C" { diff --git a/mm/2s2h/Enhancements/NameTag/NameTag.h b/mm/2s2h/NameTag/NameTag.h similarity index 100% rename from mm/2s2h/Enhancements/NameTag/NameTag.h rename to mm/2s2h/NameTag/NameTag.h diff --git a/mm/2s2h/z_play_2SH.cpp b/mm/2s2h/z_play_2SH.cpp index 7cafb1ac5..e446f19c7 100644 --- a/mm/2s2h/z_play_2SH.cpp +++ b/mm/2s2h/z_play_2SH.cpp @@ -3,7 +3,7 @@ #include "2s2h/resource/type/Scene.h" #include #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" extern "C" { #include "global.h" diff --git a/mm/2s2h/z_scene_2SH.cpp b/mm/2s2h/z_scene_2SH.cpp index 61ee7ed0d..a47055ae5 100644 --- a/mm/2s2h/z_scene_2SH.cpp +++ b/mm/2s2h/z_scene_2SH.cpp @@ -6,7 +6,7 @@ #include #include #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/resource/type/Scene.h" #include "2s2h/resource/type/CollisionHeader.h" #include "2s2h/resource/type/Cutscene.h" diff --git a/mm/src/audio/code_8019AF00.c b/mm/src/audio/code_8019AF00.c index 3600f8c81..dbe3e12e4 100644 --- a/mm/src/audio/code_8019AF00.c +++ b/mm/src/audio/code_8019AF00.c @@ -1,6 +1,6 @@ #include "global.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" typedef struct { /* 0x0 */ s8 x; diff --git a/mm/src/code/game.c b/mm/src/code/game.c index 7fb04a125..a4dc6d8cc 100644 --- a/mm/src/code/game.c +++ b/mm/src/code/game.c @@ -13,7 +13,7 @@ #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include "debug.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" s32 gFramerateDivisor = 1; f32 gFramerateDivisorF = 1.0f; diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index ac9add966..b01225633 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -22,7 +22,7 @@ #include #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/BenPort.h" // bss diff --git a/mm/src/code/z_camera.c b/mm/src/code/z_camera.c index 7b02ea02a..ee1ea70c9 100644 --- a/mm/src/code/z_camera.c +++ b/mm/src/code/z_camera.c @@ -63,7 +63,7 @@ Vec3f D_801EDDD0; Vec3f D_801EDDE0; Vec3f D_801EDDF0; #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/Camera/Camera.h" // Camera will reload its paramData. Usually that means setting the read-only data from what is stored in diff --git a/mm/src/code/z_demo.c b/mm/src/code/z_demo.c index e9a24432a..3d34959c0 100644 --- a/mm/src/code/z_demo.c +++ b/mm/src/code/z_demo.c @@ -8,7 +8,7 @@ #include "overlays/gamestates/ovl_daytelop/z_daytelop.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" #include -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" s16 sCutsceneQuakeIndex; struct CutsceneCamera sCutsceneCameraInfo; diff --git a/mm/src/code/z_lib.c b/mm/src/code/z_lib.c index 5ca4d4f7a..39407d07f 100644 --- a/mm/src/code/z_lib.c +++ b/mm/src/code/z_lib.c @@ -1,7 +1,7 @@ #include "global.h" #include #include "BenPort.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c index 48d29c4d6..7f0c82be5 100644 --- a/mm/src/code/z_message.c +++ b/mm/src/code/z_message.c @@ -6,7 +6,7 @@ #include "interface/parameter_static/parameter_static.h" #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include "BenPort.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "assets/archives/schedule_dma_static/schedule_dma_static_yar.h" #include "assets/archives/icon_item_static/icon_item_static_yar.h" #include "assets/archives/icon_item_24_static/icon_item_24_static_yar.h" diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index 2e3734a7e..66bb29055 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -20,7 +20,7 @@ #include #include "BenGui/HudEditor.h" #include "2s2h_assets.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" // 2S2H [Port] This was originally static but needs to be global so it can be accessed in z_kaleido_collect, // z_kaleido_debug, and z_kaleido_draw. diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index 56f132219..deab776c1 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -35,7 +35,7 @@ u8 sMotionBlurStatus; #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include "debug.h" #include "BenPort.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #include "2s2h/Enhancements/Graphics/Graphics.h" #include "2s2h/DeveloperTools/CollisionViewer.h" diff --git a/mm/src/code/z_player_lib.c b/mm/src/code/z_player_lib.c index e90fda727..9f624b93d 100644 --- a/mm/src/code/z_player_lib.c +++ b/mm/src/code/z_player_lib.c @@ -45,7 +45,7 @@ #include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" #include "2s2h/BenPort.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void PlayerCall_Init(Actor* thisx, PlayState* play); void PlayerCall_Destroy(Actor* thisx, PlayState* play); diff --git a/mm/src/code/z_shrink_window.c b/mm/src/code/z_shrink_window.c index 2e36948db..c4aa3ac86 100644 --- a/mm/src/code/z_shrink_window.c +++ b/mm/src/code/z_shrink_window.c @@ -7,7 +7,7 @@ #include "global.h" #include "z64shrink_window.h" #include -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "BenPort.h" diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index ed6212a8f..47592e63c 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -5,7 +5,7 @@ #include #include "BenPort.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages); void func_80147414(SramContext* sramCtx, s32 fileNum, s32 arg2); diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 1b1e35214..23bba491d 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -2,7 +2,7 @@ #include "z64shrink_window.h" #include "z64view.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" s32 View_ApplyPerspective(View* view); s32 View_ApplyOrtho(View* view); diff --git a/mm/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c b/mm/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c index 686e9572b..4e906615a 100644 --- a/mm/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c +++ b/mm/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c @@ -7,7 +7,7 @@ #include "z_arms_hook.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_link_child/object_link_child.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) diff --git a/mm/src/overlays/actors/ovl_Boss_02/z_boss_02.c b/mm/src/overlays/actors/ovl_Boss_02/z_boss_02.c index 2fe43d749..716c83c4a 100644 --- a/mm/src/overlays/actors/ovl_Boss_02/z_boss_02.c +++ b/mm/src/overlays/actors/ovl_Boss_02/z_boss_02.c @@ -12,7 +12,7 @@ #include "overlays/actors/ovl_Item_B_Heart/z_item_b_heart.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_20) diff --git a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c index 8a25910eb..adee27afa 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c @@ -6,7 +6,7 @@ #include "z_elf_msg3.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c index c77db2dbf..8d9aacb2e 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c @@ -6,7 +6,7 @@ #include "z_elf_msg6.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c b/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c index 7ea427bd0..411a4a98b 100644 --- a/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c +++ b/mm/src/overlays/actors/ovl_En_Fsn/z_en_fsn.c @@ -6,7 +6,7 @@ #include "z_en_fsn.h" #include "objects/gameplay_keep/gameplay_keep.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c index a6e7fec72..9d38823ac 100644 --- a/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c +++ b/mm/src/overlays/actors/ovl_En_Horse/z_en_horse.c @@ -12,7 +12,7 @@ #include "overlays/actors/ovl_Obj_Um/z_obj_um.h" #include "overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.h" #include "objects/object_horse_link_child/object_horse_link_child.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Ja/z_en_ja.c b/mm/src/overlays/actors/ovl_En_Ja/z_en_ja.c index e48572bd8..002cea076 100644 --- a/mm/src/overlays/actors/ovl_En_Ja/z_en_ja.c +++ b/mm/src/overlays/actors/ovl_En_Ja/z_en_ja.c @@ -5,7 +5,7 @@ */ #include "z_en_ja.h" -#include "Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c b/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c index 3e15732da..bcc0529d0 100644 --- a/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c +++ b/mm/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c @@ -6,7 +6,7 @@ #include "z_en_ossan.h" #include "objects/gameplay_keep/gameplay_keep.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c index 4a3d1c5d9..17e77c5e6 100644 --- a/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c +++ b/mm/src/overlays/actors/ovl_En_Racedog/z_en_racedog.c @@ -12,7 +12,7 @@ #include "overlays/actors/ovl_En_Aob_01/z_en_aob_01.h" #include "overlays/actors/ovl_En_Dg/z_en_dg.h" -#include "Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_80000000) diff --git a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c index 76ac1efd6..1dccb5eb2 100644 --- a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c +++ b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c @@ -7,7 +7,7 @@ #include "z_en_slime.h" #include "overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_200) diff --git a/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c b/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c index 13c1eb329..60fd05a4c 100644 --- a/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c +++ b/mm/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c @@ -8,7 +8,7 @@ #include "objects/object_mastergolon/object_mastergolon.h" #include "objects/object_masterzoora/object_masterzoora.h" #include "objects/gameplay_keep/gameplay_keep.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10) diff --git a/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c b/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c index a8c11c517..5ed9acc31 100644 --- a/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c +++ b/mm/src/overlays/actors/ovl_En_Test4/z_en_test4.c @@ -8,7 +8,7 @@ #include "z64horse.h" #include "overlays/gamestates/ovl_daytelop/z_daytelop.h" #include "overlays/actors/ovl_En_Horse/z_en_horse.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20 | ACTOR_FLAG_100000) diff --git a/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c b/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c index 40eda53bf..db8401dd6 100644 --- a/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c +++ b/mm/src/overlays/actors/ovl_En_Trt/z_en_trt.c @@ -7,7 +7,7 @@ #include "z_en_trt.h" #include "objects/object_trt/object_trt.h" #include "objects/gameplay_keep/gameplay_keep.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY) diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 3ce8993dc..397dfdd0c 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -45,7 +45,7 @@ #include "objects/object_link_nuts/object_link_nuts.h" #include "objects/object_link_child/object_link_child.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define THIS ((Player*)thisx) diff --git a/mm/src/overlays/gamestates/ovl_title/z_title.c b/mm/src/overlays/gamestates/ovl_title/z_title.c index dfc1c3160..0a1642812 100644 --- a/mm/src/overlays/gamestates/ovl_title/z_title.c +++ b/mm/src/overlays/gamestates/ovl_title/z_title.c @@ -13,7 +13,7 @@ #include "build.h" #include "BenPort.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include #define dgShipLogoDL "__OTR__misc/nintendo_rogo_static/gShipLogoDL" diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c index 5e91c8e7e..2441c27bf 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c @@ -8,7 +8,7 @@ #include "interface/parameter_static/parameter_static.h" #include "BenGui/HudEditor.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" s16 sEquipState = EQUIP_STATE_MAGIC_ARROW_GROW_ORB; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c index 140ba179a..b6ebdcbbd 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c @@ -8,7 +8,7 @@ #include "interface/parameter_static/parameter_static.h" #include "BenGui/HudEditor.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" s16 sMaskEquipState = EQUIP_STATE_MAGIC_ARROW_GROW_ORB; diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c index 2b7c35156..078491f2a 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c @@ -22,7 +22,7 @@ #include "2s2h_assets.h" -#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" +#include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/Enhancements/Songs/Songs.h" From 69edc89292dc89e8dacf830b501869f0282efcad Mon Sep 17 00:00:00 2001 From: Archez Date: Sat, 5 Oct 2024 12:54:00 -0400 Subject: [PATCH 57/82] [Enhancement] Keep Express Mail in the same cycle (#791) * Add enhancement for reusing letter to mama in one cycle * add menu widget item for express mail --- mm/2s2h/BenGui/BenMenuBar.cpp | 7 +++ mm/2s2h/BenGui/SearchableMenuItems.h | 11 ++++ mm/2s2h/Enhancements/Cycle/Cycle.h | 1 + .../Enhancements/Cycle/KeepExpressMail.cpp | 55 +++++++++++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 1 + mm/src/code/z_msgevent.c | 6 ++ 7 files changed, 82 insertions(+) create mode 100644 mm/2s2h/Enhancements/Cycle/KeepExpressMail.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index e8f7d7352..081d13955 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -476,6 +476,13 @@ void DrawEnhancementsMenu() { { .tooltip = "Playing the Song Of Time will not reset the current time speed set by Inverted Song of Time." }); + if (UIWidgets::CVarCheckbox( + "Keep Express Mail", "gEnhancements.Cycle.KeepExpressMail", + { .tooltip = "Allows the player to keep the Express Mail in their inventory after delivering it " + "the first time, so that both deliveries can be done within one cycle" })) { + RegisterKeepExpressMail(); + } + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 0, 255)); ImGui::SeparatorText("Unstable"); ImGui::PopStyleColor(); diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 95785d296..e4279230e 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -930,6 +930,17 @@ void AddEnhancements() { "Playing the Song Of Time will not reset the Sword back to Kokiri Sword.", WIDGET_CVAR_CHECKBOX }, { "Do not reset Rupees", "gEnhancements.Cycle.DoNotResetRupees", "Playing the Song Of Time will not reset the your rupees.", WIDGET_CVAR_CHECKBOX }, + { "Do not reset Time Speed", "gEnhancements.Cycle.DoNotResetTimeSpeed", + "Playing the Song Of Time will not reset the current time speed set by Inverted Song of Time.", + WIDGET_CVAR_CHECKBOX }, + { + .widgetName = "Keep Express Mail", + .widgetCVar = "gEnhancements.Cycle.KeepExpressMail", + .widgetTooltip = "Allows the player to keep the Express Mail in their inventory after delivering it " + "the first time, so that both deliveries can be done within one cycle", + .widgetType = WIDGET_CVAR_CHECKBOX, + .widgetCallback = [](widgetInfo& info) { RegisterKeepExpressMail(); }, + }, { .widgetName = "Unstable", .widgetType = WIDGET_SEPARATOR_TEXT, .widgetOptions = { .color = UIWidgets::Colors::Yellow } }, diff --git a/mm/2s2h/Enhancements/Cycle/Cycle.h b/mm/2s2h/Enhancements/Cycle/Cycle.h index 612ff1991..9c8812743 100644 --- a/mm/2s2h/Enhancements/Cycle/Cycle.h +++ b/mm/2s2h/Enhancements/Cycle/Cycle.h @@ -2,5 +2,6 @@ #define CYCLE_H void RegisterEndOfCycleSaveHooks(); +void RegisterKeepExpressMail(); #endif // CYCLE_H diff --git a/mm/2s2h/Enhancements/Cycle/KeepExpressMail.cpp b/mm/2s2h/Enhancements/Cycle/KeepExpressMail.cpp new file mode 100644 index 000000000..196082d86 --- /dev/null +++ b/mm/2s2h/Enhancements/Cycle/KeepExpressMail.cpp @@ -0,0 +1,55 @@ +#include "libultraship/bridge.h" +#include "2s2h/GameInteractor/GameInteractor.h" + +extern "C" { +#include "z64save.h" +#include "z64scene.h" +#include "variables.h" +} + +static HOOK_ID onItemDeleteID = 0; + +void CheckScene(s16 sceneId) { + if (sceneId != SCENE_MILK_BAR && sceneId != SCENE_POSTHOUSE) { + return; + } + + onItemDeleteID = REGISTER_VB_SHOULD(VB_MSG_SCRIPT_DEL_ITEM, { + Actor* actor = va_arg(args, Actor*); + ItemId itemId = va_arg(args, ItemId); + + // Keep the express mail only on the first trade for the cycle + // Postman checking for Madame Aroma trade cycle flag + // Madame Aroma checking for Postman trade cycle flag + if (itemId == ITEM_LETTER_MAMA && (actor->id == ACTOR_EN_PM && !CHECK_WEEKEVENTREG(WEEKEVENTREG_57_04)) || + (actor->id == ACTOR_EN_AL && !CHECK_WEEKEVENTREG(WEEKEVENTREG_86_01))) { + *should = false; + } + }); +} + +void RegisterKeepExpressMail() { + static HOOK_ID onSceneInitID = 0; + + GameInteractor::Instance->UnregisterGameHookForID(onItemDeleteID); + GameInteractor::Instance->UnregisterGameHook(onSceneInitID); + onSceneInitID = 0; + onItemDeleteID = 0; + + if (!CVarGetInteger("gEnhancements.Cycle.KeepExpressMail", 0)) { + return; + } + + // Register item hook right away after toggle + if (gPlayState != nullptr) { + CheckScene(gPlayState->sceneId); + } + + onSceneInitID = + GameInteractor::Instance->RegisterGameHook([](s16 sceneId, s8 spawnNum) { + GameInteractor::Instance->UnregisterGameHookForID(onItemDeleteID); + onItemDeleteID = 0; + + CheckScene(sceneId); + }); +} diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 0e014d318..f7f1a4a1a 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -22,6 +22,7 @@ void InitEnhancements() { RegisterEndOfCycleSaveHooks(); RegisterSavingEnhancements(); RegisterAutosave(); + RegisterKeepExpressMail(); // Dialogue RegisterFastBankSelection(); diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index d73e763ae..e3f79ecb6 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -48,6 +48,7 @@ typedef enum { VB_SONG_AVAILABLE_TO_PLAY, VB_USE_CUSTOM_CAMERA, VB_DELETE_OWL_SAVE, + VB_MSG_SCRIPT_DEL_ITEM, VB_CONSIDER_BUNNY_HOOD_EQUIPPED, VB_USE_ITEM_EQUIP_MASK, VB_KALEIDO_DISPLAY_ITEM_TEXT, diff --git a/mm/src/code/z_msgevent.c b/mm/src/code/z_msgevent.c index 469d46c77..9e8d4cb08 100644 --- a/mm/src/code/z_msgevent.c +++ b/mm/src/code/z_msgevent.c @@ -1,5 +1,7 @@ #include "global.h" +#include "2s2h/GameInteractor/GameInteractor.h" + #define MSCRIPT_CONTINUE 0 #define MSCRIPT_STOP 1 @@ -876,6 +878,10 @@ s32 MsgEvent_Cmd42(Actor* actor, PlayState* play, u8** scriptPtr, MsgEventCallba u8* script = *scriptPtr; s16 item = MSCRIPT_GET_16(script, 1); + if (!GameInteractor_Should(VB_MSG_SCRIPT_DEL_ITEM, true, actor, item)) { + return MSCRIPT_CONTINUE; + } + Inventory_DeleteItem(item, SLOT(item)); return MSCRIPT_CONTINUE; } From da793a5bf2c8cbdcb6adcf904068b17d53260fb7 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 5 Oct 2024 09:54:23 -0700 Subject: [PATCH 58/82] Fix Sidebar Search (#796) * Ensures the sidebar search gets added if on at boot. Searches the sidebar entries to find an entry with a label that matches the searchSidebarEntry label to delete when disabling sidebar search, just in case something goes wrong and it's not actually where it's supposed to be (sidebarSearchIndex). * ... clang... --- mm/2s2h/BenGui/SearchableMenuItems.h | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index e4279230e..682b1fd1e 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -403,6 +403,12 @@ void FreeLookPitchMinMax() { CVarSetFloat("gEnhancements.Camera.FreeLook.MinPitch", std::min(maxY, minY)); } +void InsertSidebarSearch() { + menuEntries[0].sidebarEntries.insert(menuEntries[0].sidebarEntries.begin() + searchSidebarIndex, + searchSidebarEntry); + CVarSetInteger(menuEntries[0].sidebarCvar, CVarGetInteger(menuEntries[0].sidebarCvar, 0) + 1); +} + void AddSettings() { // General Settings settingsSidebar.push_back( @@ -447,12 +453,18 @@ void AddSettings() { {}, [](widgetInfo& info) { if (CVarGetInteger("gSettings.SidebarSearch", 0)) { - menuEntries[0].sidebarEntries.insert(menuEntries[0].sidebarEntries.begin() + searchSidebarIndex, - searchSidebarEntry); - CVarSetInteger(menuEntries[0].sidebarCvar, CVarGetInteger(menuEntries[0].sidebarCvar, 0) + 1); + InsertSidebarSearch(); } else { - menuEntries[0].sidebarEntries.erase(menuEntries[0].sidebarEntries.begin() + searchSidebarIndex); - CVarSetInteger(menuEntries[0].sidebarCvar, CVarGetInteger(menuEntries[0].sidebarCvar, 0) - 1); + std::erase_if(menuEntries[0].sidebarEntries, [](SidebarEntry entry) { + return strncmp(entry.label.c_str(), searchSidebarEntry.label.c_str(), 5) == 0; + }); + int32_t sidebarVal = CVarGetInteger(menuEntries[0].sidebarCvar, 0); + if (sidebarVal < menuEntries.size()) { + sidebarVal -= 1; + } else { + sidebarVal = menuEntries.size() - 1; + } + CVarSetInteger(menuEntries[0].sidebarCvar, sidebarVal); } } }, { "Search Input Autofocus", "gSettings.SearchAutofocus", @@ -679,6 +691,10 @@ void AddSettings() { "Enables the separate Input Editor window.", WIDGET_WINDOW_BUTTON, { .size = UIWidgets::Sizes::Inline, .windowName = "2S2H Input Editor" } } } } }); + + if (CVarGetInteger("gSettings.SidebarSearch", 0)) { + settingsSidebar.insert(settingsSidebar.begin() + searchSidebarIndex, searchSidebarEntry); + } } int32_t motionBlurStrength; From 790d36bfbcf2135bcdcf5ed3c8ac5d18aa973983 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 6 Oct 2024 20:55:16 -0500 Subject: [PATCH 59/82] Add options for first person aiming (#596) --- mm/2s2h/BenGui/BenMenuBar.cpp | 44 ++++++ mm/2s2h/BenGui/SearchableMenuItems.h | 132 +++++++++++++++++- mm/2s2h/GameInteractor/GameInteractor.cpp | 35 ++++- mm/2s2h/GameInteractor/GameInteractor.h | 8 +- .../actors/ovl_player_actor/z_player.c | 115 +++++++++++++++ 5 files changed, 326 insertions(+), 8 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 081d13955..54a1fe6aa 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -348,6 +348,50 @@ void DrawEnhancementsMenu() { { .tooltip = "Fixes the camera snap that occurs when you are moving and press the targetting button." }); + ImGui::SeparatorText("First Person"); + UIWidgets::CVarCheckbox("Disable Auto-Centering", + "gEnhancements.Camera.FirstPerson.DisableFirstPersonAutoCenterView"); + UIWidgets::CVarCheckbox("Invert X Axis", "gEnhancements.Camera.FirstPerson.InvertX"); + UIWidgets::CVarCheckbox("Invert Y Axis", "gEnhancements.Camera.FirstPerson.InvertY", + { .defaultValue = true }); + UIWidgets::CVarSliderFloat("X Axis Sensitivity: %.0f%%", "gEnhancements.Camera.FirstPerson.SensitivityX", + 0.1f, 2.0f, 1.0f, { .isPercentage = true }); + UIWidgets::CVarSliderFloat("Y Axis Sensitivity: %.0f%%", "gEnhancements.Camera.FirstPerson.SensitivityY", + 0.1f, 2.0f, 1.0f, { .isPercentage = true }); + UIWidgets::CVarCheckbox( + "Gyro Aiming", "gEnhancements.Camera.FirstPerson.GyroEnabled", + { .tooltip = "Enables gyro aiming in first person mode. Requires a controller with gyro support, and " + "for it to be mapped in the Controller Mapping menu" }); + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0)) { + UIWidgets::CVarCheckbox("Invert Gyro X Axis", "gEnhancements.Camera.FirstPerson.GyroInvertX"); + UIWidgets::CVarCheckbox("Invert Gyro Y Axis", "gEnhancements.Camera.FirstPerson.GyroInvertY"); + UIWidgets::CVarSliderFloat("Gyro X Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.GyroSensitivityX", 0.1f, 2.0f, 1.0f, + { .isPercentage = true }); + UIWidgets::CVarSliderFloat("Gyro Y Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.GyroSensitivityY", 0.1f, 2.0f, 1.0f, + { .isPercentage = true }); + } + + UIWidgets::CVarCheckbox( + "Right Stick Aiming", "gEnhancements.Camera.FirstPerson.RightStickEnabled", + { .tooltip = "Enables right stick aiming in first person mode. Requires the controller right stick to " + "be mapped in the Controller Mapping menu" }); + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickEnabled", 0)) { + UIWidgets::CVarCheckbox("Move with left stick while in first person", + "gEnhancements.Camera.FirstPerson.MoveInFirstPerson"); + UIWidgets::CVarCheckbox("Invert Right Stick X Axis", + "gEnhancements.Camera.FirstPerson.RightStickInvertX"); + UIWidgets::CVarCheckbox("Invert Right Stick Y Axis", + "gEnhancements.Camera.FirstPerson.RightStickInvertY", { .defaultValue = true }); + UIWidgets::CVarSliderFloat("Right Stick X Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.RightStickSensitivityX", 0.1f, 2.0f, 1.0f, + { .isPercentage = true }); + UIWidgets::CVarSliderFloat("Right Stick Y Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.RightStickSensitivityY", 0.1f, 2.0f, 1.0f, + { .isPercentage = true }); + } + ImGui::SeparatorText("Free Look"); if (UIWidgets::CVarCheckbox( "Free Look", "gEnhancements.Camera.FreeLook.Enable", diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 682b1fd1e..ab6768809 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -31,6 +31,9 @@ typedef enum { DISABLE_FOR_DEBUG_CAM_OFF, DISABLE_FOR_FREE_LOOK_ON, DISABLE_FOR_FREE_LOOK_OFF, + DISABLE_FOR_GYRO_OFF, + DISABLE_FOR_GYRO_ON, + DISABLE_FOR_RIGHT_STICK_OFF, DISABLE_FOR_AUTO_SAVE_OFF, DISABLE_FOR_NULL_PLAY_STATE, DISABLE_FOR_DEBUG_MODE_OFF, @@ -278,6 +281,17 @@ static std::map disabledMap = { { DISABLE_FOR_FREE_LOOK_OFF, { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0); }, "Free Look is Disabled" } }, + { DISABLE_FOR_GYRO_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0); }, + "Gyro Aiming is Disabled" } }, + { DISABLE_FOR_GYRO_ON, + { [](disabledInfo& info) -> bool { return CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0); }, + "Gyro Aiming is Enabled" } }, + { DISABLE_FOR_RIGHT_STICK_OFF, + { [](disabledInfo& info) -> bool { + return !CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickEnabled", 0); + }, + "Right Stick Aiming is Disabled" } }, { DISABLE_FOR_AUTO_SAVE_OFF, { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Saving.Autosave", 0); }, "AutoSave is Disabled" } }, @@ -703,12 +717,118 @@ void AddEnhancements() { enhancementsSidebar.push_back( { "Camera", 3, - { { { .widgetName = "Fixes", .widgetType = WIDGET_SEPARATOR_TEXT }, - { "Fix Targetting Camera Snap", - "gEnhancements.Camera.FixTargettingCameraSnap", - "Fixes the camera snap that occurs when you are moving and press the targetting button.", - WIDGET_CVAR_CHECKBOX, - {} } }, + { { + { .widgetName = "Fixes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Fix Targetting Camera Snap", + "gEnhancements.Camera.FixTargettingCameraSnap", + "Fixes the camera snap that occurs when you are moving and press the targetting button.", + WIDGET_CVAR_CHECKBOX, + {} }, + { .widgetName = "First Person", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Disable Auto-Centering", + "gEnhancements.Camera.FirstPerson.DisableFirstPersonAutoCenterView", + "Disables the auto-centering of the camera in first person mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_GYRO_ON).active) + info.activeDisables.push_back(DISABLE_FOR_GYRO_ON); + } }, + { "Invert X Axis", "gEnhancements.Camera.FirstPerson.InvertX", + "Inverts the X Axis of the Camera in First Person Mode.", WIDGET_CVAR_CHECKBOX }, + { "Invert Y Axis", + "gEnhancements.Camera.FirstPerson.InvertY", + "Inverts the Y Axis of the Camera in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + { .defaultVariant = true } }, + { "X Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.SensitivityX", + "Adjusts the Sensitivity of the X Axis in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr }, + { "Y Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.SensitivityY", + "Adjusts the Sensitivity of the Y Axis in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr }, + { "Gyro Aiming", + "gEnhancements.Camera.FirstPerson.GyroEnabled", + "Enables Gyro Aiming in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr }, + { "Invert Gyro X Axis", + "gEnhancements.Camera.FirstPerson.GyroInvertX", + "Inverts the X Axis of the Gyro in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_GYRO_OFF).active; } }, + { "Invert Gyro Y Axis", + "gEnhancements.Camera.FirstPerson.GyroInvertY", + "Inverts the Y Axis of the Gyro in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_GYRO_OFF).active; } }, + { "Gyro X Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.GyroSensitivityX", + "Adjusts the Sensitivity of the X Axis of the Gyro in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_GYRO_OFF).active; } }, + { "Gyro Y Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.GyroSensitivityY", + "Adjusts the Sensitivity of the Y Axis of the Gyro in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_GYRO_OFF).active; } }, + { "Right Stick Aiming", "gEnhancements.Camera.FirstPerson.RightStickEnabled", + "Enables Right Stick Aiming in First Person Mode.", WIDGET_CVAR_CHECKBOX }, + { "Move while aiming", + "gEnhancements.Camera.FirstPerson.MoveInFirstPerson", + "Allows movement with the left stick while in first person mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { + if (disabledMap.at(DISABLE_FOR_RIGHT_STICK_OFF).active) + info.activeDisables.push_back(DISABLE_FOR_RIGHT_STICK_OFF); + } }, + { "Invert Right Stick X Axis", + "gEnhancements.Camera.FirstPerson.RightStickInvertX", + "Inverts the X Axis of the Right Stick in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_RIGHT_STICK_OFF).active; } }, + { "Invert Right Stick Y Axis", + "gEnhancements.Camera.FirstPerson.RightStickInvertY", + "Inverts the Y Axis of the Right Stick in First Person Mode.", + WIDGET_CVAR_CHECKBOX, + { .defaultVariant = true }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_RIGHT_STICK_OFF).active; } }, + { "Right Stick X Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.RightStickSensitivityX", + "Adjusts the Sensitivity of the X Axis of the Right Stick in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_RIGHT_STICK_OFF).active; } }, + { "Right Stick Y Axis Sensitivity: %.0f%%", + "gEnhancements.Camera.FirstPerson.RightStickSensitivityY", + "Adjusts the Sensitivity of the Y Axis of the Right Stick in First Person Mode.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 10.0f, .max = 200.0f, .defaultVariant = 100.0f, .format = "%.0f%%", .isPercentage = true }, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_RIGHT_STICK_OFF).active; } }, + }, // Camera Enhancements { { .widgetName = "Cameras", .widgetType = WIDGET_SEPARATOR_TEXT }, { "Free Look", diff --git a/mm/2s2h/GameInteractor/GameInteractor.cpp b/mm/2s2h/GameInteractor/GameInteractor.cpp index fbaf19930..78963a3e2 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/GameInteractor/GameInteractor.cpp @@ -266,6 +266,36 @@ int GameInteractor_InvertControl(GIInvertType type) { result *= -1; } break; + case GI_INVERT_FIRST_PERSON_AIM_X: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.InvertX", 0)) { + result *= -1; + } + break; + case GI_INVERT_FIRST_PERSON_AIM_Y: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.InvertY", 1)) { + result *= -1; + } + break; + case GI_INVERT_FIRST_PERSON_GYRO_X: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroInvertX", 0)) { + result *= -1; + } + break; + case GI_INVERT_FIRST_PERSON_GYRO_Y: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroInvertY", 0)) { + result *= -1; + } + break; + case GI_INVERT_FIRST_PERSON_RIGHT_STICK_X: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickInvertX", 0)) { + result *= -1; + } + break; + case GI_INVERT_FIRST_PERSON_RIGHT_STICK_Y: + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickInvertY", 1)) { + result *= -1; + } + break; } // Invert all X axis inputs if the Mirrored World mode is enabled @@ -273,13 +303,16 @@ int GameInteractor_InvertControl(GIInvertType type) { switch (type) { case GI_INVERT_CAMERA_RIGHT_STICK_X: case GI_INVERT_MOVEMENT_X: - case GI_INVERT_FIRST_PERSON_AIM_X: case GI_INVERT_SHIELD_X: case GI_INVERT_SHOP_X: case GI_INVERT_HORSE_X: case GI_INVERT_ZORA_SWIM_X: case GI_INVERT_DEBUG_DPAD_X: case GI_INVERT_TELESCOPE_X: + case GI_INVERT_FIRST_PERSON_AIM_X: + case GI_INVERT_FIRST_PERSON_GYRO_X: + case GI_INVERT_FIRST_PERSON_RIGHT_STICK_X: + case GI_INVERT_FIRST_PERSON_MOVING_X: result *= -1; break; default: diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index e3f79ecb6..20cada536 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -69,13 +69,19 @@ typedef enum { GI_INVERT_CAMERA_RIGHT_STICK_X, GI_INVERT_CAMERA_RIGHT_STICK_Y, GI_INVERT_MOVEMENT_X, - GI_INVERT_FIRST_PERSON_AIM_X, GI_INVERT_SHIELD_X, GI_INVERT_SHOP_X, GI_INVERT_HORSE_X, GI_INVERT_ZORA_SWIM_X, GI_INVERT_DEBUG_DPAD_X, GI_INVERT_TELESCOPE_X, + GI_INVERT_FIRST_PERSON_AIM_X, + GI_INVERT_FIRST_PERSON_AIM_Y, + GI_INVERT_FIRST_PERSON_GYRO_X, + GI_INVERT_FIRST_PERSON_GYRO_Y, + GI_INVERT_FIRST_PERSON_RIGHT_STICK_X, + GI_INVERT_FIRST_PERSON_RIGHT_STICK_Y, + GI_INVERT_FIRST_PERSON_MOVING_X, } GIInvertType; typedef enum { diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 397dfdd0c..e6cb26b9f 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -13004,7 +13004,122 @@ void Player_Destroy(Actor* thisx, PlayState* play) { func_80831454(this); } +s32 Ship_HandleFirstPersonAiming(PlayState* play, Player* this, s32 arg2) { + s16 var_s0; + s32 stickX = 0; + s32 stickY = 0; + float gyroX = 0.0f; + float gyroY = 0.0f; + + if (!CVarGetInteger("gEnhancements.Camera.FirstPerson.MoveInFirstPerson", 0)) { + s32 leftStickX = sPlayerControlInput->rel.stick_x; // -60 to 60 + s32 leftStickY = sPlayerControlInput->rel.stick_y; // -60 to 60 + + leftStickX *= GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_AIM_X); + leftStickY *= -GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_AIM_Y); + + stickX += leftStickX * CVarGetFloat("gEnhancements.Camera.FirstPerson.SensitivityX", 1.0f); + stickY += leftStickY * CVarGetFloat("gEnhancements.Camera.FirstPerson.SensitivityY", 1.0f); + } + + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0)) { + gyroX = sPlayerControlInput->cur.gyro_y * 720; // -40 to 40, avg -4 to 4 + gyroY = sPlayerControlInput->cur.gyro_x * 720; // -20 to 20, avg -2 to 2 + + gyroX *= GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_GYRO_X); + gyroY *= -GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_GYRO_Y); + + gyroX *= CVarGetFloat("gEnhancements.Camera.FirstPerson.GyroSensitivityX", 1.0f); + gyroY *= CVarGetFloat("gEnhancements.Camera.FirstPerson.GyroSensitivityY", 1.0f); + } + + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickEnabled", 0)) { + s32 rightStickX = sPlayerControlInput->cur.right_stick_x; // -40 to 40, avg -4 to 4 + s32 rightStickY = sPlayerControlInput->cur.right_stick_y; // -20 to 20, avg -2 to 2 + + rightStickX *= GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_RIGHT_STICK_X); + rightStickY *= -GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_RIGHT_STICK_Y); + + stickX += rightStickX * CVarGetFloat("gEnhancements.Camera.FirstPerson.RightStickSensitivityX", 1.0f); + stickY += rightStickY * CVarGetFloat("gEnhancements.Camera.FirstPerson.RightStickSensitivityY", 1.0f); + } + + stickX = CLAMP(stickX, -60, 60); + stickY = CLAMP(stickY, -60, 60); + + if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) { // First person without weapon + var_s0 = stickY * 0xF0; + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.DisableFirstPersonAutoCenterView", 0) || + CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0)) { + this->actor.focus.rot.x += var_s0 * 0.1f; + } else { + Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E); + } + this->actor.focus.rot.x += gyroY; + this->actor.focus.rot.x = CLAMP(this->actor.focus.rot.x, -14000, 14000); + + var_s0 = stickX * -0x10; + var_s0 = CLAMP(var_s0, -0xBB8, 0xBB8); + this->actor.focus.rot.y += var_s0 + gyroX; + } else { // First person with weapon + s16 temp3; + + temp3 = ((stickY >= 0) ? 1 : -1) * (s32)((1.0f - Math_CosS(stickY * 0xC8)) * 1500.0f); + this->actor.focus.rot.x += temp3 + gyroY; + + if (this->stateFlags1 & PLAYER_STATE1_800000) { + this->actor.focus.rot.x = CLAMP(this->actor.focus.rot.x, -0x1F40, 0xFA0); + } else { + this->actor.focus.rot.x = CLAMP(this->actor.focus.rot.x, -0x36B0, 0x36B0); + } + + var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y; + temp3 = ((stickX >= 0) ? 1 : -1) * (s32)((1.0f - Math_CosS(stickX * 0xC8)) * -1500.0f); + var_s0 += temp3; + + this->actor.focus.rot.y = CLAMP(var_s0 + gyroX, -0x4AAA, 0x4AAA) + this->actor.shape.rot.y; + } + + if (CVarGetInteger("gEnhancements.Camera.FirstPerson.MoveInFirstPerson", 0) && + CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickEnabled", 0)) { + f32 movementSpeed = 8.25f; // account for form + if (this->currentMask == PLAYER_MASK_BUNNY) { + movementSpeed *= 1.5f; + } + + f32 relX = + (-sPlayerControlInput->rel.stick_x / 10) * GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_MOVING_X); + f32 relY = (sPlayerControlInput->rel.stick_y / 10); + + // Normalize so that diagonal movement isn't faster + f32 relMag = sqrtf((relX * relX) + (relY * relY)); + if (relMag > 1.0f) { + relX /= relMag; + relY /= relMag; + } + + // Determine what left and right mean based on camera angle + f32 relX2 = relX * Math_CosS(this->actor.focus.rot.y) + relY * Math_SinS(this->actor.focus.rot.y); + f32 relY2 = relY * Math_CosS(this->actor.focus.rot.y) - relX * Math_SinS(this->actor.focus.rot.y); + + // Calculate distance for footstep sound + f32 distance = sqrtf((relX2 * relX2) + (relY2 * relY2)) * movementSpeed; + func_8083EA44(this, distance / 4.5f); + + this->actor.world.pos.x += (relX2 * movementSpeed) + this->actor.colChkInfo.displacement.x; + this->actor.world.pos.z += (relY2 * movementSpeed) + this->actor.colChkInfo.displacement.z; + } + + this->unk_AA6 |= 2; + + return func_80832754(this, (play->bButtonAmmoPlusOne != 0) || func_800B7128(this) || func_8082EF20(this)); +} + s32 func_80847190(PlayState* play, Player* this, s32 arg2) { + // #region 2S2H [Enhancements] Use our own heavily modified version of this for customizations + return Ship_HandleFirstPersonAiming(play, this, arg2); + // #endregion + s32 pad; s16 var_s0; s32 stickX = sPlayerControlInput->rel.stick_x; From cd4ee56d4874b694507008696132266cca8a916e Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Mon, 7 Oct 2024 10:25:09 -0500 Subject: [PATCH 60/82] Implement faster song playback enhancement (#801) --- mm/2s2h/BenGui/SearchableMenuItems.h | 8 ++++- mm/2s2h/Enhancements/Enhancements.cpp | 1 + .../Enhancements/Songs/FasterSongPlayback.cpp | 30 +++++++++++++++++++ mm/2s2h/Enhancements/Songs/Songs.h | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/Songs/FasterSongPlayback.cpp diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index ab6768809..2bd672834 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1226,7 +1226,13 @@ void AddEnhancements() { WIDGET_CVAR_SLIDER_INT, { 1, 7, 7 } }, { "Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput", - "Prevent dropping inputs when playing the ocarina quickly.", WIDGET_CVAR_CHECKBOX } } } }); + "Prevent dropping inputs when playing the ocarina quickly.", WIDGET_CVAR_CHECKBOX }, + { "Faster Song Playback", + "gEnhancements.Songs.FasterSongPlayback", + "Speeds up the playback of songs.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterFasterSongPlayback(); } } } } }); enhancementsSidebar.push_back( { "Time Savers", 3, diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index f7f1a4a1a..3afba3157 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -55,6 +55,7 @@ void InitEnhancements() { // Songs RegisterEnableSunsSong(); + RegisterFasterSongPlayback(); RegisterPauseOwlWarp(); RegisterZoraEggCount(); diff --git a/mm/2s2h/Enhancements/Songs/FasterSongPlayback.cpp b/mm/2s2h/Enhancements/Songs/FasterSongPlayback.cpp new file mode 100644 index 000000000..fe4dc02c0 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/FasterSongPlayback.cpp @@ -0,0 +1,30 @@ +#include "2s2h/GameInteractor/GameInteractor.h" +#include "libultraship/libultraship.h" + +extern "C" { +#include "variables.h" + +extern u8 sPlaybackState; +} + +void RegisterFasterSongPlayback() { + static uint32_t onPlayerUpdate = 0; + GameInteractor::Instance->UnregisterGameHookForID(onPlayerUpdate); + + onPlayerUpdate = 0; + + if (!CVarGetInteger("gEnhancements.Songs.FasterSongPlayback", 0)) { + return; + } + + onPlayerUpdate = + GameInteractor::Instance->RegisterGameHookForID(ACTOR_PLAYER, [](Actor* actor) { + if (gPlayState->msgCtx.msgMode >= MSGMODE_SONG_PLAYED && gPlayState->msgCtx.msgMode <= MSGMODE_17) { + if (gPlayState->msgCtx.stateTimer > 1) { + gPlayState->msgCtx.stateTimer = 1; + } + gPlayState->msgCtx.ocarinaSongEffectActive = 0; + sPlaybackState = 0; + } + }); +} diff --git a/mm/2s2h/Enhancements/Songs/Songs.h b/mm/2s2h/Enhancements/Songs/Songs.h index 22469f29e..ecd2a6942 100644 --- a/mm/2s2h/Enhancements/Songs/Songs.h +++ b/mm/2s2h/Enhancements/Songs/Songs.h @@ -2,6 +2,7 @@ #define SONGS_H void RegisterEnableSunsSong(); +void RegisterFasterSongPlayback(); void RegisterZoraEggCount(); void RegisterPauseOwlWarp(); From cae9c27c62f52d3a85f8b57ff048cd107e8cbb3f Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 7 Oct 2024 11:25:34 -0400 Subject: [PATCH 61/82] Add HD support for Igos room curtains (#783) --- .../overlays/actors/ovl_Boss_06/z_boss_06.c | 22 +++++++++++++++++-- .../overlays/actors/ovl_Boss_06/z_boss_06.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.c b/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.c index 912ff71a6..1730278a1 100644 --- a/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.c +++ b/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.c @@ -10,7 +10,8 @@ #include "overlays/actors/ovl_En_Knight/z_en_knight.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_knight/object_knight.h" -#include "BenPort.h" + +#include "2s2h/BenPort.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_20) @@ -493,6 +494,9 @@ void Boss06_Update(Actor* thisx, PlayState* play) { } else { this->unk_200[idx] &= 0xF; } + + // 2S2H [Port] Map the coordinates to the blended mask + this->curtainTexMask[((s32)sp7C.y * 64) + x] = true; } } } @@ -588,7 +592,19 @@ void Boss06_Draw(Actor* thisx, PlayState* play2) { } if (this->unk_144 & 1) { - gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(&this->unk_200)); + // 2S2H [Port][HD Textures] To support CPU modified textures for any arbitrary texture size and alt asset + // toggling, we need to set the original texture resource as the segment value and register each curtain's mask + // as a blended texture. The blended tex opcode is necessary since there are two curtains in the scene, but only + // one mask can be registered to a resource at a time. + if (true) { + gSPRegisterBlendedTex(POLY_OPA_DISP++, object_knight_Tex_019490, this->curtainTexMask, NULL); + gSPInvalidateTexCache(POLY_OPA_DISP++, this->curtainTexMask); + gSPInvalidateTexCache(POLY_OPA_DISP++, object_knight_Tex_019490); + gSPSegment(POLY_OPA_DISP++, 0x08, object_knight_Tex_019490); + } else { + gSPInvalidateTexCache(POLY_OPA_DISP++, &this->unk_200); + gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(&this->unk_200)); + } Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + this->unk_1A8, this->actor.world.pos.z, MTXMODE_NEW); @@ -664,4 +680,6 @@ void Boss06_Reset(void) { D_809F4974 = 0; D_809F4978 = 0; D_809F497C = 0; + + Gfx_UnregisterBlendedTexture(object_knight_Tex_019490); } diff --git a/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.h b/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.h index f7b4d3ec0..b0807fa7b 100644 --- a/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.h +++ b/mm/src/overlays/actors/ovl_Boss_06/z_boss_06.h @@ -48,6 +48,8 @@ typedef struct Boss06 { /* 0xA1C */ Vec3f unk_A1C; /* 0xA28 */ f32 unk_A28; /* 0xA2C */ f32 unk_A2C; + // 2S2H [Port] + /* */ u8 curtainTexMask[64 * 64]; // [HD Textures] Mask for CPU modified texture } Boss06; // size = 0xA30 #endif // Z_BOSS_06_H From 7e10b1315ede6522c28db47fa3d0f2d8b87167a2 Mon Sep 17 00:00:00 2001 From: mckinlee Date: Mon, 7 Oct 2024 12:02:36 -0400 Subject: [PATCH 62/82] [Enhancement] Disable Takkuri Steal (#776) * simple and works * implement proxy's feedback Co-authored-by: Garrett Joe Cox * forgot to remove unneeded check from testing * remove null arg * simple and works * implement proxy's feedback Co-authored-by: Garrett Joe Cox * forgot to remove unneeded check from testing * remove null arg * changes * bump lus * add checkbox to modern menu * clang * archez feedback * proxy feedback --- mm/2s2h/BenGui/BenMenuBar.cpp | 9 +++++++++ mm/2s2h/BenGui/SearchableMenuItems.h | 9 +++++++++ .../DifficultyOptions/DifficultyOptions.h | 6 ++++++ .../DifficultyOptions/DisableTakkuriSteal.cpp | 14 ++++++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 +++ mm/2s2h/Enhancements/Enhancements.h | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 1 + .../actors/ovl_En_Thiefbird/z_en_thiefbird.c | 4 +++- 8 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/DifficultyOptions/DifficultyOptions.h create mode 100644 mm/2s2h/Enhancements/DifficultyOptions/DisableTakkuriSteal.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 54a1fe6aa..f987b312b 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -743,6 +743,15 @@ void DrawEnhancementsMenu() { ImGui::EndMenu(); } + if (UIWidgets::BeginMenu("Difficulty Options")) { + if (UIWidgets::CVarCheckbox("Disable Takkuri Steal", "gEnhancements.Cheats.DisableTakkuriSteal", + { .tooltip = "Prevents the Takkuri from stealing key items like bottles and " + "swords. It may still steal other items." })) { + RegisterDisableTakkuriSteal(); + } + ImGui::EndMenu(); + } + if (mHudEditorWindow) { UIWidgets::WindowButton("Hud Editor", "gWindows.HudEditor", mHudEditorWindow, { .tooltip = "Enables the Hud Editor window, allowing you to edit your hud" }); diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 2bd672834..a6caf6df4 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1306,6 +1306,15 @@ void AddEnhancements() { WIDGET_CVAR_CHECKBOX, {}, [](widgetInfo& info) { RegisterWoodfallMountainAppearance(); } } } } }); + enhancementsSidebar.push_back( + { "Difficulty Options", + 3, + { { { "Disable Takkuri Steal", + "gEnhancements.Cheats.DisableTakkuriSteal", + "Prevents the Takkuri from stealing key items like bottles and swords. It may still steal other items.", + WIDGET_CVAR_CHECKBOX, + {}, + [](widgetInfo& info) { RegisterDisableTakkuriSteal(); } } } } }); enhancementsSidebar.push_back({ "HUD Editor", 1, { // HUD Editor diff --git a/mm/2s2h/Enhancements/DifficultyOptions/DifficultyOptions.h b/mm/2s2h/Enhancements/DifficultyOptions/DifficultyOptions.h new file mode 100644 index 000000000..5680ec0af --- /dev/null +++ b/mm/2s2h/Enhancements/DifficultyOptions/DifficultyOptions.h @@ -0,0 +1,6 @@ +#ifndef DIFFICULTY_OPTIONS_H +#define DIFFICULTY_OPTIONS_H + +void RegisterDisableTakkuriSteal(); + +#endif // DIFFICULTY_OPTIONS_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/DifficultyOptions/DisableTakkuriSteal.cpp b/mm/2s2h/Enhancements/DifficultyOptions/DisableTakkuriSteal.cpp new file mode 100644 index 000000000..214c38202 --- /dev/null +++ b/mm/2s2h/Enhancements/DifficultyOptions/DisableTakkuriSteal.cpp @@ -0,0 +1,14 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" + +void RegisterDisableTakkuriSteal() { + static HOOK_ID thiefBirdStealHookID = 0; + GameInteractor::Instance->UnregisterGameHookForID(thiefBirdStealHookID); + thiefBirdStealHookID = 0; + + if (!CVarGetInteger("gEnhancements.Cheats.DisableTakkuriSteal", 0)) { + return; + } + + thiefBirdStealHookID = REGISTER_VB_SHOULD(VB_THIEF_BIRD_STEAL, { *should = false; }); +} \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 3afba3157..4b90ac954 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -72,4 +72,7 @@ void InitEnhancements() { // Modes RegisterPlayAsKafei(); RegisterTimeMovesWhenYouMove(); + + // Difficulty Options + RegisterDisableTakkuriSteal(); } diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 8ec82aa36..5abf01fc6 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -16,6 +16,7 @@ #include "Restorations/Restorations.h" #include "Saving/SavingEnhancements.h" #include "Songs/Songs.h" +#include "DifficultyOptions/DifficultyOptions.h" enum AlwaysWinDoggyRaceOptions { ALWAYS_WIN_DOGGY_RACE_OFF, diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 20cada536..3af119040 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -63,6 +63,7 @@ typedef enum { VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE, VB_DRAW_SLIME_BODY_ITEM, VB_ZTARGET_SPEED_CHECK, + VB_THIEF_BIRD_STEAL, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_Thiefbird/z_en_thiefbird.c b/mm/src/overlays/actors/ovl_En_Thiefbird/z_en_thiefbird.c index 19ac9ad60..144f35f11 100644 --- a/mm/src/overlays/actors/ovl_En_Thiefbird/z_en_thiefbird.c +++ b/mm/src/overlays/actors/ovl_En_Thiefbird/z_en_thiefbird.c @@ -10,6 +10,8 @@ #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/GameInteractor/GameInteractor.h" + #define FLAGS \ (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY | ACTOR_FLAG_200 | ACTOR_FLAG_IGNORE_QUAKE | ACTOR_FLAG_80000000) @@ -585,7 +587,7 @@ void func_80C1193C(EnThiefbird* this, PlayState* play) { if (!(this->collider.base.atFlags & AT_BOUNCED)) { if ((D_80C1392C != 0) && CUR_UPG_VALUE(UPG_QUIVER) && ((STOLEN_ITEM_1 == STOLEN_ITEM_NONE) || (STOLEN_ITEM_2 == STOLEN_ITEM_NONE)) && - (Rand_ZeroOne() < 0.5f) && func_80C10B0C(this, play)) { + GameInteractor_Should(VB_THIEF_BIRD_STEAL, Rand_ZeroOne() < 0.5f) && func_80C10B0C(this, play)) { func_80C1242C(this); } else if (func_80C10E98(play)) { func_80C11338(this, play); From fa702ed90c3d28093dfb95cb9069018e4fa03a48 Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 7 Oct 2024 13:05:17 -0400 Subject: [PATCH 63/82] Extract pause maps and minimaps, support alt assets, fix pause map icons (#780) * extract pause maps and minimaps and support alt assets * Fix missing door transitions on pause menu map --- mm/2s2h/z_scene_2SH.cpp | 1 + .../map_grand_static/map_grand_static.h | 392 +++++++++--------- .../archives/map_i_static/map_i_static.h | 232 +++++------ .../xml/GC_US/archives/map_grand_static.xml | 196 ++++----- mm/assets/xml/GC_US/archives/map_i_static.xml | 116 +++--- .../xml/N64_US/archives/map_grand_static.xml | 196 ++++----- .../xml/N64_US/archives/map_i_static.xml | 116 +++--- mm/src/code/z_map_disp.c | 113 +++-- 8 files changed, 679 insertions(+), 683 deletions(-) diff --git a/mm/2s2h/z_scene_2SH.cpp b/mm/2s2h/z_scene_2SH.cpp index a47055ae5..60777db82 100644 --- a/mm/2s2h/z_scene_2SH.cpp +++ b/mm/2s2h/z_scene_2SH.cpp @@ -258,6 +258,7 @@ void Scene_CommandTransiActorList(PlayState* play, SOH::ISceneCommand* cmd) { play->transitionActors.count = list->numTransitionActors; play->transitionActors.list = (TransitionActorEntry*)list->GetRawPointer(); + MapDisp_InitTransitionActorData(play, play->transitionActors.count, play->transitionActors.list); } void Scene_CommandEnvLightSettings(PlayState* play, SOH::ISceneCommand* cmd) { diff --git a/mm/assets/archives/map_grand_static/map_grand_static.h b/mm/assets/archives/map_grand_static/map_grand_static.h index 71d9f29d9..bc9129c15 100644 --- a/mm/assets/archives/map_grand_static/map_grand_static.h +++ b/mm/assets/archives/map_grand_static/map_grand_static.h @@ -3,297 +3,297 @@ #include "align_asset_macro.h" -#define dmap_grand_static_Blob_000000 "__OTR__map_grand_static/map_grand_static_Blob_000000" -static const ALIGN_ASSET(2) char map_grand_static_Blob_000000[] = dmap_grand_static_Blob_000000; +#define dgMapGrandStatic100Tex "__OTR__map_grand_static/gMapGrandStatic100Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic100Tex[] = dgMapGrandStatic100Tex; -#define dmap_grand_static_Blob_000FF0 "__OTR__map_grand_static/map_grand_static_Blob_000FF0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_000FF0[] = dmap_grand_static_Blob_000FF0; +#define dgMapGrandStatic101Tex "__OTR__map_grand_static/gMapGrandStatic101Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic101Tex[] = dgMapGrandStatic101Tex; -#define dmap_grand_static_Blob_001FE0 "__OTR__map_grand_static/map_grand_static_Blob_001FE0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_001FE0[] = dmap_grand_static_Blob_001FE0; +#define dgMapGrandStatic102Tex "__OTR__map_grand_static/gMapGrandStatic102Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic102Tex[] = dgMapGrandStatic102Tex; -#define dmap_grand_static_Blob_002FD0 "__OTR__map_grand_static/map_grand_static_Blob_002FD0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_002FD0[] = dmap_grand_static_Blob_002FD0; +#define dgMapGrandStatic103Tex "__OTR__map_grand_static/gMapGrandStatic103Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic103Tex[] = dgMapGrandStatic103Tex; -#define dmap_grand_static_Blob_003FC0 "__OTR__map_grand_static/map_grand_static_Blob_003FC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_003FC0[] = dmap_grand_static_Blob_003FC0; +#define dgMapGrandStatic104Tex "__OTR__map_grand_static/gMapGrandStatic104Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic104Tex[] = dgMapGrandStatic104Tex; -#define dmap_grand_static_Blob_004FB0 "__OTR__map_grand_static/map_grand_static_Blob_004FB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_004FB0[] = dmap_grand_static_Blob_004FB0; +#define dgMapGrandStatic105Tex "__OTR__map_grand_static/gMapGrandStatic105Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic105Tex[] = dgMapGrandStatic105Tex; -#define dmap_grand_static_Blob_005AF0 "__OTR__map_grand_static/map_grand_static_Blob_005AF0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_005AF0[] = dmap_grand_static_Blob_005AF0; +#define dgMapGrandStatic106Tex "__OTR__map_grand_static/gMapGrandStatic106Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic106Tex[] = dgMapGrandStatic106Tex; -#define dmap_grand_static_Blob_006AE0 "__OTR__map_grand_static/map_grand_static_Blob_006AE0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_006AE0[] = dmap_grand_static_Blob_006AE0; +#define dgMapGrandStatic107Tex "__OTR__map_grand_static/gMapGrandStatic107Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic107Tex[] = dgMapGrandStatic107Tex; -#define dmap_grand_static_Blob_007AD0 "__OTR__map_grand_static/map_grand_static_Blob_007AD0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_007AD0[] = dmap_grand_static_Blob_007AD0; +#define dgMapGrandStatic108Tex "__OTR__map_grand_static/gMapGrandStatic108Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic108Tex[] = dgMapGrandStatic108Tex; -#define dmap_grand_static_Blob_008AC0 "__OTR__map_grand_static/map_grand_static_Blob_008AC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_008AC0[] = dmap_grand_static_Blob_008AC0; +#define dgMapGrandStatic109Tex "__OTR__map_grand_static/gMapGrandStatic109Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic109Tex[] = dgMapGrandStatic109Tex; -#define dmap_grand_static_Blob_009AB0 "__OTR__map_grand_static/map_grand_static_Blob_009AB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_009AB0[] = dmap_grand_static_Blob_009AB0; +#define dgMapGrandStatic10ATex "__OTR__map_grand_static/gMapGrandStatic10ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic10ATex[] = dgMapGrandStatic10ATex; -#define dmap_grand_static_Blob_009ED0 "__OTR__map_grand_static/map_grand_static_Blob_009ED0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_009ED0[] = dmap_grand_static_Blob_009ED0; +#define dgMapGrandStatic10BTex "__OTR__map_grand_static/gMapGrandStatic10BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic10BTex[] = dgMapGrandStatic10BTex; -#define dmap_grand_static_Blob_00AEC0 "__OTR__map_grand_static/map_grand_static_Blob_00AEC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00AEC0[] = dmap_grand_static_Blob_00AEC0; +#define dgMapGrandStatic10CTex "__OTR__map_grand_static/gMapGrandStatic10CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic10CTex[] = dgMapGrandStatic10CTex; -#define dmap_grand_static_Blob_00B310 "__OTR__map_grand_static/map_grand_static_Blob_00B310" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00B310[] = dmap_grand_static_Blob_00B310; +#define dgMapGrandStatic10DTex "__OTR__map_grand_static/gMapGrandStatic10DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic10DTex[] = dgMapGrandStatic10DTex; -#define dmap_grand_static_Blob_00BAB0 "__OTR__map_grand_static/map_grand_static_Blob_00BAB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00BAB0[] = dmap_grand_static_Blob_00BAB0; +#define dgMapGrandStatic10ETex "__OTR__map_grand_static/gMapGrandStatic10ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic10ETex[] = dgMapGrandStatic10ETex; -#define dmap_grand_static_Blob_00CAA0 "__OTR__map_grand_static/map_grand_static_Blob_00CAA0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00CAA0[] = dmap_grand_static_Blob_00CAA0; +#define dgMapGrandStatic10FTex "__OTR__map_grand_static/gMapGrandStatic10FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic10FTex[] = dgMapGrandStatic10FTex; -#define dmap_grand_static_Blob_00DA90 "__OTR__map_grand_static/map_grand_static_Blob_00DA90" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00DA90[] = dmap_grand_static_Blob_00DA90; +#define dgMapGrandStatic110Tex "__OTR__map_grand_static/gMapGrandStatic110Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic110Tex[] = dgMapGrandStatic110Tex; -#define dmap_grand_static_Blob_00EA80 "__OTR__map_grand_static/map_grand_static_Blob_00EA80" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00EA80[] = dmap_grand_static_Blob_00EA80; +#define dgMapGrandStatic111Tex "__OTR__map_grand_static/gMapGrandStatic111Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic111Tex[] = dgMapGrandStatic111Tex; -#define dmap_grand_static_Blob_00F200 "__OTR__map_grand_static/map_grand_static_Blob_00F200" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00F200[] = dmap_grand_static_Blob_00F200; +#define dgMapGrandStatic112Tex "__OTR__map_grand_static/gMapGrandStatic112Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic112Tex[] = dgMapGrandStatic112Tex; -#define dmap_grand_static_Blob_00FA00 "__OTR__map_grand_static/map_grand_static_Blob_00FA00" -static const ALIGN_ASSET(2) char map_grand_static_Blob_00FA00[] = dmap_grand_static_Blob_00FA00; +#define dgMapGrandStatic113Tex "__OTR__map_grand_static/gMapGrandStatic113Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic113Tex[] = dgMapGrandStatic113Tex; -#define dmap_grand_static_Blob_010250 "__OTR__map_grand_static/map_grand_static_Blob_010250" -static const ALIGN_ASSET(2) char map_grand_static_Blob_010250[] = dmap_grand_static_Blob_010250; +#define dgMapGrandStatic114Tex "__OTR__map_grand_static/gMapGrandStatic114Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic114Tex[] = dgMapGrandStatic114Tex; -#define dmap_grand_static_Blob_010760 "__OTR__map_grand_static/map_grand_static_Blob_010760" -static const ALIGN_ASSET(2) char map_grand_static_Blob_010760[] = dmap_grand_static_Blob_010760; +#define dgMapGrandStatic115Tex "__OTR__map_grand_static/gMapGrandStatic115Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic115Tex[] = dgMapGrandStatic115Tex; -#define dmap_grand_static_Blob_010E70 "__OTR__map_grand_static/map_grand_static_Blob_010E70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_010E70[] = dmap_grand_static_Blob_010E70; +#define dgMapGrandStatic116Tex "__OTR__map_grand_static/gMapGrandStatic116Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic116Tex[] = dgMapGrandStatic116Tex; -#define dmap_grand_static_Blob_011950 "__OTR__map_grand_static/map_grand_static_Blob_011950" -static const ALIGN_ASSET(2) char map_grand_static_Blob_011950[] = dmap_grand_static_Blob_011950; +#define dgMapGrandStatic117Tex "__OTR__map_grand_static/gMapGrandStatic117Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic117Tex[] = dgMapGrandStatic117Tex; -#define dmap_grand_static_Blob_011FB0 "__OTR__map_grand_static/map_grand_static_Blob_011FB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_011FB0[] = dmap_grand_static_Blob_011FB0; +#define dgMapGrandStatic118Tex "__OTR__map_grand_static/gMapGrandStatic118Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic118Tex[] = dgMapGrandStatic118Tex; -#define dmap_grand_static_Blob_012C10 "__OTR__map_grand_static/map_grand_static_Blob_012C10" -static const ALIGN_ASSET(2) char map_grand_static_Blob_012C10[] = dmap_grand_static_Blob_012C10; +#define dgMapGrandStatic119Tex "__OTR__map_grand_static/gMapGrandStatic119Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic119Tex[] = dgMapGrandStatic119Tex; -#define dmap_grand_static_Blob_013A20 "__OTR__map_grand_static/map_grand_static_Blob_013A20" -static const ALIGN_ASSET(2) char map_grand_static_Blob_013A20[] = dmap_grand_static_Blob_013A20; +#define dgMapGrandStatic11ATex "__OTR__map_grand_static/gMapGrandStatic11ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic11ATex[] = dgMapGrandStatic11ATex; -#define dmap_grand_static_Blob_013E00 "__OTR__map_grand_static/map_grand_static_Blob_013E00" -static const ALIGN_ASSET(2) char map_grand_static_Blob_013E00[] = dmap_grand_static_Blob_013E00; +#define dgMapGrandStatic11BTex "__OTR__map_grand_static/gMapGrandStatic11BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic11BTex[] = dgMapGrandStatic11BTex; -#define dmap_grand_static_Blob_0143A0 "__OTR__map_grand_static/map_grand_static_Blob_0143A0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0143A0[] = dmap_grand_static_Blob_0143A0; +#define dgMapGrandStatic11CTex "__OTR__map_grand_static/gMapGrandStatic11CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic11CTex[] = dgMapGrandStatic11CTex; -#define dmap_grand_static_Blob_014BC0 "__OTR__map_grand_static/map_grand_static_Blob_014BC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_014BC0[] = dmap_grand_static_Blob_014BC0; +#define dgMapGrandStatic11DTex "__OTR__map_grand_static/gMapGrandStatic11DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic11DTex[] = dgMapGrandStatic11DTex; -#define dmap_grand_static_Blob_015000 "__OTR__map_grand_static/map_grand_static_Blob_015000" -static const ALIGN_ASSET(2) char map_grand_static_Blob_015000[] = dmap_grand_static_Blob_015000; +#define dgMapGrandStatic11ETex "__OTR__map_grand_static/gMapGrandStatic11ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic11ETex[] = dgMapGrandStatic11ETex; -#define dmap_grand_static_Blob_015590 "__OTR__map_grand_static/map_grand_static_Blob_015590" -static const ALIGN_ASSET(2) char map_grand_static_Blob_015590[] = dmap_grand_static_Blob_015590; +#define dgMapGrandStatic11FTex "__OTR__map_grand_static/gMapGrandStatic11FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic11FTex[] = dgMapGrandStatic11FTex; -#define dmap_grand_static_Blob_015B30 "__OTR__map_grand_static/map_grand_static_Blob_015B30" -static const ALIGN_ASSET(2) char map_grand_static_Blob_015B30[] = dmap_grand_static_Blob_015B30; +#define dgMapGrandStatic120Tex "__OTR__map_grand_static/gMapGrandStatic120Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic120Tex[] = dgMapGrandStatic120Tex; -#define dmap_grand_static_Blob_0162D0 "__OTR__map_grand_static/map_grand_static_Blob_0162D0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0162D0[] = dmap_grand_static_Blob_0162D0; +#define dgMapGrandStatic121Tex "__OTR__map_grand_static/gMapGrandStatic121Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic121Tex[] = dgMapGrandStatic121Tex; -#define dmap_grand_static_Blob_016A70 "__OTR__map_grand_static/map_grand_static_Blob_016A70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_016A70[] = dmap_grand_static_Blob_016A70; +#define dgMapGrandStatic122Tex "__OTR__map_grand_static/gMapGrandStatic122Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic122Tex[] = dgMapGrandStatic122Tex; -#define dmap_grand_static_Blob_017860 "__OTR__map_grand_static/map_grand_static_Blob_017860" -static const ALIGN_ASSET(2) char map_grand_static_Blob_017860[] = dmap_grand_static_Blob_017860; +#define dgMapGrandStatic123Tex "__OTR__map_grand_static/gMapGrandStatic123Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic123Tex[] = dgMapGrandStatic123Tex; -#define dmap_grand_static_Blob_0180B0 "__OTR__map_grand_static/map_grand_static_Blob_0180B0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0180B0[] = dmap_grand_static_Blob_0180B0; +#define dgMapGrandStatic124Tex "__OTR__map_grand_static/gMapGrandStatic124Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic124Tex[] = dgMapGrandStatic124Tex; -#define dmap_grand_static_Blob_018A70 "__OTR__map_grand_static/map_grand_static_Blob_018A70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_018A70[] = dmap_grand_static_Blob_018A70; +#define dgMapGrandStatic125Tex "__OTR__map_grand_static/gMapGrandStatic125Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic125Tex[] = dgMapGrandStatic125Tex; -#define dmap_grand_static_Blob_0192F0 "__OTR__map_grand_static/map_grand_static_Blob_0192F0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0192F0[] = dmap_grand_static_Blob_0192F0; +#define dgMapGrandStatic126Tex "__OTR__map_grand_static/gMapGrandStatic126Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic126Tex[] = dgMapGrandStatic126Tex; -#define dmap_grand_static_Blob_019950 "__OTR__map_grand_static/map_grand_static_Blob_019950" -static const ALIGN_ASSET(2) char map_grand_static_Blob_019950[] = dmap_grand_static_Blob_019950; +#define dgMapGrandStatic127Tex "__OTR__map_grand_static/gMapGrandStatic127Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic127Tex[] = dgMapGrandStatic127Tex; -#define dmap_grand_static_Blob_019CB0 "__OTR__map_grand_static/map_grand_static_Blob_019CB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_019CB0[] = dmap_grand_static_Blob_019CB0; +#define dgMapGrandStatic128Tex "__OTR__map_grand_static/gMapGrandStatic128Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic128Tex[] = dgMapGrandStatic128Tex; -#define dmap_grand_static_Blob_019F10 "__OTR__map_grand_static/map_grand_static_Blob_019F10" -static const ALIGN_ASSET(2) char map_grand_static_Blob_019F10[] = dmap_grand_static_Blob_019F10; +#define dgMapGrandStatic129Tex "__OTR__map_grand_static/gMapGrandStatic129Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic129Tex[] = dgMapGrandStatic129Tex; -#define dmap_grand_static_Blob_01A870 "__OTR__map_grand_static/map_grand_static_Blob_01A870" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01A870[] = dmap_grand_static_Blob_01A870; +#define dgMapGrandStatic12ATex "__OTR__map_grand_static/gMapGrandStatic12ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic12ATex[] = dgMapGrandStatic12ATex; -#define dmap_grand_static_Blob_01ABC0 "__OTR__map_grand_static/map_grand_static_Blob_01ABC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01ABC0[] = dmap_grand_static_Blob_01ABC0; +#define dgMapGrandStatic12BTex "__OTR__map_grand_static/gMapGrandStatic12BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic12BTex[] = dgMapGrandStatic12BTex; -#define dmap_grand_static_Blob_01B570 "__OTR__map_grand_static/map_grand_static_Blob_01B570" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01B570[] = dmap_grand_static_Blob_01B570; +#define dgMapGrandStatic12CTex "__OTR__map_grand_static/gMapGrandStatic12CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic12CTex[] = dgMapGrandStatic12CTex; -#define dmap_grand_static_Blob_01BEF0 "__OTR__map_grand_static/map_grand_static_Blob_01BEF0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01BEF0[] = dmap_grand_static_Blob_01BEF0; +#define dgMapGrandStatic12DTex "__OTR__map_grand_static/gMapGrandStatic12DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic12DTex[] = dgMapGrandStatic12DTex; -#define dmap_grand_static_Blob_01CEE0 "__OTR__map_grand_static/map_grand_static_Blob_01CEE0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01CEE0[] = dmap_grand_static_Blob_01CEE0; +#define dgMapGrandStatic12ETex "__OTR__map_grand_static/gMapGrandStatic12ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic12ETex[] = dgMapGrandStatic12ETex; -#define dmap_grand_static_Blob_01DA00 "__OTR__map_grand_static/map_grand_static_Blob_01DA00" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01DA00[] = dmap_grand_static_Blob_01DA00; +#define dgMapGrandStatic12FTex "__OTR__map_grand_static/gMapGrandStatic12FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic12FTex[] = dgMapGrandStatic12FTex; -#define dmap_grand_static_Blob_01E7A0 "__OTR__map_grand_static/map_grand_static_Blob_01E7A0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01E7A0[] = dmap_grand_static_Blob_01E7A0; +#define dgMapGrandStatic130Tex "__OTR__map_grand_static/gMapGrandStatic130Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic130Tex[] = dgMapGrandStatic130Tex; -#define dmap_grand_static_Blob_01EFC0 "__OTR__map_grand_static/map_grand_static_Blob_01EFC0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01EFC0[] = dmap_grand_static_Blob_01EFC0; +#define dgMapGrandStatic131Tex "__OTR__map_grand_static/gMapGrandStatic131Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic131Tex[] = dgMapGrandStatic131Tex; -#define dmap_grand_static_Blob_01F3A0 "__OTR__map_grand_static/map_grand_static_Blob_01F3A0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01F3A0[] = dmap_grand_static_Blob_01F3A0; +#define dgMapGrandStatic132Tex "__OTR__map_grand_static/gMapGrandStatic132Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic132Tex[] = dgMapGrandStatic132Tex; -#define dmap_grand_static_Blob_01FD20 "__OTR__map_grand_static/map_grand_static_Blob_01FD20" -static const ALIGN_ASSET(2) char map_grand_static_Blob_01FD20[] = dmap_grand_static_Blob_01FD20; +#define dgMapGrandStatic133Tex "__OTR__map_grand_static/gMapGrandStatic133Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic133Tex[] = dgMapGrandStatic133Tex; -#define dmap_grand_static_Blob_020680 "__OTR__map_grand_static/map_grand_static_Blob_020680" -static const ALIGN_ASSET(2) char map_grand_static_Blob_020680[] = dmap_grand_static_Blob_020680; +#define dgMapGrandStatic134Tex "__OTR__map_grand_static/gMapGrandStatic134Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic134Tex[] = dgMapGrandStatic134Tex; -#define dmap_grand_static_Blob_020DE0 "__OTR__map_grand_static/map_grand_static_Blob_020DE0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_020DE0[] = dmap_grand_static_Blob_020DE0; +#define dgMapGrandStatic135Tex "__OTR__map_grand_static/gMapGrandStatic135Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic135Tex[] = dgMapGrandStatic135Tex; -#define dmap_grand_static_Blob_021740 "__OTR__map_grand_static/map_grand_static_Blob_021740" -static const ALIGN_ASSET(2) char map_grand_static_Blob_021740[] = dmap_grand_static_Blob_021740; +#define dgMapGrandStatic136Tex "__OTR__map_grand_static/gMapGrandStatic136Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic136Tex[] = dgMapGrandStatic136Tex; -#define dmap_grand_static_Blob_021910 "__OTR__map_grand_static/map_grand_static_Blob_021910" -static const ALIGN_ASSET(2) char map_grand_static_Blob_021910[] = dmap_grand_static_Blob_021910; +#define dgMapGrandStatic137Tex "__OTR__map_grand_static/gMapGrandStatic137Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic137Tex[] = dgMapGrandStatic137Tex; -#define dmap_grand_static_Blob_021F40 "__OTR__map_grand_static/map_grand_static_Blob_021F40" -static const ALIGN_ASSET(2) char map_grand_static_Blob_021F40[] = dmap_grand_static_Blob_021F40; +#define dgMapGrandStatic138Tex "__OTR__map_grand_static/gMapGrandStatic138Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic138Tex[] = dgMapGrandStatic138Tex; -#define dmap_grand_static_Blob_0225C0 "__OTR__map_grand_static/map_grand_static_Blob_0225C0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0225C0[] = dmap_grand_static_Blob_0225C0; +#define dgMapGrandStatic139Tex "__OTR__map_grand_static/gMapGrandStatic139Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic139Tex[] = dgMapGrandStatic139Tex; -#define dmap_grand_static_Blob_022D90 "__OTR__map_grand_static/map_grand_static_Blob_022D90" -static const ALIGN_ASSET(2) char map_grand_static_Blob_022D90[] = dmap_grand_static_Blob_022D90; +#define dgMapGrandStatic13ATex "__OTR__map_grand_static/gMapGrandStatic13ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic13ATex[] = dgMapGrandStatic13ATex; -#define dmap_grand_static_Blob_023600 "__OTR__map_grand_static/map_grand_static_Blob_023600" -static const ALIGN_ASSET(2) char map_grand_static_Blob_023600[] = dmap_grand_static_Blob_023600; +#define dgMapGrandStatic13BTex "__OTR__map_grand_static/gMapGrandStatic13BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic13BTex[] = dgMapGrandStatic13BTex; -#define dmap_grand_static_Blob_024460 "__OTR__map_grand_static/map_grand_static_Blob_024460" -static const ALIGN_ASSET(2) char map_grand_static_Blob_024460[] = dmap_grand_static_Blob_024460; +#define dgMapGrandStatic13CTex "__OTR__map_grand_static/gMapGrandStatic13CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic13CTex[] = dgMapGrandStatic13CTex; -#define dmap_grand_static_Blob_024B70 "__OTR__map_grand_static/map_grand_static_Blob_024B70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_024B70[] = dmap_grand_static_Blob_024B70; +#define dgMapGrandStatic13DTex "__OTR__map_grand_static/gMapGrandStatic13DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic13DTex[] = dgMapGrandStatic13DTex; -#define dmap_grand_static_Blob_025190 "__OTR__map_grand_static/map_grand_static_Blob_025190" -static const ALIGN_ASSET(2) char map_grand_static_Blob_025190[] = dmap_grand_static_Blob_025190; +#define dgMapGrandStatic13ETex "__OTR__map_grand_static/gMapGrandStatic13ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic13ETex[] = dgMapGrandStatic13ETex; -#define dmap_grand_static_Blob_0257B0 "__OTR__map_grand_static/map_grand_static_Blob_0257B0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0257B0[] = dmap_grand_static_Blob_0257B0; +#define dgMapGrandStatic13FTex "__OTR__map_grand_static/gMapGrandStatic13FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic13FTex[] = dgMapGrandStatic13FTex; -#define dmap_grand_static_Blob_025E30 "__OTR__map_grand_static/map_grand_static_Blob_025E30" -static const ALIGN_ASSET(2) char map_grand_static_Blob_025E30[] = dmap_grand_static_Blob_025E30; +#define dgMapGrandStatic140Tex "__OTR__map_grand_static/gMapGrandStatic140Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic140Tex[] = dgMapGrandStatic140Tex; -#define dmap_grand_static_Blob_026450 "__OTR__map_grand_static/map_grand_static_Blob_026450" -static const ALIGN_ASSET(2) char map_grand_static_Blob_026450[] = dmap_grand_static_Blob_026450; +#define dgMapGrandStatic141Tex "__OTR__map_grand_static/gMapGrandStatic141Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic141Tex[] = dgMapGrandStatic141Tex; -#define dmap_grand_static_Blob_026660 "__OTR__map_grand_static/map_grand_static_Blob_026660" -static const ALIGN_ASSET(2) char map_grand_static_Blob_026660[] = dmap_grand_static_Blob_026660; +#define dgMapGrandStatic142Tex "__OTR__map_grand_static/gMapGrandStatic142Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic142Tex[] = dgMapGrandStatic142Tex; -#define dmap_grand_static_Blob_026B10 "__OTR__map_grand_static/map_grand_static_Blob_026B10" -static const ALIGN_ASSET(2) char map_grand_static_Blob_026B10[] = dmap_grand_static_Blob_026B10; +#define dgMapGrandStatic143Tex "__OTR__map_grand_static/gMapGrandStatic143Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic143Tex[] = dgMapGrandStatic143Tex; -#define dmap_grand_static_Blob_027190 "__OTR__map_grand_static/map_grand_static_Blob_027190" -static const ALIGN_ASSET(2) char map_grand_static_Blob_027190[] = dmap_grand_static_Blob_027190; +#define dgMapGrandStatic144Tex "__OTR__map_grand_static/gMapGrandStatic144Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic144Tex[] = dgMapGrandStatic144Tex; -#define dmap_grand_static_Blob_0274E0 "__OTR__map_grand_static/map_grand_static_Blob_0274E0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0274E0[] = dmap_grand_static_Blob_0274E0; +#define dgMapGrandStatic145Tex "__OTR__map_grand_static/gMapGrandStatic145Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic145Tex[] = dgMapGrandStatic145Tex; -#define dmap_grand_static_Blob_027B40 "__OTR__map_grand_static/map_grand_static_Blob_027B40" -static const ALIGN_ASSET(2) char map_grand_static_Blob_027B40[] = dmap_grand_static_Blob_027B40; +#define dgMapGrandStatic146Tex "__OTR__map_grand_static/gMapGrandStatic146Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic146Tex[] = dgMapGrandStatic146Tex; -#define dmap_grand_static_Blob_027E90 "__OTR__map_grand_static/map_grand_static_Blob_027E90" -static const ALIGN_ASSET(2) char map_grand_static_Blob_027E90[] = dmap_grand_static_Blob_027E90; +#define dgMapGrandStatic147Tex "__OTR__map_grand_static/gMapGrandStatic147Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic147Tex[] = dgMapGrandStatic147Tex; -#define dmap_grand_static_Blob_028390 "__OTR__map_grand_static/map_grand_static_Blob_028390" -static const ALIGN_ASSET(2) char map_grand_static_Blob_028390[] = dmap_grand_static_Blob_028390; +#define dgMapGrandStatic148Tex "__OTR__map_grand_static/gMapGrandStatic148Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic148Tex[] = dgMapGrandStatic148Tex; -#define dmap_grand_static_Blob_028A30 "__OTR__map_grand_static/map_grand_static_Blob_028A30" -static const ALIGN_ASSET(2) char map_grand_static_Blob_028A30[] = dmap_grand_static_Blob_028A30; +#define dgMapGrandStatic149Tex "__OTR__map_grand_static/gMapGrandStatic149Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic149Tex[] = dgMapGrandStatic149Tex; -#define dmap_grand_static_Blob_029010 "__OTR__map_grand_static/map_grand_static_Blob_029010" -static const ALIGN_ASSET(2) char map_grand_static_Blob_029010[] = dmap_grand_static_Blob_029010; +#define dgMapGrandStatic14ATex "__OTR__map_grand_static/gMapGrandStatic14ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic14ATex[] = dgMapGrandStatic14ATex; -#define dmap_grand_static_Blob_029690 "__OTR__map_grand_static/map_grand_static_Blob_029690" -static const ALIGN_ASSET(2) char map_grand_static_Blob_029690[] = dmap_grand_static_Blob_029690; +#define dgMapGrandStatic14BTex "__OTR__map_grand_static/gMapGrandStatic14BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic14BTex[] = dgMapGrandStatic14BTex; -#define dmap_grand_static_Blob_029B10 "__OTR__map_grand_static/map_grand_static_Blob_029B10" -static const ALIGN_ASSET(2) char map_grand_static_Blob_029B10[] = dmap_grand_static_Blob_029B10; +#define dgMapGrandStatic14CTex "__OTR__map_grand_static/gMapGrandStatic14CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic14CTex[] = dgMapGrandStatic14CTex; -#define dmap_grand_static_Blob_02A5F0 "__OTR__map_grand_static/map_grand_static_Blob_02A5F0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02A5F0[] = dmap_grand_static_Blob_02A5F0; +#define dgMapGrandStatic14DTex "__OTR__map_grand_static/gMapGrandStatic14DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic14DTex[] = dgMapGrandStatic14DTex; -#define dmap_grand_static_Blob_02A8C0 "__OTR__map_grand_static/map_grand_static_Blob_02A8C0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02A8C0[] = dmap_grand_static_Blob_02A8C0; +#define dgMapGrandStatic14ETex "__OTR__map_grand_static/gMapGrandStatic14ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic14ETex[] = dgMapGrandStatic14ETex; -#define dmap_grand_static_Blob_02B450 "__OTR__map_grand_static/map_grand_static_Blob_02B450" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02B450[] = dmap_grand_static_Blob_02B450; +#define dgMapGrandStatic14FTex "__OTR__map_grand_static/gMapGrandStatic14FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic14FTex[] = dgMapGrandStatic14FTex; -#define dmap_grand_static_Blob_02C1F0 "__OTR__map_grand_static/map_grand_static_Blob_02C1F0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02C1F0[] = dmap_grand_static_Blob_02C1F0; +#define dgMapGrandStatic150Tex "__OTR__map_grand_static/gMapGrandStatic150Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic150Tex[] = dgMapGrandStatic150Tex; -#define dmap_grand_static_Blob_02CAB0 "__OTR__map_grand_static/map_grand_static_Blob_02CAB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02CAB0[] = dmap_grand_static_Blob_02CAB0; +#define dgMapGrandStatic151Tex "__OTR__map_grand_static/gMapGrandStatic151Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic151Tex[] = dgMapGrandStatic151Tex; -#define dmap_grand_static_Blob_02D4E0 "__OTR__map_grand_static/map_grand_static_Blob_02D4E0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02D4E0[] = dmap_grand_static_Blob_02D4E0; +#define dgMapGrandStatic152Tex "__OTR__map_grand_static/gMapGrandStatic152Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic152Tex[] = dgMapGrandStatic152Tex; -#define dmap_grand_static_Blob_02D610 "__OTR__map_grand_static/map_grand_static_Blob_02D610" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02D610[] = dmap_grand_static_Blob_02D610; +#define dgMapGrandStatic153Tex "__OTR__map_grand_static/gMapGrandStatic153Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic153Tex[] = dgMapGrandStatic153Tex; -#define dmap_grand_static_Blob_02E240 "__OTR__map_grand_static/map_grand_static_Blob_02E240" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02E240[] = dmap_grand_static_Blob_02E240; +#define dgMapGrandStatic154Tex "__OTR__map_grand_static/gMapGrandStatic154Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic154Tex[] = dgMapGrandStatic154Tex; -#define dmap_grand_static_Blob_02EAE0 "__OTR__map_grand_static/map_grand_static_Blob_02EAE0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02EAE0[] = dmap_grand_static_Blob_02EAE0; +#define dgMapGrandStatic155Tex "__OTR__map_grand_static/gMapGrandStatic155Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic155Tex[] = dgMapGrandStatic155Tex; -#define dmap_grand_static_Blob_02FA30 "__OTR__map_grand_static/map_grand_static_Blob_02FA30" -static const ALIGN_ASSET(2) char map_grand_static_Blob_02FA30[] = dmap_grand_static_Blob_02FA30; +#define dgMapGrandStatic156Tex "__OTR__map_grand_static/gMapGrandStatic156Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic156Tex[] = dgMapGrandStatic156Tex; -#define dmap_grand_static_Blob_0303E0 "__OTR__map_grand_static/map_grand_static_Blob_0303E0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0303E0[] = dmap_grand_static_Blob_0303E0; +#define dgMapGrandStatic157Tex "__OTR__map_grand_static/gMapGrandStatic157Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic157Tex[] = dgMapGrandStatic157Tex; -#define dmap_grand_static_Blob_030B90 "__OTR__map_grand_static/map_grand_static_Blob_030B90" -static const ALIGN_ASSET(2) char map_grand_static_Blob_030B90[] = dmap_grand_static_Blob_030B90; +#define dgMapGrandStatic158Tex "__OTR__map_grand_static/gMapGrandStatic158Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic158Tex[] = dgMapGrandStatic158Tex; -#define dmap_grand_static_Blob_0314F0 "__OTR__map_grand_static/map_grand_static_Blob_0314F0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0314F0[] = dmap_grand_static_Blob_0314F0; +#define dgMapGrandStatic159Tex "__OTR__map_grand_static/gMapGrandStatic159Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic159Tex[] = dgMapGrandStatic159Tex; -#define dmap_grand_static_Blob_031C30 "__OTR__map_grand_static/map_grand_static_Blob_031C30" -static const ALIGN_ASSET(2) char map_grand_static_Blob_031C30[] = dmap_grand_static_Blob_031C30; +#define dgMapGrandStatic15ATex "__OTR__map_grand_static/gMapGrandStatic15ATex" +static const ALIGN_ASSET(2) char gMapGrandStatic15ATex[] = dgMapGrandStatic15ATex; -#define dmap_grand_static_Blob_032630 "__OTR__map_grand_static/map_grand_static_Blob_032630" -static const ALIGN_ASSET(2) char map_grand_static_Blob_032630[] = dmap_grand_static_Blob_032630; +#define dgMapGrandStatic15BTex "__OTR__map_grand_static/gMapGrandStatic15BTex" +static const ALIGN_ASSET(2) char gMapGrandStatic15BTex[] = dgMapGrandStatic15BTex; -#define dmap_grand_static_Blob_032C70 "__OTR__map_grand_static/map_grand_static_Blob_032C70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_032C70[] = dmap_grand_static_Blob_032C70; +#define dgMapGrandStatic15CTex "__OTR__map_grand_static/gMapGrandStatic15CTex" +static const ALIGN_ASSET(2) char gMapGrandStatic15CTex[] = dgMapGrandStatic15CTex; -#define dmap_grand_static_Blob_0336A0 "__OTR__map_grand_static/map_grand_static_Blob_0336A0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_0336A0[] = dmap_grand_static_Blob_0336A0; +#define dgMapGrandStatic15DTex "__OTR__map_grand_static/gMapGrandStatic15DTex" +static const ALIGN_ASSET(2) char gMapGrandStatic15DTex[] = dgMapGrandStatic15DTex; -#define dmap_grand_static_Blob_033A70 "__OTR__map_grand_static/map_grand_static_Blob_033A70" -static const ALIGN_ASSET(2) char map_grand_static_Blob_033A70[] = dmap_grand_static_Blob_033A70; +#define dgMapGrandStatic15ETex "__OTR__map_grand_static/gMapGrandStatic15ETex" +static const ALIGN_ASSET(2) char gMapGrandStatic15ETex[] = dgMapGrandStatic15ETex; -#define dmap_grand_static_Blob_034770 "__OTR__map_grand_static/map_grand_static_Blob_034770" -static const ALIGN_ASSET(2) char map_grand_static_Blob_034770[] = dmap_grand_static_Blob_034770; +#define dgMapGrandStatic15FTex "__OTR__map_grand_static/gMapGrandStatic15FTex" +static const ALIGN_ASSET(2) char gMapGrandStatic15FTex[] = dgMapGrandStatic15FTex; -#define dmap_grand_static_Blob_034BB0 "__OTR__map_grand_static/map_grand_static_Blob_034BB0" -static const ALIGN_ASSET(2) char map_grand_static_Blob_034BB0[] = dmap_grand_static_Blob_034BB0; +#define dgMapGrandStatic160Tex "__OTR__map_grand_static/gMapGrandStatic160Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic160Tex[] = dgMapGrandStatic160Tex; -#define dmap_grand_static_Blob_034F50 "__OTR__map_grand_static/map_grand_static_Blob_034F50" -static const ALIGN_ASSET(2) char map_grand_static_Blob_034F50[] = dmap_grand_static_Blob_034F50; +#define dgMapGrandStatic161Tex "__OTR__map_grand_static/gMapGrandStatic161Tex" +static const ALIGN_ASSET(2) char gMapGrandStatic161Tex[] = dgMapGrandStatic161Tex; #endif // ARCHIVES_MAP_GRAND_STATIC_H diff --git a/mm/assets/archives/map_i_static/map_i_static.h b/mm/assets/archives/map_i_static/map_i_static.h index 19ed8c541..2255b1939 100644 --- a/mm/assets/archives/map_i_static/map_i_static.h +++ b/mm/assets/archives/map_i_static/map_i_static.h @@ -3,177 +3,177 @@ #include "align_asset_macro.h" -#define dmap_i_static_Blob_000000 "__OTR__map_i_static/map_i_static_Blob_000000" -static const ALIGN_ASSET(2) char map_i_static_Blob_000000[] = dmap_i_static_Blob_000000; +#define dgMapIStatic00Tex "__OTR__map_i_static/gMapIStatic00Tex" +static const ALIGN_ASSET(2) char gMapIStatic00Tex[] = dgMapIStatic00Tex; -#define dmap_i_static_Blob_000FF0 "__OTR__map_i_static/map_i_static_Blob_000FF0" -static const ALIGN_ASSET(2) char map_i_static_Blob_000FF0[] = dmap_i_static_Blob_000FF0; +#define dgMapIStatic01Tex "__OTR__map_i_static/gMapIStatic01Tex" +static const ALIGN_ASSET(2) char gMapIStatic01Tex[] = dgMapIStatic01Tex; -#define dmap_i_static_Blob_001FE0 "__OTR__map_i_static/map_i_static_Blob_001FE0" -static const ALIGN_ASSET(2) char map_i_static_Blob_001FE0[] = dmap_i_static_Blob_001FE0; +#define dgMapIStatic02Tex "__OTR__map_i_static/gMapIStatic02Tex" +static const ALIGN_ASSET(2) char gMapIStatic02Tex[] = dgMapIStatic02Tex; -#define dmap_i_static_Blob_002FD0 "__OTR__map_i_static/map_i_static_Blob_002FD0" -static const ALIGN_ASSET(2) char map_i_static_Blob_002FD0[] = dmap_i_static_Blob_002FD0; +#define dgMapIStatic03Tex "__OTR__map_i_static/gMapIStatic03Tex" +static const ALIGN_ASSET(2) char gMapIStatic03Tex[] = dgMapIStatic03Tex; -#define dmap_i_static_Blob_003FC0 "__OTR__map_i_static/map_i_static_Blob_003FC0" -static const ALIGN_ASSET(2) char map_i_static_Blob_003FC0[] = dmap_i_static_Blob_003FC0; +#define dgMapIStatic04Tex "__OTR__map_i_static/gMapIStatic04Tex" +static const ALIGN_ASSET(2) char gMapIStatic04Tex[] = dgMapIStatic04Tex; -#define dmap_i_static_Blob_004FB0 "__OTR__map_i_static/map_i_static_Blob_004FB0" -static const ALIGN_ASSET(2) char map_i_static_Blob_004FB0[] = dmap_i_static_Blob_004FB0; +#define dgMapIStatic05Tex "__OTR__map_i_static/gMapIStatic05Tex" +static const ALIGN_ASSET(2) char gMapIStatic05Tex[] = dgMapIStatic05Tex; -#define dmap_i_static_Blob_005180 "__OTR__map_i_static/map_i_static_Blob_005180" -static const ALIGN_ASSET(2) char map_i_static_Blob_005180[] = dmap_i_static_Blob_005180; +#define dgMapIStatic06Tex "__OTR__map_i_static/gMapIStatic06Tex" +static const ALIGN_ASSET(2) char gMapIStatic06Tex[] = dgMapIStatic06Tex; -#define dmap_i_static_Blob_005330 "__OTR__map_i_static/map_i_static_Blob_005330" -static const ALIGN_ASSET(2) char map_i_static_Blob_005330[] = dmap_i_static_Blob_005330; +#define dgMapIStatic07Tex "__OTR__map_i_static/gMapIStatic07Tex" +static const ALIGN_ASSET(2) char gMapIStatic07Tex[] = dgMapIStatic07Tex; -#define dmap_i_static_Blob_005510 "__OTR__map_i_static/map_i_static_Blob_005510" -static const ALIGN_ASSET(2) char map_i_static_Blob_005510[] = dmap_i_static_Blob_005510; +#define dgMapIStatic08Tex "__OTR__map_i_static/gMapIStatic08Tex" +static const ALIGN_ASSET(2) char gMapIStatic08Tex[] = dgMapIStatic08Tex; -#define dmap_i_static_Blob_005610 "__OTR__map_i_static/map_i_static_Blob_005610" -static const ALIGN_ASSET(2) char map_i_static_Blob_005610[] = dmap_i_static_Blob_005610; +#define dgMapIStatic09Tex "__OTR__map_i_static/gMapIStatic09Tex" +static const ALIGN_ASSET(2) char gMapIStatic09Tex[] = dgMapIStatic09Tex; -#define dmap_i_static_Blob_005670 "__OTR__map_i_static/map_i_static_Blob_005670" -static const ALIGN_ASSET(2) char map_i_static_Blob_005670[] = dmap_i_static_Blob_005670; +#define dgMapIStatic0ATex "__OTR__map_i_static/gMapIStatic0ATex" +static const ALIGN_ASSET(2) char gMapIStatic0ATex[] = dgMapIStatic0ATex; -#define dmap_i_static_Blob_005820 "__OTR__map_i_static/map_i_static_Blob_005820" -static const ALIGN_ASSET(2) char map_i_static_Blob_005820[] = dmap_i_static_Blob_005820; +#define dgMapIStatic0BTex "__OTR__map_i_static/gMapIStatic0BTex" +static const ALIGN_ASSET(2) char gMapIStatic0BTex[] = dgMapIStatic0BTex; -#define dmap_i_static_Blob_005890 "__OTR__map_i_static/map_i_static_Blob_005890" -static const ALIGN_ASSET(2) char map_i_static_Blob_005890[] = dmap_i_static_Blob_005890; +#define dgMapIStatic0CTex "__OTR__map_i_static/gMapIStatic0CTex" +static const ALIGN_ASSET(2) char gMapIStatic0CTex[] = dgMapIStatic0CTex; -#define dmap_i_static_Blob_0059C0 "__OTR__map_i_static/map_i_static_Blob_0059C0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0059C0[] = dmap_i_static_Blob_0059C0; +#define dgMapIStatic0DTex "__OTR__map_i_static/gMapIStatic0DTex" +static const ALIGN_ASSET(2) char gMapIStatic0DTex[] = dgMapIStatic0DTex; -#define dmap_i_static_Blob_005B60 "__OTR__map_i_static/map_i_static_Blob_005B60" -static const ALIGN_ASSET(2) char map_i_static_Blob_005B60[] = dmap_i_static_Blob_005B60; +#define dgMapIStatic0ETex "__OTR__map_i_static/gMapIStatic0ETex" +static const ALIGN_ASSET(2) char gMapIStatic0ETex[] = dgMapIStatic0ETex; -#define dmap_i_static_Blob_005C60 "__OTR__map_i_static/map_i_static_Blob_005C60" -static const ALIGN_ASSET(2) char map_i_static_Blob_005C60[] = dmap_i_static_Blob_005C60; +#define dgMapIStatic0FTex "__OTR__map_i_static/gMapIStatic0FTex" +static const ALIGN_ASSET(2) char gMapIStatic0FTex[] = dgMapIStatic0FTex; -#define dmap_i_static_Blob_005E10 "__OTR__map_i_static/map_i_static_Blob_005E10" -static const ALIGN_ASSET(2) char map_i_static_Blob_005E10[] = dmap_i_static_Blob_005E10; +#define dgMapIStatic10Tex "__OTR__map_i_static/gMapIStatic10Tex" +static const ALIGN_ASSET(2) char gMapIStatic10Tex[] = dgMapIStatic10Tex; -#define dmap_i_static_Blob_005F30 "__OTR__map_i_static/map_i_static_Blob_005F30" -static const ALIGN_ASSET(2) char map_i_static_Blob_005F30[] = dmap_i_static_Blob_005F30; +#define dgMapIStatic11Tex "__OTR__map_i_static/gMapIStatic11Tex" +static const ALIGN_ASSET(2) char gMapIStatic11Tex[] = dgMapIStatic11Tex; -#define dmap_i_static_Blob_006050 "__OTR__map_i_static/map_i_static_Blob_006050" -static const ALIGN_ASSET(2) char map_i_static_Blob_006050[] = dmap_i_static_Blob_006050; +#define dgMapIStatic12Tex "__OTR__map_i_static/gMapIStatic12Tex" +static const ALIGN_ASSET(2) char gMapIStatic12Tex[] = dgMapIStatic12Tex; -#define dmap_i_static_Blob_0062B0 "__OTR__map_i_static/map_i_static_Blob_0062B0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0062B0[] = dmap_i_static_Blob_0062B0; +#define dgMapIStatic13Tex "__OTR__map_i_static/gMapIStatic13Tex" +static const ALIGN_ASSET(2) char gMapIStatic13Tex[] = dgMapIStatic13Tex; -#define dmap_i_static_Blob_006400 "__OTR__map_i_static/map_i_static_Blob_006400" -static const ALIGN_ASSET(2) char map_i_static_Blob_006400[] = dmap_i_static_Blob_006400; +#define dgMapIStatic14Tex "__OTR__map_i_static/gMapIStatic14Tex" +static const ALIGN_ASSET(2) char gMapIStatic14Tex[] = dgMapIStatic14Tex; -#define dmap_i_static_Blob_006620 "__OTR__map_i_static/map_i_static_Blob_006620" -static const ALIGN_ASSET(2) char map_i_static_Blob_006620[] = dmap_i_static_Blob_006620; +#define dgMapIStatic15Tex "__OTR__map_i_static/gMapIStatic15Tex" +static const ALIGN_ASSET(2) char gMapIStatic15Tex[] = dgMapIStatic15Tex; -#define dmap_i_static_Blob_006920 "__OTR__map_i_static/map_i_static_Blob_006920" -static const ALIGN_ASSET(2) char map_i_static_Blob_006920[] = dmap_i_static_Blob_006920; +#define dgMapIStatic16Tex "__OTR__map_i_static/gMapIStatic16Tex" +static const ALIGN_ASSET(2) char gMapIStatic16Tex[] = dgMapIStatic16Tex; -#define dmap_i_static_Blob_006A30 "__OTR__map_i_static/map_i_static_Blob_006A30" -static const ALIGN_ASSET(2) char map_i_static_Blob_006A30[] = dmap_i_static_Blob_006A30; +#define dgMapIStatic17Tex "__OTR__map_i_static/gMapIStatic17Tex" +static const ALIGN_ASSET(2) char gMapIStatic17Tex[] = dgMapIStatic17Tex; -#define dmap_i_static_Blob_006B40 "__OTR__map_i_static/map_i_static_Blob_006B40" -static const ALIGN_ASSET(2) char map_i_static_Blob_006B40[] = dmap_i_static_Blob_006B40; +#define dgMapIStatic18Tex "__OTR__map_i_static/gMapIStatic18Tex" +static const ALIGN_ASSET(2) char gMapIStatic18Tex[] = dgMapIStatic18Tex; -#define dmap_i_static_Blob_006C90 "__OTR__map_i_static/map_i_static_Blob_006C90" -static const ALIGN_ASSET(2) char map_i_static_Blob_006C90[] = dmap_i_static_Blob_006C90; +#define dgMapIStatic19Tex "__OTR__map_i_static/gMapIStatic19Tex" +static const ALIGN_ASSET(2) char gMapIStatic19Tex[] = dgMapIStatic19Tex; -#define dmap_i_static_Blob_006DB0 "__OTR__map_i_static/map_i_static_Blob_006DB0" -static const ALIGN_ASSET(2) char map_i_static_Blob_006DB0[] = dmap_i_static_Blob_006DB0; +#define dgMapIStatic1ATex "__OTR__map_i_static/gMapIStatic1ATex" +static const ALIGN_ASSET(2) char gMapIStatic1ATex[] = dgMapIStatic1ATex; -#define dmap_i_static_Blob_006E70 "__OTR__map_i_static/map_i_static_Blob_006E70" -static const ALIGN_ASSET(2) char map_i_static_Blob_006E70[] = dmap_i_static_Blob_006E70; +#define dgMapIStatic1BTex "__OTR__map_i_static/gMapIStatic1BTex" +static const ALIGN_ASSET(2) char gMapIStatic1BTex[] = dgMapIStatic1BTex; -#define dmap_i_static_Blob_006F40 "__OTR__map_i_static/map_i_static_Blob_006F40" -static const ALIGN_ASSET(2) char map_i_static_Blob_006F40[] = dmap_i_static_Blob_006F40; +#define dgMapIStatic1CTex "__OTR__map_i_static/gMapIStatic1CTex" +static const ALIGN_ASSET(2) char gMapIStatic1CTex[] = dgMapIStatic1CTex; -#define dmap_i_static_Blob_007170 "__OTR__map_i_static/map_i_static_Blob_007170" -static const ALIGN_ASSET(2) char map_i_static_Blob_007170[] = dmap_i_static_Blob_007170; +#define dgMapIStatic1DTex "__OTR__map_i_static/gMapIStatic1DTex" +static const ALIGN_ASSET(2) char gMapIStatic1DTex[] = dgMapIStatic1DTex; -#define dmap_i_static_Blob_007210 "__OTR__map_i_static/map_i_static_Blob_007210" -static const ALIGN_ASSET(2) char map_i_static_Blob_007210[] = dmap_i_static_Blob_007210; +#define dgMapIStatic1ETex "__OTR__map_i_static/gMapIStatic1ETex" +static const ALIGN_ASSET(2) char gMapIStatic1ETex[] = dgMapIStatic1ETex; -#define dmap_i_static_Blob_0073D0 "__OTR__map_i_static/map_i_static_Blob_0073D0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0073D0[] = dmap_i_static_Blob_0073D0; +#define dgMapIStatic1FTex "__OTR__map_i_static/gMapIStatic1FTex" +static const ALIGN_ASSET(2) char gMapIStatic1FTex[] = dgMapIStatic1FTex; -#define dmap_i_static_Blob_0074D0 "__OTR__map_i_static/map_i_static_Blob_0074D0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0074D0[] = dmap_i_static_Blob_0074D0; +#define dgMapIStatic20Tex "__OTR__map_i_static/gMapIStatic20Tex" +static const ALIGN_ASSET(2) char gMapIStatic20Tex[] = dgMapIStatic20Tex; -#define dmap_i_static_Blob_007650 "__OTR__map_i_static/map_i_static_Blob_007650" -static const ALIGN_ASSET(2) char map_i_static_Blob_007650[] = dmap_i_static_Blob_007650; +#define dgMapIStatic21Tex "__OTR__map_i_static/gMapIStatic21Tex" +static const ALIGN_ASSET(2) char gMapIStatic21Tex[] = dgMapIStatic21Tex; -#define dmap_i_static_Blob_0077A0 "__OTR__map_i_static/map_i_static_Blob_0077A0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0077A0[] = dmap_i_static_Blob_0077A0; +#define dgMapIStatic22Tex "__OTR__map_i_static/gMapIStatic22Tex" +static const ALIGN_ASSET(2) char gMapIStatic22Tex[] = dgMapIStatic22Tex; -#define dmap_i_static_Blob_007850 "__OTR__map_i_static/map_i_static_Blob_007850" -static const ALIGN_ASSET(2) char map_i_static_Blob_007850[] = dmap_i_static_Blob_007850; +#define dgMapIStatic23Tex "__OTR__map_i_static/gMapIStatic23Tex" +static const ALIGN_ASSET(2) char gMapIStatic23Tex[] = dgMapIStatic23Tex; -#define dmap_i_static_Blob_0078A0 "__OTR__map_i_static/map_i_static_Blob_0078A0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0078A0[] = dmap_i_static_Blob_0078A0; +#define dgMapIStatic24Tex "__OTR__map_i_static/gMapIStatic24Tex" +static const ALIGN_ASSET(2) char gMapIStatic24Tex[] = dgMapIStatic24Tex; -#define dmap_i_static_Blob_0078E0 "__OTR__map_i_static/map_i_static_Blob_0078E0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0078E0[] = dmap_i_static_Blob_0078E0; +#define dgMapIStatic25Tex "__OTR__map_i_static/gMapIStatic25Tex" +static const ALIGN_ASSET(2) char gMapIStatic25Tex[] = dgMapIStatic25Tex; -#define dmap_i_static_Blob_007A50 "__OTR__map_i_static/map_i_static_Blob_007A50" -static const ALIGN_ASSET(2) char map_i_static_Blob_007A50[] = dmap_i_static_Blob_007A50; +#define dgMapIStatic26Tex "__OTR__map_i_static/gMapIStatic26Tex" +static const ALIGN_ASSET(2) char gMapIStatic26Tex[] = dgMapIStatic26Tex; -#define dmap_i_static_Blob_007AD0 "__OTR__map_i_static/map_i_static_Blob_007AD0" -static const ALIGN_ASSET(2) char map_i_static_Blob_007AD0[] = dmap_i_static_Blob_007AD0; +#define dgMapIStatic27Tex "__OTR__map_i_static/gMapIStatic27Tex" +static const ALIGN_ASSET(2) char gMapIStatic27Tex[] = dgMapIStatic27Tex; -#define dmap_i_static_Blob_007B60 "__OTR__map_i_static/map_i_static_Blob_007B60" -static const ALIGN_ASSET(2) char map_i_static_Blob_007B60[] = dmap_i_static_Blob_007B60; +#define dgMapIStatic28Tex "__OTR__map_i_static/gMapIStatic28Tex" +static const ALIGN_ASSET(2) char gMapIStatic28Tex[] = dgMapIStatic28Tex; -#define dmap_i_static_Blob_007C20 "__OTR__map_i_static/map_i_static_Blob_007C20" -static const ALIGN_ASSET(2) char map_i_static_Blob_007C20[] = dmap_i_static_Blob_007C20; +#define dgMapIStatic29Tex "__OTR__map_i_static/gMapIStatic29Tex" +static const ALIGN_ASSET(2) char gMapIStatic29Tex[] = dgMapIStatic29Tex; -#define dmap_i_static_Blob_007CA0 "__OTR__map_i_static/map_i_static_Blob_007CA0" -static const ALIGN_ASSET(2) char map_i_static_Blob_007CA0[] = dmap_i_static_Blob_007CA0; +#define dgMapIStatic2ATex "__OTR__map_i_static/gMapIStatic2ATex" +static const ALIGN_ASSET(2) char gMapIStatic2ATex[] = dgMapIStatic2ATex; -#define dmap_i_static_Blob_007D90 "__OTR__map_i_static/map_i_static_Blob_007D90" -static const ALIGN_ASSET(2) char map_i_static_Blob_007D90[] = dmap_i_static_Blob_007D90; +#define dgMapIStatic2BTex "__OTR__map_i_static/gMapIStatic2BTex" +static const ALIGN_ASSET(2) char gMapIStatic2BTex[] = dgMapIStatic2BTex; -#define dmap_i_static_Blob_007EA0 "__OTR__map_i_static/map_i_static_Blob_007EA0" -static const ALIGN_ASSET(2) char map_i_static_Blob_007EA0[] = dmap_i_static_Blob_007EA0; +#define dgMapIStatic2CTex "__OTR__map_i_static/gMapIStatic2CTex" +static const ALIGN_ASSET(2) char gMapIStatic2CTex[] = dgMapIStatic2CTex; -#define dmap_i_static_Blob_007FA0 "__OTR__map_i_static/map_i_static_Blob_007FA0" -static const ALIGN_ASSET(2) char map_i_static_Blob_007FA0[] = dmap_i_static_Blob_007FA0; +#define dgMapIStatic2DTex "__OTR__map_i_static/gMapIStatic2DTex" +static const ALIGN_ASSET(2) char gMapIStatic2DTex[] = dgMapIStatic2DTex; -#define dmap_i_static_Blob_007FF0 "__OTR__map_i_static/map_i_static_Blob_007FF0" -static const ALIGN_ASSET(2) char map_i_static_Blob_007FF0[] = dmap_i_static_Blob_007FF0; +#define dgMapIStatic2ETex "__OTR__map_i_static/gMapIStatic2ETex" +static const ALIGN_ASSET(2) char gMapIStatic2ETex[] = dgMapIStatic2ETex; -#define dmap_i_static_Blob_008080 "__OTR__map_i_static/map_i_static_Blob_008080" -static const ALIGN_ASSET(2) char map_i_static_Blob_008080[] = dmap_i_static_Blob_008080; +#define dgMapIStatic2FTex "__OTR__map_i_static/gMapIStatic2FTex" +static const ALIGN_ASSET(2) char gMapIStatic2FTex[] = dgMapIStatic2FTex; -#define dmap_i_static_Blob_008190 "__OTR__map_i_static/map_i_static_Blob_008190" -static const ALIGN_ASSET(2) char map_i_static_Blob_008190[] = dmap_i_static_Blob_008190; +#define dgMapIStatic30Tex "__OTR__map_i_static/gMapIStatic30Tex" +static const ALIGN_ASSET(2) char gMapIStatic30Tex[] = dgMapIStatic30Tex; -#define dmap_i_static_Blob_0081F0 "__OTR__map_i_static/map_i_static_Blob_0081F0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0081F0[] = dmap_i_static_Blob_0081F0; +#define dgMapIStatic31Tex "__OTR__map_i_static/gMapIStatic31Tex" +static const ALIGN_ASSET(2) char gMapIStatic31Tex[] = dgMapIStatic31Tex; -#define dmap_i_static_Blob_008300 "__OTR__map_i_static/map_i_static_Blob_008300" -static const ALIGN_ASSET(2) char map_i_static_Blob_008300[] = dmap_i_static_Blob_008300; +#define dgMapIStatic32Tex "__OTR__map_i_static/gMapIStatic32Tex" +static const ALIGN_ASSET(2) char gMapIStatic32Tex[] = dgMapIStatic32Tex; -#define dmap_i_static_Blob_008360 "__OTR__map_i_static/map_i_static_Blob_008360" -static const ALIGN_ASSET(2) char map_i_static_Blob_008360[] = dmap_i_static_Blob_008360; +#define dgMapIStatic33Tex "__OTR__map_i_static/gMapIStatic33Tex" +static const ALIGN_ASSET(2) char gMapIStatic33Tex[] = dgMapIStatic33Tex; -#define dmap_i_static_Blob_0083F0 "__OTR__map_i_static/map_i_static_Blob_0083F0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0083F0[] = dmap_i_static_Blob_0083F0; +#define dgMapIStatic34Tex "__OTR__map_i_static/gMapIStatic34Tex" +static const ALIGN_ASSET(2) char gMapIStatic34Tex[] = dgMapIStatic34Tex; -#define dmap_i_static_Blob_008500 "__OTR__map_i_static/map_i_static_Blob_008500" -static const ALIGN_ASSET(2) char map_i_static_Blob_008500[] = dmap_i_static_Blob_008500; +#define dgMapIStatic35Tex "__OTR__map_i_static/gMapIStatic35Tex" +static const ALIGN_ASSET(2) char gMapIStatic35Tex[] = dgMapIStatic35Tex; -#define dmap_i_static_Blob_0085F0 "__OTR__map_i_static/map_i_static_Blob_0085F0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0085F0[] = dmap_i_static_Blob_0085F0; +#define dgMapIStatic36Tex "__OTR__map_i_static/gMapIStatic36Tex" +static const ALIGN_ASSET(2) char gMapIStatic36Tex[] = dgMapIStatic36Tex; -#define dmap_i_static_Blob_008680 "__OTR__map_i_static/map_i_static_Blob_008680" -static const ALIGN_ASSET(2) char map_i_static_Blob_008680[] = dmap_i_static_Blob_008680; +#define dgMapIStatic37Tex "__OTR__map_i_static/gMapIStatic37Tex" +static const ALIGN_ASSET(2) char gMapIStatic37Tex[] = dgMapIStatic37Tex; -#define dmap_i_static_Blob_008700 "__OTR__map_i_static/map_i_static_Blob_008700" -static const ALIGN_ASSET(2) char map_i_static_Blob_008700[] = dmap_i_static_Blob_008700; +#define dgMapIStatic38Tex "__OTR__map_i_static/gMapIStatic38Tex" +static const ALIGN_ASSET(2) char gMapIStatic38Tex[] = dgMapIStatic38Tex; -#define dmap_i_static_Blob_0087F0 "__OTR__map_i_static/map_i_static_Blob_0087F0" -static const ALIGN_ASSET(2) char map_i_static_Blob_0087F0[] = dmap_i_static_Blob_0087F0; +#define dgMapIStatic39Tex "__OTR__map_i_static/gMapIStatic39Tex" +static const ALIGN_ASSET(2) char gMapIStatic39Tex[] = dgMapIStatic39Tex; #endif // ARCHIVES_MAP_I_STATIC_H diff --git a/mm/assets/xml/GC_US/archives/map_grand_static.xml b/mm/assets/xml/GC_US/archives/map_grand_static.xml index 94e51b350..5aac6a2ce 100644 --- a/mm/assets/xml/GC_US/archives/map_grand_static.xml +++ b/mm/assets/xml/GC_US/archives/map_grand_static.xml @@ -1,102 +1,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mm/assets/xml/GC_US/archives/map_i_static.xml b/mm/assets/xml/GC_US/archives/map_i_static.xml index 15e1a4348..d625d3173 100644 --- a/mm/assets/xml/GC_US/archives/map_i_static.xml +++ b/mm/assets/xml/GC_US/archives/map_i_static.xml @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mm/assets/xml/N64_US/archives/map_grand_static.xml b/mm/assets/xml/N64_US/archives/map_grand_static.xml index 94e51b350..5aac6a2ce 100644 --- a/mm/assets/xml/N64_US/archives/map_grand_static.xml +++ b/mm/assets/xml/N64_US/archives/map_grand_static.xml @@ -1,102 +1,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mm/assets/xml/N64_US/archives/map_i_static.xml b/mm/assets/xml/N64_US/archives/map_i_static.xml index 15e1a4348..d625d3173 100644 --- a/mm/assets/xml/N64_US/archives/map_i_static.xml +++ b/mm/assets/xml/N64_US/archives/map_i_static.xml @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mm/src/code/z_map_disp.c b/mm/src/code/z_map_disp.c index 6f2ce25fb..7ed312f3a 100644 --- a/mm/src/code/z_map_disp.c +++ b/mm/src/code/z_map_disp.c @@ -9,6 +9,7 @@ #include "BenPort.h" #include "BenGui/HudEditor.h" +#include "assets/2s2h_assets.h" void MapDisp_DestroyMapI(PlayState* play); void MapDisp_InitMapI(PlayState* play); @@ -102,58 +103,41 @@ static Color_RGBA8 sMinimapActorCategoryColors[12] = { TransitionActorEntry sTransitionActors[ROOM_TRANSITION_MAX]; PauseDungeonMap sPauseDungeonMap; -static const char* sMapTextures[] = { - map_i_static_Blob_000000, map_i_static_Blob_000FF0, map_i_static_Blob_001FE0, map_i_static_Blob_002FD0, - map_i_static_Blob_003FC0, map_i_static_Blob_004FB0, map_i_static_Blob_005180, map_i_static_Blob_005330, - map_i_static_Blob_005510, map_i_static_Blob_005610, map_i_static_Blob_005670, map_i_static_Blob_005820, - map_i_static_Blob_005890, map_i_static_Blob_0059C0, map_i_static_Blob_005B60, map_i_static_Blob_005C60, - map_i_static_Blob_005E10, map_i_static_Blob_005F30, map_i_static_Blob_006050, map_i_static_Blob_0062B0, - map_i_static_Blob_006400, map_i_static_Blob_006620, map_i_static_Blob_006920, map_i_static_Blob_006A30, - map_i_static_Blob_006B40, map_i_static_Blob_006C90, map_i_static_Blob_006DB0, map_i_static_Blob_006E70, - map_i_static_Blob_006F40, map_i_static_Blob_007170, map_i_static_Blob_007210, map_i_static_Blob_0073D0, - map_i_static_Blob_0074D0, map_i_static_Blob_007650, map_i_static_Blob_0077A0, map_i_static_Blob_007850, - map_i_static_Blob_0078A0, map_i_static_Blob_0078E0, map_i_static_Blob_007A50, map_i_static_Blob_007AD0, - map_i_static_Blob_007B60, map_i_static_Blob_007C20, map_i_static_Blob_007CA0, map_i_static_Blob_007D90, - map_i_static_Blob_007EA0, map_i_static_Blob_007FA0, map_i_static_Blob_007FF0, map_i_static_Blob_008080, - map_i_static_Blob_008190, map_i_static_Blob_0081F0, map_i_static_Blob_008300, map_i_static_Blob_008360, - map_i_static_Blob_0083F0, map_i_static_Blob_008500, map_i_static_Blob_0085F0, map_i_static_Blob_008680, - map_i_static_Blob_008700, map_i_static_Blob_0087F0, +// 2S2H [Port] Textures maps and extra variables for enhancement features +static TexturePtr sMapITextures[] = { + gMapIStatic00Tex, gMapIStatic01Tex, gMapIStatic02Tex, gMapIStatic03Tex, gMapIStatic04Tex, gMapIStatic05Tex, + gMapIStatic06Tex, gMapIStatic07Tex, gMapIStatic08Tex, gMapIStatic09Tex, gMapIStatic0ATex, gMapIStatic0BTex, + gMapIStatic0CTex, gMapIStatic0DTex, gMapIStatic0ETex, gMapIStatic0FTex, gMapIStatic10Tex, gMapIStatic11Tex, + gMapIStatic12Tex, gMapIStatic13Tex, gMapIStatic14Tex, gMapIStatic15Tex, gMapIStatic16Tex, gMapIStatic17Tex, + gMapIStatic18Tex, gMapIStatic19Tex, gMapIStatic1ATex, gMapIStatic1BTex, gMapIStatic1CTex, gMapIStatic1DTex, + gMapIStatic1ETex, gMapIStatic1FTex, gMapIStatic20Tex, gMapIStatic21Tex, gMapIStatic22Tex, gMapIStatic23Tex, + gMapIStatic24Tex, gMapIStatic25Tex, gMapIStatic26Tex, gMapIStatic27Tex, gMapIStatic28Tex, gMapIStatic29Tex, + gMapIStatic2ATex, gMapIStatic2BTex, gMapIStatic2CTex, gMapIStatic2DTex, gMapIStatic2ETex, gMapIStatic2FTex, + gMapIStatic30Tex, gMapIStatic31Tex, gMapIStatic32Tex, gMapIStatic33Tex, gMapIStatic34Tex, gMapIStatic35Tex, + gMapIStatic36Tex, gMapIStatic37Tex, gMapIStatic38Tex, gMapIStatic39Tex, }; -static const char* sMapGrandTextures[] = { - map_grand_static_Blob_000000, map_grand_static_Blob_000FF0, map_grand_static_Blob_001FE0, - map_grand_static_Blob_002FD0, map_grand_static_Blob_003FC0, map_grand_static_Blob_004FB0, - map_grand_static_Blob_005AF0, map_grand_static_Blob_006AE0, map_grand_static_Blob_007AD0, - map_grand_static_Blob_008AC0, map_grand_static_Blob_009AB0, map_grand_static_Blob_009ED0, - map_grand_static_Blob_00AEC0, map_grand_static_Blob_00B310, map_grand_static_Blob_00BAB0, - map_grand_static_Blob_00CAA0, map_grand_static_Blob_00DA90, map_grand_static_Blob_00EA80, - map_grand_static_Blob_00F200, map_grand_static_Blob_00FA00, map_grand_static_Blob_010250, - map_grand_static_Blob_010760, map_grand_static_Blob_010E70, map_grand_static_Blob_011950, - map_grand_static_Blob_011FB0, map_grand_static_Blob_012C10, map_grand_static_Blob_013A20, - map_grand_static_Blob_013E00, map_grand_static_Blob_0143A0, map_grand_static_Blob_014BC0, - map_grand_static_Blob_015000, map_grand_static_Blob_015590, map_grand_static_Blob_015B30, - map_grand_static_Blob_0162D0, map_grand_static_Blob_016A70, map_grand_static_Blob_017860, - map_grand_static_Blob_0180B0, map_grand_static_Blob_018A70, map_grand_static_Blob_0192F0, - map_grand_static_Blob_019950, map_grand_static_Blob_019CB0, map_grand_static_Blob_019F10, - map_grand_static_Blob_01A870, map_grand_static_Blob_01ABC0, map_grand_static_Blob_01B570, - map_grand_static_Blob_01BEF0, map_grand_static_Blob_01CEE0, map_grand_static_Blob_01DA00, - map_grand_static_Blob_01E7A0, map_grand_static_Blob_01EFC0, map_grand_static_Blob_01F3A0, - map_grand_static_Blob_01FD20, map_grand_static_Blob_020680, map_grand_static_Blob_020DE0, - map_grand_static_Blob_021740, map_grand_static_Blob_021910, map_grand_static_Blob_021F40, - map_grand_static_Blob_0225C0, map_grand_static_Blob_022D90, map_grand_static_Blob_023600, - map_grand_static_Blob_024460, map_grand_static_Blob_024B70, map_grand_static_Blob_025190, - map_grand_static_Blob_0257B0, map_grand_static_Blob_025E30, map_grand_static_Blob_026450, - map_grand_static_Blob_026660, map_grand_static_Blob_026B10, map_grand_static_Blob_027190, - map_grand_static_Blob_0274E0, map_grand_static_Blob_027B40, map_grand_static_Blob_027E90, - map_grand_static_Blob_028390, map_grand_static_Blob_028A30, map_grand_static_Blob_029010, - map_grand_static_Blob_029690, map_grand_static_Blob_029B10, map_grand_static_Blob_02A5F0, - map_grand_static_Blob_02A8C0, map_grand_static_Blob_02B450, map_grand_static_Blob_02C1F0, - map_grand_static_Blob_02CAB0, map_grand_static_Blob_02D4E0, map_grand_static_Blob_02D610, - map_grand_static_Blob_02E240, map_grand_static_Blob_02EAE0, map_grand_static_Blob_02FA30, - map_grand_static_Blob_0303E0, map_grand_static_Blob_030B90, map_grand_static_Blob_0314F0, - map_grand_static_Blob_031C30, map_grand_static_Blob_032630, map_grand_static_Blob_032C70, - map_grand_static_Blob_0336A0, map_grand_static_Blob_033A70, map_grand_static_Blob_034770, - map_grand_static_Blob_034BB0, map_grand_static_Blob_034F50, +static TexturePtr sMapGrandTextures[] = { + gMapGrandStatic100Tex, gMapGrandStatic101Tex, gMapGrandStatic102Tex, gMapGrandStatic103Tex, gMapGrandStatic104Tex, + gMapGrandStatic105Tex, gMapGrandStatic106Tex, gMapGrandStatic107Tex, gMapGrandStatic108Tex, gMapGrandStatic109Tex, + gMapGrandStatic10ATex, gMapGrandStatic10BTex, gMapGrandStatic10CTex, gMapGrandStatic10DTex, gMapGrandStatic10ETex, + gMapGrandStatic10FTex, gMapGrandStatic110Tex, gMapGrandStatic111Tex, gMapGrandStatic112Tex, gMapGrandStatic113Tex, + gMapGrandStatic114Tex, gMapGrandStatic115Tex, gMapGrandStatic116Tex, gMapGrandStatic117Tex, gMapGrandStatic118Tex, + gMapGrandStatic119Tex, gMapGrandStatic11ATex, gMapGrandStatic11BTex, gMapGrandStatic11CTex, gMapGrandStatic11DTex, + gMapGrandStatic11ETex, gMapGrandStatic11FTex, gMapGrandStatic120Tex, gMapGrandStatic121Tex, gMapGrandStatic122Tex, + gMapGrandStatic123Tex, gMapGrandStatic124Tex, gMapGrandStatic125Tex, gMapGrandStatic126Tex, gMapGrandStatic127Tex, + gMapGrandStatic128Tex, gMapGrandStatic129Tex, gMapGrandStatic12ATex, gMapGrandStatic12BTex, gMapGrandStatic12CTex, + gMapGrandStatic12DTex, gMapGrandStatic12ETex, gMapGrandStatic12FTex, gMapGrandStatic130Tex, gMapGrandStatic131Tex, + gMapGrandStatic132Tex, gMapGrandStatic133Tex, gMapGrandStatic134Tex, gMapGrandStatic135Tex, gMapGrandStatic136Tex, + gMapGrandStatic137Tex, gMapGrandStatic138Tex, gMapGrandStatic139Tex, gMapGrandStatic13ATex, gMapGrandStatic13BTex, + gMapGrandStatic13CTex, gMapGrandStatic13DTex, gMapGrandStatic13ETex, gMapGrandStatic13FTex, gMapGrandStatic140Tex, + gMapGrandStatic141Tex, gMapGrandStatic142Tex, gMapGrandStatic143Tex, gMapGrandStatic144Tex, gMapGrandStatic145Tex, + gMapGrandStatic146Tex, gMapGrandStatic147Tex, gMapGrandStatic148Tex, gMapGrandStatic149Tex, gMapGrandStatic14ATex, + gMapGrandStatic14BTex, gMapGrandStatic14CTex, gMapGrandStatic14DTex, gMapGrandStatic14ETex, gMapGrandStatic14FTex, + gMapGrandStatic150Tex, gMapGrandStatic151Tex, gMapGrandStatic152Tex, gMapGrandStatic153Tex, gMapGrandStatic154Tex, + gMapGrandStatic155Tex, gMapGrandStatic156Tex, gMapGrandStatic157Tex, gMapGrandStatic158Tex, gMapGrandStatic159Tex, + gMapGrandStatic15ATex, gMapGrandStatic15BTex, gMapGrandStatic15CTex, gMapGrandStatic15DTex, gMapGrandStatic15ETex, + gMapGrandStatic15FTex, gMapGrandStatic160Tex, gMapGrandStatic161Tex, }; static bool sMirrorWorldActive = false; @@ -181,13 +165,17 @@ void Ship_MapDispUpdateMirrorMode() { } } -// BENTODO, can we just set dest insetead of doing a memcpy? -void MapDisp_GetMapITexture(void* dst, s32 mapCompactId) { +// 2S2H [Port] Changed dest to double pointer for assigning texture path string instead of Dma load +void MapDisp_GetMapITexture(void** dst, s32 mapCompactId) { s32 mapSize = MapDisp_GetSizeOfMapITex(mapCompactId); - if (mapSize != 0) { - void* data = ResourceMgr_LoadTexOrDListByName(sMapTextures[mapCompactId]); - memcpy(dst, data, mapSize); + if (MapDisp_GetSizeOfMapITex(mapCompactId) != 0) { + if (mapCompactId < ARRAY_COUNT(sMapITextures)) { + *dst = sMapITextures[mapCompactId]; + } else { + *dst = gEmptyTexture; + } + // CmpDma_LoadFile(SEGMENT_ROM_START(map_i_static), mapCompactId, dst, MapDisp_GetSizeOfMapITex(mapCompactId)); } } @@ -1224,8 +1212,15 @@ void MapDisp_SwapRooms(s16 nextRoom) { sMapDisp.minimapCurTex = sMapDisp.texBuff0; } if (MapData_GetSizeOfMapGrandTex(nextMapDataRoom->mapId) != 0) { - sMapDisp.minimapCurTex = ResourceMgr_LoadTexOrDListByName( - sMapGrandTextures[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(nextMapDataRoom->mapId)]); + // 2S2H [Port] Assign texture path string instead of a Dma load + if (MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(nextMapDataRoom->mapId) < + ARRAY_COUNTU(sMapGrandTextures)) { + sMapDisp.minimapCurTex = + sMapGrandTextures[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(nextMapDataRoom->mapId)]; + } else { + sMapDisp.minimapCurTex = gEmptyTexture; + } + // CmpDma_LoadFile(SEGMENT_ROM_START(map_grand_static), // MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(nextMapDataRoom->mapId), // sMapDisp.minimapCurTex, @@ -1481,8 +1476,8 @@ void* MapDisp_AllocDungeonMap(PlayState* play, void* heap) { for (dungeonMapRoomIter = 0; dungeonMapRoomIter < sPauseDungeonMap.textureCount; dungeonMapRoomIter++) { s32 mapCompactId = sPauseDungeonMap.mapI_mapCompactId[dungeonMapRoomIter]; - // 2S2H [Port] directly set the pointer to the texture instead of using memcpy - MapDisp_GetMapITexture(sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter], mapCompactId); + // 2S2H [Port] Pass the pointer of the array element to directly set texture + MapDisp_GetMapITexture(&sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter], mapCompactId); if (dungeonMapRoomIter + 1 < sPauseDungeonMap.textureCount) { sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter + 1] = ALIGN16((intptr_t)sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter] + From b7d7a2d9bfd063d7b7ef0cc499343985f5be1f1d Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:26:13 -0600 Subject: [PATCH 64/82] [Enhancement] Add option to always get the Cremia Hug Cutscene after completing the milk run (#688) * Cremia always gives hugs after getting Romani Mask. Adds enhancement option but the option doesn't change anything yet * moved cremia enhancement out of cutscene files * hook works now * change enhancement to picklist * cleaned conditional * move to minigame section and add modern menu item * clang format --- mm/2s2h/BenGui/BenMenuBar.cpp | 13 +++++++++++++ mm/2s2h/BenGui/SearchableMenuItems.h | 14 ++++++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Enhancements.h | 6 ++++++ mm/2s2h/Enhancements/Minigames/CremiaHugs.cpp | 18 ++++++++++++++++++ mm/2s2h/Enhancements/Minigames/Minigames.h | 2 ++ mm/2s2h/GameInteractor/GameInteractor.h | 1 + .../actors/ovl_En_Ma_Yto/z_en_ma_yto.c | 5 ++++- 8 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/Minigames/CremiaHugs.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index f987b312b..6c329fe8e 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -52,6 +52,12 @@ static const std::unordered_map alwaysWinDoggyraceOptions { ALWAYS_WIN_DOGGY_RACE_ALWAYS, "Always" }, }; +static const std::unordered_map cremiaRewardOptions = { + { CREMIA_REWARD_RANDOM, "Vanilla" }, + { CREMIA_REWARD_ALWAYS_HUG, "Hug" }, + { CREMIA_REWARD_ALWAYS_RUPEE, "Rupee" }, +}; + static const std::unordered_map timeStopOptions = { { TIME_STOP_OFF, "Off" }, { TIME_STOP_TEMPLES, "Temples" }, @@ -665,6 +671,13 @@ void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Minigames")) { UIWidgets::CVarCombobox("Always Win Doggy Race", "gEnhancements.Minigames.AlwaysWinDoggyRace", alwaysWinDoggyraceOptions); + UIWidgets::CVarCombobox( + "Milk Run Reward Options", "gEnhancements.Minigames.CremiaHugs", cremiaRewardOptions, + { .tooltip = "Choose what reward you get for winning the Milk Run minigame after the first time. \n" + "-Vanilla: Reward is Random\n" + "-Hug: Get the hugging cutscene\n" + "-Rupee: Get the rupee reward", + .defaultIndex = CREMIA_REWARD_RANDOM }); ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index a6caf6df4..8325ff7a5 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -363,6 +363,12 @@ static const std::unordered_map alwaysWinDoggyraceOptions { ALWAYS_WIN_DOGGY_RACE_ALWAYS, "Always" }, }; +static const std::unordered_map cremiaRewardOptions = { + { CREMIA_REWARD_RANDOM, "Vanilla" }, + { CREMIA_REWARD_ALWAYS_HUG, "Hug" }, + { CREMIA_REWARD_ALWAYS_RUPEE, "Rupee" }, +}; + static const std::unordered_map clockTypeOptions = { { CLOCK_TYPE_ORIGINAL, "Original" }, { CLOCK_TYPE_3DS, "MM3D style" }, @@ -1001,6 +1007,14 @@ void AddEnhancements() { "Makes the Doggy Race easier to win.", WIDGET_CVAR_COMBOBOX, { .comboBoxOptions = alwaysWinDoggyraceOptions } }, + { "Milk Run Reward Options", + "gEnhancements.Minigames.CremiaHugs", + "Choose what reward you get for winning the Milk Run minigame after the first time. \n" + "-Vanilla: Reward is Random\n" + "-Hug: Get the hugging cutscene\n" + "-Rupee: Get the rupee reward", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = cremiaRewardOptions } }, { "Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", "Removes the animation for equipping Magic Arrows.", WIDGET_CVAR_CHECKBOX }, { "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 4b90ac954..c8f31b28c 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -47,6 +47,7 @@ void InitEnhancements() { // Minigames RegisterAlwaysWinDoggyRace(); + RegisterCremiaHugs(); // Player RegisterClimbSpeed(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 5abf01fc6..aaee6c43c 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -36,6 +36,12 @@ enum ClockTypeOptions { CLOCK_TYPE_TEXT_BASED, }; +enum CremiaRewardsOptions { + CREMIA_REWARD_RANDOM, + CREMIA_REWARD_ALWAYS_HUG, + CREMIA_REWARD_ALWAYS_RUPEE, +}; + #ifdef __cplusplus extern "C" { #endif diff --git a/mm/2s2h/Enhancements/Minigames/CremiaHugs.cpp b/mm/2s2h/Enhancements/Minigames/CremiaHugs.cpp new file mode 100644 index 000000000..2a9123fe3 --- /dev/null +++ b/mm/2s2h/Enhancements/Minigames/CremiaHugs.cpp @@ -0,0 +1,18 @@ +#include +#include "GameInteractor/GameInteractor.h" +#include "Enhancements/Enhancements.h" + +extern "C" { +#include +} + +void RegisterCremiaHugs() { + REGISTER_VB_SHOULD(VB_PLAY_CREMIA_HUG_CUTSCENE, { + uint8_t selectedOption = CVarGetInteger("gEnhancements.Minigames.CremiaHugs", 0); + if (selectedOption == CREMIA_REWARD_ALWAYS_HUG) { + *should = true; + } else if (selectedOption == CREMIA_REWARD_ALWAYS_RUPEE) { + *should = false; + } + }); +} diff --git a/mm/2s2h/Enhancements/Minigames/Minigames.h b/mm/2s2h/Enhancements/Minigames/Minigames.h index f7b02c094..f616fc81a 100644 --- a/mm/2s2h/Enhancements/Minigames/Minigames.h +++ b/mm/2s2h/Enhancements/Minigames/Minigames.h @@ -3,4 +3,6 @@ void RegisterAlwaysWinDoggyRace(); +void RegisterCremiaHugs(); + #endif // MINIGAMES_H diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 3af119040..7937b076b 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -64,6 +64,7 @@ typedef enum { VB_DRAW_SLIME_BODY_ITEM, VB_ZTARGET_SPEED_CHECK, VB_THIEF_BIRD_STEAL, + VB_PLAY_CREMIA_HUG_CUTSCENE, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_Ma_Yto/z_en_ma_yto.c b/mm/src/overlays/actors/ovl_En_Ma_Yto/z_en_ma_yto.c index 86c70ae69..3180d566b 100644 --- a/mm/src/overlays/actors/ovl_En_Ma_Yto/z_en_ma_yto.c +++ b/mm/src/overlays/actors/ovl_En_Ma_Yto/z_en_ma_yto.c @@ -7,6 +7,8 @@ #include "z_en_ma_yto.h" #include "overlays/actors/ovl_En_Ma_Yts/z_en_ma_yts.h" +#include "2s2h/GameInteractor/GameInteractor.h" + #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_100000 | ACTOR_FLAG_2000000) #define THIS ((EnMaYto*)thisx) @@ -308,7 +310,8 @@ void EnMaYto_ChooseAction(EnMaYto* this, PlayState* play) { case MA_YTO_TYPE_AFTERMILKRUN: this->unk310 = 0; if ((INV_CONTENT(ITEM_MASK_ROMANI) == ITEM_MASK_ROMANI) && - CHECK_WEEKEVENTREG(WEEKEVENTREG_ESCORTED_CREMIA) && (Rand_Next() & 0x80)) { + CHECK_WEEKEVENTREG(WEEKEVENTREG_ESCORTED_CREMIA) && + (GameInteractor_Should(VB_PLAY_CREMIA_HUG_CUTSCENE, Rand_Next() & 0x80))) { EnMaYto_SetupBeginWarmFuzzyFeelingCs(this); } else { EnMaYto_SetupAfterMilkRunInit(this); From 0b16bced84e7e97edcf93b7fbaa125062ee33c43 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Thu, 10 Oct 2024 00:46:05 -0400 Subject: [PATCH 65/82] [Cheat] Allow Elegy of Emptiness anywhere (#712) * Add cheat to allow Elegy of Emptiness anywhere * Use modern menu for Elegy Anywhere, rename VB Removed redundant null from Elegy scene check Moved ElegyAnywhere enhancement's menu order * Remove extraneous widgets from ElegyAnywhere menu --- mm/2s2h/BenGui/BenMenuBar.cpp | 2 ++ mm/2s2h/BenGui/SearchableMenuItems.h | 2 ++ mm/2s2h/Enhancements/Cheats/Cheats.h | 1 + mm/2s2h/Enhancements/Cheats/ElegyAnywhere.cpp | 10 ++++++++++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 1 + mm/src/code/z_message.c | 14 ++++++++------ 7 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 mm/2s2h/Enhancements/Cheats/ElegyAnywhere.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 6c329fe8e..04a96eaf8 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -792,6 +792,8 @@ void DrawCheatsMenu() { { .tooltip = "Holding L makes you float into the air" })) { RegisterMoonJumpOnL(); } + UIWidgets::CVarCheckbox("Elegy of Emptiness Anywhere", "gCheats.ElegyAnywhere", + { .tooltip = "Allows Elegy of Emptiness outside of Ikana" }); UIWidgets::CVarCombobox( "Stop Time in Dungeons", "gCheats.TempleTimeStop", timeStopOptions, { .tooltip = "Stops time from advancing in selected areas. Requires a room change to update.\n\n" diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 8325ff7a5..f0c3ed129 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -973,6 +973,8 @@ void AddEnhancements() { WIDGET_CVAR_CHECKBOX, {}, [](widgetInfo& info) { RegisterMoonJumpOnL(); } }, + { "Elegy of Emptiness Anywhere", "gCheats.ElegyAnywhere", "Allows Elegy of Emptiness outside of Ikana", + WIDGET_CVAR_CHECKBOX }, { "Stop Time in Dungeons", "gCheats.TempleTimeStop", "Stops time from advancing in selected areas. Requires a room change to update.\n\n" diff --git a/mm/2s2h/Enhancements/Cheats/Cheats.h b/mm/2s2h/Enhancements/Cheats/Cheats.h index f89dc877c..d429064b8 100644 --- a/mm/2s2h/Enhancements/Cheats/Cheats.h +++ b/mm/2s2h/Enhancements/Cheats/Cheats.h @@ -7,5 +7,6 @@ void RegisterMoonJumpOnL(); void RegisterTimeStopInTemples(); void RegisterUnbreakableRazorSword(); void RegisterUnrestrictedItems(); +void RegisterElegyAnywhere(); #endif // CHEATS_H diff --git a/mm/2s2h/Enhancements/Cheats/ElegyAnywhere.cpp b/mm/2s2h/Enhancements/Cheats/ElegyAnywhere.cpp new file mode 100644 index 000000000..ee04b4f5c --- /dev/null +++ b/mm/2s2h/Enhancements/Cheats/ElegyAnywhere.cpp @@ -0,0 +1,10 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" + +void RegisterElegyAnywhere() { + REGISTER_VB_SHOULD(VB_ELEGY_CHECK_SCENE, { + if (CVarGetInteger("gCheats.ElegyAnywhere", 0)) { + *should = true; + } + }); +} diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index c8f31b28c..4f58b9755 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -13,6 +13,7 @@ void InitEnhancements() { RegisterUnbreakableRazorSword(); RegisterUnrestrictedItems(); RegisterTimeStopInTemples(); + RegisterElegyAnywhere(); // Clock RegisterTextBasedClock(); diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 7937b076b..a49f350fe 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -65,6 +65,7 @@ typedef enum { VB_ZTARGET_SPEED_CHECK, VB_THIEF_BIRD_STEAL, VB_PLAY_CREMIA_HUG_CUTSCENE, + VB_ELEGY_CHECK_SCENE, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c index 7f0c82be5..68d1fa5e7 100644 --- a/mm/src/code/z_message.c +++ b/mm/src/code/z_message.c @@ -4821,12 +4821,14 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { if (msgCtx->ocarinaAction == OCARINA_ACTION_FREE_PLAY_DONE) { if (sLastPlayedSong == OCARINA_SONG_ELEGY) { - if ((play->sceneId == SCENE_F40) || (play->sceneId == SCENE_F41) || - (play->sceneId == SCENE_IKANAMAE) || (play->sceneId == SCENE_CASTLE) || - (play->sceneId == SCENE_IKNINSIDE) || (play->sceneId == SCENE_IKANA) || - (play->sceneId == SCENE_INISIE_N) || (play->sceneId == SCENE_INISIE_R) || - (play->sceneId == SCENE_INISIE_BS) || (play->sceneId == SCENE_RANDOM) || - (play->sceneId == SCENE_REDEAD) || (play->sceneId == SCENE_TOUGITES)) { + if (GameInteractor_Should( + VB_ELEGY_CHECK_SCENE, + (play->sceneId == SCENE_F40) || (play->sceneId == SCENE_F41) || + (play->sceneId == SCENE_IKANAMAE) || (play->sceneId == SCENE_CASTLE) || + (play->sceneId == SCENE_IKNINSIDE) || (play->sceneId == SCENE_IKANA) || + (play->sceneId == SCENE_INISIE_N) || (play->sceneId == SCENE_INISIE_R) || + (play->sceneId == SCENE_INISIE_BS) || (play->sceneId == SCENE_RANDOM) || + (play->sceneId == SCENE_REDEAD) || (play->sceneId == SCENE_TOUGITES))) { play->msgCtx.ocarinaMode = OCARINA_MODE_EVENT; } else { sLastPlayedSong = 0xFF; From 4d3c39224ced7c3e4580f605e8077d94cebd6780 Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:48:21 -0600 Subject: [PATCH 66/82] [Enhancement] Add First Cycle Skip (#716) * add option to skip first cycle * nest cycle skip in intro skip * set persistant flags from first cycle * better comments * missed a flag * add modern menu option * clang format * add entrance cutscene flags --- mm/2s2h/BenGui/BenMenuBar.cpp | 6 +++ mm/2s2h/BenGui/SearchableMenuItems.h | 16 +++++++- .../Cutscenes/SkipIntroSequence.cpp | 41 +++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 04a96eaf8..a8de6bb51 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -472,6 +472,12 @@ void DrawEnhancementsMenu() { { .tooltip = "When starting a game you will be taken straight to South Clock Town as Deku Link.", }); + if (CVarGetInteger("gEnhancements.Cutscenes.SkipIntroSequence", 0)) { + UIWidgets::CVarCheckbox( + "Skip First Cycle", "gEnhancements.Cutscenes.SkipFirstCycle", + { .tooltip = "When starting a game you will be taken straight to South Clock Town as Human Link " + "with Deku Mask, Ocarina, Song of Time, and Song of Healing." }); + } UIWidgets::CVarCheckbox( "Skip Story Cutscenes", "gEnhancements.Cutscenes.SkipStoryCutscenes", { diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index f0c3ed129..cd4284237 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -46,7 +46,8 @@ typedef enum { DISABLE_FOR_MOTION_BLUR_MODE, DISABLE_FOR_MOTION_BLUR_OFF, DISABLE_FOR_FRAME_ADVANCE_OFF, - DISABLE_FOR_WARP_POINT_NOT_SET + DISABLE_FOR_WARP_POINT_NOT_SET, + DISABLE_FOR_INTRO_SKIP_OFF, } DisableOption; struct widgetInfo; @@ -341,7 +342,10 @@ static std::map disabledMap = { "Frame Advance is Disabled" } }, { DISABLE_FOR_WARP_POINT_NOT_SET, { [](disabledInfo& info) -> bool { return !CVarGetInteger(WARP_POINT_CVAR "Saved", 0); }, - "Warp Point Not Saved" } } + "Warp Point Not Saved" } }, + { DISABLE_FOR_INTRO_SKIP_OFF, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gEnhancements.Cutscenes.SkipIntroSequence", 0); }, + "Intro Skip Not Selected" } } }; std::unordered_map menuThemeOptions = { @@ -1264,6 +1268,14 @@ void AddEnhancements() { { "Skip Intro Sequence", "gEnhancements.Cutscenes.SkipIntroSequence", "When starting a game you will be taken straight to South Clock Town as Deku Link.", WIDGET_CVAR_CHECKBOX }, + { "Skip First Cycle", + "gEnhancements.Cutscenes.SkipFirstCycle", + "When starting a game you will be taken straight to South Clock Town as Human Link " + "with Deku Mask, Ocarina, Song of Time, and Song of Healing.", + WIDGET_CVAR_CHECKBOX, + {}, + nullptr, + [](widgetInfo& info) { info.isHidden = disabledMap.at(DISABLE_FOR_INTRO_SKIP_OFF).active; } }, { "Skip Story Cutscenes", "gEnhancements.Cutscenes.SkipStoryCutscenes", "Disclaimer: This doesn't do much yet, we will be progressively adding more skips over time.", WIDGET_CVAR_CHECKBOX }, diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp index 031639236..92c0b0046 100644 --- a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp +++ b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp @@ -3,8 +3,10 @@ extern "C" { #include "z64.h" +#include extern PlayState* gPlayState; extern SaveContext gSaveContext; +void Flags_SetWeekEventReg(s32 flag); } void RegisterSkipIntroSequence() { @@ -24,6 +26,45 @@ void RegisterSkipIntroSequence() { // Mark chest as opened and give the player the Deku Nuts gSaveContext.cycleSceneFlags[SCENE_OPENINGDAN].chest |= (1 << 0); Item_Give(gPlayState, ITEM_DEKU_NUTS_10); + + if (CVarGetInteger("gEnhancements.Cutscenes.SkipFirstCycle", 0)) { + gSaveContext.save.playerForm = PLAYER_FORM_HUMAN; + gSaveContext.save.saveInfo.playerData.isMagicAcquired = true; + Item_Give(gPlayState, ITEM_OCARINA_OF_TIME); + Item_Give(gPlayState, ITEM_MASK_DEKU); + gSaveContext.save.saveInfo.inventory.questItems = (1 << QUEST_SONG_TIME) | (1 << QUEST_SONG_HEALING); + if (gSaveContext.save.saveInfo.playerData.threeDayResetCount < 1) { + gSaveContext.save.saveInfo.playerData.threeDayResetCount = 1; + } + gSaveContext.save.isFirstCycle = false; + + // Lose nuts + AMMO(ITEM_DEKU_NUT) = 0; + + // Tatl's text at seeing the broken great fairy + gSaveContext.cycleSceneFlags[SCENE_YOUSEI_IZUMI].switch0 |= (1 << 10); + + // Tatl's text when first entering South Clock Town if not already set + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_59_04)) { + SET_WEEKEVENTREG(WEEKEVENTREG_59_04); + } + + // Set Tatl second cycle (?) text if not already set + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_31_04)) { + SET_WEEKEVENTREG(WEEKEVENTREG_31_04); + } + + // Set Entrance Cutscene flags for Clock Town if not already set + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_ENTERED_EAST_CLOCK_TOWN)) { + SET_WEEKEVENTREG(WEEKEVENTREG_ENTERED_EAST_CLOCK_TOWN); + } + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WEST_CLOCK_TOWN)) { + SET_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WEST_CLOCK_TOWN); + } + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_ENTERED_NORTH_CLOCK_TOWN)) { + SET_WEEKEVENTREG(WEEKEVENTREG_ENTERED_NORTH_CLOCK_TOWN); + } + } } }); } From bb386e25a0002dd262ff51d68ec683f80030e338 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:51:05 -0400 Subject: [PATCH 67/82] [Enhancement] Enable putaway as Fierce Deity (#717) * Add enhancement to enable putaway as Fierce Deity * Fix hooks for putaway and FD sword wield --------- Co-authored-by: Garrett Cox --- mm/2s2h/BenGui/BenMenuBar.cpp | 2 ++ mm/2s2h/BenGui/SearchableMenuItems.h | 2 ++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + .../Player/FierceDeityPutaway.cpp | 19 +++++++++++++++++++ mm/2s2h/Enhancements/Player/Player.h | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 2 ++ .../actors/ovl_player_actor/z_player.c | 11 ++++++----- 7 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 mm/2s2h/Enhancements/Player/FierceDeityPutaway.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index a8de6bb51..75c615d19 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -716,6 +716,8 @@ void DrawEnhancementsMenu() { } UIWidgets::CVarCheckbox("Instant Putaway", "gEnhancements.Player.InstantPutaway", { .tooltip = "Allows Link to instantly puts away held item without waiting." }); + UIWidgets::CVarCheckbox("Fierce Deity Putaway", "gEnhancements.Player.FierceDeityPutaway", + { .tooltip = "Allows Fierce Deity Link to put away his sword." }); ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index cd4284237..5edbf1402 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1001,6 +1001,8 @@ void AddEnhancements() { ([](widgetInfo& info) { RegisterFastFlowerLaunch(); }) }, { "Instant Putaway", "gEnhancements.Player.InstantPutaway", "Allows Link to instantly puts away held item without waiting.", WIDGET_CVAR_CHECKBOX }, + { "Fierce Deity Putaway", "gEnhancements.Player.FierceDeityPutaway", + "Allows Fierce Deity Link to put away his sword.", WIDGET_CVAR_CHECKBOX }, { "Climb speed", "gEnhancements.PlayerMovement.ClimbSpeed", "Increases the speed at which Link climbs vines and ladders.", diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 4f58b9755..6d0abc386 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -54,6 +54,7 @@ void InitEnhancements() { RegisterClimbSpeed(); RegisterFastFlowerLaunch(); RegisterInstantPutaway(); + RegisterFierceDeityPutaway(); // Songs RegisterEnableSunsSong(); diff --git a/mm/2s2h/Enhancements/Player/FierceDeityPutaway.cpp b/mm/2s2h/Enhancements/Player/FierceDeityPutaway.cpp new file mode 100644 index 000000000..cad33ae43 --- /dev/null +++ b/mm/2s2h/Enhancements/Player/FierceDeityPutaway.cpp @@ -0,0 +1,19 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "variables.h" + +void RegisterFierceDeityPutaway() { + REGISTER_VB_SHOULD(VB_SHOULD_PUTAWAY, { + if (CVarGetInteger("gEnhancements.Player.FierceDeityPutaway", 0)) { + Player* player = GET_PLAYER(gPlayState); + if (player->transformation == PLAYER_FORM_FIERCE_DEITY) + *should = true; + } + }); + + REGISTER_VB_SHOULD(VB_FD_ALWAYS_WIELD_SWORD, { + if (CVarGetInteger("gEnhancements.Player.FierceDeityPutaway", 0)) { + *should = false; + } + }); +} diff --git a/mm/2s2h/Enhancements/Player/Player.h b/mm/2s2h/Enhancements/Player/Player.h index 0bcc94156..6aebb110a 100644 --- a/mm/2s2h/Enhancements/Player/Player.h +++ b/mm/2s2h/Enhancements/Player/Player.h @@ -4,5 +4,6 @@ void RegisterClimbSpeed(); void RegisterFastFlowerLaunch(); void RegisterInstantPutaway(); +void RegisterFierceDeityPutaway(); #endif // PLAYER_H diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index a49f350fe..6afed0605 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -65,6 +65,8 @@ typedef enum { VB_ZTARGET_SPEED_CHECK, VB_THIEF_BIRD_STEAL, VB_PLAY_CREMIA_HUG_CUTSCENE, + VB_FD_ALWAYS_WIELD_SWORD, + VB_SHOULD_PUTAWAY, VB_ELEGY_CHECK_SCENE, } GIVanillaBehavior; diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index e6cb26b9f..11817644e 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -3761,8 +3761,9 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { ItemId item; EquipSlot i = func_8082FDC4(); - i = ((i >= EQUIP_SLOT_A) && (this->transformation == PLAYER_FORM_FIERCE_DEITY) && - (this->heldItemAction != PLAYER_IA_SWORD_TWO_HANDED)) + i = GameInteractor_Should(VB_FD_ALWAYS_WIELD_SWORD, (i >= EQUIP_SLOT_A) && + (this->transformation == PLAYER_FORM_FIERCE_DEITY) && + (this->heldItemAction != PLAYER_IA_SWORD_TWO_HANDED)) ? EQUIP_SLOT_B : i; @@ -8115,7 +8116,7 @@ s32 Player_ActionChange_6(Player* this, PlayState* play) { } if ((this->putAwayCountdown == 0) && (this->heldItemAction >= PLAYER_IA_SWORD_KOKIRI) && - (this->transformation != PLAYER_FORM_FIERCE_DEITY)) { + GameInteractor_Should(VB_SHOULD_PUTAWAY, (this->transformation != PLAYER_FORM_FIERCE_DEITY))) { Player_UseItem(play, this, ITEM_NONE); } else { this->stateFlags2 ^= PLAYER_STATE2_100000; @@ -11243,8 +11244,8 @@ void Player_SetDoAction(PlayState* play, Player* this) { } else if ((this->transformation == PLAYER_FORM_DEKU) && !(this->stateFlags1 & PLAYER_STATE1_8000000) && (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) { doActionA = DO_ACTION_ATTACK; - } else if (((this->transformation == PLAYER_FORM_HUMAN) || - (this->transformation == PLAYER_FORM_ZORA)) && + } else if (GameInteractor_Should(VB_SHOULD_PUTAWAY, ((this->transformation == PLAYER_FORM_HUMAN) || + (this->transformation == PLAYER_FORM_ZORA))) && ((this->heldItemAction >= PLAYER_IA_SWORD_KOKIRI) || ((this->stateFlags2 & PLAYER_STATE2_100000) && (play->actorCtx.targetCtx.fairyActor == NULL)))) { From 3ebfdb3928c7f08b203e06fc9bda5a5fdea0ca32 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:51:05 -0400 Subject: [PATCH 68/82] [Enhancement] Skip the scarecrow song (#723) * Add enhancement to skip the scarecrow song * Update SkipScarecrowSong to use variadic args --- mm/2s2h/BenGui/BenMenuBar.cpp | 2 ++ mm/2s2h/BenGui/SearchableMenuItems.h | 2 ++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + .../Enhancements/Songs/SkipScarecrowSong.cpp | 29 +++++++++++++++++++ mm/2s2h/Enhancements/Songs/Songs.h | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 1 + .../actors/ovl_En_Kakasi/z_en_kakasi.c | 8 +++-- 7 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 mm/2s2h/Enhancements/Songs/SkipScarecrowSong.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 75c615d19..93152da61 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -755,6 +755,8 @@ void DrawEnhancementsMenu() { { .tooltip = "Enables using the Dpad for Ocarina playback." }); UIWidgets::CVarCheckbox("Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput", { .tooltip = "Prevent dropping inputs when playing the ocarina quickly" }); + UIWidgets::CVarCheckbox("Skip Scarecrow Song", "gEnhancements.Playback.SkipScarecrowSong", + { .tooltip = "Pierre appears when the Ocarina is pulled out." }); UIWidgets::CVarCheckbox("Pause Owl Warp", "gEnhancements.Songs.PauseOwlWarp", { .tooltip = "Allows the player to use the pause menu map to owl warp instead of " "having to play the Song of Soaring." }); diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 5edbf1402..1bff76ce3 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1249,6 +1249,8 @@ void AddEnhancements() { { 1, 7, 7 } }, { "Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput", "Prevent dropping inputs when playing the ocarina quickly.", WIDGET_CVAR_CHECKBOX }, + { "Skip Scarecrow Song", "gEnhancements.Playback.SkipScarecrowSong", + "Pierre appears when the Ocarina is pulled out.", WIDGET_CVAR_CHECKBOX }, { "Faster Song Playback", "gEnhancements.Songs.FasterSongPlayback", "Speeds up the playback of songs.", diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 6d0abc386..e0518fdc2 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -61,6 +61,7 @@ void InitEnhancements() { RegisterFasterSongPlayback(); RegisterPauseOwlWarp(); RegisterZoraEggCount(); + RegisterSkipScarecrowSong(); // Restorations RegisterPowerCrouchStab(); diff --git a/mm/2s2h/Enhancements/Songs/SkipScarecrowSong.cpp b/mm/2s2h/Enhancements/Songs/SkipScarecrowSong.cpp new file mode 100644 index 000000000..1804de148 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/SkipScarecrowSong.cpp @@ -0,0 +1,29 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" + +extern "C" { +#include "z64.h" +#include "functions.h" +#include "src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h" +extern PlayState* gPlayState; +} + +void RegisterSkipScarecrowSong() { + REGISTER_VB_SHOULD(VB_NEED_SCARECROW_SONG, { + if (CVarGetInteger("gEnhancements.Playback.SkipScarecrowSong", 0)) { + EnKakasi* enKakasi = va_arg(args, EnKakasi*); + /* + * This is somewhat similar to the condition that the scarecrow normally checks, except it checks if the + * instrument is being played at all instead of having played the Scarecrow's Song in particular, and it + * bypasses the check that Link has taught Pierre a song this cycle. + */ + if ((enKakasi->picto.actor.xzDistToPlayer < enKakasi->songSummonDist) && + ((BREG(1) != 0) || (gPlayState->msgCtx.ocarinaMode == OCARINA_MODE_ACTIVE))) { + *should = true; + // Properly get out of the ocarina playing state + AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); + Message_CloseTextbox(gPlayState); + } + } + }); +} diff --git a/mm/2s2h/Enhancements/Songs/Songs.h b/mm/2s2h/Enhancements/Songs/Songs.h index ecd2a6942..d4df3cc88 100644 --- a/mm/2s2h/Enhancements/Songs/Songs.h +++ b/mm/2s2h/Enhancements/Songs/Songs.h @@ -5,6 +5,7 @@ void RegisterEnableSunsSong(); void RegisterFasterSongPlayback(); void RegisterZoraEggCount(); void RegisterPauseOwlWarp(); +void RegisterSkipScarecrowSong(); #ifdef __cplusplus extern "C" { diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 6afed0605..28b4936d5 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -68,6 +68,7 @@ typedef enum { VB_FD_ALWAYS_WIELD_SWORD, VB_SHOULD_PUTAWAY, VB_ELEGY_CHECK_SCENE, + VB_NEED_SCARECROW_SONG, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.c b/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.c index 4e2e27cf6..c73d37e3a 100644 --- a/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.c +++ b/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.c @@ -7,6 +7,7 @@ #include "prevent_bss_reordering.h" #include "z_en_kakasi.h" #include "objects/object_ka/object_ka.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_2000000) @@ -1053,8 +1054,11 @@ void EnKakasi_SetupIdleUnderground(EnKakasi* this) { } void EnKakasi_IdleUnderground(EnKakasi* this, PlayState* play) { - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_79_08) && (this->picto.actor.xzDistToPlayer < this->songSummonDist) && - ((BREG(1) != 0) || (play->msgCtx.ocarinaMode == OCARINA_MODE_PLAYED_SCARECROW_SPAWN))) { + if (GameInteractor_Should(VB_NEED_SCARECROW_SONG, + CHECK_WEEKEVENTREG(WEEKEVENTREG_79_08) && + (this->picto.actor.xzDistToPlayer < this->songSummonDist) && + ((BREG(1) != 0) || (play->msgCtx.ocarinaMode == OCARINA_MODE_PLAYED_SCARECROW_SPAWN)), + this)) { this->picto.actor.flags &= ~ACTOR_FLAG_CANT_LOCK_ON; play->msgCtx.ocarinaMode = OCARINA_MODE_END; this->actionFunc = EnKakasi_SetupRiseOutOfGround; From 0129959d7b601d36dba78ffbc27177ddfe7da405 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 10 Oct 2024 13:38:58 -0500 Subject: [PATCH 69/82] Fix fairy container and seahorse rendering (#804) --- mm/2s2h/BenPort.cpp | 4 ++++ mm/2s2h/BenPort.h | 1 + mm/src/code/z_draw.c | 6 ++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 0c3c9dda8..e8a08471a 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -1176,6 +1176,10 @@ extern "C" Vtx* ResourceMgr_LoadVtxByName(char* path) { return (Vtx*)ResourceGetDataByName(path); } +extern "C" Mtx* ResourceMgr_LoadMtxByName(char* path) { + return (Mtx*)ResourceGetDataByName(path); +} + extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) { SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path); return *sequence; diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h index 1bad7f7af..f67607bbc 100644 --- a/mm/2s2h/BenPort.h +++ b/mm/2s2h/BenPort.h @@ -103,6 +103,7 @@ Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc); char* ResourceMgr_LoadVtxArrayByName(const char* path); size_t ResourceMgr_GetVtxArraySizeByName(const char* path); Vtx* ResourceMgr_LoadVtxByName(char* path); +Mtx* ResourceMgr_LoadMtxByName(char* path); KeyFrameSkeleton* ResourceMgr_LoadKeyFrameSkelByName(const char* path); KeyFrameAnimation* ResourceMgr_LoadKeyFrameAnimByName(const char* path); diff --git a/mm/src/code/z_draw.c b/mm/src/code/z_draw.c index 1d5b967d7..8dd890d73 100644 --- a/mm/src/code/z_draw.c +++ b/mm/src/code/z_draw.c @@ -90,6 +90,8 @@ #include "assets/objects/object_bsmask/object_bsmask.h" #include "assets/objects/object_st/object_st.h" +#include "2s2h/BenPort.h" + void GetItem_DrawBombchu(PlayState* play, s16 drawId); void GetItem_DrawPoes(PlayState* play, s16 drawId); void GetItem_DrawFairyBottle(PlayState* play, s16 drawId); @@ -669,7 +671,7 @@ void GetItem_DrawSeahorse(PlayState* play, s16 drawId) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, sDrawItemTable[drawId].drawResources[1]); - Matrix_MtxToMtxF(Lib_SegmentedToVirtual(sDrawItemTable[drawId].drawResources[3]), &mtx); + Matrix_MtxToMtxF(ResourceMgr_LoadMtxByName(Lib_SegmentedToVirtual(sDrawItemTable[drawId].drawResources[3])), &mtx); Matrix_Mult(&mtx, MTXMODE_APPLY); Matrix_ReplaceRotation(&play->billboardMtxF); @@ -695,7 +697,7 @@ void GetItem_DrawFairyContainer(PlayState* play, s16 drawId) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, sDrawItemTable[drawId].drawResources[1]); - Matrix_MtxToMtxF(Lib_SegmentedToVirtual(sDrawItemTable[drawId].drawResources[3]), &mtx); + Matrix_MtxToMtxF(ResourceMgr_LoadMtxByName(Lib_SegmentedToVirtual(sDrawItemTable[drawId].drawResources[3])), &mtx); Matrix_Mult(&mtx, MTXMODE_APPLY); Matrix_ReplaceRotation(&play->billboardMtxF); From 64ebfa222eac018365c82fdd22cdce7c81978c0f Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:38:51 -0400 Subject: [PATCH 70/82] [Enhancement] Two-handed sword spin attacks (#679) * Enhancement to enable magic for 2-handed swords Create a new magic charge size for the two-handed swords Add utility method for determining if the held item's button is being pressed, not just B * Clean up two-handed sword spin attacks Add hook for thunder matrix transformation, move that logic into TwoHandedSwordSpinAttack Move held item button press function into TwoHandedSwordSpinAttack.cpp Add enhancement to the searchable menu Clean up logic for magic spin attack form check Use variadic args for hooks * Remove redundant includes from TwoHandedSwordSpinAttack.cpp * Use extern on TwoHandedSwordSpinAttack structs --- mm/2s2h/BenGui/BenMenuBar.cpp | 3 + mm/2s2h/BenGui/SearchableMenuItems.h | 3 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Equipment/Equipment.h | 1 + .../Equipment/TwoHandedSwordSpinAttack.cpp | 57 +++++++++++++++++++ mm/2s2h/GameInteractor/GameInteractor.h | 3 + .../actors/ovl_En_M_Thunder/z_en_m_thunder.c | 19 ++++--- .../actors/ovl_player_actor/z_player.c | 23 ++++++-- 8 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 mm/2s2h/Enhancements/Equipment/TwoHandedSwordSpinAttack.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 93152da61..ddd988877 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -578,6 +578,9 @@ void DrawEnhancementsMenu() { { .tooltip = "Pressing B will instantly recall the fin boomerang back to Zora Link after they are thrown." }); + UIWidgets::CVarCheckbox( + "Two-Handed Sword Spin Attack", "gEnhancements.Equipment.TwoHandedSwordSpinAttack", + { .tooltip = "Enables magic spin attacks for the Fierce Deity Sword and Great Fairy's Sword." }); ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 1bff76ce3..4131b5941 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1027,6 +1027,9 @@ void AddEnhancements() { "Removes the animation for equipping Magic Arrows.", WIDGET_CVAR_CHECKBOX }, { "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", "Pressing B will instantly recall the fin boomerang back to Zora Link after they are thrown.", + WIDGET_CVAR_CHECKBOX }, + { "Two-Handed Sword Spin Attack", "gEnhancements.Equipment.TwoHandedSwordSpinAttack", + "Enables magic spin attacks for the Fierce Deity Sword and Great Fairy's Sword.", WIDGET_CVAR_CHECKBOX } }, { { .widgetName = "Modes", .widgetType = WIDGET_SEPARATOR_TEXT }, { "Play as Kafei", "gModes.PlayAsKafei", "Requires scene reload to take effect.", WIDGET_CVAR_CHECKBOX }, diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index e0518fdc2..22c97aa68 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -34,6 +34,7 @@ void InitEnhancements() { // Fixes RegisterFierceDeityZTargetMovement(); + RegisterTwoHandedSwordSpinAttack(); // Graphics RegisterDisableBlackBars(); diff --git a/mm/2s2h/Enhancements/Equipment/Equipment.h b/mm/2s2h/Enhancements/Equipment/Equipment.h index ca23748c9..849c10257 100644 --- a/mm/2s2h/Enhancements/Equipment/Equipment.h +++ b/mm/2s2h/Enhancements/Equipment/Equipment.h @@ -3,5 +3,6 @@ void RegisterInstantRecall(); void RegisterSkipMagicArrowEquip(); +void RegisterTwoHandedSwordSpinAttack(); #endif // EQUIPMENT_H diff --git a/mm/2s2h/Enhancements/Equipment/TwoHandedSwordSpinAttack.cpp b/mm/2s2h/Enhancements/Equipment/TwoHandedSwordSpinAttack.cpp new file mode 100644 index 000000000..64d6c706f --- /dev/null +++ b/mm/2s2h/Enhancements/Equipment/TwoHandedSwordSpinAttack.cpp @@ -0,0 +1,57 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.h" + +extern "C" { +extern PlayState* gPlayState; +extern Input* sPlayerControlInput; +} + +void RegisterTwoHandedSwordSpinAttack() { + + REGISTER_VB_SHOULD(VB_CHECK_HELD_ITEM_BUTTON_PRESS, { + if (CVarGetInteger("gEnhancements.Equipment.TwoHandedSwordSpinAttack", 0)) { + // Instead of checking B only, check whichever button is assigned to the currently held item. This allows + // the Great Fairy Sword, a C button item, to be held for charged spin attacks. + Player* player = GET_PLAYER(gPlayState); + u16* sDpadItemButtons = va_arg(args, u16*); + u16* sPlayerItemButtons = va_arg(args, u16*); + + if (player->heldItemButton < 0) { + *should = false; + } else { + uint16_t buttonToCheck; + if (IS_HELD_DPAD(player->heldItemButton)) { + buttonToCheck = sDpadItemButtons[HELD_ITEM_TO_DPAD(player->heldItemButton)]; + } else { + buttonToCheck = sPlayerItemButtons[player->heldItemButton]; + } + *should = CHECK_BTN_ALL(sPlayerControlInput->cur.button, buttonToCheck); + } + } + }); + + REGISTER_VB_SHOULD(VB_MAGIC_SPIN_ATTACK_CHECK_FORM, { + if (CVarGetInteger("gEnhancements.Equipment.TwoHandedSwordSpinAttack", 0)) { + // Additionally allow the Fierce Deity form to use charged spin attacks + PlayerTransformation form = va_arg(args, PlayerTransformation); + if (form == PLAYER_FORM_FIERCE_DEITY) { + *should = true; + } + } + }); + + REGISTER_VB_SHOULD(VB_TRANSFORM_THUNDER_MATRIX, { + if (CVarGetInteger("gEnhancements.Equipment.TwoHandedSwordSpinAttack", 0)) { + EnMThunder* enMThunder = va_arg(args, EnMThunder*); + // Define new thunder matrix transformation for two-handed sword magic. Applies to both the GFS and the + // Fierce Deity sword. + if (enMThunder->type == ENMTHUNDER_TYPE_GREAT_FAIRYS_SWORD) { + Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY); + Matrix_Scale(-1.7f, -1.0f, -0.6f, MTXMODE_APPLY); + Matrix_RotateXS(0x4000, MTXMODE_APPLY); + *should = false; + } + } + }); +} diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 28b4936d5..253690740 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -69,6 +69,9 @@ typedef enum { VB_SHOULD_PUTAWAY, VB_ELEGY_CHECK_SCENE, VB_NEED_SCARECROW_SONG, + VB_CHECK_HELD_ITEM_BUTTON_PRESS, + VB_MAGIC_SPIN_ATTACK_CHECK_FORM, + VB_TRANSFORM_THUNDER_MATRIX, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c b/mm/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c index 766d832c0..47929fb60 100644 --- a/mm/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c +++ b/mm/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c @@ -8,6 +8,7 @@ #include "z64rumble.h" #include "overlays/actors/ovl_Eff_Dust/z_eff_dust.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) @@ -543,14 +544,16 @@ void EnMThunder_Draw(Actor* thisx, PlayState* play2) { Matrix_Mult(&player->leftHandMf, MTXMODE_NEW); - if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) { - Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY); - Matrix_Scale(-1.2f, -0.8f, -0.6f, MTXMODE_APPLY); - Matrix_RotateXS(0x4000, MTXMODE_APPLY); - } else { - Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY); - Matrix_Scale(-0.7f, -0.6f, -0.4f, MTXMODE_APPLY); - Matrix_RotateXS(0x4000, MTXMODE_APPLY); + if (GameInteractor_Should(VB_TRANSFORM_THUNDER_MATRIX, true, this)) { + if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) { + Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY); + Matrix_Scale(-1.2f, -0.8f, -0.6f, MTXMODE_APPLY); + Matrix_RotateXS(0x4000, MTXMODE_APPLY); + } else { + Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY); + Matrix_Scale(-0.7f, -0.6f, -0.4f, MTXMODE_APPLY); + Matrix_RotateXS(0x4000, MTXMODE_APPLY); + } } if (this->unk1B0 >= 0.85f) { diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 11817644e..83eb3374f 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -5268,7 +5268,9 @@ void func_808332A0(PlayState* play, Player* this, s32 magicCost, s32 isSwordBeam } this->stateFlags1 |= PLAYER_STATE1_1000; - if ((this->actor.id == ACTOR_PLAYER) && (isSwordBeam || (this->transformation == PLAYER_FORM_HUMAN))) { + if ((this->actor.id == ACTOR_PLAYER) && + (isSwordBeam || (GameInteractor_Should(VB_MAGIC_SPIN_ATTACK_CHECK_FORM, + this->transformation == PLAYER_FORM_HUMAN, this->transformation)))) { s16 pitch = 0; Actor* thunder; @@ -8192,13 +8194,16 @@ s32 func_8083A4A4(Player* this, f32* arg1, s16* arg2, f32 arg3) { } void func_8083A548(Player* this) { - if ((this->unk_ADC > 0) && !CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { + if ((this->unk_ADC > 0) && + !GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), + sDpadItemButtons, sPlayerItemButtons)) { this->unk_ADC = -this->unk_ADC; } } s32 Player_ActionChange_8(Player* this, PlayState* play) { - if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { + if (GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), + sDpadItemButtons, sPlayerItemButtons)) { if (!(this->stateFlags1 & PLAYER_STATE1_400000) && (Player_GetMeleeWeaponHeld(this) != PLAYER_MELEEWEAPON_NONE)) { if ((this->unk_ADC > 0) && (((this->transformation == PLAYER_FORM_ZORA)) || @@ -10462,7 +10467,9 @@ s32 func_80840A30(PlayState* play, Player* this, f32* arg2, f32 arg3) { s32 func_80840CD4(Player* this, PlayState* play) { if (Player_StartCsAction(play, this)) { this->stateFlags2 |= PLAYER_STATE2_20000; - } else if (!CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { + } else if (!GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, + CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), sDpadItemButtons, + sPlayerItemButtons)) { PlayerMeleeWeaponAnimation meleeWeaponAnim; if ((this->unk_B08 >= 0.85f) || func_808333CC(this)) { @@ -14561,7 +14568,9 @@ void Player_Action_12(Player* this, PlayState* play) { if (!func_80847880(play, this)) { if (!Player_TryActionChangeList(play, this, sPlayerActionChangeList7, false) || (Player_Action_12 == this->actionFunc)) { - if (!CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { + if (!GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, + CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), sDpadItemButtons, + sPlayerItemButtons)) { func_80839E74(this, play); } } @@ -15246,7 +15255,9 @@ void Player_Action_30(Player* this, PlayState* play) { if (this->unk_B08 >= 0.1f) { this->unk_ADD = 0; this->av2.actionVar2 = 1; - } else if (!CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { + } else if (!GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, + CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), sDpadItemButtons, + sPlayerItemButtons)) { func_80840E5C(this, play); } } else if (!func_80840CD4(this, play)) { From 9cd2f6e784ef48544c5bbe1d4bd363ac63899f75 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Tue, 15 Oct 2024 11:39:07 -0600 Subject: [PATCH 71/82] Update BUILDING.md (#810) --- docs/BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 8feb79ec3..8f6c7ec2e 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -20,7 +20,7 @@ It is recommended that you install Python and Git standalone, the install proces 1. Clone the 2 Ship 2 Harkinian repository -_Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule init`` after cloning to pull in the libultraship submodule!_ +_Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule update --init`` after cloning to pull in the libultraship submodule!_ 2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice From cbc89b8af4718e72349552642d162c2ef2725587 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:51:47 -0400 Subject: [PATCH 72/82] Fix item id type (#813) * fix wrong type * Update z_kaleido_item.c --- .../kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c index 2441c27bf..b4d7e5179 100644 --- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c +++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c @@ -322,10 +322,8 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->itemVtx[j + 0].v.ob[1] - 32; } } - // #region 2S2H [Port] Originally this was done in KaleidoScope_Update, but now we are using gSPGrayscale on - // the fly It reads odd here to assign a u8 to a u16, then cast it to s32 for gPlayerFormItemRestrictions - // but this matches the behavior of the original code - u16 itemId = gSaveContext.save.saveInfo.inventory.items[i]; + // #region 2S2H [Port] Originally this was done in KaleidoScope_Update, but now we are using gSPGrayscale. + ItemId itemId = gSaveContext.save.saveInfo.inventory.items[i]; u8 itemRestricted = GameInteractor_Should( VB_ITEM_BE_RESTRICTED, !gPlayerFormItemRestrictions[GET_PLAYER_FORM][(s32)itemId], &itemId); if (itemRestricted) { From 941b48b802445898a1fb057ccdd9297d4abf1f1b Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 26 Oct 2024 00:28:08 -0500 Subject: [PATCH 73/82] Add swordsman school options (#779) --- mm/2s2h/BenGui/BenMenuBar.cpp | 2 ++ mm/2s2h/BenGui/SearchableMenuItems.h | 5 +++ mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Minigames/Minigames.h | 2 +- .../Minigames/SwordsmanSchool.cpp | 31 +++++++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/Minigames/SwordsmanSchool.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index ddd988877..deb7003d4 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -687,6 +687,8 @@ void DrawEnhancementsMenu() { "-Hug: Get the hugging cutscene\n" "-Rupee: Get the rupee reward", .defaultIndex = CREMIA_REWARD_RANDOM }); + UIWidgets::CVarSliderInt("Swordsman School Winning Score: %d", + "gEnhancements.Minigames.SwordsmanSchoolScore", 1, 30, 30); ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 4131b5941..376aa379a 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1023,6 +1023,11 @@ void AddEnhancements() { "-Rupee: Get the rupee reward", WIDGET_CVAR_COMBOBOX, { .comboBoxOptions = cremiaRewardOptions } }, + { "Swordsman School Winning Score", + "gEnhancements.Minigames.SwordsmanSchoolScore", + "Sets the score required to win the Swordsman School.", + WIDGET_CVAR_SLIDER_INT, + { 1, 30, 30 } }, { "Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", "Removes the animation for equipping Magic Arrows.", WIDGET_CVAR_CHECKBOX }, { "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 22c97aa68..411d0cd15 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -50,6 +50,7 @@ void InitEnhancements() { // Minigames RegisterAlwaysWinDoggyRace(); RegisterCremiaHugs(); + RegisterSwordsmanSchool(); // Player RegisterClimbSpeed(); diff --git a/mm/2s2h/Enhancements/Minigames/Minigames.h b/mm/2s2h/Enhancements/Minigames/Minigames.h index f616fc81a..2106dad20 100644 --- a/mm/2s2h/Enhancements/Minigames/Minigames.h +++ b/mm/2s2h/Enhancements/Minigames/Minigames.h @@ -2,7 +2,7 @@ #define MINIGAMES_H void RegisterAlwaysWinDoggyRace(); - void RegisterCremiaHugs(); +void RegisterSwordsmanSchool(); #endif // MINIGAMES_H diff --git a/mm/2s2h/Enhancements/Minigames/SwordsmanSchool.cpp b/mm/2s2h/Enhancements/Minigames/SwordsmanSchool.cpp new file mode 100644 index 000000000..6bd0448d9 --- /dev/null +++ b/mm/2s2h/Enhancements/Minigames/SwordsmanSchool.cpp @@ -0,0 +1,31 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" + +extern "C" { +#include "overlays/actors/ovl_En_Kendo_Js/z_en_kendo_js.h" + +void func_80B274BC(EnKendoJs* thisx, PlayState* play); +} + +void RegisterSwordsmanSchool() { + GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_KENDO_JS, [](Actor* actor, bool* should) { + EnKendoJs* kendo = (EnKendoJs*)actor; + + if (kendo->actionFunc != func_80B274BC) { + return; + } + + // Finishes the game early, as soon as the player reaches the required score + if (gSaveContext.minigameScore >= CVarGetInteger("gEnhancements.Minigames.SwordsmanSchoolScore", 30)) { + kendo->unk_290 = 140; + kendo->unk_284 = 5; + } + + // Each time player chops a log, check if they've reached the required score + if (kendo->unk_290 >= 140 && kendo->unk_284 == 5 && + gSaveContext.minigameScore >= CVarGetInteger("gEnhancements.Minigames.SwordsmanSchoolScore", 30)) { + gSaveContext.minigameScore = 30; + } + }); +} From 50bc007d465980a03a4d703f458fab629f0bd1f7 Mon Sep 17 00:00:00 2001 From: balloondude2 <55861555+balloondude2@users.noreply.github.com> Date: Wed, 30 Oct 2024 22:37:24 -0600 Subject: [PATCH 74/82] Adds an option to the save editor to invert Stone Tower (#812) * add option to invert st in save editor * only allow inverting in stone tower scenes * change tooltip to disabledTooltip Co-authored-by: Archez --------- Co-authored-by: Archez --- mm/2s2h/DeveloperTools/SaveEditor.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mm/2s2h/DeveloperTools/SaveEditor.cpp b/mm/2s2h/DeveloperTools/SaveEditor.cpp index 1853abe3d..4904fba28 100644 --- a/mm/2s2h/DeveloperTools/SaveEditor.cpp +++ b/mm/2s2h/DeveloperTools/SaveEditor.cpp @@ -217,6 +217,8 @@ void UpdateGameTime(u16 gameTime) { void DrawTempleClears() { bool cleared; bool open; + bool inverted = false; + bool inStoneTower = false; // Woodfall cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE); @@ -302,7 +304,6 @@ void DrawTempleClears() { } // Stone Tower - // Stone Tower Temple is always open so there is no need to have an option to open it. cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE); if (UIWidgets::Checkbox("Stone Tower cleared", &cleared)) { if (cleared) { @@ -311,6 +312,22 @@ void DrawTempleClears() { CLEAR_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE); } } + + if (gPlayState != NULL) { + inStoneTower = Play_GetOriginalSceneId(gPlayState->sceneId) == SCENE_F40; + inverted = Flags_GetSwitch(gPlayState, 20); + } + + ImGui::SameLine(); + + if (UIWidgets::Checkbox("Stone Tower Inverted", &inverted, + { .disabled = !inStoneTower, .disabledTooltip = "Can only invert while in Stone Tower" })) { + if (inverted) { + Flags_SetSwitch(gPlayState, 20); + } else { + Flags_UnsetSwitch(gPlayState, 20); + } + } } void DrawGeneralTab() { From 0966633d2ac697d179fc99bdd626f5f2443cda51 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 2 Nov 2024 15:44:21 -0500 Subject: [PATCH 75/82] Implement simple notifications system (#816) * Implement simple notifications system * Remove demoWindow call * Fix initializer order --- mm/2s2h/BenGui/BenGui.cpp | 7 ++ mm/2s2h/BenGui/Notification.cpp | 140 ++++++++++++++++++++++++++ mm/2s2h/BenGui/Notification.h | 37 +++++++ mm/2s2h/BenGui/SearchableMenuItems.h | 43 ++++++++ mm/2s2h/BenPort.cpp | 2 + mm/2s2h/DeveloperTools/SaveEditor.cpp | 19 +--- mm/2s2h/ShipUtils.cpp | 21 +++- mm/2s2h/ShipUtils.h | 5 +- 8 files changed, 253 insertions(+), 21 deletions(-) create mode 100644 mm/2s2h/BenGui/Notification.cpp create mode 100644 mm/2s2h/BenGui/Notification.h diff --git a/mm/2s2h/BenGui/BenGui.cpp b/mm/2s2h/BenGui/BenGui.cpp index dfc57bf34..4a9fa2967 100644 --- a/mm/2s2h/BenGui/BenGui.cpp +++ b/mm/2s2h/BenGui/BenGui.cpp @@ -8,6 +8,7 @@ #include #include "UIWidgets.hpp" #include "HudEditor.h" +#include "Notification.h" #ifdef __APPLE__ #include "graphic/Fast3D/gfx_metal.h" @@ -36,6 +37,7 @@ std::shared_ptr mCollisionViewerWindow; std::shared_ptr mEventLogWindow; std::shared_ptr mBenMenu; std::shared_ptr mBenInputEditorWindow; +std::shared_ptr mNotificationWindow; void SetupGuiElements() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); @@ -93,6 +95,10 @@ void SetupGuiElements() { mEventLogWindow = std::make_shared("gWindows.EventLog", "Event Log", ImVec2(520, 600)); gui->AddGuiWindow(mEventLogWindow); gui->SetPadBtnTogglesMenu(); + + mNotificationWindow = std::make_shared("gWindows.Notifications", "Notifications Window"); + gui->AddGuiWindow(mNotificationWindow); + mNotificationWindow->Show(); } void Destroy() { @@ -104,6 +110,7 @@ void Destroy() { mGfxDebuggerWindow = nullptr; mCollisionViewerWindow = nullptr; mEventLogWindow = nullptr; + mNotificationWindow = nullptr; mSaveEditorWindow = nullptr; mHudEditorWindow = nullptr; diff --git a/mm/2s2h/BenGui/Notification.cpp b/mm/2s2h/BenGui/Notification.cpp new file mode 100644 index 000000000..0c363d8d4 --- /dev/null +++ b/mm/2s2h/BenGui/Notification.cpp @@ -0,0 +1,140 @@ + +#include "Notification.h" +#include + +extern "C" { +#include "functions.h" +#include "macros.h" +#include "variables.h" +} + +namespace Notification { + +static uint32_t nextId = 0; +static std::vector notifications = {}; + +void Window::Draw() { + auto vp = ImGui::GetMainViewport(); + + const float margin = 30.0f; + const float padding = 10.0f; + + int position = CVarGetInteger("gNotifications.Position", 3); + + // Top Left + ImVec2 basePosition; + switch (position) { + case 0: // Top Left + basePosition = ImVec2(vp->Pos.x + margin, vp->Pos.y + margin); + break; + case 1: // Top Right + basePosition = ImVec2(vp->Pos.x + vp->Size.x - margin, vp->Pos.y + margin); + break; + case 2: // Bottom Left + basePosition = ImVec2(vp->Pos.x + margin, vp->Pos.y + vp->Size.y - margin); + break; + case 3: // Bottom Right + basePosition = ImVec2(vp->Pos.x + vp->Size.x - margin, vp->Pos.y + vp->Size.y - margin); + break; + case 4: // Hidden + return; + } + + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, CVarGetFloat("gNotifications.BgOpacity", 0.5f))); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f * CVarGetFloat("gNotifications.Size", 1.8f), 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f * CVarGetFloat("gNotifications.Size", 1.8f), 8.0f)); + + for (int index = 0; index < notifications.size(); ++index) { + auto& notification = notifications[index]; + int inverseIndex = -ABS(index - (notifications.size() - 1)); + + ImGui::SetNextWindowViewport(vp->ID); + if (notification.remainingTime < 4.0f) { + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, (notification.remainingTime - 1) / 3.0f); + } else { + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.0f); + } + + ImGui::Begin(("notification#" + std::to_string(notification.id)).c_str(), nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoScrollbar); + + ImGui::SetWindowFontScale(CVarGetFloat("gNotifications.Size", 1.8f)); + + ImVec2 notificationPos; + switch (position) { + case 0: // Top Left + notificationPos = + ImVec2(basePosition.x, basePosition.y + ((ImGui::GetWindowSize().y + padding) * inverseIndex)); + break; + case 1: // Top Right + notificationPos = ImVec2(basePosition.x - ImGui::GetWindowSize().x, + basePosition.y + ((ImGui::GetWindowSize().y + padding) * inverseIndex)); + break; + case 2: // Bottom Left + notificationPos = ImVec2(basePosition.x, + basePosition.y - ((ImGui::GetWindowSize().y + padding) * (inverseIndex + 1))); + break; + case 3: // Bottom Right + notificationPos = ImVec2(basePosition.x - ImGui::GetWindowSize().x, + basePosition.y - ((ImGui::GetWindowSize().y + padding) * (inverseIndex + 1))); + break; + } + + ImGui::SetWindowPos(notificationPos); + ImGui::AlignTextToFramePadding(); + + if (notification.itemIcon != nullptr) { + ImGui::Image( + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(notification.itemIcon), + ImVec2(22 * CVarGetFloat("gNotifications.Size", 1.8f), 22 * CVarGetFloat("gNotifications.Size", 1.8f))); + ImGui::SameLine(); + } + if (!notification.prefix.empty()) { + ImGui::TextColored(notification.prefixColor, "%s", notification.prefix.c_str()); + ImGui::SameLine(); + } + ImGui::TextColored(notification.messageColor, "%s", notification.message.c_str()); + if (!notification.suffix.empty()) { + ImGui::SameLine(); + ImGui::TextColored(notification.suffixColor, "%s", notification.suffix.c_str()); + } + + ImGui::End(); + ImGui::PopStyleVar(); + } + + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(2); +} + +void Window::UpdateElement() { + for (int index = 0; index < notifications.size(); ++index) { + auto& notification = notifications[index]; + + // decrement remainingTime + notification.remainingTime -= ImGui::GetIO().DeltaTime; + + // remove notification if it has expired + if (notification.remainingTime <= 0) { + notifications.erase(notifications.begin() + index); + --index; + } + } +} + +void Emit(Options notification) { + notification.id = nextId++; + if (notification.remainingTime == 0.0f) { + notification.remainingTime = CVarGetFloat("gNotifications.Duration", 10.0f); + } + notifications.push_back(notification); + AudioSfx_PlaySfx(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultReverb); +} + +} // namespace Notification diff --git a/mm/2s2h/BenGui/Notification.h b/mm/2s2h/BenGui/Notification.h new file mode 100644 index 000000000..bc3a93b9b --- /dev/null +++ b/mm/2s2h/BenGui/Notification.h @@ -0,0 +1,37 @@ +#ifndef NOTIFICATION_H +#define NOTIFICATION_H +#ifdef __cplusplus + +#include +#include + +namespace Notification { + +struct Options { + uint32_t id = 0; + const char* itemIcon = nullptr; + std::string prefix = ""; + ImVec4 prefixColor = ImVec4(0.5f, 0.5f, 1.0f, 1.0f); + std::string message = ""; + ImVec4 messageColor = ImVec4(0.7f, 0.7f, 0.7f, 1.0f); + std::string suffix = ""; + ImVec4 suffixColor = ImVec4(1.0f, 0.5f, 0.5f, 1.0f); + float remainingTime = 0.0f; // Seconds +}; + +class Window : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override{}; + void DrawElement() override{}; + void Draw() override; + void UpdateElement() override; +}; + +void Emit(Options notification); + +} // namespace Notification + +#endif // __cplusplus +#endif // NOTIFICATION_H diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 376aa379a..fa93b8ca7 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -2,6 +2,7 @@ #include "2s2h/DeveloperTools/DeveloperTools.h" #include "UIWidgets.hpp" #include "BenMenuBar.h" +#include "Notification.h" #include "macros.h" #include "variables.h" #include @@ -420,6 +421,10 @@ static const std::unordered_map timeStopOptions = { { TIME_STOP_TEMPLES_DUNGEONS, "Temples + Mini Dungeons" }, }; +static const std::unordered_map notificationPosition = { + { 0, "Top Left" }, { 1, "Top Right" }, { 2, "Bottom Left" }, { 3, "Bottom Right" }, { 4, "Hidden" }, +}; + void FreeLookPitchMinMax() { f32 maxY = CVarGetFloat("gEnhancements.Camera.FreeLook.MaxPitch", 72.0f); f32 minY = CVarGetFloat("gEnhancements.Camera.FreeLook.MinPitch", -49.0f); @@ -716,6 +721,44 @@ void AddSettings() { WIDGET_WINDOW_BUTTON, { .size = UIWidgets::Sizes::Inline, .windowName = "2S2H Input Editor" } } } } }); + settingsSidebar.push_back({ "Notifications", + 1, + { { + { "Position", + "gNotifications.Position", + "Which corner of the screen notifications appear in.", + WIDGET_CVAR_COMBOBOX, + { .defaultVariant = 3, .comboBoxOptions = notificationPosition } }, + { "Duration: %.0f seconds", + "gNotifications.Duration", + "How long notifications are displayed for.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 300.0f, .max = 3000.0f, .defaultVariant = 1000.0f } }, + { "Background Opacity: %.0f%%", + "gNotifications.BgOpacity", + "How opaque the background of notifications is.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 0.0f, .max = 100.0f, .defaultVariant = 50.0f, .isPercentage = true } }, + { "Size %.1f", + "gNotifications.Size", + "How large notifications are.", + WIDGET_CVAR_SLIDER_FLOAT, + { .min = 100.0f, .max = 500.0f, .defaultVariant = 180.0f } }, + { "Test Notification", + "", + "Displays a test notification.", + WIDGET_BUTTON, + {}, + [](widgetInfo& info) { + Notification::Emit({ + .itemIcon = "__OTR__icon_item_24_static_yar/gQuestIconGoldSkulltulaTex", + .prefix = "This", + .message = "is a", + .suffix = "test.", + }); + } }, + } } }); + if (CVarGetInteger("gSettings.SidebarSearch", 0)) { settingsSidebar.insert(settingsSidebar.begin() + searchSidebarIndex, searchSidebarEntry); } diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index e8a08471a..dbb56d2af 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -55,6 +55,7 @@ CrowdControl* CrowdControl::Instance; #include "2s2h/DeveloperTools/DebugConsole.h" #include "2s2h/DeveloperTools/DeveloperTools.h" #include "2s2h/SaveManager/SaveManager.h" +#include "2s2h/ShipUtils.h" // Resource Types/Factories #include "resource/type/Blob.h" @@ -512,6 +513,7 @@ extern "C" void InitOTR() { OTRGlobals::Instance = new OTRGlobals(); GameInteractor::Instance = new GameInteractor(); + LoadGuiTextures(); BenGui::SetupGuiElements(); InitEnhancements(); InitDeveloperTools(); diff --git a/mm/2s2h/DeveloperTools/SaveEditor.cpp b/mm/2s2h/DeveloperTools/SaveEditor.cpp index 4904fba28..1024b2028 100644 --- a/mm/2s2h/DeveloperTools/SaveEditor.cpp +++ b/mm/2s2h/DeveloperTools/SaveEditor.cpp @@ -1,6 +1,7 @@ #include "SaveEditor.h" #include "2s2h/BenGui/UIWidgets.hpp" #include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/BenGui/Notification.h" #include "interface/icon_item_dungeon_static/icon_item_dungeon_static.h" #include "archives/icon_item_24_static/icon_item_24_static_yar.h" @@ -2011,24 +2012,6 @@ void SaveEditorWindow::DrawElement() { } } -const char* textureLoad[8] = { gDungeonStrayFairyWoodfallIconTex, - gDungeonStrayFairySnowheadIconTex, - gDungeonStrayFairyGreatBayIconTex, - gDungeonStrayFairyStoneTowerIconTex, - gQuestIconDungeonMapTex, - gQuestIconCompassTex, - gQuestIconSmallKeyTex, - gQuestIconBossKeyTex }; - void SaveEditorWindow::InitElement() { initSafeItemsForInventorySlot(); - - for (TexturePtr entry : gItemIcons) { - const char* path = static_cast(entry); - Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1)); - } - for (int i = 0; i <= 7; i++) { - Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(textureLoad[i], textureLoad[i], - ImVec4(1, 1, 1, 1)); - } } diff --git a/mm/2s2h/ShipUtils.cpp b/mm/2s2h/ShipUtils.cpp index 5d50eb62e..2b4c26ce9 100644 --- a/mm/2s2h/ShipUtils.cpp +++ b/mm/2s2h/ShipUtils.cpp @@ -1,6 +1,5 @@ #include "ShipUtils.h" -#include -#include "PR/ultratypes.h" +#include #include "assets/2s2h_assets.h" extern "C" { @@ -8,6 +7,9 @@ extern "C" { extern f32 sNESFontWidths[160]; extern const char* fontTbl[156]; +extern TexturePtr gItemIcons[131]; +extern TexturePtr gQuestIcons[14]; +extern TexturePtr gBombersNotebookPhotos[24]; } // Build vertex coordinates for a quad command @@ -54,3 +56,18 @@ extern "C" TexturePtr Ship_GetCharFontTextureNES(u8 character) { return (TexturePtr)fontTbl[adjustedChar]; } + +void LoadGuiTextures() { + for (TexturePtr entry : gItemIcons) { + const char* path = static_cast(entry); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1)); + } + for (TexturePtr entry : gQuestIcons) { + const char* path = static_cast(entry); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1)); + } + for (TexturePtr entry : gBombersNotebookPhotos) { + const char* path = static_cast(entry); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1)); + } +} diff --git a/mm/2s2h/ShipUtils.h b/mm/2s2h/ShipUtils.h index f30c39aac..8afcb5117 100644 --- a/mm/2s2h/ShipUtils.h +++ b/mm/2s2h/ShipUtils.h @@ -1,10 +1,13 @@ #ifndef SHIP_UTILS_H #define SHIP_UTILS_H -#include +#include #include "PR/ultratypes.h" #ifdef __cplusplus + +void LoadGuiTextures(); + extern "C" { #endif From 207df24ffde84bc6e89fd1fd54653b7542661d32 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Sun, 3 Nov 2024 16:13:09 -0500 Subject: [PATCH 76/82] Fix bug with two-handed sword magic and dance (#819) --- mm/src/overlays/actors/ovl_player_actor/z_player.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm/src/overlays/actors/ovl_player_actor/z_player.c b/mm/src/overlays/actors/ovl_player_actor/z_player.c index 83eb3374f..38309acb6 100644 --- a/mm/src/overlays/actors/ovl_player_actor/z_player.c +++ b/mm/src/overlays/actors/ovl_player_actor/z_player.c @@ -14568,9 +14568,7 @@ void Player_Action_12(Player* this, PlayState* play) { if (!func_80847880(play, this)) { if (!Player_TryActionChangeList(play, this, sPlayerActionChangeList7, false) || (Player_Action_12 == this->actionFunc)) { - if (!GameInteractor_Should(VB_CHECK_HELD_ITEM_BUTTON_PRESS, - CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B), sDpadItemButtons, - sPlayerItemButtons)) { + if (!CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_B)) { func_80839E74(this, play); } } From c2ec2f2cc3a49bff45106fdaf4cccc90f2b8a149 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 5 Nov 2024 23:17:14 -0500 Subject: [PATCH 77/82] Fix installed macports detection for github runner (#821) --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02931a149..db96aa3d8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -192,15 +192,17 @@ jobs: key: ${{ runner.os }}-14-macports-${{ hashFiles('.github/workflows/macports-deps.txt') }} restore-keys: | ${{ runner.os }}-14-macports- + # Updated PATH applies to the next step and onwards - name: Install MacPorts (if necessary) run: | - if [ command -v port &>/dev/null ]; then + if command -v /opt/local/bin/port 2>&1 >/dev/null; then echo "MacPorts already installed" else + echo "Installing MacPorts" wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-14-Sonoma.pkg sudo installer -pkg ./MacPorts-2.9.3-14-Sonoma.pkg -target / fi - echo "/opt/local/bin:/opt/local/sbin" >> $GITHUB_PATH + echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH" - name: Install dependencies run: | brew uninstall --ignore-dependencies libpng From 2141922ee3d79d4b170c9cadedbad65d20a767c5 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 5 Nov 2024 23:25:31 -0500 Subject: [PATCH 78/82] Fix authentic overflowed textures (#794) * fix authentic overflow textures * Add overflow assets and enable patching them --- mm/2s2h/BenGui/BenMenuBar.cpp | 8 + mm/2s2h/BenGui/SearchableMenuItems.h | 9 +- .../GfxPatcher/AuthenticGfxPatches.cpp | 233 +++++++++++++++++- .../GfxPatcher/AuthenticGfxPatches.h | 1 + mm/assets/xml/GC_US/objects/gameplay_keep.xml | 4 + mm/assets/xml/GC_US/objects/object_ik.xml | 2 + .../xml/N64_US/objects/gameplay_keep.xml | 4 + mm/assets/xml/N64_US/objects/object_ik.xml | 2 + 8 files changed, 261 insertions(+), 2 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index deb7003d4..2911b6458 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -8,6 +8,7 @@ #include #include #include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h" #include "2s2h/DeveloperTools/DeveloperTools.h" #include "HudEditor.h" @@ -605,6 +606,13 @@ void DrawEnhancementsMenu() { { .tooltip = "Fixes a bug that results in the Ikana Great Fairy fountain looking " "green instead of yellow, this was fixed in the EU version" }); + if (UIWidgets::CVarCheckbox( + "Fix Texture overflow OOB", "gEnhancements.Fixes.FixTexturesOOB", + { .tooltip = "Fixes textures that normally overflow to be patched with the correct size or format", + .defaultValue = true })) { + GfxPatcher_ApplyOverflowTexturePatches(); + } + ImGui::EndMenu(); } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index fa93b8ca7..6e5d65a9f 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1,5 +1,6 @@ #include "2s2h/Enhancements/Enhancements.h" #include "2s2h/DeveloperTools/DeveloperTools.h" +#include "2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h" #include "UIWidgets.hpp" #include "BenMenuBar.h" #include "Notification.h" @@ -1366,7 +1367,13 @@ void AddEnhancements() { { "Fix Ikana Great Fairy Fountain Color", "gFixes.FixIkanaGreatFairyFountainColor", "Fixes a bug that results in the Ikana Great Fairy fountain looking green instead of yellow, this was " "fixed in the EU version", - WIDGET_CVAR_CHECKBOX } } } }); + WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Fix Texture overflow OOB", + .widgetCVar = "gEnhancements.Fixes.FixTexturesOOB", + .widgetTooltip = "Fixes textures that normally overflow to be patched with the correct size or format", + .widgetType = WIDGET_CVAR_CHECKBOX, + .widgetOptions = { .defaultVariant = true }, + .widgetCallback = [](widgetInfo& info) { GfxPatcher_ApplyOverflowTexturePatches(); } } } } }); enhancementsSidebar.push_back( { "Restorations", 3, diff --git a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp index 3364ff86b..eb3d86397 100644 --- a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp +++ b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.cpp @@ -1,7 +1,11 @@ #include "AuthenticGfxPatches.h" +#include "libultraship/libultraship.h" +#include extern "C" { -#include +#include "objects/gameplay_keep/gameplay_keep.h" +#include "objects/object_fz/object_fz.h" +#include "objects/object_ik/object_ik.h" #include "overlays/ovl_En_Syateki_Okuta/ovl_En_Syateki_Okuta.h" #include "overlays/ovl_Obj_Jgame_Light/ovl_Obj_Jgame_Light.h" @@ -10,6 +14,231 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); Gfx* ResourceMgr_LoadGfxByName(const char* path); } +#define dgameplay_keep_Tex_00CA30_Overflow "__OTR__objects/gameplay_keep/gameplay_keep_Tex_00CA30_Overflow" +static const ALIGN_ASSET(2) char gameplay_keep_Tex_00CA30_Overflow[] = dgameplay_keep_Tex_00CA30_Overflow; + +#define dgEffIceFragmentTex_Overflow "__OTR__objects/gameplay_keep/gEffIceFragmentTex_Overflow" +static const ALIGN_ASSET(2) char gEffIceFragmentTex_Overflow[] = dgEffIceFragmentTex_Overflow; + +#define dgIronKnuckleFireTex_Overflow "__OTR__objects/object_ik/gIronKnuckleFireTex_Overflow" +static const ALIGN_ASSET(2) char gIronKnuckleFireTex_Overflow[] = dgIronKnuckleFireTex_Overflow; + +typedef struct { + const char* dlist; + int startInstruction; +} DListPatchInfo; + +static DListPatchInfo freezardBodyDListPatchInfos[] = { + { object_fz_DL_001130, 5 }, { object_fz_DL_0021A0, 5 }, { object_fz_DL_002CA0, 5 }, + { object_fz_DL_003260, 5 }, { object_fz_DL_0033F0, 5 }, +}; + +static DListPatchInfo ironKnuckleDListPatchInfos[] = { + { gIronKnuckleVambraceLeftDL, 39 }, + { gIronKnuckleVambraceLeftDL, 59 }, + + { gIronKnuckleArmLeftDL, 38 }, + + { gIronKnuckleVambraceRightDL, 39 }, + { gIronKnuckleVambraceRightDL, 59 }, + + { gIronKnuckleArmRightDL, 38 }, + + { gIronKnuckleWaistDL, 8 }, + { gIronKnuckleWaistDL, 28 }, + + { gIronKnucklePauldronLeftDL, 8 }, + { gIronKnucklePauldronLeftDL, 31 }, + + { gIronKnuckleBootTipLeftDL, 15 }, + { gIronKnuckleBootTipLeftDL, 37 }, + { gIronKnuckleBootTipLeftDL, 52 }, + { gIronKnuckleBootTipLeftDL, 68 }, + + { gIronKnuckleWaistArmorLeftDL, 27 }, + { gIronKnuckleWaistArmorLeftDL, 46 }, + { gIronKnuckleWaistArmorLeftDL, 121 }, + + { gIronKnucklePauldronRightDL, 8 }, + { gIronKnucklePauldronRightDL, 32 }, + + { gIronKnuckleBootTipRightDL, 15 }, + { gIronKnuckleBootTipRightDL, 37 }, + { gIronKnuckleBootTipRightDL, 52 }, + { gIronKnuckleBootTipRightDL, 68 }, + + { gIronKnuckleWaistArmorRightDL, 23 }, + { gIronKnuckleWaistArmorRightDL, 42 }, + { gIronKnuckleWaistArmorRightDL, 106 }, +}; + +static DListPatchInfo arrowTipDListPatchInfos[] = { + { gameplay_keep_DL_013FF0, 46 }, + { gameplay_keep_DL_014370, 5 }, +}; + +void PatchArrowTipTexture() { + // Custom texture for Arrow tips that accounts for overflow texture reading + Gfx arrowTipTextureWithOverflowFixGfx = + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b_LOAD_BLOCK, 1, gameplay_keep_Tex_00CA30_Overflow); + + // Gfx instructions to fix authentic vanilla bug where the Arrow tips texture is read as the wrong size + Gfx arrowTipTextureWithSizeFixGfx[] = { + gsDPLoadTextureBlock(gameplay_keep_Tex_00CA30, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_MIRROR | G_TX_WRAP, + G_TX_MIRROR | G_TX_WRAP, 5, 5, 1, 1), + }; + + bool fixTexturesOOB = CVarGetInteger("gEnhancements.Fixes.FixTexturesOOB", 0); + + for (const auto& patchInfo : arrowTipDListPatchInfos) { + const char* dlist = patchInfo.dlist; + int start = patchInfo.startInstruction; + + // Patch using custom overflowed texture + if (!fixTexturesOOB) { + // Unpatch the other texture fix + for (size_t i = 4; i < 8; i++) { + int instruction = start + i; + std::string unpatchName = "arrowTipTextureWithSizeFix_" + std::to_string(instruction); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + } + + std::string patchName = "arrowTipTextureWithOverflowFix_" + std::to_string(start); + std::string patchName2 = "arrowTipTextureWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), start, arrowTipTextureWithOverflowFixGfx); + ResourceMgr_PatchGfxByName(dlist, patchName2.c_str(), start + 1, gsSPNoOp()); + } else { // Patch texture to use correct image size/fmt + // Unpatch the other texture fix + std::string unpatchName = "arrowTipTextureWithOverflowFix_" + std::to_string(start); + std::string unpatchName2 = "arrowTipTextureWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName2.c_str()); + + for (size_t i = 4; i < 8; i++) { + int instruction = start + i; + std::string patchName = "arrowTipTextureWithSizeFix_" + std::to_string(instruction); + + if (i == 0) { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, gsSPNoOp()); + } else { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, + arrowTipTextureWithSizeFixGfx[i - 1]); + } + } + } + } +} + +void PatchFreezardBodyTexture() { + // Custom texture for Freezard effect that accounts for overflow texture reading + Gfx freezardBodyTextureWithOverflowFixGfx = + gsDPSetTextureImage(G_IM_FMT_IA, G_IM_SIZ_16b_LOAD_BLOCK, 1, gEffIceFragmentTex_Overflow); + + // Gfx instructions to fix authentic vanilla bug where the Freezard effect texture is read as the wrong format + Gfx freezardBodyTextureWithFormatFixGfx[] = { + gsDPLoadTextureBlock(gEffIceFragmentTex, G_IM_FMT_I, G_IM_SIZ_8b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD), + }; + + bool fixTexturesOOB = CVarGetInteger("gEnhancements.Fixes.FixTexturesOOB", 0); + + for (const auto& patchInfo : freezardBodyDListPatchInfos) { + const char* dlist = patchInfo.dlist; + int start = patchInfo.startInstruction; + + // Patch using custom overflowed texture + if (!fixTexturesOOB) { + // Unpatch the other texture fix + for (size_t i = 0; i < 8; i++) { + int instruction = start + i; + std::string unpatchName = "freezardBodyTextureWithFormatFix_" + std::to_string(instruction); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + } + + std::string patchName = "freezardBodyTextureWithOverflowFix_" + std::to_string(start); + std::string patchName2 = "freezardBodyTextureWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), start, freezardBodyTextureWithOverflowFixGfx); + ResourceMgr_PatchGfxByName(dlist, patchName2.c_str(), start + 1, gsSPNoOp()); + } else { // Patch texture to use correct image size/fmt + // Unpatch the other texture fix + std::string unpatchName = "freezardBodyTextureWithOverflowFix_" + std::to_string(start); + std::string unpatchName2 = "freezardBodyTextureWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName2.c_str()); + + for (size_t i = 0; i < 8; i++) { + int instruction = start + i; + std::string patchName = "freezardBodyTextureWithFormatFix_" + std::to_string(instruction); + + if (i == 0) { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, gsSPNoOp()); + } else { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, + freezardBodyTextureWithFormatFixGfx[i - 1]); + } + } + } + } +} + +void PatchIronKnuckleFireTexture() { + // Custom texture for Iron Knuckle texture that accounts for overflow texture reading + Gfx ironKnuckleFireTexWithOverflowFixGfx = + gsDPSetTextureImage(G_IM_FMT_I, G_IM_SIZ_8b_LOAD_BLOCK, 1, gIronKnuckleFireTex_Overflow); + + // Gfx instructions to fix authentic vanilla bug where the Iron Knuckle texture is read as the wrong size + Gfx ironKnuckleFireTexWithFormatFixGfx[] = { + gsDPLoadTextureBlock_4b(gIronKnuckleFireTex, G_IM_FMT_I, 32, 64, 0, G_TX_MIRROR | G_TX_WRAP, + G_TX_MIRROR | G_TX_WRAP, 5, 6, G_TX_NOLOD, G_TX_NOLOD), + }; + + bool fixTexturesOOB = CVarGetInteger("gEnhancements.Fixes.FixTexturesOOB", 0); + + for (const auto& patchInfo : ironKnuckleDListPatchInfos) { + const char* dlist = patchInfo.dlist; + int start = patchInfo.startInstruction; + + // Patch using custom overflowed texture + if (!fixTexturesOOB) { + // Unpatch the other texture fix + for (size_t i = 0; i < 8; i++) { + int instruction = start + i; + std::string unpatchName = "ironKnuckleFireTexWithSizeFix_" + std::to_string(instruction); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + } + + std::string patchName = "ironKnuckleFireTexWithOverflowFix_" + std::to_string(start); + std::string patchName2 = "ironKnuckleFireTexWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), start, ironKnuckleFireTexWithOverflowFixGfx); + ResourceMgr_PatchGfxByName(dlist, patchName2.c_str(), start + 1, gsSPNoOp()); + } else { // Patch texture to use correct image size/fmt + // Unpatch the other texture fix + std::string unpatchName = "ironKnuckleFireTexWithOverflowFix_" + std::to_string(start); + std::string unpatchName2 = "ironKnuckleFireTexWithOverflowFix_" + std::to_string(start + 1); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str()); + ResourceMgr_UnpatchGfxByName(dlist, unpatchName2.c_str()); + + for (size_t i = 0; i < 8; i++) { + int instruction = start + i; + std::string patchName = "ironKnuckleFireTexWithSizeFix_" + std::to_string(instruction); + + if (i == 0) { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, gsSPNoOp()); + } else { + ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, + ironKnuckleFireTexWithFormatFixGfx[i - 1]); + } + } + } + } +} + +void GfxPatcher_ApplyOverflowTexturePatches() { + PatchArrowTipTexture(); + PatchFreezardBodyTexture(); + PatchIronKnuckleFireTexture(); +} + void PatchMiniGameCrossAndCircleSymbols() { // The X and O displayed in mini-games are incorrectly set to FMT_I instead of FMT_IA, // Fast3D throws an assert and does nothing as FMT_I with SIZ_16 is not a valid texture type. @@ -39,4 +268,6 @@ void PatchMiniGameCrossAndCircleSymbols() { // Applies required patches for authentic bugs to allow the game to play and render properly void GfxPatcher_ApplyNecessaryAuthenticPatches() { PatchMiniGameCrossAndCircleSymbols(); + + GfxPatcher_ApplyOverflowTexturePatches(); } diff --git a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h index 1a9c8b224..68eec242d 100644 --- a/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h +++ b/mm/2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h @@ -2,5 +2,6 @@ #define AUTHENTIC_GFX_PATCHES_H void GfxPatcher_ApplyNecessaryAuthenticPatches(); +void GfxPatcher_ApplyOverflowTexturePatches(); #endif // AUTHENTIC_GFX_PATCHES_H diff --git a/mm/assets/xml/GC_US/objects/gameplay_keep.xml b/mm/assets/xml/GC_US/objects/gameplay_keep.xml index 5da957423..f3e140c6f 100644 --- a/mm/assets/xml/GC_US/objects/gameplay_keep.xml +++ b/mm/assets/xml/GC_US/objects/gameplay_keep.xml @@ -85,6 +85,8 @@ + + @@ -1158,6 +1160,8 @@ + + diff --git a/mm/assets/xml/GC_US/objects/object_ik.xml b/mm/assets/xml/GC_US/objects/object_ik.xml index af271f081..df751f43a 100644 --- a/mm/assets/xml/GC_US/objects/object_ik.xml +++ b/mm/assets/xml/GC_US/objects/object_ik.xml @@ -58,6 +58,8 @@ + + diff --git a/mm/assets/xml/N64_US/objects/gameplay_keep.xml b/mm/assets/xml/N64_US/objects/gameplay_keep.xml index eee79cdd1..98141bcb6 100644 --- a/mm/assets/xml/N64_US/objects/gameplay_keep.xml +++ b/mm/assets/xml/N64_US/objects/gameplay_keep.xml @@ -85,6 +85,8 @@ + + @@ -1140,6 +1142,8 @@ + + diff --git a/mm/assets/xml/N64_US/objects/object_ik.xml b/mm/assets/xml/N64_US/objects/object_ik.xml index af271f081..df751f43a 100644 --- a/mm/assets/xml/N64_US/objects/object_ik.xml +++ b/mm/assets/xml/N64_US/objects/object_ik.xml @@ -58,6 +58,8 @@ + + From d1bbba626d3e71e56c8cb769f0dcefcb2347d772 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 7 Nov 2024 18:08:37 -0500 Subject: [PATCH 79/82] Add alt assets toggle to menus (#824) * Add alt assets toggle to menus * Add toggle to control alt asset hotkey --- mm/2s2h/BenGui/BenMenuBar.cpp | 6 ++++++ mm/2s2h/BenGui/SearchableMenuItems.h | 31 +++++++++++++++++++--------- mm/2s2h/BenPort.cpp | 10 +++++---- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 2911b6458..c3d3a0547 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -620,6 +620,12 @@ void DrawEnhancementsMenu() { ImGui::SeparatorText("Clock"); UIWidgets::CVarCombobox("Clock Type", "gEnhancements.Graphics.ClockType", clockTypeOptions); UIWidgets::CVarCheckbox("24 Hours Clock", "gEnhancements.Graphics.24HoursClock"); + + ImGui::SeparatorText("Mods"); + UIWidgets::CVarCheckbox("Use Alternate Assets", "gEnhancements.Mods.AlternateAssets", + { .tooltip = "Toggle between standard assets and alternate assets. Usually mods " + "will indicate if this setting has to be used or not." }); + MotionBlur_RenderMenuOptions(); ImGui::SeparatorText("Other"); UIWidgets::CVarCheckbox("Authentic logo", "gEnhancements.Graphics.AuthenticLogo", diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 6e5d65a9f..89e6a77cd 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -449,7 +449,7 @@ void AddSettings() { "gSettings.MenuTheme", "Changes the Theme of the Menu Widgets.", WIDGET_CVAR_COMBOBOX, - { .comboBoxOptions = menuThemeOptions } }, + { .defaultVariant = COLOR_INDIGO, .comboBoxOptions = menuThemeOptions } }, #if not defined(__SWITCH__) and not defined(__WIIU__) { "Menubar Controller Navigation", CVAR_IMGUI_CONTROLLER_NAV, "Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: " @@ -467,15 +467,6 @@ void AddSettings() { CVarGetInteger("gSettings.CursorVisibility", 0)); } }, #endif - { "Open App Files Folder", - "", - "Opens the folder that contains the save and mods folders, etc.", - WIDGET_BUTTON, - {}, - [](widgetInfo& info) { - std::string filesPath = Ship::Context::GetInstance()->GetAppDirectoryPath(); - SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); - } }, { "Search In Sidebar", "gSettings.SidebarSearch", "Displays the Search menu as a sidebar entry in Settings instead of in the header.", @@ -500,6 +491,20 @@ void AddSettings() { { "Search Input Autofocus", "gSettings.SearchAutofocus", "Search input box gets autofocus when visible. Does not affect using other widgets.", WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Alt Assets Tab hotkey", + .widgetCVar = "gEnhancements.Mods.AlternateAssetsHotkey", + .widgetTooltip = "Allows pressing the Tab key to toggle alternate assets", + .widgetType = WIDGET_CVAR_CHECKBOX, + .widgetOptions = { .defaultVariant = true } }, + { "Open App Files Folder", + "", + "Opens the folder that contains the save and mods folders, etc.", + WIDGET_BUTTON, + {}, + [](widgetInfo& info) { + std::string filesPath = Ship::Context::GetInstance()->GetAppDirectoryPath(); + SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); + } }, } } }); // Audio Settings settingsSidebar.push_back( @@ -1170,6 +1175,12 @@ void AddEnhancements() { { .comboBoxOptions = clockTypeOptions } }, { "24 Hours Clock", "gEnhancements.Graphics.24HoursClock", "Changes from a 12 Hour to a 24 Hour Clock", WIDGET_CVAR_CHECKBOX }, + { .widgetName = "Mods", .widgetType = WIDGET_SEPARATOR_TEXT }, + { .widgetName = "Use Alternate Assets", + .widgetCVar = "gEnhancements.Mods.AlternateAssets", + .widgetTooltip = "Toggle between standard assets and alternate assets. Usually mods will indicate if " + "this setting has to be used or not.", + .widgetType = WIDGET_CVAR_CHECKBOX }, { .widgetName = "Motion Blur", .widgetType = WIDGET_SEPARATOR_TEXT }, { "Motion Blur Mode", "gEnhancements.Graphics.MotionBlur.Mode", diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index dbb56d2af..7179d9db5 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -154,7 +154,7 @@ OTRGlobals::OTRGlobals() { Ship::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json", archiveFiles, {}, 3, { .SampleRate = 44100, .SampleLength = 1024, .DesiredBuffered = 2480 }); - prevAltAssets = CVarGetInteger("gAltAssets", 0); + prevAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0); context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets); // Override LUS defaults @@ -688,8 +688,10 @@ extern "C" void Graph_StartFrame() { #endif case KbScancode::LUS_KB_TAB: { // Toggle HD Assets - CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0)); - // ShouldClearTextureCacheAtEndOfFrame = true; + if (CVarGetInteger("gEnhancements.Mods.AlternateAssetsHotkey", 1)) { + CVarSetInteger("gEnhancements.Mods.AlternateAssets", + !CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0)); + } break; } } @@ -778,7 +780,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { } } - bool curAltAssets = CVarGetInteger("gAltAssets", 0); + bool curAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0); if (prevAltAssets != curAltAssets) { prevAltAssets = curAltAssets; Ship::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets); From be70a5a1236c0b7ef309cc239432fd61d7634f6b Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:51:58 -0500 Subject: [PATCH 80/82] Item tracker (#707) * Core tracker code mostly done. * Format * Clean up enums. * Format * Header cleanup * Update * use CVars * format * Add editor to modern menu * format * Fix item tracker cvar loading/saving and add item tracker button for modern menu * update button label --------- Co-authored-by: Archez --- mm/2s2h/BenGui/BenGui.cpp | 18 +- mm/2s2h/BenGui/BenMenuBar.cpp | 14 + mm/2s2h/BenGui/SearchableMenuItems.h | 9 + mm/2s2h/Enhancements/Trackers/ItemTracker.cpp | 506 ++++++++++++++++++ mm/2s2h/Enhancements/Trackers/ItemTracker.h | 82 +++ .../Trackers/ItemTrackerSettings.cpp | 77 +++ .../Trackers/ItemTrackerSettings.h | 12 + 7 files changed, 717 insertions(+), 1 deletion(-) create mode 100644 mm/2s2h/Enhancements/Trackers/ItemTracker.cpp create mode 100644 mm/2s2h/Enhancements/Trackers/ItemTracker.h create mode 100644 mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.cpp create mode 100644 mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.h diff --git a/mm/2s2h/BenGui/BenGui.cpp b/mm/2s2h/BenGui/BenGui.cpp index 4a9fa2967..51ae063ea 100644 --- a/mm/2s2h/BenGui/BenGui.cpp +++ b/mm/2s2h/BenGui/BenGui.cpp @@ -21,6 +21,9 @@ #include "include/global.h" #include "include/z64audio.h" +#include "Enhancements/Trackers/ItemTracker.h" +#include "Enhancements/Trackers/ItemTrackerSettings.h" + namespace BenGui { // MARK: - Delegates @@ -38,6 +41,8 @@ std::shared_ptr mEventLogWindow; std::shared_ptr mBenMenu; std::shared_ptr mBenInputEditorWindow; std::shared_ptr mNotificationWindow; +std::shared_ptr mItemTrackerWindow; +std::shared_ptr mItemTrackerSettingsWindow; void SetupGuiElements() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); @@ -94,6 +99,13 @@ void SetupGuiElements() { mEventLogWindow = std::make_shared("gWindows.EventLog", "Event Log", ImVec2(520, 600)); gui->AddGuiWindow(mEventLogWindow); + + mItemTrackerWindow = std::make_shared("gWindows.ItemTracker", "Item Tracker"); + gui->AddGuiWindow(mItemTrackerWindow); + + mItemTrackerSettingsWindow = std::make_shared("gWindows.ItemTrackerSettings", + "Item Tracker Settings", ImVec2(800, 400)); + gui->AddGuiWindow(mItemTrackerSettingsWindow); gui->SetPadBtnTogglesMenu(); mNotificationWindow = std::make_shared("gWindows.Notifications", "Notifications Window"); @@ -102,6 +114,9 @@ void SetupGuiElements() { } void Destroy() { + auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); + + gui->RemoveAllGuiWindows(); mBenMenuBar = nullptr; mBenMenu = nullptr; mStatsWindow = nullptr; @@ -111,9 +126,10 @@ void Destroy() { mCollisionViewerWindow = nullptr; mEventLogWindow = nullptr; mNotificationWindow = nullptr; - mSaveEditorWindow = nullptr; mHudEditorWindow = nullptr; mActorViewerWindow = nullptr; + mItemTrackerWindow = nullptr; + mItemTrackerSettingsWindow = nullptr; } } // namespace BenGui diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index c3d3a0547..58b7f6f39 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -12,6 +12,9 @@ #include "2s2h/DeveloperTools/DeveloperTools.h" #include "HudEditor.h" +#include "2s2h/Enhancements/Trackers/ItemTracker.h" +#include "2s2h/Enhancements/Trackers/ItemTrackerSettings.h" + extern "C" { #include "z64.h" #include "functions.h" @@ -345,6 +348,8 @@ void DrawSettingsMenu() { } extern std::shared_ptr mHudEditorWindow; +extern std::shared_ptr mItemTrackerWindow; +extern std::shared_ptr mItemTrackerSettingsWindow; void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Enhancements")) { @@ -799,6 +804,15 @@ void DrawEnhancementsMenu() { { .tooltip = "Enables the Hud Editor window, allowing you to edit your hud" }); } + if (mItemTrackerWindow) { + UIWidgets::WindowButton("Item Tracker", "gWindows.ItemTracker", mItemTrackerWindow); + } + + if (mItemTrackerSettingsWindow) { + UIWidgets::WindowButton("Item Tracker Settings", "gWindows.ItemTrackerSettings", + mItemTrackerSettingsWindow); + } + ImGui::EndMenu(); } } diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index 89e6a77cd..122344851 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1424,6 +1424,15 @@ void AddEnhancements() { "Enables the HUD Editor window, allowing you to modify your HUD", WIDGET_WINDOW_BUTTON, { .size = UIWidgets::Sizes::Inline, .windowName = "HUD Editor" } } } } }); + enhancementsSidebar.push_back( + { "Item Tracker", + 1, + { // Item Tracker Settings + { { "Popout Item Tracker Settings", + "gWindows.ItemTrackerSettings", + "", + WIDGET_WINDOW_BUTTON, + { .size = UIWidgets::Sizes::Inline, .windowName = "Item Tracker Settings" } } } } }); } void AddDevTools() { diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker.cpp b/mm/2s2h/Enhancements/Trackers/ItemTracker.cpp new file mode 100644 index 000000000..641ffb97e --- /dev/null +++ b/mm/2s2h/Enhancements/Trackers/ItemTracker.cpp @@ -0,0 +1,506 @@ +#include "ItemTracker.h" +#include "Context.h" +#include "config/Config.h" +#include "assets/archives/icon_item_static/icon_item_static_yar.h" +#include "assets/archives/icon_item_24_static/icon_item_24_static_yar.h" + +#define CFG_TRACKER_ITEM(var) ("ItemTracker." var) + +using namespace Ship; + +ItemTrackerWindow::~ItemTrackerWindow() { + auto config = Context::GetInstance()->GetConsoleVariables(); + + config->SetFloat(CFG_TRACKER_ITEM("BgColorR"), mBgColor.x); + config->SetFloat(CFG_TRACKER_ITEM("BgColorG"), mBgColor.y); + config->SetFloat(CFG_TRACKER_ITEM("BgColorB"), mBgColor.z); + config->SetFloat(CFG_TRACKER_ITEM("BgColorA"), mBgColor.w); + config->SetFloat(CFG_TRACKER_ITEM("IconSize"), mIconSize); + config->SetFloat(CFG_TRACKER_ITEM("IconSpacing"), mIconSpacing); + config->SetFloat(CFG_TRACKER_ITEM("TextSize"), mTextSize); + config->SetFloat(CFG_TRACKER_ITEM("TextOffset"), mTextOffset); + config->SetInteger(CFG_TRACKER_ITEM("WindowType"), (int8_t)mWindowType); + config->SetInteger(CFG_TRACKER_ITEM("IsDraggable"), mIsDraggable); + config->SetInteger(CFG_TRACKER_ITEM("OnlyDrawPaused"), mOnlyDrawPaused); + config->SetInteger(CFG_TRACKER_ITEM("DrawCurrentAmmo"), mCapacityModes[ItemTrackerCapacityMode::DrawCurrent]); + config->SetInteger(CFG_TRACKER_ITEM("DrawMaxAmmo"), mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity]); + config->SetInteger(CFG_TRACKER_ITEM("DrawMaxCapacity"), mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]); + config->SetInteger(CFG_TRACKER_ITEM("InventoryDrawMode"), (int8_t)mItemDrawModes[SECTION_INVENTORY]); + config->SetInteger(CFG_TRACKER_ITEM("MasksDrawMode"), (int8_t)mItemDrawModes[SECTION_MASKS]); + config->SetInteger(CFG_TRACKER_ITEM("SongsDrawMode"), (int8_t)mItemDrawModes[SECTION_SONGS]); + config->SetInteger(CFG_TRACKER_ITEM("DungeonDrawMode"), (int8_t)mItemDrawModes[SECTION_DUNGEON]); + + config->Save(); +} + +void ItemTrackerWindow::LoadSettings() { + auto config = Context::GetInstance()->GetConsoleVariables(); + + mCapacityModes.fill(false); + + mBgColor.x = config->GetFloat(CFG_TRACKER_ITEM("BgColorR"), 0.0f); + mBgColor.y = config->GetFloat(CFG_TRACKER_ITEM("BgColorG"), 0.0f); + mBgColor.z = config->GetFloat(CFG_TRACKER_ITEM("BgColorB"), 0.0f); + mBgColor.w = config->GetFloat(CFG_TRACKER_ITEM("BgColorA"), 0.0f); + mIconSize = config->GetFloat(CFG_TRACKER_ITEM("IconSize"), 13.0f); + mIconSpacing = config->GetFloat(CFG_TRACKER_ITEM("IconSpacing"), 12.0f); + mTextSize = config->GetFloat(CFG_TRACKER_ITEM("TextSize"), 13.0f); + mTextOffset = config->GetFloat(CFG_TRACKER_ITEM("TextOffset"), 0.0f); + mWindowType = + (TrackerWindowType)config->GetInteger(CFG_TRACKER_ITEM("WindowType"), (int8_t)TrackerWindowType::Floating); + mIsDraggable = config->GetInteger(CFG_TRACKER_ITEM("IsDraggable"), false); + mOnlyDrawPaused = config->GetInteger(CFG_TRACKER_ITEM("OnlyDrawPaused"), false); + mCapacityModes[ItemTrackerCapacityMode::DrawCurrent] = + config->GetInteger(CFG_TRACKER_ITEM("DrawCurrentAmmo"), false); + mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity] = + config->GetInteger(CFG_TRACKER_ITEM("DrawMaxAmmo"), false); + mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity] = + config->GetInteger(CFG_TRACKER_ITEM("DrawMaxCapacity"), false); + mItemDrawModes[SECTION_INVENTORY] = (ItemTrackerDisplayType)config->GetInteger( + CFG_TRACKER_ITEM("InventoryDrawMode"), (int32_t)ItemTrackerDisplayType::Hidden); + mItemDrawModes[SECTION_MASKS] = (ItemTrackerDisplayType)config->GetInteger(CFG_TRACKER_ITEM("MasksDrawMode"), + (int32_t)ItemTrackerDisplayType::Hidden); + mItemDrawModes[SECTION_SONGS] = (ItemTrackerDisplayType)config->GetInteger(CFG_TRACKER_ITEM("SongsDrawMode"), + (int32_t)ItemTrackerDisplayType::Hidden); + mItemDrawModes[SECTION_DUNGEON] = (ItemTrackerDisplayType)config->GetInteger( + CFG_TRACKER_ITEM("DungeonDrawMode"), (int32_t)ItemTrackerDisplayType::Hidden); +} + +void ItemTrackerWindow::BeginFloatingWindows(const char* name, ImGuiWindowFlags flags) { + ImGuiWindowFlags windowFlags = flags; + + if (windowFlags == 0) { + windowFlags |= + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize; + } + + if (mWindowType == TrackerWindowType::Floating) { + ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID); + windowFlags |= ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar; + + if (!mIsDraggable) { + windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove; + } + } + ImGui::PushStyleColor(ImGuiCol_WindowBg, mBgColor); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + ImGui::Begin(name, nullptr, windowFlags); +} + +void EndFloatingWindows() { + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::End(); +} + +static constexpr ImVec4 opaqueTex = { 1.0f, 1.0f, 1.0f, 1.0f }; +static constexpr ImVec4 fadedTex = { 0.5f, 0.5f, 0.5f, 0.5f }; + +void DrawItem(char* tex, bool drawFaded, float itemSize) { + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(tex), ImVec2(itemSize, itemSize), + ImVec2(0, 0), ImVec2(1, 1), drawFaded ? fadedTex : opaqueTex); +} + +static constexpr std::array songInfo = { + ImVec4(0.588f, 1.0f, 0.392f, 1.0f), // QUEST_SONG_SONATA + ImVec4(1.0f, 0.313f, 0.156f, 1.0f), // QUEST_SONG_LULLABY + ImVec4(0.392f, 0.588f, 1.0f, 1.0f), // QUEST_SONG_BOSSA_NOVA + ImVec4(1.0f, 0.627f, 0.0f, 1.0f), // QUEST_SONG_ELEGY + ImVec4(1.0f, 0.392f, 1.0f, 1.0f), // QUEST_SONG_OATH +}; + +void ItemTrackerWindow::DrawNote(size_t songIndex, bool drawFaded) { + ImVec4 color; + // Scale the note to 24*36 from 16*24 because all other items assume 36*36. + constexpr float noteTo36scale = 36.0f / 24.0f; + + const float iconScale = mIconSize / 36.0f; + + // Scale the note icon with the rest of the items. + const ImVec2 scaledNoteSize(noteTo36scale * 16.0f * iconScale, noteTo36scale * 24.0f * iconScale); + + if (songIndex >= 5) { + color = songInfo[songIndex - 5]; + } else { + color = { 1.0f, 1.0f, 1.0f, 1.0f }; + } + if (drawFaded) { + color.w = .5f; + } + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gItemIconSongNoteTex), + scaledNoteSize, ImVec2(0, 0), ImVec2(1, 1), color); +} + +extern "C" { +#include "z64save.h" +#include "macros.h" +#include "z64.h" +extern void* gItemIcons[131]; +extern uint8_t gItemSlots[77]; +extern SaveContext gSaveContext; +extern u32 gBitFlags[32]; +extern PlayState* gPlayState; +extern u16 gUpgradeCapacities[][4]; +extern u32 gUpgradeMasks[]; +extern u8 gUpgradeShifts[]; +} + +// The textures in gItemIcons aren't in the same order as the subscreen +static constexpr std::array sMaskTextures = { + gItemIconPostmansHatTex, gItemIconAllNightMaskTex, gItemIconBlastMaskTex, gItemIconStoneMaskTex, + gItemIconGreatFairyMaskTex, gItemIconDekuMaskTex, gItemIconKeatonMaskTex, gItemIconBremenMaskTex, + gItemIconBunnyHoodTex, gItemIconDonGeroMaskTex, gItemIconMaskOfScentsTex, gItemIconGoronMaskTex, + gItemIconRomaniMaskTex, gItemIconCircusLeaderMaskTex, gItemIconKafeisMaskTex, gItemIconCouplesMaskTex, + gItemIconMaskOfTruthTex, gItemIconZoraMaskTex, gItemIconKamaroMaskTex, gItemIconGibdoMaskTex, + gItemIconGaroMaskTex, gItemIconCaptainsHatTex, gItemIconGiantsMaskTex, gItemIconFierceDeityMaskTex, +}; + +// The songs in the enum are in the wrong order and has the unused songs +static constexpr std::array sSongBits = { + QUEST_SONG_TIME, QUEST_SONG_HEALING, QUEST_SONG_EPONA, QUEST_SONG_SOARING, QUEST_SONG_STORMS, + QUEST_SONG_SONATA, QUEST_SONG_LULLABY, QUEST_SONG_BOSSA_NOVA, QUEST_SONG_ELEGY, QUEST_SONG_OATH, +}; + +bool ItemTrackerWindow::HasAmmoCount(int itemId) { + switch (itemId) { + case ITEM_BOW: + case ITEM_BOMB: + case ITEM_BOMBCHU: + case ITEM_DEKU_STICK: + case ITEM_DEKU_NUT: + return true; + default: + return false; + } +} + +ItemTrackerWindow::AmmoInfo ItemTrackerWindow::GetAmmoInfo(int itemId) { + AmmoInfo info; + switch (itemId) { + case ITEM_BOW: + info = { .cur = (uint8_t)AMMO(ITEM_BOW), .curCap = (uint8_t)CUR_CAPACITY(UPG_QUIVER), .maxCap = 50 }; + break; + case ITEM_BOMB: + info = { .cur = (uint8_t)AMMO(ITEM_BOMB), .curCap = (uint8_t)CUR_CAPACITY(UPG_BOMB_BAG), .maxCap = 40 }; + break; + case ITEM_BOMBCHU: + info = { .cur = (uint8_t)AMMO(ITEM_BOMBCHU), .curCap = (uint8_t)CUR_CAPACITY(UPG_BOMB_BAG), .maxCap = 40 }; + break; + case ITEM_DEKU_STICK: + info = { .cur = (uint8_t)AMMO(ITEM_DEKU_STICK), + .curCap = (uint8_t)CUR_CAPACITY(UPG_DEKU_STICKS), + .maxCap = 30 }; + break; + case ITEM_DEKU_NUT: + info = { .cur = (uint8_t)AMMO(ITEM_DEKU_NUT), + .curCap = (uint8_t)CUR_CAPACITY(UPG_DEKU_NUTS), + .maxCap = 40 }; + break; + default: + info = { 0 }; + } + return info; +} + +void ItemTrackerWindow::DrawAmmoCount(int itemId, const ImVec2& iconPos) { + // Zeroing 16 bytes is a little more optimized than 10 + char ammoStr[16] = { 0 }; + char curStr[4] = { 0 }; + char curCapStr[4] = { 0 }; + char maxCapStr[4] = { 0 }; + AmmoInfo info; + + if (!HasAmmoCount(itemId)) { + return; + } + + info = GetAmmoInfo(itemId); + + if (mCapacityModes[ItemTrackerCapacityMode::DrawCurrent]) { + snprintf(curStr, std::size(curStr), "%d", info.cur); + if (mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity] || + mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) { + strncat(curStr, "/", 1); + } + } + + if (mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity]) { + snprintf(curCapStr, std::size(curStr), "%d", info.curCap); + if (mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) { + strncat(curCapStr, "/", 1); + } + } + + if (mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) { + snprintf(maxCapStr, std::size(curStr), "%d", info.maxCap); + } + + ImGui::SetWindowFontScale(mTextSize / 13.0f); + ImVec2 iconPos2 = ImGui::GetCursorScreenPos(); + + snprintf(ammoStr, std::size(ammoStr), "%s%s%s", curStr, curCapStr, maxCapStr); + + float x = iconPos2.x + (mIconSize / 2.0f) - (ImGui::CalcTextSize(ammoStr).x / 2.0f); + // Normalize the offset based on the icon being 36x36 to account for larger icons. + ImGui::SetCursorScreenPos({ x, iconPos2.y - (mTextOffset / 36.0f) * mIconSize }); + + ImGui::Text("%s", ammoStr); +} + +int ItemTrackerWindow::DrawItems(int columns, int prevDrawnColumns) { + int topPadding = 0; + size_t i = 0; + // Draw items minus bottles + for (; i < 24 - BOTTLE_MAX; i++) { + bool drawFaded = false; + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + char* texToDraw; + const ImVec2 pos = { (column * (mIconSize + mIconSpacing) + 8.0f), + (row * (mIconSize + mIconSpacing)) + 8.0f + topPadding }; + + ImGui::SetCursorPos(pos); + + if (gSaveContext.save.saveInfo.inventory.items[i] == ITEM_NONE) { + if (column == 5) { + // BENTODO these slots can hold multiple items. Something fun to do would be to draw the multitile + // design here instead of nothing DrawMultiItem(nullptr, false, row, column); + continue; + } + texToDraw = (char*)gItemIcons[i]; + drawFaded = true; + } else { + texToDraw = (char*)gItemIcons[gSaveContext.save.saveInfo.inventory.items[i]]; + } + ImGui::BeginGroup(); + DrawItem(texToDraw, drawFaded, mIconSize); + DrawAmmoCount((int)i, pos); + ImGui::EndGroup(); + } + + // DrawBottles + for (; i < 24; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f), + (row * (mIconSize + mIconSpacing)) + 8.0f + topPadding)); + + if (gSaveContext.save.saveInfo.inventory.items[i] == ITEM_NONE) { + DrawItem(const_cast(gItemIconEmptyBottleTex), true, mIconSize); + } else { + DrawItem((char*)gItemIcons[gSaveContext.save.saveInfo.inventory.items[i]], false, mIconSize); + } + } + return 4; +} + +int ItemTrackerWindow::DrawMasks(int columns, int prevDrawnColumns) { + int topPadding = 0; + // Masks + for (size_t i = 0; i < 24; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f), + (row * (mIconSize + mIconSpacing)) + 8.0f + topPadding)); + + DrawItem(const_cast(sMaskTextures[i]), gSaveContext.save.saveInfo.inventory.items[i + 24] == ITEM_NONE, + mIconSize); + } + return 4; +} + +static int RoundDown(int orig, int nearest) { + int res = orig % nearest; + return orig - res; +} + +int ItemTrackerWindow::DrawSongs(int columns, int prevDrawnColumns) { + int topPadding = 0; + + for (size_t i = 0; i < sSongBits.size(); i++) { + int row = prevDrawnColumns + (i / 5); + int column = i % 5; + ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f), + (row * (mIconSize + mIconSpacing)) + 8.0f + topPadding)); + + DrawNote(i, !CHECK_QUEST_ITEM(sSongBits[i])); + } + return 2; +} + +int ItemTrackerWindow::DrawDungeonItemsVert(int columns, int prevDrawnColumns) { + int topPadding = 0; + + // The icon size is based on 36x36. + float iconScale = mIconSize / 36.0f; + // Yes this does nothing. But for other icon sizes it will. + float squareIconSize = iconScale * 36.0f; + float rectIconSize = iconScale * 36.0f; + + for (size_t i = 0; i < 4; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (squareIconSize + mIconSpacing) + 8.0f), + (row * (squareIconSize + mIconSpacing)) + 8.0f + topPadding)); + DrawItem(static_cast(gItemIcons[i + ITEM_REMAINS_ODOLWA]), !CHECK_QUEST_ITEM(i), squareIconSize); + } + + prevDrawnColumns++; + + for (size_t i = 0; i < 4; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f), + (row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding)); + DrawItem(const_cast(gQuestIconBossKeyTex), !CHECK_DUNGEON_ITEM(DUNGEON_BOSS_KEY, i), rectIconSize); + } + + prevDrawnColumns++; + + for (size_t i = 0; i < 4; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f), + (row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding)); + DrawItem(const_cast(gQuestIconCompassTex), !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, i), rectIconSize); + } + + prevDrawnColumns++; + + for (size_t i = 0; i < 4; i++) { + int row = prevDrawnColumns + (i / columns); + int column = i % columns; + ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f), + (row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding)); + DrawItem(const_cast(gQuestIconDungeonMapTex), !CHECK_DUNGEON_ITEM(DUNGEON_MAP, i), rectIconSize); + } + + return 4; +} + +void ItemTrackerWindow::DrawItemsInRows(int columns) { + float iconSize = mIconSize; + float iconSpacing = mIconSpacing; + int topPadding = 0; + int mainWindowPos = 0; + int advancedBy = 0; + + if (gPlayState == nullptr) { + ImGui::Text("Item tracker not available"); + return; + } + if (mOnlyDrawPaused && gPlayState->pauseCtx.state == 0) { + return; + } + if (mItemDrawModes[SECTION_INVENTORY] != ItemTrackerDisplayType::Hidden) { + if (mItemDrawModes[SECTION_INVENTORY] == ItemTrackerDisplayType::Seperate) { + BeginFloatingWindows("Items"); + } + advancedBy = DrawItems(6, mainWindowPos); + if (mItemDrawModes[SECTION_INVENTORY] == ItemTrackerDisplayType::Seperate) { + EndFloatingWindows(); + } else { + mainWindowPos += advancedBy; + } + } + + if (mItemDrawModes[SECTION_MASKS] != ItemTrackerDisplayType::Hidden) { + int drawPos = mainWindowPos; + if (mItemDrawModes[SECTION_MASKS] == ItemTrackerDisplayType::Seperate) { + drawPos = 0; + BeginFloatingWindows("Masks"); + } + advancedBy = DrawMasks(6, drawPos); + if (mItemDrawModes[SECTION_MASKS] == ItemTrackerDisplayType::Seperate) { + EndFloatingWindows(); + } else { + mainWindowPos += advancedBy; + } + } + + if (mItemDrawModes[SECTION_SONGS] != ItemTrackerDisplayType::Hidden) { + int drawPos = mainWindowPos; + if (mItemDrawModes[SECTION_SONGS] == ItemTrackerDisplayType::Seperate) { + drawPos = 0; + BeginFloatingWindows("Songs"); + } + advancedBy = DrawSongs(5, drawPos); + if (mItemDrawModes[SECTION_SONGS] == ItemTrackerDisplayType::Seperate) { + EndFloatingWindows(); + } else { + mainWindowPos += advancedBy; + } + } + + if (mItemDrawModes[SECTION_DUNGEON] != ItemTrackerDisplayType::Hidden) { + int drawPos = mainWindowPos; + if (mItemDrawModes[SECTION_DUNGEON] == ItemTrackerDisplayType::Seperate) { + drawPos = 0; + BeginFloatingWindows("Dungeon Items"); + } + advancedBy = DrawDungeonItemsVert(6, drawPos); + if (mItemDrawModes[SECTION_DUNGEON] == ItemTrackerDisplayType::Seperate) { + EndFloatingWindows(); + } else { + mainWindowPos += advancedBy; + } + } +} + +ImVec4* ItemTrackerWindow::GetBgColorPtr() { + return &mBgColor; +} + +float* ItemTrackerWindow::GetIconSizePtr() { + return &mIconSize; +} + +float* ItemTrackerWindow::GetIconSpacingPtr() { + return &mIconSpacing; +} + +float* ItemTrackerWindow::GetTextSizePtr() { + return &mTextSize; +} + +float* ItemTrackerWindow::GetTextOffsetPtr() { + return &mTextOffset; +} + +TrackerWindowType* ItemTrackerWindow::GetWindowTypePtr() { + return &mWindowType; +} + +bool* ItemTrackerWindow::GetIsDraggablePtr() { + return &mIsDraggable; +} + +bool* ItemTrackerWindow::GetOnlyShowPausedPtr() { + return &mOnlyDrawPaused; +} + +ItemTrackerDisplayType* ItemTrackerWindow::GetDrawModePtr(ItemTrackerSection type) { + return &mItemDrawModes[type]; +} + +bool* ItemTrackerWindow::GetCapacityModePtr(ItemTrackerCapacityMode mode) { + return &mCapacityModes[mode]; +} + +void ItemTrackerWindow::Draw() { + if (!IsVisible()) { + return; + } + BeginFloatingWindows("Inventory Items Tracker"); + DrawItemsInRows(); + EndFloatingWindows(); +} +void ItemTrackerWindow::InitElement() { + LoadSettings(); +} + +void ItemTrackerWindow::DrawElement() { +} diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker.h b/mm/2s2h/Enhancements/Trackers/ItemTracker.h new file mode 100644 index 000000000..6f8cbe1c5 --- /dev/null +++ b/mm/2s2h/Enhancements/Trackers/ItemTracker.h @@ -0,0 +1,82 @@ +#include "window/gui/Gui.h" +#include "window/gui/GuiWindow.h" +#include + +typedef enum class TrackerWindowType : uint8_t { + Floating, + Window, +} TrackerWindowType; + +typedef enum class ItemTrackerDisplayType : int8_t { + Hidden, + MainWindow, + Seperate, +} ItemTrackerDisplayType; + +typedef enum { + SECTION_INVENTORY, + SECTION_MASKS, + SECTION_SONGS, + SECTION_DUNGEON, + SECTION_MAX, +} ItemTrackerSection; + +typedef enum { + DrawCurrent, + DrawCurCapacity, + DrawMaxCapacity, + DrawCapacityMax, +} ItemTrackerCapacityMode; + +class ItemTrackerWindow : public Ship::GuiWindow { + typedef struct AmmoInfo { + uint8_t cur; + uint8_t curCap; + uint8_t maxCap; + } AmmoInfo; + + public: + using GuiWindow::GuiWindow; + ~ItemTrackerWindow(); + void Draw() override; + + ImVec4* GetBgColorPtr(); + float* GetIconSizePtr(); + float* GetIconSpacingPtr(); + float* GetTextSizePtr(); + float* GetTextOffsetPtr(); + TrackerWindowType* GetWindowTypePtr(); + bool* GetIsDraggablePtr(); + bool* GetOnlyShowPausedPtr(); + ItemTrackerDisplayType* GetDrawModePtr(ItemTrackerSection type); + bool* GetCapacityModePtr(ItemTrackerCapacityMode mode); + void LoadSettings(); + + protected: + void InitElement() override; + void DrawElement() override; + void UpdateElement() override{}; + + private: + void BeginFloatingWindows(const char* name, ImGuiWindowFlags flags = 0); + void DrawItemsInRows(int columns = 6); + int DrawItems(int columns, int startAt); + int DrawMasks(int columns, int startAt); + int DrawSongs(int columns, int startAt); + void DrawNote(size_t songIndex, bool drawFaded); + int DrawDungeonItemsVert(int columns, int startAt); + void DrawAmmoCount(int itemId, const ImVec2& iconPos); + bool HasAmmoCount(int itemId); + AmmoInfo GetAmmoInfo(int itemId); + + ImVec4 mBgColor; + float mIconSize = 36.0f; + float mIconSpacing = 12.0f; + float mTextSize = 13.0f; + float mTextOffset = 0.0f; + TrackerWindowType mWindowType = TrackerWindowType::Floating; + bool mIsDraggable = false; + bool mOnlyDrawPaused = false; + std::array mCapacityModes; + std::array mItemDrawModes; +}; diff --git a/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.cpp b/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.cpp new file mode 100644 index 000000000..01c2089aa --- /dev/null +++ b/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.cpp @@ -0,0 +1,77 @@ +#include "ItemTrackerSettings.h" +#include "ItemTracker.h" +#include "../../BenGui/UIWidgets.hpp" + +namespace BenGui { +extern std::shared_ptr mItemTrackerWindow; +} + +using namespace BenGui; + +void ItemTrackerSettingsWindow::UpdateElement() { +} + +void ItemTrackerSettingsWindow::InitElement() { +} + +static const char* windowTypes[2] = { "Floating", "Window" }; +static const char* displayTypes[3] = { "Hidden", "Main Window", "Separate" }; +static const char* displayModes[2] = { "Always", "Combo Button Hold" }; + +void ItemTrackerSettingsWindow::DrawElement() { + ImGui::SetNextWindowSize(ImVec2(733, 472), ImGuiCond_FirstUseEver); + const UIWidgets::FloatSliderOptions sliderOpts = { .format = "%.0f", .step = 1.0f }; + + if (!ImGui::BeginChild("Item Tracker Settings")) { + ImGui::EndChild(); + return; + } + + UIWidgets::WindowButton("Show/Hide Item Tracker", "gWindows.ItemTracker", mItemTrackerWindow, + { .size = UIWidgets::Sizes::Inline }); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f }); + ImGui::BeginTable("itemTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV); + ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); + ImGui::TableSetupColumn("Section settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); + ImGui::TableHeadersRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("BG Color"); + ImGui::SameLine(); + + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); + + ImGui::ColorEdit4("BG Color", (float*)mItemTrackerWindow->GetBgColorPtr(), + ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoLabel); + + UIWidgets::Combobox("Window Type", mItemTrackerWindow->GetWindowTypePtr(), windowTypes); + UIWidgets::Checkbox("Enable Dragging", mItemTrackerWindow->GetIsDraggablePtr()); + UIWidgets::Checkbox("Only enable while paused", mItemTrackerWindow->GetOnlyShowPausedPtr()); + + UIWidgets::SliderFloat("Icon size : %.0fpx", mItemTrackerWindow->GetIconSizePtr(), 0.0f, 128.0f, sliderOpts); + UIWidgets::SliderFloat("Icon margins : %.0fpx", mItemTrackerWindow->GetIconSpacingPtr(), -5.0f, 50.0f, sliderOpts); + UIWidgets::SliderFloat("Text size : %.0fpx", mItemTrackerWindow->GetTextSizePtr(), 1.0f, 30.0f, sliderOpts); + UIWidgets::SliderFloat("Text Offset : %0.fpx", mItemTrackerWindow->GetTextOffsetPtr(), 0.0f, 40.0f, sliderOpts); + + ImGui::TableNextColumn(); + + UIWidgets::Combobox("Inventory", mItemTrackerWindow->GetDrawModePtr(SECTION_INVENTORY), displayTypes); + UIWidgets::Combobox("Masks", mItemTrackerWindow->GetDrawModePtr(SECTION_MASKS), displayTypes); + UIWidgets::Combobox("Songs", mItemTrackerWindow->GetDrawModePtr(SECTION_SONGS), displayTypes); + UIWidgets::Combobox("Dungeon Items", mItemTrackerWindow->GetDrawModePtr(SECTION_DUNGEON), displayTypes); + + UIWidgets::Checkbox("Draw Current Ammo", + mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawCurrent)); + + UIWidgets::Checkbox("Draw Current Capacity", + mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawCurCapacity)); + + UIWidgets::Checkbox("Draw Max Capacity", + mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawMaxCapacity)); + + ImGui::PopStyleVar(1); + ImGui::EndTable(); + + ImGui::EndChild(); +} diff --git a/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.h b/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.h new file mode 100644 index 000000000..b4df6fd4c --- /dev/null +++ b/mm/2s2h/Enhancements/Trackers/ItemTrackerSettings.h @@ -0,0 +1,12 @@ +#include "window/gui/Gui.h" +#include "window/gui/GuiWindow.h" + +class ItemTrackerSettingsWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + protected: + void InitElement() override; + void DrawElement() override; + void UpdateElement() override; +}; From 449a2ebc70d12a7f5c01d6833100435af152ee6c Mon Sep 17 00:00:00 2001 From: Archez Date: Sat, 9 Nov 2024 21:15:10 -0500 Subject: [PATCH 81/82] Archive version checking and regeneration (#822) * Add archive version checking and regeneration * update building docs and copy assets for visual studio --- docs/BUILDING.md | 83 ++++++---- mm/2s2h/BenPort.cpp | 292 ++++++++++++++++++++++------------ mm/2s2h/BenPort.h | 4 - mm/2s2h/Extractor/Extract.cpp | 105 +++++------- mm/2s2h/Extractor/Extract.h | 5 +- mm/CMakeLists.txt | 14 +- 6 files changed, 298 insertions(+), 205 deletions(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 8f6c7ec2e..34775cdd2 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -22,7 +22,7 @@ It is recommended that you install Python and Git standalone, the install proces _Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule update --init`` after cloning to pull in the libultraship submodule!_ -2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice +2. After setup and initial build, use the built-in O2R extraction to make your mm.o2r file. _Note: Instructions assume using powershell_ ```powershell @@ -30,22 +30,17 @@ _Note: Instructions assume using powershell_ cd 2ship2harkinian # Setup cmake project -& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -# Extract assets & generate OTR (run this anytime you need to regenerate OTR) -& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssets # --config Release (if you're packaging) -# Compile project -& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 # --config Release (if you're packaging) +# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 -# Now you can run the executable in .\build\x64 - -# If you need to clean the project you can run -& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target clean - -# If you need to regenerate the asset headers to check them into source -& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssetHeaders - -# If you need a newer 2ship.o2r only +# Generate 2ship.o2r & 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target Generate2ShipOtr + +# Compile project +# Add `--config Release` if you're packaging +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 + +# Now you can run the executable in .\build\x64 or run in Visual Studio ``` ### Developing 2S2H @@ -76,6 +71,19 @@ cd "build/x64" & 'C:\Program Files\CMake\bin\cpack.exe' -G ZIP ``` +### Additional CMake Targets +#### Clean +```powershell +# If you need to clean the project you can run +C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target clean +``` + +#### Regenerate Asset Headers +```powershell +# If you need to regenerate the asset headers to check them into source +C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target ExtractAssetHeaders +``` + ## Linux ### Install dependencies #### Debian/Ubuntu @@ -124,13 +132,16 @@ cd 2ship2harkinian git submodule update --init # Generate Ninja project -cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -DPython3_EXECUTABLE=$(which python3) (if you are using non-standard Python installations such as PyEnv) +# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging +# Add `-DPython3_EXECUTABLE=$(which python3)` if you are using non-standard Python installations such as PyEnv +cmake -H. -Bbuild-cmake -GNinja # Generate 2ship.o2r cmake --build build-cmake --target Generate2ShipOtr # Compile the project -cmake --build build-cmake # --config Release (if you're packaging) +# Add `--config Release` if you're packaging +cmake --build build-cmake # Now you can run the executable in ./build-cmake/mm/2s2h.elf # To develop the project open the repository in VSCode (or your preferred editor) @@ -157,7 +168,6 @@ cmake --build build-cmake --target clean #### Regenerate Asset Headers ```bash # If you need to regenerate the asset headers to check them into source -cp OTRExporter cmake --build build-cmake --target ExtractAssetHeaders ``` @@ -174,27 +184,21 @@ git clone https://github.com/HarbourMasters/2ship2harkinian.git cd 2ship2harkinian # Clone the submodule libultraship git submodule update --init -# Copy the baserom to the OTRExporter folder -cp OTRExporter + # Generate Ninja project -cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -# Extract assets & generate OTR (run this anytime you need to regenerate OTR) -cmake --build build-cmake --target ExtractAssets +# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging +cmake -H. -Bbuild-cmake -GNinja + +# Generate 2ship.o2r +cmake --build build-cmake --target Generate2ShipOtr + # Compile the project -cmake --build build-cmake # --config Release (if you're packaging) +# Add `--config Release` if you're packaging +cmake --build build-cmake # Now you can run the executable file: ./build-cmake/mm/2s2h-macos # To develop the project open the repository in VSCode (or your preferred editor) - -# If you need to clean the project you can run -cmake --build build-cmake --target clean - -# If you need to regenerate the asset headers to check them into source -cmake --build build-cmake --target ExtractAssetHeaders - -# If you need a newer 2ship.o2r only -cmake --build build-cmake --target Generate2ShipOtr ``` ### Generating a distributable @@ -206,6 +210,19 @@ cd build-cmake cpack ``` +### Additional CMake Targets +#### Clean +```bash +# If you need to clean the project you can run +cmake --build build-cmake --target clean +``` + +#### Regenerate Asset Headers +```bash +# If you need to regenerate the asset headers to check them into source +cmake --build build-cmake --target ExtractAssetHeaders +``` + # Compatible Roms See [`supportedHashes.json`](supportedHashes.json) diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 7179d9db5..5764408ba 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include "z64animation.h" #include "z64bgcheck.h" @@ -27,6 +26,7 @@ #include "macros.h" #include #include +#include "build.h" #include #include @@ -145,10 +145,9 @@ OTRGlobals::OTRGlobals() { } } } - std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, OOT_NTSC_US_MQ, OOT_PAL_GC_MQ_DBG, - OOT_NTSC_US_10, OOT_NTSC_US_11, OOT_NTSC_US_12, OOT_PAL_10, - OOT_PAL_11, OOT_NTSC_JP_GC_CE, OOT_NTSC_JP_GC, OOT_NTSC_US_GC, - OOT_PAL_GC, OOT_PAL_GC_DBG1, OOT_PAL_GC_DBG2 }; + + std::unordered_set validHashes = { MM_NTSC_US_10, MM_NTSC_US_GC }; + // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) context = Ship::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json", archiveFiles, {}, 3, @@ -162,8 +161,6 @@ OTRGlobals::OTRGlobals() { (spdlog::level::level_enum)CVarGetInteger("gDeveloperTools.LogLevel", 1)); Ship::Context::GetInstance()->GetLogger()->set_pattern("[%H:%M:%S.%e] [%s:%#] [%l] %v"); - // context = Ship::Context::CreateUninitializedInstance("Ship of Harkinian", appShortName, "shipofharkinian.json"); - auto overlay = context->GetInstance()->GetWindow()->GetGui()->GetGameOverlay(); overlay->LoadFont("Press Start 2P", "fonts/PressStart2P-Regular.ttf", 12.0f); overlay->LoadFont("Fipps", "fonts/Fipps-Regular.otf", 32.0f); @@ -230,59 +227,22 @@ OTRGlobals::OTRGlobals() { // gSaveStateMgr = std::make_shared(); // gRandomizer = std::make_shared(); - hasMasterQuest = hasOriginal = false; - - // Move the camera strings from read only memory onto the heap (writable memory) - // This is in OTRGlobals right now because this is a place that will only ever be run once at the beginning of - // startup. We should probably find some code in db_camera that does initialization and only run once, and then - // dealloc on deinitialization. - // cameraStrings = (char**)malloc(sizeof(constCameraStrings)); - // for (int32_t i = 0; i < sizeof(constCameraStrings) / sizeof(char*); i++) { - // // OTRTODO: never deallocated... - // auto dup = strdup(constCameraStrings[i]); - // cameraStrings[i] = dup; - //} auto versions = context->GetResourceManager()->GetArchiveManager()->GetGameVersions(); -#if 0 for (uint32_t version : versions) { - if (!ValidHashes.contains(version)) { + if (!validHashes.contains(version)) { #if defined(__SWITCH__) - SPDLOG_ERROR("Invalid OTR File!"); + SPDLOG_ERROR("Invalid O2R File!"); #elif defined(__WIIU__) Ship::WiiU::ThrowInvalidOTR(); #else - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Invalid OTR File", - "Attempted to load an invalid OTR file. Try regenerating.", nullptr); - SPDLOG_ERROR("Invalid OTR File!"); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Invalid O2R File", + "Attempted to load an invalid O2R file. Try regenerating.", nullptr); + SPDLOG_ERROR("Invalid O2R File!"); #endif exit(1); } - switch (version) { - case OOT_PAL_MQ: - case OOT_NTSC_JP_MQ: - case OOT_NTSC_US_MQ: - case OOT_PAL_GC_MQ_DBG: - hasMasterQuest = true; - break; - case OOT_NTSC_US_10: - case OOT_NTSC_US_11: - case OOT_NTSC_US_12: - case OOT_PAL_10: - case OOT_PAL_11: - case OOT_NTSC_JP_GC_CE: - case OOT_NTSC_JP_GC: - case OOT_NTSC_US_GC: - case OOT_PAL_GC: - case OOT_PAL_GC_DBG1: - case OOT_PAL_GC_DBG2: - hasOriginal = true; - break; - default: - break; - } } -#endif fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf"); fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf"); @@ -296,14 +256,6 @@ OTRGlobals::OTRGlobals() { OTRGlobals::~OTRGlobals() { } -bool OTRGlobals::HasMasterQuest() { - return hasMasterQuest; -} - -bool OTRGlobals::HasOriginal() { - return hasOriginal; -} - uint32_t OTRGlobals::GetInterpolationFPS() { if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { return CVarGetInteger("gInterpolationFPS", 20); @@ -479,23 +431,198 @@ void Ben_ProcessDroppedFiles(std::string filePath) { } } -extern "C" void InitOTR() { +typedef struct { + uint16_t major; + uint16_t minor; + uint16_t patch; +} ArchiveVersion; + +// Read the port version from an archive file +ArchiveVersion ReadPortVersionFromArchive(std::string archivePath, bool isO2rType) { + ArchiveVersion version = {}; + + // Use a temporary archive instance to load the archive appropriately and read the version file + std::shared_ptr archive; + if (isO2rType) { + archive = make_shared(archivePath); + } else { + archive = make_shared(archivePath); + } + if (archive->Open()) { + auto t = archive->LoadFile("portVersion", std::make_shared()); + if (t != nullptr && t->IsLoaded) { + auto stream = std::make_shared(t->Buffer->data(), t->Buffer->size()); + auto reader = std::make_shared(stream); + Ship::Endianness endianness = (Ship::Endianness)reader->ReadUByte(); + reader->SetEndianness(endianness); + version.major = reader->ReadUInt16(); + version.minor = reader->ReadUInt16(); + version.patch = reader->ReadUInt16(); + } + archive->Close(); + } + + return version; +} + +// Check that a 2ship.o2r exists and matches the version of 2ship running +// Otherwise show a message and exit +void Check2ShipArchiveVersion(std::string archivePath) { + std::string msg; + +#if defined(__SWITCH__) + msg = "\x1b[4;2HPlease re-extract it from the download." + "\x1b[6;2HPress the Home button to exit..."; +#elif defined(__WIIU__) + msg = "Please extract the 2ship.o2r from the 2 Ship 2 Harkinian download\nto your folder.\n\n" + "Press and hold the power button to shutdown..."; +#else + msg = "Please extract the 2ship.o2r from the 2 Ship 2 Harkinian download to your folder.\n\nExiting..."; +#endif + + if (!std::filesystem::exists(archivePath)) { #if not defined(__SWITCH__) && not defined(__WIIU__) - if (!std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("mm.o2r", appShortName)) && - !std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("mm.zip", appShortName)) && - !std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("mm.otr", appShortName))) { + Extractor::ShowErrorBox("2ship.o2r file is missing", msg.c_str()); + exit(1); +#elif defined(__SWITCH__) + Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou are missing the 2ship.o2r file." + msg).c_str()); +#elif defined(__WIIU__) + OSFatal(("You are missing the 2ship.o2r file\n\n" + msg).c_str()); +#endif + } + + ArchiveVersion archiveVer = ReadPortVersionFromArchive(archivePath, true); + + if (archiveVer.major != gBuildVersionMajor || archiveVer.minor != gBuildVersionMinor || + archiveVer.patch != gBuildVersionPatch) { +#if not defined(__SWITCH__) && not defined(__WIIU__) + Extractor::ShowErrorBox("2ship.o2r file version does not match", msg.c_str()); + exit(1); +#elif defined(__SWITCH__) + Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou have an old 2ship.o2r file." + msg).c_str()); +#elif defined(__WIIU__) + OSFatal(("You have an old 2ship.o2r file\n\n" + msg).c_str()); +#endif + } +} + +// Checks the program version stored in the o2r and compares the major/minor value to 2ship +// For Windows/Mac/Linux if the version doesn't match, offer to regenerate it +void DetectArchiveVersion(std::string fileName, bool isO2rType) { + bool isArchiveOld = false; + std::string archivePath = Ship::Context::LocateFileAcrossAppDirs(fileName, appShortName); + + // Doesn't exist so nothing to do here + if (!std::filesystem::exists(archivePath)) { + return; + } + + ArchiveVersion archiveVer = ReadPortVersionFromArchive(archivePath, isO2rType); + + // Check both major and minor for game archives + if (archiveVer.major != gBuildVersionMajor || archiveVer.minor != gBuildVersionMinor) { + isArchiveOld = true; + } + + if (isArchiveOld) { +#if not defined(__SWITCH__) && not defined(__WIIU__) + char msgBuf[250]; + char version[18]; // 5 digits for int16_max (x3) + separators + terminator + + if (archiveVer.major != 0 || archiveVer.minor != 0 || archiveVer.patch != 0) { + snprintf(version, 18, "%d.%d.%d", archiveVer.major, archiveVer.minor, archiveVer.patch); + } else { + snprintf(version, 18, "no version found"); + } + + snprintf(msgBuf, 250, + "The %s file was generated with a different version of 2 Ship 2 Harkinian.\n" + "O2R version: %s\n\n" + "You must regenerate to be able to play, otherwise the program will exit.\n" + "Would you like to regenerate it now?", + fileName.c_str(), version); + + if (Extractor::ShowYesNoBox("Old O2R File Found", msgBuf) == IDYES) { + std::string installPath = Ship::Context::GetAppBundlePath(); + if (!std::filesystem::exists(installPath + "/assets/extractor")) { + Extractor::ShowErrorBox( + "Extractor assets not found", + "Unable to regenerate. Missing assets/extractor folder needed to generate O2R file.\n\nExiting..."); + exit(1); + } + + Extractor extract; + if (!extract.Run(Ship::Context::GetAppDirectoryPath(appShortName))) { + Extractor::ShowErrorBox("Error", "An error occurred, no O2R file was generated.\n\nExiting..."); + exit(1); + } + + // We can only regenerate O2R archives, so we should just delete the old OTR file + if (!isO2rType) { + std::filesystem::remove(archivePath); + } + + extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName)); + + // Rename the new O2R with the previously used extension + if (isO2rType) { + std::filesystem::rename(Ship::Context::LocateFileAcrossAppDirs("mm.o2r", appShortName), archivePath); + } + } else { + exit(1); + } + +#elif defined(__SWITCH__) + Ship::Switch::PrintErrorMessageToScreen("\x1b[2;2HYou've launched the 2Ship with an old game O2R file." + "\x1b[4;2HPlease regenerate a new game O2R and relaunch." + "\x1b[6;2HPress the Home button to exit..."); +#elif defined(__WIIU__) + OSFatal("You've launched the 2Ship with an old a game O2R file.\n\n" + "Please generate a game O2R and relaunch.\n\n" + "Press and hold the Power button to shutdown..."); +#endif + } +} + +extern "C" void InitOTR() { + +#ifdef __SWITCH__ + Ship::Switch::Init(Ship::PreInitPhase); +#elif defined(__WIIU__) + Ship::WiiU::Init(appShortName); +#endif + + // BENTODO: OTRExporter is filling the version file with garbage. Uncomment once fixed. + // Check2ShipArchiveVersion(Ship::Context::GetPathRelativeToAppBundle("2ship.o2r")); + + std::string mmPathO2R = Ship::Context::LocateFileAcrossAppDirs("mm.o2r", appShortName); + std::string mmPathZIP = Ship::Context::LocateFileAcrossAppDirs("mm.zip", appShortName); + std::string mmPathOtr = Ship::Context::LocateFileAcrossAppDirs("mm.otr", appShortName); + + // Check game archives in preferred order + if (std::filesystem::exists(mmPathO2R)) { + DetectArchiveVersion("mm.o2r", true); + } else if (std::filesystem::exists(mmPathZIP)) { + DetectArchiveVersion("mm.zip", true); + } else if (std::filesystem::exists(mmPathOtr)) { + DetectArchiveVersion("mm.otr", false); + } + +#if not defined(__SWITCH__) && not defined(__WIIU__) + if (!std::filesystem::exists(mmPathO2R) && !std::filesystem::exists(mmPathZIP) && + !std::filesystem::exists(mmPathOtr)) { std::string installPath = Ship::Context::GetAppBundlePath(); if (!std::filesystem::exists(installPath + "/assets/extractor")) { Extractor::ShowErrorBox( "Extractor assets not found", - "No game O2R files found. Missing assets/extractor folder needed to generate O2R file. Exiting..."); + "No game O2R file found. Missing assets/extractor folder needed to generate O2R file. Exiting..."); exit(1); } - if (Extractor::ShowYesNoBox("No O2R Files", "No O2R files found. Generate one now?") == IDYES) { + if (Extractor::ShowYesNoBox("No O2R File", "No O2R files found. Generate one now?") == IDYES) { Extractor extract; - if (!extract.Run()) { - Extractor::ShowErrorBox("Error", "An error occurred, no OTR file was generated. Exiting..."); + if (!extract.Run(Ship::Context::GetAppDirectoryPath(appShortName))) { + Extractor::ShowErrorBox("Error", "An error occurred, no O2R file was generated. Exiting..."); exit(1); } extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName)); @@ -505,12 +632,6 @@ extern "C" void InitOTR() { } #endif -#ifdef __SWITCH__ - Ship::Switch::Init(Ship::PreInitPhase); -#elif defined(__WIIU__) - Ship::WiiU::Init("soh"); -#endif - OTRGlobals::Instance = new OTRGlobals(); GameInteractor::Instance = new GameInteractor(); LoadGuiTextures(); @@ -839,22 +960,8 @@ extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) { Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index]; switch (version) { - case OOT_NTSC_US_10: - case OOT_NTSC_US_11: - case OOT_NTSC_US_12: - case OOT_PAL_10: - case OOT_PAL_11: case MM_NTSC_US_10: return GAME_PLATFORM_N64; - case OOT_NTSC_JP_GC: - case OOT_NTSC_US_GC: - case OOT_PAL_GC: - case OOT_NTSC_JP_MQ: - case OOT_NTSC_US_MQ: - case OOT_PAL_MQ: - case OOT_PAL_GC_DBG1: - case OOT_PAL_GC_DBG2: - case OOT_PAL_GC_MQ_DBG: case MM_NTSC_US_GC: return GAME_PLATFORM_GC; } @@ -865,24 +972,9 @@ extern "C" uint32_t ResourceMgr_GetGameRegion(int index) { Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index]; switch (version) { - case OOT_NTSC_US_10: - case OOT_NTSC_US_11: - case OOT_NTSC_US_12: - case OOT_NTSC_JP_GC: - case OOT_NTSC_US_GC: - case OOT_NTSC_JP_MQ: - case OOT_NTSC_US_MQ: case MM_NTSC_US_10: case MM_NTSC_US_GC: return GAME_REGION_NTSC; - case OOT_PAL_10: - case OOT_PAL_11: - case OOT_PAL_GC: - case OOT_PAL_MQ: - case OOT_PAL_GC_DBG1: - case OOT_PAL_GC_DBG2: - case OOT_PAL_GC_MQ_DBG: - return GAME_REGION_PAL; } } diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h index f67607bbc..4c7791da1 100644 --- a/mm/2s2h/BenPort.h +++ b/mm/2s2h/BenPort.h @@ -36,16 +36,12 @@ class OTRGlobals { OTRGlobals(); ~OTRGlobals(); - bool HasMasterQuest(); - bool HasOriginal(); uint32_t GetInterpolationFPS(); std::shared_ptr> ListFiles(std::string path); private: ImFont* CreateFontWithSize(float size, std::string fontPath = ""); void CheckSaveFile(size_t sramSize) const; - bool hasMasterQuest; - bool hasOriginal; }; uint32_t IsGameMasterQuest(); diff --git a/mm/2s2h/Extractor/Extract.cpp b/mm/2s2h/Extractor/Extract.cpp index 16c823d38..1b6b23738 100644 --- a/mm/2s2h/Extractor/Extract.cpp +++ b/mm/2s2h/Extractor/Extract.cpp @@ -51,42 +51,18 @@ extern "C" uint32_t CRC32C(unsigned char* data, size_t dataSize); -static constexpr uint32_t OOT_PAL_GC = 0x09465AC3; -static constexpr uint32_t OOT_PAL_MQ = 0x1D4136F3; -static constexpr uint32_t OOT_PAL_GC_DBG1 = 0x871E1C92; // 03-21-2002 build -static constexpr uint32_t OOT_PAL_GC_DBG2 = 0x87121EFE; // 03-13-2002 build -static constexpr uint32_t OOT_PAL_GC_MQ_DBG = 0x917D18F6; -static constexpr uint32_t OOT_PAL_10 = 0xB044B569; -static constexpr uint32_t OOT_PAL_11 = 0xB2055FBD; - static constexpr uint32_t MM_US_10 = 0x5354631C; static constexpr uint32_t MM_US_GC = 0xB443EB08; static const std::unordered_map verMap = { - { MM_US_10, "US 1.0" }, { MM_US_GC, "US GC" }, - //{ OOT_PAL_GC, "PAL Gamecube" }, - //{ OOT_PAL_MQ, "PAL MQ" }, - //{ OOT_PAL_GC_DBG1, "PAL Debug 1" }, - //{ OOT_PAL_GC_DBG2, "PAL Debug 2" }, - //{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" }, - //{ OOT_PAL_10, "PAL N64 1.0" }, - //{ OOT_PAL_11, "PAL N64 1.1" }, + { MM_US_10, "US 1.0" }, + { MM_US_GC, "US GC" }, }; // TODO only check the first 54MB of the rom. static constexpr std::array goodCrcs = { 0x96F49400, // MM US 1.0 32MB 0xBB434787, // MM GC - // 0xfa8c0555, // MQ DBG 64MB (Original overdump) - // 0x8652ac4c, // MQ DBG 64MB - // 0x5B8A1EB7, // MQ DBG 64MB (Empty overdump) - // 0x1f731ffe, // MQ DBG 54MB - // 0x044b3982, // NMQ DBG 54MB - // 0xEB15D7B9, // NMQ DBG 64MB - // 0xDA8E61BF, // GC PAL - // 0x7A2FAE68, // GC MQ PAL - // 0xFD9913B1, // N64 PAL 1.0 - // 0xE033FBBA, // N64 PAL 1.1 }; enum class ButtonId : int { @@ -112,7 +88,13 @@ void Extractor::ShowSizeErrorBox() const { } void Extractor::ShowCrcErrorBox() const { - ShowErrorBox("Rom CRC invalid", "Rom CRC did not match the list of known good roms. Please find another."); + ShowErrorBox("Rom CRC invalid", + "Rom CRC did not match the list of known compatible roms. Please find another.\n\n" + "Visit https://2ship.equipment/ to validate your ROM and see a list of compatible versions"); +} + +void Extractor::ShowCompressedErrorBox() const { + ShowErrorBox("File is Compressed", "The selected file appears to be compressed. Please extract before using."); } int Extractor::ShowRomPickBox(uint32_t verCrc) const { @@ -225,7 +207,7 @@ void Extractor::GetRoms(std::vector& roms) { //} #elif unix // Open the directory of the app. - DIR* d = opendir("."); + DIR* d = opendir(mSearchPath.c_str()); struct dirent* dir; if (d != NULL) { @@ -247,7 +229,7 @@ void Extractor::GetRoms(std::vector& roms) { } closedir(d); #else - for (const auto& file : std::filesystem::directory_iterator("./")) { + for (const auto& file : std::filesystem::directory_iterator(mSearchPath)) { if (file.is_directory()) continue; if ((file.path().extension() == ".n64") || (file.path().extension() == ".z64") || @@ -297,7 +279,7 @@ bool Extractor::GetRomPathFromBox() { } mCurrentRomPath = nameBuffer; #else - auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64 *.n64 *.v64" }).result(); + auto selection = pfd::open_file("Select a file", mSearchPath, { "N64 Roms", "*.z64 *.n64 *.v64" }).result(); if (selection.empty()) { return false; @@ -318,11 +300,6 @@ size_t Extractor::GetCurRomSize() const { } bool Extractor::ValidateAndFixRom() { - // The MQ debug rom sometimes has the header patched to look like a US rom. Change it back - if (GetRomVerCrc() == OOT_PAL_GC_MQ_DBG) { - mRomData[0x3E] = 'P'; - } - const uint32_t actualCrc = CRC32C(mRomData.get(), mCurRomSize); for (const uint32_t crc : goodCrcs) { @@ -333,6 +310,25 @@ bool Extractor::ValidateAndFixRom() { return false; } +// The file box will only allow selecting an n64 rom but typing in the file name will allow selecting anything. +bool Extractor::ValidateNotCompressed() const { + // ZIP file header + if (mRomData[0] == 'P' && mRomData[1] == 'K' && mRomData[2] == 0x03 && mRomData[3] == 0x04) { + return false; + } + // RAR file header. Only the first 4 bytes. + if (mRomData[0] == 'R' && mRomData[1] == 'a' && mRomData[2] == 'r' && mRomData[3] == 0x21) { + return false; + } + // 7z file header. 37 7A BC AF 27 1C + if (mRomData[0] == '7' && mRomData[1] == 'z' && mRomData[2] == 0xBC && mRomData[3] == 0xAF && mRomData[4] == 0x27 && + mRomData[5] == 0x1C) { + return false; + } + + return true; +} + bool Extractor::ValidateRomSize() const { if (mCurRomSize != MB32 && mCurRomSize != MB54 && mCurRomSize != MB64) { return false; @@ -341,6 +337,10 @@ bool Extractor::ValidateRomSize() const { } bool Extractor::ValidateRom(bool skipCrcTextBox) { + if (!ValidateNotCompressed()) { + ShowCompressedErrorBox(); + return false; + } if (!ValidateRomSize()) { ShowSizeErrorBox(); return false; @@ -410,10 +410,12 @@ bool Extractor::ManuallySearchForRomMatchingType(RomSearchMode searchMode) { return true; } -bool Extractor::Run(RomSearchMode searchMode) { +bool Extractor::Run(std::string searchPath, RomSearchMode searchMode) { std::vector roms; std::ifstream inFile; + mSearchPath = searchPath; + GetRoms(roms); FilterRoms(roms, searchMode); @@ -456,8 +458,10 @@ bool Extractor::Run(RomSearchMode searchMode) { if (rom == roms.back()) { ShowCrcErrorBox(); } else { - ShowErrorBox("Rom CRC invalid", - "Rom CRC did not match the list of known good roms. Trying the next one..."); + ShowErrorBox( + "Rom CRC invalid", + "Rom CRC did not match the list of known compatible roms. Trying the next one...\n\n" + "Visit https://2ship.equipment/ to validate your ROM and see a list of compatible versions"); } continue; } @@ -480,34 +484,11 @@ bool Extractor::Run(RomSearchMode searchMode) { } bool Extractor::IsMasterQuest() const { - switch (GetRomVerCrc()) { - case OOT_PAL_MQ: - case OOT_PAL_GC_MQ_DBG: - return true; - case OOT_PAL_10: - case OOT_PAL_11: - case OOT_PAL_GC: - case OOT_PAL_GC_DBG1: - return false; - default: - UNREACHABLE; - } + return false; } const char* Extractor::GetZapdVerStr() const { switch (GetRomVerCrc()) { - case OOT_PAL_GC: - return "GC_NMQ_PAL_F"; - case OOT_PAL_MQ: - return "GC_MQ_PAL_F"; - case OOT_PAL_GC_DBG1: - return "GC_NMQ_D"; - case OOT_PAL_GC_MQ_DBG: - return "GC_MQ_D"; - case OOT_PAL_10: - return "N64_PAL_10"; - case OOT_PAL_11: - return "N64_PAL_11"; case MM_US_10: return "N64_US"; case MM_US_GC: diff --git a/mm/2s2h/Extractor/Extract.h b/mm/2s2h/Extractor/Extract.h index 4109c6196..ae4fa740a 100644 --- a/mm/2s2h/Extractor/Extract.h +++ b/mm/2s2h/Extractor/Extract.h @@ -28,6 +28,7 @@ enum class RomSearchMode { class Extractor { std::unique_ptr mRomData = std::make_unique(MB64); std::string mCurrentRomPath; + std::string mSearchPath; size_t mCurRomSize = 0; bool GetRomPathFromBox(); @@ -38,6 +39,7 @@ class Extractor { bool ValidateRomSize() const; bool ValidateRom(bool skipCrcBox = false); + bool ValidateNotCompressed() const; const char* GetZapdVerStr() const; void SetRomInfo(const std::string& path); @@ -46,6 +48,7 @@ class Extractor { void GetRoms(std::vector& roms); void ShowSizeErrorBox() const; void ShowCrcErrorBox() const; + void ShowCompressedErrorBox() const; int ShowRomPickBox(uint32_t verCrc) const; bool ManuallySearchForRom(); bool ManuallySearchForRomMatchingType(RomSearchMode searchMode); @@ -56,7 +59,7 @@ class Extractor { static void ShowErrorBox(const char* title, const char* text); bool IsMasterQuest() const; - bool Run(RomSearchMode searchMode = RomSearchMode::Both); + bool Run(std::string searchPath, RomSearchMode searchMode = RomSearchMode::Both); bool CallZapd(std::string installPath, std::string exportdir); const char* GetZapdStr(); std::string Mkdtemp(); diff --git a/mm/CMakeLists.txt b/mm/CMakeLists.txt index 4640ff349..79bbab7fb 100644 --- a/mm/CMakeLists.txt +++ b/mm/CMakeLists.txt @@ -524,18 +524,22 @@ endif() ################################################################################ # Pre build events ################################################################################ +if (CMAKE_GENERATOR MATCHES "Visual Studio") + set(VS_COPY_ASSETS_CMD ${CMAKE_COMMAND} -E copy_directory $/assets ${CMAKE_BINARY_DIR}/mm/assets) +endif() if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMENT "Copying asset xmls..." + TARGET ${PROJECT_NAME} + POST_BUILD + COMMENT "Copying asset xmls..." COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mm/assets/extractor $/assets/extractor - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mm/assets/xml $/assets/extractor/xmls + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mm/assets/xml $/assets/extractor/xmls COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists $/assets/extractor/filelists COMMAND ${CMAKE_COMMAND} -E make_directory $/assets/extractor/symbols COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_MM.txt $/assets/extractor/symbols COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_MM.txt $/assets/extractor/symbols - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_MM.txt $/assets/extractor/symbols + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_MM.txt $/assets/extractor/symbols + COMMAND ${VS_COPY_ASSETS_CMD} ) endif() ################################################################################ From ad50070aba485ab98a3ee3cabd2a2eced8a6583a Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 9 Nov 2024 20:43:03 -0600 Subject: [PATCH 82/82] Bump for Satoko Alfa (#825) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 921ac70b6..040f32df4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,10 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") -project(2s2h VERSION 1.0.2 LANGUAGES C CXX) +project(2s2h VERSION 1.1.0 LANGUAGES C CXX) include(CMake/2ship-cvars.cmake) include(CMake/lus-cvars.cmake) -set(PROJECT_BUILD_NAME "Rika Charlie" CACHE STRING "" FORCE) +set(PROJECT_BUILD_NAME "Satoko Alfa" CACHE STRING "" FORCE) set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT 2ship)