mirror of https://github.com/AxioDL/metaforce.git
Implement CSeedling
This commit is contained in:
parent
eafe1d54a6
commit
dd705a3db9
|
@ -91,9 +91,9 @@ public:
|
|||
CBCGenerateCmd(pas::EGenerateType type, s32 animId = -1)
|
||||
: CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type), x18_animId(animId)
|
||||
{ x1c_24_targetTransform = false; x1c_25_overrideAnim = false; }
|
||||
CBCGenerateCmd(pas::EGenerateType type, const zeus::CVector3f& vec)
|
||||
CBCGenerateCmd(pas::EGenerateType type, const zeus::CVector3f& vec, bool targetTransform = false, bool overrideAnim = false)
|
||||
: CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type), xc_targetPos(vec)
|
||||
{ x1c_24_targetTransform = false; x1c_25_overrideAnim = false; }
|
||||
{ x1c_24_targetTransform = targetTransform; x1c_25_overrideAnim = overrideAnim; }
|
||||
pas::EGenerateType GetGenerateType() const { return x8_type; }
|
||||
const zeus::CVector3f& GetExitTargetPos() const { return xc_targetPos; }
|
||||
bool HasExitTargetPos() const { return x1c_24_targetTransform; }
|
||||
|
|
|
@ -7,21 +7,21 @@ namespace pas
|
|||
enum class ELocomotionType
|
||||
{
|
||||
Invalid = -1,
|
||||
Crouch,
|
||||
Relaxed,
|
||||
Lurk,
|
||||
Combat,
|
||||
Internal4,
|
||||
Internal5,
|
||||
Internal6,
|
||||
Internal7,
|
||||
Internal8,
|
||||
Internal9,
|
||||
Internal10,
|
||||
Internal11,
|
||||
Internal12,
|
||||
Internal13,
|
||||
Internal14
|
||||
Crouch = 0,
|
||||
Relaxed = 1,
|
||||
Lurk = 2,
|
||||
Combat = 3,
|
||||
Internal4 = 4,
|
||||
Internal5 = 5,
|
||||
Internal6 = 6,
|
||||
Internal7 = 7,
|
||||
Internal8 = 8,
|
||||
Internal9 = 9,
|
||||
Internal10 = 10,
|
||||
Internal11 = 11,
|
||||
Internal12 = 12,
|
||||
Internal13 = 13,
|
||||
Internal14 = 14
|
||||
};
|
||||
|
||||
enum class ELocomotionAnim
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#include "MP1/World/CSeedling.hpp"
|
||||
#include "World/CPatternedInfo.hpp"
|
||||
#include "World/CWorld.hpp"
|
||||
#include "World/CGameArea.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
#include "CSeedling.hpp"
|
||||
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -8,12 +15,21 @@ namespace MP1
|
|||
|
||||
CSeedling::CSeedling(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
|
||||
CAssetId, CAssetId, const CDamageInfo&, const CDamageInfo&, float f1, float f2, float f3, float f4)
|
||||
CAssetId needleId, CAssetId weaponId, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2,
|
||||
float f1, float f2, float f3, float f4)
|
||||
: CWallWalker(ECharacter::Seedling, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
|
||||
EMovementType::Ground, EColliderType::Zero, EBodyType::WallWalker, actParms, f1, f2,
|
||||
EKnockBackVariant::Small, f3, EWalkerType::Seedling, f4, false)
|
||||
, x5d8_searchPath(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
||||
, x6bc_spikeData(new CModelData(CStaticRes(needleId, GetModelData()->GetScale())))
|
||||
, x6c0_projectileInfo(weaponId, dInfo1)
|
||||
, x6e8_deathDamage(dInfo2)
|
||||
, x722_24_renderOnlyClusterA(true)
|
||||
, x722_25_curNeedleCluster(false)
|
||||
{
|
||||
|
||||
const_cast<TToken<CWeaponDescription>*>(&x6c0_projectileInfo.Token())->Lock();
|
||||
CreateShadow(false);
|
||||
SetKeepInThermalVisor();
|
||||
}
|
||||
|
||||
void CSeedling::Accept(IVisitor& visitor)
|
||||
|
@ -21,5 +37,228 @@ void CSeedling::Accept(IVisitor& visitor)
|
|||
visitor.Visit(this);
|
||||
}
|
||||
|
||||
const std::string CSeedling::skNeedleLocators[2][6] =
|
||||
{
|
||||
{
|
||||
"A_spike1_LCTR_SDK",
|
||||
"A_spike2_LCTR_SDK",
|
||||
"A_spike3_LCTR_SDK",
|
||||
"A_spike4_LCTR_SDK",
|
||||
"A_spike5_LCTR_SDK",
|
||||
"A_spike6_LCTR_SDK",
|
||||
},
|
||||
{
|
||||
"B_spike1_LCTR_SDK",
|
||||
"B_spike2_LCTR_SDK",
|
||||
"B_spike3_LCTR_SDK",
|
||||
"B_spike4_LCTR_SDK",
|
||||
"B_spike5_LCTR_SDK",
|
||||
"B_spike6_LCTR_SDK",
|
||||
}
|
||||
};
|
||||
|
||||
void CSeedling::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
|
||||
{
|
||||
CPatterned::AcceptScriptMsg(msg, uid, mgr);
|
||||
|
||||
if (msg == EScriptObjectMessage::Activate)
|
||||
{
|
||||
x5d6_27_disableMove = false;
|
||||
TUniqueId id = GetWaypointForState(mgr, EScriptObjectState::Patrol, EScriptObjectMessage::Follow);
|
||||
if (id != kInvalidUniqueId)
|
||||
x2dc_destObj = id;
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Registered)
|
||||
{
|
||||
x450_bodyController->Activate(mgr);
|
||||
x704_modelBounds = GetModelData()->GetBounds();
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::InitializedInArea)
|
||||
{
|
||||
x5d8_searchPath.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea);
|
||||
}
|
||||
}
|
||||
|
||||
void CSeedling::Think(float dt, CStateManager& mgr)
|
||||
{
|
||||
if (!GetActive())
|
||||
return;
|
||||
|
||||
++x5d4_thinkCounter;
|
||||
x5d6_26_playerObstructed = false;
|
||||
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways());
|
||||
CGameArea::EOcclusionState occlusionState = CGameArea::EOcclusionState::Occluded;
|
||||
if (area && area->IsPostConstructed())
|
||||
occlusionState = area->GetPostConstructed()->x10dc_occlusionState;
|
||||
|
||||
if (occlusionState == CGameArea::EOcclusionState::Occluded)
|
||||
x5d6_26_playerObstructed = true;
|
||||
|
||||
if (!x5d6_26_playerObstructed)
|
||||
{
|
||||
zeus::CVector3f playerPos = mgr.GetPlayer().GetTranslation();
|
||||
float distance = (playerPos - GetTranslation()).magnitude();
|
||||
if (distance > x5c4_playerObstructionMinDist)
|
||||
{
|
||||
zeus::CVector3f direction = (playerPos - GetTranslation()).normalized();
|
||||
CRayCastResult result = mgr.RayStaticIntersection(playerPos, direction, distance,
|
||||
CMaterialFilter::skPassEverything);
|
||||
if (result.IsValid())
|
||||
x5d6_26_playerObstructed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (x5d6_26_playerObstructed)
|
||||
xf8_24_movable = false;
|
||||
|
||||
xf8_24_movable = !x5d6_24_alignToFloor;
|
||||
CWallWalker::Think(dt, mgr);
|
||||
|
||||
if (!x5d6_25_hasAlignSurface && x450_bodyController->GetPercentageFrozen() < 0.00001f && x5d6_24_alignToFloor)
|
||||
AlignToFloor(mgr, x590_colSphere.GetSphere().radius, GetTranslation() + (2.f * (dt * GetVelocity())), dt);
|
||||
|
||||
if (x71c_attackCoolOff > 0.f)
|
||||
x71c_attackCoolOff -= dt;
|
||||
}
|
||||
|
||||
void CSeedling::Render(const CStateManager& mgr) const
|
||||
{
|
||||
if (x400_25_alive && x6bc_spikeData)
|
||||
{
|
||||
u32 index = x722_24_renderOnlyClusterA ? 0 : u32(x722_25_curNeedleCluster);
|
||||
CModelFlags flags;
|
||||
flags.x2_flags = 3;
|
||||
flags.x4_color = zeus::CColor::skWhite;
|
||||
|
||||
for (const std::string& sv : skNeedleLocators[index])
|
||||
x6bc_spikeData->Render(mgr, GetLctrTransform(sv), x90_actorLights.get(), flags);
|
||||
}
|
||||
|
||||
CWallWalker::Render(mgr);
|
||||
}
|
||||
|
||||
void CSeedling::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
|
||||
{
|
||||
if (type == EUserEventType::Projectile)
|
||||
LaunchNeedles(mgr);
|
||||
else if (type == EUserEventType::BeginAction)
|
||||
x722_24_renderOnlyClusterA = true;
|
||||
else
|
||||
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
|
||||
}
|
||||
|
||||
std::experimental::optional<zeus::CAABox> CSeedling::GetTouchBounds() const
|
||||
{
|
||||
return x704_modelBounds.getTransformedAABox(GetTransform());
|
||||
}
|
||||
|
||||
void CSeedling::Touch(CActor& act, CStateManager& mgr)
|
||||
{
|
||||
if (x400_25_alive)
|
||||
{
|
||||
if (TCastToPtr<CPlayer> pl = act)
|
||||
MassiveDeath(mgr);
|
||||
}
|
||||
|
||||
CPatterned::Touch(act, mgr);
|
||||
}
|
||||
|
||||
void CSeedling::Patrol(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
|
||||
x5d6_24_alignToFloor = true;
|
||||
x150_momentum.zeroOut();
|
||||
x5d6_25_hasAlignSurface = false;
|
||||
xf8_24_movable = false;
|
||||
|
||||
TUniqueId id = (x720_prevObj != kInvalidUniqueId ? x720_prevObj :
|
||||
GetWaypointForState(mgr, EScriptObjectState::Patrol,
|
||||
EScriptObjectMessage::Follow));
|
||||
|
||||
if (id != kInvalidUniqueId)
|
||||
x2dc_destObj = id;
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
UpdateWPDestination(mgr);
|
||||
zeus::CVector3f upVec = GetTransform().upVector();
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(
|
||||
CBCLocomotionCmd(ProjectVectorToPlane((x2e0_destPos - GetTranslation()).normalized(), upVec), {}, 0.f));
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
||||
ProjectVectorToPlane(ProjectVectorToPlane(x45c_steeringBehaviors.Seek(*this, x2e0_destPos), upVec), upVec),
|
||||
{}, 1.f));
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(1.f * GetTransform().frontVector(), {}, 0.f));
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x720_prevObj = x2dc_destObj;
|
||||
}
|
||||
}
|
||||
|
||||
void CSeedling::Active(CStateManager& mgr, EStateMsg msg, float arg)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
||||
CPatterned::Patrol(mgr, msg, arg);
|
||||
}
|
||||
|
||||
void CSeedling::Enraged(CStateManager&, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8);
|
||||
}
|
||||
|
||||
void CSeedling::ProjectileAttack(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x32c_animState = EAnimState::One;
|
||||
else if (msg == EStateMsg::Update)
|
||||
TryCommand(mgr, pas::EAnimationState::ProjectileAttack, &CPatterned::TryProjectileAttack, 0);
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x32c_animState = EAnimState::Zero;
|
||||
x71c_attackCoolOff = (x300_maxAttackRange * mgr.GetActiveRandom()->Float()) + x304_averageAttackTime;
|
||||
}
|
||||
}
|
||||
|
||||
void CSeedling::Generate(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x32c_animState = EAnimState::One;
|
||||
else if (msg == EStateMsg::Update)
|
||||
TryCommand(mgr, pas::EAnimationState::Generate, &CPatterned::TryGenerate, 0);
|
||||
}
|
||||
|
||||
bool CSeedling::ShouldAttack(CStateManager& mgr, float)
|
||||
{
|
||||
if (x71c_attackCoolOff > 0.f)
|
||||
return false;
|
||||
|
||||
return mgr.CanCreateProjectile(GetUniqueId(), EWeaponType::AI, 6);
|
||||
}
|
||||
|
||||
void CSeedling::LaunchNeedles(CStateManager& mgr)
|
||||
{
|
||||
for (const std::string& needle : skNeedleLocators[u32(x722_25_curNeedleCluster)])
|
||||
LaunchProjectile(GetLctrTransform(needle), mgr, 6, EProjectileAttrib::None, true, {}, 0xFFFF, false,
|
||||
GetModelData()->GetScale());
|
||||
|
||||
x722_25_curNeedleCluster = !x722_25_curNeedleCluster;
|
||||
x722_24_renderOnlyClusterA = false;
|
||||
}
|
||||
|
||||
void CSeedling::MassiveDeath(CStateManager& mgr)
|
||||
{
|
||||
if (x400_25_alive)
|
||||
{
|
||||
mgr.ApplyDamageToWorld(GetUniqueId(), *this, GetTranslation(), x6e8_deathDamage,
|
||||
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}));
|
||||
LaunchNeedles(mgr);
|
||||
}
|
||||
CPatterned::MassiveDeath(mgr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "World/CWallWalker.hpp"
|
||||
#include "World/CPathFindSearch.hpp"
|
||||
#include "Weapon/CProjectileInfo.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -8,6 +10,17 @@ namespace MP1
|
|||
{
|
||||
class CSeedling : public CWallWalker
|
||||
{
|
||||
static const std::string skNeedleLocators[2][6];
|
||||
CPathFindSearch x5d8_searchPath;
|
||||
std::unique_ptr<CModelData> x6bc_spikeData;
|
||||
CProjectileInfo x6c0_projectileInfo;
|
||||
CDamageInfo x6e8_deathDamage;
|
||||
zeus::CAABox x704_modelBounds = zeus::CAABox::skNullBox;
|
||||
float x71c_attackCoolOff = 0.f;
|
||||
TUniqueId x720_prevObj = kInvalidUniqueId;
|
||||
bool x722_24_renderOnlyClusterA : 1;
|
||||
bool x722_25_curNeedleCluster : 1;
|
||||
void LaunchNeedles(CStateManager&);
|
||||
public:
|
||||
DEFINE_PATTERNED(Seedling)
|
||||
CSeedling(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&,
|
||||
|
@ -16,6 +29,21 @@ public:
|
|||
float, float, float, float);
|
||||
|
||||
void Accept(IVisitor&);
|
||||
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
|
||||
void Think(float, CStateManager&);
|
||||
void Render(const CStateManager&) const;
|
||||
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt);
|
||||
CProjectileInfo* GetProjectileInfo() { return &x6c0_projectileInfo; }
|
||||
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
|
||||
void Touch(CActor&, CStateManager&);
|
||||
CPathFindSearch* GetSearchPath() { return &x5d8_searchPath; }
|
||||
void Patrol(CStateManager&, EStateMsg, float);
|
||||
void Active(CStateManager&, EStateMsg, float);
|
||||
void Enraged(CStateManager&, EStateMsg, float);
|
||||
void ProjectileAttack(CStateManager&, EStateMsg, float);
|
||||
void Generate(CStateManager&, EStateMsg, float);
|
||||
bool ShouldAttack(CStateManager&, float);
|
||||
void MassiveDeath(CStateManager&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1026,6 +1026,16 @@ void CPatterned::TryLoopReaction(CStateManager& mgr, int arg)
|
|||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType(arg)));
|
||||
}
|
||||
|
||||
void CPatterned::TryProjectileAttack(CStateManager&, int arg)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCProjectileAttackCmd(pas::ESeverity(arg), x2e0_destPos, false));
|
||||
}
|
||||
|
||||
void CPatterned::TryGenerate(CStateManager& mgr, int arg)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType(arg), x2e0_destPos, true));
|
||||
}
|
||||
|
||||
void CPatterned::BuildBodyController(EBodyType bodyType)
|
||||
{
|
||||
if (x450_bodyController)
|
||||
|
|
|
@ -381,6 +381,8 @@ public:
|
|||
|
||||
void TryCommand(CStateManager& mgr, pas::EAnimationState state, CPatternedTryFunc func, int arg);
|
||||
void TryLoopReaction(CStateManager& mgr, int arg);
|
||||
void TryProjectileAttack(CStateManager& mgr, int arg);
|
||||
void TryGenerate(CStateManager& mgr, int arg);
|
||||
|
||||
virtual bool KnockbackWhenFrozen() const { return true; }
|
||||
virtual void MassiveDeath(CStateManager& mgr);
|
||||
|
@ -422,6 +424,12 @@ public:
|
|||
bool CanLongJump() const { return x328_26_longJump; }
|
||||
bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; }
|
||||
|
||||
void SetKeepInThermalVisor()
|
||||
{
|
||||
x403_24_keepThermalVisorState = true;
|
||||
xe6_27_thermalVisorFlags = 1 | 2;
|
||||
}
|
||||
|
||||
//region Casting Functions
|
||||
|
||||
template <class T>
|
||||
|
|
Loading…
Reference in New Issue