From 08c161fd13836b34bb3257d8361add14e967eac8 Mon Sep 17 00:00:00 2001 From: PurpleHato <47987542+PurpleHato@users.noreply.github.com> Date: Sun, 29 May 2022 22:40:50 +0200 Subject: [PATCH] Enhancement: More options for Kaleido Link (#394) * Enhancement: More options for Kaleido Link ADDED: 14 animations to use ADDED: 2 random mode ADDED: Link rotation on the menu with DPAD-Left and Right ADDED: Reset position with DPAD-Up and Down * ADDED/ Choice to use C-Button or D-pad --- libultraship/libultraship/SohImGuiImpl.cpp | 41 ++++++- soh/src/code/z_player_lib.c | 108 ++++++++++++++++-- .../ovl_kaleido_scope/z_kaleido_equipment.c | 32 +++++- 3 files changed, 168 insertions(+), 13 deletions(-) diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index c03cd8e78..3c3ca9c6c 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -861,9 +861,48 @@ namespace SohImGui { if (ImGui::BeginMenu("Graphics")) { + if (ImGui::BeginMenu("Animated Link in Pause Menu")) { + ImGui::Text("Rotation"); + EnhancementRadioButton("Disabled", "gPauseLiveRotation", 0); + EnhancementRadioButton("Rotate Link with D-pad", "gPauseLiveRotation", 1); + Tooltip("Allow you to rotate Link on the Equipment menu with the DPAD\nUse DPAD-Up or DPAD-Down to reset Link's rotation"); + EnhancementRadioButton("Rotate Link with C-buttons", "gPauseLiveRotation", 2); + Tooltip("Allow you to rotate Link on the Equipment menu with the C-buttons\nUse C-Up or C-Down to reset Link's rotation"); + + if (CVar_GetS32("gPauseLiveRotation", 0) != 0) { + EnhancementSliderInt("Rotation Speed: %d", "##MinRotationSpeed", "gPauseLiveLinkRotationSpeed", 1, 20, ""); + } + ImGui::Separator(); + ImGui::Text("Static loop"); + EnhancementRadioButton("Disabled", "gPauseLiveLink", 0); + EnhancementRadioButton("Idle (standing)", "gPauseLiveLink", 1); + EnhancementRadioButton("Idle (look around)", "gPauseLiveLink", 2); + EnhancementRadioButton("Idle (belt)", "gPauseLiveLink", 3); + EnhancementRadioButton("Idle (shield)", "gPauseLiveLink", 4); + EnhancementRadioButton("Idle (test sword)", "gPauseLiveLink", 5); + EnhancementRadioButton("Idle (yawn)", "gPauseLiveLink", 6); + EnhancementRadioButton("Battle Stance", "gPauseLiveLink", 7); + EnhancementRadioButton("Walking (no shield)", "gPauseLiveLink", 8); + EnhancementRadioButton("Walking (holding shield)", "gPauseLiveLink", 9); + EnhancementRadioButton("Running (no shield)", "gPauseLiveLink", 10); + EnhancementRadioButton("Running (holding shield)", "gPauseLiveLink", 11); + EnhancementRadioButton("Hand on hip", "gPauseLiveLink", 12); + EnhancementRadioButton("Spin attack charge", "gPauseLiveLink", 13); + EnhancementRadioButton("Look at hand", "gPauseLiveLink", 14); + ImGui::Separator(); + ImGui::Text("Randomize"); + EnhancementRadioButton("Random", "gPauseLiveLink", 15); + Tooltip("Randomize the animation played each time you open the menu"); + EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16); + Tooltip("andomize the animation played on hte menu after a certain time"); + if (CVar_GetS32("gPauseLiveLink", 0) >= 16) { + EnhancementSliderInt("Frame to wait: %d", "##MinFrameCount", "gMinFrameCount", 1, 1000, ""); + } + + ImGui::EndMenu(); + } EnhancementCheckbox("N64 Mode", "gN64Mode"); Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); - EnhancementCheckbox("Animated Link in Pause Menu", "gPauseLiveLink"); EnhancementCheckbox("Enable 3D Dropped items", "gNewDrops"); EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon"); Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 83fae7ff1..cf7fbd51c 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -1661,26 +1661,118 @@ void func_80091A24(GlobalContext* globalCtx, void* seg04, void* seg06, SkelAnime CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_player_lib.c", 3288); } +uintptr_t SelectedAnim = 0; // Current Animaiton on the menu +s16 EquipedStance; // Link's current mode (Two handed, One handed...) +s16 FrameCountSinceLastAnim = 0; // Time since last animation +s16 MinFrameCount; // Frame to wait before checking if we need to change the animation + void func_8009214C(GlobalContext* globalCtx, u8* segment, SkelAnime* skelAnime, Vec3f* pos, Vec3s* rot, f32 scale, s32 sword, s32 tunic, s32 shield, s32 boots) { + Input* p1Input = &globalCtx->state.input[0]; Vec3f eye = { 0.0f, 0.0f, -400.0f }; Vec3f at = { 0.0f, 0.0f, 0.0f }; Vec3s* destTable; Vec3s* srcTable; s32 i; + bool canswitchrnd = false; + s16 SelectedMode = CVar_GetS32("gPauseLiveLink", 1); + MinFrameCount = CVar_GetS32("gMinFrameCount", 200); gSegments[4] = VIRTUAL_TO_PHYSICAL(segment + 0x3800); gSegments[6] = VIRTUAL_TO_PHYSICAL(segment + 0x8800); - if (CVar_GetS32("gPauseLiveLink", 0) || CVar_GetS32("gPauseTriforce", 0)) { - uintptr_t anim = gPlayerAnim_003238; // idle + uintptr_t* PauseMenuAnimSet[15][4] = { + { 0, 0, 0, 0 }, // 0 = none + // IDLE // Two Handed // No shield // Kid Hylian Shield + { gPlayerAnim_003238, gPlayerAnim_002BE0, gPlayerAnim_003240, gPlayerAnim_003240 }, // Idle + { gPlayerAnim_003200, gPlayerAnim_003200, gPlayerAnim_003200, gPlayerAnim_003200 }, // Idle look around + { gPlayerAnim_0033E0, gPlayerAnim_0033E0, gPlayerAnim_0033E0, gPlayerAnim_0033E0 }, // Idle Belt + { gPlayerAnim_003418, gPlayerAnim_003418, gPlayerAnim_003418, gPlayerAnim_003418 }, // Idle shield adjust + { gPlayerAnim_003420, gPlayerAnim_003428, gPlayerAnim_003420, gPlayerAnim_003420 }, // Idle test sword + { gPlayerAnim_0033F0, gPlayerAnim_0033F0, gPlayerAnim_0033F0, gPlayerAnim_0033F0 }, // Idle yawn + { gPlayerAnim_0025D0, gPlayerAnim_002BD0, gPlayerAnim_0025D0, gPlayerAnim_0025D0 }, // Battle Stance + { gPlayerAnim_003290, gPlayerAnim_002BF8, gPlayerAnim_003290, gPlayerAnim_003290 }, // Walking (No shield) + { gPlayerAnim_003268, gPlayerAnim_002BF8, gPlayerAnim_003268, gPlayerAnim_003268 }, // Walking (Holding shield) + { gPlayerAnim_003138, gPlayerAnim_002B40, gPlayerAnim_003138, gPlayerAnim_003138 }, // Running (No shield) + { gPlayerAnim_003140, gPlayerAnim_002B40, gPlayerAnim_003140, gPlayerAnim_003140 }, // Running (Holding shield) + { gPlayerAnim_0031A8, gPlayerAnim_0031A8, gPlayerAnim_0031A8, gPlayerAnim_0031A8 }, // Hand on hip + { gPlayerAnim_002AF0, gPlayerAnim_002928, gPlayerAnim_002AF0, gPlayerAnim_002AF0 }, // Spin Charge + { gPlayerAnim_002820, gPlayerAnim_002820, gPlayerAnim_002820, gPlayerAnim_002820 }, // Look at hand + }; + s16 AnimArraySize = ARRAY_COUNT(PauseMenuAnimSet); - if (CUR_EQUIP_VALUE(EQUIP_SWORD) >= 3) - anim = gPlayerAnim_002BE0; // Two Handed Anim - else if (CUR_EQUIP_VALUE(EQUIP_SHIELD) == 0) - anim = gPlayerAnim_003240; - else if (CUR_EQUIP_VALUE(EQUIP_SHIELD) == 2 && LINK_AGE_IN_YEARS == YEARS_CHILD) - anim = gPlayerAnim_003240; + if (CVar_GetS32("gPauseLiveLink", !0) || CVar_GetS32("gPauseTriforce", 0)) { + uintptr_t anim = 0; // Initialise anim + + if (CUR_EQUIP_VALUE(EQUIP_SWORD) >= 3) { + EquipedStance = 1; + } else if (CUR_EQUIP_VALUE(EQUIP_SHIELD) == 0) { + EquipedStance = 2; + } else if (CUR_EQUIP_VALUE(EQUIP_SHIELD) == 2 && LINK_AGE_IN_YEARS == YEARS_CHILD) { + EquipedStance = 3; + } else { + // Link is idle so revert to 0 + EquipedStance = 0; + } + + if (SelectedMode == 16) { + // Apply Random function + s16 SwitchAtFrame = 0; + s16 CurAnimDuration = 0; + if (FrameCountSinceLastAnim == 0) { + // When opening Kaleido this will be passed one time + SelectedAnim = rand() % (AnimArraySize - 0); + if (SelectedAnim == 0) { + // prevent loading 0 that would result to a crash. + SelectedAnim = 1; + } + } else if (FrameCountSinceLastAnim >= 1) { + SwitchAtFrame = Animation_GetLastFrame(PauseMenuAnimSet[SelectedAnim][EquipedStance]); + CurAnimDuration = Animation_GetLastFrame(PauseMenuAnimSet[SelectedAnim][EquipedStance]); + if (SwitchAtFrame < MinFrameCount) { + // Animation frame count is lower than minimal wait time then we wait for another round. + // This will be looped to always add current animation time if that still lower than minimum time + while (SwitchAtFrame < MinFrameCount) { + SwitchAtFrame = SwitchAtFrame + CurAnimDuration; + } + } else if (CurAnimDuration >= MinFrameCount) { + // Since we have more (or same) animation time than min duration we set the wait time to animation + // time. + SwitchAtFrame = CurAnimDuration; + } + if (FrameCountSinceLastAnim >= SwitchAtFrame) { + SelectedAnim = rand() % (AnimArraySize - 0); + if (SelectedAnim == 0) { + // prevent loading 0 that would result to a crash. + SelectedAnim = 1; + } + FrameCountSinceLastAnim = 1; + } + anim = PauseMenuAnimSet[SelectedAnim][EquipedStance]; + } + FrameCountSinceLastAnim++; + } else if (SelectedMode == 15) { + // When opening Kaleido this will be passed one time + if (FrameCountSinceLastAnim < 1) { + SelectedAnim = rand() % (AnimArraySize - 0); + FrameCountSinceLastAnim++; + if (SelectedAnim == 0) { + // prevent loading 0 that would result to a crash. + SelectedAnim = 1; + } + FrameCountSinceLastAnim = 1; + } + if (CHECK_BTN_ALL(p1Input->press.button, BTN_B) || CHECK_BTN_ALL(p1Input->press.button, BTN_START)) { + FrameCountSinceLastAnim = 0; + } + anim = PauseMenuAnimSet[SelectedAnim][EquipedStance]; + } else if (SelectedMode < 16) { + // Not random so we place our CVar as SelectedAnim + SelectedAnim = SelectedMode; + anim = PauseMenuAnimSet[SelectedAnim][EquipedStance]; + } + + anim = PauseMenuAnimSet[SelectedAnim][EquipedStance]; //anim = gPlayerAnim_003428; // Use for biggoron sword? diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index 719eaa3f3..125981bff 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -89,11 +89,17 @@ void KaleidoScope_DrawEquipmentImage(GlobalContext* globalCtx, void* source, u32 CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_kaleido_equipment.c", 122); } +Vec3s link_kaleido_rot = { 0, 32300, 0 }; // Default rotation link face us. + void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) { PauseContext* pauseCtx = &globalCtx->pauseCtx; Vec3f pos; - Vec3s rot; + //Vec3s rot; // Removed for not having it use din the function f32 scale; + Input* input = &globalCtx->state.input[0]; + s16 RotationSpeed = 150 * CVar_GetS32("gPauseLiveLinkRotationSpeed", 0); + bool AllowCRotation = (CVar_GetS32("gPauseLiveLinkRotation", 0) == 2) ? true : false; + bool AllowDPadRotation = (CVar_GetS32("gPauseLiveLinkRotation", 0) == 1) ? true : false; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { pos.x = 2.0f; @@ -112,11 +118,29 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) { scale = 0.047f; } - rot.y = 32300; - rot.x = rot.z = 0; + link_kaleido_rot.x = link_kaleido_rot.z = 0; + + if (AllowDPadRotation && CHECK_BTN_ALL(input->cur.button, BTN_DLEFT) || + AllowCRotation && CHECK_BTN_ALL(input->cur.button, BTN_CLEFT)) { + link_kaleido_rot.y = link_kaleido_rot.y - RotationSpeed; + } else if (AllowDPadRotation && CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT) || + AllowCRotation && CHECK_BTN_ALL(input->cur.button, BTN_CRIGHT)) { + link_kaleido_rot.y = link_kaleido_rot.y + RotationSpeed; + } + + if (AllowDPadRotation && CHECK_BTN_ALL(input->press.button, BTN_DUP) || + AllowDPadRotation && CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { + link_kaleido_rot.y = 32300; + } else if (AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CUP) || + AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CDOWN)) { + link_kaleido_rot.y = 32300; + } + + link_kaleido_rot.x = 0; + extern int fbTest; gsSPSetFB(globalCtx->state.gfxCtx->polyOpa.p++, fbTest); - func_8009214C(globalCtx, pauseCtx->playerSegment, &pauseCtx->playerSkelAnime, &pos, &rot, scale, + func_8009214C(globalCtx, pauseCtx->playerSegment, &pauseCtx->playerSkelAnime, &pos, &link_kaleido_rot, scale, CUR_EQUIP_VALUE(EQUIP_SWORD), CUR_EQUIP_VALUE(EQUIP_TUNIC) - 1, CUR_EQUIP_VALUE(EQUIP_SHIELD), CUR_EQUIP_VALUE(EQUIP_BOOTS) - 1); gsSPResetFB(globalCtx->state.gfxCtx->polyOpa.p++);