mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-04-23 09:04:21 +00:00
200 lines
8.3 KiB
C++
200 lines
8.3 KiB
C++
#include "Npc/SmallBirdStateFlyAway.h"
|
|
|
|
#include "Library/Collision/CollisionPartsKeeperUtil.h"
|
|
#include "Library/Collision/CollisionPartsTriangle.h"
|
|
#include "Library/LiveActor/ActorActionFunction.h"
|
|
#include "Library/LiveActor/ActorMovementFunction.h"
|
|
#include "Library/LiveActor/ActorPoseUtil.h"
|
|
#include "Library/LiveActor/LiveActor.h"
|
|
#include "Library/Math/MathUtil.h"
|
|
#include "Library/Nerve/NerveSetupUtil.h"
|
|
#include "Library/Nerve/NerveUtil.h"
|
|
|
|
#include "Util/NpcAnimUtil.h"
|
|
#include "Util/SpecialBuildUtil.h"
|
|
|
|
namespace {
|
|
NERVE_IMPL(SmallBirdStateFlyAway, FlyAway);
|
|
NERVE_IMPL(SmallBirdStateFlyAway, FlyAwayHomeLanding);
|
|
NERVE_IMPL(SmallBirdStateFlyAway, FlyAwayKoopa);
|
|
|
|
NERVES_MAKE_STRUCT(SmallBirdStateFlyAway, FlyAway, FlyAwayHomeLanding, FlyAwayKoopa);
|
|
} // namespace
|
|
|
|
SmallBirdStateFlyAway::SmallBirdStateFlyAway(al::LiveActor* actor)
|
|
: BirdStateFlyAwayBase("小鳥の飛び去り", actor) {
|
|
initNerve(&NrvSmallBirdStateFlyAway.FlyAway, 0);
|
|
}
|
|
|
|
void SmallBirdStateFlyAway::appear() {
|
|
BirdStateFlyAwayBase::appear();
|
|
mDisappearStep = al::getRandom(10) * 5 + 240;
|
|
if (isFlyAwayByHomeLanding()) {
|
|
mAngle = al::getRandom(45.0f, 70.0f);
|
|
al::setNerve(this, &NrvSmallBirdStateFlyAway.FlyAwayHomeLanding);
|
|
} else if (isFlyAwayByKoopa()) {
|
|
mAngle = al::getRandom(45.0f, 70.0f);
|
|
al::setNerve(this, &NrvSmallBirdStateFlyAway.FlyAwayKoopa);
|
|
} else {
|
|
mTargetDir.set(al::getFront(mActor));
|
|
al::setNerve(this, &NrvSmallBirdStateFlyAway.FlyAway);
|
|
}
|
|
}
|
|
|
|
static void startActionAtRandomFrameIfNotPlaying(al::LiveActor* actor, const char* action_name) {
|
|
if (!al::isActionPlaying(actor, action_name))
|
|
al::startActionAtRandomFrame(actor, action_name);
|
|
}
|
|
|
|
void SmallBirdStateFlyAway::startFlyAwayByKoopa() {
|
|
BirdStateFlyAwayBase::startFlyAwayByKoopa();
|
|
startActionAtRandomFrameIfNotPlaying(mActor, "Fly");
|
|
}
|
|
|
|
// TODO: Probably within `sead`
|
|
static void setLength(sead::Vector3f* vec, f32 length) {
|
|
f32 old_length = vec->length();
|
|
if (old_length > 0)
|
|
*vec *= length / old_length;
|
|
}
|
|
|
|
static bool tryFaceToHorizontalDirection(al::LiveActor* actor, const sead::Vector3f& dir) {
|
|
sead::Vector3f horizontal_dir = dir;
|
|
al::verticalizeVec(&horizontal_dir, al::getGravity(actor), horizontal_dir);
|
|
if (!al::tryNormalizeOrZero(&horizontal_dir))
|
|
return false;
|
|
al::faceToDirection(actor, horizontal_dir);
|
|
return true;
|
|
}
|
|
|
|
// NON_MATCHING: wrong offset in store, should probably be ignored by tools/check
|
|
// (https://decomp.me/scratch/icRWQ)
|
|
void SmallBirdStateFlyAway::exeFlyAway() {
|
|
if (al::isFirstStep(this)) {
|
|
static const f32 gHorizontalAccel = 2.0f;
|
|
static const f32 gE3MovieHorizontalAccel[] = {2.0f, 3.0f, 4.0f, 5.0f};
|
|
static const f32 gVerticalAccel[] = {0.7f, 0.65f, 0.6f, 0.55f};
|
|
static const f32 gE3MovieVerticalAccel[] = {3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f};
|
|
static s32 gVerticalAccelIndex = 0;
|
|
static s32 gHorizontalAccelIndex = 0;
|
|
static s32 gCollisionCheckOffsetStep = 0;
|
|
|
|
mIsColliding = false;
|
|
startActionAtRandomFrameIfNotPlaying(mActor, "Fly");
|
|
if (rs::isModeE3MovieRom()) {
|
|
gVerticalAccelIndex = al::wrapValue(gVerticalAccelIndex + 1, 6);
|
|
mVerticalAccel = gE3MovieVerticalAccel[gVerticalAccelIndex];
|
|
gHorizontalAccelIndex = al::wrapValue(gHorizontalAccelIndex + 1, 4);
|
|
mHorizontalAccel = gE3MovieHorizontalAccel[gHorizontalAccelIndex];
|
|
} else {
|
|
gVerticalAccelIndex = al::wrapValue(gVerticalAccelIndex + 1, 4);
|
|
mVerticalAccel = gVerticalAccel[gVerticalAccelIndex];
|
|
mHorizontalAccel = gHorizontalAccel;
|
|
}
|
|
mTargetAccelDir = {0, mVerticalAccel, mHorizontalAccel};
|
|
al::normalize(&mTargetAccelDir);
|
|
gCollisionCheckOffsetStep = al::wrapValue(gCollisionCheckOffsetStep + 1, 10);
|
|
mCollisionCheckOffsetStep = gCollisionCheckOffsetStep;
|
|
}
|
|
|
|
if (mHasTargetPos) {
|
|
sead::Vector3f velocity = al::getVelocity(mActor);
|
|
al::parallelizeVec(&velocity, al::getFront(mActor), velocity);
|
|
*al::getVelocityPtr(mActor) -= velocity;
|
|
|
|
sead::Vector3f target_dir = mTargetPos - al::getTrans(mActor);
|
|
al::verticalizeVec(&target_dir, al::getGravity(mActor), target_dir);
|
|
if (!al::tryNormalizeOrZero(&target_dir))
|
|
target_dir.set(al::getFront(mActor));
|
|
al::turnVecToVecDegree(&target_dir, al::getFront(mActor), target_dir, 15);
|
|
al::turnVecToVecRate(&mTargetDir, target_dir, 0.2f);
|
|
al::normalize(&mTargetDir);
|
|
al::turnVecToVecRate(al::getFrontPtr(mActor), mTargetDir, 0.1f);
|
|
al::normalize(al::getFrontPtr(mActor));
|
|
|
|
*al::getVelocityPtr(mActor) += velocity.length() * al::getFront(mActor);
|
|
}
|
|
|
|
sead::Quatf quat = sead::Quatf::unit;
|
|
al::calcQuat(&quat, mActor);
|
|
|
|
sead::Vector3f accel = {0, mVerticalAccel, mHorizontalAccel};
|
|
f32 accel_mag = accel.length();
|
|
|
|
if (al::isFirstStep(this) || al::isIntervalStep(this, 10, mCollisionCheckOffsetStep)) {
|
|
sead::Vector3f rotated = accel;
|
|
rotated.rotate(quat);
|
|
sead::Vector3f vec = rotated;
|
|
f32 max_speed = al::calcSpeedMax(accel_mag, 0.97f);
|
|
setLength(&vec, max_speed * 60);
|
|
sead::Vector3f hit_pos = {0, 0, 0};
|
|
al::Triangle triangle;
|
|
mIsColliding = alCollisionUtil::getFirstPolyOnArrow(
|
|
mActor, &hit_pos, &triangle, al::getTrans(mActor), vec, nullptr, nullptr);
|
|
if (mIsColliding) {
|
|
f32 distance = (hit_pos - al::getTrans(mActor)).length();
|
|
if (distance < max_speed * 10 && !al::isFirstStep(this)) {
|
|
bool turn_successful = tryFaceToHorizontalDirection(mActor, triangle.getNormal(0));
|
|
if (!turn_successful)
|
|
mHorizontalAccel = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
sead::Vector3f accel_dir = {0, mVerticalAccel, mHorizontalAccel};
|
|
al::normalize(&accel_dir);
|
|
if (mIsColliding) {
|
|
al::turnVecToVecDegree(&mTargetAccelDir, sead::Vector3f::ey, 2.5f);
|
|
al::normalize(&mTargetAccelDir);
|
|
}
|
|
al::turnVecToVecRate(&accel_dir, mTargetAccelDir, 0.15f);
|
|
al::normalize(&accel_dir);
|
|
|
|
accel = accel_dir * accel_mag;
|
|
mVerticalAccel = accel.y;
|
|
mHorizontalAccel = accel.z;
|
|
|
|
f32 old_accel = al::calcNerveValue(this, 1, 31, 2.0f, 0.8f);
|
|
f32 new_accel = al::calcNerveValue(this, 30, 2.0f, 0.8f);
|
|
mHorizontalAccel *= al::normalize(new_accel, 0.0f, old_accel);
|
|
|
|
sead::Vector3f rotated = accel_dir;
|
|
rotated.rotate(quat);
|
|
al::setVelocity(mActor, rotated * al::calcSpeed(mActor));
|
|
al::addVelocity(mActor, -al::getGravity(mActor) * mVerticalAccel +
|
|
al::getFront(mActor) * mHorizontalAccel);
|
|
al::scaleVelocity(mActor, 0.97f);
|
|
BirdFunction::tryUpdateFlyAwayDisappearDitherAlpha(mActor, this, mDisappearStep - 60,
|
|
mDisappearStep);
|
|
if (al::isGreaterEqualStep(this, mDisappearStep))
|
|
kill();
|
|
}
|
|
|
|
void SmallBirdStateFlyAway::exeFlyAwayHomeLanding() {
|
|
if (al::isFirstStep(this))
|
|
startActionAtRandomFrameIfNotPlaying(mActor, "Fly");
|
|
al::addVelocity(mActor,
|
|
(al::getFront(mActor) * sead::Mathf::sin(sead::Mathf::deg2rad(mAngle)) -
|
|
al::getGravity(mActor) * sead::Mathf::cos(sead::Mathf::deg2rad(mAngle))) *
|
|
al::calcNerveValue(this, 30, 1.75f, 0.75f));
|
|
al::scaleVelocity(mActor, 0.97f);
|
|
BirdFunction::tryUpdateFlyAwayDisappearDitherAlpha(mActor, this, mDisappearStep - 60,
|
|
mDisappearStep);
|
|
if (al::isGreaterEqualStep(this, mDisappearStep))
|
|
kill();
|
|
}
|
|
|
|
void SmallBirdStateFlyAway::exeFlyAwayKoopa() {
|
|
if (al::isFirstStep(this))
|
|
startActionAtRandomFrameIfNotPlaying(mActor, "Fly");
|
|
al::addVelocity(mActor,
|
|
(al::getFront(mActor) * sead::Mathf::sin(sead::Mathf::deg2rad(mAngle)) -
|
|
al::getGravity(mActor) * sead::Mathf::cos(sead::Mathf::deg2rad(mAngle))) *
|
|
al::calcNerveValue(this, 30, 5.5f, 4.0f));
|
|
al::scaleVelocity(mActor, 0.97f);
|
|
BirdFunction::tryUpdateFlyAwayDisappearDitherAlpha(mActor, this, mDisappearStep - 60,
|
|
mDisappearStep);
|
|
if (al::isGreaterEqualStep(this, mDisappearStep))
|
|
kill();
|
|
}
|