diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 86772676..c99ea488 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -80196,12 +80196,12 @@ 0x0000007100edd54c,act::hasOneTagByNames_0,1160,_ZN4ksys3act16hasOneTagAtLeastEPNS0_5ActorERKN4sead14SafeStringBaseIcEE 0x0000007100edd9d4,act::hasOneTagByNames,724,_ZN4ksys3act16hasOneTagAtLeastEPNS0_12BaseProcLinkERKN4sead14SafeStringBaseIcEE 0x0000007100eddca8,ActorAccessor::hasOneTagByNames,688,_ZN4ksys3act16hasOneTagAtLeastERKNS0_20ActorConstDataAccessERKN4sead14SafeStringBaseIcEE -0x0000007100eddf58,PlacementObj::shouldSkipSpawnWeatherStuff,108, -0x0000007100eddfc4,PlacementObj::isAnimalMasterAppearance,148, -0x0000007100ede058,PlacementObj::shouldSkipSpawnGodForestActor,256, -0x0000007100ede158,PlacementObj::shouldSkipSpawnFairy,188, -0x0000007100ede214,sub_7100EDE214,208, -0x0000007100ede2e4,PlacementMgr::setSomeGlobalPlacementFlags,180, +0x0000007100eddf58,PlacementObj::shouldSkipSpawnWeatherStuff,108,_ZN4ksys3act26shouldSkipSpawnWhenRainingEPNS_3map6ObjectE? +0x0000007100eddfc4,PlacementObj::isAnimalMasterAppearance,148,_ZN4ksys3act29shouldSkipSpawnIfGodForestOffEPNS_3map6ObjectE +0x0000007100ede058,PlacementObj::shouldSkipSpawnGodForestActor,256,_ZN4ksys3act29shouldSkipSpawnGodForestActorEPNS_3map6ObjectE +0x0000007100ede158,PlacementObj::shouldSkipSpawnFairy,188,_ZN4ksys3act20shouldSkipSpawnFairyEPNS_3map6ObjectE +0x0000007100ede214,sub_7100EDE214,208,_ZN4ksys3act20shouldSkipSpawnFairyERKN4sead14SafeStringBaseIcEE +0x0000007100ede2e4,PlacementMgr::setSomeGlobalPlacementFlags,180,_ZN4ksys3act31initSpawnConditionGameDataFlagsEv 0x0000007100ede398,act::hasAnyRevivalTag,328, 0x0000007100ede4e0,hasStopTimerMiddleTag,28, 0x0000007100ede4fc,hasStopTimerShortTag,28, diff --git a/src/KingSystem/ActorSystem/actActorUtil.cpp b/src/KingSystem/ActorSystem/actActorUtil.cpp index 98937a2d..f7e37ebe 100644 --- a/src/KingSystem/ActorSystem/actActorUtil.cpp +++ b/src/KingSystem/ActorSystem/actActorUtil.cpp @@ -4,16 +4,32 @@ #include "KingSystem/ActorSystem/actActorParam.h" #include "KingSystem/ActorSystem/actBaseProcLink.h" #include "KingSystem/ActorSystem/actInfoData.h" +#include "KingSystem/ActorSystem/actTag.h" +#include "KingSystem/GameData/gdtManager.h" +#include "KingSystem/Map/mapObject.h" +#include "KingSystem/Map/mapPlacementMgr.h" #include "KingSystem/Resource/resResourceActorLink.h" +#include "KingSystem/World/worldManager.h" namespace ksys::act { -static ActorConstDataAccess getAccessor(BaseProcLink* link) { +namespace { + +ActorConstDataAccess getAccessor(BaseProcLink* link) { ActorConstDataAccess accessor; acquireActor(link, &accessor); return accessor; } +const char* sArrowTypes[] = { + "NormalArrow", "BombArrow_A", "AncientArrow", "FireArrow", "IceArrow", "ElectricArrow", +}; +gdt::FlagHandle sAnimalMasterAppearanceHandle = gdt::InvalidHandle; +gdt::FlagHandle sFairyCountCheckHandle = gdt::InvalidHandle; +gdt::FlagHandle sIsGetStopTimerLv2Handle = gdt::InvalidHandle; + +} // namespace + bool hasTag(Actor* actor, const sead::SafeString& tag) { if (!actor) return false; @@ -70,7 +86,7 @@ bool hasOneTagAtLeast(BaseProcLink* link, const sead::SafeString& tags) { return false; } -bool act::hasOneTagAtLeast(const ActorConstDataAccess& accessor, const sead::SafeString& tags) { +bool hasOneTagAtLeast(const ActorConstDataAccess& accessor, const sead::SafeString& tags) { sead::FixedSafeString<32> tag; for (auto it = tags.tokenBegin(","); tags.tokenEnd(",") != it; ++it) { it.get(&tag); @@ -80,4 +96,68 @@ bool act::hasOneTagAtLeast(const ActorConstDataAccess& accessor, const sead::Saf return false; } +// NON_MATCHING: this version doesn't have unnecessary register moves. +bool shouldSkipSpawnWhenRaining(map::Object* obj) { + if (obj->getFlags().isOff(map::Object::Flag::CreateNotRain)) + return false; + + if (!world::Manager::instance()) + return false; + + const auto pos = obj->getTranslate(); + return !world::Manager::instance()->isRaining(pos); +} + +bool shouldSkipSpawnIfGodForestOff(map::Object* obj) { + bool value = false; + if (obj->getFlags().isOff(map::Object::Flag::UnderGodForestOff)) + return false; + if (!gdt::Manager::instance()->getBool(sAnimalMasterAppearanceHandle, &value, true)) + return false; + return value != 0; +} + +bool shouldSkipSpawnGodForestActor(map::Object* obj) { + bool value = false; + if (obj->getFlags().isOn(map::Object::Flag::UnderGodForest) && + gdt::Manager::instance()->getBool(sAnimalMasterAppearanceHandle, &value, true) && !value) { + return true; + } + return shouldSkipSpawnIfGodForestOff(obj); +} + +static bool isFairyCountCheckEnabled() { + bool value = false; + return gdt::Manager::instance()->getBool(sFairyCountCheckHandle, &value, true) && value; +} + +bool shouldSkipSpawnFairy(map::Object* obj) { + const map::ActorData& actor_data = obj->getActorData(); + if (!actor_data.mFlags.isOnBit(map::ActorData::Flag::Fairy)) + return false; + + return isFairyCountCheckEnabled(); +} + +bool shouldSkipSpawnFairy(const sead::SafeString& actor) { + auto* info = InfoData::instance(); + if (!info || !info->hasTag(actor.cstr(), tags::Fairy)) + return false; + + return isFairyCountCheckEnabled(); +} + +void initSpawnConditionGameDataFlags() { + sFairyCountCheckHandle = gdt::Manager::instance()->getBoolHandle("FairyCountCheck"); + sAnimalMasterAppearanceHandle = + gdt::Manager::instance()->getBoolHandle("AnimalMaster_Appearance"); + sIsGetStopTimerLv2Handle = gdt::Manager::instance()->getBoolHandle("IsGet_Obj_StopTimerLv2"); +} + +// TODO: remove this once IsGetStopTimerLv2 is used +// The only purpose of this function is to prevent sIsGetStopTimerLv2Handle from being optimized out +auto initSpawnConditionGameDataFlags_dummy() { + return sIsGetStopTimerLv2Handle; +} + } // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actActorUtil.h b/src/KingSystem/ActorSystem/actActorUtil.h index 73f329d5..1841c55f 100644 --- a/src/KingSystem/ActorSystem/actActorUtil.h +++ b/src/KingSystem/ActorSystem/actActorUtil.h @@ -60,13 +60,13 @@ bool hasOneTagAtLeast(Actor* actor, const sead::SafeString& tags); bool hasOneTagAtLeast(BaseProcLink* link, const sead::SafeString& tags); bool hasOneTagAtLeast(const ActorConstDataAccess& accessor, const sead::SafeString& tags); -bool shouldSkipSpawnForWeatherReasons(map::Object* obj); -bool isAnimalMasterAppearance(map::Object* obj); +bool shouldSkipSpawnWhenRaining(map::Object* obj); +bool shouldSkipSpawnIfGodForestOff(map::Object* obj); bool shouldSkipSpawnGodForestActor(map::Object* obj); bool shouldSkipSpawnFairy(map::Object* obj); bool shouldSkipSpawnFairy(const sead::SafeString& actor); -/// Must be called before using any of the "should skip" functions above + isAnimalMasterAppearance. +/// Must be called before using any of the "should skip" functions above. void initSpawnConditionGameDataFlags(); bool hasAnyRevivalTag(const sead::SafeString& actor); diff --git a/src/KingSystem/GameData/gdtManager.h b/src/KingSystem/GameData/gdtManager.h index 7dca62ce..26f93fbb 100644 --- a/src/KingSystem/GameData/gdtManager.h +++ b/src/KingSystem/GameData/gdtManager.h @@ -266,16 +266,14 @@ public: #undef GDT_GET_HANDLE_ #define GDT_GET_(NAME, T) \ - void NAME(FlagHandle handle, T* value, bool debug = false) { \ - unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ - ref.get().NAME(value, idx); \ - return true; \ + bool NAME(FlagHandle handle, T* value, bool debug = false) { \ + return unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ + return ref.get().NAME(value, idx); \ }); \ } \ - void NAME(FlagHandle handle, T* value, s32 sub_idx, bool debug = false) { \ - unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ - ref.get().NAME(value, idx, sub_idx); \ - return true; \ + bool NAME(FlagHandle handle, T* value, s32 sub_idx, bool debug = false) { \ + return unwrapHandle(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \ + return ref.get().NAME(value, idx, sub_idx); \ }); \ } diff --git a/src/KingSystem/Map/mapObject.h b/src/KingSystem/Map/mapObject.h index 3f62b226..0640d0d1 100644 --- a/src/KingSystem/Map/mapObject.h +++ b/src/KingSystem/Map/mapObject.h @@ -148,6 +148,10 @@ public: auto getId() const { return mId; } auto getStaticCompoundId() const { return mStaticCompoundId; } + const ActorData& getActorData() const { + return PlacementMgr::instance()->mPlacementActors->mActorData[mActorDataIdx]; + } + u8 getNumLinksPointingToMe() const { return mNumLinksPointingToMe; } const MubinIter& getMubinIter() const { return mMubinIter; } diff --git a/src/KingSystem/World/worldManager.h b/src/KingSystem/World/worldManager.h index ca0a2e98..45ede28d 100644 --- a/src/KingSystem/World/worldManager.h +++ b/src/KingSystem/World/worldManager.h @@ -43,7 +43,12 @@ public: // FIXME: incomplete class Manager : public sead::hostio::Node { + SEAD_SINGLETON_DISPOSER(Manager) Manager(); + virtual ~Manager(); + +public: + bool isRaining(const sead::Vector3f& pos) const; WorldInfo mWorldInfo; DungeonEnv mDungeonEnv;