diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 5f9e5fd..b5b0c53 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -152,6 +152,7 @@ set(SWA_PATCHES_CXX_SOURCES "patches/audio_patches.cpp" "patches/camera_patches.cpp" "patches/fps_patches.cpp" + "patches/inspire_patches.cpp" "patches/misc_patches.cpp" "patches/object_patches.cpp" "patches/player_patches.cpp" diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index 04399ab..20c3ea9 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -64,6 +64,11 @@ #include "SWA/HUD/Sonic/HudSonicStage.h" #include "SWA/Inspire/InspireMovieOverlay.h" #include "SWA/Inspire/InspireMovieOverlayInfo.h" +#include "SWA/Inspire/InspireOpacityAnimationInfo.h" +#include "SWA/Inspire/InspireScene.h" +#include "SWA/Inspire/InspireSceneData.h" +#include "SWA/Inspire/InspireSceneInfo.h" +#include "SWA/Inspire/InspireTextureAnimationInfo.h" #include "SWA/Inspire/InspireTextureOverlay.h" #include "SWA/Inspire/InspireTextureOverlayInfo.h" #include "SWA/Movie/MovieDisplayer.h" diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireMovieOverlayInfo.h b/UnleashedRecomp/api/SWA/Inspire/InspireMovieOverlayInfo.h index 3443d63..de5549a 100644 --- a/UnleashedRecomp/api/SWA/Inspire/InspireMovieOverlayInfo.h +++ b/UnleashedRecomp/api/SWA/Inspire/InspireMovieOverlayInfo.h @@ -8,10 +8,10 @@ namespace SWA::Inspire { public: Hedgehog::Base::CSharedString m_MovieName; - be m_StartTime; - be m_FadeInStartTime; - be m_FadeInEndTime; - be m_FadeOutStartTime; - be m_FadeOutEndTime; + be m_Prepare; + be m_InStart; + be m_InEnd; + be m_OutStart; + be m_OutEnd; }; } diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireOpacityAnimationInfo.h b/UnleashedRecomp/api/SWA/Inspire/InspireOpacityAnimationInfo.h new file mode 100644 index 0000000..e281e17 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Inspire/InspireOpacityAnimationInfo.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA::Inspire +{ + class COpacityAnimationInfo + { + public: + be m_Opacity; + be m_Frame; + }; +} diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireScene.h b/UnleashedRecomp/api/SWA/Inspire/InspireScene.h new file mode 100644 index 0000000..780ed8c --- /dev/null +++ b/UnleashedRecomp/api/SWA/Inspire/InspireScene.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace SWA::Inspire +{ + struct SSceneData + { + be Frame; + be Cut; + bool IsPlaying; + SWA_INSERT_PADDING(0x177); + }; + + class CScene + { + public: + SWA_INSERT_PADDING(0xC0); + xpointer m_pData; + }; +} diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireSceneData.h b/UnleashedRecomp/api/SWA/Inspire/InspireSceneData.h new file mode 100644 index 0000000..88db249 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Inspire/InspireSceneData.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA::Inspire +{ + class CSceneData // : public Hedgehog::Database::CDatabaseData + { + public: + SWA_INSERT_PADDING(0x80); + Hedgehog::Base::CSharedString m_ResourceName; + }; +} diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireSceneInfo.h b/UnleashedRecomp/api/SWA/Inspire/InspireSceneInfo.h new file mode 100644 index 0000000..617a7eb --- /dev/null +++ b/UnleashedRecomp/api/SWA/Inspire/InspireSceneInfo.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace SWA::Inspire +{ + class CSceneInfo {}; +} diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireTextureAnimationInfo.h b/UnleashedRecomp/api/SWA/Inspire/InspireTextureAnimationInfo.h new file mode 100644 index 0000000..d500ae4 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Inspire/InspireTextureAnimationInfo.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace SWA::Inspire +{ + class CTextureAnimationInfo + { + public: + SWA_INSERT_PADDING(0x10); + Hedgehog::Base::CSharedString m_MovieTex; + Hedgehog::Base::CSharedString m_MovieSfd; + SWA_INSERT_PADDING(0x08); + be m_Prepare; + be m_Start; + be m_End; + be m_Width; + be m_Height; + }; +} diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlay.h b/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlay.h index b6e1986..8384c3c 100644 --- a/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlay.h +++ b/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlay.h @@ -11,7 +11,7 @@ namespace SWA::Inspire { public: xpointer m_pVftable; - boost::shared_ptr m_spInfo; + boost::shared_ptr m_spInfo; xpointer m_pScene; boost::shared_ptr m_spTextureData; }; diff --git a/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlayInfo.h b/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlayInfo.h index 3befa01..fd35d64 100644 --- a/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlayInfo.h +++ b/UnleashedRecomp/api/SWA/Inspire/InspireTextureOverlayInfo.h @@ -4,12 +4,11 @@ namespace SWA::Inspire { - class CInspireTextureOverlayInfo + class CTextureOverlayInfo { public: - Hedgehog::Base::CSharedString m_CameraName; - be m_Unk1; - be m_Unk2; - be m_Unk3; + Hedgehog::Base::CSharedString m_Picture; + be m_Start; + be m_End; }; } diff --git a/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h index b7f64e3..285e678 100644 --- a/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h +++ b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h @@ -4,5 +4,9 @@ namespace SWA::Sequence::Unit { - class CPlayMovieUnit : public CUnitBase {}; + class CPlayMovieUnit : public CUnitBase + { + public: + Hedgehog::Base::CSharedString m_SceneName; + }; } diff --git a/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h b/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h index a10d6f6..47a3e36 100644 --- a/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h +++ b/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h @@ -29,12 +29,16 @@ namespace SWA::Sequence::Utility SVertexData m_TopRight; SVertexData m_BottomRight; SVertexData m_BottomLeft; - bool m_MaintainAspectRatio; + bool m_Field1A4; SWA_INSERT_PADDING(0x18); be m_TimeElapsed; }; - SWA_INSERT_PADDING(0x18); + xpointer m_pVftable; + Hedgehog::Base::CSharedString m_SceneName; + SWA_INSERT_PADDING(0x10); xpointer m_pRender; + SWA_INSERT_PADDING(0x04); + xpointer m_pResourceName; }; } diff --git a/UnleashedRecomp/app.cpp b/UnleashedRecomp/app.cpp index c4b6a32..c485193 100644 --- a/UnleashedRecomp/app.cpp +++ b/UnleashedRecomp/app.cpp @@ -2,10 +2,11 @@ #include #include #include -#include -#include -#include #include +#include +#include +#include +#include void App::Restart(std::vector restartArgs) { @@ -24,7 +25,7 @@ void App::Exit() std::_Exit(0); } -// CApplication::Ctor +// SWA::CApplication PPC_FUNC_IMPL(__imp__sub_824EB490); PPC_FUNC(sub_824EB490) { @@ -37,7 +38,7 @@ PPC_FUNC(sub_824EB490) static std::thread::id g_mainThreadId = std::this_thread::get_id(); -// CApplication::Update +// SWA::CApplication::Update PPC_FUNC_IMPL(__imp__sub_822C1130); PPC_FUNC(sub_822C1130) { @@ -47,6 +48,7 @@ PPC_FUNC(sub_822C1130) if (Config::FPS >= FPS_MIN && Config::FPS < FPS_MAX) { double targetDeltaTime = 1.0 / Config::FPS; + if (abs(ctx.f1.f64 - targetDeltaTime) < 0.00001) ctx.f1.f64 = targetDeltaTime; } @@ -65,6 +67,7 @@ PPC_FUNC(sub_822C1130) GameWindow::Update(); AudioPatches::Update(App::s_deltaTime); + InspirePatches::Update(); __imp__sub_822C1130(ctx, base); } diff --git a/UnleashedRecomp/app.h b/UnleashedRecomp/app.h index 6505e18..bf05692 100644 --- a/UnleashedRecomp/app.h +++ b/UnleashedRecomp/app.h @@ -8,6 +8,7 @@ public: static inline bool s_isInit; static inline bool s_isMissingDLC; static inline bool s_isLoading; + static inline bool s_isWerehog; static inline ELanguage s_language; diff --git a/UnleashedRecomp/patches/inspire_patches.cpp b/UnleashedRecomp/patches/inspire_patches.cpp new file mode 100644 index 0000000..3527ca1 --- /dev/null +++ b/UnleashedRecomp/patches/inspire_patches.cpp @@ -0,0 +1,134 @@ +#include "inspire_patches.h" +#include +#include +#include +#include +#include + +static SWA::Inspire::CScene* g_pScene; +static std::string g_sceneName; +static bool g_isFirstFrameChecked; +static uint32_t g_eventDispatchCount; + +static std::array g_alwaysEvilSonic = +{ + "evrt_m2_02", // Same As Ever + "evrt_s1_05", // Chun-nan Temple + "evrt_s3_04", // Holoskan Temple + "evrt_t0_02", // Shamaran Temple + "evrt_m7_02", // The Final Temple + "evrt_m7_04", // Congratulations + "evrt_m8_02", // The Egg Dragoon + "evrt_m8_03" // Planet's End +}; + +static std::unordered_map> g_evilSonicTimings = +{ + { "evrt_m0_01_05", { 8189.97f, 10821 } }, // Opening + { "evrt_m0_06", { 0, 5104.07f } }, // A New Journey + { "evrt_m1_02", { 1162.46f, 3513 } }, // The First Night + { "evrt_m6_03", { 2445, 5744 } }, // No Reason + { "evrt_m8_04", { 0, 2314 } } // Dark Gaia Appears +}; + +// SWA::Inspire::CScene +PPC_FUNC_IMPL(__imp__sub_82B98D80); +PPC_FUNC(sub_82B98D80) +{ + __imp__sub_82B98D80(ctx, base); + + g_pScene = (SWA::Inspire::CScene*)g_memory.Translate(ctx.r3.u32); + g_isFirstFrameChecked = false; + g_eventDispatchCount = 0; +} + +// ~SWA::Inspire::CScene +PPC_FUNC_IMPL(__imp__sub_82B98D30); +PPC_FUNC(sub_82B98D30) +{ + __imp__sub_82B98D30(ctx, base); + + g_pScene = nullptr; + g_sceneName.clear(); + + SDL_User_EvilSonic(App::s_isWerehog); +} + +PPC_FUNC_IMPL(__imp__sub_82B9BA98); +PPC_FUNC(sub_82B9BA98) +{ + auto sceneName = (Hedgehog::Base::CSharedString*)g_memory.Translate(ctx.r5.u32); + + g_sceneName = sceneName->c_str(); + + __imp__sub_82B9BA98(ctx, base); +} + +void InspirePatches::DrawDebug() +{ + if (!g_pScene) + { + ImGui::Text("There is no active scene."); + return; + } + + ImGui::Text("Name: %s", g_sceneName.c_str()); + ImGui::Text("Frame: %f", g_pScene->m_pData->Frame.get()); + ImGui::Text("Cut: %d", g_pScene->m_pData->Cut.get()); + + static std::vector g_loggedFrames{}; + + ImGui::Separator(); + + if (ImGui::Button("Log")) + g_loggedFrames.push_back(g_pScene->m_pData->Frame); + + if (ImGui::Button("Clear")) + g_loggedFrames.clear(); + + if (g_loggedFrames.size()) + { + ImGui::Separator(); + + for (auto& frame : g_loggedFrames) + ImGui::Text("%f", frame); + } +} + +void InspirePatches::Update() +{ + if (!g_pScene || !g_sceneName.size()) + return; + + if (!g_isFirstFrameChecked && std::find(g_alwaysEvilSonic.begin(), g_alwaysEvilSonic.end(), g_sceneName) != g_alwaysEvilSonic.end()) + { + SDL_User_EvilSonic(true); + g_isFirstFrameChecked = true; + return; + } + + auto findResult = g_evilSonicTimings.find(g_sceneName); + + if (findResult != g_evilSonicTimings.end()) + { + auto& timings = findResult->second; + auto& frame = g_pScene->m_pData->Frame; + + if (!g_isFirstFrameChecked && timings.first > 0) + { + SDL_User_EvilSonic(false); + g_isFirstFrameChecked = true; + } + + if (!g_eventDispatchCount && (frame > timings.first && frame < timings.second)) + { + SDL_User_EvilSonic(true); + g_eventDispatchCount++; + } + else if (g_eventDispatchCount == 1 && frame > timings.second) + { + SDL_User_EvilSonic(false); + g_eventDispatchCount++; + } + } +} diff --git a/UnleashedRecomp/patches/inspire_patches.h b/UnleashedRecomp/patches/inspire_patches.h new file mode 100644 index 0000000..2ff4f75 --- /dev/null +++ b/UnleashedRecomp/patches/inspire_patches.h @@ -0,0 +1,8 @@ +#pragma once + +class InspirePatches +{ +public: + static void DrawDebug(); + static void Update(); +}; diff --git a/UnleashedRecomp/patches/player_patches.cpp b/UnleashedRecomp/patches/player_patches.cpp index 07d00f8..5dfafd5 100644 --- a/UnleashedRecomp/patches/player_patches.cpp +++ b/UnleashedRecomp/patches/player_patches.cpp @@ -3,6 +3,7 @@ #include #include #include +#include static uint32_t g_lastEnemyScore; static uint32_t g_lastTrickScore; @@ -122,20 +123,24 @@ void SetXButtonHomingMidAsmHook(PPCRegister& r30) r30.u32 = Config::HomingAttackOnBoost; } -// SWA::Player::CEvilSonicContext::Ctor +// SWA::Player::CEvilSonicContext PPC_FUNC_IMPL(__imp__sub_823B49D8); PPC_FUNC(sub_823B49D8) { __imp__sub_823B49D8(ctx, base); + App::s_isWerehog = true; + SDL_User_EvilSonic(true); } -// SWA::Player::CEvilSonicContext::Dtor +// ~SWA::Player::CEvilSonicContext PPC_FUNC_IMPL(__imp__sub_823B4590); PPC_FUNC(sub_823B4590) { __imp__sub_823B4590(ctx, base); + App::s_isWerehog = false; + SDL_User_EvilSonic(false); } diff --git a/UnleashedRecomp/ui/window_events.h b/UnleashedRecomp/ui/window_events.h index b63d2c2..3a0c592 100644 --- a/UnleashedRecomp/ui/window_events.h +++ b/UnleashedRecomp/ui/window_events.h @@ -29,11 +29,11 @@ inline void SDL_MoveEvent(SDL_Window* pWindow, int x, int y) SDL_PushEvent(&event); } -inline void SDL_User_EvilSonic(bool isCtor) +inline void SDL_User_EvilSonic(bool isEvil) { SDL_Event event{}; event.type = SDL_USER_EVILSONIC; - event.user.code = isCtor; + event.user.code = isEvil; SDL_PushEvent(&event); }