#include "Runtime/MP1/World/CIceSheegoth.hpp" #include "Runtime/CSimplePool.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/Camera/CCameraManager.hpp" #include "Runtime/Camera/CCameraShakeData.hpp" #include "Runtime/Camera/CFirstPersonCamera.hpp" #include "Runtime/Character/CPASAnimParmData.hpp" #include "Runtime/Collision/CCollisionActor.hpp" #include "Runtime/Collision/CCollisionActorManager.hpp" #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/Graphics/CBooRenderer.hpp" #include "Runtime/Particle/CElementGen.hpp" #include "Runtime/Particle/CParticleElectric.hpp" #include "Runtime/Particle/CParticleSwoosh.hpp" #include "Runtime/Weapon/CFlameInfo.hpp" #include "Runtime/Weapon/CFlameThrower.hpp" #include "Runtime/World/CGameArea.hpp" #include "Runtime/World/CPatternedInfo.hpp" #include "Runtime/World/CPlayer.hpp" #include "Runtime/World/CWorld.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path namespace metaforce::MP1 { namespace { constexpr std::array skSphereJointList = {{ {"Jaw_end_LCTR", 0.55f}, {"Pelvis", 1.1f}, {"LCTR_SHEMOUTH", 1.1f}, {"butt_LCTR", 0.7f}, {"Ice_Shards_LCTR", 1.2f}, {"GillL_LCTR", 0.6f}, {"GillR_LCTR", 0.6f}, }}; constexpr std::array skLeftLegJointList = {{ {"L_hip", "L_knee", 0.4f, 0.75f}, {"L_ankle", "L_Toe_3", 0.4f, 0.75f}, }}; constexpr std::array skRightLegJointList = {{ {"R_hip", "R_knee", 0.4f, 0.75f}, {"R_ankle", "R_Toe_3", 0.4f, 0.75f}, }}; } // namespace CIceSheegothData::CIceSheegothData(CInputStream& in, [[maybe_unused]] s32 propertyCount) : x0_(zeus::degToRad(in.readFloatBig())) , x4_(zeus::degToRad(in.readFloatBig())) , x8_(zeus::CVector3f::ReadBig(in)) , x14_(in.readFloatBig()) , x18_(in) , x80_(in) , xe8_(in) , x150_(in) , x154_(in) , x170_(in.readFloatBig()) , x174_(in.readFloatBig()) , x178_(in) , x17c_fireBreathResId(in) , x180_fireBreathDamage(in) , x19c_(in) , x1a0_(in) , x1a4_(in) , x1a8_(in) , x1ac_(in) , x1b0_(in.readFloatBig()) , x1b4_(in.readFloatBig()) , x1b8_(in) , x1d4_(CSfxManager::TranslateSFXID(in.readUint32Big())) , x1d8_(in.readFloatBig()) , x1dc_(in.readFloatBig()) , x1e0_maxInterestTime(in.readFloatBig()) , x1e4_(in) , x1e8_(CSfxManager::TranslateSFXID(in.readUint32Big())) , x1ec_(in) , x1f0_24_(in.readBool()) , x1f0_25_(in.readBool()) {} CIceSheegoth::CIceSheegoth(TUniqueId uid, std::string_view name, const CEntityInfo& info, zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms, const CIceSheegothData& sheegothData) : CPatterned(ECharacter::IceSheeegoth, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, EMovementType::Ground, EColliderType::One, EBodyType::BiPedal, actParms, EKnockBackVariant::Large) , x56c_sheegothData(sheegothData) , x760_pathSearch(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x844_approachSearch(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x94c_(x3b4_speed) , x974_(sheegothData.Get_x174()) , x98c_mouthVulnerability(pInfo.GetDamageVulnerability()) , x9f4_boneTracking(*GetModelData()->GetAnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f), EBoneTrackingFlags::None) , xa30_(GetBoundingBox(), GetMaterialList()) , xa58_(sheegothData.Get_x150(), sheegothData.Get_x154()) , xa84_(sheegothData.Get_x178().IsValid() ? g_SimplePool->GetObj({SBIG('WPSC'), sheegothData.Get_x178()}) : g_SimplePool->GetObj("FlameThrower"sv)) , xa8c_(g_SimplePool->GetObj({SBIG('PART'), sheegothData.Get_x1a0()})) , xa9c_(std::make_unique(xa8c_, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One)) , xaa0_(g_SimplePool->GetObj({SBIG('PART'), sheegothData.Get_x1a4()})) , xab0_(std::make_unique(xaa0_, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One)) , xab4_(g_SimplePool->GetObj({SBIG('PART'), sheegothData.Get_x1a4()})) , xac4_(std::make_unique(xaa0_, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One)) , xac8_(g_SimplePool->GetObj({SBIG('ELSC'), sheegothData.Get_x1ac()})) , xad8_(std::make_unique(xac8_)) , xadc_(g_SimplePool->GetObj({SBIG('PART'), sheegothData.Get_x19c()})) { UpdateTouchBounds(); x460_knockBackController.SetEnableFreeze(false); x460_knockBackController.SetX82_24(false); x460_knockBackController.SetEnableLaggedBurnDeath(false); x460_knockBackController.SetEnableExplodeDeath(false); x950_ = GetAnimationDistance( CPASAnimParmData(pas::EAnimationState::Step, CPASAnimParm::FromEnum(1), CPASAnimParm::FromEnum(0))) * GetModelData()->GetScale().y(); xa9c_->SetGlobalScale(GetModelData()->GetScale()); xab0_->SetGlobalScale(GetModelData()->GetScale()); xac4_->SetGlobalScale(GetModelData()->GetScale()); xad8_->SetGlobalScale(GetModelData()->GetScale()); x450_bodyController->BodyStateInfo().SetLocoAnimChangeAtEndOfAnimOnly(true); MakeThermalColdAndHot(); x328_31_energyAttractor = true; } void CIceSheegoth::Accept(IVisitor& visitor) { visitor.Visit(this); } void CIceSheegoth::Think(float dt, CStateManager& mgr) { if (!GetActive()) { return; } CPatterned::Think(dt, mgr); AttractProjectiles(mgr); UpdateTimers(dt); UpdateScanState(mgr); if (!IsAlive()) { x974_ = std::max(0.f, x974_ - (dt * x56c_sheegothData.Get_x170())); if (GetBodyController()->GetBodyStateInfo().GetCurrentState()->IsDying()) { SetPassthroughVulnerability(mgr); } } x96c_ -= dt; if (x96c_ < 0.f) { GetBodyController()->GetCommandMgr().DeliverCmd( CBCAdditiveReactionCmd(pas::EAdditiveReactionType::Four, 1.f, false)); x96c_ = 3.f * mgr.GetActiveRandom()->Float() + 2.f; } GetModelData()->GetAnimationData()->PreRender(); x9f4_boneTracking.Update(dt); x9f4_boneTracking.PreRender(mgr, *GetModelData()->GetAnimationData(), GetTransform(), GetModelData()->GetScale(), *GetBodyController()); xa2c_collisionManager->Update(dt, mgr, CCollisionActorManager::EUpdateOptions::ObjectSpace); PreventWorldCollisions(dt, mgr); UpdateHealthInfo(mgr); SetSteeringSpeed(dt, mgr); UpdateParticleEffects(dt, mgr); UpdateThermalFrozenState(x428_damageCooldownTimer > 0.f); } void CIceSheegoth::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) { switch (msg) { case EScriptObjectMessage::Activate: { xa2c_collisionManager->SetActive(mgr, true); break; } case EScriptObjectMessage::Deactivate: { xa2c_collisionManager->SetActive(mgr, false); break; } case EScriptObjectMessage::Start: { xb28_24_shotAt = true; break; } case EScriptObjectMessage::Touched: { ApplyContactDamage(sender, mgr); if (const TCastToConstPtr colAct = mgr.ObjectById(sender)) { if (const TCastToConstPtr wp = mgr.GetObjectById(colAct->GetLastTouchedObject())) { if (wp->GetOwnerId() == mgr.GetPlayer().GetUniqueId()) { xb28_24_shotAt = true; } } } break; } case EScriptObjectMessage::Registered: { if (!HasPatrolPath(mgr, 0.f)) { x450_bodyController->SetLocomotionType(pas::ELocomotionType::Crouch); } x450_bodyController->Activate(mgr); SetupCollisionActorManager(mgr); CreateFlameThrower(mgr); if (x450_bodyController->GetBodyStateInfo().GetMaxSpeed() > 0.f) { x944_ = x948_ = (0.9f * x450_bodyController->GetBodyStateInfo().GetLocomotionSpeed(pas::ELocomotionAnim::Walk)) / x450_bodyController->GetBodyStateInfo().GetMaxSpeed(); } GetBodyController()->GetCommandMgr().SetSteeringBlendMode(ESteeringBlendMode::FullSpeed); xaf4_mouthLocator = GetModelData()->GetAnimationData()->GetLocatorSegId("LCTR_SHEMOUTH"sv); break; } case EScriptObjectMessage::Deleted: { xa2c_collisionManager->Destroy(mgr); if (xa80_flameThrowerId != kInvalidUniqueId) { mgr.FreeScriptObject(xa80_flameThrowerId); xa80_flameThrowerId = kInvalidUniqueId; } if (xaf0_crackleSfx) { CSfxManager::RemoveEmitter(xaf0_crackleSfx); xaf0_crackleSfx.reset(); } break; } case EScriptObjectMessage::InitializedInArea: { x760_pathSearch.SetArea(mgr.GetWorld()->GetArea(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea); x844_approachSearch.SetArea(mgr.GetWorld()->GetArea(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea); break; } case EScriptObjectMessage::Damage: { if (const TCastToConstPtr colAct = mgr.ObjectById(sender)) { if (const TCastToConstPtr wp = mgr.GetObjectById(colAct->GetLastTouchedObject())) { if (sender == xaf6_iceShardsCollider && !xb28_27_) { sub_8019ebf0(mgr, wp->GetDamageInfo().GetDamage()); if (!xaec_ || xaec_->IsSystemDeletable()) { xaec_ = std::make_unique(xadc_, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One); } } else { TakeDamage(zeus::skZero3f, 0.f); if (IsGillCollider(colAct.GetPtr())) { x97c_ = 0.2f; x980_ = GetTransform().basis[1]; } } } } else { ApplyWeaponDamage(mgr, sender); } xb28_24_shotAt = true; x968_interestTimer = 0.f; mgr.InformListeners(GetTranslation(), EListenNoiseType::PlayerFire); break; } case EScriptObjectMessage::InvulnDamage: { if (sender == xaf6_iceShardsCollider && !xb28_27_) { if (const TCastToConstPtr colAct = mgr.ObjectById(sender)) { if (const TCastToConstPtr wp = mgr.GetObjectById(colAct->GetLastTouchedObject())) { sub_8019ebf0(mgr, wp->GetDamageInfo().GetDamage()); if (!xaec_ || xaec_->IsSystemDeletable()) { xaec_ = std::make_unique(xadc_, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One); } } } } mgr.InformListeners(GetTranslation(), EListenNoiseType::PlayerFire); xb28_24_shotAt = true; x968_interestTimer = 0.f; break; } case EScriptObjectMessage::SuspendedMove: { if (xa2c_collisionManager != nullptr) { xa2c_collisionManager->SetMovable(mgr, false); } break; } default: break; } CPatterned::AcceptScriptMsg(msg, sender, mgr); } void CIceSheegoth::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) { CPatterned::AddToRenderer(frustum, mgr); if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot) { if (x428_damageCooldownTimer == 0.f && xb29_25_ && (HasModelData() && (GetModelData()->HasAnimData() || GetModelData()->HasNormalModel()))) { GetModelData()->RenderParticles(frustum); } } else { std::optional bounds1; if (xaec_) { bounds1 = xaec_->GetBounds(); } std::optional bounds2; if (xa9c_) { bounds2 = xa9c_->GetBounds(); } std::optional bounds3; if (xab0_) { bounds3 = xab0_->GetBounds(); } std::optional bounds4; if (xac4_) { bounds4 = xac4_->GetBounds(); } std::optional bounds5; if (xad8_) { bounds5 = xad8_->GetBounds(); } /* Lawl retro std::optional bounds6; if (xad8_) { bounds6 = xad8_->GetBounds(); } */ zeus::CAABox accumulatedBounds = zeus::skInvertedBox; if (bounds1) { accumulatedBounds.accumulateBounds(*bounds1); } /* Lawl retro if (bounds6) { accumulatedBounds.accumulateBounds(*bounds6); } */ if (bounds2) { accumulatedBounds.accumulateBounds(*bounds2); } if (bounds3) { accumulatedBounds.accumulateBounds(*bounds3); } if (bounds4) { accumulatedBounds.accumulateBounds(*bounds4); } if (bounds5) { accumulatedBounds.accumulateBounds(*bounds5); } if (frustum.aabbFrustumTest(accumulatedBounds)) { if (xaec_) { g_Renderer->AddParticleGen(*xaec_); } g_Renderer->AddParticleGen(*xa9c_); g_Renderer->AddParticleGen(*xab0_); g_Renderer->AddParticleGen(*xac4_); g_Renderer->AddParticleGen(*xad8_); } } } zeus::CVector3f CIceSheegoth::GetAimPosition(const CStateManager& mgr, float dt) const { if (GetBodyController()->GetLocomotionType() != pas::ELocomotionType::Crouch) { if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) { zeus::CVector3f pos = zeus::skZero3f; for (TUniqueId uid : xafc_gillColliders) { if (const TCastToConstPtr colAct = mgr.GetObjectById(uid)) { pos += colAct->GetTranslation(); } } if (!pos.isZero()) { return pos * (1.f / static_cast(xafc_gillColliders.size())); } } else if (!xb29_29_scanned && mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::Scan) { if (const TCastToConstPtr colAct = mgr.GetObjectById(xaf6_iceShardsCollider)) { return colAct->GetTranslation(); } } else if (const TCastToConstPtr colAct = mgr.GetObjectById(xaf8_mouthCollider)) { return colAct->GetTranslation(); } } return CPatterned::GetAimPosition(mgr, dt); } EWeaponCollisionResponseTypes CIceSheegoth::GetCollisionResponseType(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const CWeaponMode& mode, EProjectileAttrib attrib) const { return mode.GetType() == EWeaponType::Ice ? EWeaponCollisionResponseTypes::None : CPatterned::GetCollisionResponseType(v1, v2, mode, attrib); } zeus::CAABox CIceSheegoth::GetSortingBounds(const CStateManager& mgr) const { const zeus::CAABox box = CActor::GetSortingBounds(mgr); const zeus::CVector3f offset = 0.125f * (box.max - box.min); const zeus::CVector3f center = box.center(); return {center - offset, center + offset}; } void CIceSheegoth::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { switch (type) { case EUserEventType::Projectile: { zeus::CTransform gunPos = GetLctrTransform(node.GetLocatorName()); zeus::CVector3f interceptPos = GetProjectileInfo()->PredictInterceptPos( gunPos.origin, mgr.GetPlayer().GetAimPosition(mgr, 0.f), mgr.GetPlayer(), true, dt); zeus::CVector3f predictOffset = interceptPos - gunPos.origin; zeus::CVector3f lookPos; if (zeus::CVector3f::getAngleDiff(GetTransform().frontVector(), predictOffset) > zeus::degToRad(60.f)) { if (!predictOffset.canBeNormalized()) { lookPos = gunPos.origin + predictOffset.magnitude() * gunPos.frontVector(); } else { lookPos = gunPos.origin + (predictOffset.magnitude() * zeus::CVector3f::slerp(GetTransform().frontVector(), predictOffset.normalized(), zeus::CRelAngle::FromDegrees(60.f))); } } LaunchProjectile(zeus::lookAt(gunPos.origin, lookPos), mgr, 4, EProjectileAttrib::None, false, std::nullopt, -1, false, zeus::skOne3f); x974_ = std::max(0.f, x974_ - 0.3333f * x56c_sheegothData.Get_x170()); if (xb28_27_ && !ShouldSpecialAttack(mgr, 0.f)) { GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd{EBodyStateCmd::ExitState}); } return; } case EUserEventType::DamageOn: if (!xb28_26_) { break; } if (CFlameThrower* fl = static_cast(mgr.ObjectById(xa80_flameThrowerId))) { fl->Fire(GetTransform(), mgr, false); } break; case EUserEventType::DamageOff: if (!xb28_26_) { break; } if (CFlameThrower* fl = static_cast(mgr.ObjectById(xa80_flameThrowerId))) { fl->Reset(mgr, false); } break; case EUserEventType::ScreenShake: ShakePlayer(mgr); return; case EUserEventType::BecomeShootThrough: SetPassthroughVulnerability(mgr); return; default: break; } CPatterned::DoUserAnimEvent(mgr, node, type, dt); } void CIceSheegoth::PathFind(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { xb28_24_shotAt = false; xb29_28_ = false; x968_interestTimer = 0.f; GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); x9f4_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); x9f4_boneTracking.SetActive(true); UpdateAttackPosition(mgr, x2e0_destPos); SetPathFindMode(EPathFindMode::Normal); if (!x56c_sheegothData.Get_x1f0_24()) { CPatterned::PathFind(mgr, msg, dt); } } else if (msg == EStateMsg::Update) { SetPathFindMode(EPathFindMode::Normal); if (x56c_sheegothData.Get_x1f0_24() && GetSearchPath() != nullptr && !PathShagged(mgr, 0.f) && x760_pathSearch.GetCurrentWaypoint() < x760_pathSearch.GetWaypoints().size() - 1) { CPatterned::PathFind(mgr, EStateMsg::Update, dt); x968_interestTimer = 0.f; zeus::CVector3f moveVec = GetBodyController()->GetCommandMgr().GetMoveVector(); if (GetTransform().basis[1].dot(moveVec) < 0.f && moveVec.canBeNormalized()) { GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(zeus::skZero3f, moveVec.normalized(), 1.f)); } } else { const zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); if (sub_8019ecdc(mgr, zeus::degToRad(15.f)) && posDiff.canBeNormalized()) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(zeus::skZero3f, posDiff.normalized(), 1.f)); } } x3b4_speed = (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Turn ? 2.f : 1.f) * x94c_; } else if (msg == EStateMsg::Deactivate) { x9f4_boneTracking.SetActive(false); x3b4_speed = x94c_; } } void CIceSheegoth::TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); if (HasPatrolPath(mgr, 0.f)) { Patrol(mgr, msg, dt); UpdateDest(mgr); } else { SetDestPos(x3a0_latestLeashPosition); } const zeus::CVector3f arrivalPos = x45c_steeringBehaviors.Arrival(*this, x92c_lastDest, 15.f); x92c_lastDest = x2e0_destPos; if (GetSearchPath() != nullptr) { SetPathFindMode(EPathFindMode::Normal); CPatterned::PathFind(mgr, msg, dt); const zeus::CVector3f moveVec = GetBodyController()->GetCommandMgr().GetMoveVector(); if (moveVec.canBeNormalized()) { GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); GetBodyController()->GetCommandMgr().DeliverCmd( CBCLocomotionCmd{arrivalPos.magnitude() * moveVec.normalized(), zeus::skZero3f, 1.f}); } else { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{arrivalPos, zeus::skZero3f, 1.f}); } } } else if (msg == EStateMsg::Update) { const zeus::CVector3f arrivalPos = x45c_steeringBehaviors.Arrival(*this, x92c_lastDest, 15.f); if (GetSearchPath() && PathShagged(mgr, dt)) { SetPathFindMode(EPathFindMode::Normal); CPatterned::PathFind(mgr, EStateMsg::Update, dt); const zeus::CVector3f moveVec = GetBodyController()->GetCommandMgr().GetMoveVector(); if (moveVec.canBeNormalized()) { GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); GetBodyController()->GetCommandMgr().DeliverCmd( CBCLocomotionCmd{arrivalPos.magnitude() * moveVec.normalized(), zeus::skZero3f, 1.f}); } else { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{arrivalPos, zeus::skZero3f, 1.f}); } } } } void CIceSheegoth::Generate(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; x938_ = GetTransform().basis[1]; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Generate) { GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); x568_ = 3; SendScriptMsgs(EScriptObjectState::Attack, mgr, EScriptObjectMessage::None); } else { GetBodyController()->GetCommandMgr().DeliverCmd( CBCGenerateCmd{x56c_sheegothData.Get_x1f0_25() ? pas::EGenerateType::Eight : pas::EGenerateType::Zero}); } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Generate) { x568_ = 4; } } } void CIceSheegoth::Deactivate(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 1; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Generate) { x568_ = 3; } else { GetBodyController()->GetCommandMgr().DeliverCmd(CBCGenerateCmd{pas::EGenerateType::One}); } } else if (x568_ == 1) { if ((x3a0_latestLeashPosition - GetTranslation()).magSquared() > 1.f) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{ x45c_steeringBehaviors.Arrival(*this, x3a0_latestLeashPosition, 15.f), zeus::skZero3f, 1.f}); } else { x568_ = 2; } } else if (x568_ == 2) { const float angleDiff = zeus::CVector3f::getAngleDiff(GetTransform().frontVector(), x938_); if (angleDiff <= zeus::degToRad(5.f)) { x568_ = 0; } else { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{zeus::skZero3f, x938_, 1.f}); } } else if (x568_ == 3) { x568_ = 4; } } } void CIceSheegoth::Attack(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb28_29_ = true; xb28_25_ = true; x2e0_destPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f); SetPathFindMode(EPathFindMode::Normal); CPatterned::PathFind(mgr, msg, dt); SetCollisionActorExtendedTouchBounds(mgr, zeus::CVector3f{2.f}); x95c_ = 0.f; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { x95c_ += dt; if (x95c_ >= x56c_sheegothData.Get_x1d8()) { x568_ = 4; } else if (!xb28_29_) { x568_ = 3; xb28_29_ = true; const bool isPlayerMorphed = mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed; GetBodyController()->GetCommandMgr().DeliverCmd( CBCMeleeAttackCmd{isPlayerMorphed ? pas::ESeverity::Two : pas::ESeverity::One}); } else if (xb28_29_) { const zeus::CTransform mouthXf = GetLctrTransform(xaf4_mouthLocator); if (GetTransform().frontVector().dot(mgr.GetPlayer().GetTranslation() - mouthXf.origin) > 0.f) { SetPathFindMode(EPathFindMode::Normal); if (GetSearchPath() != nullptr && !PathShagged(mgr, 0.f)) { CPatterned::PathFind(mgr, EStateMsg::Update, dt); } else { x568_ = 4; } } else { x568_ = 4; } } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::MeleeAttack) { x568_ = 4; } } else if (msg == EStateMsg::Deactivate) { if (!sub_801a1794(mgr)) { x954_attackTimeLeft = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime; } SetCollisionActorExtendedTouchBounds(mgr, zeus::skZero3f); xb28_29_ = false; xb28_25_ = false; x960_ = x56c_sheegothData.Get_x1dc(); x95c_ = 0.f; } } void CIceSheegoth::DoubleSnap(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb28_29_ = true; xb28_28_ = true; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::MeleeAttack) { x568_ = 3; } else if (IsOnGround()) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd{pas::ESeverity::Zero}); } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::MeleeAttack) { x568_ = 4; } } else if (msg == EStateMsg::Deactivate) { if (!sub_801a1794(mgr) || !TooClose(mgr, dt)) { x958_ = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime; } xb28_29_ = false; xb28_28_ = false; } } void CIceSheegoth::TurnAround(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x9f4_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); x9f4_boneTracking.SetActive(true); UpdateAttackPosition(mgr, x2e0_destPos); SetPathFindMode(EPathFindMode::Normal); CPatterned::PathFind(mgr, EStateMsg::Activate, dt); GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); } else if (msg == EStateMsg::Update) { if (!sub_8019ecdc(mgr, zeus::degToRad(15.f))) { const float speedScale = GetModelData()->GetAnimationData()->GetSpeedScale(); const zeus::CVector3f aimPos = (mgr.GetPlayer().GetAimPosition(mgr, speedScale > 0.f ? 1.25f / speedScale : 0.f).toVec2f() - GetTranslation().toVec2f()); if (aimPos.canBeNormalized()) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{zeus::skZero3f, aimPos.normalized(), 1.f}); } } x3b4_speed = (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Turn ? 2.f : 1.f) * x94c_; } else if (msg == EStateMsg::Deactivate) { x9f4_boneTracking.SetActive(false); x3b4_speed = x94c_; } } void CIceSheegoth::Crouch(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); mgr.GetPlayer().SetOrbitRequestForTarget(GetUniqueId(), CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr); GetBodyController()->SetLocomotionType(pas::ELocomotionType::Crouch); x968_interestTimer = x56c_sheegothData.GetMaxInterestTime(); x400_24_hitByPlayerProjectile = false; } else if (msg == EStateMsg::Deactivate) { AddMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); } } void CIceSheegoth::Taunt(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb29_25_ = true; SetMouthVulnerability(mgr, true); } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Taunt) { x568_ = 3; } else { GetBodyController()->GetCommandMgr().DeliverCmd(CBCTauntCmd{pas::ETauntType::Zero}); } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Taunt) { x568_ = 4; } } else if (msg == EStateMsg::Deactivate) { SetMouthVulnerability(mgr, false); xb29_25_ = false; } } void CIceSheegoth::ProjectileAttack(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb28_26_ = true; xb29_25_ = true; xb29_27_ = false; x968_interestTimer = 0.f; SetGillVulnerability(mgr, true); } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::ProjectileAttack) { GetBodyController()->GetCommandMgr().DeliverCmd( CBCProjectileAttackCmd{pas::ESeverity::Two, mgr.GetPlayer().GetTranslation(), false}); } else { x568_ = 3; x3b4_speed = 2.f * x94c_; } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::ProjectileAttack) { x568_ = 4; } } else if (msg == EStateMsg::Deactivate) { x3b4_speed = x94c_; if (!sub_801a1794(mgr)) { x954_attackTimeLeft = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime; } if (CFlameThrower* fl = static_cast(mgr.ObjectById(xa80_flameThrowerId))) { fl->Reset(mgr, false); } SetGillVulnerability(mgr, false); if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::ProjectileAttack) { GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd{EBodyStateCmd::NextState}); } xb29_25_ = false; xb28_26_ = false; } } void CIceSheegoth::Flinch(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb29_25_ = true; SetGillVulnerability(mgr, true); SetMouthVulnerability(mgr, true); } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::KnockBack) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCKnockBackCmd{x980_, pas::ESeverity::One}); } else { x568_ = 4; } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::KnockBack) { x568_ = 4; } } else if (msg == EStateMsg::Deactivate) { SetGillVulnerability(mgr, true); SetMouthVulnerability(mgr, true); xb29_25_ = false; } } void CIceSheegoth::Approach(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); x9f4_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); UpdateAttackPosition(mgr, x2e0_destPos); SetPathFindMode(EPathFindMode::Normal); if (!xb29_27_) { GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); } xb29_24_ = !xb29_24_; xb29_28_ = true; x92c_lastDest = mgr.GetPlayer().GetTranslation(); } else if (msg == EStateMsg::Update) { SetPathFindMode(EPathFindMode::Approach); if (xb29_24_) { x2e0_destPos = x92c_lastDest; if (x844_approachSearch.FindClosestReachablePoint(GetTranslation(), x2e0_destPos) == CPathFindSearch::EResult::Success) { if ((GetTranslation() - x2e0_destPos).magSquared() < 81.f) { x2e0_destPos = GetTranslation(); } x92c_lastDest = x2e0_destPos; CPatterned::PathFind(mgr, EStateMsg::Activate, dt); if (!xb29_27_) { GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); } } xb29_24_ = false; } if (x56c_sheegothData.Get_x1f0_24() && GetSearchPath() != nullptr && !PathShagged(mgr, 0.f) && x760_pathSearch.GetCurrentWaypoint() < x760_pathSearch.GetWaypoints().size() - 1) { CPatterned::PathFind(mgr, EStateMsg::Update, dt); } else { const zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); if (sub_8019ecdc(mgr, zeus::degToRad(15.f)) && posDiff.canBeNormalized()) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd{zeus::skZero3f, posDiff.normalized(), 1.f}); } } xb29_27_ = true; x3b4_speed = (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Turn ? 2.f : 1.f) * x94c_; } else if (msg == EStateMsg::Deactivate) { x9f4_boneTracking.SetActive(false); SetPathFindMode(EPathFindMode::Normal); x3b4_speed = x94c_; } } void CIceSheegoth::Enraged(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; xb28_30_ = true; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Generate) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Three)); } else { x568_ = 3; } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Generate) { x568_ = 4; } } } void CIceSheegoth::SpecialAttack(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x568_ = 0; x968_interestTimer = 0.f; xb28_27_ = true; xb29_27_ = false; } else if (msg == EStateMsg::Update) { if (x568_ == 0) { if (GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::LoopAttack) { GetBodyController()->GetCommandMgr().DeliverCmd(CBCLoopAttackCmd{pas::ELoopAttackType::Zero, true}); } else { x568_ = 4; x3b4_speed = 2.f * x94c_; } } else if (x568_ == 3 && GetBodyController()->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::LoopAttack) { x568_ = 4; } } } bool CIceSheegoth::Leash(CStateManager& mgr, float arg) { const zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); if ((x3a0_latestLeashPosition - posDiff).magSquared() <= x3c8_leashRadius * x3c8_leashRadius) { return false; } return posDiff.magSquared() > x3cc_playerLeashRadius && x3d4_curPlayerLeashTime > x3d0_playerLeashTime; } bool CIceSheegoth::OffLine(CStateManager& mgr, float arg) { SetPathFindMode(EPathFindMode::Normal); return PathShagged(mgr, arg); } bool CIceSheegoth::TooClose(CStateManager& mgr, float arg) { if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed) { const zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); if (posDiff.z() < 0.f && posDiff.magSquared() < x978_) { return true; } } return false; } bool CIceSheegoth::InMaxRange(CStateManager& mgr, float arg) { if (x56c_sheegothData.Get_x1f0_24()) { return true; } return CPatterned::InMaxRange(mgr, arg); } bool CIceSheegoth::InDetectionRange(CStateManager& mgr, float arg) { if (xb28_24_shotAt) { return true; } zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); float range = std::min(1.f, arg) * x3bc_detectionRange; if (posDiff.magSquared() < range * range) { if (x3c0_detectionHeightRange <= 0.f) { return true; } return (posDiff.z() * posDiff.z()) < x3c0_detectionHeightRange * x3c0_detectionHeightRange; } return false; } bool CIceSheegoth::SpotPlayer(CStateManager& mgr, float arg) { return xb28_24_shotAt || CPatterned::SpotPlayer(mgr, arg); } bool CIceSheegoth::AnimOver(CStateManager& mgr, float arg) { return x568_ == 4; } bool CIceSheegoth::ShouldAttack(CStateManager& mgr, float arg) { if (GetAreaIdAlways() == mgr.GetPlayer().GetAreaId() && x954_attackTimeLeft <= 0.f && x974_ >= 0.3333f * x56c_sheegothData.Get_x170() && sub_8019ecbc()) { const zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f); const zeus::CTransform lctrXf = GetLctrTransform(xaf4_mouthLocator); if ((aimPos - lctrXf.origin).magSquared() > x2fc_minAttackRange * x2fc_minAttackRange && !ShouldTurn(mgr, zeus::degToRad(15.f))) { return !IsPatternObstructed(mgr, lctrXf.origin, aimPos); } } return false; } bool CIceSheegoth::ShouldDoubleSnap(CStateManager& mgr, float arg) { if (GetAreaIdAlways() != mgr.GetPlayer().GetAreaIdAlways() || x958_ > 0.f) { return false; } SetPathFindMode(EPathFindMode::Approach); return (!PathShagged(mgr, 0.f) && x760_pathSearch.GetCurrentWaypoint() < x760_pathSearch.GetWaypoints().size() - 1) || (x92c_lastDest - GetTranslation()).magSquared() < 81.f; } bool CIceSheegoth::InPosition(CStateManager& mgr, float arg) { return (x92c_lastDest - GetTranslation()).magSquared() < 81.f; } bool CIceSheegoth::ShouldTurn(CStateManager& mgr, float arg) { if (arg == 0.f) { arg = zeus::degToRad(45.f); } return zeus::CVector2f::getAngleDiff(GetTransform().frontVector().toVec2f(), mgr.GetPlayer().GetTranslation().toVec2f() - GetTranslation().toVec2f()) > arg; } bool CIceSheegoth::AggressionCheck(CStateManager& mgr, float arg) { return !(!IsAlive() || xb28_30_ || !sub_801a1794(mgr)); } bool CIceSheegoth::ShouldFire(CStateManager& mgr, float arg) { if (GetAreaIdAlways() != mgr.GetPlayer().GetAreaIdAlways()) { return false; } zeus::CVector3f pos = mgr.GetPlayer().GetTranslation(); zeus::CTransform lctrXf = GetLctrTransform(xaf4_mouthLocator); if ((pos - lctrXf.origin).magSquared() <= x300_maxAttackRange * x300_maxAttackRange && std::fabs(pos.z() - GetTranslation().z()) < (lctrXf.origin.z() - GetTranslation().z()) && !ShouldTurn(mgr, 0.2617994f)) { return !IsPatternObstructed(mgr, lctrXf.origin, pos); } return false; } bool CIceSheegoth::ShouldFlinch(CStateManager& mgr, float arg) { return xb29_25_ && x97c_ > 0.f; } bool CIceSheegoth::ShotAt(CStateManager& mgr, float arg) { return x400_24_hitByPlayerProjectile; } bool CIceSheegoth::ShouldSpecialAttack(CStateManager& mgr, float arg) { if (GetAreaIdAlways() == mgr.GetPlayer().GetAreaId() && x954_attackTimeLeft <= 0.f && x974_ >= 0.3333f * x56c_sheegothData.Get_x170() && sub_8019ecbc()) { const zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f); const zeus::CTransform lctrXf = GetLctrTransform(xaf4_mouthLocator); if ((aimPos - lctrXf.origin).magSquared() > x2fc_minAttackRange * x2fc_minAttackRange && !ShouldTurn(mgr, zeus::degToRad(15.f))) { return !IsPatternObstructed(mgr, lctrXf.origin, aimPos); } } return false; } bool CIceSheegoth::LostInterest(CStateManager& mgr, float arg) { return x968_interestTimer >= x56c_sheegothData.GetMaxInterestTime(); } void CIceSheegoth::UpdateTouchBounds() { x978_ = 1.75f * GetModelData()->GetScale().y(); zeus::CAABox box{-x978_, -x978_, 0.f, x978_, x978_, 2.f * x978_}; SetBoundingBox(box); xa30_.SetBox(box); x760_pathSearch.SetCharacterRadius(x978_); x760_pathSearch.SetCharacterHeight(x978_); x760_pathSearch.SetPadding(20.f); x844_approachSearch.SetCharacterRadius(x978_); x844_approachSearch.SetCharacterHeight(x978_); x844_approachSearch.SetPadding(20.f); } void CIceSheegoth::ApplyContactDamage(TUniqueId sender, CStateManager& mgr) { if (const TCastToConstPtr colAct = mgr.GetObjectById(sender)) { if (colAct->GetHealthInfo(mgr)->GetHP() <= 0.f) { return; } bool bVar5 = (xb28_29_ && !xb28_25_ && xb28_28_) ? true : IsMouthCollider(sender); if (colAct->GetLastTouchedObject() == mgr.GetPlayer().GetUniqueId()) { if (bVar5) { mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), GetUniqueId(), x56c_sheegothData.Get_x1b8(), CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f); } else { mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), GetUniqueId(), GetContactDamage(), CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f); } } } } void CIceSheegoth::AddSphereCollisionList(const SSphereJointInfo* info, size_t count, std::vector& vecOut) { for (size_t i = 0; i < count; ++i) { const auto& joint = info[i]; CSegId id = GetModelData()->GetAnimationData()->GetLocatorSegId(joint.name); if (id.IsInvalid()) { continue; } vecOut.push_back(CJointCollisionDescription::SphereCollision(id, joint.radius, joint.name, 1000.f)); xb1c_.push_back(id); } } void CIceSheegoth::AddCollisionList(const SJointInfo* info, size_t count, std::vector& vecOut) { for (size_t i = 0; i < count; ++i) { const auto& joint = info[i]; CSegId fromId = GetModelData()->GetAnimationData()->GetLocatorSegId(joint.from); CSegId toId = GetModelData()->GetAnimationData()->GetLocatorSegId(joint.to); if (fromId.IsInvalid() || toId.IsInvalid()) { continue; } vecOut.push_back(CJointCollisionDescription::SphereSubdivideCollision( fromId, toId, joint.radius, joint.separation, CJointCollisionDescription::EOrientationType::One, joint.from, 1000.f)); } } void CIceSheegoth::SetupCollisionActorManager(CStateManager& mgr) { std::vector joints; joints.reserve(7); AddSphereCollisionList(skSphereJointList.data(), skSphereJointList.size(), joints); AddCollisionList(skLeftLegJointList.data(), skLeftLegJointList.size(), joints); AddCollisionList(skRightLegJointList.data(), skRightLegJointList.size(), joints); xa2c_collisionManager = std::make_unique(mgr, GetUniqueId(), GetAreaIdAlways(), joints, true); xa2c_collisionManager->SetActive(mgr, GetActive()); xa2c_collisionManager->AddMaterial(mgr, EMaterialTypes::CameraPassthrough); xb04_.clear(); xafc_gillColliders.clear(); for (size_t i = 0; i < xa2c_collisionManager->GetNumCollisionActors(); ++i) { const auto& desc = xa2c_collisionManager->GetCollisionDescFromIndex(i); if (TCastToPtr colAct = mgr.ObjectById(desc.GetCollisionActorId())) { colAct->SetDamageVulnerability(CDamageVulnerability::ImmuneVulnerabilty()); if (desc.GetName() == "LCTR_SHEMOUTH"sv) { xaf8_mouthCollider = desc.GetCollisionActorId(); colAct->SetDamageVulnerability(x98c_mouthVulnerability); } else if (desc.GetName() == "Jaw_end_LCTR"sv) { colAct->SetDamageVulnerability(CDamageVulnerability::PassThroughVulnerabilty()); } else if (desc.GetName() == "Ice_Shards_LCTR"sv) { xaf6_iceShardsCollider = desc.GetCollisionActorId(); colAct->SetWeaponCollisionResponseType(EWeaponCollisionResponseTypes::None); } else if (desc.GetName() == "GillL_LCTR"sv || desc.GetName() == "GillR_LCTR"sv) { xafc_gillColliders.emplace_back(desc.GetCollisionActorId()); } else { xb04_.emplace_back(desc.GetCollisionActorId()); colAct->SetDamageVulnerability(x56c_sheegothData.Get_x80()); } } } SetupHealthInfo(mgr); SetMaterialFilter(CMaterialFilter::MakeIncludeExclude( {EMaterialTypes::Solid}, {EMaterialTypes::Player, EMaterialTypes::CollisionActor, EMaterialTypes::AIPassthrough})); AddMaterial(EMaterialTypes::ProjectilePassthrough, mgr); xa2c_collisionManager->AddMaterial(mgr, {EMaterialTypes::AIJoint, EMaterialTypes::CameraPassthrough}); } void CIceSheegoth::SetupHealthInfo(CStateManager& mgr) { CHealthInfo* thisHealth = HealthInfo(mgr); x970_maxHp = thisHealth->GetHP(); for (auto& id : xafc_gillColliders) { if (TCastToPtr colAct = mgr.ObjectById(id)) { *colAct->HealthInfo(mgr) = *thisHealth; } } if (TCastToPtr colAct = mgr.ObjectById(xaf8_mouthCollider)) { *colAct->HealthInfo(mgr) = *thisHealth; } for (auto& id : xb04_) { if (TCastToPtr colAct = mgr.ObjectById(id)) { *colAct->HealthInfo(mgr) = *thisHealth; } } } void CIceSheegoth::sub_8019ebf0(CStateManager& mgr, float damage) { x974_ = zeus::clamp(0.f, x974_ + damage, x56c_sheegothData.Get_x170()); float fVar1 = (1.f / 3.f) * x56c_sheegothData.Get_x170(); if (fVar1 <= 0.f) { xb29_26_ = true; } else { xb29_26_ = mgr.GetActiveRandom()->Float() <= (x974_ / (3.f * fVar1)); } } void CIceSheegoth::ApplyWeaponDamage(CStateManager& mgr, TUniqueId sender) { if (const TCastToConstPtr wp = mgr.GetObjectById(sender)) { mgr.ApplyDamage(sender, xaf8_mouthCollider, wp->GetOwnerId(), wp->GetDamageInfo(), CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f); } } void CIceSheegoth::CreateFlameThrower(CStateManager& mgr) { if (xa80_flameThrowerId != kInvalidUniqueId) { return; } xa80_flameThrowerId = mgr.AllocateUniqueId(); mgr.AddObject(new CFlameThrower(xa84_, "IceSheegoth_Flame"sv, EWeaponType::Plasma, CFlameInfo{6, 4, x56c_sheegothData.GetFireBreathResId(), 15, 0.0625f, 20.f, 1.f}, {}, EMaterialTypes::CollisionActor, x56c_sheegothData.GetFireBreathDamage(), xa80_flameThrowerId, GetAreaIdAlways(), GetUniqueId(), EProjectileAttrib::None, x56c_sheegothData.Get_x1e4(), x56c_sheegothData.Get_x1e8(), x56c_sheegothData.Get_x1ec())); } void CIceSheegoth::AttractProjectiles(CStateManager& mgr) { if (!IsAlive()) return; rstl::reserved_vector nearProjectiles; zeus::CAABox attractionBounds = zeus::CAABox{GetTranslation() - x56c_sheegothData.Get_x14(), GetTranslation() + x56c_sheegothData.Get_x14()}; mgr.BuildNearList(nearProjectiles, attractionBounds, CMaterialFilter::MakeInclude({EMaterialTypes::Projectile}), nullptr); if (nearProjectiles.empty()) return; zeus::CVector3f attractionPos = GetEnergyAttractionPos(mgr); rstl::reserved_vector nearCharacters; mgr.BuildNearList(nearCharacters, attractionBounds, CMaterialFilter::MakeInclude({EMaterialTypes::Character}), nullptr); for (TUniqueId projectileId : nearProjectiles) { if (TCastToPtr proj = mgr.ObjectById(projectileId)) { if (!ShouldAttractProjectile(*proj, mgr)) continue; const zeus::CVector3f projPos = (attractionPos - proj->GetTranslation()) - proj->GetPreviousPos(); if (!projPos.canBeNormalized() || !IsClosestSheegoth(mgr, nearCharacters, projPos)) continue; const float mag = (attractionPos - proj->GetTranslation()).magnitude(); const zeus::CVector3f b = proj->GetTranslation() + (0.5f * mag) * (proj->GetTranslation() - proj->GetPreviousPos()).normalized(); const zeus::CVector3f c = attractionPos + zeus::CVector3f{0.f, 0.f, 0.4f * (0.4f * mag)}; const zeus::CVector3f point1 = zeus::getBezierPoint(proj->GetTranslation(), b, c, attractionPos, 0.333f); const zeus::CVector3f point2 = zeus::getBezierPoint(proj->GetTranslation(), b, c, attractionPos, 0.666f); const float t = (point2 - point1).magnitude() + (point1 - proj->GetTranslation()).magnitude() + (attractionPos - point2).magnitude(); const zeus::CVector3f point3 = zeus::getBezierPoint(proj->GetTranslation(), b, c, attractionPos, t / (proj->GetTranslation() - proj->GetPreviousPos()).magnitude()); zeus::CVector3f lookPos = point3 - proj->GetTranslation(); if (!lookPos.canBeNormalized()) { return; } zeus::CTransform xf = zeus::lookAt(zeus::skZero3f, lookPos); xf.orthonormalize(); proj->ProjectileWeapon().SetWorldSpaceOrientation(xf); zeus::CVector3f velocity = 0.8f * proj->GetProjectileWeapon().GetVelocity().normalized(); proj->ProjectileWeapon().SetVelocity(proj->ProjectileWeapon().GetVelocity() * (0.3999f + (velocity * 0.6f))); } } } void CIceSheegoth::UpdateTimers(float dt) { if (x954_attackTimeLeft > 0.f) { x954_attackTimeLeft -= (xb29_27_ ? 2.f : 1.f) * dt; } if (x960_ > 0.f) { x960_ -= dt; } if (x97c_ > 0.f) { x97c_ -= dt; } if (x958_ > 0.f) { x958_ -= dt; } if (x968_interestTimer < x56c_sheegothData.GetMaxInterestTime()) { x968_interestTimer += dt; } } void CIceSheegoth::UpdateScanState(CStateManager& mgr) { if (!xb29_29_scanned && GetScannableObjectInfo() != nullptr && zeus::close_enough(1.f, mgr.GetPlayerState()->GetScanTime(GetScannableObjectInfo()->GetScannableObjectId()))) { xb29_29_scanned = true; } } void CIceSheegoth::SetPassthroughVulnerability(CStateManager& mgr) { for (size_t i = 0; i < xa2c_collisionManager->GetNumCollisionActors(); ++i) { const auto& jInfo = xa2c_collisionManager->GetCollisionDescFromIndex(i); if (TCastToPtr colAct = mgr.ObjectById(jInfo.GetCollisionActorId())) { colAct->AddMaterial(EMaterialTypes::ProjectilePassthrough); } } } void CIceSheegoth::PreventWorldCollisions(float dt, CStateManager& mgr) { if (GetBodyController()->GetLocomotionType() == pas::ELocomotionType::Crouch || !IsOnGround() || mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed) { return; } zeus::CAABox ourBox = GetModelData()->GetBounds(GetTransform()); zeus::CAABox plBox = mgr.GetPlayer().GetBoundingBox(); if (!ourBox.intersects(plBox)) { return; } zeus::CVector3f maxDeviation = zeus::skZero3f; float lastMag = 0.f; zeus::CVector3f predictedTrans = PredictMotion(dt).x0_translation; for (CSegId uid : xb1c_) { auto deviation = xa2c_collisionManager->GetDeviation(mgr, uid); if (!deviation) { continue; } const zeus::CVector3f curDeviation = ((*deviation) + predictedTrans); if (curDeviation.magnitude() > lastMag) { maxDeviation = curDeviation; lastMag = curDeviation.magnitude(); } } if (lastMag <= (0.6f * GetModelData()->GetScale().y())) { return; } zeus::CVector3f posDiff = GetTranslation() - mgr.GetPlayer().GetTranslation(); const zeus::CVector3f direction = GetTransform().transposeRotate( (posDiff.dot(posDiff * maxDeviation.normalized()) / posDiff.magSquared()) * posDiff); ApplyImpulseOR(GetMoveToORImpulseWR(direction, dt), zeus::CAxisAngle{}); } void CIceSheegoth::UpdateHealthInfo(CStateManager& mgr) { if (!IsAlive()) { return; } float hpDelta = 0.f; if (const TCastToConstPtr colAct = mgr.ObjectById(xaf8_mouthCollider)) { hpDelta = std::max(hpDelta, x970_maxHp - colAct->GetHealthInfo(mgr)->GetHP()); } for (const auto& uid : xafc_gillColliders) { if (const TCastToConstPtr colAct = mgr.ObjectById(uid)) { hpDelta = std::max(hpDelta, x970_maxHp - colAct->GetHealthInfo(mgr)->GetHP()); } } for (const auto& uid : xb04_) { if (const TCastToConstPtr colAct = mgr.ObjectById(uid)) { hpDelta = std::max(hpDelta, x970_maxHp - colAct->GetHealthInfo(mgr)->GetHP()); } } HealthInfo(mgr)->SetHP(HealthInfo(mgr)->GetHP() - hpDelta); if (GetHealthInfo(mgr)->GetHP() > 0.f) { if (const TCastToPtr colAct = mgr.ObjectById(xaf8_mouthCollider)) { colAct->HealthInfo(mgr)->SetHP(x970_maxHp); } for (const auto& uid : xafc_gillColliders) { if (const TCastToPtr colAct = mgr.ObjectById(uid)) { colAct->HealthInfo(mgr)->SetHP(x970_maxHp); } } for (const auto& uid : xb04_) { if (const TCastToPtr colAct = mgr.ObjectById(uid)) { colAct->HealthInfo(mgr)->SetHP(x970_maxHp); } } } else { Death(mgr, zeus::skZero3f, EScriptObjectState::DeathRattle); } } void CIceSheegoth::SetSteeringSpeed(float dt, CStateManager& mgr) { const float steeringSpeedRange = x95c_ > 0.f ? 1.f : x944_; if (steeringSpeedRange > x948_) { x948_ = std::max(steeringSpeedRange, x948_ - (2.f * dt)); } else if (steeringSpeedRange < x948_) { x948_ = std::min(steeringSpeedRange, x948_ + (2.f * dt)); } GetBodyController()->GetCommandMgr().SetSteeringSpeedRange(x948_, x948_); } void CIceSheegoth::UpdateParticleEffects(float dt, CStateManager& mgr) { if (auto* fl = static_cast(mgr.ObjectById(xa80_flameThrowerId))) { if (fl->GetActive()) { fl->SetTransform(GetLctrTransform("LCTR_SHEMOUTH"sv), dt); } } if (const TCastToConstPtr colAct = mgr.GetObjectById(xaf6_iceShardsCollider)) { const float time = 0.333f * x56c_sheegothData.Get_x170(); if (x974_ >= 3.f * time) { xa9c_->SetParticleEmission(false); xab0_->SetParticleEmission(false); xac4_->SetParticleEmission(true); xad8_->SetParticleEmission(true); } else if (x974_ >= 2.f * time) { xa9c_->SetParticleEmission(false); xab0_->SetParticleEmission(true); xac4_->SetParticleEmission(false); xad8_->SetParticleEmission(false); } else { xa9c_->SetParticleEmission(x974_ > 0.f); xab0_->SetParticleEmission(false); xac4_->SetParticleEmission(false); xad8_->SetParticleEmission(false); } const zeus::CTransform rotation = GetTransform().getRotation(); const zeus::CVector3f pos = colAct->GetTranslation(); xa9c_->SetOrientation(rotation); xa9c_->SetGlobalTranslation(pos); xab0_->SetOrientation(rotation); xab0_->SetGlobalTranslation(pos); xac4_->SetOrientation(rotation); xac4_->SetGlobalTranslation(pos); xad8_->SetOrientation(rotation); xad8_->SetGlobalTranslation(pos); if (xaec_) { xaec_->SetParticleEmission(true); xaec_->SetOrientation(rotation); xaec_->SetGlobalTranslation(pos); xaec_->SetGlobalScale(GetModelData()->GetScale()); xaec_->Update(dt); } xa9c_->Update(dt); xab0_->Update(dt); xac4_->Update(dt); xad8_->Update(dt); if (x974_ < 2.f * time && xaf0_crackleSfx) { CSfxManager::RemoveEmitter(xaf0_crackleSfx); } else { xaf0_crackleSfx = CSfxManager::AddEmitter(x56c_sheegothData.Get_x1d4(), GetTranslation(), zeus::skZero3f, false, true, 127, kInvalidAreaId); } } else { xa9c_->SetParticleEmission(false); xab0_->SetParticleEmission(false); xac4_->SetParticleEmission(false); xad8_->SetParticleEmission(false); } } void CIceSheegoth::UpdateAttackPosition(CStateManager& mgr, zeus::CVector3f& attackPos) { attackPos = GetTranslation(); if (x954_attackTimeLeft > 0.f) { return; } attackPos = mgr.GetPlayer().GetTranslation(); zeus::CVector3f distVec = GetTranslation() - attackPos; if (distVec.canBeNormalized()) { attackPos += x2fc_minAttackRange * distVec.normalized(); } } bool CIceSheegoth::sub_8019ecdc(CStateManager& mgr, float minAngle) { const zeus::CVector3f plAimPos = mgr.GetPlayer().GetAimPosition(mgr, GetModelData()->GetAnimationData()->GetSpeedScale() > 0.f ? 1.25f / GetModelData()->GetAnimationData()->GetSpeedScale() : 0.f); return zeus::CVector2f::getAngleDiff(GetTransform().basis[1].toVec2f(), plAimPos.toVec2f() - GetTranslation().toVec2f()) > minAngle; } void CIceSheegoth::SetMouthVulnerability(CStateManager& mgr, bool isVulnerable) { if (TCastToPtr colAct = mgr.ObjectById(xaf8_mouthCollider)) { colAct->SetDamageVulnerability(isVulnerable ? x56c_sheegothData.Get_xe8() : x98c_mouthVulnerability); } } void CIceSheegoth::SetGillVulnerability(CStateManager& mgr, bool isVulnerable) { for (TUniqueId uid : xafc_gillColliders) { if (TCastToPtr colAct = mgr.ObjectById(uid)) { colAct->SetDamageVulnerability(isVulnerable ? x56c_sheegothData.Get_x18() : CDamageVulnerability::ImmuneVulnerabilty()); } } } void CIceSheegoth::SetCollisionActorExtendedTouchBounds(CStateManager& mgr, const zeus::CVector3f& extents) { for (size_t i = 0; i < xa2c_collisionManager->GetNumCollisionActors(); ++i) { if (TCastToPtr colAct = mgr.ObjectById(xa2c_collisionManager->GetCollisionDescFromIndex(i).GetCollisionActorId())) { colAct->SetExtendedTouchBounds(extents); } } } void CIceSheegoth::ShakePlayer(CStateManager& mgr) { const zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - GetTranslation(); const float magnitude = (0.5f - (0.01f * posDiff.magnitude())); if (magnitude > 0.f) { if (mgr.GetPlayer().GetSurfaceRestraint() != CPlayer::ESurfaceRestraints::Air && !mgr.GetPlayer().IsInWaterMovement()) { bool applyImpulseToPlayer = true; if (mgr.GetPlayer().GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Morphed) { if (mgr.GetCameraManager()->GetCurrentCameraId() == mgr.GetCameraManager()->GetFirstPersonCamera()->GetUniqueId()) { mgr.GetCameraManager()->AddCameraShaker( CCameraShakeData::BuildPatternedExplodeShakeData(GetTranslation(), 0.5f, magnitude, 50.f), true); } applyImpulseToPlayer = xb28_27_; } if (applyImpulseToPlayer) { const zeus::CVector3f direction = magnitude * ((xb28_27_ ? 40.f : 25.f) * zeus::skUp); zeus::CVector3f impulse = zeus::skZero3f; if (x978_ < posDiff.magnitude() && xb28_27_ && posDiff.toVec2f().canBeNormalized()) { impulse = magnitude * (12.5f * posDiff.toVec2f().normalized()); } mgr.GetPlayer().ApplyImpulseWR(mgr.GetPlayer().GetMass() * (direction + impulse), zeus::CAxisAngle{}); mgr.GetPlayer().SetMoveState(CPlayer::EPlayerMovementState::ApplyJump, mgr); } } } if (xb28_28_) { sub_8019ebf0(mgr, 0.25f * x56c_sheegothData.Get_x170()); } } zeus::CVector3f CIceSheegoth::GetEnergyAttractionPos(CStateManager& mgr) const { if (const TCastToConstPtr colAct = mgr.GetObjectById(xaf6_iceShardsCollider)) { return colAct->GetTranslation(); } return GetTranslation(); } bool CIceSheegoth::ShouldAttractProjectile(const CGameProjectile& proj, CStateManager& mgr) const { if (proj.GetType() != EWeaponType::Missile && proj.GetType() != EWeaponType::Plasma && (!proj.GetDamageInfo().GetWeaponMode().IsComboed() || proj.GetType() != EWeaponType::Power)) { const CActor* ent = static_cast(mgr.GetObjectById(proj.GetOwnerId())); if (ent != nullptr) { if (CPatterned::CastTo(ent) == nullptr && ent->GetAreaIdAlways() == GetAreaIdAlways()) { zeus::CVector3f r = GetTransform().rotate(x56c_sheegothData.Get_x8()); zeus::CVector3f posDiff = proj.GetTranslation() - ent->GetTranslation(); if (proj.GetType() == EWeaponType::Wave && !proj.GetDamageInfo().GetWeaponMode().IsCharged() && !proj.GetDamageInfo().GetWeaponMode().IsComboed() && posDiff.magSquared() < 100.f) { return false; } zeus::CVector3f xyPos = posDiff.toVec2f() - GetTranslation().toVec2f() + r.toVec2f(); if (zeus::CVector3f::getAngleDiff(GetTransform().frontVector(), xyPos) <= x56c_sheegothData.Get_x4()) { if (zeus::CVector3f::getAngleDiff(GetTransform().frontVector(), -xyPos) >= x56c_sheegothData.Get_x0()) { return false; } } return true; } } } return false; } bool CIceSheegoth::IsClosestSheegoth(CStateManager& mgr, const rstl::reserved_vector& nearList, const zeus::CVector3f& projectileOffset) const { zeus::CVector3f diff = projectileOffset - GetTranslation(); const float diffMag = diff.magSquared(); for (const auto& uid : nearList) { const CIceSheegoth* goth = CPatterned::CastTo(mgr.GetObjectById(uid)); if (!goth || goth->GetUniqueId() == GetUniqueId()) continue; diff = projectileOffset - goth->GetTranslation(); if (diff.magSquared() < diffMag) { return false; } } return true; } } // namespace metaforce::MP1