summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2022-02-07 00:27:23 +0100
committerGitHub <noreply@github.com>2022-02-07 00:27:23 +0100
commit0e00e340eece6ccf9507da1e3476b3db60f6cc10 (patch)
tree45221220658b3051bb88b8392471607a0c34e3fa /src
parent0b5693c100b8643400fa8776f1a29be1bb4547a9 (diff)
parent199c7d25526c2852a4b4a2bc4fb18a0fd2db6ad5 (diff)
Merge pull request #81 from ThePixelGamer/PlacementStruct
PlacementStruct1
Diffstat (limited to 'src')
-rw-r--r--src/KingSystem/ActorSystem/LOD/actLodState.cpp5
-rw-r--r--src/KingSystem/Map/CMakeLists.txt2
-rw-r--r--src/KingSystem/Map/mapLazyTraverseList.h2
-rw-r--r--src/KingSystem/Map/mapPlacementActors.h10
-rw-r--r--src/KingSystem/Map/mapPlacementAreaMgr.cpp640
-rw-r--r--src/KingSystem/Map/mapPlacementAreaMgr.h244
-rw-r--r--src/KingSystem/Map/mapStagePreActorCache.h5
-rw-r--r--src/KingSystem/Utils/MathUtil.h12
8 files changed, 910 insertions, 10 deletions
diff --git a/src/KingSystem/ActorSystem/LOD/actLodState.cpp b/src/KingSystem/ActorSystem/LOD/actLodState.cpp
index 3dff3e29..03f01885 100644
--- a/src/KingSystem/ActorSystem/LOD/actLodState.cpp
+++ b/src/KingSystem/ActorSystem/LOD/actLodState.cpp
@@ -3,6 +3,7 @@
#include "KingSystem/ActorSystem/actActorParam.h"
#include "KingSystem/ActorSystem/actActorUtil.h"
#include "KingSystem/Map/mapObject.h"
+#include "KingSystem/Map/mapPlacementAreaMgr.h"
#include "KingSystem/Map/mapPlacementMgr.h"
#include "KingSystem/Resource/Actor/resResourceLod.h"
#include "KingSystem/System/OcclusionQueryCylinder.h"
@@ -156,10 +157,10 @@ LodState::LodState(sead::Heap* heap, sead::BitFlag32 flags, Actor* actor,
}
auto* pm = map::PlacementMgr::instance();
- map::PlacementStruct1* ps1 = nullptr;
+ map::PlacementAreaMgr* ps1 = nullptr;
if (pm && pm->mPlacementActors && (ps1 = pm->mPlacementActors->mStruct1)) {
if (!ps1->mIsOneHitChallengeActive) {
- if (ps1->mFlags.isOnBit(15)) {
+ if (ps1->mFlags.isOn(map::PlacementAreaMgr::Flag::FinalTrial)) {
if (actor->getName() == "DgnObj_DLC_IbutsuEx_Candle_A_01" ||
actor->getName() == "TBox_Dungeon_Stone" ||
actor->getName() == "DgnObj_DLC_SwordLight_A_01") {
diff --git a/src/KingSystem/Map/CMakeLists.txt b/src/KingSystem/Map/CMakeLists.txt
index 4c612d59..b201b701 100644
--- a/src/KingSystem/Map/CMakeLists.txt
+++ b/src/KingSystem/Map/CMakeLists.txt
@@ -14,6 +14,8 @@ target_sources(uking PRIVATE
mapObjectLink.h
mapPlacementActors.cpp
mapPlacementActors.h
+ mapPlacementAreaMgr.cpp
+ mapPlacementAreaMgr.h
mapPlacementMap.cpp
mapPlacementMap.h
mapPlacementMapMgr.cpp
diff --git a/src/KingSystem/Map/mapLazyTraverseList.h b/src/KingSystem/Map/mapLazyTraverseList.h
index 12afcd7e..99bb6dd4 100644
--- a/src/KingSystem/Map/mapLazyTraverseList.h
+++ b/src/KingSystem/Map/mapLazyTraverseList.h
@@ -15,6 +15,8 @@ public:
void updateFlags();
bool wereFlagsUpdated();
+ bool empty() const { return !mHasEntries; }
+
private:
struct Entry {
sead::FixedSafeString<0x40> flag_name;
diff --git a/src/KingSystem/Map/mapPlacementActors.h b/src/KingSystem/Map/mapPlacementActors.h
index 0f34a16e..8479eaed 100644
--- a/src/KingSystem/Map/mapPlacementActors.h
+++ b/src/KingSystem/Map/mapPlacementActors.h
@@ -13,6 +13,7 @@ namespace ksys::map {
class Object;
class PlacementMap;
+class PlacementAreaMgr;
// TODO: rename
enum class ActorFlag8 {
@@ -103,13 +104,6 @@ public:
};
KSYS_CHECK_SIZE_NX150(ActorData, 0x1A0);
-// FIXME: incomplete
-class PlacementStruct1 {
-public:
- sead::BitFlag16 mFlags;
- bool mIsOneHitChallengeActive;
-};
-
class PlacementActors {
public:
u32 getNumStaticObjs() const;
@@ -124,7 +118,7 @@ public:
u8 _0[0x28 - 0x0];
sead::ReadWriteLock mLock;
- PlacementStruct1* mStruct1;
+ PlacementAreaMgr* mStruct1;
u8 _e8[0x538 - 0xe8];
sead::SafeArray<ActorData, 6000> mActorData;
u8 _261b38[0x2a8058 - 0x261b38];
diff --git a/src/KingSystem/Map/mapPlacementAreaMgr.cpp b/src/KingSystem/Map/mapPlacementAreaMgr.cpp
new file mode 100644
index 00000000..295e5bfd
--- /dev/null
+++ b/src/KingSystem/Map/mapPlacementAreaMgr.cpp
@@ -0,0 +1,640 @@
+#include "KingSystem/Map/mapPlacementAreaMgr.h"
+
+#include "KingSystem/Map/mapLazyTraverseList.h"
+#include "KingSystem/Map/mapMubinIter.h"
+#include "KingSystem/Map/mapObject.h"
+#include "KingSystem/Map/mapObjectLink.h"
+#include "KingSystem/Utils/MathUtil.h"
+
+#include <math/seadMatrix.h>
+
+namespace ksys::map {
+
+static s32 s_npc_count = 0;
+
+enum class UnkFlag : u8 {
+ _1 = 1 << 0,
+ _2 = 1 << 1,
+ _4 = 1 << 2,
+ _20 = 1 << 5,
+ _40 = 1 << 6,
+ _80 = 1 << 7
+};
+static sead::TypedBitFlag<UnkFlag> s_unk_flag;
+
+static sead::SafeArray<float, 26> s_npc_scales = {
+ {0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.85f, 0.6f, 0.75f, 0.6f, 0.6f, 0.6f, 0.6f,
+ 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.75f, 0.6f, 0.6f}};
+
+// NON_MATCHING: weird memsets, hard to replicate
+PlacementAreaMgr::PlacementAreaMgr() {
+ mInnerHideCount = 0;
+ mPlayerPos = sead::Vector3f::zero;
+ mActiveNpc = 0;
+
+ if (mObjects && !mObjects->empty()) {
+ s_unk_flag.set(UnkFlag::_80);
+ }
+
+ mJudgeAreaCount = 0;
+ _2a468Count = 0;
+ mGeneralAreasCount = 0;
+ _2d5c4 = 0.0f;
+ mOptAreasCount = 0;
+ mFarModelsCount = 0;
+ mIntroArea = nullptr;
+ mFlags.set(Flag::_10);
+}
+
+PlacementAreaMgr::~PlacementAreaMgr() {
+ s_npc_count = 0;
+}
+
+// NON_MATCHING: many various parts don't match but should be a template
+bool PlacementAreaMgr::parseAreas(const sead::SafeString& unit_config_name,
+ const MubinIter& obj_iter) {
+ if (unit_config_name == "AreaCulling_InnerHide") {
+ auto& area = mInnerHide[mInnerHideCount++];
+ SRT srt;
+ obj_iter.getSRT(&srt);
+
+ bool hide = true;
+ obj_iter.tryGetParamBoolByKey(&hide, "HideOutSide");
+ area.params.hide_out_side = hide;
+
+ s32 culling = 0;
+ obj_iter.tryGetIntByKey(&culling, "CullingOption");
+ switch (static_cast<Unknown1::CullingOption>(culling)) {
+ case Unknown1::CullingOption::_0:
+ area.params.culling = Unknown1::CullingType::None;
+ break;
+ case Unknown1::CullingOption::_1:
+ area.params.culling = Unknown1::CullingType::Culling_1;
+ break;
+ case Unknown1::CullingOption::_2:
+ area.params.culling = Unknown1::CullingType::Culling_3;
+ break;
+ case Unknown1::CullingOption::_3:
+ area.params.culling = Unknown1::CullingType::Culling_F;
+ break;
+ case Unknown1::CullingOption::_4:
+ area.params.culling = Unknown1::CullingType::Culling_1F;
+ break;
+ case Unknown1::CullingOption::_5:
+ area.params.culling = Unknown1::CullingType::Culling_33;
+ break;
+ case Unknown1::CullingOption::_6:
+ area.params.culling = Unknown1::CullingType::Culling_3B;
+ break;
+ case Unknown1::CullingOption::_7:
+ area.params.culling = Unknown1::CullingType::Culling_1B;
+ break;
+ case Unknown1::CullingOption::_8:
+ area.params.culling = Unknown1::CullingType::Culling_18;
+ break;
+ case Unknown1::CullingOption::_9:
+ area.params.culling = Unknown1::CullingType::Culling_10;
+ break;
+ case Unknown1::CullingOption::_A:
+ area.params.culling = Unknown1::CullingType::Culling_13;
+ break;
+ case Unknown1::CullingOption::_B:
+ area.params.culling = Unknown1::CullingType::Culling_43;
+ break;
+ case Unknown1::CullingOption::_C:
+ area.params.culling = Unknown1::CullingType::Culling_9B;
+ break;
+
+ default:
+ break;
+ }
+
+ bool connect;
+ obj_iter.tryGetBoolByKey(&connect, "IsConnectNeighborArea");
+ area.params.is_connect_neighbor_area = connect;
+
+ area.hide_room_num = 0xFF;
+ obj_iter.tryGetParamUInt8ByKey(&area.hide_room_num, "HideRoomNum");
+
+ bool weirdCheck = false;
+ // is this some sort of hack?
+ if (srt.translate.x > -440.0f && srt.translate.x < -436.0f && srt.translate.z > -1036.0f &&
+ srt.translate.z < -1032.0f) {
+ srt.scale.x = 27.863f;
+ srt.translate.x = -439.24f;
+ weirdCheck = true;
+ srt.translate.z = -1033.4f;
+ srt.scale.z = 40.908f;
+ }
+
+ area.translate = srt.translate;
+
+ float scale = sead::Mathf::max3(srt.scale.x, srt.scale.y, srt.scale.z); // same logic
+
+ float calcMaxSize = sead::Mathf::max(scale * 0.5f, 4.0f);
+ float calcXPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcXPlus, "CalcMarginXPlus");
+ float calcXMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcXMinus, "CalcMarginXMinus");
+ float calcYPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcYPlus, "CalcMarginYPlus");
+ float calcYMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcYMinus, "CalcMarginYMinus");
+ float calcZPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcZPlus, "CalcMarginZPlus");
+ float calcZMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&calcZMinus, "CalcMarginZMinus");
+
+ if (weirdCheck) {
+ calcXMinus = 3.0f;
+ }
+
+ if (calcXPlus < 0.0f) {
+ calcXPlus = calcMaxSize;
+ }
+ if (calcXMinus < 0.0f) {
+ calcXMinus = calcMaxSize;
+ }
+ if (calcYPlus < 0.0f) {
+ calcYPlus = calcMaxSize;
+ }
+ if (calcYMinus < 0.0f) {
+ calcYMinus = calcMaxSize;
+ }
+ if (calcZPlus < 0.0f) {
+ calcZPlus = calcMaxSize;
+ }
+ if (calcZMinus < 0.0f) {
+ calcZMinus = calcMaxSize;
+ }
+
+ float loadMaxSize = calcMaxSize * 1.75f;
+ float loadXPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadXPlus, "LoadMarginXPlus");
+ float loadXMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadXMinus, "LoadMarginXMinus");
+ float loadYPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadYPlus, "LoadMarginYPlus");
+ float loadYMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadYMinus, "LoadMarginYMinus");
+ float loadZPlus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadZPlus, "LoadMarginZPlus");
+ float loadZMinus = -1.0f;
+ obj_iter.tryGetParamFloatByKey(&loadZMinus, "LoadMarginZMinus");
+
+ if (loadXPlus < 0.0f) {
+ loadXPlus = loadMaxSize;
+ }
+ if (loadXMinus < 0.0f) {
+ loadXMinus = loadMaxSize;
+ }
+ if (loadYPlus < 0.0f) {
+ loadYPlus = loadMaxSize;
+ }
+ if (loadYMinus < 0.0f) {
+ loadYMinus = loadMaxSize;
+ }
+ if (loadZPlus < 0.0f) {
+ loadZPlus = loadMaxSize;
+ }
+ if (loadZMinus < 0.0f) {
+ loadZMinus = loadMaxSize;
+ }
+
+ // same code in AreaCulling_TwinsHide
+ area.base = Axis{srt.scale};
+ area.calc = Axis{srt.scale + sead::Vector3f{calcXPlus, calcYPlus, calcZPlus},
+ srt.scale + sead::Vector3f{calcXMinus, calcYMinus, calcZMinus}};
+ area.load = Axis{srt.scale + sead::Vector3f{loadXPlus, loadYPlus, loadZPlus},
+ srt.scale + sead::Vector3f{loadXMinus, loadYMinus, loadZMinus}};
+ area._d8 = Axis{-sead::Vector3f::ones};
+
+ sead::Matrix33f m;
+ m.makeR(srt.rotate);
+
+ for (size_t i = 0; i < 6; ++i) {
+ area.base[i] = srt.translate + (m * area.base[i]);
+ area.calc[i] = srt.translate + (m * area.calc[i]);
+ area.load[i] = srt.translate + (m * area.load[i]);
+ area._d8[i] = m * area._d8[i];
+ }
+
+ return true;
+ } else if (unit_config_name == "AreaCulling_OuterNPCMementary") {
+ if (s_npc_count > 25) { // this if statement has ++ but this structure makes more sense
+ return true;
+ }
+
+ auto& area = mNpc[s_npc_count++];
+ SRT srt;
+
+ obj_iter.getSRT(&srt);
+ area.translate = srt.translate;
+ area.scale = srt.scale.x;
+ return true;
+ } else if (unit_config_name.include("AreaCulling_TwinsHide")) { // no objects
+ Unknown1* area;
+ if (unit_config_name.include("Alpha")) {
+ area = &mAlpha; // 2980C
+ } else if (unit_config_name.include("Omega")) {
+ area = &mOmega; // 29958
+ } else {
+ return true;
+ }
+
+ SRT srt;
+ obj_iter.getSRT(&srt);
+ area->translate = srt.translate;
+
+ area->base = Axis{srt.scale};
+ area->calc = Axis{srt.scale};
+ area->load = Axis{-sead::Vector3f::ones};
+ area->_d8 = Axis{-sead::Vector3f::ones};
+
+ sead::Matrix33f m;
+ m.makeR(srt.rotate);
+
+ for (size_t i = 0; i < 6; ++i) {
+ area->base[i] = srt.translate + (m * area->base[i]);
+ area->calc[i] = srt.translate + (m * area->calc[i]);
+ area->load[i] = srt.translate + (m * area->load[i]);
+ area->_d8[i] = m * area->_d8[i];
+ }
+
+ s_unk_flag.set(UnkFlag::_40);
+ return true;
+ } else if (unit_config_name == "AreaCulling_JudgeArea") { // no objects
+ SRT srt;
+ auto& area = mJudgeArea[mJudgeAreaCount++];
+
+ obj_iter.getSRT(&srt);
+ area.bb.set(srt.translate - srt.scale, srt.translate + srt.scale);
+
+ MubinIter links;
+ if (!obj_iter.tryGetParamIterByKey(&links, "LinksToObj")) {
+ return true;
+ }
+
+ for (int i = 0; i < links.getSize(); ++i) {
+ MubinIter iter;
+ if (links.tryGetIterByIndex(&iter, i)) {
+ u32 _id = 0;
+ if (iter.tryGetParamUIntByKey(&_id, "DestUnitHashId")) {
+ area.parent_ids[area.parent_count++] = _id;
+ }
+ }
+ }
+
+ return true;
+ } else if (unit_config_name.include("AreaCulling_")) { // only InnerOn?
+ auto& area = mGeneralAreas[mGeneralAreasCount++];
+ SRT srt;
+
+ obj_iter.getSRT(&srt);
+ area.bb.set(srt.translate - srt.scale, srt.translate + srt.scale);
+ obj_iter.tryGetParamUIntByKey(&area.id, "HashId");
+
+ area.type = GeneralArea::Type::None;
+
+ const char* param = nullptr;
+ if (obj_iter.tryGetParamStringByKey(&param, "UniqueName")) {
+ if (sead::SafeString(param) == "LoadOpt") {
+ area.type = GeneralArea::Type::LoadOpt;
+ }
+ }
+
+ if (area.type == GeneralArea::Type::LoadOpt) {
+ auto& subArea = mOptAreas[mOptAreasCount++];
+ subArea.parent_area = &area;
+ subArea.id = "Demo102_0";
+ } else {
+ auto& subArea = mJudgeArea[mJudgeAreaCount++];
+ sead::Vector3f offset{20.0f, 0.0f, 20.0f};
+ subArea.bb.set(srt.translate - srt.scale - offset, srt.translate + srt.scale + offset);
+ subArea.parent_ids[subArea.parent_count++] = 0;
+ subArea.parent_areas[0] = &area;
+ }
+
+ return true;
+ } else if (unit_config_name == "FarModelCullingArea") {
+ auto& area = mFarModels[mFarModelsCount++];
+ SRT srt;
+
+ obj_iter.getSRT(&srt);
+ area.translate = srt.translate;
+ area.rotate = srt.rotate;
+ area.scale = srt.scale;
+ area.id.format("Area_%04d", mFarModels.size() - 1);
+
+ return true;
+ }
+
+ return false;
+}
+
+PlacementAreaMgr::GeneralArea* PlacementAreaMgr::findGeneralArea(const u32& id) {
+ for (int i = 0; i < mGeneralAreasCount; i++) {
+ if (mGeneralAreas[i].id == id) {
+ return &mGeneralAreas[i];
+ }
+ }
+
+ return nullptr;
+}
+
+// NON_MATCHING: stack doesn't match, not sure if that's due to the first loop
+void PlacementAreaMgr::x() {
+ s_unk_flag.set(UnkFlag::_20);
+ s_unk_flag.set(UnkFlag::_4);
+ s_unk_flag.set(UnkFlag::_2);
+ s_unk_flag.set(UnkFlag::_1);
+
+ for (int i = 0; i < mInnerHideCount; i++) {
+ auto& area = mInnerHide[i];
+
+ area._12c = isInsideNpcIdx(area.translate);
+ area._130_count = 0;
+ }
+
+ for (int i = 0; i < mInnerHideCount; i++) {
+ auto& area = mInnerHide[i];
+
+ if (area.hide_room_num == 0xFF) {
+ continue;
+ }
+
+ for (int j = 0; j < mInnerHideCount; j++) {
+ auto& subarea = mInnerHide[j];
+
+ if (i != j) {
+ if (subarea.hide_room_num != 0xFF && area._12c == subarea._12c &&
+ area.hide_room_num == subarea.hide_room_num) {
+ area._130[area._130_count++] = j;
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < mInnerHideCount; i++) {
+ auto& area = mInnerHide[i];
+
+ if (area.params.is_connect_neighbor_area) {
+ for (int j = 0; j < mInnerHideCount; j++) {
+ auto& subarea = mInnerHide[j];
+
+ if (subarea.params.is_connect_neighbor_area && i != j) {
+ if (area._12c == subarea._12c && (x_0(i, j) || x_0(j, i))) {
+ addLinkPair(i, j);
+ }
+ }
+ }
+ }
+ }
+
+ mAlpha._12c = -1;
+ mOmega._12c = -1;
+ for (int i = 0; i < mJudgeAreaCount; i++) {
+ auto& judgeArea = mJudgeArea[i];
+ for (int j = 0; j < judgeArea.parent_count; j++) {
+ auto& id = judgeArea.parent_ids[j];
+
+ if (id == 0) {
+ continue;
+ }
+
+ // doesn't necessarily exist, done to try and match
+ judgeArea.parent_areas[j] = findGeneralArea(id);
+ }
+ }
+}
+
+void PlacementAreaMgr::Unknown1::addLink(const int& idx) {
+ if (_130_count == 0) {
+ _130[_130_count++] = idx;
+ } else {
+ // check to see if idx is in _130, add to end if not
+ for (u8 i = 0; i < _130_count && _130[i] != idx; i++) {
+ if (i == (_130_count - 1)) {
+ _130[_130_count++] = idx;
+ break;
+ }
+ }
+
+ // weird logic because this would only trigger if _130_count was 6 in the loop
+ if ((_130_count - 1) >= _130.size()) {
+ --_130_count;
+ }
+ }
+}
+
+void PlacementAreaMgr::addLinkPair(const int& idx, const int& sub_idx) {
+ mInnerHide[idx].addLink(sub_idx);
+ mInnerHide[sub_idx].addLink(idx);
+}
+
+bool PlacementAreaMgr::insideInnerHideTrans(const int& idx) {
+ if (mActiveNpc != mInnerHide[idx]._12c) {
+ return util::sqXZDistance(mPlayerPos, mInnerHide[idx].translate) <
+ sead::Mathf::square(1000.0f);
+ }
+
+ if (mActiveNpc == 5)
+ return true;
+
+ if (mActiveNpc == 6) {
+ return util::sqXZDistance(mPlayerPos, mInnerHide[idx].translate) <
+ sead::Mathf::square(500.0f);
+ }
+
+ if (mFlags.isOn(Flag::FinalTrial) || mFlags.isOn(Flag::_4000)) {
+ return true;
+ }
+
+ if (mFlags.isOff(Flag::Remains)) {
+ if (mFlags.isOn(Flag::AocField)) {
+ return true;
+ }
+
+ if (mActiveNpc != 21 && mActiveNpc != 16 && mActiveNpc != 14 && mActiveNpc != 7 &&
+ mActiveNpc != 2 && mActiveNpc != 0) {
+ return util::sqXZDistance(mPlayerPos, mInnerHide[idx].translate) <
+ sead::Mathf::square(200.0f);
+ }
+ }
+
+ return util::sqXZDistance(mPlayerPos, mInnerHide[idx].translate) < sead::Mathf::square(500.0f);
+}
+
+bool PlacementAreaMgr::insideInnerHideBase(const int& idx) {
+ for (int i = 0; i < 6; i++) {
+ if ((mPlayerPos - mInnerHide[idx].base[i]).dot(mInnerHide[idx]._d8[i]) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideInnerHideCalc(const int& idx) {
+ for (int i = 0; i < 6; i++) {
+ if ((mPlayerPos - mInnerHide[idx].calc[i]).dot(mInnerHide[idx]._d8[i]) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideInnerHideLoad(const int& idx) {
+ for (int i = 0; i < 6; i++) {
+ if ((mPlayerPos - mInnerHide[idx].load[i]).dot(mInnerHide[idx]._d8[i]) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideInnerHideBase(const sead::Vector3f& pos, const float& dist_from_face,
+ const int& idx) {
+ for (int i = 0; i < 6; i++) {
+ if ((pos - mInnerHide[idx].base[i]).dot(mInnerHide[idx]._d8[i]) <= dist_from_face) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideInnerHideCalc(const sead::Vector3f& pos, const float& dist_from_face,
+ const int& idx) {
+ for (int i = 0; i < 6; i++) {
+ if ((pos - mInnerHide[idx].calc[i]).dot(mInnerHide[idx]._d8[i]) <= dist_from_face) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideAlphaBase() {
+ for (int i = 0; i < 6; i++) {
+ if ((mPlayerPos - mAlpha.base[i]).dot(mAlpha._d8[i]) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideAlphaBase(const sead::Vector3f& pos, const float& dist_from_face) {
+ for (int i = 0; i < 6; i++) {
+ if ((pos - mAlpha.base[i]).dot(mAlpha._d8[i]) < dist_from_face) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideOmegaBase() {
+ for (int i = 0; i < 6; i++) {
+ if ((mPlayerPos - mOmega.base[i]).dot(mOmega._d8[i]) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::insideOmegaBase(const sead::Vector3f& pos, const float& dist_from_face) {
+ for (int i = 0; i < 6; i++) {
+ if ((pos - mOmega.base[i]).dot(mOmega._d8[i]) < dist_from_face) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlacementAreaMgr::isPlayerInsideNpc(const sead::Vector3f& pos) {
+ // matches with 2 && but this looks cleaner
+ if (mActiveNpc >= 0 && !isInsideNpc(pos)) {
+ if (util::sqXZDistance(mPlayerPos, mNpc[mActiveNpc].translate) <
+ (mNpc[mActiveNpc].scale * s_npc_scales[mActiveNpc])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// used to try and simplify PlacementAreaMgr::x and PlacementAreaMgr::isInsideNpc logic
+// doesn't seem to match so maybe remove after matching x?
+s8 PlacementAreaMgr::isInsideNpcIdx(const sead::Vector3f& pos) {
+ for (int i = 0; i < mNpc.size(); i++) {
+ if (!mNpc[i].isInside(pos)) {
+ continue;
+ }
+
+ if (i == 5) {
+ if (mNpc[6].isInside(pos)) {
+ continue;
+ }
+ }
+
+ return i;
+ }
+
+ return -1;
+}
+
+bool PlacementAreaMgr::isInsideNpc(const sead::Vector3f& pos) {
+ if (s_unk_flag.isOff(UnkFlag::_4)) {
+ return false;
+ }
+
+ // XXX: what the heck Nintendo
+ int i = 0;
+ while (i < mNpc.size()) {
+ if (i == 5) {
+ if (mNpc[i].isInside(pos) && !mNpc[i + 1].isInside(pos)) {
+ return true;
+ }
+ } else {
+ if (mNpc[i].isInside(pos)) {
+ return true;
+ }
+ }
+
+ ++i;
+ }
+
+ return false;
+}
+
+void PlacementAreaMgr::loadDemoCulling(const sead::SafeString& demo_name) {
+ mIntroArea = nullptr;
+
+ for (int i = 0; i < mOptAreasCount; ++i) {
+ auto& area = mOptAreas[i];
+
+ bool loaded = false;
+ if (area.id == demo_name) {
+ loaded = true;
+ mIntroArea = &area;
+ }
+ area.parent_area->loaded = loaded;
+ }
+}
+
+void PlacementAreaMgr::unloadDemoCulling() {
+ mIntroArea = nullptr;
+
+ for (int i = 0; i < mOptAreasCount; ++i) {
+ mOptAreas[i].parent_area->loaded = false;
+ }
+}
+
+} // namespace ksys::map \ No newline at end of file
diff --git a/src/KingSystem/Map/mapPlacementAreaMgr.h b/src/KingSystem/Map/mapPlacementAreaMgr.h
new file mode 100644
index 00000000..17ddd0ad
--- /dev/null
+++ b/src/KingSystem/Map/mapPlacementAreaMgr.h
@@ -0,0 +1,244 @@
+#pragma once
+
+#include <container/seadSafeArray.h>
+#include <math/seadBoundBox.h>
+#include <math/seadVector.h>
+#include <prim/seadSafeString.h>
+#include <prim/seadTypedBitFlag.h>
+
+#include "KingSystem/Map/mapStagePreActorCache.h"
+#include "KingSystem/Map/mapTypes.h"
+#include "KingSystem/Utils/Types.h"
+
+namespace ksys::gdt {
+class Manager;
+}
+
+namespace ksys::map {
+
+class LazyTraverseList;
+class MubinIter;
+class Object;
+
+class PlacementAreaMgr {
+ // not "Axis" and probably not in this class but I dunno what it does
+ // contains + and - of each x, y, z as a vector
+ class Axis {
+ public:
+ Axis() = default;
+ explicit Axis(const sead::Vector3f& v) : Axis(v, v) {}
+
+ // parameter names only based on default values
+ Axis(const sead::Vector3f& plus, const sead::Vector3f& minus) {
+ data[0] = {0.0f - minus.x, 0.0f, 0.0f};
+ data[1] = {0.0f + plus.x, 0.0f, 0.0f};
+ data[2] = {0.0f, 0.0f, 0.0f - minus.z};
+ data[3] = {0.0f, 0.0f, 0.0f + plus.z};
+ data[4] = {0.0f, 0.0f - minus.y, 0.0f};
+ data[5] = {0.0f, 0.0f + plus.y, 0.0f};
+ }
+
+ // needs an assert
+ sead::Vector3f& operator[](size_t idx) { return data[idx]; }
+
+ const sead::Vector3f& operator[](size_t idx) const { return data[idx]; }
+
+ private:
+ sead::Vector3f data[6]{};
+ };
+
+ struct Unknown1 { // only params appears in PlacementAreaMgr's ctor
+ // unsure about these culling enums and the params bitfield
+ enum class CullingOption : s32 { _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _A, _B, _C };
+
+ enum class CullingType : u8 {
+ None,
+ Culling_1 = 1 << 0,
+ Culling_2 = 1 << 1,
+ Culling_4 = 1 << 2,
+ Culling_8 = 1 << 3,
+ Culling_10 = 1 << 4,
+ Culling_20 = 1 << 5,
+ Culling_40 = 1 << 6,
+ Culling_80 = 1 << 7,
+
+ Culling_3 = Culling_2 | Culling_1,
+ Culling_B = Culling_8 | Culling_3,
+ Culling_F = Culling_8 | Culling_4 | Culling_3,
+ Culling_13 = Culling_10 | Culling_3,
+ Culling_18 = Culling_10 | Culling_8,
+ Culling_1B = Culling_10 | Culling_B,
+ Culling_1F = Culling_10 | Culling_F,
+ Culling_30 = Culling_20 | Culling_10,
+ Culling_33 = Culling_30 | Culling_3,
+ Culling_3B = Culling_30 | Culling_B,
+ Culling_43 = Culling_40 | Culling_3,
+ Culling_9B = Culling_80 | Culling_1B,
+ };
+
+ Axis base{}, calc{}, load{}, _d8{};
+ sead::Vector3f translate{};
+ s8 _12c; // something to do with _29C54/mActiveNpc
+ u8 hide_room_num;
+ u8 _130_count;
+ sead::SafeArray<int, 6> _130{}; // used to index mInnerHide, parent idx?
+ struct Params { // _148 : u16
+ bool hide_out_side : 1;
+ bool is_connect_neighbor_area : 1;
+ bool _4 : 1;
+ bool _8 : 1;
+ bool _10 : 1;
+ bool _20 : 1;
+ CullingType culling : 8;
+ } params{};
+ KSYS_CHECK_SIZE_NX150(Params, 0x2);
+
+ // helpers
+ Unknown1() { memset(&params, 0, sizeof(params)); }
+
+ void addLink(const int& idx); // unsure about name
+ };
+ KSYS_CHECK_SIZE_NX150(Unknown1, 0x14C);
+
+ struct OuterNPCMementary {
+ sead::Vector3f translate;
+ f32 scale;
+
+ // should probably remove
+ bool isInside(const sead::Vector3f& pos) const {
+ return (pos - translate).squaredLength() < sead::Mathf::square(scale);
+ }
+ };
+ KSYS_CHECK_SIZE_NX150(OuterNPCMementary, 0x10);
+
+ struct GeneralArea { // InnerOn?
+ enum class Type : u8 { None = 0, LoadOpt = 2 };
+
+ sead::BoundBox3f bb{};
+ u32 id;
+ Type type;
+ bool loaded;
+ };
+ KSYS_CHECK_SIZE_NX150(GeneralArea, 0x20);
+
+ struct JudgeArea {
+ sead::BoundBox3f bb{};
+ sead::SafeArray<GeneralArea*, 8> parent_areas{};
+ sead::SafeArray<u32, 8> parent_ids{};
+ s32 parent_count = 0;
+ };
+ KSYS_CHECK_SIZE_NX150(JudgeArea, 0x80);
+
+ struct OptArea {
+ GeneralArea* parent_area;
+ sead::FixedSafeString<16> id{};
+ };
+ KSYS_CHECK_SIZE_NX150(OptArea, 0x30);
+
+ struct FarModel {
+ sead::Vector3f translate;
+ sead::Vector3f rotate;
+ sead::Vector3f scale;
+ sead::FixedSafeString<16> id{};
+ };
+ KSYS_CHECK_SIZE_NX150(FarModel, 0x50);
+
+public:
+ enum class Flag : u16 {
+ Remains = 1 << 0,
+ AocField = 1 << 1,
+ FireOrWindRemains = 1 << 2,
+ _8 = 1 << 3,
+ _10 = 1 << 4,
+ WindRelicFlag = 1 << 5,
+ FirstInCastleBossRoom = 1 << 6,
+ LastBoss = 1 << 7,
+ _100 = 1 << 8,
+ _200 = 1 << 9,
+ _400 = 1 << 10,
+ _800 = 1 << 11,
+ _1000 = 1 << 12,
+ _2000 = 1 << 13,
+ _4000 = 1 << 14,
+ FinalTrial = 1 << 15
+ };
+
+ // d1f4d8
+ static bool getIsPlayedDemo145AndFirstInCastleBossRoom(ksys::gdt::Manager& gdm,
+ bool* first_in_ganon_boss_room,
+ bool* played_demo_145);
+
+ // d1c8c0
+ PlacementAreaMgr();
+ ~PlacementAreaMgr();
+
+ // d1cecc
+ bool parseAreas(const sead::SafeString& unit_config_name, const MubinIter& obj_iter);
+ // d1e578
+ void x();
+ void addLinkPair(const int& idx, const int& sub_idx);
+ // d1eb24
+ void postPlaceActorsUpdateFlagsAndLazyTraverse();
+ bool insideInnerHideTrans(const int& idx);
+ bool insideInnerHideBase(const int& idx);
+ bool insideInnerHideCalc(const int& idx);
+ bool insideInnerHideLoad(const int& idx);
+ void loadDemoCulling(const sead::SafeString& demo_name);
+ void unloadDemoCulling();
+ // d1fe78
+ bool shouldSkipSpawnOneHitChallengeActor(const Object& obj);
+ // d20bcc
+ bool shouldSkipSpawn(const Object& obj, bool a3);
+ bool insideInnerHideBase(const sead::Vector3f& pos, const float& dist_from_face,
+ const int& idx);
+ bool isPlayerInsideNpc(const sead::Vector3f& pos);
+ // d21ddc
+ void boundsChecking();
+ bool insideInnerHideCalc(const sead::Vector3f& pos, const float& dist_from_face,
+ const int& idx);
+ bool insideAlphaBase(const sead::Vector3f& pos, const float& dist_from_face);
+ bool insideOmegaBase();
+ bool insideOmegaBase(const sead::Vector3f& pos, const float& dist_from_face);
+ bool insideAlphaBase();
+ // d231cc
+ void boundsChecking_1(); // looks eerily similar to boundsChecking
+ // d2388c
+ void weirdSetup(); // perhaps used with teleport feature?
+ bool isInsideNpc(const sead::Vector3f& pos);
+ // d24400
+ void pushFarModels();
+ // d2449c
+ bool x_0(const int& idx, const int& sub_idx);
+
+ s8 isInsideNpcIdx(const sead::Vector3f& pos);
+ GeneralArea* findGeneralArea(const u32& id);
+
+ sead::TypedBitFlag<Flag> mFlags;
+ bool mIsOneHitChallengeActive = false;
+ bool mNotAocField = false;
+ bool _4 = false;
+ sead::SafeArray<Unknown1, 512> mInnerHide{}; // parseObj
+ s32 mInnerHideCount;
+ Unknown1 mAlpha{}, mOmega{}; // parseObj
+ sead::SafeArray<OuterNPCMementary, 26> mNpc{};
+ sead::Vector3f mPlayerPos;
+ f32 mCameraAngleMaybe = 50.0f; // fov?
+ s32 mActiveNpc; // 0 - 25
+ LazyTraverseList* mObjects = StagePreActorCache::instance()->getObjects();
+ sead::SafeArray<JudgeArea, 16> mJudgeArea{};
+ s32 mJudgeAreaCount;
+ sead::SafeArray<char, 128> _2a468{}; // probably not char
+ s32 _2a468Count;
+ sead::SafeArray<GeneralArea, 64> mGeneralAreas{};
+ s32 mGeneralAreasCount;
+ sead::SafeArray<OptArea, 4> mOptAreas{};
+ s32 mOptAreasCount;
+ OptArea* mIntroArea;
+ sead::SafeArray<FarModel, 128> mFarModels{};
+ s32 mFarModelsCount;
+ f32 _2d5c4; // distance?
+ u8 _2d5c8 = 0; // enum potentially
+};
+KSYS_CHECK_SIZE_NX150(PlacementAreaMgr, 0x2D5D0);
+
+} // namespace ksys::map \ No newline at end of file
diff --git a/src/KingSystem/Map/mapStagePreActorCache.h b/src/KingSystem/Map/mapStagePreActorCache.h
index 7d87c958..666779e8 100644
--- a/src/KingSystem/Map/mapStagePreActorCache.h
+++ b/src/KingSystem/Map/mapStagePreActorCache.h
@@ -9,15 +9,20 @@ class ForestRenderer;
namespace ksys::map {
+class LazyTraverseList;
+
// TODO
class StagePreActorCache {
SEAD_SINGLETON_DISPOSER(StagePreActorCache)
StagePreActorCache();
public:
+ LazyTraverseList* getObjects() const { return mObjects; }
auto* getForestRenderer() { return mForestRenderer; }
private:
+ char _0[0x20];
+ LazyTraverseList* mObjects;
gfx::ForestRenderer* mForestRenderer;
};
diff --git a/src/KingSystem/Utils/MathUtil.h b/src/KingSystem/Utils/MathUtil.h
new file mode 100644
index 00000000..6ceb07f5
--- /dev/null
+++ b/src/KingSystem/Utils/MathUtil.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <math/seadVector.h>
+
+namespace ksys::util {
+
+// too specific for sead
+inline float sqXZDistance(const sead::Vector3f& a, const sead::Vector3f& b) {
+ return sead::Mathf::square(a.x - b.x) + sead::Mathf::square(a.z - b.z);
+}
+
+} // namespace ksys::util \ No newline at end of file