1#include "Library/Area/AreaObjUtil.h"
2
3#include "Library/Area/AreaObj.h"
4#include "Library/Area/AreaObjDirector.h"
5#include "Library/Area/AreaObjGroup.h"
6#include "Library/Area/AreaShape.h"
7#include "Library/Area/IUseAreaObj.h"
8#include "Library/Math/MathUtil.h"
9#include "Library/Placement/PlacementFunction.h"
10
11namespace al {
12AreaObj* tryFindAreaObj(const IUseAreaObj* areaUser, const char* name,
13 const sead::Vector3f& position) {
14 return areaUser->getAreaObjDirector()->getInVolumeAreaObj(name, position);
15}
16
17AreaObj* tryFindAreaObjWithFilter(const IUseAreaObj* areaUser, const char* name,
18 const sead::Vector3f& position, AreaObjFilterBase* filter) {
19 AreaObjGroup* areaObjGroup = tryFindAreaObjGroup(areaUser, name);
20 if (areaObjGroup == nullptr)
21 return nullptr;
22
23 AreaObj* currentAreaObj = nullptr;
24 s32 size = areaObjGroup->getSize();
25 for (s32 i = 0; i < size; i++) {
26 AreaObj* areaObj = areaObjGroup->getAreaObj(index: i);
27
28 if ((currentAreaObj == nullptr ||
29 currentAreaObj->getPriority() <= areaObj->getPriority()) &&
30 areaObj->isInVolume(pos: position) && filter->isValidArea(areaObj)) {
31 currentAreaObj = areaObj;
32 }
33 }
34
35 return currentAreaObj;
36}
37
38bool tryFindAreaObjAll(const IUseAreaObj* areaUser, const char* name,
39 const sead::Vector3f& position, AreaObjFindCallBack* callBack) {
40 AreaObjGroup* areaObjGroup = tryFindAreaObjGroup(areaUser, name);
41 if (areaObjGroup == nullptr)
42 return false;
43
44 bool foundAnyArea = false;
45 s32 size = areaObjGroup->getSize();
46 for (s32 i = 0; i < size; i++) {
47 AreaObj* areaObj = areaObjGroup->getAreaObj(index: i);
48
49 if (areaObj->isInVolume(pos: position)) {
50 callBack->findArea(areaObj);
51 foundAnyArea = true;
52 }
53 }
54
55 return foundAnyArea;
56}
57
58AreaObjGroup* tryFindAreaObjGroup(const IUseAreaObj* areaUser, const char* name) {
59 return areaUser->getAreaObjDirector()->getAreaObjGroup(name);
60}
61
62bool isInAreaObj(const AreaObjGroup* group, const sead::Vector3f& position) {
63 return tryGetAreaObj(group, position) != nullptr;
64}
65
66AreaObj* tryGetAreaObj(const AreaObjGroup* group, const sead::Vector3f& position) {
67 if (group == nullptr)
68 return nullptr;
69
70 return group->getInVolumeAreaObj(position);
71}
72
73bool isInAreaPos(const AreaObj* areaObj, const sead::Vector3f& position) {
74 return areaObj->isInVolume(pos: position);
75}
76
77bool isInAreaObj(const IUseAreaObj* areaUser, const char* name, const sead::Vector3f& position) {
78 return tryFindAreaObj(areaUser, name, position) != nullptr;
79}
80
81bool isExistAreaObj(const IUseAreaObj* areaUser, const char* name) {
82 return areaUser->getAreaObjDirector()->isExistAreaGroup(name);
83}
84
85bool isInDeathArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) {
86 return isInAreaObj(areaUser, name: "DeathArea", position);
87}
88
89bool isInWaterArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) {
90 return isInAreaObj(areaUser, name: "WaterArea", position);
91}
92
93bool isInPlayerControlOffArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) {
94 return isInAreaObj(areaUser, name: "PlayerControlOffArea", position);
95}
96
97s32 calcAreaObjNum(const IUseAreaObj* areaUser, const char* name) {
98 AreaObjGroup* group = tryFindAreaObjGroup(areaUser, name);
99 if (group == nullptr)
100 return 0;
101
102 return group->getSize();
103}
104
105f32 calcWaterSinkDepth(const IUseAreaObj* areaUser, const sead::Vector3f& position) {
106 AreaObj* areaObj = tryFindAreaObj(areaUser, name: "WaterArea", position);
107 if (!areaObj)
108 return -1.0f;
109
110 sead::Vector3f hitPosition;
111 sead::Vector3f normal;
112 sead::Vector3f position2 = {position.x, position.y + 100000.0f, position.z};
113
114 if (!checkAreaObjCollisionByArrow(outHitPosition: &hitPosition, outNormal: &normal, areaObj, position1: position, position2))
115 return -1.0f;
116
117 return hitPosition.y - position.y;
118}
119
120bool tryGetAreaObjArg(s32* outArg, const AreaObj* areaObj, const char* key) {
121 if (areaObj->getPlacementInfo() == nullptr)
122 return false;
123
124 return tryGetArg(arg: outArg, placementInfo: *areaObj->getPlacementInfo(), key);
125}
126
127bool tryGetAreaObjArg(f32* outArg, const AreaObj* areaObj, const char* key) {
128 if (areaObj->getPlacementInfo() == nullptr)
129 return false;
130
131 return tryGetArg(arg: outArg, placementInfo: *areaObj->getPlacementInfo(), key);
132}
133
134bool tryGetAreaObjArg(bool* outArg, const AreaObj* areaObj, const char* key) {
135 if (areaObj->getPlacementInfo() == nullptr)
136 return false;
137
138 return tryGetArg(arg: outArg, placementInfo: *areaObj->getPlacementInfo(), key);
139}
140
141bool tryGetAreaObjStringArg(const char** outArg, const AreaObj* areaObj, const char* key) {
142 if (areaObj->getPlacementInfo() == nullptr)
143 return false;
144
145 return tryGetStringArg(arg: outArg, initInfo: *areaObj->getPlacementInfo(), key);
146}
147
148const sead::Matrix34f& getAreaObjBaseMtx(const AreaObj* areaObj) {
149 return areaObj->getAreaMtx();
150}
151
152const sead::Vector3f& getAreaObjScale(const AreaObj* areaObj) {
153 return areaObj->getAreaShape()->getScale();
154}
155
156void getAreaObjDirFront(sead::Vector3f* outFrontDir, const AreaObj* areaObj) {
157 getAreaObjBaseMtx(areaObj).getBase(o&: *outFrontDir, axis: 2);
158}
159
160void getAreaObjDirUp(sead::Vector3f* outUpDir, const AreaObj* areaObj) {
161 getAreaObjBaseMtx(areaObj).getBase(o&: *outUpDir, axis: 1);
162}
163
164void getAreaObjDirSide(sead::Vector3f* outSideDir, const AreaObj* areaObj) {
165 getAreaObjBaseMtx(areaObj).getBase(o&: *outSideDir, axis: 0);
166}
167
168void calcNearestAreaObjEdgePos(sead::Vector3f* outNearestEdgePos, const AreaObj* areaObj,
169 const sead::Vector3f& position) {
170 areaObj->getAreaShape()->calcNearestEdgePoint(outNearestEdgePos, position);
171}
172
173void calcNearestAreaObjEdgePosTopY(sead::Vector3f* outNearestEdgePosTopY, const AreaObj* areaObj,
174 const sead::Vector3f& position) {
175 sead::Vector3f scale = {0.0f, 0.0f, 0.0f};
176 tryGetScale(scale: &scale, placementInfo: *areaObj->getPlacementInfo());
177
178 sead::Vector3f areaPos = getAreaObjBaseMtx(areaObj).getBase(axis: 3);
179
180 sead::Vector3f sideDir;
181 getAreaObjDirSide(outSideDir: &sideDir, areaObj);
182
183 sead::Vector3f upDir;
184 getAreaObjDirUp(outUpDir: &upDir, areaObj);
185
186 sead::Vector3f diff;
187 diff.x = position.x - areaPos.x;
188 diff.y = position.y - areaPos.y;
189 diff.z = position.z - areaPos.z;
190
191 verticalizeVec(out: &diff, vertical: upDir, vec: diff);
192 limitVectorParallelVertical(&diff, sideDir, scale.x * 1000.0f, scale.z * 1000.0f);
193
194 diff.setScaleAdd(t: scale.y * 1000.0f, a: upDir, b: diff);
195 outNearestEdgePosTopY->set(diff + areaPos);
196}
197
198f32 calcNearestAreaObjEdgeRateTopY(const AreaObj* areaObj, const sead::Vector3f& position) {
199 sead::Vector3f areaPos = getAreaObjBaseMtx(areaObj).getBase(axis: 3);
200
201 sead::Vector3f upDir;
202 getAreaObjDirUp(outUpDir: &upDir, areaObj);
203
204 sead::Vector3f nearestEdgePosTopY;
205 calcNearestAreaObjEdgePosTopY(outNearestEdgePosTopY: &nearestEdgePosTopY, areaObj, position);
206
207 f32 distToAreaPos = upDir.dot(t: nearestEdgePosTopY - areaPos);
208 if (distToAreaPos < 0.0f || isNearZero(value: distToAreaPos))
209 return 1.0f;
210
211 f32 distToPosition = sead::Mathf::clampMin(val: upDir.dot(t: nearestEdgePosTopY - position), min_: 0.0f);
212
213 return sead::Mathf::clamp(value: distToPosition / distToAreaPos, low: 0.0f, high: 1.0f);
214}
215
216void calcAreaObjCenterPos(sead::Vector3f* outCenterPosition, const AreaObj* areaObj) {
217 sead::Vector3f pos = getAreaObjBaseMtx(areaObj).getBase(axis: 3);
218 f32 scaleY = getAreaObjScale(areaObj).y;
219
220 outCenterPosition->x = pos.x;
221 outCenterPosition->y = pos.y + scaleY * 1000.0f / 2.0f;
222 outCenterPosition->z = pos.z;
223}
224
225bool checkAreaObjCollisionByArrow(sead::Vector3f* outHitPosition, sead::Vector3f* outNormal,
226 const AreaObj* areaObj, const sead::Vector3f& position1,
227 const sead::Vector3f& position2) {
228 return areaObj->getAreaShape()->checkArrowCollision(outHitPosition, outNormal, position1,
229 position2);
230}
231
232bool calcFindAreaSurface(const IUseAreaObj* areaUser, const char* name,
233 sead::Vector3f* outHitPosition, sead::Vector3f* outNormal,
234 const sead::Vector3f& position1, const sead::Vector3f& position2) {
235 if (tryFindAreaObj(areaUser, name, position: position1))
236 return false;
237
238 sead::Vector3f positionHalfway = (position1 + position2) / 2.0f;
239
240 AreaObj* areaObj = tryFindAreaObj(areaUser, name, position: positionHalfway);
241 if (!areaObj) {
242 areaObj = tryFindAreaObj(areaUser, name, position: position2);
243 if (!areaObj)
244 return false;
245 }
246
247 return checkAreaObjCollisionByArrow(outHitPosition, outNormal, areaObj, position1, position2);
248}
249
250bool calcFindAreaSurface(const IUseAreaObj* areaUser, const char* name,
251 sead::Vector3f* outHitPosition, sead::Vector3f* outNormal,
252 const sead::Vector3f& position, const sead::Vector3f& direction,
253 f32 distance) {
254 sead::Vector3f position1;
255 sead::Vector3f position2;
256 position1.setScaleAdd(t: distance, a: direction, b: position);
257 position2.setScaleAdd(t: distance, a: -direction, b: position);
258
259 if (tryFindAreaObj(areaUser, name, position: position1))
260 return false;
261
262 AreaObj* areaObj = tryFindAreaObj(areaUser, name, position);
263 if (!areaObj) {
264 areaObj = tryFindAreaObj(areaUser, name, position: position2);
265 if (!areaObj)
266 return false;
267 }
268
269 return checkAreaObjCollisionByArrow(outHitPosition, outNormal, areaObj, position1, position2);
270}
271} // namespace al
272