metaforce/Runtime/MP1/World/CFlaahgraTentacle.cpp

276 lines
8.9 KiB
C++

#include "Runtime/MP1/World/CFlaahgraTentacle.hpp"
#include <array>
#include "Runtime/CStateManager.hpp"
#include "Runtime/Collision/CCollisionActor.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CScriptTrigger.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
namespace metaforce::MP1 {
namespace {
constexpr std::string_view skpTentacleTip = "Arm_12"sv;
constexpr std::array<SSphereJointInfo, 3> skJointList{{
{"Arm_8", 2.f},
{"Arm_10", 1.2f},
{"Arm_12", 1.2f},
}};
} // Anonymous namespace
CFlaahgraTentacle::CFlaahgraTentacle(TUniqueId uid, std::string_view name, const CEntityInfo& info,
const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo,
const CActorParameters& actParms)
: CPatterned(ECharacter::FlaahgraTentacle, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Large) {
GetActorLights()->SetCastShadows(false);
x460_knockBackController.SetAutoResetImpulse(false);
CreateShadow(false);
}
void CFlaahgraTentacle::Accept(IVisitor& visitor) { visitor.Visit(this); }
void CFlaahgraTentacle::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
switch (msg) {
case EScriptObjectMessage::Registered: {
x450_bodyController->Activate(mgr);
SetupCollisionManager(mgr);
break;
}
case EScriptObjectMessage::Deleted: {
x56c_collisionManager->Destroy(mgr);
if (const TCastToPtr<CScriptTrigger> trigger = mgr.ObjectById(x58c_triggerId)) {
trigger->SetForceVector(x580_forceVector);
}
break;
}
case EScriptObjectMessage::Touched: {
if (const TCastToConstPtr<CCollisionActor> colAct = mgr.GetObjectById(uid)) {
if (colAct->GetLastTouchedObject() == mgr.GetPlayer().GetUniqueId() && x420_curDamageRemTime <= 0.f) {
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), GetUniqueId(), GetContactDamage(),
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {});
x420_curDamageRemTime = x424_damageWaitTime;
}
}
break;
}
case EScriptObjectMessage::Play: {
x578_ = 0.04f;
break;
}
case EScriptObjectMessage::Deactivate: {
DeathDelete(mgr);
break;
}
case EScriptObjectMessage::Open: {
ExtractTentacle(mgr);
break;
}
case EScriptObjectMessage::Close: {
RetractTentacle(mgr);
break;
}
case EScriptObjectMessage::InitializedInArea: {
SaveBombSlotInfo(mgr);
break;
}
default:
break;
}
CPatterned::AcceptScriptMsg(msg, uid, mgr);
}
void CFlaahgraTentacle::Think(float dt, CStateManager& mgr) {
if (!GetActive()) {
return;
}
CPatterned::Think(dt, mgr);
x56c_collisionManager->Update(dt, mgr, CCollisionActorManager::EUpdateOptions::ObjectSpace);
if (x574_ > 0.f) {
x574_ -= dt;
}
if (x578_ > 0.f) {
x578_ -= dt;
}
}
void CFlaahgraTentacle::AddSphereCollisionList(const SSphereJointInfo* sphereJoints, size_t jointCount,
std::vector<CJointCollisionDescription>& outJoints) {
const CAnimData* animData = GetModelData()->GetAnimationData();
for (size_t i = 0; i < jointCount; ++i) {
const SSphereJointInfo& sphereJoint = sphereJoints[i];
const CSegId segId = animData->GetLocatorSegId(sphereJoint.name);
if (segId.IsInvalid()) {
continue;
}
outJoints.push_back(CJointCollisionDescription::SphereCollision(segId, sphereJoint.radius, sphereJoint.name, 10.f));
}
}
void CFlaahgraTentacle::SetupCollisionManager(CStateManager& mgr) {
std::vector<CJointCollisionDescription> jointList;
AddSphereCollisionList(skJointList.data(), skJointList.size(), jointList);
x56c_collisionManager =
std::make_unique<CCollisionActorManager>(mgr, GetUniqueId(), GetAreaIdAlways(), jointList, true);
for (u32 i = 0; i < x56c_collisionManager->GetNumCollisionActors(); ++i) {
const CJointCollisionDescription& desc = x56c_collisionManager->GetCollisionDescFromIndex(i);
if (const TCastToPtr<CCollisionActor> colAct = mgr.ObjectById(desc.GetCollisionActorId())) {
colAct->SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(
{EMaterialTypes::Player}, {EMaterialTypes::Character, EMaterialTypes::CollisionActor,
EMaterialTypes::NoStaticCollision, EMaterialTypes::NoPlatformCollision}));
colAct->AddMaterial(EMaterialTypes::ScanPassthrough);
colAct->SetDamageVulnerability(*GetDamageVulnerability());
if (x57c_tentacleTipAct == kInvalidUniqueId && desc.GetName() == skpTentacleTip) {
x57c_tentacleTipAct = desc.GetCollisionActorId();
}
}
}
RemoveMaterial(EMaterialTypes::Solid, EMaterialTypes::Target, EMaterialTypes::Orbit, mgr);
AddMaterial(EMaterialTypes::Scannable, mgr);
}
zeus::CVector3f CFlaahgraTentacle::GetAimPosition(const CStateManager& mgr, float dt) const {
if (const TCastToConstPtr<CCollisionActor> colAct = mgr.GetObjectById(x57c_tentacleTipAct)) {
return colAct->GetTranslation();
}
return CPatterned::GetAimPosition(mgr, dt);
}
void CFlaahgraTentacle::ExtractTentacle(CStateManager& mgr) {
if (!Inside(mgr, 0.f)) {
return;
}
x58e_24_ = true;
if (const TCastToPtr<CScriptTrigger> trigger = mgr.ObjectById(x58c_triggerId)) {
trigger->SetForceVector(x580_forceVector);
}
}
void CFlaahgraTentacle::RetractTentacle(CStateManager& mgr) {
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Crouch);
if (const TCastToPtr<CScriptTrigger> trigger = mgr.ObjectById(x58c_triggerId)) {
trigger->SetForceVector({});
}
}
void CFlaahgraTentacle::SaveBombSlotInfo(CStateManager& mgr) {
for (const SConnection& conn : GetConnectionList()) {
if (conn.x0_state != EScriptObjectState::Modify || conn.x4_msg != EScriptObjectMessage::ToggleActive) {
continue;
}
const TUniqueId uid = mgr.GetIdForScript(conn.x8_objId);
if (const TCastToConstPtr<CScriptTrigger> trigger = mgr.GetObjectById(uid)) {
x58c_triggerId = uid;
x580_forceVector = trigger->GetForceVector();
return;
}
}
}
bool CFlaahgraTentacle::ShouldAttack(CStateManager& mgr, float) {
if (x578_ > 0.f) {
return true;
}
if (x574_ > 0.f || mgr.GetPlayer().IsInWaterMovement()) {
return false;
}
if (const TCastToConstPtr<CCollisionActor> colAct = mgr.GetObjectById(x57c_tentacleTipAct)) {
const float mag = (mgr.GetPlayer().GetTranslation().toVec2f() - colAct->GetTranslation().toVec2f()).magSquared();
return mag >= (x2fc_minAttackRange * x2fc_minAttackRange) && mag <= (x300_maxAttackRange * x300_maxAttackRange);
}
return false;
}
void CFlaahgraTentacle::Attack(CStateManager& mgr, EStateMsg msg, float) {
if (msg == EStateMsg::Activate) {
x568_ = 0;
} else if (msg == EStateMsg::Update) {
if (x568_ == 0) {
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::MeleeAttack) {
x568_ = 2;
} else {
x450_bodyController->GetCommandMgr().DeliverCmd(
CBCMeleeAttackCmd((x578_ > 0.f ? pas::ESeverity::Zero : pas::ESeverity::One), {}));
}
} else if (x568_ == 2 &&
x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::MeleeAttack) {
x568_ = 3;
}
} else if (msg == EStateMsg::Deactivate) {
x574_ = (x308_attackTimeVariation * mgr.GetActiveRandom()->Float()) + x304_averageAttackTime;
x578_ = 0.f;
}
}
void CFlaahgraTentacle::Retreat(CStateManager& mgr, EStateMsg msg, float) {
if (msg == EStateMsg::Update) {
if (!x58e_24_) {
return;
}
if (x330_stateMachineState.GetTime() <= 1.f) {
return;
}
if (const TCastToConstPtr<CScriptTrigger> trigger = mgr.ObjectById(x58c_triggerId)) {
if (!trigger->IsPlayerTriggerProc()) {
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
}
}
} else if (msg == EStateMsg::Deactivate) {
x58e_24_ = false;
}
}
void CFlaahgraTentacle::InActive(CStateManager& mgr, EStateMsg msg, float arg) {
if (msg == EStateMsg::Activate) {
x570_ = 0.f;
} else if (msg == EStateMsg::Update) {
if (Inside(mgr, 0.f)) {
return;
}
if (const TCastToConstPtr<CScriptTrigger> trigger = mgr.ObjectById(x58c_triggerId)) {
if (trigger->IsPlayerTriggerProc()) {
if (x570_ > 1.f) {
RetractTentacle(mgr);
ExtractTentacle(mgr);
} else {
x570_ += arg;
}
}
}
}
}
void CFlaahgraTentacle::Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state) {
if (!IsAlive()) {
return;
}
x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "Dead");
if (GetBodyController()->GetPercentageFrozen() > 0.f) {
GetBodyController()->UnFreeze();
}
x400_25_alive = false;
}
} // namespace metaforce::MP1