mirror of
https://github.com/doldecomp/sms.git
synced 2026-11-07 09:06:00 -10:00
621 lines
15 KiB
C++
621 lines
15 KiB
C++
#include <Enemy/Enemy.hpp>
|
|
#include <Enemy/Graph.hpp>
|
|
#include <Enemy/EnemyManager.hpp>
|
|
#include <Enemy/Conductor.hpp>
|
|
#include <Map/Map.hpp>
|
|
#include <Map/MapData.hpp>
|
|
#include <Player/MarioAccess.hpp>
|
|
#include <M3DUtil/MActor.hpp>
|
|
#include <MarioUtil/MathUtil.hpp>
|
|
#include <MarioUtil/MtxUtil.hpp>
|
|
#include <Strategic/Spine.hpp>
|
|
#include <JSystem/J3D/J3DGraphAnimator/J3DAnimation.hpp>
|
|
#include <JSystem/J3D/J3DGraphAnimator/J3DModel.hpp>
|
|
#include <JSystem/JDrama/JDRNameRefGen.hpp>
|
|
#include <JSystem/JMath.hpp>
|
|
|
|
// rogue includes needed for matching sinit & bss
|
|
#include <MSound/MSSetSound.hpp>
|
|
#include <MSound/MSoundBGM.hpp>
|
|
|
|
TSpineEnemy::TSpineEnemy(const char* name)
|
|
: TLiveActor(name)
|
|
, mGoalPath(4)
|
|
, unk128(0)
|
|
, unk12C(0.0f)
|
|
, unk130(0)
|
|
, mDistToMarioSquared(0.0f)
|
|
, unk138(nullptr)
|
|
, mHitPoints(1)
|
|
, mMarchSpeed(1.0f)
|
|
, mTurnSpeed(5.0f)
|
|
, mBodyScale(1.0f)
|
|
, mWallRadius(1.0f)
|
|
{
|
|
mSpine = new TSpineBase<TLiveActor>(this);
|
|
unk124 = new TGraphTracer;
|
|
}
|
|
|
|
TSpineEnemy::~TSpineEnemy() { }
|
|
|
|
void TSpineEnemy::init(TLiveManager* param_1)
|
|
{
|
|
TLiveActor::init(param_1);
|
|
TSpineEnemyParams* params = getSaveParam();
|
|
if (params) {
|
|
mBodyRadius = params->mSLBodyRadius.get();
|
|
mWallRadius = params->mSLWallRadius.get();
|
|
mHeadHeight = params->mSLHeadHeight.get();
|
|
mScaledBodyRadius = mBodyScale * mBodyRadius;
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::reset()
|
|
{
|
|
unk124->reset();
|
|
goToShortestNextGraphNode();
|
|
offLiveFlag(LIVE_FLAG_DEAD);
|
|
offLiveFlag(LIVE_FLAG_UNK8);
|
|
offLiveFlag(LIVE_FLAG_UNK10);
|
|
offLiveFlag(LIVE_FLAG_CLIPPED_OUT);
|
|
onLiveFlag(LIVE_FLAG_UNK800);
|
|
mSpine->reset();
|
|
mSpine->pushAfterCurrent(mSpine->getDefault());
|
|
}
|
|
|
|
void TSpineEnemy::load(JSUMemoryInputStream& stream)
|
|
{
|
|
JDrama::TActor::load(stream);
|
|
|
|
char buffer[256];
|
|
stream.readString(buffer, 256);
|
|
TLiveManager* mgr
|
|
= static_cast<TLiveManager*>(JDrama::TNameRefGen::search(buffer));
|
|
|
|
char buffer2[256];
|
|
stream.readString(buffer2, 256);
|
|
unk124->init(gpConductor->getGraphByName(buffer2));
|
|
|
|
mGroundPlane = TMap::getIllegalCheckData();
|
|
|
|
init(mgr);
|
|
}
|
|
|
|
void TSpineEnemy::calcEnemyRootMatrix()
|
|
{
|
|
J3DModel* pJVar13 = getModel();
|
|
MtxPtr mtx = pJVar13->getBaseTRMtx();
|
|
|
|
pJVar13->setBaseScale(mScaling);
|
|
|
|
if (unk130 == 0) {
|
|
MsMtxSetRotRPH(mtx, mRotation.x, mRotation.y, mRotation.z);
|
|
} else {
|
|
if (unk130 >= 2 && !isAirborne() && unk138 != nullptr) {
|
|
JGeometry::TVec3<f32> v2 = unk138->getNormal();
|
|
|
|
JGeometry::TVec3<f32> v1;
|
|
v1.cross(v2, JGeometry::TVec3<f32>(0.0f, 1.0f, 0.0f));
|
|
v1.normalize();
|
|
|
|
JGeometry::TVec3<f32> v3;
|
|
v3.cross(v1, v2);
|
|
v3.normalize();
|
|
|
|
mtx[0][0] = v1.x;
|
|
mtx[1][0] = v1.y;
|
|
mtx[2][0] = v1.z;
|
|
mtx[0][1] = v2.x;
|
|
mtx[1][1] = v2.y;
|
|
mtx[2][1] = v2.z;
|
|
mtx[0][2] = v3.x;
|
|
mtx[1][2] = v3.y;
|
|
mtx[2][2] = v3.z;
|
|
mtx[0][3] = 0.0f;
|
|
mtx[1][3] = 0.0f;
|
|
mtx[2][3] = 0.0f;
|
|
} else {
|
|
if (unk130 >= 1 && !mGroundPlane->isIllegalData()) {
|
|
JGeometry::TVec3<f32> v1(MsSin(mRotation.y), 0.0f,
|
|
MsCos(mRotation.y));
|
|
|
|
JGeometry::TVec3<f32> v2 = mGroundPlane->getNormal();
|
|
v1.cross(v2, v1);
|
|
v1.normalize();
|
|
|
|
JGeometry::TVec3<f32> v3;
|
|
v3.cross(v1, v2);
|
|
v3.normalize();
|
|
|
|
mtx[0][0] = v1.x;
|
|
mtx[1][0] = v1.y;
|
|
mtx[2][0] = v1.z;
|
|
mtx[0][1] = v2.x;
|
|
mtx[1][1] = v2.y;
|
|
mtx[2][1] = v2.z;
|
|
mtx[0][2] = v3.x;
|
|
mtx[1][2] = v3.y;
|
|
mtx[2][2] = v3.z;
|
|
mtx[0][3] = 0.0f;
|
|
mtx[1][3] = 0.0f;
|
|
mtx[2][3] = 0.0f;
|
|
} else {
|
|
MsMtxSetRotRPH(mtx, mRotation.x, mRotation.y, mRotation.z);
|
|
}
|
|
}
|
|
}
|
|
|
|
mtx[0][3] = mPosition.x;
|
|
mtx[1][3] = mPosition.y;
|
|
mtx[2][3] = mPosition.z;
|
|
}
|
|
|
|
// TODO: the frame is 8 bytes short (0x28, target 0x30).
|
|
void TSpineEnemy::calcRootMatrix()
|
|
{
|
|
if (mHolder && mHolder->getHeldObject() == this) {
|
|
MtxPtr src = mHolder->getTakingMtx();
|
|
if (src) {
|
|
getModel()->setBaseTRMtx(src);
|
|
mPosition.set(src[0][3], src[1][3], src[2][3]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
calcEnemyRootMatrix();
|
|
}
|
|
|
|
TSpineEnemyParams* TSpineEnemy::getSaveParam() const
|
|
{
|
|
return ((TEnemyManager*)mManager)->getSaveParam();
|
|
}
|
|
|
|
void TSpineEnemy::resetToPosition(const JGeometry::TVec3<f32>& position)
|
|
{
|
|
mPosition = position;
|
|
offLiveFlag(LIVE_FLAG_UNK8);
|
|
offLiveFlag(LIVE_FLAG_DEAD);
|
|
reset();
|
|
resetHitPoints();
|
|
offHitFilter(HIT_FILTER_NO_COLLISION);
|
|
mVelocity = JGeometry::TVec3<f32>(0.0f, 5.0f, 0.0f);
|
|
onLiveFlag(LIVE_FLAG_UNK8000);
|
|
onLiveFlag(LIVE_FLAG_AIRBORNE);
|
|
control();
|
|
}
|
|
|
|
void TSpineEnemy::resetSRTV(const JGeometry::TVec3<f32>& position,
|
|
const JGeometry::TVec3<f32>& rotation,
|
|
const JGeometry::TVec3<f32>& scaling,
|
|
const JGeometry::TVec3<f32>& velocity)
|
|
{
|
|
mPosition = position;
|
|
offLiveFlag(LIVE_FLAG_UNK8);
|
|
offLiveFlag(LIVE_FLAG_DEAD);
|
|
reset();
|
|
mRotation = rotation;
|
|
mScaling = scaling;
|
|
resetHitPoints();
|
|
offHitFilter(HIT_FILTER_NO_COLLISION);
|
|
mVelocity = velocity;
|
|
onLiveFlag(LIVE_FLAG_UNK8000);
|
|
onLiveFlag(LIVE_FLAG_AIRBORNE);
|
|
control();
|
|
}
|
|
|
|
f32 TSpineEnemy::calcMinimumTurnRadius(f32 param_1, f32 param_2) const
|
|
{
|
|
f32 result;
|
|
if (param_2 >= 90.0f) {
|
|
result = 0.0f;
|
|
} else {
|
|
f32 thing = MsSin(param_2);
|
|
if (thing == 0.0f)
|
|
result = 100000.0f;
|
|
else
|
|
result = param_1 * MsSin(-(param_2 * 0.5f - 90.0f)) / thing;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
f32 TSpineEnemy::calcTurnSpeedToReach(f32 march_speed, f32 param_2) const
|
|
{
|
|
if (param_2 == 0.0f)
|
|
return 0.0f;
|
|
|
|
f32 fVar12 = param_2 * 2.0f * param_2;
|
|
f32 asdf = -(march_speed * march_speed - fVar12) / fVar12;
|
|
f32 dVar11 = MsClamp(asdf, -1.0f, 1.0f);
|
|
|
|
if (dVar11 == 1.0f)
|
|
return 0.0f;
|
|
|
|
if (dVar11 == -1.0f)
|
|
return 180.0f;
|
|
|
|
f32 fVar32 = -(dVar11 * dVar11 - 1.0f);
|
|
|
|
// TODO: THitActor::calcEntryRadius has same problem
|
|
volatile f32 f = fVar32 * __frsqrte(fVar32);
|
|
f32 tmp = matan(f, dVar11) * (360.0f / 65536.0f);
|
|
return 90.0f - tmp;
|
|
}
|
|
|
|
void TSpineEnemy::updateSquareToMario()
|
|
{
|
|
// assert?
|
|
(void)&SMS_GetMarioPos();
|
|
mDistToMarioSquared = PSVECSquareDistance(&mPosition, &SMS_GetMarioPos());
|
|
}
|
|
|
|
BOOL TSpineEnemy::receiveMessage(THitActor* sender, u32 message)
|
|
{
|
|
if (message == HIT_MESSAGE_TAKE && mHolder == nullptr) {
|
|
mHolder = (TTakeActor*)sender;
|
|
return true;
|
|
}
|
|
|
|
if (message <= HIT_MESSAGE_PUSH_UP) {
|
|
kill();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
BOOL TSpineEnemy::isInSight(const JGeometry::TVec3<f32>& pos, f32 length,
|
|
f32 angle, f32 aware) const
|
|
{
|
|
return MsIsInSight(mPosition, mRotation.y, pos, length, angle, aware);
|
|
}
|
|
|
|
void TSpineEnemy::setGoalPathFromGraph()
|
|
{
|
|
JGeometry::TVec3<f32> local_48;
|
|
unk124->getCurrent().getPoint(&local_48);
|
|
setGoal(local_48);
|
|
}
|
|
|
|
void TSpineEnemy::goToInitialVisibleNode(f32, f32) { }
|
|
|
|
void TSpineEnemy::goToInitialGraphNodeCheckY(f32 param_1) { }
|
|
|
|
#pragma dont_inline on
|
|
int TSpineEnemy::goToShortestNextGraphNode()
|
|
{
|
|
if (unk124->unk0 == nullptr)
|
|
return -1;
|
|
|
|
if (unk124->mCurrIdx < 0)
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
else
|
|
unk124->moveTo(unk124->unk0->getShortestNextIndex(
|
|
unk124->mCurrIdx, unk124->mPrevIdx, -1));
|
|
|
|
if (unk124->mCurrIdx < 0)
|
|
return -1;
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
return 0;
|
|
}
|
|
#pragma dont_inline off
|
|
|
|
int TSpineEnemy::jumpToNextGraphNode()
|
|
{
|
|
if (unk124->mCurrIdx < 0 || !unk124->getCurrent().checkFlag(0x1))
|
|
return -1;
|
|
|
|
int idx = unk124->unk0->getNeighborNodeIndexByFlag(unk124->mCurrIdx,
|
|
unk124->mPrevIdx, 2);
|
|
if (idx >= 0) {
|
|
unk124->moveTo(idx);
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
return idx;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void TSpineEnemy::goToRandomNextGraphNode()
|
|
{
|
|
if (unk124->getCurGraphIndex() < 0)
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
else
|
|
unk124->moveTo(unk124->unk0->getRandomNextIndex(
|
|
unk124->getCurGraphIndex(), unk124->getPrevIndex(), -1));
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
}
|
|
|
|
void TSpineEnemy::goToRandomEscapeGraphNode()
|
|
{
|
|
if (unk124->getCurGraphIndex() < 0)
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
else
|
|
unk124->moveTo(unk124->unk0->getEscapeFromMarioIndex(
|
|
unk124->getCurGraphIndex(), -1, mPosition, -1));
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
}
|
|
|
|
void TSpineEnemy::goToExclusiveNextGraphNode()
|
|
{
|
|
if (mManager == nullptr) {
|
|
goToRandomNextGraphNode();
|
|
} else {
|
|
if (unk124->mCurrIdx < 0) {
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
} else {
|
|
int idx = unk124->unk0->getRandomNextIndex(
|
|
unk124->getCurGraphIndex(), unk124->getPrevIndex(), -1);
|
|
for (int i = 0; i < mManager->getObjNum(); ++i) {
|
|
TSpineEnemy* enemy = (TSpineEnemy*)mManager->getObj(i);
|
|
if (this != enemy && idx == enemy->unk124->mCurrIdx)
|
|
idx = unk124->unk0->getRandomNextIndex(
|
|
unk124->getCurGraphIndex(), idx, -1);
|
|
}
|
|
unk124->moveTo(idx);
|
|
}
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::goToDirectedNextGraphNode(
|
|
const JGeometry::TVec3<f32>& param_1)
|
|
{
|
|
int currIdx = unk124->mCurrIdx;
|
|
int prevIdx = unk124->mPrevIdx;
|
|
if (currIdx < 0) {
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
} else {
|
|
int idx = unk124->unk0->getAimToDirNextIndex(currIdx, prevIdx, param_1,
|
|
mPosition, -1);
|
|
unk124->moveTo(idx);
|
|
}
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
}
|
|
|
|
// TODO: fake
|
|
static inline JGeometry::TVec3<f32> polarXZ(f32 theta, f32 radius)
|
|
{
|
|
f32 c = radius * MsCos(theta);
|
|
f32 s = radius * MsSin(theta);
|
|
return JGeometry::TVec3<f32>(s, 0.0f, c);
|
|
}
|
|
|
|
void TSpineEnemy::goToDirLimitedNextGraphNode(f32 param_1)
|
|
{
|
|
int currIdx = unk124->mCurrIdx;
|
|
int prevIdx = unk124->mPrevIdx;
|
|
if (currIdx < 0) {
|
|
unk124->setTo(unk124->unk0->findNearestNodeIndex(mPosition, -1));
|
|
} else {
|
|
TGraphWeb* web = unk124->unk0;
|
|
JGeometry::TVec3<f32> local_3c = polarXZ(mRotation.y, 1.0f);
|
|
|
|
int idx = web->getRandomButDirLimited(currIdx, prevIdx, local_3c,
|
|
mPosition, param_1, -1);
|
|
unk124->moveTo(idx);
|
|
}
|
|
|
|
setGoalPathFromGraph();
|
|
unk128 = 0;
|
|
unk12C = 0.0f;
|
|
}
|
|
|
|
void TSpineEnemy::updateStayCount(f32) { }
|
|
|
|
BOOL TSpineEnemy::turnToCurPathNode(f32 param_1)
|
|
{
|
|
JGeometry::TVec3<f32> tmp = getCurrentTarget().getPoint();
|
|
tmp -= mPosition;
|
|
|
|
f32 rot = MsAngleDiff(MsGetRotFromZaxisY(tmp), mRotation.y);
|
|
|
|
BOOL uVar2 = false;
|
|
if (rot > 0.0f) {
|
|
if (rot < param_1) {
|
|
uVar2 = true;
|
|
} else {
|
|
rot = param_1;
|
|
}
|
|
} else {
|
|
if (rot > -param_1) {
|
|
uVar2 = true;
|
|
} else {
|
|
rot = -param_1;
|
|
}
|
|
}
|
|
|
|
mRotation.y = MsWrap(mRotation.y + rot, 0.0f, 360.0f);
|
|
return uVar2;
|
|
}
|
|
|
|
void TSpineEnemy::walkToCurPathNode(f32 march_speed, f32 turn_speed,
|
|
f32 param_3)
|
|
{
|
|
JGeometry::TVec3<f32> tmp = getCurrentTarget().getPoint();
|
|
tmp -= mPosition;
|
|
|
|
f32 fVar7 = tmp.length();
|
|
f32 angle = MsWrap(param_3 + MsGetRotFromZaxisY(tmp), 0.0f, 360.0f);
|
|
f32 fVar2 = MsAngleDiff(angle, mRotation.y);
|
|
|
|
f32 fVar5 = fVar2;
|
|
if (fVar7 > calcMinimumTurnRadius(march_speed, turn_speed) * 2.0f) {
|
|
if (fVar2 > 0.0f) {
|
|
fVar5 = MsMin(fVar2, turn_speed);
|
|
} else {
|
|
fVar5 = MsMax(fVar2, -turn_speed);
|
|
}
|
|
} else {
|
|
f32 fVar3 = calcTurnSpeedToReach(march_speed, fVar7 * 0.5f);
|
|
|
|
if (fVar2 > 0.0f) {
|
|
fVar5 = MsMin(fVar2, fVar3);
|
|
} else {
|
|
fVar5 = MsMax(fVar2, -fVar3);
|
|
}
|
|
}
|
|
|
|
mRotation.y = MsWrap(mRotation.y + fVar5, 0.0f, 360.0f);
|
|
|
|
JGeometry::TVec3<f32> vel = mPositionDelta;
|
|
vel += polarXZ(mRotation.y, march_speed);
|
|
mPositionDelta = vel;
|
|
|
|
if (abs(fVar7 - unk12C) < 100.0f) {
|
|
unk128 += 1;
|
|
} else {
|
|
unk128 = 0;
|
|
unk12C = fVar7;
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::zigzagToCurPathNode(f32 march_speed, f32 turn_speed,
|
|
f32 cycle, f32 angle)
|
|
{
|
|
if (unk124->unk10 == 0.0f) {
|
|
walkToCurPathNode(march_speed, turn_speed, 0.0f);
|
|
return;
|
|
}
|
|
|
|
f32 f29 = angle * unk124->unk10;
|
|
|
|
f32 dVar9 = getCurrentTargetDistance();
|
|
|
|
f32 dVar13 = MsWrap(dVar9, 0.0f, cycle);
|
|
|
|
cycle = 360.0f * (1.0f / cycle);
|
|
f32 phaseShift = getPhaseShift();
|
|
dVar13 *= cycle;
|
|
phaseShift = dVar13 + phaseShift;
|
|
f29 *= MsSin(phaseShift);
|
|
|
|
JGeometry::TVec3<f32> local_58 = mCurrentTarget.getPoint();
|
|
local_58 -= mPosition;
|
|
f32 dVar12 = f29 + MsGetRotFromZaxisY(local_58);
|
|
|
|
f32 fVar1 = MsAngleDiff(dVar12, mRotation.y);
|
|
f32 fVar2 = fVar1;
|
|
|
|
f32 fVar3 = calcMinimumTurnRadius(march_speed, turn_speed);
|
|
|
|
if (dVar9 > fVar3 * 2.0f) {
|
|
if (fVar1 > 0.0f) {
|
|
fVar2 = MsMin(fVar1, turn_speed);
|
|
} else {
|
|
fVar2 = MsMax(fVar1, -turn_speed);
|
|
}
|
|
}
|
|
|
|
mRotation.y = MsWrap(mRotation.y + fVar2, 0.0f, 360.0f);
|
|
|
|
JGeometry::TVec3<f32> vel = mPositionDelta;
|
|
vel += polarXZ(mRotation.y, march_speed);
|
|
mPositionDelta = vel;
|
|
|
|
if (abs(dVar9 - unk12C) < 100.0f) {
|
|
unk128 += 1;
|
|
} else {
|
|
unk128 = 0;
|
|
unk12C = dVar9;
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::doShortCut()
|
|
{
|
|
if (mGoalPath.size() <= 0)
|
|
return;
|
|
|
|
if (getCurrentTargetDistance() < getBodyRadius()) {
|
|
switchNextGoalPathNode();
|
|
return;
|
|
}
|
|
|
|
TPathNode node;
|
|
node = mGoalPath.peek();
|
|
|
|
JGeometry::TVec3<f32> local_28 = node.getPoint() - mPosition;
|
|
if (local_28.x == 0.0f && local_28.y == 0.0f && local_28.z == 0.0f)
|
|
local_28.x = 1.0f;
|
|
local_28.normalize();
|
|
local_28 *= mMarchSpeed;
|
|
local_28 += mPosition;
|
|
if (!gpMap->isTouchedOneWallAndMoveXZ(
|
|
&local_28.x, local_28.y + getHeadHeight(), &local_28.z,
|
|
getBodyRadius() * 2.0f)) {
|
|
switchNextGoalPathNode();
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::searchNearestBrother() const { }
|
|
|
|
f32 TSpineEnemy::getCurAnmFrameNo(int type) const
|
|
{
|
|
TEnemyManager* mgr = (TEnemyManager*)mManager;
|
|
|
|
int iVar1 = getMActor()->getCurAnmIdx(type);
|
|
TSharedMActorSet* set = mgr->getSharedMActorSet(iVar1);
|
|
if (set == nullptr) {
|
|
return getMActor()->getFrameCtrl(type)->getFrame();
|
|
} else {
|
|
return set->getMActor(getInstanceIndex())
|
|
->getFrameCtrl(type)
|
|
->getFrame();
|
|
}
|
|
}
|
|
|
|
BOOL TSpineEnemy::checkCurAnmEnd(int type) const
|
|
{
|
|
TEnemyManager* mgr = (TEnemyManager*)mManager;
|
|
|
|
int iVar1 = getMActor()->getCurAnmIdx(type);
|
|
TSharedMActorSet* set = mgr->getSharedMActorSet(iVar1);
|
|
if (set == nullptr) {
|
|
return getMActor()->curAnmEndsNext(type, nullptr);
|
|
} else {
|
|
return set->getMActor(getInstanceIndex())
|
|
->curAnmEndsNext(type, nullptr);
|
|
}
|
|
}
|
|
|
|
void TSpineEnemy::perform(u32 cue, JDrama::TGraphics* graphics)
|
|
{
|
|
TEnemyManager* mgr = (TEnemyManager*)getManager();
|
|
|
|
if (mgr != nullptr) {
|
|
if ((cue & CUE_CALC_ANIM)
|
|
&& !checkLiveFlag(LIVE_FLAG_HIDDEN | LIVE_FLAG_CLIPPED_OUT)
|
|
&& TEnemyManager::mIsCopyAnmMtx && mgr->getUnk4C() >= 0) {
|
|
if (checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_UNK200))
|
|
return;
|
|
|
|
if (mgr->copyAnmMtx(this))
|
|
return;
|
|
}
|
|
} else {
|
|
if ((cue & CUE_CALC_ANIM)
|
|
&& !checkLiveFlag(LIVE_FLAG_HIDDEN | LIVE_FLAG_CLIPPED_OUT)
|
|
&& checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_UNK200)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
TLiveActor::perform(cue, graphics);
|
|
}
|