1#include "Library/LiveActor/ActorMovementFunction.h"
2
3#include "Library/Area/AreaObjUtil.h"
4#include "Library/Audio/System/AudioKeeper.h"
5#include "Library/Collision/Collider.h"
6#include "Library/Collision/CollisionPartsKeeperUtil.h"
7#include "Library/Collision/CollisionPartsTriangle.h"
8#include "Library/HitSensor/SensorFunction.h"
9#include "Library/LiveActor/ActorCollisionFunction.h"
10#include "Library/LiveActor/ActorParamMove.h"
11#include "Library/LiveActor/ActorPoseKeeper.h"
12#include "Library/LiveActor/ActorPoseUtil.h"
13#include "Library/LiveActor/ActorSensorUtil.h"
14#include "Library/Math/MathUtil.h"
15#include "Library/Matrix/MatrixUtil.h"
16#include "Library/Player/PlayerUtil.h"
17#include "Library/Screen/ScreenPointKeeper.h"
18#include "Library/Se/SeKeeper.h"
19
20namespace al {
21
22inline f32 modDegree(f32 deg) {
23 return modf(a: deg + 360.0f, b: 360.0f) + 0.0f;
24}
25
26void resetPosition(LiveActor* actor) {
27 if (actor->getPoseKeeper())
28 actor->calcAnim();
29 if (actor->getHitSensorKeeper()) {
30 alSensorFunction::clearHitSensors(actor);
31 alSensorFunction::updateHitSensorsAll(actor);
32 }
33 if (actor->getScreenPointKeeper())
34 alScreenPointFunction::updateScreenPointAll(actor);
35 if (actor->getCollider())
36 actor->getCollider()->onInvalidate();
37 if (actor->getCollisionParts())
38 resetAllCollisionMtx(actor);
39 if (actor->getAudioKeeper() && actor->getAudioKeeper()->getSeKeeper())
40 actor->getAudioKeeper()->getSeKeeper()->resetPosition();
41}
42
43void resetPosition(LiveActor* actor, const sead::Vector3f& trans) {
44 updatePoseTrans(actor, trans);
45 resetPosition(actor);
46}
47
48void resetRotatePosition(LiveActor* actor, const sead::Vector3f& rot, const sead::Vector3f& trans) {
49 updatePoseRotate(actor, rotate: rot);
50 resetPosition(actor, trans);
51}
52
53void resetQuatPosition(LiveActor* actor, const sead::Quatf& quat, const sead::Vector3f& trans) {
54 updatePoseQuat(actor, quat);
55 resetPosition(actor, trans);
56}
57
58void resetMtxPosition(LiveActor* actor, const sead::Matrix34f& mtx) {
59 updatePoseMtx(actor, mtx: &mtx);
60 resetPosition(actor);
61}
62
63void resetActorPosition(LiveActor* actor, const LiveActor* target) {
64 resetMtxPosition(actor, mtx: *target->getBaseMtx());
65}
66
67bool trySetPosOnGround(LiveActor* actor) {
68 sead::Vector3f pos = getTrans(actor);
69 sead::Vector3f dir = {0.0f, -500.0f, 0.0f};
70 pos.y += 200.0f;
71 return alCollisionUtil::getFirstPolyOnArrow(actor, getTransPtr(actor), nullptr, pos, dir,
72 nullptr, nullptr);
73}
74
75const sead::Vector3f& getVelocity(const LiveActor* actor) {
76 return actor->getPoseKeeper()->getVelocity();
77}
78
79sead::Vector3f* getVelocityPtr(LiveActor* actor) {
80 return actor->getPoseKeeper()->getVelocityPtr();
81}
82
83void separateVelocityHV(sead::Vector3f* horizontal, sead::Vector3f* vertical,
84 const LiveActor* actor) {
85 separateVelocityDirHV(horizontal, vertical, actor, dir: getGravity(actor));
86}
87
88void separateVelocityDirHV(sead::Vector3f* horizontal, sead::Vector3f* vertical,
89 const LiveActor* actor, const sead::Vector3f& dir) {
90 separateVectorHV(horizontal, vertical, dir, getVelocity(actor));
91}
92
93void separateVelocityParallelVertical(sead::Vector3f* parallel, sead::Vector3f* vertical,
94 const LiveActor* actor, const sead::Vector3f& dir) {
95 separateVectorParallelVertical(parallel, vertical, dir, getVelocity(actor));
96}
97
98void setVelocity(LiveActor* actor, const sead::Vector3f& vel) {
99 getVelocityPtr(actor)->set(vel);
100}
101
102void setVelocity(LiveActor* actor, f32 x, f32 y, f32 z) {
103 getVelocityPtr(actor)->set(x_: x, y_: y, z_: z);
104}
105
106void setVelocityX(LiveActor* actor, f32 x) {
107 getVelocityPtr(actor)->x = x;
108}
109
110void setVelocityY(LiveActor* actor, f32 y) {
111 getVelocityPtr(actor)->y = y;
112}
113
114void setVelocityZ(LiveActor* actor, f32 z) {
115 getVelocityPtr(actor)->z = z;
116}
117
118void setVelocityZero(LiveActor* actor) {
119 setVelocity(actor, x: 0.0f, y: 0.0f, z: 0.0f);
120}
121
122void setVelocityZeroX(LiveActor* actor) {
123 setVelocityX(actor, x: 0.0f);
124}
125
126void setVelocityZeroY(LiveActor* actor) {
127 setVelocityY(actor, y: 0.0f);
128}
129
130void setVelocityZeroZ(LiveActor* actor) {
131 setVelocityZ(actor, z: 0.0f);
132}
133
134void setVelocityZeroH(LiveActor* actor) {
135 setVelocityZeroH(actor, gravity: getGravity(actor));
136}
137
138void setVelocityZeroH(LiveActor* actor, const sead::Vector3f& gravity) {
139 sead::Vector3f* velocity = getVelocityPtr(actor);
140 parallelizeVec(velocity, gravity, *velocity);
141}
142
143void setVelocityZeroV(LiveActor* actor) {
144 setVelocityZeroV(actor, gravity: getGravity(actor));
145}
146
147void setVelocityZeroV(LiveActor* actor, const sead::Vector3f& gravity) {
148 sead::Vector3f* velocity = getVelocityPtr(actor);
149 verticalizeVec(out: velocity, vertical: gravity, vec: *velocity);
150}
151
152void setVelocityJump(LiveActor* actor, f32 speed) {
153 getVelocityPtr(actor)->setScale(a: getGravity(actor), t: -speed);
154}
155
156void setVelocityToFront(LiveActor* actor, f32 speed) {
157 sead::Vector3f front = {0.0f, 0.0f, 0.0f};
158 calcFrontDir(front: &front, actor);
159 getVelocityPtr(actor)->setScale(a: front, t: speed);
160}
161
162void setVelocityToUp(LiveActor* actor, f32 speed) {
163 sead::Vector3f up = {0.0f, 0.0f, 0.0f};
164 calcUpDir(up: &up, actor);
165 getVelocityPtr(actor)->setScale(a: up, t: speed);
166}
167
168void setVelocityToSide(LiveActor* actor, f32 speed) {
169 sead::Vector3f side = {0.0f, 0.0f, 0.0f};
170 calcSideDir(side: &side, actor);
171 getVelocityPtr(actor)->setScale(a: side, t: speed);
172}
173
174void setVelocityToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 speed) {
175 sead::Vector3f normDir;
176 tryNormalizeOrZero(out: &normDir, vec: dir);
177 getVelocityPtr(actor)->setScale(a: normDir, t: speed);
178}
179
180void setVelocityToGravity(LiveActor* actor, f32 speed) {
181 getVelocityPtr(actor)->setScale(a: getGravity(actor), t: speed);
182}
183
184void setVelocitySeparateHV(LiveActor* actor, const sead::Vector3f& h, const sead::Vector3f& v,
185 f32 speedH, f32 speedV) {
186 calcVectorSeparateHV(getVelocityPtr(actor), h, v, speedH, speedV);
187}
188
189void setVelocitySeparateHV(LiveActor* actor, const sead::Vector3f& h, f32 speedH, f32 speedV) {
190 calcVelocitySeparateHV(velocity: getVelocityPtr(actor), actor, h, speedH, speedV);
191}
192
193void calcVelocitySeparateHV(sead::Vector3f* velocity, const LiveActor* actor,
194 const sead::Vector3f& h, f32 speedH, f32 speedV) {
195 calcVectorSeparateHV(velocity, h, -getGravity(actor), speedH, speedV);
196}
197
198void setVelocitySeparateUp(LiveActor* actor, const sead::Vector3f& h, f32 speedH, f32 speedV) {
199 sead::Vector3f up;
200 calcUpDir(up: &up, actor);
201 setVelocitySeparateHV(actor, h, v: up, speedH, speedV);
202}
203
204void setVelocityOnlyDir(LiveActor* actor, const sead::Vector3f& dir, f32 speed) {
205 sead::Vector3f normDir;
206 tryNormalizeOrZero(out: &normDir, vec: dir);
207 getVelocityPtr(actor)->add(a: normDir * (speed - normDir.dot(t: getVelocity(actor))));
208}
209
210void setVelocityOnlyV(LiveActor* actor, f32 speed) {
211 setVelocityOnlyDir(actor, dir: getGravity(actor), speed: -speed);
212}
213
214void setVelocityOnlyGravity(LiveActor* actor, f32 speed) {
215 setVelocityOnlyDir(actor, dir: getGravity(actor), speed);
216}
217
218void addVelocity(LiveActor* actor, const sead::Vector3f& vel) {
219 getVelocityPtr(actor)->add(a: vel);
220}
221
222void addVelocity(LiveActor* actor, f32 x, f32 y, f32 z) {
223 addVelocity(actor, vel: {x, y, z});
224}
225
226void addVelocityX(LiveActor* actor, f32 x) {
227 getVelocityPtr(actor)->x += x;
228}
229
230void addVelocityY(LiveActor* actor, f32 y) {
231 getVelocityPtr(actor)->y += y;
232}
233
234void addVelocityZ(LiveActor* actor, f32 z) {
235 getVelocityPtr(actor)->z += z;
236}
237
238void addVelocityDump(LiveActor* actor, const sead::Vector3f& dir, f32 force) {
239 getVelocity(actor); // unused
240 sead::Vector3f accel = dir - getVelocity(actor);
241 sead::Vector3f add;
242 lerpVec(&add, dir, accel, force);
243 addVelocity(actor, vel: add);
244}
245
246void addVelocityJump(LiveActor* actor, f32 force) {
247 addVelocity(actor, vel: getGravity(actor) * -force);
248}
249
250inline void addVelocityInline(LiveActor* actor, const sead::Vector3f& vel, f32 force) {
251 sead::Vector3f* velocity = getVelocityPtr(actor);
252 velocity->setScaleAdd(t: force, a: vel, b: *velocity);
253}
254
255void addVelocityToFront(LiveActor* actor, f32 force) {
256 sead::Vector3f front;
257 calcFrontDir(front: &front, actor);
258 addVelocityInline(actor, vel: front, force);
259}
260
261void addVelocityToUp(LiveActor* actor, f32 force) {
262 sead::Vector3f up = {0.0f, 0.0f, 0.0f};
263 calcUpDir(up: &up, actor);
264 addVelocityInline(actor, vel: up, force);
265}
266
267void addVelocityToSide(LiveActor* actor, f32 force) {
268 sead::Vector3f side = {0.0f, 0.0f, 0.0f};
269 calcSideDir(side: &side, actor);
270 addVelocityInline(actor, vel: side, force);
271}
272
273void addVelocityToDown(LiveActor* actor, f32 force) {
274 sead::Vector3f down = {0.0f, 0.0f, 0.0f};
275 calcDownDir(down: &down, actor);
276 addVelocityInline(actor, vel: down, force);
277}
278
279void addVelocityToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 force) {
280 sead::Vector3f normDir;
281 tryNormalizeOrZero(out: &normDir, vec: dir);
282 addVelocityInline(actor, vel: normDir, force);
283}
284
285void addVelocityToGravity(LiveActor* actor, f32 force) {
286 sead::Vector3f* velocity = getVelocityPtr(actor);
287 velocity->setScaleAdd(t: force, a: getGravity(actor), b: *velocity);
288}
289
290void addVelocityToGravityLimit(LiveActor* actor, f32 force, f32 limit) {
291 addVectorLimit(getVelocityPtr(actor), getGravity(actor) * force, limit);
292}
293
294void addVelocityToGravityFittedGround(LiveActor* actor, f32 force, u32 maxAirTime) {
295 sead::Vector3f* velocity = getVelocityPtr(actor);
296 const sead::Vector3f& normal = getOnGroundNormal(actor, maxAirTime);
297 // TODO maybe this should be a Vector3::subScale() method?
298 velocity->x -= normal.x * force;
299 velocity->y -= normal.y * force;
300 velocity->z -= normal.z * force;
301}
302
303void addVelocityToGravityNaturalOrFittedGround(LiveActor* actor, f32 force) {
304 sead::Vector3f gravity = sead::Vector3f::zero;
305 calcGravityDir(gravity: &gravity, actor);
306 addVelocityInline(actor, vel: gravity, force);
307}
308
309void calcGravityDir(sead::Vector3f* gravity, const LiveActor* actor) {
310 if (isCollidedGround(actor))
311 *gravity = -getOnGroundNormal(actor, 0);
312 else
313 gravity->set(getGravity(actor));
314 tryNormalizeOrZero(out: gravity);
315}
316
317void addVelocityToTarget(LiveActor* actor, const sead::Vector3f& target, f32 force) {
318 sead::Vector3f diff = target;
319 diff -= getTrans(actor);
320 tryNormalizeOrZero(out: &diff);
321 addVelocityInline(actor, vel: diff, force);
322}
323
324void addVelocityToTarget(LiveActor* actor, const sead::Vector3f& target, f32 minForce, f32 maxForce,
325 f32 minDistance, f32 maxDistance) {
326 sead::Vector3f diff = target;
327 diff -= getTrans(actor);
328 f32 distance;
329 separateScalarAndDirection(&distance, &diff, diff);
330 f32 normDistance = normalize(x: distance, min: minDistance, max: maxDistance);
331 sead::Vector3f* velocity = getVelocityPtr(actor);
332 f32 force = lerpValue(a: minForce, b: maxForce, t: normDistance);
333 velocity->setScaleAdd(t: force, a: diff, b: *velocity);
334}
335
336void addVelocityToTargetH(LiveActor* actor, const sead::Vector3f& target, f32 force) {
337 sead::Vector3f diff = target;
338 diff -= getTrans(actor);
339 verticalizeVec(out: &diff, vertical: getGravity(actor), vec: diff);
340 tryNormalizeOrZero(out: &diff);
341 addVelocityInline(actor, vel: diff, force);
342}
343
344void addVelocityToTargetHV(LiveActor* actor, const sead::Vector3f& target, f32 forceH, f32 forceV) {
345 sead::Vector3f diff = target;
346 diff -= getTrans(actor);
347 f32 diffDown = diff.dot(t: getGravity(actor));
348 sead::Vector3f diffV = diffDown * getGravity(actor);
349 sead::Vector3f diffH = diff - diffV;
350 tryNormalizeOrZero(out: &diffH);
351 tryNormalizeOrZero(out: &diffV);
352 addVelocityInline(actor, vel: diffH, force: forceH);
353 addVelocityInline(actor, vel: diffV, force: forceV);
354}
355
356void addVelocityDampToTarget(LiveActor* actor, const sead::Vector3f& target, f32 forceDamp) {
357 addVelocityDampToTarget(actor, target, force: forceDamp, damp: forceDamp);
358}
359
360void addVelocityDampToTarget(LiveActor* actor, const sead::Vector3f& target, f32 force, f32 damp) {
361 sead::Vector3f diff = (target - getTrans(actor)) * force;
362 sead::Vector3f* velocity = getVelocityPtr(actor);
363 lerpVec(velocity, *velocity, diff, damp);
364}
365
366bool addVelocityToPlayer(LiveActor* actor, f32 force, const sead::Vector3f& offset) {
367 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
368 if (!tryFindNearestPlayerPos(&playerPos, actor))
369 return false;
370
371 addVelocityToTarget(actor, target: playerPos + offset, force);
372 return true;
373}
374
375bool addVelocityToPlayerHV(LiveActor* actor, f32 forceH, f32 forceV, const sead::Vector3f& offset) {
376 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
377 if (!tryFindNearestPlayerPos(&playerPos, actor))
378 return false;
379
380 addVelocityToTargetHV(actor, target: playerPos + offset, forceH, forceV);
381 return true;
382}
383
384void addVelocityFromTarget(LiveActor* actor, const sead::Vector3f& target, f32 force) {
385 sead::Vector3f diff = getTrans(actor);
386 diff -= target;
387 tryNormalizeOrZero(out: &diff);
388 addVelocityInline(actor, vel: diff, force);
389}
390
391void addVelocityFromTargetHV(LiveActor* actor, const sead::Vector3f& target, f32 forceH,
392 f32 forceV) {
393 sead::Vector3f diff = getTrans(actor);
394 diff -= target;
395 f32 diffDown = diff.dot(t: getGravity(actor));
396 sead::Vector3f diffV = diffDown * getGravity(actor);
397 sead::Vector3f diffH = diff - diffV;
398 tryNormalizeOrZero(out: &diffH);
399 tryNormalizeOrZero(out: &diffV);
400 addVelocityInline(actor, vel: diffH, force: forceH);
401 addVelocityInline(actor, vel: diffV, force: forceV);
402}
403
404bool addVelocityFromPlayer(LiveActor* actor, f32 force, const sead::Vector3f& offset) {
405 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
406 if (!tryFindNearestPlayerPos(&playerPos, actor))
407 return false;
408
409 addVelocityFromTarget(actor, target: playerPos + offset, force);
410 return true;
411}
412
413bool addVelocityFromPlayerHV(LiveActor* actor, f32 forceH, f32 forceV,
414 const sead::Vector3f& offset) {
415 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
416 if (!tryFindNearestPlayerPos(&playerPos, actor))
417 return false;
418
419 addVelocityFromTargetHV(actor, target: playerPos + offset, forceH, forceV);
420 return true;
421}
422
423void addVelocityClockwiseToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 force) {
424 sead::Vector3f dirVelocity;
425 if (!calcVelocityClockwiseToDirection(actor, dirVelocity: &dirVelocity, dir))
426 return;
427 sead::Vector3f normDir;
428 tryNormalizeOrZero(out: &normDir, vec: dirVelocity);
429 addVelocityInline(actor, vel: normDir, force);
430}
431
432bool calcVelocityClockwiseToDirection(LiveActor* actor, sead::Vector3f* dirVelocity,
433 const sead::Vector3f& dir) {
434 sead::Vector3f normDir;
435 if (!dirVelocity || !tryNormalizeOrZero(out: &normDir, vec: dir))
436 return false;
437
438 dirVelocity->setCross(a: getGravity(actor), b: normDir);
439 return true;
440}
441
442void addVelocityClockwiseToTarget(LiveActor* actor, const sead::Vector3f& target, f32 force) {
443 addVelocityClockwiseToDirection(actor, dir: target - getTrans(actor), force);
444}
445
446void addVelocityJumpGroundInertia(LiveActor* actor, const sead::Vector3f& velocity, f32 force) {
447 sead::Vector3f inertia = {0.0f, 0.0f, 0.0f};
448 calcJumpInertia(&inertia, actor, velocity, force);
449 addVelocity(actor, vel: inertia);
450}
451
452void tryAddVelocityLimit(LiveActor* actor, const sead::Vector3f& velocity, f32 limit) {
453 sead::Vector3f newVelocity = getVelocity(actor);
454 addVectorLimit(&newVelocity, velocity, limit);
455 setVelocity(actor, vel: newVelocity);
456}
457
458void subVelocityExceptDirectionLimit(LiveActor* actor, const sead::Vector3f& direction, f32 subVel,
459 f32 limit) {
460 sead::Vector3f horizontal = {0.0f, 0.0f, 0.0f};
461 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
462 separateVelocityDirHV(horizontal: &horizontal, vertical: &vertical, actor, dir: direction);
463
464 f32 length = horizontal.length();
465 f32 newLen = sead::Mathf::clampMin(val: length - subVel, min_: limit);
466 // TODO sead function to scale a vector to a certain length?
467 f32 lenAgain = horizontal.length();
468 if (lenAgain > 0.0f)
469 horizontal *= newLen / lenAgain;
470
471 setVelocity(actor, vel: horizontal + vertical);
472}
473
474void scaleVelocity(LiveActor* actor, f32 factor) {
475 *getVelocityPtr(actor) *= factor;
476}
477
478void scaleVelocityLimit(LiveActor* actor, f32 factor, f32 limit) {
479 sead::Vector3f direction = {0.0f, 0.0f, 0.0f};
480 f32 scalar = 0.0f;
481 if (separateScalarAndDirection(&scalar, &direction, getVelocity(actor)))
482 return;
483
484 // enforces a *lower* limit = minimum speed!
485 if (scalar < limit)
486 return;
487 scalar = sead::Mathf::clampMin(val: scalar * factor, min_: limit);
488 setVelocity(actor, vel: scalar * direction);
489}
490
491void scaleVelocityX(LiveActor* actor, f32 factorX) {
492 getVelocityPtr(actor)->x *= factorX;
493}
494
495void scaleVelocityY(LiveActor* actor, f32 factorY) {
496 getVelocityPtr(actor)->y *= factorY;
497}
498
499void scaleVelocityZ(LiveActor* actor, f32 factorZ) {
500 getVelocityPtr(actor)->z *= factorZ;
501}
502
503void scaleVelocityHV(LiveActor* actor, f32 factorH, f32 factorV) {
504 scaleVelocityParallelVertical(actor, direction: getGravity(actor), parallel: factorV, vertical: factorH);
505}
506
507void scaleVelocityDirection(LiveActor* actor, const sead::Vector3f& direction, f32 factor) {
508 sead::Vector3f* velocity = getVelocityPtr(actor);
509 scaleVectorDirection(outVec: velocity, inVec: direction, dir: *velocity, scale: factor);
510}
511
512void scaleVelocityExceptDirection(LiveActor* actor, const sead::Vector3f& direction, f32 factor) {
513 sead::Vector3f* velocity = getVelocityPtr(actor);
514 scaleVectorExceptDirection(outVec: velocity, inVec: direction, dir: *velocity, scale: factor);
515}
516
517void scaleVelocityParallelVertical(LiveActor* actor, const sead::Vector3f& direction, f32 parallel,
518 f32 vertical) {
519 const sead::Vector3f& velocity = getVelocity(actor);
520
521 f32 speedV = direction.dot(t: velocity);
522 sead::Vector3f parallelVec = direction * (speedV * parallel);
523 sead::Vector3f verticalVec = velocity;
524 // TODO sead subScale ?
525 verticalVec.x -= direction.x * speedV;
526 verticalVec.y -= direction.y * speedV;
527 verticalVec.z -= direction.z * speedV;
528
529 sead::Vector3f* newVelocity = getVelocityPtr(actor);
530 *newVelocity = parallelVec;
531 newVelocity->setScaleAdd(t: vertical, a: verticalVec, b: parallelVec);
532}
533
534void limitVelocity(LiveActor* actor, f32 limit) {
535 if (calcSpeed(actor) > limit) {
536 tryNormalizeOrZero(out: getVelocityPtr(actor));
537 scaleVelocity(actor, factor: limit);
538 }
539}
540
541f32 calcSpeed(const LiveActor* actor) {
542 return getVelocity(actor).length();
543}
544
545void limitVelocityX(LiveActor* actor, f32 limitX) {
546 if (getVelocity(actor).x > limitX)
547 getVelocityPtr(actor)->x = limitX;
548 else if (getVelocity(actor).x < -limitX)
549 getVelocityPtr(actor)->x = -limitX;
550}
551
552void limitVelocityY(LiveActor* actor, f32 limitY) {
553 if (getVelocity(actor).y > limitY)
554 getVelocityPtr(actor)->y = limitY;
555 else if (getVelocity(actor).y < -limitY)
556 getVelocityPtr(actor)->y = -limitY;
557}
558
559void limitVelocityZ(LiveActor* actor, f32 limitZ) {
560 if (getVelocity(actor).z > limitZ)
561 getVelocityPtr(actor)->z = limitZ;
562 else if (getVelocity(actor).z < -limitZ)
563 getVelocityPtr(actor)->z = -limitZ;
564}
565
566void limitVelocityH(LiveActor* actor, f32 limitH) {
567 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
568 sead::Vector3f horizontal = {0.0f, 0.0f, 0.0f};
569 separateVelocityParallelVertical(parallel: &vertical, vertical: &horizontal, actor, dir: getGravity(actor));
570 if (horizontal.squaredLength() > sead::Mathf::square(t: limitH)) {
571 f32 length = horizontal.length();
572 if (length > 0.0f)
573 horizontal *= limitH / length;
574 }
575 setVelocity(actor, vel: vertical + horizontal);
576}
577
578void limitVelocityHV(LiveActor* actor, f32 limitH, f32 limitV) {
579 sead::Vector3f horizontal, vertical;
580 separateVelocityHV(horizontal: &horizontal, vertical: &vertical, actor);
581 if (horizontal.squaredLength() > sead::Mathf::square(t: limitH)) {
582 f32 length = horizontal.length();
583 if (length > 0.0f)
584 horizontal *= limitH / length;
585 }
586 if (vertical.squaredLength() > sead::Mathf::square(t: limitV)) {
587 f32 length = vertical.length();
588 if (length > 0.0f)
589 vertical *= limitV / length;
590 }
591 setVelocity(actor, vel: horizontal + vertical);
592}
593
594void limitVelocityUpGravityH(LiveActor* actor, f32 limitDown, f32 limitUp, f32 limitH) {
595 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
596 sead::Vector3f horizontal = {0.0f, 0.0f, 0.0f};
597 separateVelocityParallelVertical(parallel: &vertical, vertical: &horizontal, actor, dir: getGravity(actor));
598 if (horizontal.squaredLength() > sead::Mathf::square(t: limitH)) {
599 f32 length = horizontal.length();
600 if (length > 0.0f)
601 horizontal *= limitH / length;
602 }
603
604 f32 speedV = vertical.dot(t: getGravity(actor));
605 if (speedV > limitUp)
606 vertical = getGravity(actor) * limitUp;
607 f32 negLimitDown = -limitDown;
608 if (speedV < negLimitDown)
609 vertical = getGravity(actor) * negLimitDown;
610 setVelocity(actor, vel: vertical + horizontal);
611}
612
613void limitVelocityDir(LiveActor* actor, const sead::Vector3f& dir, f32 limit) {
614 sead::Vector3f parallel = {0.0f, 0.0f, 0.0f};
615 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
616 separateVelocityParallelVertical(parallel: &parallel, vertical: &vertical, actor, dir);
617 if (parallel.squaredLength() > sead::Mathf::square(t: limit)) {
618 f32 length = parallel.length();
619 if (length > 0.0f)
620 parallel *= limit / length;
621 }
622 setVelocity(actor, vel: parallel + vertical);
623}
624
625void limitVelocityDirSign(LiveActor* actor, const sead::Vector3f& dir, f32 limit) {
626 sead::Vector3f parallel = {0.0f, 0.0f, 0.0f};
627 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
628 separateVelocityParallelVertical(parallel: &parallel, vertical: &vertical, actor, dir);
629 if (dir.dot(t: parallel) < 0.0f)
630 return;
631
632 if (parallel.squaredLength() > sead::Mathf::square(t: limit)) {
633 f32 length = parallel.length();
634 if (length > 0.0f)
635 parallel *= limit / length;
636 }
637 setVelocity(actor, vel: parallel + vertical);
638}
639
640void limitVelocityDirV(LiveActor* actor, const sead::Vector3f& dir, f32 limit) {
641 sead::Vector3f parallel = {0.0f, 0.0f, 0.0f};
642 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
643 separateVelocityParallelVertical(parallel: &parallel, vertical: &vertical, actor, dir);
644 if (vertical.squaredLength() > sead::Mathf::square(t: limit)) {
645 f32 length = vertical.length();
646 if (length > 0.0f)
647 vertical *= limit / length;
648 }
649 setVelocity(actor, vel: parallel + vertical);
650}
651
652void limitVelocityDirVRate(LiveActor* actor, const sead::Vector3f& dir, f32 limit, f32 rate) {
653 sead::Vector3f parallel = {0.0f, 0.0f, 0.0f};
654 sead::Vector3f vertical = {0.0f, 0.0f, 0.0f};
655 separateVelocityParallelVertical(parallel: &parallel, vertical: &vertical, actor, dir);
656 if (vertical.squaredLength() > sead::Mathf::square(t: limit)) {
657 f32 length1 = vertical.length();
658 f32 length = vertical.length();
659 if (length > 0.0f)
660 vertical *= ((length1 - limit) * rate + limit) / length;
661 }
662 setVelocity(actor, vel: parallel + vertical);
663}
664
665void limitVelocityParallelVertical(LiveActor* actor, const sead::Vector3f& dir, f32 parallel,
666 f32 vertical) {
667 limitVectorParallelVertical(getVelocityPtr(actor), dir, parallel, vertical);
668}
669
670void limitVelocitySeparateHV(LiveActor* actor, const sead::Vector3f& dir, f32 horizontal,
671 f32 vertical) {
672 limitVectorSeparateHV(getVelocityPtr(actor), dir, horizontal, vertical);
673}
674
675u32 reboundVelocityPart(LiveActor* actor, f32 rebound, f32 threshold) {
676 return reboundVelocityPart(actor, ground: rebound, wall: rebound, ceiling: rebound, threshold);
677}
678
679u32 reboundVelocityPart(LiveActor* actor, f32 ground, f32 wall, f32 ceiling, f32 threshold) {
680 u32 result = 0;
681 if (isCollidedGround(actor)) {
682 sead::Vector3f normal = getCollidedGroundNormal(actor);
683 f32 dot = normal.dot(t: getVelocity(actor));
684 if (ground < 0.0f || dot < -threshold) {
685 addVelocity(actor, vel: -(normal * ((ground + 1.0f) * dot)));
686 if (ground >= 0.0f)
687 result |= 1;
688 } else if (dot < 0.0f) {
689 addVelocity(actor, vel: -(normal * dot));
690 }
691 }
692
693 if (isCollidedWall(actor)) {
694 sead::Vector3f normal = getCollidedWallNormal(actor);
695 f32 dot = normal.dot(t: getVelocity(actor));
696 if (wall < 0.0f || dot < -threshold) {
697 addVelocity(actor, vel: -(normal * ((wall + 1.0f) * dot)));
698 if (wall >= 0.0f)
699 result |= 2;
700 } else if (dot < 0.0f) {
701 addVelocity(actor, vel: -(normal * dot));
702 }
703 }
704
705 if (isCollidedCeiling(actor)) {
706 sead::Vector3f normal = getCollidedCeilingNormal(actor);
707 f32 dot = normal.dot(t: getVelocity(actor));
708 if (ceiling < 0.0f || dot < -threshold) {
709 addVelocity(actor, vel: -(normal * ((ceiling + 1.0f) * dot)));
710 if (ceiling >= 0.0f)
711 result |= 4;
712 } else if (dot < 0.0f) {
713 addVelocity(actor, vel: -(normal * dot));
714 }
715 }
716
717 return result;
718}
719
720bool reboundVelocityFromEachCollision(LiveActor* actor, f32 ground, f32 wall, f32 ceiling,
721 f32 threshold) {
722 if (!isCollided(actor))
723 return false;
724
725 sead::Vector3f normalSum;
726 calcCollidedNormalSum(actor, &normalSum);
727 if (isNearZero(vec: normalSum, tolerance: 0.001f))
728 return false;
729
730 normalize(vec: &normalSum);
731 const sead::Vector3f& gravity = getGravity(actor);
732 f32 rebound;
733 if (isFloorPolygon(normalSum, gravity))
734 rebound = ground;
735 else if (isWallPolygon(normalSum, gravity))
736 rebound = wall;
737 else if (isCeilingPolygon(normalSum, gravity))
738 rebound = ceiling;
739 else
740 rebound = 0.0f;
741
742 f32 dot = normalSum.dot(t: getVelocity(actor));
743 if (dot < -threshold) {
744 sead::Vector3f* velocity = getVelocityPtr(actor);
745 f32 mul = (rebound + 1.0f) * dot;
746 velocity->setScaleAdd(t: -mul, a: normalSum, b: *velocity);
747 return true;
748 } else if (dot < 0.0f) {
749 sead::Vector3f* velocity = getVelocityPtr(actor);
750 velocity->setScaleAdd(t: -dot, a: normalSum, b: *velocity);
751 }
752 return false;
753}
754
755bool reboundVelocityFromCollision(LiveActor* actor, f32 reboundStrength, f32 reboundMin,
756 f32 friction) {
757 if (!isCollided(actor))
758 return false;
759
760 sead::Vector3f normalSum;
761 calcCollidedNormalSum(actor, &normalSum);
762 if (isNearZero(vec: normalSum, tolerance: 0.001f))
763 return false;
764
765 normalize(vec: &normalSum);
766 f32 dot = normalSum.dot(t: getVelocity(actor));
767 if (dot < -reboundMin) {
768 *getVelocityPtr(actor) -= normalSum * dot;
769 scaleVelocity(actor, factor: friction);
770 *getVelocityPtr(actor) -= normalSum * dot * reboundStrength;
771 return true;
772 } else if (dot < 0.0f) {
773 *getVelocityPtr(actor) -= normalSum * dot;
774 }
775 return false;
776}
777
778bool reboundVelocityFromTriangles(LiveActor* actor, f32 reboundStrength, f32 reboundMin) {
779 Collider* collider = getActorCollider(actor);
780 s32 _4c = collider->get_4c();
781 if (collider->get_48() == 0)
782 return false;
783
784 bool isRebound = false;
785 for (s32 i = 0; i != _4c; i++) {
786 sead::Vector3f normal = collider->getPlane(i)->getNormal(index: 0);
787 f32 dot = normal.dot(t: getVelocity(actor));
788 if (reboundStrength < 0.0) {
789 addVelocity(actor, vel: -((reboundStrength + 1.0f) * dot * normal));
790 isRebound = true;
791 } else if (dot < -reboundMin) {
792 addVelocity(actor, vel: -((reboundStrength + 1.0f) * dot * normal));
793 isRebound = true;
794 } else if (dot < 0.0)
795 addVelocity(actor, vel: -(dot * normal));
796 }
797
798 return isRebound;
799}
800
801bool reboundVelocityFromActor(LiveActor* actor, const LiveActor* target, f32 reboundStrength) {
802 return reboundVelocityFromActor(actor, target, targetVelocity: getVelocity(actor: target), reboundStrength);
803}
804
805__attribute__((always_inline)) bool
806reboundVelocityFromActorInline(LiveActor* actor, const LiveActor* target,
807 const sead::Vector3f& targetVelocity, f32 reboundStrength) {
808 sead::Vector3f direction;
809 calcDirToActor(dir: &direction, actor, target);
810 f32 dot = (getVelocity(actor) - targetVelocity).dot(t: direction);
811 if (dot <= 0.0f) // moving away from each other
812 return false;
813
814 addVelocity(actor, vel: direction * dot * -(reboundStrength + 1.0f));
815 return true;
816}
817
818bool reboundVelocityFromActor(LiveActor* actor, const LiveActor* target,
819 const sead::Vector3f& targetVelocity, f32 reboundStrength) {
820 return reboundVelocityFromActorInline(actor, target, targetVelocity, reboundStrength);
821}
822
823bool reboundVelocityFromSensor(LiveActor* actor, const HitSensor* sensor, f32 reboundStrength) {
824 return reboundVelocityFromSensor(actor, sensor, targetVelocity: getActorVelocity(sensor), reboundStrength);
825}
826
827bool reboundVelocityFromSensor(LiveActor* actor, const HitSensor* sensor,
828 const sead::Vector3f& targetVelocity, f32 reboundStrength) {
829 return reboundVelocityFromActorInline(actor, target: getSensorHost(sensor), targetVelocity,
830 reboundStrength);
831}
832
833bool calcDirToActor(sead::Vector3f* dir, const LiveActor* actor, const LiveActor* target) {
834 dir->setSub(a: getTrans(actor: target), b: getTrans(actor));
835 return !tryNormalizeOrZero(out: dir);
836}
837
838bool reboundVelocityBetweenActor(LiveActor* actor, LiveActor* target,
839 const sead::Vector3f& direction, f32 reboundStrength);
840
841bool reboundVelocityBetweenActor(LiveActor* actor, LiveActor* target, f32 reboundStrength) {
842 sead::Vector3f direction;
843 calcDirToActor(dir: &direction, actor, target);
844 return reboundVelocityBetweenActor(actor, target, direction, reboundStrength);
845}
846
847bool reboundVelocityBetweenActor(LiveActor* actor, LiveActor* target,
848 const sead::Vector3f& direction, f32 reboundStrength) {
849 f32 dot = (getVelocity(actor) - getVelocity(actor: target)).dot(t: direction);
850 if (dot <= 0.0f) // moving away from each other
851 return false;
852 sead::Vector3f vel = direction * dot * ((reboundStrength + 1.0f) * 0.5f);
853 addVelocity(actor: target, vel);
854 addVelocity(actor, vel: -vel);
855 return true;
856}
857
858bool reboundVelocityBetweenSensor(HitSensor* sensorA, HitSensor* sensorB, f32 reboundStrength) {
859 sead::Vector3f direction;
860 calcDirBetweenSensors(&direction, sensorA, sensorB);
861 return reboundVelocityBetweenActor(actor: getSensorHost(sensorA), target: getSensorHost(sensorB), direction,
862 reboundStrength);
863}
864
865void calcVelocityKeepLengthBetweenActor(sead::Vector3f* vel, const LiveActor* actor,
866 const LiveActor* target, f32 targetLength, f32 force) {
867 sead::Vector3f dir;
868 dir.setSub(a: getTrans(actor: target), b: getTrans(actor));
869 f32 len = dir.length();
870 tryNormalizeOrDirZ(vec: &dir);
871 *vel = (targetLength - len) * dir * force * 0.5f;
872}
873
874void addVelocityKeepLengthBetweenActor(LiveActor* actor, LiveActor* target, f32 targetLength,
875 f32 force) {
876 sead::Vector3f vel;
877 calcVelocityKeepLengthBetweenActor(vel: &vel, actor, target, targetLength, force);
878 addVelocity(actor, vel: -vel);
879 addVelocity(actor: target, vel);
880}
881
882void addVelocityDumpKeepLengthBetweenActor(LiveActor* actor, LiveActor* target, f32 targetLength,
883 f32 lenForce, f32 dumpForce) {
884 sead::Vector3f vel;
885 calcVelocityKeepLengthBetweenActor(vel: &vel, actor, target, targetLength, force: lenForce);
886 addVelocityDump(actor, dir: -vel, force: dumpForce);
887 addVelocityDump(actor: target, dir: vel, force: dumpForce);
888}
889
890void calcVelocityBlowAttack(sead::Vector3f* velocity, const LiveActor* actor,
891 const sead::Vector3f& trans, f32 speedH, f32 speedV) {
892 calcVelocitySeparateHV(velocity, actor, h: getTrans(actor) - trans, speedH, speedV);
893}
894
895void addVelocityBlowAttack(LiveActor* actor, const sead::Vector3f& trans, f32 speedH, f32 speedV) {
896 sead::Vector3f velocity;
897 calcVelocityBlowAttack(velocity: &velocity, actor, trans, speedH, speedV);
898 addVelocity(actor, vel: velocity);
899}
900
901void addVelocityBlowAttack(LiveActor* actor, const HitSensor* sensor, f32 speedH, f32 speedV) {
902 addVelocityBlowAttack(actor, trans: getSensorPos(sensor), speedH, speedV);
903}
904
905void setVelocityBlowAttack(LiveActor* actor, const sead::Vector3f& trans, f32 speedH, f32 speedV) {
906 setVelocitySeparateHV(actor, h: getTrans(actor) - trans, speedH, speedV);
907}
908
909void setVelocityBlowAttack(LiveActor* actor, const HitSensor* sensor, f32 speedH, f32 speedV) {
910 setVelocitySeparateHV(actor, h: getTrans(actor) - getSensorPos(sensor), speedH, speedV);
911}
912
913void setVelocityBlowAttackAndTurnToTarget(LiveActor* actor, const sead::Vector3f& target,
914 f32 speedH, f32 speedV) {
915 sead::Vector3f dir = getTrans(actor) - target;
916 bool isValidDir = tryNormalizeOrZero(out: &dir);
917 setVelocitySeparateHV(actor, h: dir, speedH, speedV);
918 if (!isValidDir)
919 return;
920 sead::Quatf quat;
921 makeQuatUpFront(outQuat: &quat, up: -getGravity(actor), front: -dir);
922 updatePoseQuat(actor, quat);
923}
924
925bool isVelocityFast(const LiveActor* actor, f32 threshold) {
926 return getVelocity(actor).squaredLength() > sead::Mathf::square(t: threshold);
927}
928
929bool isVelocityFastH(const LiveActor* actor, f32 threshold) {
930 sead::Vector3f velocity = getVelocity(actor);
931 verticalizeVec(out: &velocity, vertical: getGravity(actor), vec: velocity);
932 return sead::Mathf::square(t: threshold) < velocity.squaredLength();
933}
934
935bool isVelocitySlow(const LiveActor* actor, f32 threshold) {
936 return getVelocity(actor).squaredLength() < sead::Mathf::square(t: threshold);
937}
938
939bool isVelocitySlowH(const LiveActor* actor, f32 threshold) {
940 sead::Vector3f velocity = getVelocity(actor);
941 verticalizeVec(out: &velocity, vertical: getGravity(actor), vec: velocity);
942 return velocity.squaredLength() < sead::Mathf::square(t: threshold);
943}
944
945f32 calcSpeedH(const LiveActor* actor) {
946 sead::Vector3f velocityH;
947 verticalizeVec(out: &velocityH, vertical: getGravity(actor), vec: getVelocity(actor));
948 return velocityH.length();
949}
950
951f32 calcSpeedV(const LiveActor* actor) {
952 return -getVelocity(actor).dot(t: getGravity(actor));
953}
954
955f32 calcSpeedDirection(const LiveActor* actor, const sead::Vector3f& dir) {
956 return sead::Mathf::abs(x: getVelocity(actor).dot(t: dir));
957}
958
959f32 calcSpeedExceptDir(const LiveActor* actor, const sead::Vector3f& dir) {
960 sead::Vector3f velocityExceptDir = {0.0f, 0.0f, 0.0f};
961 verticalizeVec(out: &velocityExceptDir, vertical: dir, vec: getVelocity(actor));
962 return velocityExceptDir.length();
963}
964
965bool isNear(const LiveActor* actor, const LiveActor* target, f32 threshold) {
966 return isNear(actor, trans: getTrans(actor: target), threshold);
967}
968
969bool isNear(const LiveActor* actor, const sead::Vector3f& trans, f32 threshold) {
970 return (getTrans(actor) - trans).squaredLength() < sead::Mathf::square(t: threshold);
971}
972
973bool isNearXZ(const LiveActor* actor, const sead::Vector3f& trans, f32 threshold) {
974 const sead::Vector3f& actorTrans = getTrans(actor);
975 return sead::Mathf::square(t: actorTrans.x - trans.x) +
976 sead::Mathf::square(t: actorTrans.z - trans.z) <
977 sead::Mathf::square(t: threshold);
978}
979
980bool isNearH(const LiveActor* actor, const sead::Vector3f& trans, f32 threshold) {
981 return calcDistanceH(actor, trans) < threshold;
982}
983
984f32 calcDistanceH(const LiveActor* actor, const sead::Vector3f& trans) {
985 sead::Vector3f dist;
986 verticalizeVec(out: &dist, vertical: getGravity(actor), vec: trans - getTrans(actor));
987 return dist.length();
988}
989
990bool isNearV(const LiveActor* actor, const sead::Vector3f& trans, f32 threshold) {
991 return calcDistanceV(actor, trans) < threshold;
992}
993
994f32 calcDistanceV(const LiveActor* actor, const sead::Vector3f& trans) {
995 const sead::Vector3f& gravity = getGravity(actor);
996 return sead::Mathf::abs(x: (trans - getTrans(actor)).dot(t: gravity));
997}
998
999bool isNearHV(const LiveActor* actor, const sead::Vector3f& trans, f32 threshH, f32 threshV) {
1000 if (calcDistanceV(actor, trans) > threshV)
1001 return false;
1002 return isNearH(actor, trans, threshold: threshH);
1003}
1004
1005bool isNearHV(const LiveActor* actor, const sead::Vector3f& trans, f32 threshH, f32 minV,
1006 f32 maxV) {
1007 f32 height = calcHeight(actor, trans);
1008 if (height < minV || height > maxV)
1009 return false;
1010 return isNearH(actor, trans, threshold: threshH);
1011}
1012
1013f32 calcHeight(const LiveActor* actor, const sead::Vector3f& trans) {
1014 const sead::Vector3f& gravity = getGravity(actor);
1015 return -(trans - getTrans(actor)).dot(t: gravity);
1016}
1017
1018bool isFar(const LiveActor* actor, const LiveActor* target, f32 threshold) {
1019 return isFar(actor, trans: getTrans(actor: target), threshold);
1020}
1021
1022bool isFar(const LiveActor* actor, const sead::Vector3f& trans, f32 threshold) {
1023 return (getTrans(actor) - trans).squaredLength() > sead::Mathf::square(t: threshold);
1024}
1025
1026f32 calcDistance(const LiveActor* actor, const LiveActor* target) {
1027 return calcDistance(actor, trans: getTrans(actor: target));
1028}
1029
1030f32 calcDistance(const LiveActor* actor, const sead::Vector3f& trans) {
1031 return (getTrans(actor) - trans).length();
1032}
1033
1034f32 calcDistanceV(const LiveActor* actor, const LiveActor* target) {
1035 return calcDistanceV(actor, trans: getTrans(actor: target));
1036}
1037
1038f32 calcDistanceH(const LiveActor* actor, const LiveActor* target) {
1039 return calcDistanceH(actor, trans: getTrans(actor: target));
1040}
1041
1042f32 calcDistanceH(const LiveActor* actor, const sead::Vector3f& trans1,
1043 const sead::Vector3f& trans2) {
1044 sead::Vector3f dist;
1045 verticalizeVec(out: &dist, vertical: getGravity(actor), vec: trans2 - trans1);
1046 return dist.length();
1047}
1048
1049f32 calcHeight(const LiveActor* actor, const LiveActor* target) {
1050 return calcHeight(actor, trans: getTrans(actor: target));
1051}
1052
1053f32 calcDistanceFront(const LiveActor* actor, const sead::Vector3f& trans) {
1054 sead::Vector3f front;
1055 calcFrontDir(front: &front, actor);
1056 return (trans - getTrans(actor)).dot(t: front);
1057}
1058
1059f32 calcDistanceFront(const LiveActor* actor, const LiveActor* target) {
1060 return calcDistanceFront(actor, trans: getTrans(actor: target));
1061}
1062
1063void addRotateAndRepeatX(LiveActor* actor, f32 deg) {
1064 setRotateX(actor, x: modDegree(deg: getRotate(actor).x + deg));
1065}
1066
1067void addRotateAndRepeatY(LiveActor* actor, f32 deg) {
1068 setRotateY(actor, y: modDegree(deg: getRotate(actor).y + deg));
1069}
1070
1071void addRotateAndRepeatZ(LiveActor* actor, f32 deg) {
1072 setRotateZ(actor, z: modDegree(deg: getRotate(actor).z + deg));
1073}
1074
1075void addRandomRotateY(LiveActor* actor) {
1076 addRotateAndRepeatY(actor, deg: getRandomDegree());
1077}
1078
1079void calcQuatSide(sead::Vector3f* side, const LiveActor* actor) {
1080 calcQuatSide(out: side, quat: getQuat(actor));
1081}
1082
1083void calcQuatUp(sead::Vector3f* up, const LiveActor* actor) {
1084 calcQuatUp(out: up, quat: getQuat(actor));
1085}
1086
1087void calcQuatFront(sead::Vector3f* front, const LiveActor* actor) {
1088 calcQuatFront(out: front, quat: getQuat(actor));
1089}
1090
1091void calcQuatLocalAxis(sead::Vector3f* local, const LiveActor* actor, s32 axis) {
1092 calcQuatLocalAxis(local, getQuat(actor), axis);
1093}
1094
1095void calcTransOffsetFront(sead::Vector3f* offset, const LiveActor* actor, f32 len) {
1096 multVecPose(posOut: offset, actor, posIn: {0.0f, 0.0f, len});
1097}
1098
1099void calcTransOffsetUp(sead::Vector3f* offset, const LiveActor* actor, f32 len) {
1100 multVecPose(posOut: offset, actor, posIn: {0.0f, len, 0.0f});
1101}
1102
1103void calcTransOffsetSide(sead::Vector3f* offset, const LiveActor* actor, f32 len) {
1104 multVecPose(posOut: offset, actor, posIn: {len, 0.0f, 0.0f});
1105}
1106
1107void setTransOffsetLocalDir(LiveActor* actor, const sead::Quatf& quat,
1108 const sead::Vector3f& globalOffset, f32 localOffset, s32 axis) {
1109 sead::Vector3f offset;
1110 calcQuatLocalAxis(&offset, quat, axis);
1111 getTransPtr(actor)->setScaleAdd(t: localOffset, a: offset, b: globalOffset);
1112}
1113
1114void addTransOffsetLocal(LiveActor* actor, const sead::Vector3f& localOffset) {
1115 sead::Quatf quat = sead::Quatf::unit;
1116 calcQuat(quat: &quat, actor);
1117 sead::Vector3f offset;
1118 offset.setRotated(q: quat, a: localOffset);
1119 *getTransPtr(actor) += offset;
1120}
1121
1122void addTransOffsetLocalDir(LiveActor* actor, f32 localOffset, s32 axis) {
1123 setTransOffsetLocalDir(actor, quat: getQuat(actor), globalOffset: getTrans(actor), localOffset, axis);
1124}
1125
1126void rotateQuatXDirDegree(LiveActor* actor, f32 deg) {
1127 sead::Quatf* quat = getQuatPtr(actor);
1128 rotateQuatXDirDegree(quat, *quat, deg);
1129}
1130
1131void rotateQuatXDirDegree(LiveActor* actor, const sead::Quatf& quat, f32 deg) {
1132 rotateQuatXDirDegree(getQuatPtr(actor), quat, deg);
1133}
1134
1135void rotateQuatYDirDegree(LiveActor* actor, f32 deg) {
1136 sead::Quatf* quat = getQuatPtr(actor);
1137 rotateQuatYDirDegree(quat, *quat, deg);
1138}
1139
1140void rotateQuatYDirDegree(LiveActor* actor, const sead::Quatf& quat, f32 deg) {
1141 rotateQuatYDirDegree(getQuatPtr(actor), quat, deg);
1142}
1143
1144void rotateQuatZDirDegree(LiveActor* actor, f32 deg) {
1145 sead::Quatf* quat = getQuatPtr(actor);
1146 rotateQuatZDirDegree(quat, *quat, deg);
1147}
1148
1149void rotateQuatZDirDegree(LiveActor* actor, const sead::Quatf& quat, f32 deg) {
1150 rotateQuatZDirDegree(getQuatPtr(actor), quat, deg);
1151}
1152
1153void rotateQuatLocalDirDegree(LiveActor* actor, s32 axis, f32 deg) {
1154 sead::Quatf* quat = getQuatPtr(actor);
1155 rotateQuatLocalDirDegree(quat, *quat, axis, deg);
1156}
1157
1158void rotateQuatLocalDirDegree(LiveActor* actor, const sead::Quatf& quat, s32 axis, f32 deg) {
1159 rotateQuatLocalDirDegree(getQuatPtr(actor), quat, axis, deg);
1160}
1161
1162void rotateQuatYDirRandomDegree(LiveActor* actor) {
1163 sead::Quatf* quat = getQuatPtr(actor);
1164 rotateQuatYDirDegree(quat, *quat, getRandomDegree());
1165}
1166
1167void rotateQuatYDirRandomDegree(LiveActor* actor, const sead::Quatf& quat) {
1168 rotateQuatYDirDegree(getQuatPtr(actor), quat, getRandomDegree());
1169}
1170
1171bool turnQuatFrontToDirDegreeH(LiveActor* actor, const sead::Vector3f& dir, f32 deg) {
1172 return turnQuatFrontToDirDegreeH(getQuatPtr(actor), dir, deg);
1173}
1174
1175bool turnQuatFrontToPosDegreeH(LiveActor* actor, const sead::Vector3f& pos, f32 deg) {
1176 sead::Vector3f dir;
1177 dir.setSub(a: pos, b: getTrans(actor));
1178 return turnQuatFrontToDirDegreeH(actor, dir, deg);
1179}
1180
1181bool turnQuatFrontFromPosDegreeH(LiveActor* actor, const sead::Vector3f& pos, f32 deg) {
1182 sead::Vector3f dir;
1183 dir.setSub(a: getTrans(actor), b: pos);
1184 return turnQuatFrontToDirDegreeH(actor, dir, deg);
1185}
1186
1187void turnFront(LiveActor* actor, f32 deg) {
1188 sead::Vector3f up = sead::Vector3f::ey;
1189 calcUpDir(up: &up, actor);
1190 turnFront(actor, up, deg);
1191}
1192
1193void turnFront(LiveActor* actor, const sead::Vector3f& up, f32 deg) {
1194 sead::Vector3f* front = getFrontPtr(actor);
1195 rotateVectorDegree(front, *front, up, deg);
1196 normalize(vec: getFrontPtr(actor));
1197}
1198
1199void turnFrontToPos(LiveActor* actor, const sead::Vector3f& pos, f32 deg) {
1200 turnFrontToDir(actor, dir: pos - getTrans(actor), deg);
1201}
1202
1203void turnFrontToDir(LiveActor* actor, const sead::Vector3f& dir, f32 deg) {
1204 turnFrontToDirGetIsFinished(actor, dir, deg);
1205}
1206
1207bool turnFrontToDirGetIsFinished(LiveActor* actor, const sead::Vector3f& dir, f32 deg) {
1208 sead::Vector3f up;
1209 calcFrontDir(front: &up, actor);
1210 bool finished = turnDirectionDegree(actor, vec: &up, dir, deg);
1211 rotateVectorDegree(getFrontPtr(actor), getFront(actor), up, deg);
1212 normalize(vec: getFrontPtr(actor));
1213 return finished;
1214}
1215
1216bool turnDirectionDegree(const LiveActor* actor, sead::Vector3f* vec, const sead::Vector3f& dir,
1217 f32 deg) {
1218 f32 cos = sead::Mathf::cos(t: sead::Mathf::deg2rad(deg));
1219 return turnDirection(actor, vec, dir, cos);
1220}
1221
1222void turnFrontToTarget(LiveActor* actor, const LiveActor* target, f32 deg) {
1223 turnFrontToDir(actor, dir: getTrans(actor: target) - getTrans(actor), deg);
1224}
1225
1226void turnFrontFromTarget(LiveActor* actor, const LiveActor* target, f32 deg) {
1227 turnFrontToDir(actor, dir: getTrans(actor) - getTrans(actor: target), deg);
1228}
1229
1230bool turnFrontToPlayer(LiveActor* actor, f32 deg) {
1231 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1232 if (!tryFindNearestPlayerPos(&playerPos, actor))
1233 return false;
1234 turnFrontToDir(actor, dir: playerPos - getTrans(actor), deg);
1235 return true;
1236}
1237
1238bool turnFrontFromPlayer(LiveActor* actor, f32 deg) {
1239 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1240 if (!tryFindNearestPlayerPos(&playerPos, actor))
1241 return false;
1242 turnFrontToDir(actor, dir: getTrans(actor) - playerPos, deg);
1243 return true;
1244}
1245
1246bool turnDirection(const LiveActor* actor, sead::Vector3f* vec, const sead::Vector3f& dir,
1247 f32 cos) {
1248 return turnVecToVecCosOnPlane(vec, dir, getGravity(actor), cos);
1249}
1250
1251bool turnDirectionToTarget(const LiveActor* actor, sead::Vector3f* vec,
1252 const sead::Vector3f& target, f32 cos) {
1253 return turnDirection(actor, vec, dir: target - getTrans(actor), cos);
1254}
1255
1256bool turnDirectionToTargetDegree(const LiveActor* actor, sead::Vector3f* vec,
1257 const sead::Vector3f& target, f32 deg) {
1258 return turnDirectionDegree(actor, vec, dir: target - getTrans(actor), deg);
1259}
1260
1261bool turnDirectionFromTargetDegree(const LiveActor* actor, sead::Vector3f* vec,
1262 const sead::Vector3f& target, f32 deg) {
1263 return turnDirectionDegree(actor, vec, dir: getTrans(actor) - target, deg);
1264}
1265
1266void turnDirectionAlongGround(const LiveActor* actor, sead::Vector3f* dir) {
1267 sead::Vector3f down;
1268 if (isCollidedGround(actor))
1269 down = -getOnGroundNormal(actor, 0);
1270 else
1271 down.set(getGravity(actor));
1272
1273 verticalizeVec(out: dir, vertical: down, vec: *dir);
1274 normalize(vec: dir);
1275}
1276
1277void turnDirectionAlongGround(LiveActor* actor) {
1278 if (tryGetQuatPtr(actor)) {
1279 sead::Vector3f ground;
1280 calcFrontDir(front: &ground, actor);
1281
1282 sead::Vector3f down;
1283 if (isCollidedGround(actor))
1284 down = -getOnGroundNormal(actor, 0);
1285 else
1286 down.set(getGravity(actor));
1287
1288 verticalizeVec(out: &ground, vertical: down, vec: ground);
1289 if (!tryNormalizeOrZero(out: &ground))
1290 return;
1291
1292 turnToDirectionAxis(actor, horizontal: ground, vertical: -down, deg: 180.0f);
1293 } else if (getFrontPtr(actor)) {
1294 turnDirectionAlongGround(actor, dir: getFrontPtr(actor));
1295 }
1296}
1297
1298bool turnToDirectionAxis(LiveActor* actor, const sead::Vector3f& horizontal,
1299 const sead::Vector3f& vertical, f32 deg) {
1300 sead::Vector3f front = {0.0f, 0.0f, 0.0f};
1301 calcFrontDir(front: &front, actor);
1302 bool result = turnVecToVecCosOnPlane(&front, horizontal, vertical,
1303 sead::Mathf::cos(t: sead::Mathf::deg2rad(deg)));
1304
1305 sead::Quatf quat = sead::Quatf::unit;
1306 makeQuatUpFront(outQuat: &quat, up: vertical, front);
1307 updatePoseQuat(actor, quat);
1308 return result;
1309}
1310
1311bool turnFrontSpherical(const LiveActor* actor, sead::Vector3f* vec,
1312 const sead::Vector3f& targetFront, f32 cos) {
1313 sead::Vector3f front;
1314 calcFrontDir(front: &front, actor);
1315 sead::Vector3f axis;
1316 axis.setCross(a: front, b: targetFront);
1317 if (isNearZero(vec: axis, tolerance: 0.001f))
1318 calcUpDir(up: &axis, actor);
1319 normalize(vec: &axis);
1320 normalize(vec: &front);
1321 return turnVecToVecCosOnPlane(vec, front, targetFront, axis, cos);
1322}
1323
1324bool turnFrontSphericalToTarget(const LiveActor* actor, sead::Vector3f* vec,
1325 const sead::Vector3f& target, f32 cos) {
1326 sead::Vector3f targetFront = target - getTrans(actor);
1327 if (!tryNormalizeOrZero(out: &targetFront)) {
1328 calcFrontDir(front: vec, actor);
1329 return true;
1330 }
1331 return turnFrontSpherical(actor, vec, targetFront, cos);
1332}
1333
1334bool turnFrontSphericalToTargetDegree(const LiveActor* actor, sead::Vector3f* vec,
1335 const sead::Vector3f& target, f32 deg) {
1336 return turnFrontSphericalToTarget(actor, vec, target,
1337 cos: sead::Mathf::cos(t: sead::Mathf::deg2rad(deg)));
1338}
1339
1340bool turnToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 deg) {
1341 sead::Vector3f vec;
1342 calcFrontDir(front: &vec, actor);
1343 bool result = turnDirectionDegree(actor, vec: &vec, dir, deg);
1344
1345 sead::Quatf quat;
1346 makeQuatUpFront(outQuat: &quat, up: -getGravity(actor), front: vec);
1347 updatePoseQuat(actor, quat);
1348 return result;
1349}
1350
1351void turnLocalDirToDirection(LiveActor* actor, const sead::Vector3f& localDir,
1352 const sead::Vector3f& targetDir, f32 deg) {
1353 sead::Quatf quat;
1354 calcQuat(quat: &quat, actor);
1355 sead::Vector3f globalDir = localDir;
1356 rotateVectorQuat(&globalDir, quat);
1357
1358 sead::Quatf quat2;
1359 makeQuatRotationLimit(&quat2, globalDir, targetDir, sead::Mathf::deg2rad(deg));
1360
1361 quat2 *= quat;
1362 updatePoseQuat(actor, quat: quat2);
1363}
1364
1365bool turnToTarget(LiveActor* actor, const sead::Vector3f& target, f32 deg) {
1366 sead::Vector3f dir = target - getTrans(actor);
1367 if (!tryNormalizeOrZero(out: &dir))
1368 return false;
1369 return turnToDirection(actor, dir, deg);
1370}
1371
1372bool turnToTarget(LiveActor* actor, const LiveActor* target, f32 deg) {
1373 return turnToTarget(actor, target: getTrans(actor: target), deg);
1374}
1375
1376void faceToDirection(LiveActor* actor, const sead::Vector3f& dir) {
1377 if (isParallelDirection(a: dir, b: getGravity(actor), tolerance: 0.01f))
1378 return;
1379
1380 sead::Quatf quat;
1381 makeQuatUpFront(outQuat: &quat, up: -getGravity(actor), front: dir);
1382 updatePoseQuat(actor, quat);
1383}
1384
1385void faceToDirectionSupportUp(LiveActor* actor, const sead::Vector3f& dir) {
1386 sead::Vector3f up = {0.0f, 0.0f, 0.0f};
1387 calcUpDir(up: &up, actor);
1388 if (isParallelDirection(a: dir, b: up, tolerance: 0.01f))
1389 return;
1390
1391 sead::Quatf quat;
1392 makeQuatFrontUp(outQuat: &quat, front: dir, up);
1393 updatePoseQuat(actor, quat);
1394}
1395
1396void faceToTarget(LiveActor* actor, const sead::Vector3f& target) {
1397 sead::Vector3f direction = target - getTrans(actor);
1398 if (!tryNormalizeOrZero(out: &direction))
1399 return;
1400 faceToDirection(actor, dir: direction);
1401}
1402
1403void faceToTarget(LiveActor* actor, const LiveActor* target) {
1404 faceToTarget(actor, target: getTrans(actor: target));
1405}
1406
1407void faceToSensor(LiveActor* actor, const HitSensor* sensor) {
1408 faceToTarget(actor, target: getSensorPos(sensor));
1409}
1410
1411void faceToVelocity(LiveActor* actor) {
1412 sead::Vector3f direction = getVelocity(actor);
1413 if (!tryNormalizeOrZero(out: &direction))
1414 return;
1415 faceToDirection(actor, dir: direction);
1416}
1417
1418void calcDirClockwiseToDir(sead::Vector3f* out, const LiveActor* actor, const sead::Vector3f& dir) {
1419 sead::Vector3f result;
1420 result.setCross(a: getGravity(actor), b: dir);
1421 tryNormalizeOrZero(out, vec: result);
1422}
1423
1424void calcDirClockwiseToPos(sead::Vector3f* out, const LiveActor* actor,
1425 const sead::Vector3f& target) {
1426 calcDirClockwiseToDir(out, actor, dir: target - getTrans(actor));
1427}
1428
1429void calcDirToActorH(sead::Vector3f* out, const LiveActor* actor, const LiveActor* target) {
1430 calcDirToActorH(out, actor, dir: getTrans(actor: target));
1431}
1432
1433void calcDirToActorH(sead::Vector3f* out, const LiveActor* actor, const sead::Vector3f& target) {
1434 out->setSub(a: target, b: getTrans(actor));
1435 verticalizeVec(out, vertical: getGravity(actor), vec: *out);
1436 tryNormalizeOrZero(out);
1437}
1438
1439f32 calcAngleToTargetH(const LiveActor* actor, const sead::Vector3f& target) {
1440 sead::Vector3f front = {0.0f, 0.0f, 0.0f};
1441 sead::Vector3f up = {0.0f, 0.0f, 0.0f};
1442 sead::Vector3f dir = {0.0f, 0.0f, 0.0f};
1443 calcFrontDir(front: &front, actor);
1444 calcUpDir(up: &up, actor);
1445 dir.setSub(a: target, b: getTrans(actor));
1446 if (!tryNormalizeOrZero(out: &dir))
1447 return 0.0f;
1448 return calcAngleOnPlaneDegree(a: front, b: dir, vertical: up);
1449}
1450
1451f32 calcAngleToTargetV(const LiveActor* actor, const sead::Vector3f& target) {
1452 sead::Vector3f front = {0.0f, 0.0f, 0.0f};
1453 sead::Vector3f side = {0.0f, 0.0f, 0.0f};
1454 sead::Vector3f dir = {0.0f, 0.0f, 0.0f};
1455 calcFrontDir(front: &front, actor);
1456 calcSideDir(side: &side, actor);
1457 dir.setSub(a: target, b: getTrans(actor));
1458 if (!tryNormalizeOrZero(out: &dir))
1459 return 0.0f;
1460 return calcAngleOnPlaneDegree(a: front, b: dir, vertical: side);
1461}
1462
1463bool isFaceToTargetDegree(const LiveActor* actor, const sead::Vector3f& target,
1464 const sead::Vector3f& face, f32 threshDeg) {
1465 return isNearAngleDegree(a: target - getTrans(actor), b: face, tolerance: threshDeg);
1466}
1467
1468bool isFaceToTargetDegree(const LiveActor* actor, const sead::Vector3f& target, f32 threshDeg) {
1469 sead::Vector3f front;
1470 calcFrontDir(front: &front, actor);
1471 return isNearAngleDegree(a: target - getTrans(actor), b: front, tolerance: threshDeg);
1472}
1473
1474bool isFaceToTargetDegreeHV(const LiveActor* actor, const sead::Vector3f& target,
1475 const sead::Vector3f& face, f32 degH, f32 degV) {
1476 return isNearAngleDegreeHV(a: target - getTrans(actor), b: face, c: getGravity(actor), toleranceH: degH, toleranceV: degV);
1477}
1478
1479bool isFaceToTargetDegreeH(const LiveActor* actor, const sead::Vector3f& target,
1480 const sead::Vector3f& face, f32 degH) {
1481 sead::Vector3f diff = target;
1482 diff -= getTrans(actor);
1483 verticalizeVec(out: &diff, vertical: getGravity(actor), vec: diff);
1484 sead::Vector3f alignedFace;
1485 verticalizeVec(out: &alignedFace, vertical: getGravity(actor), vec: face);
1486 return isNearAngleDegree(a: diff, b: alignedFace, tolerance: degH);
1487}
1488
1489bool isInSightCone(const LiveActor* actor, const sead::Vector3f& target, const sead::Vector3f& face,
1490 f32 maxDist, f32 threshDeg) {
1491 return (getTrans(actor) - target).squaredLength() < sead::Mathf::square(t: maxDist) &&
1492 isFaceToTargetDegree(actor, target, face, threshDeg);
1493}
1494
1495bool isInSightConeTarget(const LiveActor* actor, const LiveActor* target, f32 maxDist,
1496 f32 threshDeg) {
1497 sead::Vector3f front;
1498 calcFrontDir(front: &front, actor);
1499 return isInSightCone(actor, target: getTrans(actor: target), face: front, maxDist, threshDeg);
1500}
1501
1502bool isInSightConePlayer(const LiveActor* actor, f32 maxDist, f32 threshDeg) {
1503 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1504 if (!tryFindNearestPlayerPos(&playerPos, actor))
1505 return false;
1506 sead::Vector3f front;
1507 calcFrontDir(front: &front, actor);
1508 return isInSightCone(actor, target: playerPos, face: front, maxDist, threshDeg);
1509}
1510
1511bool isInSightFan(const LiveActor* actor, const sead::Vector3f& target, const sead::Vector3f& face,
1512 f32 maxDist, f32 angleH, f32 angleV) {
1513 return (getTrans(actor) - target).squaredLength() < sead::Mathf::square(t: maxDist) &&
1514 isFaceToTargetDegreeHV(actor, target, face, degH: angleH, degV: angleV);
1515}
1516
1517bool isInSightFanTarget(const LiveActor* actor, const LiveActor* target, f32 maxDist, f32 angleH,
1518 f32 angleV) {
1519 sead::Vector3f front = sead::Vector3f::ez;
1520 calcFrontDir(front: &front, actor);
1521 return isInSightFan(actor, target: getTrans(actor: target), face: front, maxDist, angleH, angleV);
1522}
1523
1524bool isInSightBox(const LiveActor* actor, const sead::Vector3f& pos, const sead::BoundBox3f& box) {
1525 sead::Vector3f localPos;
1526 multVecInvPose(posOut: &localPos, actor, posIn: pos);
1527 return box.isInside(p: localPos);
1528}
1529
1530void walkAndTurnToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 forceFront,
1531 f32 forceGravity, f32 decay, f32 deg, bool turnAlongGround) {
1532 walkAndTurnToDirection(actor, front: getFrontPtr(actor), dir, forceFront, forceGravity, decay, deg,
1533 turnAlongGround);
1534}
1535
1536void walkAndTurnToDirection(LiveActor* actor, sead::Vector3f* front, const sead::Vector3f& dir,
1537 f32 forceFront, f32 forceGravity, f32 decay, f32 deg,
1538 bool turnAlongGround) {
1539 turnDirection(actor, vec: front, dir, cos: sead::Mathf::cos(t: sead::Mathf::deg2rad(deg)));
1540 if (turnAlongGround)
1541 turnDirectionAlongGround(actor);
1542
1543 sead::Vector3f velFront;
1544 tryNormalizeOrZero(out: &velFront, vec: *front);
1545 addVelocityInline(actor, vel: velFront, force: forceFront);
1546
1547 if (!isOnGround(actor, 3))
1548 addVelocityToGravity(actor, force: forceGravity);
1549
1550 scaleVelocity(actor, factor: decay);
1551}
1552
1553void walkAndTurnPoseToDirection(LiveActor* actor, const sead::Vector3f& dir,
1554 const ActorParamMove& param, bool turnAlongGround) {
1555 sead::Vector3f* frontPtr;
1556 sead::Vector3f frontForQuat;
1557 if (getQuatPtr(actor)) {
1558 frontPtr = &frontForQuat;
1559 calcFrontDir(front: &frontForQuat, actor);
1560 turnToDirection(actor, dir, deg: param.turnDegrees);
1561 } else if (getFrontPtr(actor)) {
1562 frontPtr = getFrontPtr(actor);
1563 turnDirectionDegree(actor, vec: frontPtr, dir, deg: param.turnDegrees);
1564 } else
1565 return;
1566
1567 if (turnAlongGround)
1568 turnDirectionAlongGround(actor);
1569
1570 f32 forceFront = param.forceFront;
1571 sead::Vector3f velFront;
1572 tryNormalizeOrZero(out: &velFront, vec: *frontPtr);
1573 addVelocityInline(actor, vel: velFront, force: forceFront);
1574
1575 if (!isOnGround(actor, 3))
1576 addVelocityToGravity(actor, force: param.forceGravity);
1577
1578 // BUG: should have been param.decay (_8)
1579 scaleVelocity(actor, factor: param.forceFront);
1580}
1581
1582void walkAndTurnToTarget(LiveActor* actor, const sead::Vector3f& target, f32 forceFront,
1583 f32 forceGravity, f32 decay, f32 deg, bool turnAlongGround) {
1584 sead::Vector3f dir = target - getTrans(actor);
1585 walkAndTurnToDirection(actor, dir, forceFront, forceGravity, decay, deg, turnAlongGround);
1586}
1587
1588void flyAndTurnToDirection(LiveActor* actor, sead::Vector3f* front, const sead::Vector3f& dir,
1589 f32 forceFront, f32 forceGravity, f32 decay, f32 deg) {
1590 sead::Vector3f normFrontH, actorFront, frontH;
1591
1592 calcFrontDir(front: &actorFront, actor);
1593 turnDirectionDegree(actor, vec: &actorFront, dir, deg);
1594 turnVecToVecDegree(front, *front, actorFront, deg);
1595
1596 calcFrontDir(front: &frontH, actor);
1597 verticalizeVec(out: &frontH, vertical: getGravity(actor), vec: frontH);
1598 normalize(vec: &frontH);
1599
1600 tryNormalizeOrZero(out: &normFrontH, vec: frontH);
1601 addVelocityInline(actor, vel: normFrontH, force: forceFront);
1602 addVelocityToGravity(actor, force: forceGravity);
1603 scaleVelocity(actor, factor: decay);
1604}
1605
1606void flyAndTurnToDirection(LiveActor* actor, const sead::Vector3f& dir, f32 forceFront,
1607 f32 forceGravity, f32 decay, f32 deg) {
1608 flyAndTurnToDirection(actor, front: getFrontPtr(actor), dir, forceFront, forceGravity, decay, deg);
1609}
1610
1611void flyAndTurnToTarget(LiveActor* actor, const sead::Vector3f& target, f32 forceFront,
1612 f32 forceGravity, f32 decay, f32 deg) {
1613 flyAndTurnToDirection(actor, dir: target - getTrans(actor), forceFront, forceGravity, decay, deg);
1614}
1615
1616bool walkAndTurnToDirectionFittedGroundGravity(LiveActor* actor, sead::Vector3f* front,
1617 const sead::Vector3f& dir, f32 forceFront,
1618 f32 forceGravity, f32 decay, f32 deg,
1619 bool turnAlongGround) {
1620 turnDirection(actor, vec: front, dir, cos: sead::Mathf::cos(t: sead::Mathf::deg2rad(deg)));
1621 if (turnAlongGround)
1622 turnDirectionAlongGround(actor, dir: front);
1623
1624 sead::Vector3f velFront;
1625 tryNormalizeOrZero(out: &velFront, vec: *front);
1626 addVelocityInline(actor, vel: velFront, force: forceFront);
1627
1628 bool isOnGround = isOnGroundNoVelocity(actor, 3);
1629 if (isOnGround)
1630 addVelocityToGravityFittedGround(actor, force: forceGravity, maxAirTime: 3);
1631 else
1632 addVelocityToGravity(actor, force: forceGravity);
1633
1634 scaleVelocity(actor, factor: decay);
1635 return isOnGround;
1636}
1637
1638bool walkAndTurnToDirectionFittedGroundGravity(LiveActor* actor, const sead::Vector3f& dir,
1639 f32 forceFront, f32 forceGravity, f32 decay, f32 deg,
1640 bool turnAlongGround) {
1641 return walkAndTurnToDirectionFittedGroundGravity(actor, front: getFrontPtr(actor), dir, forceFront,
1642 forceGravity, decay, deg, turnAlongGround);
1643}
1644
1645bool walkAndTurnToTargetFittedGroundGravity(LiveActor* actor, const sead::Vector3f& target,
1646 f32 forceFront, f32 forceGravity, f32 decay, f32 deg,
1647 bool turnAlongGround) {
1648 return walkAndTurnToDirectionFittedGroundGravity(actor, dir: target - getTrans(actor), forceFront,
1649 forceGravity, decay, deg, turnAlongGround);
1650}
1651
1652bool tryKillByDeathArea(LiveActor* actor) {
1653 if (!isInDeathArea(areaUser: actor, position: getTrans(actor)))
1654 return false;
1655 actor->kill();
1656 return true;
1657}
1658
1659void rotateAndKeepColliderPosRate(LiveActor* actor, const sead::Vector3f& up,
1660 const sead::Vector3f& front, f32 rate) {
1661 sead::Vector3f colliderPos = {0.0f, 0.0f, 0.0f};
1662 calcColliderPos(&colliderPos, actor);
1663
1664 sead::Vector3f localColliderPos;
1665 sead::Matrix34f mtx;
1666 makeMtxRT(mtx: &mtx, actor);
1667 calcMtxLocalTrans(&localColliderPos, mtx, colliderPos);
1668
1669 sead::Quatf quat;
1670 makeQuatUpFront(outQuat: &quat, up, front);
1671 slerpQuat(getQuatPtr(actor), getQuat(actor), quat, rate);
1672
1673 sead::Matrix34f mtx2;
1674 makeMtxRT(mtx: &mtx2, actor);
1675
1676 sead::Vector3f newColliderPos = {0.0f, 0.0f, 0.0f};
1677 calcTransLocalOffsetByMtx(&newColliderPos, mtx2, localColliderPos);
1678 sead::Vector3f colliderOffset = colliderPos - newColliderPos;
1679
1680 *getTransPtr(actor) += colliderOffset;
1681 resetPosition(actor);
1682}
1683
1684void calcSpringMovement(LiveActor* actor, const sead::Vector3f& pos, f32 springPos, f32 sinStrength,
1685 const sead::Vector3f& offset, f32 constStrength, f32 sinAmpl) {
1686 f32 sinPart = sead::Mathf::sin(t: sead::Mathf::clamp(value: springPos, low: 0.0f, high: 1.0f) * 2 *
1687 sead::Mathf::pi() * sinAmpl) *
1688 (1.0f - springPos) * sinStrength;
1689 f32 constPart = (1.0f - springPos) * constStrength;
1690 getTransPtr(actor)->setScaleAdd(t: sinPart + constPart, a: offset, b: pos);
1691}
1692
1693bool addVelocityClockwiseToPlayer(LiveActor* actor, f32 force) {
1694 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1695 if (!tryFindNearestPlayerPos(&playerPos, actor))
1696 return false;
1697 addVelocityClockwiseToDirection(actor, dir: playerPos - getTrans(actor), force);
1698 return true;
1699}
1700
1701bool calcDirClockwiseToPlayer(sead::Vector3f* dir, const LiveActor* actor) {
1702 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1703 if (!tryFindNearestPlayerPos(&playerPos, actor))
1704 return false;
1705 // BUG: should have been calcDirClockwiseToPos
1706 calcDirClockwiseToDir(out: dir, actor, dir: playerPos);
1707 return true;
1708}
1709
1710bool flyAndTurnToPlayer(LiveActor* actor, const ActorParamMove& param) {
1711 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1712 if (!tryFindNearestPlayerPos(&playerPos, actor))
1713 return false;
1714 flyAndTurnToTarget(actor, target: playerPos, forceFront: param.forceFront, forceGravity: param.forceGravity, decay: param.decay,
1715 deg: param.turnDegrees);
1716 return true;
1717}
1718
1719bool escapeFromPlayer(LiveActor* actor, f32 forceFront, f32 forceGravity, f32 decay, f32 deg) {
1720 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1721 if (!tryFindNearestPlayerPos(&playerPos, actor))
1722 return false;
1723 walkAndTurnToDirection(actor, dir: getTrans(actor) - playerPos, forceFront, forceGravity, decay, deg,
1724 turnAlongGround: true);
1725 return true;
1726}
1727
1728bool escapeFromPlayer(LiveActor* actor, sead::Vector3f* front, f32 forceFront, f32 forceGravity,
1729 f32 decay, f32 deg) {
1730 sead::Vector3f playerPos = {0.0f, 0.0f, 0.0f};
1731 if (!tryFindNearestPlayerPos(&playerPos, actor))
1732 return false;
1733 walkAndTurnToDirection(actor, front, dir: getTrans(actor) - playerPos, forceFront, forceGravity,
1734 decay, deg, turnAlongGround: true);
1735 return true;
1736}
1737
1738bool walkAndTurnToPlayer(LiveActor* actor, f32 forceFront, f32 forceGravity, f32 decay, f32 deg,
1739 bool turnAlongGround) {
1740 sead::Vector3f playerPos;
1741 if (!tryFindNearestPlayerPos(&playerPos, actor))
1742 return false;
1743 return walkAndTurnToTargetFittedGroundGravity(actor, target: playerPos, forceFront, forceGravity, decay,
1744 deg, turnAlongGround);
1745}
1746
1747bool isPlayerInSightFan(const LiveActor* actor, f32 maxDist, f32 angleH, f32 angleV) {
1748 sead::Vector3f playerPos;
1749 if (!tryFindNearestPlayerPos(&playerPos, actor))
1750 return false;
1751 sead::Vector3f front;
1752 calcFrontDir(front: &front, actor);
1753 return isInSightFan(actor, target: playerPos, face: front, maxDist, angleH, angleV);
1754}
1755
1756inline bool nextMove(Triangle* triangle, const LiveActor* actor, const sead::Vector3f& velocity,
1757 f32 gravity, f32 searchDist) {
1758 sead::Vector3f hitPos = {0.0f, 0.0f, 0.0f};
1759 sead::Vector3f pos = getTrans(actor) + velocity;
1760 pos.y += gravity;
1761
1762 return alCollisionUtil::getFirstPolyOnArrow(actor, &hitPos, triangle, pos,
1763 -sead::Vector3f::ey * searchDist, nullptr, nullptr);
1764}
1765
1766bool isFallOrDamageCodeNextMove(const LiveActor* actor, const sead::Vector3f& velocity, f32 gravity,
1767 f32 searchDist) {
1768 Triangle triangle;
1769 if (!nextMove(triangle: &triangle, actor, velocity, gravity, searchDist))
1770 return true;
1771 return isFloorCode(triangle, "DamageFire") || isFloorCode(triangle, "Poison");
1772}
1773
1774bool isFallNextMove(const LiveActor* actor, const sead::Vector3f& velocity, f32 gravity,
1775 f32 searchDist) {
1776 Triangle triangle;
1777 return !nextMove(triangle: &triangle, actor, velocity, gravity, searchDist);
1778}
1779
1780} // namespace al
1781