2016-05-18 03:57:43 +00:00
|
|
|
#include "CBeetle.hpp"
|
2018-12-31 05:01:42 +00:00
|
|
|
#include "CStateManager.hpp"
|
2016-05-18 03:57:43 +00:00
|
|
|
#include "World/CDamageInfo.hpp"
|
2016-08-23 03:12:50 +00:00
|
|
|
#include "Character/CCharLayoutInfo.hpp"
|
2017-01-15 03:07:01 +00:00
|
|
|
#include "TCastTo.hpp"
|
2018-12-31 05:01:42 +00:00
|
|
|
#include "World/CPatternedInfo.hpp"
|
|
|
|
#include "Character/CPASAnimParmData.hpp"
|
|
|
|
#include "World/CTeamAiMgr.hpp"
|
|
|
|
#include "World/CWorld.hpp"
|
|
|
|
#include "World/CPlayer.hpp"
|
|
|
|
#include "World/CScriptWaypoint.hpp"
|
2016-05-18 03:57:43 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
namespace urde::MP1 {
|
2016-05-18 03:57:43 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
CBeetle::CBeetle(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
|
|
|
CModelData&& mData, const CPatternedInfo& pInfo, CPatterned::EFlavorType flavor,
|
2018-12-31 05:01:42 +00:00
|
|
|
CBeetle::EEntranceType entranceType, const CDamageInfo& touchDamage,
|
|
|
|
const CDamageVulnerability& platingVuln, const zeus::CVector3f& tailAimReference,
|
|
|
|
float initialAttackDelay, float retreatTime, float f3,
|
|
|
|
const CDamageVulnerability& tailVuln, const CActorParameters& aParams,
|
2019-06-12 02:05:17 +00:00
|
|
|
const std::optional<CStaticRes>& tailModel)
|
2018-12-08 05:30:43 +00:00
|
|
|
: CPatterned(ECharacter::Beetle, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Ground,
|
2018-12-31 05:01:42 +00:00
|
|
|
EColliderType::One, EBodyType::BiPedal, aParams, EKnockBackVariant(flavor))
|
|
|
|
, x56c_entranceType(entranceType)
|
|
|
|
, x574_tailAimReference(tailAimReference)
|
|
|
|
, x580_f3(f3)
|
|
|
|
, x584_touchDamage(touchDamage)
|
2019-06-12 02:05:17 +00:00
|
|
|
, x5ac_tailModel(tailModel ? std::optional<CModelData>(CModelData(*tailModel)) :
|
|
|
|
std::optional<CModelData>())
|
2018-12-31 05:01:42 +00:00
|
|
|
, x5fc_pathFindSearch(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
|
|
|
, x744_platingVuln(platingVuln)
|
|
|
|
, x7ac_tailVuln(tailVuln)
|
|
|
|
, x814_attackDelayTimer(initialAttackDelay)
|
|
|
|
, x834_retreatTime(retreatTime) {
|
|
|
|
x5a0_headbuttDist = GetAnimationDistance(CPASAnimParmData(7, CPASAnimParm::FromEnum(0), CPASAnimParm::FromEnum(1)));
|
2019-01-31 20:44:05 +00:00
|
|
|
x5a4_jumpBackwardDist =
|
|
|
|
x64_modelData->GetScale().y() *
|
|
|
|
GetAnimationDistance(CPASAnimParmData(3, CPASAnimParm::FromEnum(1), CPASAnimParm::FromEnum(0)));
|
2018-12-31 05:01:42 +00:00
|
|
|
MakeThermalColdAndHot();
|
|
|
|
if (x3fc_flavor == EFlavorType::One)
|
|
|
|
x460_knockBackController.SetLocomotionDuringElectrocution(true);
|
|
|
|
}
|
2016-05-18 03:57:43 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CBeetle::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
2016-05-18 03:57:43 +00:00
|
|
|
|
2018-12-31 05:01:42 +00:00
|
|
|
void CBeetle::SquadAdd(CStateManager& mgr) {
|
|
|
|
if (x570_aiMgr != kInvalidUniqueId)
|
|
|
|
if (TCastToPtr<CTeamAiMgr> aimgr = mgr.ObjectById(x570_aiMgr))
|
2019-01-31 20:44:05 +00:00
|
|
|
aimgr->AssignTeamAiRole(*this, CTeamAiRole::ETeamAiRole::Melee, CTeamAiRole::ETeamAiRole::Unknown,
|
|
|
|
CTeamAiRole::ETeamAiRole::Invalid);
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::SquadRemove(CStateManager& mgr) {
|
|
|
|
if (x570_aiMgr != kInvalidUniqueId)
|
|
|
|
if (TCastToPtr<CTeamAiMgr> aimgr = mgr.ObjectById(x570_aiMgr))
|
|
|
|
if (aimgr->IsPartOfTeam(GetUniqueId()))
|
|
|
|
aimgr->RemoveTeamAiRole(GetUniqueId());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Think(float dt, CStateManager& mgr) {
|
|
|
|
if (!GetActive())
|
|
|
|
return;
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId())) {
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->SetLocomotionType(role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Melee
|
|
|
|
? pas::ELocomotionType::Lurk
|
|
|
|
: pas::ELocomotionType::Relaxed);
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
|
|
|
SquadAdd(mgr);
|
|
|
|
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
|
|
|
}
|
|
|
|
x460_knockBackController.SetAutoResetImpulse(IsOnGround());
|
|
|
|
if (x814_attackDelayTimer > 0.f)
|
|
|
|
x814_attackDelayTimer -= dt;
|
|
|
|
if ((x824_predictPos - GetTranslation()).toVec2f().magSquared() > 0.1f * dt)
|
|
|
|
x820_posDeviationCounter += 1;
|
|
|
|
else
|
|
|
|
x820_posDeviationCounter = 0;
|
|
|
|
CPatterned::Think(dt, mgr);
|
|
|
|
x824_predictPos = x138_velocity * dt + GetTranslation();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::SetupRetreatPoints(CStateManager& mgr) {
|
|
|
|
for (const auto& conn : GetConnectionList()) {
|
|
|
|
if (conn.x0_state == EScriptObjectState::Retreat && conn.x4_msg == EScriptObjectMessage::Follow) {
|
|
|
|
if (TCastToConstPtr<CScriptWaypoint> wp = mgr.GetObjectById(mgr.GetIdForScript(conn.x8_objId))) {
|
|
|
|
x6e0_retreatPoints.push_back(wp->GetTranslation());
|
|
|
|
if (x6e0_retreatPoints.size() == 8)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
|
|
|
|
bool forward = true;
|
|
|
|
switch (msg) {
|
|
|
|
case EScriptObjectMessage::Activate:
|
|
|
|
SquadAdd(mgr);
|
|
|
|
break;
|
|
|
|
case EScriptObjectMessage::Deactivate:
|
|
|
|
case EScriptObjectMessage::Deleted:
|
|
|
|
SquadRemove(mgr);
|
|
|
|
break;
|
|
|
|
case EScriptObjectMessage::OnFloor:
|
|
|
|
forward = false;
|
2019-02-24 07:15:54 +00:00
|
|
|
SetMomentumWR(zeus::skZero3f);
|
2018-12-31 05:01:42 +00:00
|
|
|
x328_27_onGround = true;
|
|
|
|
break;
|
|
|
|
case EScriptObjectMessage::Falling:
|
|
|
|
if (!x450_bodyController->IsFrozen()) {
|
|
|
|
SetMomentumWR({0.f, 0.f, -(GetGravityConstant() * xe8_mass)});
|
|
|
|
x328_27_onGround = false;
|
|
|
|
}
|
|
|
|
forward = false;
|
|
|
|
break;
|
|
|
|
case EScriptObjectMessage::InitializedInArea:
|
|
|
|
if (x570_aiMgr == kInvalidUniqueId) {
|
|
|
|
x570_aiMgr = CTeamAiMgr::GetTeamAiMgr(*this, mgr);
|
|
|
|
if (GetActive())
|
|
|
|
SquadAdd(mgr);
|
|
|
|
}
|
|
|
|
SetupRetreatPoints(mgr);
|
2019-01-31 20:44:05 +00:00
|
|
|
x5fc_pathFindSearch.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea);
|
2018-12-31 05:01:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (forward)
|
|
|
|
CPatterned::AcceptScriptMsg(msg, sender, mgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
|
|
|
|
if (x400_25_alive) {
|
|
|
|
switch (mgr.GetPlayerState()->GetActiveVisor(mgr)) {
|
|
|
|
case CPlayerState::EPlayerVisor::XRay:
|
|
|
|
x42c_color.a() = 76.5f / 255.f;
|
|
|
|
break;
|
|
|
|
case CPlayerState::EPlayerVisor::Thermal:
|
|
|
|
if (x838_25_burrowing)
|
|
|
|
x42c_color.a() = x830_intoGroundFactor;
|
|
|
|
else
|
|
|
|
x42c_color.a() = 1.f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
x42c_color.a() = 1.f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CPatterned::PreRender(mgr, frustum);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Render(const CStateManager& mgr) const {
|
|
|
|
if (x3fc_flavor == EFlavorType::One && x400_25_alive) {
|
|
|
|
zeus::CTransform tailXf = GetLctrTransform("Target_Tail"sv);
|
|
|
|
if (x428_damageCooldownTimer >= 0.f && x42c_color.a() == 1.f) {
|
|
|
|
if (x5ac_tailModel) {
|
2019-02-24 07:15:54 +00:00
|
|
|
CModelFlags flags(2, 0, 3, zeus::skWhite);
|
2018-12-31 05:01:42 +00:00
|
|
|
flags.addColor = x42c_color;
|
|
|
|
x5ac_tailModel->Render(mgr, tailXf, x90_actorLights.get(), flags);
|
|
|
|
}
|
|
|
|
} else if (x5ac_tailModel) {
|
2019-02-24 07:15:54 +00:00
|
|
|
CModelFlags flags(0, 0, 3, zeus::skWhite);
|
2018-12-31 05:01:42 +00:00
|
|
|
x5ac_tailModel->Render(mgr, tailXf, x90_actorLights.get(), flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CPatterned::Render(mgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
const CDamageVulnerability* CBeetle::GetDamageVulnerability() const {
|
|
|
|
if (x838_25_burrowing)
|
|
|
|
return &CDamageVulnerability::PassThroughVulnerabilty();
|
|
|
|
if (x3fc_flavor == EFlavorType::One)
|
|
|
|
return x450_bodyController->IsOnFire() ? &x7ac_tailVuln : &x744_platingVuln;
|
|
|
|
return CAi::GetDamageVulnerability();
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
const CDamageVulnerability* CBeetle::GetDamageVulnerability(const zeus::CVector3f& pos, const zeus::CVector3f& dir,
|
2018-12-31 05:01:42 +00:00
|
|
|
const CDamageInfo& dInfo) const {
|
|
|
|
if (x838_25_burrowing)
|
|
|
|
return &CDamageVulnerability::PassThroughVulnerabilty();
|
|
|
|
if (x3fc_flavor == EFlavorType::One) {
|
|
|
|
if (dInfo.GetWeaponMode().IsComboed() && dInfo.GetWeaponMode().GetType() == EWeaponType::Wave)
|
|
|
|
return &x7ac_tailVuln;
|
|
|
|
if (GetTransform().basis[1].dot(dir) > 0.f &&
|
|
|
|
GetTransform().basis[1].dot(zeus::CUnitVector3f(pos - GetBoundingBox().center())) < -0.5f)
|
|
|
|
return &x7ac_tailVuln;
|
|
|
|
else
|
|
|
|
return &x744_platingVuln;
|
|
|
|
}
|
|
|
|
return GetDamageVulnerability();
|
|
|
|
}
|
|
|
|
|
|
|
|
zeus::CVector3f CBeetle::GetOrbitPosition(const CStateManager& mgr) const {
|
|
|
|
zeus::CVector3f ret = CPatterned::GetOrbitPosition(mgr);
|
|
|
|
ret.z() = float(GetBoundingBox().center().z());
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
zeus::CVector3f CBeetle::GetAimPosition(const CStateManager& mgr, float dt) const {
|
|
|
|
if (x3fc_flavor == EFlavorType::One || x3fc_flavor == EFlavorType::Two) {
|
|
|
|
zeus::CTransform tailXf = GetLctrTransform("Target_Tail"sv);
|
|
|
|
zeus::CVector3f scaleRange = tailXf * x574_tailAimReference - GetTranslation();
|
|
|
|
zeus::CAABox aabb = GetBoundingBox();
|
|
|
|
float minFactor = 10.f;
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
if (scaleRange[i] < 0.f) {
|
|
|
|
float factor = (aabb.min[i] - GetTranslation()[i]) / scaleRange[i];
|
|
|
|
if (factor < minFactor)
|
|
|
|
minFactor = factor;
|
|
|
|
} else if (scaleRange[i] > 0.f) {
|
|
|
|
float factor = (aabb.max[i] - GetTranslation()[i]) / scaleRange[i];
|
|
|
|
if (factor < minFactor)
|
|
|
|
minFactor = factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return scaleRange * minFactor + GetTranslation();
|
|
|
|
} else {
|
|
|
|
return CPhysicsActor::GetAimPosition(mgr, dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
EWeaponCollisionResponseTypes CBeetle::GetCollisionResponseType(const zeus::CVector3f& pos, const zeus::CVector3f& dir,
|
2018-12-31 05:01:42 +00:00
|
|
|
const CWeaponMode& wMode,
|
|
|
|
EProjectileAttrib attribs) const {
|
|
|
|
if (x450_bodyController->IsFrozen() && wMode.GetType() == EWeaponType::Ice)
|
|
|
|
return EWeaponCollisionResponseTypes::None;
|
2019-01-31 20:44:05 +00:00
|
|
|
if (x838_25_burrowing)
|
2018-12-31 05:01:42 +00:00
|
|
|
return EWeaponCollisionResponseTypes::Unknown69;
|
|
|
|
if (x3fc_flavor == EFlavorType::One) {
|
|
|
|
if (GetTransform().basis[1].dot(dir) > 0.f &&
|
|
|
|
GetTransform().basis[1].dot(zeus::CUnitVector3f(pos - GetBoundingBox().center())) < -0.5f)
|
|
|
|
return EWeaponCollisionResponseTypes::Unknown44;
|
|
|
|
if (!x744_platingVuln.WeaponHurts(wMode, false))
|
|
|
|
return EWeaponCollisionResponseTypes::Unknown69;
|
|
|
|
}
|
|
|
|
return EWeaponCollisionResponseTypes::Unknown19;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) {
|
|
|
|
bool handled = false;
|
|
|
|
switch (type) {
|
|
|
|
case EUserEventType::ChangeMaterial:
|
|
|
|
AddMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, mgr);
|
|
|
|
x328_25_verticalMovement = true;
|
|
|
|
RemoveMaterial(EMaterialTypes::GroundCollider, mgr);
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
case EUserEventType::GenerateEnd:
|
|
|
|
x328_25_verticalMovement = false;
|
|
|
|
AddMaterial(EMaterialTypes::GroundCollider, mgr);
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
case EUserEventType::DamageOn: {
|
|
|
|
zeus::CVector3f center =
|
2019-01-31 20:44:05 +00:00
|
|
|
GetTransform() * (x64_modelData->GetScale() * GetLocatorTransform("LCTR_GARMOUTH"sv).origin);
|
2018-12-31 05:01:42 +00:00
|
|
|
zeus::CVector3f extent = x64_modelData->GetScale() * zeus::CVector3f(2.f, 2.f, 0.5f);
|
|
|
|
if (zeus::CAABox(center - extent, center + extent).intersects(mgr.GetPlayer().GetBoundingBox())) {
|
|
|
|
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), GetUniqueId(), x584_touchDamage,
|
2019-02-24 07:15:54 +00:00
|
|
|
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f);
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EUserEventType::Delete:
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!handled)
|
|
|
|
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::CollidedWith(TUniqueId uid, const CCollisionInfoList& list, CStateManager& mgr) {
|
|
|
|
static CMaterialList envList(EMaterialTypes::Ceiling, EMaterialTypes::Wall);
|
|
|
|
for (const auto& c : list) {
|
|
|
|
if (c.GetMaterialLeft().Intersection(envList) != 0 &&
|
|
|
|
x450_bodyController->GetCurrentStateId() == pas::EAnimationState::MeleeAttack) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::NextState));
|
2019-02-24 07:15:54 +00:00
|
|
|
SetVelocityWR(zeus::skZero3f);
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CPatterned::CollidedWith(uid, list, mgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state) {
|
|
|
|
if (x400_25_alive) {
|
|
|
|
if (x3fc_flavor == EFlavorType::One) {
|
|
|
|
zeus::CTransform backupXf = GetTransform();
|
|
|
|
SetTransform(GetLctrTransform("Target_Tail"sv));
|
|
|
|
SendScriptMsgs(EScriptObjectState::DeathRattle, mgr, EScriptObjectMessage::None);
|
|
|
|
SetTransform(backupXf);
|
|
|
|
}
|
|
|
|
CPatterned::Death(mgr, direction, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
void CBeetle::TakeDamage(const zeus::CVector3f& direction, float magnitude) { x428_damageCooldownTimer = 0.33f; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::IsListening() const { return true; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
|
|
|
zeus::CVector3f CBeetle::GetOrigin(const CStateManager& mgr, const CTeamAiRole& role,
|
|
|
|
const zeus::CVector3f& aimPos) const {
|
|
|
|
float midRange = (x2fc_minAttackRange + x300_maxAttackRange) * 0.5f;
|
|
|
|
zeus::CVector3f playerToThis = GetTranslation() - aimPos;
|
|
|
|
if (playerToThis.canBeNormalized())
|
|
|
|
return aimPos + playerToThis.normalized() * midRange;
|
|
|
|
else
|
|
|
|
return aimPos + GetTransform().basis[1] * midRange;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::FollowPattern(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 1;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 1:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Step) {
|
|
|
|
x568_stateProg = 3;
|
|
|
|
} else if (IsOnGround()) {
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection::Left, pas::EStepType::Normal));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Step && IsOnGround()) {
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection::Right, pas::EStepType::Normal));
|
2018-12-31 05:01:42 +00:00
|
|
|
x568_stateProg = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Step)
|
|
|
|
x568_stateProg = x814_attackDelayTimer <= 0.f ? 4 : 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverTargetVector(mgr.GetPlayer().GetTranslation() - GetTranslation());
|
2018-12-31 05:01:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::RefinePathFindDest(CStateManager& mgr, zeus::CVector3f& dest) {
|
|
|
|
dest = mgr.GetPlayer().GetTranslation();
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId())) {
|
|
|
|
dest = role->GetTeamPosition();
|
|
|
|
} else {
|
|
|
|
zeus::CVector3f thisToDest = dest - GetTranslation();
|
|
|
|
dest += (thisToDest.canBeNormalized() ? thisToDest.normalized() : GetTransform().basis[1]) *
|
2019-01-31 20:44:05 +00:00
|
|
|
(0.5f * (x2fc_minAttackRange + x300_maxAttackRange));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::SeparateFromMelees(CStateManager& mgr) {
|
|
|
|
for (CEntity* ent : mgr.GetListeningAiObjectList()) {
|
|
|
|
if (TCastToPtr<CPatterned> ai = ent) {
|
|
|
|
if (ai.GetPtr() != this && ai->GetAreaIdAlways() == GetAreaIdAlways()) {
|
|
|
|
float dist = 4.f;
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, ai->GetUniqueId()))
|
|
|
|
if (role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Melee)
|
|
|
|
dist *= 2.f;
|
|
|
|
zeus::CVector3f move = x45c_steeringBehaviors.Separation(*this, ai->GetTranslation(), dist);
|
|
|
|
if (!move.isZero())
|
2019-02-24 07:15:54 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::PathFind(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
if (GetSearchPath()) {
|
|
|
|
RefinePathFindDest(mgr, x2e0_destPos);
|
|
|
|
CPatterned::PathFind(mgr, msg, dt);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update: {
|
|
|
|
zeus::CVector3f dest = mgr.GetPlayer().GetTranslation();
|
|
|
|
RefinePathFindDest(mgr, dest);
|
|
|
|
zeus::CVector3f delta = dest - GetTranslation();
|
|
|
|
zeus::CVector3f move;
|
|
|
|
if (!PathShagged(mgr, 0.f) && !x5fc_pathFindSearch.IsOver()) {
|
|
|
|
CPatterned::PathFind(mgr, msg, dt);
|
|
|
|
move = x450_bodyController->GetCommandMgr().GetMoveVector();
|
|
|
|
} else {
|
|
|
|
move = x45c_steeringBehaviors.Arrival(*this, dest, 5.f);
|
|
|
|
}
|
|
|
|
if (GetTransform().basis[1].dot(move) >= 0.f || GetTransform().basis[1].dot(delta) <= 0.f) {
|
2019-02-24 07:15:54 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
|
|
|
zeus::CVector3f face = delta.canBeNormalized() ? delta.normalized() : GetTransform().basis[1];
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, face, 1.f));
|
|
|
|
}
|
|
|
|
SeparateFromMelees(mgr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::TargetPlayer(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
if (msg == EStateMsg::Activate) {
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId()))
|
|
|
|
x2e0_destPos = role->GetTeamPosition();
|
|
|
|
else
|
|
|
|
x2e0_destPos = mgr.GetPlayer().GetTranslation();
|
|
|
|
x2dc_destObj = mgr.GetPlayer().GetUniqueId();
|
|
|
|
x2ec_reflectedDestPos = GetTranslation();
|
|
|
|
x328_24_inPosition = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Generate(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
if (x56c_entranceType == EEntranceType::FacePlayer || x450_bodyController->GetActive()) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Zero));
|
|
|
|
SetTransform(zeus::lookAt(GetTranslation(), mgr.GetPlayer().GetTranslation()));
|
|
|
|
} else {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Zero, x388_anim));
|
|
|
|
}
|
|
|
|
if (!x450_bodyController->GetActive())
|
|
|
|
x450_bodyController->Activate(mgr);
|
|
|
|
RemoveMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, mgr);
|
|
|
|
x568_stateProg = 0;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Generate) {
|
|
|
|
x568_stateProg = 2;
|
|
|
|
x5a8_animTimeRem = x450_bodyController->GetAnimTimeRemaining();
|
|
|
|
} else {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Zero));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Generate) {
|
|
|
|
x568_stateProg = 4;
|
|
|
|
} else if (x68_material.HasMaterial(EMaterialTypes::Solid) && x5a8_animTimeRem > 0.f) {
|
|
|
|
rstl::reserved_vector<TUniqueId, 1024> nearList;
|
|
|
|
mgr.BuildNearList(nearList, zeus::CAABox(GetTranslation() - 5.f, GetTranslation() + 5.f),
|
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), this);
|
|
|
|
if (!nearList.empty()) {
|
|
|
|
zeus::CVector3f totalSep;
|
|
|
|
float sepFactor = 5.f * dt / x5a8_animTimeRem;
|
|
|
|
for (TUniqueId id : nearList) {
|
|
|
|
if (CActor* act = static_cast<CActor*>(mgr.ObjectById(id))) {
|
|
|
|
zeus::CVector3f sep = x45c_steeringBehaviors.Separation(*this, act->GetTranslation(), 5.f);
|
|
|
|
sep.z() = std::max(0.f, float(sep.z()));
|
|
|
|
totalSep += sep * sepFactor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetTranslation(GetTranslation() + totalSep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EStateMsg::Deactivate:
|
|
|
|
AddMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, EMaterialTypes::GroundCollider, mgr);
|
|
|
|
x328_25_verticalMovement = false;
|
|
|
|
x838_25_burrowing = false;
|
2019-01-03 03:47:28 +00:00
|
|
|
if (x328_26_solidCollision)
|
2018-12-31 05:01:42 +00:00
|
|
|
DeathDelete(mgr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Deactivate(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 0;
|
|
|
|
SquadRemove(mgr);
|
|
|
|
x818_stateFinishTimer = 0.f;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Generate) {
|
2019-01-31 20:44:05 +00:00
|
|
|
RemoveMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, EMaterialTypes::Target, EMaterialTypes::Orbit,
|
|
|
|
mgr);
|
2018-12-31 05:01:42 +00:00
|
|
|
mgr.GetPlayer().SetOrbitRequestForTarget(GetUniqueId(), CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
|
|
|
|
x838_25_burrowing = true;
|
|
|
|
x5a8_animTimeRem = x450_bodyController->GetAnimTimeRemaining();
|
|
|
|
x568_stateProg = 2;
|
|
|
|
} else if (IsOnGround()) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::One));
|
|
|
|
} else {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
2019-02-24 07:15:54 +00:00
|
|
|
x45c_steeringBehaviors.Seek(*this, mgr.GetPlayer().GetTranslation()), zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Generate) {
|
|
|
|
x568_stateProg = 3;
|
|
|
|
x830_intoGroundFactor = 0.f;
|
|
|
|
auto aabb = GetBoundingBox();
|
2019-02-24 07:15:54 +00:00
|
|
|
SetTranslation((aabb.max.z() - aabb.min.z()) * 3.f * zeus::skDown + GetTranslation());
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
|
|
|
float remTime = x450_bodyController->GetAnimTimeRemaining();
|
|
|
|
x830_intoGroundFactor = x5a8_animTimeRem > 0.f ? remTime / x5a8_animTimeRem : 0.f;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
x818_stateFinishTimer += dt;
|
|
|
|
if (x818_stateFinishTimer >= 0.75f) {
|
|
|
|
SendScriptMsgs(EScriptObjectState::DeactivateState, mgr, EScriptObjectMessage::None);
|
|
|
|
mgr.FreeScriptObject(GetUniqueId());
|
|
|
|
x568_stateProg = 4;
|
|
|
|
x830_intoGroundFactor = 0.f;
|
|
|
|
} else {
|
|
|
|
auto aabb = GetBoundingBox();
|
2019-02-24 07:15:54 +00:00
|
|
|
SetTranslation((aabb.max.z() - aabb.min.z()) * 4.f * zeus::skDown * dt + GetTranslation());
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-02-18 05:47:46 +00:00
|
|
|
break;
|
2018-12-31 05:01:42 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x838_26_canSkid = false;
|
|
|
|
x838_24_hitSomething = false;
|
|
|
|
x2e0_destPos = mgr.GetPlayer().GetTranslation();
|
|
|
|
x2e0_destPos.z() = GetTranslation().z();
|
|
|
|
x568_stateProg = 0;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::MeleeAttack) {
|
|
|
|
x568_stateProg = 1;
|
|
|
|
x838_26_canSkid = true;
|
|
|
|
} else if (IsOnGround()) {
|
|
|
|
zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f);
|
|
|
|
aimPos.z() = GetTranslation().z();
|
|
|
|
zeus::CVector3f aimDelta = aimPos - GetTranslation();
|
|
|
|
aimDelta.z() = 0.f;
|
|
|
|
if (aimDelta.canBeNormalized())
|
|
|
|
aimPos += aimDelta.normalized() * 5.f;
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity::One, aimPos));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::MeleeAttack) {
|
|
|
|
x568_stateProg = 4;
|
|
|
|
} else if (IsOnGround()) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverTargetVector(x2e0_destPos - GetTranslation());
|
|
|
|
} else {
|
|
|
|
x568_stateProg = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::MeleeAttack)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-01-03 03:47:28 +00:00
|
|
|
if (x328_26_solidCollision)
|
2018-12-31 05:01:42 +00:00
|
|
|
x838_24_hitSomething = true;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Deactivate:
|
|
|
|
CTeamAiMgr::ResetTeamAiRole(CTeamAiMgr::EAttackType::Melee, mgr, x570_aiMgr, GetUniqueId(), true);
|
|
|
|
x814_attackDelayTimer = mgr.GetActiveRandom()->Float() * x308_attackTimeVariation + x304_averageAttackTime;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::JumpBack(CStateManager&, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 0;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Step) {
|
|
|
|
x568_stateProg = 2;
|
|
|
|
} else if (IsOnGround()) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(
|
2019-01-31 20:44:05 +00:00
|
|
|
CBCStepCmd(pas::EStepDirection::Backward, pas::EStepType::Normal));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Step)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::DoubleSnap(CStateManager&, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 0;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::MeleeAttack) {
|
|
|
|
x568_stateProg = 2;
|
|
|
|
} else {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity::Zero));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::MeleeAttack)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
else
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverTargetVector(x2e0_destPos - GetTranslation());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Shuffle(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x328_24_inPosition = false;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update: {
|
|
|
|
zeus::CVector3f playerPos = mgr.GetPlayer().GetTranslation();
|
|
|
|
zeus::CVector3f playerToThis = GetTranslation() - playerPos;
|
|
|
|
float midRange = 0.5f * (x2fc_minAttackRange + x300_maxAttackRange);
|
|
|
|
zeus::CVector3f playerLimit;
|
|
|
|
if (playerToThis.canBeNormalized())
|
|
|
|
playerLimit = playerToThis.normalized() * midRange + playerPos;
|
|
|
|
else
|
|
|
|
playerLimit = GetTransform().basis[1] * midRange + playerPos;
|
|
|
|
if ((GetTranslation() - playerLimit).magSquared() > 4.f) {
|
|
|
|
pas::EStepDirection dir = GetStepDirection(-playerToThis);
|
|
|
|
switch (dir) {
|
|
|
|
case pas::EStepDirection::Forward:
|
|
|
|
case pas::EStepDirection::Backward: {
|
|
|
|
zeus::CVector3f move = x45c_steeringBehaviors.Arrival(*this, x2e0_destPos, x300_maxAttackRange);
|
|
|
|
if (GetTransform().basis[1].dot(move) >= 0.f || GetTransform().basis[1].dot(playerToThis) >= 0.f) {
|
2019-02-24 07:15:54 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
|
|
|
move, playerToThis.canBeNormalized() ? -playerToThis.normalized() : GetTransform().basis[1], 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case pas::EStepDirection::Left:
|
|
|
|
case pas::EStepDirection::Right: {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(dir, pas::EStepType::Normal));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverTargetVector(-playerToThis);
|
|
|
|
} else {
|
|
|
|
x328_24_inPosition = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::TurnAround(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 0;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Turn) {
|
|
|
|
x568_stateProg = 2;
|
|
|
|
} else {
|
|
|
|
zeus::CVector3f thisToPlayer = mgr.GetPlayer().GetTranslation() - GetTranslation();
|
2019-01-31 20:44:05 +00:00
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
2019-02-24 07:15:54 +00:00
|
|
|
zeus::skZero3f,
|
|
|
|
(thisToPlayer.magnitude() > FLT_EPSILON) ? thisToPlayer.normalized() : zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Turn)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Skid(CStateManager&, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
if (IsOnGround() && x838_26_canSkid) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCSlideCmd(pas::ESlideType::Zero, GetTransform().basis[1]));
|
|
|
|
x568_stateProg = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Slide)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Deactivate:
|
|
|
|
x838_26_canSkid = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Taunt(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(
|
2019-01-31 20:44:05 +00:00
|
|
|
CBCTauntCmd(mgr.GetActiveRandom()->Float() < 0.75f ? pas::ETauntType::One : pas::ETauntType::Zero));
|
2018-12-31 05:01:42 +00:00
|
|
|
x568_stateProg = 2;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Taunt)
|
|
|
|
x568_stateProg = 4;
|
|
|
|
else
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverTargetVector(mgr.GetPlayer().GetTranslation() - GetTranslation());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 CBeetle::FindFurthestRetreatPoint(CStateManager& mgr) const {
|
|
|
|
s32 ret = -1;
|
|
|
|
if (x6e0_retreatPoints.empty())
|
|
|
|
return ret;
|
|
|
|
zeus::CVector2f playerPos = mgr.GetPlayer().GetTranslation().toVec2f();
|
|
|
|
ret = mgr.GetActiveRandom()->Range(0, s32(x6e0_retreatPoints.size() - 1));
|
|
|
|
float maxDist = (playerPos - x6e0_retreatPoints[ret].toVec2f()).magSquared();
|
|
|
|
if (maxDist < 100.f) {
|
|
|
|
s32 i = 0;
|
|
|
|
for (const auto& v : x6e0_retreatPoints) {
|
|
|
|
float dist = (playerPos - v.toVec2f()).magSquared();
|
|
|
|
if (dist > maxDist) {
|
|
|
|
maxDist = dist;
|
|
|
|
ret = i;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Retreat(CStateManager& mgr, EStateMsg msg, float dt) {
|
|
|
|
switch (msg) {
|
|
|
|
case EStateMsg::Activate:
|
|
|
|
x568_stateProg = 0;
|
|
|
|
SquadRemove(mgr);
|
|
|
|
x818_stateFinishTimer = 0.f;
|
|
|
|
x3b4_speed = 2.f * x81c_;
|
|
|
|
break;
|
|
|
|
case EStateMsg::Update:
|
|
|
|
switch (x568_stateProg) {
|
|
|
|
case 0:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::Generate) {
|
2019-01-31 20:44:05 +00:00
|
|
|
RemoveMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, EMaterialTypes::Target, EMaterialTypes::Orbit,
|
|
|
|
mgr);
|
|
|
|
mgr.GetPlayer().SetOrbitRequestForTarget(GetUniqueId(), CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
|
2018-12-31 05:01:42 +00:00
|
|
|
x838_25_burrowing = true;
|
|
|
|
x5a8_animTimeRem = x450_bodyController->GetAnimTimeRemaining();
|
|
|
|
x568_stateProg = 2;
|
|
|
|
} else if (IsOnGround()) {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::One));
|
|
|
|
} else {
|
|
|
|
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
2019-02-24 07:15:54 +00:00
|
|
|
x45c_steeringBehaviors.Seek(*this, mgr.GetPlayer().GetTranslation()), zeus::skZero3f, 1.f));
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (x450_bodyController->GetCurrentStateId() != pas::EAnimationState::Generate) {
|
|
|
|
x568_stateProg = 3;
|
|
|
|
x830_intoGroundFactor = 0.f;
|
|
|
|
auto aabb = GetBoundingBox();
|
2019-02-24 07:15:54 +00:00
|
|
|
SetTranslation((aabb.max.z() - aabb.min.z()) * 3.f * zeus::skDown + GetTranslation());
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
|
|
|
float remTime = x450_bodyController->GetAnimTimeRemaining();
|
|
|
|
x830_intoGroundFactor = (x5a8_animTimeRem > 0.f) ? remTime / x5a8_animTimeRem : 0.f;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
x818_stateFinishTimer += dt;
|
|
|
|
if (x818_stateFinishTimer >= x834_retreatTime) {
|
|
|
|
x568_stateProg = 4;
|
|
|
|
x830_intoGroundFactor = 0.f;
|
|
|
|
} else {
|
|
|
|
auto aabb = GetBoundingBox();
|
2019-02-24 07:15:54 +00:00
|
|
|
zeus::CVector3f downVec = (aabb.max.z() - aabb.min.z()) * 3.f * zeus::skDown;
|
2019-01-31 20:44:05 +00:00
|
|
|
SetTranslation(((x834_retreatTime > 0.f) ? (1.f / x834_retreatTime) * downVec : downVec) * dt +
|
|
|
|
GetTranslation());
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EStateMsg::Deactivate: {
|
|
|
|
s32 idx = FindFurthestRetreatPoint(mgr);
|
|
|
|
if (idx != -1) {
|
|
|
|
SetTranslation(x6e0_retreatPoints[idx]);
|
2019-01-31 20:44:05 +00:00
|
|
|
AddMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, EMaterialTypes::Target, EMaterialTypes::Orbit, mgr);
|
2018-12-31 05:01:42 +00:00
|
|
|
} else {
|
|
|
|
SendScriptMsgs(EScriptObjectState::DeactivateState, mgr, EScriptObjectMessage::None);
|
|
|
|
mgr.FreeScriptObject(GetUniqueId());
|
|
|
|
}
|
|
|
|
x400_24_hitByPlayerProjectile = false;
|
|
|
|
x3b4_speed = x81c_;
|
|
|
|
x838_25_burrowing = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CBeetle::InAttackPosition(CStateManager& mgr, float arg) {
|
|
|
|
float distSq = (mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared();
|
|
|
|
if (distSq > x2fc_minAttackRange * x2fc_minAttackRange && distSq < x300_maxAttackRange * x300_maxAttackRange)
|
|
|
|
if (SpotPlayer(mgr, x3c8_leashRadius))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::PathShagged(CStateManager&, float arg) { return false; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
|
|
|
bool CBeetle::InRange(CStateManager& mgr, float arg) {
|
|
|
|
zeus::CVector3f targetPos = mgr.GetPlayer().GetTranslation();
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId())) {
|
|
|
|
if (role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Melee)
|
|
|
|
targetPos = role->GetTeamPosition();
|
|
|
|
}
|
|
|
|
return (targetPos - GetTranslation()).magSquared() < 100.f;
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::PatternOver(CStateManager& mgr, float arg) { return AnimOver(mgr, arg); }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::HasAttackPattern(CStateManager&, float arg) { return true; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::AnimOver(CStateManager&, float arg) { return x568_stateProg == 4; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
|
|
|
bool CBeetle::ShouldAttack(CStateManager& mgr, float arg) {
|
|
|
|
if (x814_attackDelayTimer <= 0.f) {
|
|
|
|
if (TCastToPtr<CTeamAiMgr> tmgr = mgr.ObjectById(x570_aiMgr)) {
|
|
|
|
if (tmgr->HasTeamAiRole(GetUniqueId()))
|
|
|
|
return tmgr->AddMeleeAttacker(GetUniqueId());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CBeetle::ShouldDoubleSnap(CStateManager& mgr, float arg) {
|
|
|
|
if (!GetSearchPath() && IsOnGround()) {
|
|
|
|
zeus::CVector3f targetPos = mgr.GetPlayer().GetTranslation();
|
|
|
|
float dist = x5a0_headbuttDist + x300_maxAttackRange;
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId()))
|
|
|
|
targetPos = role->GetTeamPosition();
|
|
|
|
zeus::CVector3f delta = targetPos - GetTranslation();
|
|
|
|
if (delta.magSquared() > dist * dist && GetTransform().basis[1].dot(delta.normalized()) > 0.98f) {
|
|
|
|
rstl::reserved_vector<TUniqueId, 1024> nearList;
|
|
|
|
mgr.BuildNearList(nearList, GetTranslation(), GetTransform().basis[1], x5a0_headbuttDist,
|
2019-01-31 20:44:05 +00:00
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Character}), this);
|
2018-12-31 05:01:42 +00:00
|
|
|
TUniqueId bestId = kInvalidUniqueId;
|
2019-01-31 20:44:05 +00:00
|
|
|
CRayCastResult res =
|
|
|
|
mgr.RayWorldIntersection(bestId, GetTranslation(), GetTransform().basis[1], x5a0_headbuttDist,
|
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), nearList);
|
2018-12-31 05:01:42 +00:00
|
|
|
if (res.IsInvalid())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CBeetle::ShouldTurn(CStateManager& mgr, float arg) {
|
|
|
|
return zeus::CVector2f::getAngleDiff(GetTransform().basis[1].toVec2f(),
|
2019-01-31 20:44:05 +00:00
|
|
|
(mgr.GetPlayer().GetTranslation() - GetTranslation()).toVec2f()) >
|
|
|
|
zeus::degToRad(30.f);
|
2018-12-31 05:01:42 +00:00
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::HitSomething(CStateManager&, float arg) { return x838_24_hitSomething; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
|
|
|
bool CBeetle::ShouldJumpBack(CStateManager& mgr, float arg) {
|
|
|
|
zeus::CVector3f backDir = -GetTransform().basis[1];
|
|
|
|
const auto& aabb = GetBaseBoundingBox();
|
|
|
|
zeus::CVector3f pos = GetTranslation() + zeus::CVector3f(0.f, 0.f, (aabb.max.z() - aabb.min.z()) * 0.5f);
|
|
|
|
rstl::reserved_vector<TUniqueId, 1024> nearList;
|
|
|
|
mgr.BuildNearList(nearList, pos, backDir, x5a4_jumpBackwardDist,
|
2019-01-31 20:44:05 +00:00
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Character}), this);
|
2018-12-31 05:01:42 +00:00
|
|
|
TUniqueId bestId = kInvalidUniqueId;
|
|
|
|
CRayCastResult res = mgr.RayWorldIntersection(bestId, pos, backDir, x5a4_jumpBackwardDist,
|
2019-01-31 20:44:05 +00:00
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), nearList);
|
2018-12-31 05:01:42 +00:00
|
|
|
return res.IsInvalid();
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::Stuck(CStateManager&, float arg) { return x820_posDeviationCounter > 30; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
bool CBeetle::NoPathNodes(CStateManager&, float arg) { return false; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
|
|
|
bool CBeetle::ShouldTaunt(CStateManager& mgr, float arg) {
|
|
|
|
if (CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x570_aiMgr, GetUniqueId())) {
|
|
|
|
if (role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Unknown ||
|
|
|
|
role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Unassigned) {
|
|
|
|
return (role->GetTeamPosition() - GetTranslation()).magSquared() < 100.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CBeetle::ShotAt(CStateManager&, float arg) {
|
|
|
|
if (x3fc_flavor == EFlavorType::Two && x6e0_retreatPoints.size() > 0)
|
|
|
|
return x400_24_hitByPlayerProjectile;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Burn(float duration, float damage) {
|
|
|
|
CDamageVulnerability dVuln = *GetDamageVulnerability();
|
|
|
|
if (!x838_25_burrowing && x3fc_flavor == EFlavorType::One)
|
|
|
|
dVuln = x7ac_tailVuln;
|
|
|
|
switch (dVuln.GetVulnerability(CWeaponMode(EWeaponType::Wave), false)) {
|
|
|
|
case EVulnerability::Weak:
|
|
|
|
x450_bodyController->SetOnFire(1.5f * duration);
|
|
|
|
x3ec_pendingFireDamage = 1.5f * damage;
|
|
|
|
break;
|
|
|
|
case EVulnerability::Normal:
|
|
|
|
x450_bodyController->SetOnFire(duration);
|
|
|
|
x3ec_pendingFireDamage = damage;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBeetle::Shock(CStateManager& mgr, float duration, float damage) {
|
|
|
|
CDamageVulnerability dVuln = *GetDamageVulnerability();
|
|
|
|
if (!x838_25_burrowing && x3fc_flavor == EFlavorType::One)
|
|
|
|
dVuln = x7ac_tailVuln;
|
|
|
|
switch (dVuln.GetVulnerability(CWeaponMode(EWeaponType::Wave), false)) {
|
|
|
|
case EVulnerability::Weak:
|
|
|
|
x450_bodyController->SetElectrocuting(1.5f * duration);
|
|
|
|
x3f0_pendingShockDamage = 1.5f * damage;
|
|
|
|
break;
|
|
|
|
case EVulnerability::Normal:
|
|
|
|
x450_bodyController->SetElectrocuting(duration);
|
|
|
|
x3f0_pendingShockDamage = damage;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:44:05 +00:00
|
|
|
CPathFindSearch* CBeetle::GetSearchPath() { return &x5fc_pathFindSearch; }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2019-07-16 15:54:07 +00:00
|
|
|
float CBeetle::GetGravityConstant() const { return 4.f * CPhysicsActor::GravityConstant(); }
|
2018-12-31 05:01:42 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
} // namespace urde::MP1
|