diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 316361ea..5c349744 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -77857,7 +77857,7 @@ 0x0000007100e4174c,Ecosystem::createInstance,208,_ZN4ksys3eco9Ecosystem14createInstanceEPN4sead4HeapE 0x0000007100e4181c,Ecosystem::init,1056, 0x0000007100e41c3c,Ecosystem::calc_stubbed,4,_ZN4ksys3eco9Ecosystem4calcEv -0x0000007100e41c40,eco::getCurrentAreaNum,292,_ZNK4ksys3eco9Ecosystem17getCurrentAreaNumEPNS0_10EcoMapInfoEff? +0x0000007100e41c40,eco::getCurrentAreaNum,292,_ZNK4ksys3eco9Ecosystem10getMapAreaERKNS0_10EcoMapInfoEff! 0x0000007100e41d64,Ecosystem::__auto1,636, 0x0000007100e41fe0,Ecosystem::getStatusEffectInfo,384,_ZNK4ksys3eco9Ecosystem19getStatusEffectInfoENS0_12StatusEffectEiPNS0_16StatusEffectInfoE? 0x0000007100e42160,Ecosystem::getAreaNameByNum,120,_ZNK4ksys3eco9Ecosystem16getAreaNameByNumEiPPKc @@ -89544,37 +89544,37 @@ 0x00000071010f29a8,nullsub_5567,4, 0x00000071010f29ac,nullsub_5568,4, 0x00000071010f29b0,nullsub_5569,4, -0x00000071010f29b4,sinitWorldMgrStrings,504, -0x00000071010f2bac,WorldMgr::getWeatherType,8, -0x00000071010f2bb4,WorldMgr::setWeather,80, -0x00000071010f2c04,WorldMgr::setWeatherByName,376, -0x00000071010f2d7c,getWeatherString,68, -0x00000071010f2dc0,WorldMgr::getAreaForPosition,356, -0x00000071010f2f24,WorldMgr::getCurrentArea,8, -0x00000071010f2f2c,WorldMgr::getField784,8, -0x00000071010f2f34,WorldMgr::getField754,8, +0x00000071010f29b4,sinitWorldMgrStrings,504,_GLOBAL__sub_I_worldManager.cpp +0x00000071010f2bac,WorldMgr::getWeatherType,8,_ZNK4ksys5world7Manager14getWeatherTypeEv +0x00000071010f2bb4,WorldMgr::setWeather,80,_ZN4ksys5world7Manager14setWeatherTypeENS0_11WeatherTypeEbbb +0x00000071010f2c04,WorldMgr::setWeatherByName,376,_ZN4ksys5world7Manager14setWeatherTypeERKN4sead14SafeStringBaseIcEEbbb +0x00000071010f2d7c,getWeatherString,68,_ZN4ksys5world7Manager20getWeatherTypeStringENS0_11WeatherTypeE +0x00000071010f2dc0,WorldMgr::getAreaForPosition,356,_ZNK4ksys5world7Manager10getClimateERKN4sead7Vector3IfEE +0x00000071010f2f24,WorldMgr::getCurrentArea,8,_ZNK4ksys5world7Manager17getCurrentClimateEv +0x00000071010f2f2c,WorldMgr::getField784,8,_ZNK4ksys5world7Manager14getPrevClimateEv +0x00000071010f2f34,WorldMgr::getField754,8,_ZNK4ksys5world7Manager28getClimateTransitionProgressEv 0x00000071010f2f3c,WorldMgr::someWeatherStuff_0,972, 0x00000071010f3308,WorldMgr::x_14,44, -0x00000071010f3334,WorldMgr::getSomeClimateProp_0,32, -0x00000071010f3354,WorldMgr::getSomeClimateProp,32, +0x00000071010f3334,WorldMgr::getSomeClimateProp_0,32,_ZNK4ksys5world7Manager16isDayLockBlueSkyENS0_7ClimateE +0x00000071010f3354,WorldMgr::getSomeClimateProp,32,_ZNK4ksys5world7Manager18isNightLockBlueSkyENS0_7ClimateE 0x00000071010f3374,WorldMgr::__auto13,8, 0x00000071010f337c,WorldMgr::__auto3,40, 0x00000071010f33a4,WorldMgr::isRaining,84, -0x00000071010f33f8,WorldMgr::calcTempDay,452, -0x00000071010f35bc,WorldMgr::calcTempNight,452, -0x00000071010f3780,WorldMgr::getMoistureMaxForCurrentClimate,68, -0x00000071010f37c4,WorldMgr::getMoistureMinForCurrentClimate,68, -0x00000071010f3808,WorldMgr::__auto10,160, -0x00000071010f38a8,WorldMgr::getWindPowerForCurrentClimate,164, -0x00000071010f394c,WorldMgr::getWindPowerForPos,216, -0x00000071010f3a24,WorldMgr::__auto11,112, +0x00000071010f33f8,WorldMgr::calcTempDay,452,_ZNK4ksys5world7Manager11calcTempDayEf +0x00000071010f35bc,WorldMgr::calcTempNight,452,_ZNK4ksys5world7Manager13calcTempNightEf +0x00000071010f3780,WorldMgr::getMoistureMaxForCurrentClimate,68,_ZNK4ksys5world7Manager14getMoistureMaxEv +0x00000071010f37c4,WorldMgr::getMoistureMinForCurrentClimate,68,_ZNK4ksys5world7Manager14getMoistureMinEv +0x00000071010f3808,WorldMgr::__auto10,160,_ZNK4ksys5world7Manager16getWindDirectionEv +0x00000071010f38a8,WorldMgr::getWindPowerForCurrentClimate,164,_ZNK4ksys5world7Manager12getWindSpeedEv +0x00000071010f394c,WorldMgr::getWindPowerForPos,216,_ZNK4ksys5world7Manager12getWindSpeedERKN4sead7Vector3IfEE +0x00000071010f3a24,WorldMgr::__auto11,112,_ZNK4ksys5world7Manager16getWindDirectionERKN4sead7Vector3IfEE 0x00000071010f3a94,WorldMgr::x_9,36, 0x00000071010f3ab8,sub_71010F3AB8,36, 0x00000071010f3adc,WorldMgr::getIgnitedLevel,304, -0x00000071010f3c0c,WorldMgr::getCurrentClimatePaletteSetSelect,104, -0x00000071010f3c74,WorldMgr::getCurrentClimateFogType,104, -0x00000071010f3cdc,WorldMgr::isCurrentClimateForbidComeback,96, -0x00000071010f3d3c,WorldMgr::isClimateForbidComeback,92, +0x00000071010f3c0c,WorldMgr::getCurrentClimatePaletteSetSelect,104,_ZNK4ksys5world7Manager19getPaletteSetSelectEv +0x00000071010f3c74,WorldMgr::getCurrentClimateFogType,104,_ZNK4ksys5world7Manager10getFogTypeEv +0x00000071010f3cdc,WorldMgr::isCurrentClimateForbidComeback,96,_ZNK4ksys5world7Manager16isForbidComebackEv +0x00000071010f3d3c,WorldMgr::isClimateForbidComeback,92,_ZNK4ksys5world7Manager16isForbidComebackENS0_7ClimateE 0x00000071010f3d98,WorldMgr::unloadDgnenvAndGetWeatherMgr,76, 0x00000071010f3de4,WorldMgr::ctor,728,_ZN4ksys5world7ManagerC1Ev! 0x00000071010f40bc,WorldMgr::init,836, diff --git a/lib/sead b/lib/sead index 0acd5dbc..037df8eb 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit 0acd5dbc592bf047883a3e9aef6f6f9975d89e79 +Subproject commit 037df8eb8524b686b4539241f586e880a54e9962 diff --git a/src/KingSystem/Ecosystem/ecoSystem.cpp b/src/KingSystem/Ecosystem/ecoSystem.cpp index 96680112..42da40ac 100644 --- a/src/KingSystem/Ecosystem/ecoSystem.cpp +++ b/src/KingSystem/Ecosystem/ecoSystem.cpp @@ -30,28 +30,28 @@ SEAD_SINGLETON_DISPOSER_IMPL(Ecosystem) void Ecosystem::calc() {} // NON_MATCHING: FP instructions rearranged. -s32 Ecosystem::getCurrentAreaNum(EcoMapInfo* info, f32 posX, f32 posZ) const { +s32 Ecosystem::getMapArea(const EcoMapInfo& info, f32 posX, f32 posZ) const { posX = sead::clamp(posX, -5000.0F, 4999.0F); posZ = sead::clamp(posZ, -4000.0F, 4000.0F); f32 epsilon1 = (posX + 5000.0F >= 0.0F) ? 0.5F : -0.5F; f32 epsilon2 = (posZ + 4000.0F >= 0.0F) ? 0.5F : -0.5F; s32 x = posX + 5000.0F + epsilon1; - s32 z = (posZ + 4000.0F + epsilon2) / info->mHeader->divisor; + s32 z = (posZ + 4000.0F + epsilon2) / info.mHeader->divisor; - s32 row = sead::clamp(z, (s32)0, info->mHeader->num_rows - 2); + s32 row = sead::clamp(z, (s32)0, info.mHeader->num_rows - 2); - if (info->mHeader->divisor == 10) + if (info.mHeader->divisor == 10) x = x / 10; - s32* offsets = (s32*)info->mRowOffsets + row; + s32* offsets = (s32*)info.mRowOffsets + row; s32 val0 = offsets[0]; s32 val1 = offsets[1]; if (val0 >= val1) return -1; - Segment* segmentEnd = reinterpret_cast((char*)info->mRows + 2 * val1); - Segment* segment = reinterpret_cast((char*)info->mRows + 2 * val0); + Segment* segmentEnd = reinterpret_cast((char*)info.mRows + 2 * val1); + Segment* segment = reinterpret_cast((char*)info.mRows + 2 * val0); s32 totalLength = 0; while (true) { totalLength += segment->length; diff --git a/src/KingSystem/Ecosystem/ecoSystem.h b/src/KingSystem/Ecosystem/ecoSystem.h index c7b85aee..dada5091 100644 --- a/src/KingSystem/Ecosystem/ecoSystem.h +++ b/src/KingSystem/Ecosystem/ecoSystem.h @@ -94,6 +94,21 @@ private: virtual ~Ecosystem(); public: + void init(); + void calc(); + + s32 getMapArea(const EcoMapInfo& info, f32 posX, f32 posZ) const; + + s32 getFieldMapArea(f32 x, f32 z) const { return getMapArea(mFieldMapArea, x, z); } + + void getActorSpawnInfo(s32 areaNum, ActorType actorTypeIdx, ActorSpawnInfo* out) const; + void getStatusEffectInfo(StatusEffect statusEffectIdx, s32 idx, StatusEffectInfo* out) const; + void getAreaNameByNum(s32 areaNum, const char** out) const; + void getClimateNameByNum(s32 areaNum, const char** out) const; + void getEnvSoundNameByNum(s32 areaNum, const char** out) const; + void getEcoTraitsByNum(s32 areaNum, EcosystemTraits* out) const; + +private: res::Handle mFieldMapAreaFile; res::Handle mAreaDataFile; res::Handle mMapTowerFile; @@ -109,18 +124,6 @@ public: EcoMapInfo mLoadBalancer{}; u32 mFlags{}; u32 mLast; - - void init(); - void calc(); - - s32 getCurrentAreaNum(EcoMapInfo* info, f32 posX, f32 posZ) const; - - void getActorSpawnInfo(s32 areaNum, ActorType actorTypeIdx, ActorSpawnInfo* out) const; - void getStatusEffectInfo(StatusEffect statusEffectIdx, s32 idx, StatusEffectInfo* out) const; - void getAreaNameByNum(s32 areaNum, const char** out) const; - void getClimateNameByNum(s32 areaNum, const char** out) const; - void getEnvSoundNameByNum(s32 areaNum, const char** out) const; - void getEcoTraitsByNum(s32 areaNum, EcosystemTraits* out) const; }; } // namespace ksys::eco diff --git a/src/KingSystem/Ecosystem/ecoUtil.cpp b/src/KingSystem/Ecosystem/ecoUtil.cpp index f651de6a..6ee2731e 100644 --- a/src/KingSystem/Ecosystem/ecoUtil.cpp +++ b/src/KingSystem/Ecosystem/ecoUtil.cpp @@ -3,8 +3,7 @@ namespace ksys::eco { bool currentAreaNumIs64(const sead::Vector3f& pos) { - return Ecosystem::instance()->getCurrentAreaNum(&Ecosystem::instance()->mFieldMapArea, pos.x, - pos.z) == 64; + return Ecosystem::instance()->getFieldMapArea(pos.x, pos.z) == 64; } } // namespace ksys::eco diff --git a/src/KingSystem/World/worldManager.cpp b/src/KingSystem/World/worldManager.cpp index 10e649d8..c130ec9a 100644 --- a/src/KingSystem/World/worldManager.cpp +++ b/src/KingSystem/World/worldManager.cpp @@ -1,9 +1,309 @@ #include "KingSystem/World/worldManager.h" +#include +#include "KingSystem/Ecosystem/ecoSystem.h" +#include "KingSystem/Utils/InitTimeInfo.h" namespace ksys::world { +namespace { + +util::InitConstants sInitConsts; + +const sead::SafeString cWeatherTypes[] = { + "Bluesky", "Cloudy", "Rain", "HeavyRain", "Snow", + "HeavySnow", "ThunderStorm", "ThunderRain", "BlueskyRain", +}; + +const sead::SafeString cMagicStrings[] = { + "MagicStorm,MagicRedhot,MagicCold", + {}, + {}, +}; + +const sead::SafeString cClimates[] = { + "HyrulePlainClimate", + "NorthHyrulePlainClimate", + "HebraFrostClimate", + "TabantaAridClimate", + "FrostClimate", + "GerudoDesertClimate", + "GerudoPlateauClimate", + "EldinClimateLv0", + "TamourPlainClimate", + "ZoraTemperateClimate", + "HateruPlainClimate", + "FiloneSubtropicalClimate", + "SouthHateruHumidTemperateClimate", + "EldinClimateLv1", + "EldinClimateLv2", + // sic + "DarkWoodsClimat", + "LostWoodClimate", + "GerudoFrostClimate", + "KorogForest", + "GerudoDesertClimateLv2", +}; + +bool isValidTemp(float temp) { + return temp < 99999; +} + +} // namespace + SEAD_SINGLETON_DISPOSER_IMPL(Manager) +WeatherType Manager::getWeatherType() const { + return mWeatherType; +} + +void Manager::setWeatherType(WeatherType weather_type, bool x, bool y, bool for_demo) { + // Ignore invalid weather requests. + if (u32(weather_type) >= NumWeatherTypes) + return; + + if (mWeatherSetForDemo && !for_demo) + return; + + if (_794 != 0 && y && mWeatherType.mValue > u8(weather_type)) + return; + + mWeatherType = weather_type; + _794 = 4; + _7d5 = x; + mWeatherSetForDemo = for_demo; +} + +void Manager::setWeatherType(const sead::SafeString& weather_type, bool x, bool y, bool for_demo) { + for (u8 i = 0; i < NumWeatherTypes; ++i) { + if (weather_type == cWeatherTypes[i]) { + setWeatherType(WeatherType(i), x, y, for_demo); + return; + } + } +} + +const char* Manager::getWeatherTypeString(WeatherType type) { + auto index = ptrdiff_t(type); + if (u32(index) >= NumWeatherTypes) + index = 0; + return cWeatherTypes[index].cstr(); +} + +Climate Manager::getClimate(const sead::Vector3f& pos) const { + const auto area = eco::Ecosystem::instance()->getFieldMapArea(pos.x, pos.z); + if (area < 0) + return {}; + + const char* climate; + eco::Ecosystem::instance()->getClimateNameByNum(area, &climate); + if (climate == nullptr) + return {}; + + for (int i = 0; i < int(NumClimates); ++i) { + if (cClimates[i] == climate) + return Climate(i); + } + return {}; +} + +Climate Manager::getCurrentClimate() const { + return mCurrentClimate; +} + +Climate Manager::getPrevClimate() const { + return mPrevClimate; +} + +float Manager::getClimateTransitionProgress() const { + return mClimateTransitionProgress; +} + +bool Manager::isDayLockBlueSky(Climate climate) const { + return mWorldInfo.mClimates[int(climate)].dayLockBlueSky.ref(); +} + +bool Manager::isNightLockBlueSky(Climate climate) const { + return mWorldInfo.mClimates[int(climate)].nightLockBlueSky.ref(); +} + +float Manager::calcTempDay(float height) const { + float normal_temp = 23.0f; + + if (isMainField() && worldInfoLoaded()) { + height = sead::Mathf::max(height, 0.0f); + + int a = -1; + float h{}; + for (int i = 0; i < ClimateInfo::NumClimateTemp; ++i) { + h = float(ClimateInfo::NumClimateTemp - (i + 1)) * 100.0f; + if (height >= h) { + a = i; + break; + } + } + + float t = 1.0f; + int b = a; + if (a > 0) { + b = a - 1; + t = 1.0f - (h + 100.0f - height) / (h + 100.0f - h); + } + + if (a != -1) { + const auto& temps = mWorldInfo.mClimates[int(mCurrentClimate)].climateTempDay; + const float v = *temps[b]; + const float u = *temps[a]; + normal_temp = u + t * (v - u); + } + } + + float temp = mTempDirectDay; + if (!isValidTemp(temp)) + temp = normal_temp; + + const float extra_temp = mTempDirectDayExtra; + if (isValidTemp(extra_temp)) + temp += extra_temp; + + return temp; +} + +float Manager::calcTempNight(float height) const { + float normal_temp = 23.0f; + + if (isMainField() && worldInfoLoaded()) { + height = sead::Mathf::max(height, 0.0f); + + int a = -1; + float h{}; + for (int i = 0; i < ClimateInfo::NumClimateTemp; ++i) { + h = float(ClimateInfo::NumClimateTemp - (i + 1)) * 100.0f; + if (height >= h) { + a = i; + break; + } + } + + float t = 1.0f; + int b = a; + if (a > 0) { + b = a - 1; + t = 1.0f - (h + 100.0f - height) / (h + 100.0f - h); + } + + if (a != -1) { + const auto& temps = mWorldInfo.mClimates[int(mCurrentClimate)].climateTempNight; + const float v = *temps[b]; + const float u = *temps[a]; + normal_temp = u + t * (v - u); + } + } + + float temp = mTempDirectNight; + if (!isValidTemp(temp)) + temp = normal_temp; + + const float extra_temp = mTempDirectNightExtra; + if (isValidTemp(extra_temp)) + temp += extra_temp; + + return temp; +} + +float Manager::getMoistureMax() const { + if (!isMainField() || !worldInfoLoaded()) + return 0.0; + return mWorldInfo.mClimates[int(mCurrentClimate)].moistureMax.ref(); +} + +float Manager::getMoistureMin() const { + if (!isMainField() || !worldInfoLoaded()) + return 0.0; + return mWorldInfo.mClimates[int(mCurrentClimate)].moistureMin.ref(); +} + +sead::Vector3f Manager::getWindDirection() const { + float x; + int idx = 0; + if (mStageType == StageType::OpenWorld && mFieldType == FieldType::AocField && + mScalingMode == ScalingMode::Disabled) { + x = std::sin(mWindDirections[0]); + } else { + x = std::sin(mWindDirections[int(mCurrentClimate)]); + idx = int(mCurrentClimate); + } + return {x, 0, std::cos(mWindDirections[idx])}; +} + +float Manager::getWindSpeed() const { + float value = 0.0; + if (isMainField() && worldInfoLoaded()) { + value = mWorldInfo.mClimates[int(mCurrentClimate)].windPower.ref(); + value *= mWorldInfo.mClimates[int(mCurrentClimate)].windPowerMultiplier; + } + overrideWindSpeed(&value); + return value; +} + +float Manager::getWindSpeed(const sead::Vector3f& pos) const { + float value = 0.0; + if (isMainField() && worldInfoLoaded()) { + value = mWorldInfo.mClimates[int(getClimate(pos))].windPower.ref(); + value *= mWorldInfo.mClimates[int(getClimate(pos))].windPowerMultiplier; + } + overrideWindSpeed(&value); + return value; +} + +void Manager::overrideWindSpeed(float* wind_speed) const { + if (isAocField()) + *wind_speed = mWindSpeedAocField; + if (mMapEdgeWindEnabled) + *wind_speed = mMapEdgeWindSpeed; + if (mManualWindTimer != 0) + *wind_speed = mManualWindSpeed; +} + +sead::Vector3f Manager::getWindDirection(const sead::Vector3f& pos) const { + float x = std::sin(mWindDirections[int(getClimate(pos))]); + float z = std::cos(mWindDirections[int(getClimate(pos))]); + return {x, 0, z}; +} + +int Manager::getPaletteSetSelect() const { + if (!worldInfoLoaded() || mStageType != StageType::OpenWorld) + return 0; + + const auto climate = mCurrentClimate; + + if (isAocField()) + return 0; + + return mWorldInfo.mClimates[int(climate)].paletteSetSelect.ref(); +} + +int Manager::getFogType() const { + if (!worldInfoLoaded() || mStageType != StageType::OpenWorld) + return 0; + + const auto climate = mCurrentClimate; + + if (isAocField()) + return 0; + + return mWorldInfo.mClimates[int(climate)].fogType.ref(); +} + +bool Manager::isForbidComeback() const { + return isForbidComeback(mCurrentClimate); +} + +bool Manager::isForbidComeback(Climate climate) const { + if (!worldInfoLoaded() || !isMainField()) + return false; + return mWorldInfo.mClimates[int(climate)].forbidComeback.ref(); +} + // NON_MATCHING: stores in a different order (handwritten assignments?) but should be equivalent Manager::Manager() = default; diff --git a/src/KingSystem/World/worldManager.h b/src/KingSystem/World/worldManager.h index 1d4f4e84..92f5276f 100644 --- a/src/KingSystem/World/worldManager.h +++ b/src/KingSystem/World/worldManager.h @@ -6,15 +6,115 @@ #include #include #include +#include #include #include +#include #include "KingSystem/Resource/resHandle.h" #include "KingSystem/Utils/Types.h" namespace ksys::world { -// FIXME -class Climate {}; +enum class CalcType { + _3 = 3, +}; + +enum class StageType { + Invalid = 0, + OpenWorld = 1, + Indoor = 2, + OpenWorldTest = 3, + MainFieldDungeon = 4, + Viewer = 5, +}; + +enum class RemainsType { + +}; + +enum class FieldType { + MainField = 0, + AocField = 1, +}; + +enum class ScalingMode { + Enabled = 0, + Disabled = 1, +}; + +enum class WeatherType { + Bluesky, + Cloudy, + Rain, + HeavyRain, + Snow, + HeavySnow, + ThunderStorm, + ThunderRain, + BlueskyRain, + Invalid = 0xff, +}; +constexpr u32 NumWeatherTypes = 9; + +enum class Climate { + HyrulePlainClimate, + NorthHyrulePlainClimate, + HebraFrostClimate, + TabantaAridClimate, + FrostClimate, + GerudoDesertClimate, + GerudoPlateauClimate, + EldinClimateLv0, + TamourPlainClimate, + ZoraTemperateClimate, + HateruPlainClimate, + FiloneSubtropicalClimate, + SouthHateruHumidTemperateClimate, + EldinClimateLv1, + EldinClimateLv2, + // sic + DarkWoodsClimat, + LostWoodClimate, + GerudoFrostClimate, + KorogForest, + GerudoDesertClimateLv2, +}; +constexpr u32 NumClimates = 20; + +struct ClimateInfo { + static constexpr int NumClimateTemp = 11; + + agl::utl::Parameter weatherType; + agl::utl::Parameter weatherBlueskyRate; + agl::utl::Parameter weatherCloudyRate; + agl::utl::Parameter weatherRainRate; + agl::utl::Parameter weatherHeavyRainRate; + agl::utl::Parameter weatherStormRate; + agl::utl::Parameter dayLockBlueSky; + agl::utl::Parameter nightLockBlueSky; + sead::SafeArray, NumClimateTemp> climateTempDay; + sead::SafeArray, NumClimateTemp> climateTempNight; + agl::utl::Parameter moistureMax; + agl::utl::Parameter moistureMin; + agl::utl::Parameter windPower; + agl::utl::ParameterObj obj; + u32 windDirectionType; + float windPowerMultiplier; + agl::utl::Parameter ignitedLevel; + agl::utl::Parameter featureColor; + agl::utl::Parameter _4a0; + agl::utl::Parameter _4c0; + agl::utl::Parameter _4e0; + agl::utl::Parameter _500; + agl::utl::Parameter _520; + agl::utl::Parameter _540; + agl::utl::Parameter _560; + agl::utl::Parameter paletteSetSelect; + agl::utl::Parameter fogType; + agl::utl::Parameter forbidComeback; + agl::utl::Parameter _5e0; +}; +KSYS_CHECK_SIZE_NX150(ClimateInfo, 0x600); class WorldInfo : public agl::utl::IParameterIO, public sead::hostio::Node { public: @@ -22,7 +122,7 @@ public: u8 _1d8[0x20]; res::Handle mResHandle; - sead::Buffer mClimates; + sead::Buffer mClimates; }; KSYS_CHECK_SIZE_NX150(WorldInfo, 0x258); @@ -39,6 +139,15 @@ public: }; KSYS_CHECK_SIZE_NX150(DungeonEnv, 0x338); +class TimeMgr; +class CloudMgr; +class ShootingStarMgr; +class WeatherMgr; +class TempMgr; +class SkyMgr; +class DofMgr; +class ChemicalMgr; + // FIXME: incomplete class Manager : public sead::hostio::Node { SEAD_SINGLETON_DISPOSER(Manager) @@ -46,33 +155,79 @@ class Manager : public sead::hostio::Node { virtual ~Manager(); public: - enum class CalcType { - _3 = 3, - }; + WeatherType getWeatherType() const; + void setWeatherType(WeatherType weather_type, bool x, bool y, bool for_demo); + void setWeatherType(const sead::SafeString& weather_type, bool x, bool y, bool for_demo); + static const char* getWeatherTypeString(WeatherType type); - enum class StageType { + Climate getClimate(const sead::Vector3f& pos) const; + Climate getCurrentClimate() const; + Climate getPrevClimate() const; + float getClimateTransitionProgress() const; - }; - - enum class RemainsType { - - }; - - enum class FieldType { - - }; - - enum class ScalingMode { - - }; + bool isDayLockBlueSky(Climate climate) const; + bool isNightLockBlueSky(Climate climate) const; bool isRaining(const sead::Vector3f& pos) const; + float calcTempDay(float height) const; + float calcTempNight(float height) const; + + float getMoistureMax() const; + float getMoistureMin() const; + + sead::Vector3f getWindDirection() const; + float getWindSpeed() const; + float getWindSpeed(const sead::Vector3f& pos) const; + sead::Vector3f getWindDirection(const sead::Vector3f& pos) const; + + int getIgnitedLevel(const sead::Vector3f& pos) const; + + int getPaletteSetSelect() const; + int getFogType() const; + bool isForbidComeback() const; + bool isForbidComeback(Climate climate) const; + + void unload(); + void init(sead::Heap* heap); + void resetForStageUnload(); + void loadWorldInfoRes(); + void loadWorldInfo(); + void updateRemainsType(); + void updateGraphicsMap(StageType type); + + bool isMainField() const { return mIsMainField && mStageType == StageType::OpenWorld; } + + bool isAocField() const { + return mStageType == StageType::OpenWorld && mFieldType == FieldType::AocField && + mScalingMode == ScalingMode::Disabled; + } + + TimeMgr* getTimeMgr() const { return static_cast(mMgrs[0]); } + CloudMgr* getCloudMgr() const { return static_cast(mMgrs[1]); } + ShootingStarMgr* getShootingStarMgr() const { return static_cast(mMgrs[2]); } + WeatherMgr* getWeatherMgr() const { return static_cast(mMgrs[3]); } + TempMgr* getTempMgr() const { return static_cast(mMgrs[4]); } + SkyMgr* getSkyMgr() const { return static_cast(mMgrs[6]); } + DofMgr* getDofMgr() const { return static_cast(mMgrs[7]); } + ChemicalMgr* getChemicalMgr() const { return static_cast(mMgrs[8]); } + +private: + enum class WorldInfoLoadStatus : u8 { + NotLoaded, + Loaded, + Unloaded, + }; + + bool worldInfoLoaded() const { return mWorldInfoLoadStatus != WorldInfoLoadStatus::NotLoaded; } + + void overrideWindSpeed(float* wind_speed) const; + WorldInfo mWorldInfo; DungeonEnv mDungeonEnv; sead::DirectResource* mInfoRes{}; - sead::PtrArray mMgrs; + sead::PtrArray mMgrs; agl::utl::AtomicPtrArray mAtomicPtrArray; sead::BitFlag32 _5e0 = 1; CalcType mCalcType = CalcType::_3; @@ -92,15 +247,15 @@ public: bool _6cc = false; bool mGameSceneInitialized = false; - float mFloatsPerClimate[20]; + sead::SafeArray mWindDirections; u32 _720 = 0; sead::Vector3f mWindDir{0, 0, -1}; sead::Vector3f mDirectionalLightVecA{0, 1, 0}; sead::Vector3f mDirectionalLightVecB{0, 1, 0}; sead::Vector3f _748{0, 0, 0}; - float _754 = 1.0; - float mWindPowerIf7D4 = 1.0; - float mWindPowerIf78C = 5.0; + float mClimateTransitionProgress = 1.0; + float mMapEdgeWindSpeed = 1.0; + float mManualWindSpeed = 5.0; float mTempDirectDayExtra = 99999.9; float mTempDirectNightExtra = 99999.9; float mTempDirectDay = 99999.9; @@ -109,11 +264,11 @@ public: float mFocusDist = 100.0; float _778 = -1.0; u32 _77c = 9; - u32 mCurrentArea = 0; - u32 mPrevArea = 0; - u32 _788 = 0; - u32 _78c = 0; - u32 _790 = 0; + Climate mCurrentClimate{}; + Climate mPrevClimate{}; + u32 mWindDirectionType = 0; + u32 mManualWindTimer = 0; + u32 mMapEdgeWindDirectionType = 0; u32 _794 = 0; int _798 = -1; u32 _79c = 0; @@ -127,15 +282,15 @@ public: RemainsType mRemainsType{}; FieldType mFieldType{}; ScalingMode mScalingMode{}; - u32 _7c8 = 0; - float mWindPowerAocField = 0.75; - bool mWorldInfoLoaded = false; - u8 mWeatherType = 0xFF; - u8 _7d2 = 0; - u8 _7d3 = 1; - u8 _7d4 = 0; - u8 _7d5 = 0; - u8 _7d6 = 0; + u32 mWindChangeFinalTimer = 0; + float mWindSpeedAocField = 0.75; + WorldInfoLoadStatus mWorldInfoLoadStatus = WorldInfoLoadStatus::NotLoaded; + sead::SizedEnum mWeatherType = WeatherType::Invalid; + u8 mDirectionalLightTimer = 0; + bool mWindChangesEnabled = true; + bool mMapEdgeWindEnabled = false; + bool _7d5 = false; + bool mWeatherSetForDemo = false; u8 _7d7 = 0; bool mIsDemo = false; bool mIsMainField = false;