metaforce/Runtime/MP1/World/CSeedling.cpp

225 lines
9.0 KiB
C++
Raw Normal View History

#include "MP1/World/CSeedling.hpp"
2018-12-06 00:46:35 +00:00
#include "World/CPatternedInfo.hpp"
#include "World/CWorld.hpp"
#include "World/CGameArea.hpp"
#include "World/CPlayer.hpp"
#include "CStateManager.hpp"
#include "TCastTo.hpp"
2018-12-06 00:46:35 +00:00
#include "CSeedling.hpp"
2018-12-08 05:30:43 +00:00
namespace urde {
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,
2018-12-06 00:46:35 +00:00
CAssetId needleId, CAssetId weaponId, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2,
float f1, float f2, float f3, float f4)
2018-09-16 23:22:35 +00:00
: CWallWalker(ECharacter::Seedling, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
2018-11-05 06:12:53 +00:00
EMovementType::Ground, EColliderType::Zero, EBodyType::WallWalker, actParms, f1, f2,
2018-11-12 04:21:36 +00:00
EKnockBackVariant::Small, f3, EWalkerType::Seedling, f4, false)
2018-12-06 00:46:35 +00:00
, 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)
2018-12-08 05:30:43 +00:00
, x722_25_curNeedleCluster(false) {
const_cast<TToken<CWeaponDescription>*>(&x6c0_projectileInfo.Token())->Lock();
CreateShadow(false);
SetKeepInThermalVisor();
}
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())
2018-12-06 00:46:35 +00:00
x5d6_26_playerObstructed = true;
}
2018-12-08 05:30:43 +00:00
}
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
if (x5d6_26_playerObstructed)
xf8_24_movable = false;
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
xf8_24_movable = !x5d6_24_alignToFloor;
CWallWalker::Think(dt, mgr);
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
if (!x5d6_25_hasAlignSurface && x450_bodyController->GetPercentageFrozen() < 0.00001f && x5d6_24_alignToFloor)
AlignToFloor(mgr, x590_colSphere.GetSphere().radius, GetTranslation() + (2.f * (dt * GetVelocity())), dt);
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
if (x71c_attackCoolOff > 0.f)
x71c_attackCoolOff -= dt;
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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);
}
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
CWallWalker::Render(mgr);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
std::experimental::optional<zeus::CAABox> CSeedling::GetTouchBounds() const {
return x704_modelBounds.getTransformedAABox(GetTransform());
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
void CSeedling::Touch(CActor& act, CStateManager& mgr) {
if (x400_25_alive) {
if (TCastToPtr<CPlayer> pl = act)
MassiveDeath(mgr);
}
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
CPatterned::Touch(act, mgr);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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;
}
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
void CSeedling::Active(CStateManager& mgr, EStateMsg msg, float arg) {
if (msg == EStateMsg::Activate)
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
CPatterned::Patrol(mgr, msg, arg);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
void CSeedling::Enraged(CStateManager&, EStateMsg msg, float) {
if (msg == EStateMsg::Activate)
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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;
}
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
bool CSeedling::ShouldAttack(CStateManager& mgr, float) {
if (x71c_attackCoolOff > 0.f)
return false;
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
return mgr.CanCreateProjectile(GetUniqueId(), EWeaponType::AI, 6);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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());
2018-12-06 00:46:35 +00:00
2018-12-08 05:30:43 +00:00
x722_25_curNeedleCluster = !x722_25_curNeedleCluster;
x722_24_renderOnlyClusterA = false;
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
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);
2018-12-06 00:46:35 +00:00
}
2018-12-08 05:30:43 +00:00
} // namespace MP1
} // namespace urde