From da65708ded005b1613ce868337952d72bdf80e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 2 May 2021 11:18:59 +0200 Subject: [PATCH] ksys/world: Implement more TimeMgr functions --- data/uking_functions.csv | 30 ++-- src/KingSystem/GameData/gdtManager.h | 12 +- src/KingSystem/World/worldManager.h | 3 + src/KingSystem/World/worldSkyMgr.h | 2 + src/KingSystem/World/worldTimeMgr.cpp | 234 +++++++++++++++++++++++++- src/KingSystem/World/worldTimeMgr.h | 87 +++++++--- 6 files changed, 318 insertions(+), 50 deletions(-) diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 2ba8f635..18ded1c0 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -89360,31 +89360,31 @@ 0x00000071010e60f4,wm::TimeMgr::ctor,228,_ZN4ksys5world7TimeMgrC1Ev 0x00000071010e61d8,wm::TimeMgr::init,36,_ZN4ksys5world7TimeMgr5init_EPN4sead4HeapE 0x00000071010e61fc,wm::TimeMgr::resetForStageUnload,124,_ZN4ksys5world7TimeMgr19resetForStageUnloadEv -0x00000071010e6278,wm::TimeMgr::loadInfo,388, -0x00000071010e63fc,wm::TimeMgr::loadFlags,1632, +0x00000071010e6278,wm::TimeMgr::loadInfo,388,_ZN4ksys5world7TimeMgr8loadInfoEv +0x00000071010e63fc,wm::TimeMgr::loadFlags,1632,_ZN4ksys5world7TimeMgr9loadFlagsEv 0x00000071010e6a5c,wm::TimeMgr::dtor,172,_ZN4ksys5world7TimeMgrD1Ev 0x00000071010e6b08,sub_71010E6B08,132,_ZN4sead13DelegateEventIN4ksys5world7TimeMgr11NewDayEventEED2Ev 0x00000071010e6b8c,wm::TimeMgr::dtorDelete,180,_ZN4ksys5world7TimeMgrD0Ev 0x00000071010e6c40,wm::TimeMgr::callBloodMoonDemo,104, -0x00000071010e6ca8,wm::TimeMgr::isBloodyMoonProhibited,364, -0x00000071010e6e14,wm::TimeMgr::isBloodyMoonProhibitionFlagSet,120, -0x00000071010e6e8c,wm::TimeMgr::isInRelicBattle,372, +0x00000071010e6ca8,wm::TimeMgr::isBloodyMoonProhibited,364,_ZNK4ksys5world7TimeMgr21isBloodMoonProhibitedEv +0x00000071010e6e14,wm::TimeMgr::isBloodyMoonProhibitionFlagSet,120,_ZNK4ksys5world7TimeMgr29isBloodMoonProhibitionFlagSetEv +0x00000071010e6e8c,wm::TimeMgr::isInRelicBattle,372,_ZNK4ksys5world7TimeMgr15isInRelicBattleEv 0x00000071010e7000,wm::TimeMgr::handleNewDay,608, 0x00000071010e7260,nullsub_4540,4, 0x00000071010e7264,wm::TimeMgr::calc,2676, 0x00000071010e7cd8,wm::TimeMgr::AnimalMasterFlags::calc,772, 0x00000071010e7fdc,wm::TimeMgr::m7_null,4,_ZN4ksys5world7TimeMgr10calcType1_Ev 0x00000071010e7fe0,wm::TimeMgr::m8_null,4,_ZN4ksys5world7TimeMgr10calcType2_Ev -0x00000071010e7fe4,wm::TimeMgr::setNewTime,16,_ZN4ksys5world7TimeMgr10setNewTimeEf -0x00000071010e7ff4,wm::TimeMgr::setTime,220, -0x00000071010e80d0,wm::TimeMgr::isBloodyDay,124, -0x00000071010e814c,wm::TimeMgr::getTime,72, -0x00000071010e8194,wm::TimeMgr::setTimeForSkyEnvAocFieldMaybe,8, -0x00000071010e819c,wm::TimeMgr::getHour,32, -0x00000071010e81bc,wm::TimeMgr::getMoonType,244, -0x00000071010e82b0,wm::TimeMgr::bloodMoonTonight,188, -0x00000071010e836c,wm::getTimeOfDayTempMultiplier,176, -0x00000071010e841c,wm::TimeMgr::getField14F,8, +0x00000071010e7fe4,wm::TimeMgr::setNewTime,16,_ZN4ksys5world7TimeMgr23setTimeWithoutDayChecksEf +0x00000071010e7ff4,wm::TimeMgr::setTime,220,_ZN4ksys5world7TimeMgr7setTimeEf +0x00000071010e80d0,wm::TimeMgr::isBloodyDay,124,_ZNK4ksys5world7TimeMgr11isBloodyDayEv +0x00000071010e814c,wm::TimeMgr::getTime,72,_ZNK4ksys5world7TimeMgr16getTimeForSkyEnvEv +0x00000071010e8194,wm::TimeMgr::setTimeForSkyEnvAocFieldMaybe,8,_ZN4ksys5world7TimeMgr24setAocFieldTimeForSkyEnvEf +0x00000071010e819c,wm::TimeMgr::getHour,32,_ZNK4ksys5world7TimeMgr7getHourEv +0x00000071010e81bc,wm::TimeMgr::getMoonType,244,_ZNK4ksys5world7TimeMgr11getMoonTypeEv +0x00000071010e82b0,wm::TimeMgr::bloodMoonTonight,188,_ZNK4ksys5world7TimeMgr26willBloodMoonHappenTonightEv +0x00000071010e836c,wm::getTimeOfDayTempMultiplier,176,_ZNK4ksys5world7TimeMgr24getTemperatureMultiplierEv +0x00000071010e841c,wm::TimeMgr::getField14F,8,_ZNK4ksys5world7TimeMgr21isTimeFlowingNormallyEv 0x00000071010e8424,wm::TimeMgr::rtti1,204,_ZNK4ksys5world7TimeMgr27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x00000071010e84f0,wm::TimeMgr::rtti2,92,_ZNK4ksys5world7TimeMgr18getRuntimeTypeInfoEv 0x00000071010e854c,wm::TimeMgr::getType,8,_ZNK4ksys5world7TimeMgr7getTypeEv diff --git a/src/KingSystem/GameData/gdtManager.h b/src/KingSystem/GameData/gdtManager.h index 2ddc0308..9d51decf 100644 --- a/src/KingSystem/GameData/gdtManager.h +++ b/src/KingSystem/GameData/gdtManager.h @@ -281,14 +281,18 @@ public: #undef GDT_GET_HANDLE_ #define GDT_GET_(NAME, T) \ - bool NAME(FlagHandle handle, T* value, bool debug = false) { \ + bool NAME(FlagHandle handle, T* value, bool debug = false, \ + bool ignore_trigger_param_result = false) { \ return unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ - return ref.get().NAME(value, idx); \ + const bool result = ref.get().NAME(value, idx); \ + return ignore_trigger_param_result || result; \ }); \ } \ - bool NAME(FlagHandle handle, T* value, s32 sub_idx, bool debug = false) { \ + bool NAME(FlagHandle handle, T* value, s32 sub_idx, bool debug = false, \ + bool ignore_trigger_param_result = false) { \ return unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ - return ref.get().NAME(value, idx, sub_idx); \ + const bool result = ref.get().NAME(value, idx, sub_idx); \ + return ignore_trigger_param_result || result; \ }); \ } diff --git a/src/KingSystem/World/worldManager.h b/src/KingSystem/World/worldManager.h index bfa90b8e..2a772691 100644 --- a/src/KingSystem/World/worldManager.h +++ b/src/KingSystem/World/worldManager.h @@ -257,6 +257,9 @@ public: mScalingMode == ScalingMode::Disabled; } + StageType getStageType() const { return mStageType; } + FieldType getFieldType() const { return mFieldType; } + ScalingMode getScalingMode() const { return mScalingMode; } CalcType getCalcType() const { return mCalcType; } TimeMgr* getTimeMgr() const { return static_cast(mMgrs[0]); } diff --git a/src/KingSystem/World/worldSkyMgr.h b/src/KingSystem/World/worldSkyMgr.h index 779806b3..f77def72 100644 --- a/src/KingSystem/World/worldSkyMgr.h +++ b/src/KingSystem/World/worldSkyMgr.h @@ -14,6 +14,8 @@ public: void resetForStageUnload(); + bool checkConcentrationDarkness() const; + u8 _20[0x6b618 - 0x20]; }; KSYS_CHECK_SIZE_NX150(SkyMgr, 0x6b618); diff --git a/src/KingSystem/World/worldTimeMgr.cpp b/src/KingSystem/World/worldTimeMgr.cpp index b914772b..2c7eff5e 100644 --- a/src/KingSystem/World/worldTimeMgr.cpp +++ b/src/KingSystem/World/worldTimeMgr.cpp @@ -1,5 +1,6 @@ #include "KingSystem/World/worldTimeMgr.h" #include "KingSystem/GameData/gdtManager.h" +#include "KingSystem/World/worldManager.h" namespace ksys::world { @@ -16,7 +17,7 @@ TimeMgr::TimeMgr() { mForceBloodyDay = false; _14b = false; _cc = {}; - mMoonType = MoonType::Unknown; + mMoonType = MoonType::Auto; } void TimeMgr::init_(sead::Heap* heap) { @@ -24,7 +25,7 @@ void TimeMgr::init_(sead::Heap* heap) { mTimeForAocFieldSkyEnv = DefaultTime; mTimeStep = DefaultTimeStep; mTimeUpdateMode = {}; - mBloodMoonTimer = 0.0; + resetBloodMoonTimer(); mBloodyEndReserveTimer = 0; } @@ -41,21 +42,240 @@ void TimeMgr::resetForStageUnload() { _30[9]._4 = -1; gdt::Manager::instance()->setBool(false, mAnimalMasterCtrl.appearance_flag); - mAnimalMasterCtrl.state = {}; - mAnimalMasterCtrl.appearance_hour = {}; - mAnimalMasterCtrl.valid_hour = {}; - mAnimalMasterCtrl.start_day_of_week = {}; + mAnimalMasterCtrl.resetState(); +} + +void TimeMgr::loadInfo() { + mTimeStep = DefaultTimeStep; + mTimeUpdateMode = TimeUpdateMode::Normal; + mForceBloodyDay = false; + _14b = false; + _cc = 0.0; + mMoonType = MoonType::Auto; + + loadFlags(); + + if (mIsPlayedDemo103Flag != gdt::InvalidHandle) { + gdt::Manager::instance()->getBool(mIsPlayedDemo103Flag, &mPlayedDemo103Or997, true); + if (!mPlayedDemo103Or997) + gdt::Manager::instance()->getBool(mDemo997Flag, &mPlayedDemo103Or997, true); + } + + if (mFindDungeonActivatedFlag != gdt::InvalidHandle) + gdt::Manager::instance()->getBool(mFindDungeonActivatedFlag, &mFindDungeonActivated, true); + + bool animal_master_appearance = false; + gdt::Manager::instance()->getBool(mAnimalMasterCtrl.appearance_flag, &animal_master_appearance); + if (!animal_master_appearance) { + mAnimalMasterCtrl.resetState(); + } + + mWasBloodyDayAndDayPassed = false; +} + +void TimeMgr::loadFlags() { + mTimeFlag = gdt::Manager::instance()->getF32Handle("WM_Time"); + mNumberOfDaysFlag = gdt::Manager::instance()->getS32Handle("WM_NumberOfDays"); + mTimeDivisionFlag = gdt::Manager::instance()->getS32Handle("WM_TimeDivision"); + + gdt::Manager::instance()->getF32(mTimeFlag, &mTime); + gdt::Manager::instance()->getS32(mNumberOfDaysFlag, &mNumberOfDays); + gdt::Manager::instance()->getS32(mTimeDivisionFlag, &mTimeDivision); + + mIsDaytimeFlag = gdt::Manager::instance()->getBoolHandle("WM_DaytimeFlag"); + mIsNighttimeFlag = gdt::Manager::instance()->getBoolHandle("WM_NighttimeFlag"); + mIsPlayedDemo103Flag = gdt::Manager::instance()->getBoolHandle("IsPlayed_Demo103_0"); + mDemo997Flag = gdt::Manager::instance()->getBoolHandle("Demo997_0"); + mFindDungeonActivatedFlag = gdt::Manager::instance()->getBoolHandle("FindDungeon_Activated"); + mIsMorningAFlag = gdt::Manager::instance()->getBoolHandle("WM_IsMorningA"); + mIsMorningBFlag = gdt::Manager::instance()->getBoolHandle("WM_IsMorningB"); + mIsNoonAFlag = gdt::Manager::instance()->getBoolHandle("WM_IsNoonA"); + mIsNoonBFlag = gdt::Manager::instance()->getBoolHandle("WM_IsNoonB"); + mIsEveningAFlag = gdt::Manager::instance()->getBoolHandle("WM_IsEveningA"); + mIsEveningBFlag = gdt::Manager::instance()->getBoolHandle("WM_IsEveningB"); + mIsNightAFlag = gdt::Manager::instance()->getBoolHandle("WM_IsNightA"); + mIsNightBFlag = gdt::Manager::instance()->getBoolHandle("WM_IsNightB"); + mWaterRelicRainStopFlag = gdt::Manager::instance()->getBoolHandle("Water_Relic_RainStop"); + mIsGetPlayerStole2Flag = gdt::Manager::instance()->getBoolHandle("IsGet_PlayerStole2"); + mBloodyDayFlag = gdt::Manager::instance()->getBoolHandle("WM_BloodyDay"); + + mBloodyMoonTimerFlag = gdt::Manager::instance()->getF32Handle("WM_BloodyMoonTimer"); + gdt::Manager::instance()->getF32(mBloodyMoonTimerFlag, &mBloodMoonTimer); + + mBloodyEndReserveTimerFlag = gdt::Manager::instance()->getS32Handle("WM_bloodyEndReserveTimer"); + if (mBloodyEndReserveTimerFlag != gdt::InvalidHandle) + gdt::Manager::instance()->getS32(mBloodyEndReserveTimerFlag, &mBloodyEndReserveTimer); + + mAnimalMasterCtrl.appearance_flag = + gdt::Manager::instance()->getBoolHandle("AnimalMaster_Appearance"); + mAnimalMasterCtrl.existence_flag = + gdt::Manager::instance()->getBoolHandle("AnimalMaster_Existence"); + + mIsInHyruleCastleAreaFlag = gdt::Manager::instance()->getBoolHandle("IsInHyruleCastleArea"); + mLastBossGanonBeastGenerateFlag = + gdt::Manager::instance()->getBoolHandle("LastBossGanonBeastGenerateFlag"); + mWindRelicBattleStartFlag = gdt::Manager::instance()->getBoolHandle("Wind_Relic_BattleStart"); + mElectricRelicBattleFlag = gdt::Manager::instance()->getBoolHandle("Electric_Relic_Battle"); + mWaterRelicBattleTimeFlag = gdt::Manager::instance()->getBoolHandle("Water_Relic_BattleTime"); + mBloodyMoonProhibitionFlag = gdt::Manager::instance()->getBoolHandle("BloodyMoonProhibition"); } TimeMgr::~TimeMgr() = default; +bool TimeMgr::isBloodMoonProhibited() const { + bool prohibited = !Manager::instance()->isMainField(); + + if (gdt::Manager::instance()) { + bool castle = false; + gdt::Manager::instance()->getBool(mIsInHyruleCastleAreaFlag, &castle); + if (castle) + prohibited = true; + + bool last_boss = false; + gdt::Manager::instance()->getBool(mLastBossGanonBeastGenerateFlag, &last_boss); + if (last_boss) + prohibited = true; + } + + if (isBloodMoonProhibitionFlagSet()) + prohibited = true; + + return prohibited; +} + +bool TimeMgr::isBloodMoonProhibitionFlagSet() const { + bool value = false; + if (mBloodyMoonProhibitionFlag == gdt::InvalidHandle) + return false; + gdt::Manager::instance()->getBool(mBloodyMoonProhibitionFlag, &value); + return value; +} + +bool TimeMgr::isInRelicBattle() const { + auto* wm = Manager::instance(); + bool in_battle = false; + + if (gdt::Manager::instance()) { + bool value = false; + gdt::Manager::instance()->getBool(mWindRelicBattleStartFlag, &value); + if (value) + in_battle = true; + + value = false; + gdt::Manager::instance()->getBool(mElectricRelicBattleFlag, &value); + if (value) + in_battle = true; + + value = false; + gdt::Manager::instance()->getBool(mWaterRelicBattleTimeFlag, &value); + if (value) + in_battle = true; + } + + if (wm->getSkyMgr()->checkConcentrationDarkness()) + in_battle = true; + + return in_battle; +} + void TimeMgr::calcType1_() {} void TimeMgr::calcType2_() {} -void TimeMgr::setNewTime(float time) { +void TimeMgr::resetBloodMoonTimer() { + mBloodMoonTimer = 0.0; +} + +void TimeMgr::setTimeWithoutDayChecks(float time) { if (time >= 0.0) mNewTime = time; } +void TimeMgr::setTime(float time) { + auto* wm = Manager::instance(); + mNewTime = time; + mWasBloodyDayAndDayPassed = false; + + if (mTime > mNewTime) { + mNeedToHandleNewDay = true; + + bool was_bloody_day = false; + if (gdt::Manager::instance()) { + if (!gdt::Manager::instance()->getBool(mBloodyDayFlag, &was_bloody_day, false, true)) + return; + + if (was_bloody_day) + mWasBloodyDayAndDayPassed = true; + + if (mWasBloodyDayAndDayPassed && !wm->isMainField()) { + mWasBloodyDayAndDayPassed = false; + mResetGdtOnNextSceneUnloadForBloodMoon = true; + } + } + } +} + +bool TimeMgr::isBloodyDay() const { + bool value = false; + if (!gdt::Manager::instance()) + return false; + gdt::Manager::instance()->getBool(mBloodyDayFlag, &value); + return value; +} + +float TimeMgr::getTimeForSkyEnv() const { + if (Manager::instance()->getStageType() == StageType::OpenWorld && + Manager::instance()->getFieldType() == FieldType::AocField && + Manager::instance()->getScalingMode() == ScalingMode::Disabled) { + return mTimeForAocFieldSkyEnv; + } + return mTime; +} + +void TimeMgr::setAocFieldTimeForSkyEnv(float time) { + mTimeForAocFieldSkyEnv = time; +} + +int TimeMgr::getHour() const { + auto hour = int(mTime / durationToFloat(1, 0)); + if (hour >= 24) + hour -= 24; + return hour; +} + +MoonType TimeMgr::getMoonType() const { + auto type = MoonType(u32(mNumberOfDays + (mTime > timeToFloat(12, 0)) + 1) % 8); + + if (mMoonType != MoonType::Auto) + type = mMoonType; + + if (!willBloodMoonHappenTonight() && !mWasBloodyDay) + return type; + + return MoonType::FullMoon; +} + +bool TimeMgr::willBloodMoonHappenTonight() const { + return Manager::instance()->getTimeMgr()->getHour() >= 4 && isBloodyDay(); +} + +float TimeMgr::getTemperatureMultiplier() const { + const auto time = Manager::instance()->getTimeMgr()->getTime(); + + if (time > 4_h && time < 9_h) + return (time - 4_h) / (4_h - 9_h) + 1.0f; + + if (time >= 9_h && time < 16_h) + return 0.0f; + + if (time >= 16_h && time < 21_h) + return (21_h - time) / (16_h - 21_h) + 1.0f; + + return 1.0f; +} + +bool TimeMgr::isTimeFlowingNormally() const { + return mIsTimeFlowingNormally; +} + } // namespace ksys::world diff --git a/src/KingSystem/World/worldTimeMgr.h b/src/KingSystem/World/worldTimeMgr.h index 0f9eddd2..cabf9bfa 100644 --- a/src/KingSystem/World/worldTimeMgr.h +++ b/src/KingSystem/World/worldTimeMgr.h @@ -10,20 +10,18 @@ namespace ksys::world { -enum class TimeDivision { - Morning_A, - Morning_B, - Noon_A, - Noon_B, - Evening_A, - Evening_B, - Night_A, - Night_B, -}; -SEAD_ENUM(TimeDivisionEnum, Morning_A,Morning_B,Noon_A,Noon_B,Evening_A,Evening_B,Night_A,Night_B) +SEAD_ENUM(TimeDivision, Morning_A,Morning_B,Noon_A,Noon_B,Evening_A,Evening_B,Night_A,Night_B) -enum class MoonType { - Unknown = 0xff, +enum class MoonType : u8 { + FullMoon = 0, + WaningGibbous = 1, + ThirdQuarter = 2, + WaningCrescent = 3, + NewMoon = 4, + WaxingCrescent = 5, + FirstQuarter = 6, + WaxingGibbous = 7, + Auto = 0xff, }; constexpr float timeToFloat(int h, int m) { @@ -34,6 +32,14 @@ constexpr float durationToFloat(int h, int m) { return timeToFloat(h, m); } +constexpr float operator""_h(unsigned long long hours) { + return timeToFloat(static_cast(hours), 0); +} + +constexpr float operator""_m(unsigned long long minutes) { + return timeToFloat(0, static_cast(minutes)); +} + // TODO class TimeMgr : public Job { SEAD_RTTI_OVERRIDE(TimeMgr, Job) @@ -47,8 +53,27 @@ public: JobType getType() const override { return JobType::Time; } + void loadInfo(); void resetForStageUnload(); - void setNewTime(float time); + + void callBloodMoonDemo(); + bool isBloodMoonProhibited() const; + bool isBloodMoonProhibitionFlagSet() const; + bool isInRelicBattle() const; + + void resetBloodMoonTimer(); + void setTimeWithoutDayChecks(float time); + void setTime(float time); + bool isBloodyDay() const; + float getTime() const { return mTime; } + float getTimeForSkyEnv() const; + void setAocFieldTimeForSkyEnv(float time); + int getHour() const; + int getMinute() const; + MoonType getMoonType() const; + bool willBloodMoonHappenTonight() const; + float getTemperatureMultiplier() const; + bool isTimeFlowingNormally() const; protected: void init_(sead::Heap* heap) override; @@ -58,7 +83,7 @@ protected: private: enum class TimeUpdateMode { - + Normal = 0, }; struct AnimalMasterController { @@ -68,6 +93,13 @@ private: void calc(); + void resetState() { + state = {}; + appearance_hour = {}; + valid_hour = {}; + start_day_of_week = {}; + } + gdt::FlagHandle appearance_flag = gdt::InvalidHandle; gdt::FlagHandle existence_flag = gdt::InvalidHandle; State state{}; @@ -80,12 +112,14 @@ private: static constexpr float DefaultTime = timeToFloat(5, 15); static constexpr float DefaultTimeStep = durationToFloat(0, 1) / 30.0; + void loadFlags(); + bool _20; bool _21; u16 _22; bool _24; - TimeDivision mTimeDivision{}; - TimeDivision mTimeDivision2{}; + int mTimeDivision{}; + int mTimeDivision2{}; struct { std::array _0; int _4; @@ -109,8 +143,8 @@ private: gdt::FlagHandle mFindDungeonActivatedFlag = gdt::InvalidHandle; gdt::FlagHandle mIsMorningAFlag = gdt::InvalidHandle; gdt::FlagHandle mIsMorningBFlag = gdt::InvalidHandle; - gdt::FlagHandle mIsMoonAFlag = gdt::InvalidHandle; - gdt::FlagHandle mIsMoonBFlag = gdt::InvalidHandle; + gdt::FlagHandle mIsNoonAFlag = gdt::InvalidHandle; + gdt::FlagHandle mIsNoonBFlag = gdt::InvalidHandle; gdt::FlagHandle mIsEveningAFlag = gdt::InvalidHandle; gdt::FlagHandle mIsEveningBFlag = gdt::InvalidHandle; gdt::FlagHandle mIsNightAFlag = gdt::InvalidHandle; @@ -122,24 +156,29 @@ private: gdt::FlagHandle mBloodyEndReserveTimerFlag = gdt::InvalidHandle; gdt::FlagHandle mIsInHyruleCastleAreaFlag = gdt::InvalidHandle; gdt::FlagHandle mLastBossGanonBeastGenerateFlag = gdt::InvalidHandle; - gdt::FlagHandle mWindElectricBattleStartFlag = gdt::InvalidHandle; + gdt::FlagHandle mWindRelicBattleStartFlag = gdt::InvalidHandle; gdt::FlagHandle mElectricRelicBattleFlag = gdt::InvalidHandle; - gdt::FlagHandle mWindRelicBattleTimeFlag = gdt::InvalidHandle; + gdt::FlagHandle mWaterRelicBattleTimeFlag = gdt::InvalidHandle; int mNumberOfDays{}; gdt::FlagHandle mBloodyMoonProhibitionFlag = gdt::InvalidHandle; int mBloodyEndReserveTimer{}; bool mNeedToHandleNewDay{}; - sead::SizedEnum mTimeUpdateMode{}; + sead::SizedEnum mTimeUpdateMode = TimeUpdateMode::Normal; bool mForceBloodyDay; bool _14b; - sead::SizedEnum mMoonType; + MoonType mMoonType; bool mPlayedDemo103Or997{}; bool mFindDungeonActivated{}; - bool _14f{}; + bool mIsTimeFlowingNormally{}; bool mWasBloodyDayAndDayPassed{}; bool mResetGdtOnNextSceneUnloadForBloodMoon{}; bool mWasBloodyDay{}; }; KSYS_CHECK_SIZE_NX150(TimeMgr, 0x158); +inline int TimeMgr::getMinute() const { + auto remainder = float(int(mTime * 1000.f) % int(durationToFloat(1, 0) * 1000.f)) / 1000.f; + return int((remainder / durationToFloat(1, 0)) * 60.f); +} + } // namespace ksys::world