diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 7d5a618a..dbce38a6 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -89267,10 +89267,10 @@ 0x00000071010db52c,wm::SkyMgr::getConcentrationBM,16,_ZNK4ksys5world6EnvMgr18getConcentrationBMEv 0x00000071010db53c,wm::SkyMgr::activateForcedBloodMoon,64,_ZN4ksys5world6EnvMgr23activateForcedBloodMoonEv 0x00000071010db57c,wm::SkyMgr::setBloodMoonTempProhibited,36,_ZN4ksys5world6EnvMgr23setBloodMoonProhibitionEb -0x00000071010db5a0,sub_71010DB5A0,1116, +0x00000071010db5a0,sub_71010DB5A0,1116,_ZN4ksys5world6EnvMgr21updateForcedBloodMoonEv 0x00000071010db9fc,wm::SkyMgr::isFadeOrFadeDemoScreenOpened,352, 0x00000071010dbb5c,wm::SkyMgr::updateBloodMoon,792, -0x00000071010dbe74,wm::SkyMgr::updateBloodMoonFlags,964, +0x00000071010dbe74,wm::SkyMgr::updateBloodMoonFlags,964,_ZN4ksys5world6EnvMgr20updateBloodMoonFlagsEv 0x00000071010dc238,wm::SkyMgr::return0,8, 0x00000071010dc240,wm::SkyMgr::x_4,56, 0x00000071010dc278,wm::SkyMgr::x,52, @@ -89285,7 +89285,7 @@ 0x00000071010dc650,wm::SkyMgr::x_2,68, 0x00000071010dc694,wm::SkyMgr::setWarpMistTimer,68, 0x00000071010dc6d8,wm::SkyMgr::setFogDirect,104, -0x00000071010dc740,wm::SkyMgr::getBloodMoonProgress,56, +0x00000071010dc740,wm::SkyMgr::getBloodMoonProgress,56,_ZNK4ksys5world6EnvMgr20getBloodMoonProgressEv 0x00000071010dc778,sub_71010DC778,16, 0x00000071010dc788,wm::SkyMgr::rtti1,204,_ZNK4ksys5world6EnvMgr27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x00000071010dc854,wm::SkyMgr::rtti2,92,_ZNK4ksys5world6EnvMgr18getRuntimeTypeInfoEv diff --git a/src/KingSystem/World/worldEnvMgr.cpp b/src/KingSystem/World/worldEnvMgr.cpp index 48a6d7a4..fa4e911e 100644 --- a/src/KingSystem/World/worldEnvMgr.cpp +++ b/src/KingSystem/World/worldEnvMgr.cpp @@ -1,5 +1,7 @@ #include "KingSystem/World/worldEnvMgr.h" +#include "KingSystem/Event/evtManager.h" #include "KingSystem/GameData/gdtManager.h" +#include "KingSystem/System/VFR.h" #include "KingSystem/World/worldManager.h" namespace ksys::world { @@ -299,7 +301,7 @@ bool EnvMgr::isBloodMoonNight() const { bool bm = false; bm |= wm->getTimeMgr()->isBloodyDay(); bm |= wm->getTimeMgr()->wasBloodyDay() && time < 1_h; - bm |= wm->getTimeMgr()->getBloodMoonForceMode() != TimeMgr::BloodMoonForceMode::Disabled; + bm |= wm->getTimeMgr()->isBloodMoonForced(); return bm; } @@ -322,6 +324,138 @@ void EnvMgr::setBloodMoonProhibition(bool prohibited) { mBloodMoonProhibited = prohibited; } +// FIXME: remove this once EnvMgr::isLoadingScreenOpened is implemented +// This is necessary because Clang would otherwise pass this to the member function +// as it can't see that "this" is unused +bool isLoadingScreenOpened_TEMP(); + +void EnvMgr::updateForcedBloodMoon() { + static constexpr float BloodMoonTimerDuration = 90.0f; + + switch (mForcedBloodMoonStatus) { + case 0: + // Wait for a forced blood moon to be requested + if (!mForcedBloodMoonRequested || evt::Manager::instance()->hasActiveEvent()) + break; + mForcedBloodMoonTimer = 0.0f; + mForcedBloodMoonReady = false; + ++mForcedBloodMoonStatus; + break; + + case 1: + // Update the forced blood moon timer + if (evt::Manager::instance()->hasActiveEvent() || mBloodMoonProhibited) { + mForcedBloodMoonTimer -= VFR::instance()->getDeltaTime(); + if (mForcedBloodMoonTimer <= 0.0f) { + mForcedBloodMoonTimer = 0.0f; + mForcedBloodMoonStatus = 0; + mForcedBloodMoonReady = false; + } + } else { + mForcedBloodMoonTimer += VFR::instance()->getDeltaTime(); + if (mForcedBloodMoonTimer >= BloodMoonTimerDuration) { + mForcedBloodMoonTimer = BloodMoonTimerDuration; + mForcedBloodMoonReady = true; + ++mForcedBloodMoonStatus; + } + } + break; + + case 2: + // Wait for the blood moon cutscene to be triggered externally + if (mBloodMoonProhibited && !mDeactivateForcedBloodMoon) { + mForcedBloodMoonStatus = 4; + mForcedBloodMoonReady = false; + break; + } + if (mForcedBloodMoonReady || isLoadingScreenOpened_TEMP()) + break; + mForcedBloodMoonTimer = BloodMoonTimerDuration; + ++mForcedBloodMoonStatus; + break; + + case 3: + // Slowly fade out the blood moon state + mForcedBloodMoonTimer -= VFR::instance()->getDeltaTime(); + if (mForcedBloodMoonTimer <= 0.0f) { + mForcedBloodMoonTimer = 0.0f; + mForcedBloodMoonStatus = 0; + mForcedBloodMoonRequested = false; + mForcedBloodMoonReady = false; + mDeactivateForcedBloodMoon = false; + } + break; + + case 4: + // [Alternative state 2] Wait for blood moons to be allowed again + if (mBloodMoonProhibited && !mDeactivateForcedBloodMoon) { + mForcedBloodMoonTimer -= VFR::instance()->getDeltaTime(); + if (mForcedBloodMoonTimer <= 0.0f) { + mForcedBloodMoonTimer = 0.0f; + mForcedBloodMoonStatus = 0; + return; + } + } else { + mForcedBloodMoonTimer += VFR::instance()->getDeltaTime(); + if (mForcedBloodMoonTimer >= BloodMoonTimerDuration) { + mForcedBloodMoonTimer = BloodMoonTimerDuration; + mForcedBloodMoonReady = true; + mForcedBloodMoonStatus = 2; + } + } + break; + } + + if (mForcedBloodMoonStatus == 1) { + const float progress = mForcedBloodMoonTimer / BloodMoonTimerDuration; + if (mBloodMoonStartState != 2) { + mBloodMoonEndState = mBloodMoonStartState; + mBloodMoonStartState = 2; + } + mBloodMoonProgress = progress; + } else if (mForcedBloodMoonStatus >= 2) { + const float progress = mForcedBloodMoonTimer / -BloodMoonTimerDuration + 1.0f; + if (mBloodMoonEndState != 2) { + mBloodMoonStartState = mBloodMoonEndState; + mBloodMoonEndState = 2; + } + mBloodMoonProgress = progress; + } +} + +void EnvMgr::updateBloodMoonFlags() { + auto* wm = Manager::instance(); + const auto time = wm->getTimeMgr()->getTimeForSkyEnv(); + if (!wm->isMainField()) + return; + + bool bloody_night = false; + bloody_night |= time >= 21_h && isBloodMoonNight(); + bloody_night |= wm->getTimeMgr()->wasBloodyDay() && time < 1_h; + bloody_night |= wm->getTimeMgr()->isBloodMoonForced(); + bloody_night &= !wm->getTimeMgr()->isInRelicBattle(); + + float concentration = 0.0; + if (bloody_night) { + if (time > timeToFloat(23, 30)) { + concentration = (time - timeToFloat(23, 30)) / timeToFloat(0, 30); + } else if (time < timeToFloat(0, 15)) { + concentration = (timeToFloat(0, 15) - time) / timeToFloat(0, 15); + } + } + mBloodMoonTimeRangeProgress = concentration; + + if (!evt::Manager::instance()->hasActiveEvent() && + !wm->getTimeMgr()->isBloodMoonProhibitionFlagSet()) { + VFR::lerp(&mConcentrationBM, concentration, 0.1, 0.01); + } else { + VFR::lerp(&mConcentrationBM, 0.0f, 0.1, 0.01); + } + + if (wm->getTimeMgr()->isBloodMoonForced()) + mConcentrationBM = concentration; +} + bool EnvMgr::isWaterRelicRainOn(Climate climate) const { if (climate != Climate::ZoraTemperateClimate) return false; @@ -334,4 +468,12 @@ bool EnvMgr::isWaterRelicRainOn(Climate climate) const { return !on; } +float EnvMgr::getBloodMoonProgress() const { + if (mBloodMoonStartState == 2) + return mBloodMoonProgress; + if (mBloodMoonEndState == 2) + return 1.0f - mBloodMoonProgress; + return 0.0f; +} + } // namespace ksys::world diff --git a/src/KingSystem/World/worldEnvMgr.h b/src/KingSystem/World/worldEnvMgr.h index e21ec21a..1569f3c9 100644 --- a/src/KingSystem/World/worldEnvMgr.h +++ b/src/KingSystem/World/worldEnvMgr.h @@ -187,8 +187,10 @@ public: float getConcentrationBM() const; void activateForcedBloodMoon(); void setBloodMoonProhibition(bool prohibited); + bool isLoadingScreenOpened() const; bool isWaterRelicRainOn(Climate climate) const; + float getBloodMoonProgress() const; protected: void init_(sead::Heap* heap) override; @@ -205,6 +207,7 @@ private: void updateTimeDivision(); void updateBloodMoon(); + void updateBloodMoonFlags(); void updateForcedBloodMoon(); EnvPaletteStatic mEnvPaletteStatic; @@ -273,7 +276,7 @@ private: u32 _6b5e8; u32 _6b5ec; u32 _6b5f0; - u32 mForcedBloodMoonStatus; + int mForcedBloodMoonStatus; u32 _6b5f8; u32 _6b5fc; u32 mFogMode; diff --git a/src/KingSystem/World/worldTimeMgr.h b/src/KingSystem/World/worldTimeMgr.h index 10ed6126..9127f5b3 100644 --- a/src/KingSystem/World/worldTimeMgr.h +++ b/src/KingSystem/World/worldTimeMgr.h @@ -102,6 +102,7 @@ public: return mResetGdtOnNextSceneUnloadForBloodMoon; } bool wasBloodyDay() const { return mWasBloodyDay; } + bool isBloodMoonForced() const { return mBloodMoonForceMode != BloodMoonForceMode::Disabled; } gdt::FlagHandle getWaterRelicRainStopFlag() const { return mWaterRelicRainStopFlag; }