mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-04-23 09:04:21 +00:00
Player: Implement PlayerRecoverySafetyPoint and PlayerJudgeAbyssDeadStatus (#930)
This commit is contained in:
parent
e09c84f4fb
commit
ffd385f51c
|
|
@ -123236,20 +123236,20 @@ Player/PlayerJudgeAbyssDeadStatus.o:
|
|||
label:
|
||||
- _ZN26PlayerJudgeAbyssDeadStatusC1EPK20PlayerJudgeSameNervePK25PlayerRecoverySafetyPoint
|
||||
- _ZN26PlayerJudgeAbyssDeadStatusC2EPK20PlayerJudgeSameNervePK25PlayerRecoverySafetyPoint
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x4589a0
|
||||
size: 64
|
||||
label: _ZNK26PlayerJudgeAbyssDeadStatus5judgeEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x4589e0
|
||||
size: 4
|
||||
label: _ZN26PlayerJudgeAbyssDeadStatus5resetEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
lazy: true
|
||||
- offset: 0x4589e4
|
||||
size: 4
|
||||
label: _ZN26PlayerJudgeAbyssDeadStatus6updateEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
lazy: true
|
||||
Player/PlayerJudgeActiveCameraSubjective.o:
|
||||
'.text':
|
||||
|
|
@ -125472,79 +125472,79 @@ Player/PlayerRecoverySafetyPoint.o:
|
|||
label:
|
||||
- _ZN25PlayerRecoverySafetyPointC1EPKN2al9LiveActorEPK7HackCapRKNS0_13ActorInitInfoEPK13IUseDimensionPNS0_24CollisionPartsFilterBaseEPNS0_9HitSensorE
|
||||
- _ZN25PlayerRecoverySafetyPointC2EPKN2al9LiveActorEPK7HackCapRKNS0_13ActorInitInfoEPK13IUseDimensionPNS0_24CollisionPartsFilterBaseEPNS0_9HitSensorE
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x4604cc
|
||||
size: 60
|
||||
label: _ZN25PlayerRecoverySafetyPoint5resetEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460508
|
||||
size: 264
|
||||
label: _ZN25PlayerRecoverySafetyPoint14setSafetyPointERKN4sead7Vector3IfEES4_PKN2al7AreaObjE
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460610
|
||||
size: 564
|
||||
label: _ZN25PlayerRecoverySafetyPoint24noticeRequestSafetyPointERKN4sead7Vector3IfEES4_PKN2al7AreaObjE
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460844
|
||||
size: 196
|
||||
label: _ZN25PlayerRecoverySafetyPoint20noticeDangerousPointERKN4sead7Vector3IfEEb
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460908
|
||||
size: 904
|
||||
label: _ZN25PlayerRecoverySafetyPoint20slideLastSafetyPointEPN4sead7Vector3IfEES3_bRKS2_bPN2al24CollisionPartsFilterBaseE
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460c90
|
||||
size: 108
|
||||
label: _ZNK25PlayerRecoverySafetyPoint7isValidEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460cfc
|
||||
size: 76
|
||||
label: _ZNK25PlayerRecoverySafetyPoint16isEnableRecoveryEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460d48
|
||||
size: 60
|
||||
label: _ZNK25PlayerRecoverySafetyPoint14getSafetyPointEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460d84
|
||||
size: 52
|
||||
label: _ZNK25PlayerRecoverySafetyPoint21getSafetyPointGravityEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460db8
|
||||
size: 56
|
||||
label: _ZNK25PlayerRecoverySafetyPoint18getSafetyPointAreaEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460df0
|
||||
size: 24
|
||||
label: _ZN25PlayerRecoverySafetyPoint26updateRecoveryAreaValidityEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460e08
|
||||
size: 8
|
||||
label: _ZN25PlayerRecoverySafetyPoint15setRecoveryAreaEPKN2al7AreaObjE
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460e10
|
||||
size: 32
|
||||
label: _ZNK25PlayerRecoverySafetyPoint20isActiveRecoveryAreaEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460e30
|
||||
size: 220
|
||||
label: _ZN25PlayerRecoverySafetyPoint19checkInvalidateAreaEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x460f0c
|
||||
size: 364
|
||||
label: _ZN25PlayerRecoverySafetyPoint13startRecoveryEf
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x461078
|
||||
size: 752
|
||||
label: _ZN25PlayerRecoverySafetyPoint20updateRecoveryBubbleEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x461368
|
||||
size: 64
|
||||
label: _ZN25PlayerRecoverySafetyPoint15startBubbleWaitEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
- offset: 0x4613a8
|
||||
size: 88
|
||||
label: _ZN25PlayerRecoverySafetyPoint11endRecoveryEv
|
||||
status: NotDecompiled
|
||||
status: Matching
|
||||
Player/PlayerRippleGenerator.o:
|
||||
'.text':
|
||||
- offset: 0x461400
|
||||
|
|
|
|||
|
|
@ -10,6 +10,16 @@ public:
|
|||
virtual bool isInvalidTriangle(const Triangle& triangle) const = 0;
|
||||
};
|
||||
|
||||
class TriangleFilterGroundOnly : public TriangleFilterBase {
|
||||
public:
|
||||
TriangleFilterGroundOnly(const sead::Vector3f& down) : mDown(down) {}
|
||||
|
||||
bool isInvalidTriangle(const Triangle& triangle) const override;
|
||||
|
||||
private:
|
||||
const sead::Vector3f& mDown;
|
||||
};
|
||||
|
||||
class TriangleFilterWallOnly : public TriangleFilterBase {
|
||||
public:
|
||||
TriangleFilterWallOnly(const sead::Vector3f& down) : mDown(down) {}
|
||||
|
|
|
|||
18
src/Player/PlayerJudgeAbyssDeadStatus.cpp
Normal file
18
src/Player/PlayerJudgeAbyssDeadStatus.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include "Player/PlayerJudgeAbyssDeadStatus.h"
|
||||
|
||||
#include "Player/PlayerInfo.h"
|
||||
#include "Player/PlayerJudgeSameNerve.h"
|
||||
#include "Player/PlayerRecoverySafetyPoint.h"
|
||||
#include "Util/JudgeUtil.h"
|
||||
|
||||
PlayerJudgeAbyssDeadStatus::PlayerJudgeAbyssDeadStatus(const PlayerJudgeSameNerve* nerve,
|
||||
const PlayerRecoverySafetyPoint* safePoint)
|
||||
: mNerve(nerve), mSafePoint(safePoint) {}
|
||||
|
||||
bool PlayerJudgeAbyssDeadStatus::judge() const {
|
||||
return rs::isJudge(mNerve) && !mSafePoint->isValid();
|
||||
}
|
||||
|
||||
void PlayerJudgeAbyssDeadStatus::reset() {}
|
||||
|
||||
void PlayerJudgeAbyssDeadStatus::update() {}
|
||||
22
src/Player/PlayerJudgeAbyssDeadStatus.h
Normal file
22
src/Player/PlayerJudgeAbyssDeadStatus.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "Player/IJudge.h"
|
||||
|
||||
class PlayerJudgeSameNerve;
|
||||
class PlayerRecoverySafetyPoint;
|
||||
|
||||
class PlayerJudgeAbyssDeadStatus : public IJudge {
|
||||
public:
|
||||
PlayerJudgeAbyssDeadStatus(const PlayerJudgeSameNerve* nerve,
|
||||
const PlayerRecoverySafetyPoint* safePoint);
|
||||
|
||||
bool judge() const override;
|
||||
void reset() override;
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
const PlayerJudgeSameNerve* mNerve;
|
||||
const PlayerRecoverySafetyPoint* mSafePoint;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PlayerJudgeAbyssDeadStatus) == 0x18);
|
||||
343
src/Player/PlayerRecoverySafetyPoint.cpp
Normal file
343
src/Player/PlayerRecoverySafetyPoint.cpp
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
#include "Player/PlayerRecoverySafetyPoint.h"
|
||||
|
||||
#include "Library/Area/AreaObj.h"
|
||||
#include "Library/Area/AreaObjUtil.h"
|
||||
#include "Library/Camera/CameraUtil.h"
|
||||
#include "Library/Collision/CollisionPartsKeeperUtil.h"
|
||||
#include "Library/Collision/CollisionPartsTriangle.h"
|
||||
#include "Library/Collision/PartsInterpolator.h"
|
||||
#include "Library/LiveActor/ActorActionFunction.h"
|
||||
#include "Library/LiveActor/ActorClippingFunction.h"
|
||||
#include "Library/LiveActor/ActorFlagFunction.h"
|
||||
#include "Library/LiveActor/ActorInitUtil.h"
|
||||
#include "Library/LiveActor/ActorMovementFunction.h"
|
||||
#include "Library/LiveActor/ActorPoseUtil.h"
|
||||
#include "Library/LiveActor/LiveActor.h"
|
||||
#include "Library/LiveActor/LiveActorFunction.h"
|
||||
#include "Library/Math/MathUtil.h"
|
||||
|
||||
#include "Player/HackCap.h"
|
||||
#include "System/GameDataUtil.h"
|
||||
#include "Util/ActorDimensionUtil.h"
|
||||
#include "Util/PlayerCollisionUtil.h"
|
||||
#include "Util/PlayerUtil.h"
|
||||
|
||||
PlayerRecoverySafetyPoint::PlayerRecoverySafetyPoint(const al::LiveActor* actor,
|
||||
const HackCap* hackCap,
|
||||
const al::ActorInitInfo& initInfo,
|
||||
const IUseDimension* dimension,
|
||||
al::CollisionPartsFilterBase* colFilter,
|
||||
al::HitSensor* hitSensor)
|
||||
: mActor(actor), mHackCap(hackCap), mDimension(dimension), mColFilter(colFilter),
|
||||
mHitSensor(hitSensor) {
|
||||
mTractorBubble = new al::LiveActor("復帰泡");
|
||||
al::initChildActorWithArchiveNameNoPlacementInfo(mTractorBubble, initInfo, "TractorBubble",
|
||||
nullptr);
|
||||
al::invalidateClipping(mTractorBubble);
|
||||
mTractorBubble->makeActorDead();
|
||||
|
||||
mTractorBubble2D = new al::LiveActor("復帰泡2D");
|
||||
al::initChildActorWithArchiveNameNoPlacementInfo(mTractorBubble2D, initInfo, "TractorBubble2D",
|
||||
nullptr);
|
||||
al::invalidateClipping(mTractorBubble2D);
|
||||
mTractorBubble2D->makeActorDead();
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::reset() {
|
||||
mSafety3D.reset();
|
||||
mSafety2D.reset();
|
||||
|
||||
mRecoveryArea = nullptr;
|
||||
mDefaultSafetyPos = nullptr;
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::setSafetyPoint(const sead::Vector3f& safetyPos,
|
||||
const sead::Vector3f& safetyNormal,
|
||||
const al::AreaObj* areaObj) {
|
||||
if (!rs::isPlayer2D(mActor)) {
|
||||
mSafety3D.set(safetyPos, safetyNormal, al::getGravity(mActor), areaObj);
|
||||
} else if (rs::isIn2DArea(mDimension)) {
|
||||
sead::Vector3f snapPos = safetyPos;
|
||||
rs::calcSnap2DPosition(&snapPos, mDimension, safetyPos, 500.0f);
|
||||
|
||||
mSafety2D.set(snapPos, safetyNormal, al::getGravity(mActor), areaObj);
|
||||
}
|
||||
|
||||
mDefaultSafetyPos = nullptr;
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::noticeRequestSafetyPoint(const sead::Vector3f& safetyPos,
|
||||
const sead::Vector3f& safetyNormal,
|
||||
const al::AreaObj* areaObj) {
|
||||
sead::Vector3f pos = safetyPos;
|
||||
sead::Vector3f normal = safetyNormal;
|
||||
sead::Vector3f* defaultPos = nullptr;
|
||||
|
||||
if (rs::isPlayer3D(mActor) && areaObj == nullptr) {
|
||||
const sead::Vector3f& gravity = al::getGravity(mActor);
|
||||
|
||||
sead::Vector3f rayStart = safetyPos - gravity * 10.0f;
|
||||
sead::Vector3f rayDir = gravity * 110.0f;
|
||||
const al::ArrowHitInfo* hitInfo = nullptr;
|
||||
al::TriangleFilterGroundOnly filter(gravity);
|
||||
if (!alCollisionUtil::getFirstPolyOnArrow(mActor, &hitInfo, rayStart, rayDir, nullptr,
|
||||
&filter))
|
||||
return;
|
||||
|
||||
if (!rs::isEnableRecordSafetyPoint(&defaultPos, *hitInfo->hitInfo.data(), mHitSensor,
|
||||
-gravity))
|
||||
return;
|
||||
|
||||
pos = alCollisionUtil::getCollisionHitPos(hitInfo->hitInfo.data());
|
||||
normal = alCollisionUtil::getCollisionHitNormal(hitInfo->hitInfo.data());
|
||||
}
|
||||
|
||||
setSafetyPoint(pos, normal, areaObj);
|
||||
mDefaultSafetyPos = defaultPos;
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::noticeDangerousPoint(const sead::Vector3f& pos, bool skipIfValid) {
|
||||
if (!rs::isPlayer2D(mActor)) {
|
||||
slideLastSafetyPoint(&mSafety3D.safetyPos, &mSafety3D.safetyNormal, mSafety3D.hasSafety,
|
||||
pos, skipIfValid, nullptr);
|
||||
} else if (rs::isIn2DArea(mDimension)) {
|
||||
sead::Vector3f snapPos = pos;
|
||||
rs::calcSnap2DPosition(&snapPos, mDimension, pos, 500.0f);
|
||||
slideLastSafetyPoint(&mSafety2D.safetyPos, &mSafety2D.safetyNormal, mSafety2D.hasSafety,
|
||||
snapPos, skipIfValid, mColFilter);
|
||||
}
|
||||
}
|
||||
|
||||
// Function: PlayerRecoverySafetyPoint::slideLastSafetyPoint
|
||||
// Description:
|
||||
// If the player moves slightly from the last recorded safety point, this function
|
||||
// adjusts ("slides") that point along the ground so it stays in a valid position.
|
||||
//
|
||||
// The slide distance is inversely proportional to the player's movement. Small
|
||||
// movements cause a larger adjustment (~100 units), while larger movements
|
||||
// cause little or no adjustment. This helps pull the safety point away from edges
|
||||
// or dangerous geometry without letting it drift too far across the surface.
|
||||
// I assume this is to allow some leeway for players when you're placed in a
|
||||
// recovery position.
|
||||
//
|
||||
// When skipIfValid is true, a ray is first cast behind the current safety
|
||||
// point to check whether it is still supported by valid ground. If it is, the
|
||||
// function returns early and no sliding occurs.
|
||||
|
||||
void PlayerRecoverySafetyPoint::slideLastSafetyPoint(sead::Vector3f* safetyPos,
|
||||
sead::Vector3f* safetyNormal, bool hasSafety,
|
||||
const sead::Vector3f& lastSafetyPos,
|
||||
bool skipIfValid,
|
||||
al::CollisionPartsFilterBase* colFilter) {
|
||||
if (!hasSafety)
|
||||
return;
|
||||
|
||||
sead::Vector3f slideDir = {0.0f, 0.0f, 0.0f};
|
||||
al::verticalizeVec(&slideDir, *safetyNormal, *safetyPos - lastSafetyPos);
|
||||
|
||||
f32 length = slideDir.length();
|
||||
if (length > 100.0f || !al::tryNormalizeOrZero(&slideDir))
|
||||
return;
|
||||
|
||||
const sead::Vector3f& gravity = al::getGravity(mActor);
|
||||
sead::Vector3f rayDir = 2 * (gravity * 50.0f);
|
||||
sead::Vector3f rayOffset = gravity * 50.0f;
|
||||
|
||||
const al::ArrowHitInfo* hitInfo = nullptr;
|
||||
|
||||
if (skipIfValid) {
|
||||
sead::Vector3f rayStart = *safetyPos - (length * slideDir) - rayOffset;
|
||||
al::TriangleFilterGroundOnly filter(gravity);
|
||||
if (alCollisionUtil::getFirstPolyOnArrow(mActor, &hitInfo, rayStart, rayDir, colFilter,
|
||||
&filter)) {
|
||||
sead::Vector3f* outPos = nullptr;
|
||||
if (rs::isEnableRecordSafetyPoint(&outPos, *hitInfo->hitInfo.data(), mHitSensor,
|
||||
-gravity))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Inverse rubber band logic
|
||||
// If the player hasn't moved much, assume the safety point might still be near a dangerous edge
|
||||
// and correct it inward. This (presumably, from a design perspective) allows for some leeway
|
||||
// when the player is placed in a recovery position in certain areas. However, if the player has
|
||||
// moved a large distance, only adjust it a little bit. This prevents the safety point from
|
||||
// sliding too far across the surface when the player has moved significantly.
|
||||
|
||||
length = sead::Mathf::clampMin(100.0f - length, 0.0f);
|
||||
sead::Vector3f rayStart = *safetyPos + (length * slideDir) - rayOffset;
|
||||
|
||||
sead::Vector3f* outPos = nullptr;
|
||||
if (alCollisionUtil::getFirstPolyOnArrow(mActor, &hitInfo, rayStart, rayDir, colFilter,
|
||||
nullptr)) {
|
||||
if (rs::isEnableRecordSafetyPoint(&outPos, *hitInfo->hitInfo.data(), mHitSensor,
|
||||
-gravity) &&
|
||||
rs::isCollisionCodeSafetyPoint(*hitInfo->hitInfo.data())) {
|
||||
sead::Vector3f hitPos = alCollisionUtil::getCollisionHitPos(hitInfo->hitInfo.data());
|
||||
sead::Vector3f hitNormal =
|
||||
alCollisionUtil::getCollisionHitNormal(hitInfo->hitInfo.data());
|
||||
|
||||
al::TriangleFilterGroundOnly filter(al::getGravity(mActor));
|
||||
if (!alCollisionUtil::getFirstPolyOnArrow(mActor, &hitInfo, *safetyPos - gravity * 5.0f,
|
||||
hitPos - *safetyPos, colFilter, &filter)) {
|
||||
*safetyPos = hitPos;
|
||||
*safetyNormal = hitNormal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerRecoverySafetyPoint::isValid() const {
|
||||
if (!isEnableRecovery())
|
||||
return false;
|
||||
|
||||
if (rs::isPlayer2D(mActor))
|
||||
return mSafety2D.hasSafety;
|
||||
return mSafety3D.hasSafety;
|
||||
}
|
||||
|
||||
bool PlayerRecoverySafetyPoint::isEnableRecovery() const {
|
||||
return rs::isKidsMode(mActor) || isActiveRecoveryArea() || mHackCap->isEnableRescuePlayer();
|
||||
}
|
||||
|
||||
const sead::Vector3f& PlayerRecoverySafetyPoint::getSafetyPoint() const {
|
||||
if (mDefaultSafetyPos)
|
||||
return *mDefaultSafetyPos;
|
||||
|
||||
if (rs::isPlayer2D(mActor))
|
||||
return mSafety2D.safetyPos;
|
||||
else
|
||||
return mSafety3D.safetyPos;
|
||||
}
|
||||
|
||||
const sead::Vector3f& PlayerRecoverySafetyPoint::getSafetyPointGravity() const {
|
||||
if (rs::isPlayer2D(mActor))
|
||||
return mSafety2D.gravity;
|
||||
return mSafety3D.gravity;
|
||||
}
|
||||
|
||||
const al::AreaObj* PlayerRecoverySafetyPoint::getSafetyPointArea() const {
|
||||
if (rs::isPlayer2D(mActor))
|
||||
return mSafety2D.area;
|
||||
return mSafety3D.area;
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::updateRecoveryAreaValidity() {
|
||||
if (mRecoveryArea && !mRecoveryArea->isValid())
|
||||
mRecoveryArea = nullptr;
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::setRecoveryArea(const al::AreaObj* area) {
|
||||
mRecoveryArea = area;
|
||||
}
|
||||
|
||||
bool PlayerRecoverySafetyPoint::isActiveRecoveryArea() const {
|
||||
return mRecoveryArea && mRecoveryArea->isValid();
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::checkInvalidateArea() {
|
||||
if (isValid() && al::isInAreaObj(mActor, "InvalidateRecoveryPosArea", getSafetyPoint()))
|
||||
reset();
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::startRecovery(f32 height) {
|
||||
mBubbleHeight = height; // height will be 80.0 if the player is 3D, else 60.0.
|
||||
if (mIsRecovering)
|
||||
return;
|
||||
|
||||
mIsRecovering = true;
|
||||
if (rs::isPlayer2D(mActor)) {
|
||||
mTractorBubble2D->appear();
|
||||
return;
|
||||
}
|
||||
|
||||
mTractorBubble->appear();
|
||||
al::offCollide(mTractorBubble);
|
||||
al::startAction(mTractorBubble, "Appear");
|
||||
updateRecoveryBubble();
|
||||
|
||||
if (mHackCap->isEnableRescuePlayer()) {
|
||||
al::LiveActor* hat = al::getSubActor(mTractorBubble, "装着帽子");
|
||||
hat->appear();
|
||||
al::startAction(hat, "LockOn");
|
||||
|
||||
al::startHitReactionHitEffect(mHackCap, "プレイヤー救出出現",
|
||||
al::getTrans(mTractorBubble) -
|
||||
al::getGravity(mTractorBubble) * 160.0f);
|
||||
|
||||
al::LiveActor* eye = al::getSubActor(mTractorBubble, "目");
|
||||
eye->appear();
|
||||
al::startAction(eye, "Appear");
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::updateRecoveryBubble() {
|
||||
if (rs::isPlayer2D(mActor)) {
|
||||
if (al::isDead(mTractorBubble2D))
|
||||
return;
|
||||
|
||||
sead::Vector3f up = -al::getGravity(mActor);
|
||||
sead::Vector3f side = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
al::calcSideDir(&side, mActor);
|
||||
|
||||
sead::Quatf quat = sead::Quatf::unit;
|
||||
|
||||
if (al::isParallelDirection(side, up, 0.01f))
|
||||
al::calcQuat(&quat, mTractorBubble2D);
|
||||
else
|
||||
al::makeQuatSideUp(&quat, side, up);
|
||||
|
||||
sead::Vector3f upDir = {0.0f, 0.0f, 0.0f};
|
||||
al::calcUpDir(&upDir, mActor);
|
||||
|
||||
al::resetPosition(mTractorBubble2D, al::getTrans(mActor) + upDir * mBubbleHeight);
|
||||
al::updatePoseQuat(mTractorBubble2D, quat);
|
||||
return;
|
||||
}
|
||||
|
||||
if (al::isDead(mTractorBubble))
|
||||
return;
|
||||
|
||||
if (al::isActionPlaying(mTractorBubble, "Disappear")) {
|
||||
if (al::isActionEnd(mTractorBubble)) {
|
||||
mTractorBubble->kill();
|
||||
al::getSubActor(mTractorBubble, "装着帽子")->kill();
|
||||
al::getSubActor(mTractorBubble, "目")->kill();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sead::Vector3f upDir = {0.0f, 0.0f, 0.0f};
|
||||
al::calcUpDir(&upDir, mActor);
|
||||
|
||||
al::resetPosition(mTractorBubble, al::getTrans(mActor) + upDir * mBubbleHeight);
|
||||
|
||||
sead::Vector3f camFront = {0.0f, 0.0f, 0.0f};
|
||||
al::calcCameraFront(&camFront, mActor, 0);
|
||||
|
||||
sead::Vector3f up = -al::getGravity(mActor);
|
||||
|
||||
if (al::isParallelDirection(camFront, up, 0.01f))
|
||||
camFront = al::getCameraUp(mActor, 0);
|
||||
camFront.negate();
|
||||
sead::Quatf quat = sead::Quatf::unit;
|
||||
al::makeQuatUpFront(&quat, up, camFront);
|
||||
al::updatePoseQuat(mTractorBubble, quat);
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::startBubbleWait() {
|
||||
if (!rs::isPlayer2D(mActor))
|
||||
al::startAction(mTractorBubble, "Wait");
|
||||
}
|
||||
|
||||
void PlayerRecoverySafetyPoint::endRecovery() {
|
||||
if (mIsRecovering) {
|
||||
if (rs::isPlayer2D(mActor))
|
||||
mTractorBubble2D->kill();
|
||||
else
|
||||
al::startAction(mTractorBubble, "Disappear");
|
||||
|
||||
mIsRecovering = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,63 +2,101 @@
|
|||
|
||||
#include <math/seadVector.h>
|
||||
|
||||
class HackCap;
|
||||
class IUseDimension;
|
||||
|
||||
namespace al {
|
||||
class LiveActor;
|
||||
class AreaObj;
|
||||
struct ActorInitInfo;
|
||||
class CollisionPartsFilterBase;
|
||||
class AreaObj;
|
||||
class HitSensor;
|
||||
class ActorActionKeeper;
|
||||
} // namespace al
|
||||
class HackCap;
|
||||
class IUseDimension;
|
||||
|
||||
struct SafetyPoint {
|
||||
bool hasSafety = false;
|
||||
sead::Vector3f safetyPos = {0.0f, 0.0f, 0.0f};
|
||||
sead::Vector3f safetyNormal = {0.0f, 0.0f, 0.0f};
|
||||
sead::Vector3f gravity = {0.0f, 0.0f, 0.0f};
|
||||
const al::AreaObj* area = nullptr;
|
||||
|
||||
inline void reset() {
|
||||
hasSafety = false;
|
||||
safetyPos = {0.0f, 0.0f, 0.0f};
|
||||
safetyNormal = {0.0f, 0.0f, 0.0f};
|
||||
gravity = {0.0f, 0.0f, 0.0f};
|
||||
area = nullptr;
|
||||
}
|
||||
|
||||
inline void set(const sead::Vector3f& rSafetyPos, const sead::Vector3f& rSafetyNormal,
|
||||
const sead::Vector3f& rGravity, const al::AreaObj* pAreaObj) {
|
||||
hasSafety = true;
|
||||
safetyPos.set(rSafetyPos);
|
||||
safetyNormal.set(rSafetyNormal);
|
||||
gravity.set(rGravity);
|
||||
area = pAreaObj;
|
||||
}
|
||||
};
|
||||
|
||||
class PlayerRecoverySafetyPoint {
|
||||
public:
|
||||
PlayerRecoverySafetyPoint(const al::LiveActor*, const HackCap*, const al::ActorInitInfo&,
|
||||
const IUseDimension*, al::CollisionPartsFilterBase*, al::HitSensor*);
|
||||
PlayerRecoverySafetyPoint(const al::LiveActor* actor, const HackCap* hackCap,
|
||||
const al::ActorInitInfo& initInfo, const IUseDimension* dimension,
|
||||
al::CollisionPartsFilterBase* colFilter, al::HitSensor* hitSensor);
|
||||
|
||||
void reset();
|
||||
void setSafetyPoint(const sead::Vector3f&, const sead::Vector3f&, const al::AreaObj*);
|
||||
void noticeRequestSafetyPoint(const sead::Vector3f&, const sead::Vector3f&, const al::AreaObj*);
|
||||
void noticeDangerousPoint(const sead::Vector3f&, bool);
|
||||
void slideLastSafetyPoint(sead::Vector3f*, sead::Vector3f*, bool, const sead::Vector3f&, bool,
|
||||
al::CollisionPartsFilterBase*);
|
||||
|
||||
void setSafetyPoint(const sead::Vector3f& safetyPos, const sead::Vector3f& safetyNormal,
|
||||
const al::AreaObj* areaObj);
|
||||
|
||||
void noticeRequestSafetyPoint(const sead::Vector3f& safetyNormal, const sead::Vector3f&,
|
||||
const al::AreaObj* areaObj);
|
||||
void noticeDangerousPoint(const sead::Vector3f& pos, bool skipIfValid);
|
||||
|
||||
void slideLastSafetyPoint(sead::Vector3f* safetyPos, sead::Vector3f* safetyNormal,
|
||||
bool hasSafety, const sead::Vector3f& lastSafetyPos, bool skipIfValid,
|
||||
al::CollisionPartsFilterBase* colFilter);
|
||||
|
||||
bool isValid() const;
|
||||
bool isEnableRecovery() const;
|
||||
|
||||
const sead::Vector3f& getSafetyPoint() const;
|
||||
const sead::Vector3f& getSafetyPointGravity() const;
|
||||
const sead::Vector3f& getSafetyPointArea() const;
|
||||
const al::AreaObj* getSafetyPointArea() const;
|
||||
|
||||
void updateRecoveryAreaValidity();
|
||||
void setRecoveryArea(const al::AreaObj*);
|
||||
|
||||
void setRecoveryArea(const al::AreaObj* area);
|
||||
|
||||
bool isActiveRecoveryArea() const;
|
||||
|
||||
void checkInvalidateArea();
|
||||
void startRecovery(f32);
|
||||
|
||||
void startRecovery(f32 height);
|
||||
void updateRecoveryBubble();
|
||||
void startBubbleWait();
|
||||
void endRecovery();
|
||||
|
||||
private:
|
||||
al::LiveActor* mPlayer;
|
||||
HackCap* mHackCap;
|
||||
IUseDimension* mDimension;
|
||||
al::CollisionPartsFilterBase* mCollisionPartsFilter;
|
||||
const al::LiveActor* mActor;
|
||||
const HackCap* mHackCap;
|
||||
const IUseDimension* mDimension;
|
||||
al::CollisionPartsFilterBase* mColFilter;
|
||||
al::HitSensor* mHitSensor;
|
||||
al::LiveActor* mBubble3D;
|
||||
al::LiveActor* mBubble2D;
|
||||
f32 mRecoveryTimer;
|
||||
f32 _34;
|
||||
bool mHasSafety3D;
|
||||
sead::Vector3f mSafetyPos3D;
|
||||
sead::Vector3f mSafetyNormal3D;
|
||||
sead::Vector3f mGravity3D;
|
||||
al::AreaObj* mArea3D;
|
||||
bool mHasSafety2D;
|
||||
sead::Vector3f mSafetyPos2D;
|
||||
sead::Vector3f mSafetyNormal2D;
|
||||
sead::Vector3f mGravity2D;
|
||||
al::AreaObj* mArea2D;
|
||||
bool mIsRecovering;
|
||||
al::AreaObj* mRecoveryArea;
|
||||
sead::Vector3f* mSafetyPoint;
|
||||
|
||||
al::LiveActor* mTractorBubble = nullptr;
|
||||
al::LiveActor* mTractorBubble2D = nullptr;
|
||||
|
||||
f32 mBubbleHeight = 0.0f;
|
||||
|
||||
SafetyPoint mSafety3D;
|
||||
SafetyPoint mSafety2D;
|
||||
bool mIsRecovering = false;
|
||||
|
||||
const al::AreaObj* mRecoveryArea = nullptr;
|
||||
sead::Vector3f* mDefaultSafetyPos = nullptr; // TODO: Determine actual use (currently unsure)
|
||||
};
|
||||
|
||||
static_assert(sizeof(PlayerRecoverySafetyPoint) == 0xb8);
|
||||
|
|
|
|||
Loading…
Reference in a new issue