diff --git a/Include/mg/DebugMenu.h b/Include/mg/DebugMenu.h index f156a58..2d47620 100644 --- a/Include/mg/DebugMenu.h +++ b/Include/mg/DebugMenu.h @@ -6,7 +6,7 @@ namespace mg { -// #define MG_ENABLE_DEBUG_MENU +#define MG_ENABLE_DEBUG_MENU class DebugMenu { enum Page { @@ -22,10 +22,10 @@ class DebugMenu { int mPageIndex; }; const static int sMaxPages = 6; - constexpr static const char* sPages[] { "About", "Info", "Misc.", "Scene Info", "Actor Viewer", "Options" }; - constexpr static int sPagesMaxLines[] { 1, 1, 6, 5, 3, 3 }; + const constexpr static char* sPages[] { "About", "Info", "Misc.", "Scene Info", "Actor Viewer", "Options" }; + constexpr static int sPagesMaxLines[] { 1, 1, 6, 5, 3, 6 }; - constexpr static const char* sPowerupNames[] { "Normal", "Mini", "Fire", "RaccoonDog", "Boomerang", "RaccoonDogSpecial", "RaccoonDogWhite" }; + const constexpr static char* sPowerupNames[] { "Normal", "Mini", "Fire", "RaccoonDog", "Boomerang", "RaccoonDogSpecial", "RaccoonDogWhite" }; int mCursorPos = 0; int mPrintLine = 0; @@ -35,6 +35,9 @@ class DebugMenu { int mCurBufferPos = 0; bool mTeleportEnabled = false; + bool mAlwaysTanooki = true; + bool mRestartHotkey = true; + bool mEnableFreecam = false; bool mHideMenu = false; sead::Vector3f mSavedPos { 0, 0, 0 }; @@ -60,6 +63,9 @@ class DebugMenu { { mCurBufferPos += snprintf(mBuffer + mCurBufferPos, sizeof(mBuffer) - mCurBufferPos, fmt, args...); } + + bool isFreecamEnabled() const { return mEnableFreecam; } + bool isAlwaysTanooki() const { return mAlwaysTanooki; } }; } // namespace mg diff --git a/Include/sead/prim/seadSafeString.hpp b/Include/sead/prim/seadSafeString.hpp new file mode 100644 index 0000000..8a5fb2f --- /dev/null +++ b/Include/sead/prim/seadSafeString.hpp @@ -0,0 +1,55 @@ +#pragma once + +#ifndef SEAD_PRIM_SAFE_STRING_H_ +#include +#endif +#include + +namespace sead { + +template +inline s32 BufferedSafeStringBase::copy(const SafeStringBase& src, s32 copyLength) +{ + T* dst = getMutableStringTop_(); + const T* csrc = src.cstr(); + if (dst == csrc) + return 0; + + if (copyLength < 0) + copyLength = src.calcLength(); + + if (copyLength >= mBufferSize) { + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Copy Size: %d)", mBufferSize, + copyLength); + copyLength = mBufferSize - 1; + } + + memcpy(dst, csrc, copyLength * sizeof(T)); + dst[copyLength] = SafeStringBase::cNullChar; + + return copyLength; +} + +template +inline s32 SafeStringBase::calcLength() const +{ + SEAD_ASSERT(mStringTop); + assureTerminationImpl_(); + s32 length = 0; + + for (;;) { + if (length > cMaximumLength || mStringTop[length] == cNullChar) + break; + + length++; + } + + if (length > cMaximumLength) { + SEAD_ASSERT_MSG(false, "too long string"); + return 0; + } + + return length; +} + +} // namespace sead diff --git a/Source/mg/DebugMenu.cpp b/Source/mg/DebugMenu.cpp index 1f96a5c..563b212 100644 --- a/Source/mg/DebugMenu.cpp +++ b/Source/mg/DebugMenu.cpp @@ -54,7 +54,7 @@ static ActionEntry actions[] { { 0x003cc2bc, "PlayAnim" }, }; -static bool sEnableLayoutSkip = false; +static bool sEnableLayoutSkip = true; // makes death go fast bool layoutSkipHook1(const al::IUseNerve* p) { return sEnableLayoutSkip ? true : al::isGreaterStep(p, 35); } @@ -64,6 +64,11 @@ HK_BL_HOOK(LayoutSkipHook2, 0x00361748, layoutSkipHook2); void mg::DebugMenu::update(StageScene* scene, WindowConfirmSingle* window) { + if (mAlwaysTanooki && scene->mPlayerActor->mPlayer->mFigureDirector->getFigure() != EPlayerFigure_RaccoonDog) + scene->mPlayerActor->mPlayer->mFigureDirector->change(EPlayerFigure_RaccoonDog); + if (mRestartHotkey && al::isPadHoldR() && al::isPadHoldL() && al::isPadTriggerRight()) + al::setNerve(scene, (const al::Nerve*)0x003f1054 /* mario is die */); + if (al::isPadTriggerLeft() && al::isPadHoldL()) { mHideMenu = !mHideMenu; if (!mHideMenu) @@ -275,6 +280,21 @@ void mg::DebugMenu::update(StageScene* scene, WindowConfirmSingle* window) print("State Test\n"); if (mCursorPos == 2 && al::isPadTriggerRight()) scene->mPlayerActor->mPlayer->mFigureDirector->change((EPlayerFigure)7); + + cursor(3); + print("Always Tanooki: %s\n", mAlwaysTanooki ? "Yes" : "No"); + if (mCursorPos == 3 && (al::isPadTriggerRight() || al::isPadTriggerLeft())) + mAlwaysTanooki = !mAlwaysTanooki; + + cursor(4); + print("L+R+DRight to Restart: %s\n", mRestartHotkey ? "Yes" : "No"); + if (mCursorPos == 4 && (al::isPadTriggerRight() || al::isPadTriggerLeft())) + + mRestartHotkey = !mRestartHotkey; + cursor(5); + print("Enable Freecam: %s\n", mEnableFreecam ? "Yes" : "No"); + if (mCursorPos == 5 && (al::isPadTriggerRight() || al::isPadTriggerLeft())) + mEnableFreecam = !mEnableFreecam; break; } default: @@ -307,6 +327,50 @@ void playerActionGraphMoveHook(PlayerActionGraph* graph) // gets current PlayerA graph->getCurrentNode()->getAction()->update(); } -HK_B_HOOK_FUNC(PlayerActionGraphMoveHook, &PlayerActionGraph::move, &playerActionGraphMoveHook) +HK_B_HOOK_FUNC(PlayerActionGraphMoveHook, &PlayerActionGraph::move, playerActionGraphMoveHook) HK_PATCH_ASM(DisableClosingWindowLayout, 0x0036add8, "mov r0, #0"); + +void playerFigureDirectorLose(PlayerFigureDirector* thisPtr) +{ + if (mg::DebugMenu::instance().isAlwaysTanooki()) { + thisPtr->mFigure = EPlayerFigure_RaccoonDog; + return; + } + + thisPtr->lose(); +} + +void playerFigureDirectorSet(PlayerFigureDirector* thisPtr, const EPlayerFigure& figure) +{ + if (mg::DebugMenu::instance().isAlwaysTanooki()) { + thisPtr->mFigure = EPlayerFigure_RaccoonDog; + thisPtr->mHasFigureChanged = true; + return; + } + + thisPtr->mFigure = figure; + thisPtr->mHasFigureChanged = true; +} + +void playerFigureDirectorChange(PlayerFigureDirector* thisPtr, const EPlayerFigure& figure) +{ + if (mg::DebugMenu::instance().isAlwaysTanooki()) { + thisPtr->change(EPlayerFigure_RaccoonDog); + return; + } + + thisPtr->change(figure); +} + +HK_BL_HOOK_FUNC(PlayerFigureDirectorLoseHook, 0x0018241c, playerFigureDirectorLose) +HK_B_HOOK_FUNC(PlayerFigureDirectorSetHook, 0x001980e8, playerFigureDirectorSet) + +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook1, 0x00277d5c, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook2, 0x002ce818, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook3, 0x002ce84c, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook4, 0x002cf754, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook5, 0x002cf81c, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook6, 0x002cf880, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook7, 0x002cfcd0, playerFigureDirectorChange) +HK_BL_HOOK_FUNC(PlayerFigureDirectorChangeHook8, 0x002d1034, playerFigureDirectorChange) #endif diff --git a/Source/mg/Freecam.cpp b/Source/mg/Freecam.cpp index 7b333b0..c0305ee 100644 --- a/Source/mg/Freecam.cpp +++ b/Source/mg/Freecam.cpp @@ -34,6 +34,9 @@ void updateFreecam() void freecamApplyHook(al::Camera* camera) { camera->calc(); + + if (!DebugMenu::instance().isFreecamEnabled()) + return; camera->mTarget += mg::getFreecamOffset(); camera->mPos += mg::getFreecamOffset(); } @@ -44,7 +47,7 @@ static const sead::Vector2f neutral { 0, 0 }; const sead::Vector2f& getLeftStickHook(int port) { // ignore left stick input if L is pressed (freecam is enabled) - if (al::isPadHoldL()) + if (al::isPadHoldL() && DebugMenu::instance().isFreecamEnabled()) return neutral; return al::getLeftStick(); } diff --git a/Symbols/al/Placement/PlacementFunction.sym b/Symbols/al/Placement/PlacementFunction.sym index 671c996..2e8ea7b 100644 --- a/Symbols/al/Placement/PlacementFunction.sym +++ b/Symbols/al/Placement/PlacementFunction.sym @@ -1,4 +1,6 @@ _ZN2al9tryGetArgEPfRKNS_9ByamlIterEPKc = 0x00250dc4; +_ZN2al10tryGetArg0EPiRKNS_13ActorInitInfoE = 0x002794f8; _ZN2al10tryGetArg0EPfRKNS_13ActorInitInfoE = 0x0027d238; _ZN2al10tryGetArg1EPfRKNS_13ActorInitInfoE = 0x0027089c; +_ZN2al10tryGetArg2EPfRKNS_13ActorInitInfoE = 0x002794e4;