This commit is contained in:
GRAnimated 2026-04-23 03:49:38 +02:00 committed by GitHub
commit 205182e980
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 200 additions and 10 deletions

View file

@ -8728,46 +8728,46 @@ Boss/BossUtil/BossStateChasePlayer.o:
label:
- _ZN20BossStateChasePlayerC1EPKcPN2al9LiveActorEPK25BossStateChasePlayerParam
- _ZN20BossStateChasePlayerC2EPKcPN2al9LiveActorEPK25BossStateChasePlayerParam
status: NotDecompiled
status: Matching
- offset: 0x046500
size: 16
label: _ZN20BossStateChasePlayer6appearEv
status: NotDecompiled
status: Matching
- offset: 0x046510
size: 12
label: _ZN20BossStateChasePlayer9startStopEv
status: NotDecompiled
status: Matching
- offset: 0x04651c
size: 736
label: _ZN20BossStateChasePlayer8exeChaseEv
status: NotDecompiled
status: NonMatchingMajor
- offset: 0x0467fc
size: 276
label: _ZN20BossStateChasePlayer7exeLostEv
status: NotDecompiled
status: Matching
- offset: 0x046910
size: 180
label: _ZN20BossStateChasePlayer7exeStopEv
status: NotDecompiled
status: Matching
- offset: 0x0469c4
size: 36
label: _ZN20BossStateChasePlayerD0Ev
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x0469e8
size: 8
label: _ZNK12_GLOBAL__N_128BossStateChasePlayerNrvChase7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x0469f0
size: 180
label: _ZNK12_GLOBAL__N_127BossStateChasePlayerNrvStop7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x046aa4
size: 8
label: _ZNK12_GLOBAL__N_127BossStateChasePlayerNrvLost7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
Boss/BossUtil/BossStateTalkDemo.o:
'.text':

View file

@ -0,0 +1,156 @@
#include "Boss/BossUtil/BossStateChasePlayer.h"
#include <cmath>
#include "Library/LiveActor/ActorMovementFunction.h"
#include "Library/LiveActor/ActorPoseUtil.h"
#include "Library/Math/MathUtil.h"
#include "Library/Nerve/NerveSetupUtil.h"
#include "Library/Nerve/NerveUtil.h"
#include "Library/Player/PlayerUtil.h"
namespace {
NERVE_IMPL(BossStateChasePlayer, Chase)
NERVE_IMPL(BossStateChasePlayer, Stop)
NERVE_IMPL(BossStateChasePlayer, Lost)
NERVES_MAKE_NOSTRUCT(BossStateChasePlayer, Chase, Stop, Lost)
const BossStateChasePlayerParam sDefaultParam = {1.0f, 0.3f, 0.9f, 500.0f, 0.2f,
2.0f, 0.1f, 10.0f, 90.0f};
} // namespace
BossStateChasePlayer::BossStateChasePlayer(const char* name, al::LiveActor* actor,
const BossStateChasePlayerParam* param)
: al::ActorStateBase(name, actor), mParam(param) {
initNerve(&Chase, 0);
if (!param)
mParam = &sDefaultParam;
}
void BossStateChasePlayer::appear() {
al::NerveStateBase::appear();
al::setNerve(this, &Chase);
}
void BossStateChasePlayer::startStop() {
al::setNerve(this, &Stop);
}
// NON_MATCHING: https://decomp.me/scratch/pvWjE/ - Stack frame and register allocation differ
// (target uses d8-d11/x20-x21 as callee-saved regs, extra loads of mRotationAngle/mTargetPlayer
// early); dirToPlayer built on-stack with different field ordering; subtraction operand order
// flipped in several fsub instructions
void BossStateChasePlayer::exeChase() {
mTargetPlayer = al::tryFindAlivePlayerActorFirst(mActor);
if (!mTargetPlayer) {
al::setNerve(this, &Lost);
return;
}
// Compute direction from actor to player (horizontal only, for rotation)
sead::Vector3f dirToPlayer;
dirToPlayer = al::getTrans(mTargetPlayer);
const sead::Vector3f& actorTrans = al::getTrans(mActor);
dirToPlayer.x -= actorTrans.x;
dirToPlayer.y = 0.0f;
dirToPlayer.z -= actorTrans.z;
// Update rotation toward player
if (al::tryNormalizeOrZero(&dirToPlayer)) {
sead::Vector3f frontDir = sead::Vector3f::ez;
al::calcFrontDir(&frontDir, mActor);
f32 angle = al::calcAngleOnPlaneDegree(frontDir, dirToPlayer, sead::Vector3f::ey);
f32 sign = al::sign(angle);
// Choose turn speed based on whether we're already roughly facing the player
f32 turnSpeed;
if (angle <= -mParam->frontAngleThreshold || angle >= mParam->frontAngleThreshold)
turnSpeed = mParam->turnSpeedFast;
else
turnSpeed = mParam->turnSpeedSlow;
// Clamp rotation to turn speed, preserving sign
f32 absAngle = angle > 0.0f ? angle : -angle;
f32 absTurnSpeed = turnSpeed > 0.0f ? turnSpeed : -turnSpeed;
f32 targetRotation = sign * (absAngle < absTurnSpeed ? absAngle : absTurnSpeed);
mRotationAngle = al::converge(mRotationAngle, targetRotation, mParam->turnConvergeSpeed);
al::rotateQuatYDirDegree(mActor, mRotationAngle);
} else {
mRotationAngle = al::converge(mRotationAngle, 0.0f, mParam->turnConvergeSpeed);
}
// Compute current XZ speed
const sead::Vector3f& vel = al::getVelocity(mActor);
f32 speedXZ = sqrtf(vel.x * vel.x + vel.z * vel.z);
// Get fresh front direction after rotation
sead::Vector3f frontDir = sead::Vector3f::ez;
al::calcFrontDir(&frontDir, mActor);
// Recompute direction to player for speed logic
dirToPlayer = al::getTrans(mTargetPlayer);
const sead::Vector3f& actorTrans2 = al::getTrans(mActor);
dirToPlayer.x -= actorTrans2.x;
dirToPlayer.y = 0.0f;
dirToPlayer.z -= actorTrans2.z;
bool decelerate = false;
if (al::tryNormalizeOrZero(&dirToPlayer)) {
if (al::calcAngleDegree(frontDir, dirToPlayer) > mParam->chaseAngleMax)
decelerate = true;
}
f32 newSpeed;
if (!decelerate) {
// Check if close enough to stop accelerating
const sead::Vector3f& at = al::getTrans(mActor);
const sead::Vector3f& pt = al::getTrans(mTargetPlayer);
f32 dx = at.x - pt.x;
f32 dz = at.z - pt.z;
f32 dist = sqrtf(dx * dx + dz * dz);
if (dist <= mParam->proximityStopDist)
decelerate = true;
}
if (decelerate)
newSpeed = al::converge(speedXZ, 0.0f, mParam->deceleration);
else
newSpeed = speedXZ + mParam->acceleration;
al::setVelocityToDirection(mActor, frontDir, newSpeed);
al::scaleVelocityDirection(mActor, frontDir, mParam->scaleVelocity);
}
void BossStateChasePlayer::exeLost() {
const sead::Vector3f& vel = al::getVelocity(mActor);
f32 speed = sqrtf(vel.x * vel.x + vel.y * vel.y + vel.z * vel.z);
f32 newSpeed = al::converge(speed, 0.0f, mParam->deceleration);
sead::Vector3f newVelocity = al::getVelocity(mActor);
f32 len = sqrtf(newVelocity.x * newVelocity.x + newVelocity.y * newVelocity.y +
newVelocity.z * newVelocity.z);
if (len > 0.0f) {
f32 scale = newSpeed / len;
newVelocity.x *= scale;
newVelocity.y *= scale;
newVelocity.z *= scale;
}
al::setVelocity(mActor, newVelocity);
mTargetPlayer = al::tryFindAlivePlayerActorFirst(mActor);
if (mTargetPlayer)
al::setNerve(this, &Chase);
}
void BossStateChasePlayer::exeStop() {
const sead::Vector3f& vel = al::getVelocity(mActor);
f32 speedXZ = sqrtf(vel.x * vel.x + vel.z * vel.z);
f32 newSpeed = al::converge(speedXZ, 0.0f, mParam->deceleration);
al::setVelocityToDirection(mActor, al::getVelocity(mActor), newSpeed);
if (al::isNearZero(newSpeed, 0.001f))
kill();
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "Library/Nerve/NerveStateBase.h"
struct BossStateChasePlayerParam {
f32 acceleration;
f32 deceleration;
f32 scaleVelocity;
f32 proximityStopDist;
f32 turnSpeedSlow;
f32 turnSpeedFast;
f32 turnConvergeSpeed;
f32 frontAngleThreshold;
f32 chaseAngleMax;
};
class BossStateChasePlayer : public al::ActorStateBase {
public:
BossStateChasePlayer(const char* name, al::LiveActor* actor,
const BossStateChasePlayerParam* param);
void appear() override;
void startStop();
void exeChase();
void exeLost();
void exeStop();
private:
const BossStateChasePlayerParam* mParam = nullptr;
const al::LiveActor* mTargetPlayer = nullptr;
f32 mRotationAngle = 0.0f;
};