From d4bb7d64ebdc2c46ef1a16c9bc6bff9e34f4b367 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 10 Nov 2018 17:27:54 -1000 Subject: [PATCH] All CPatterned functions implemented --- DataSpec/DNAMP1/ScriptObjects/Parameters.hpp | 28 +- DataSpec/DNAMP1/ScriptObjects/Waypoint.hpp | 20 +- Runtime/CStateManager.cpp | 8 +- Runtime/Character/CBodyState.cpp | 10 +- Runtime/Character/CBodyStateCmdMgr.hpp | 3 +- Runtime/MP1/World/CParasite.cpp | 4 +- Runtime/Weapon/CPlayerGun.cpp | 2 +- Runtime/World/CActor.cpp | 10 +- Runtime/World/CActor.hpp | 3 +- Runtime/World/CAi.hpp | 4 +- Runtime/World/CAiFuncMap.hpp | 1 + Runtime/World/CPathFindSearch.hpp | 6 + Runtime/World/CPatterned.cpp | 1189 +++++++++++++++--- Runtime/World/CPatterned.hpp | 302 +++-- Runtime/World/CPatternedInfo.cpp | 8 +- Runtime/World/CPatternedInfo.hpp | 8 +- Runtime/World/CScriptActorKeyframe.cpp | 8 +- Runtime/World/CScriptActorKeyframe.hpp | 5 +- Runtime/World/CScriptWaypoint.cpp | 10 +- Runtime/World/CScriptWaypoint.hpp | 32 +- Runtime/World/CStateMachine.cpp | 8 +- Runtime/World/CStateMachine.hpp | 30 +- Runtime/World/CWallWalker.cpp | 12 +- Runtime/World/CWallWalker.hpp | 2 +- Runtime/World/ScriptLoader.cpp | 23 +- Runtime/World/ScriptObjectSupport.cpp | 8 +- Runtime/World/ScriptObjectSupport.hpp | 8 +- 27 files changed, 1383 insertions(+), 369 deletions(-) diff --git a/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp b/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp index a70da759c..45ab1a8ca 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp @@ -276,27 +276,27 @@ struct PatternedInfo : BigDNA Value damageWaitTime; HealthInfo healthInfo; DamageVulnerability damageVulnerability; - Value unkown1; - Value unkown2; - Value unkown3; - Value unkown4; - Value unkown5; - Value unkown6; - Value unkown7; - Value soundID1; + Value halfExtent; + Value height; + Value bodyOrigin; + Value stepUpHeight; + Value xDamage; + Value frozenXDamage; + Value xDamageDelay; + Value deathSfx; AnimationParameters animationParameters; Value active; UniqueID32 stateMachine; - Value unknown8; - Value unknown9; + Value intoFreezeDur; + Value outOfFreezeDur; Value unknown10; - Value unknown11; - Value unknown12; + Value particle1Frames; + Value particle1Scale; UniqueID32 particle1; UniqueID32 electric; - Value unknown14; + Value particle2Scale; UniqueID32 particle2; - Value soundID2; + Value iceShatterSfx; void nameIDs(PAKRouter& pakRouter, const std::string& name) const { diff --git a/DataSpec/DNAMP1/ScriptObjects/Waypoint.hpp b/DataSpec/DNAMP1/ScriptObjects/Waypoint.hpp index a07e57099..643cd7060 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Waypoint.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Waypoint.hpp @@ -13,16 +13,16 @@ struct Waypoint : IScriptObject String<-1> name; Value location; Value orientation; - Value unknown1; - Value unknown2; - Value unknown3; - Value unknown4; - Value unknown5; - Value unknown6; - Value unknown7; - Value unknown8; - Value jumpFlags; // 0x2: single, 0x4: double - Value unknown10; + Value active; + Value speed; + Value pause; + Value patternTranslate; + Value patternOrient; + Value patternFit; + Value behaviour; + Value behaviourOrient; + Value behaviourModifiers; // 0x2: single, 0x4: double + Value animation; }; } diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index a6d231b67..3fd31051b 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -1740,7 +1740,7 @@ void CStateManager::TestBombHittingWater(const CActor& damager, const zeus::CVec } } -bool CStateManager::ApplyLocalDamage(const zeus::CVector3f& vec1, const zeus::CVector3f& vec2, CActor& damagee, +bool CStateManager::ApplyLocalDamage(const zeus::CVector3f& pos, const zeus::CVector3f& dir, CActor& damagee, float dam, const CWeaponMode& weapMode) { CHealthInfo* hInfo = damagee.HealthInfo(*this); @@ -1789,7 +1789,7 @@ bool CStateManager::ApplyLocalDamage(const zeus::CVector3f& vec1, const zeus::CV if (player && GetPlayerState()->CanTakeDamage()) { - player->TakeDamage(significant, vec1, mulDam, weapMode.GetType(), *this); + player->TakeDamage(significant, pos, mulDam, weapMode.GetType(), *this); if (newHp <= 0.f) x8b8_playerState->SetPlayerAlive(false); } @@ -1797,9 +1797,9 @@ bool CStateManager::ApplyLocalDamage(const zeus::CVector3f& vec1, const zeus::CV if (ai) { if (significant) - ai->TakeDamage(vec2, mulDam); + ai->TakeDamage(dir, mulDam); if (newHp <= 0.f) - ai->Death(*this, vec2, EScriptObjectState::DeathRattle); + ai->Death(*this, dir, EScriptObjectState::DeathRattle); } return significant; diff --git a/Runtime/Character/CBodyState.cpp b/Runtime/Character/CBodyState.cpp index 4af1e741c..629f9888f 100644 --- a/Runtime/Character/CBodyState.cpp +++ b/Runtime/Character/CBodyState.cpp @@ -1023,7 +1023,7 @@ bool CBSJump::CheckForWallJump(CBodyController& bc, CStateManager& mgr) float distToWall = (xc_waypoint1 - act->GetTranslation()).magnitude(); zeus::CAABox aabb = act->GetBoundingBox(); float xExtent = (aabb.max.x - aabb.min.x) * 0.5f; - if (distToWall < 1.414f * xExtent || (act->GetX328_26() && distToWall < 3.f * xExtent)) + if (distToWall < 1.414f * xExtent || (act->CanLongJump() && distToWall < 3.f * xExtent)) { x4_state = x30_26_wallBounceRight ? pas::EJumpState::WallBounceRight : pas::EJumpState::WallBounceLeft; CPASAnimParmData parms(13, CPASAnimParm::FromEnum(s32(x4_state)), @@ -1041,7 +1041,7 @@ void CBSJump::CheckForLand(CBodyController& bc, CStateManager& mgr) { if (TCastToPtr act = bc.GetOwner()) { - if (act->GetX328_26() || act->IsOnGround()) + if (act->CanLongJump() || act->IsOnGround()) { x4_state = pas::EJumpState::OutOfJump; CPASAnimParmData parms(13, CPASAnimParm::FromEnum(s32(x4_state)), @@ -1275,7 +1275,7 @@ bool CBSHurled::ShouldStartStrikeWall(CBodyController& bc) const { if (TCastToPtr ai = bc.GetOwner()) { - if (ai->GetX328_26()) + if (ai->CanLongJump()) if (!ai->IsOnGround()) return true; } @@ -1652,7 +1652,7 @@ bool CBSWallHang::CheckForLand(CBodyController& bc, CStateManager& mgr) { if (TCastToPtr ai = bc.GetOwner()) { - if (ai->GetX328_26() || ai->IsOnGround()) + if (ai->CanLongJump() || ai->IsOnGround()) { x4_state = pas::EWallHangState::DetachOutOfJump; CPASAnimParmData parms(20, CPASAnimParm::FromEnum(s32(x4_state))); @@ -1673,7 +1673,7 @@ bool CBSWallHang::CheckForWall(CBodyController& bc, CStateManager& mgr) if (wp) magSq = (wp->GetTranslation() - ai->GetTranslation()).magSquared(); - if (magSq < 1.f || ai->GetX328_26()) + if (magSq < 1.f || ai->CanLongJump()) { x4_state = pas::EWallHangState::IntoWallHang; CPASAnimParmData parms(20, CPASAnimParm::FromEnum(s32(x4_state))); diff --git a/Runtime/Character/CBodyStateCmdMgr.hpp b/Runtime/Character/CBodyStateCmdMgr.hpp index 58aa3b048..17b0cf5c6 100644 --- a/Runtime/Character/CBodyStateCmdMgr.hpp +++ b/Runtime/Character/CBodyStateCmdMgr.hpp @@ -91,7 +91,8 @@ public: CBCGenerateCmd(pas::EGenerateType type, int i) : CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type) { x1c_24_targetTransform = false; x1c_25_overrideAnim = false; } CBCGenerateCmd(pas::EGenerateType type, const zeus::CVector3f& vec) - : CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type) { x1c_24_targetTransform = false; x1c_25_overrideAnim = false; } + : CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type), xc_targetPos(vec) + { x1c_24_targetTransform = false; x1c_25_overrideAnim = false; } pas::EGenerateType GetGenerateType() const { return x8_type; } const zeus::CVector3f& GetExitTargetPos() const { return xc_targetPos; } bool HasExitTargetPos() const { return x1c_24_targetTransform; } diff --git a/Runtime/MP1/World/CParasite.cpp b/Runtime/MP1/World/CParasite.cpp index 8555eea43..fce787237 100644 --- a/Runtime/MP1/World/CParasite.cpp +++ b/Runtime/MP1/World/CParasite.cpp @@ -183,11 +183,11 @@ void CParasite::Think(float dt, CStateManager& mgr) x742_27_ = false; } - if (x420_curDamageTime <= 0.f) + if (x420_curDamageRemTime <= 0.f) { mgr.ApplyDamage(GetUniqueId(), pl->GetUniqueId(), GetUniqueId(), GetContactDamage(), CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); - x420_curDamageTime = x424_damageWaitTime; + x420_curDamageRemTime = x424_damageWaitTime; } } } diff --git a/Runtime/Weapon/CPlayerGun.cpp b/Runtime/Weapon/CPlayerGun.cpp index da7b3d52e..06ee7d9f4 100644 --- a/Runtime/Weapon/CPlayerGun.cpp +++ b/Runtime/Weapon/CPlayerGun.cpp @@ -312,7 +312,7 @@ void CPlayerGun::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CSt } else if (TCastToConstPtr ai = mgr.GetObjectById(sender)) { - if (ai->GetX402_28()) + if (ai->IsMakingBigStrike()) { x394_damageTimer = ai->GetDamageDuration(); bigStrike = true; diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 2ce1a82e8..c46b081c2 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -37,7 +37,7 @@ CActor::CActor(TUniqueId uid, bool active, std::string_view name, const CEntityI x90_actorLights = mData.IsNull() ? std::unique_ptr() : params.x0_lightParms.MakeActorLights(); if (mData.x10_animData || mData.x1c_normalModel) x64_modelData = std::make_unique(std::move(mData)); - xd0_thermalMag = params.x64_thermalMag; + xd0_damageMag = params.x64_thermalMag; xd8_nonLoopingSfxHandles.resize(2); xe4_27_notInSortedLists = true; xe4_28_transformDirty = true; @@ -241,14 +241,14 @@ void CActor::RenderInternal(const CStateManager& mgr) const { float addMag; float mulMag = 1.f; - if (xd0_thermalMag <= 1.f) + if (xd0_damageMag <= 1.f) { - mulMag = xd0_thermalMag; + mulMag = xd0_damageMag; addMag = 0.f; } - else if (xd0_thermalMag < 2.f) + else if (xd0_damageMag < 2.f) { - addMag = xd0_thermalMag - 1.f; + addMag = xd0_damageMag - 1.f; } else { diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 89bd566a5..635949e3a 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -45,7 +45,7 @@ protected: TUniqueId xc6_nextDrawNode; int xc8_drawnToken = -1; int xcc_addedToken = -1; - float xd0_thermalMag; + float xd0_damageMag; float xd4_maxVol = 1.f; rstl::reserved_vector xd8_nonLoopingSfxHandles; union @@ -200,6 +200,7 @@ public: TUniqueId GetFluidId() const { return xc4_fluidId; } bool GetPointGeneratorParticles() const { return xe5_31_pointGeneratorParticles; } void SetPointGeneratorParticles(bool s) { xe5_31_pointGeneratorParticles = s; } + CSimpleShadow* Shadow() { return x94_simpleShadow.get(); } }; } diff --git a/Runtime/World/CAi.hpp b/Runtime/World/CAi.hpp index 3e155877d..55eb48c3a 100644 --- a/Runtime/World/CAi.hpp +++ b/Runtime/World/CAi.hpp @@ -45,12 +45,12 @@ public: virtual void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); virtual CHealthInfo* HealthInfo(CStateManager&) { return &x258_healthInfo; } - virtual void Death(CStateManager& mgr, const zeus::CVector3f&, EScriptObjectState)=0; + virtual void Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state)=0; virtual void KnockBack(const zeus::CVector3f&, CStateManager&, const CDamageInfo& info, EKnockBackType type, bool inDeferred, float magnitude)=0; virtual const CDamageVulnerability* GetDamageVulnerability() const { return &x260_damageVulnerability; } virtual const CDamageVulnerability* GetDamageVulnerability() { return &x260_damageVulnerability; } - virtual void TakeDamage(const zeus::CVector3f&, float) {} + virtual void TakeDamage(const zeus::CVector3f& direction, float magnitude) {} virtual bool CanBeShot(const CStateManager&, int) { return true; } virtual bool IsListening() const { return false; } virtual int Listen(const zeus::CVector3f&, EListenNoiseType) { return 0; } diff --git a/Runtime/World/CAiFuncMap.hpp b/Runtime/World/CAiFuncMap.hpp index 91e51e29d..710b84ef0 100644 --- a/Runtime/World/CAiFuncMap.hpp +++ b/Runtime/World/CAiFuncMap.hpp @@ -7,6 +7,7 @@ namespace urde { enum class EStateMsg { + Zero = 0, One = 1, Two = 2 }; diff --git a/Runtime/World/CPathFindSearch.hpp b/Runtime/World/CPathFindSearch.hpp index d62f9fe04..3a6508197 100644 --- a/Runtime/World/CPathFindSearch.hpp +++ b/Runtime/World/CPathFindSearch.hpp @@ -38,6 +38,12 @@ public: EResult FindClosestReachablePoint(const zeus::CVector3f& p1, zeus::CVector3f& p2) const; EResult PathExists(const zeus::CVector3f& p1, const zeus::CVector3f& p2) const; EResult OnPath(const zeus::CVector3f& p1) const; + EResult GetResult() const { return xcc_result; } + u32 GetCurrentWaypoint() const { return xc8_curWaypoint; } + void SetCurrentWaypoint(u32 wp) { xc8_curWaypoint = wp; } + const rstl::reserved_vector& GetWaypoints() const { return x4_waypoints; } + bool IsOver() const { return GetCurrentWaypoint() >= x4_waypoints.size(); } + bool IsShagged() const { return GetResult() != EResult::Success; } bool SegmentOver(const zeus::CVector3f& p1) const; void GetSplinePoint(zeus::CVector3f& pOut, const zeus::CVector3f& p1) const; void GetSplinePointWithLookahead(zeus::CVector3f& pOut, const zeus::CVector3f& p1, float lookahead) const; diff --git a/Runtime/World/CPatterned.cpp b/Runtime/World/CPatterned.cpp index 67c228d22..6ec0d6074 100644 --- a/Runtime/World/CPatterned.cpp +++ b/Runtime/World/CPatterned.cpp @@ -1,4 +1,3 @@ -#include #include "CPatterned.hpp" #include "Runtime/CStateManager.hpp" #include "CPatternedInfo.hpp" @@ -15,6 +14,10 @@ #include "World/CStateMachine.hpp" #include "CExplosion.hpp" #include "Graphics/CSkinnedModel.hpp" +#include "CPathFindSearch.hpp" +#include "Camera/CFirstPersonCamera.hpp" +#include "World/CScriptWaypoint.hpp" +#include "World/CScriptActorKeyframe.hpp" namespace urde { @@ -52,24 +55,27 @@ x3c4_detectionAngle(std::cos(zeus::degToRad(pInfo.x14_dectectionAngle))), x3c8_leashRadius(pInfo.x28_leashRadius), x3cc_playerLeashRadius(pInfo.x2c_playerLeashRadius), x3d0_playerLeashTime(pInfo.x30_playerLeashTime), +x3d8_xDamageThreshold(pInfo.xdc_xDamage), +x3dc_frozenXDamageThreshold(pInfo.xe0_frozenXDamage), +x3e0_xDamageDelay(pInfo.xe4_xDamageDelay), x3fc_flavor(flavor), x460_knockBackController(kbVariant) { x400_25_alive = true; - x400_31_ = moveType == CPatterned::EMovementType::Flyer; - x402_29_ = true; - x402_30_ = x402_31_thawed = actorParms.HasThermalHeat(); - x403_25_ = true; - x403_26_ = true; + x400_31_isFlyer = moveType == CPatterned::EMovementType::Flyer; + x402_29_drawParticles = true; + x402_30_updateThermalFrozenState = x402_31_thawed = actorParms.HasThermalHeat(); + x403_25_enableStateMachine = true; + x403_26_stateControlledMassiveDeath = true; x404_contactDamage = pInfo.x34_contactDamageInfo; x424_damageWaitTime = pInfo.x50_damageWaitTime; x454_deathSfx = pInfo.xe8_deathSfx; x458_iceShatterSfx = pInfo.x134_iceShatterSfx; - x4f4_ = pInfo.x100_; - x4f8_ = pInfo.x104_; + x4f4_intoFreezeDur = pInfo.x100_intoFreezeDur; + x4f8_outofFreezeDur = pInfo.x104_outofFreezeDur; x4fc_ = pInfo.x108_; x508_colliderType = colliderType; - x50c_thermalMag = actorParms.GetThermalMag(); + x50c_baseDamageMag = actorParms.GetThermalMag(); x514_deathExplosionOffset = pInfo.x110_particle1Scale; x540_iceDeathExplosionOffset = pInfo.x124_particle2Scale; @@ -86,7 +92,7 @@ x460_knockBackController(kbVariant) x404_contactDamage.SetRadius(0.f); xe6_29_renderParticleDBInside = false; - x402_27_ = !x64_modelData->HasModel(CModelData::EWhichModel::XRay); + x402_27_noXrayModel = !x64_modelData->HasModel(CModelData::EWhichModel::XRay); BuildBodyController(bodyType); } @@ -99,7 +105,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState { CAi::AcceptScriptMsg(msg, uid, mgr); - switch(msg) + switch (msg) { case EScriptObjectMessage::Registered: { @@ -125,7 +131,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState } case EScriptObjectMessage::OnFloor: { - if (!x328_25_) + if (!x328_25_verticalMovement) { x150_momentum = {}; AddMaterial(EMaterialTypes::GroundCollider, mgr); @@ -135,7 +141,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState } case EScriptObjectMessage::Falling: { - if (!x328_25_) + if (!x328_25_verticalMovement) { if (x450_bodyController->GetPercentageFrozen() == 0.f) { @@ -147,7 +153,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState break; } case EScriptObjectMessage::Activate: - x3a0_ = GetTranslation(); + x3a0_latestLeashPosition = GetTranslation(); break; case EScriptObjectMessage::Deleted: if (x330_stateMachineState.GetActorState() != nullptr) @@ -162,7 +168,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState { if (x460_knockBackController.x81_26_enableShock && info.GetWeaponMode().IsComboed() && HealthInfo(mgr)) { - x401_31_ = true; + x401_31_nextPendingShock = true; KnockBack(GetTransform().frontVector(), mgr, info, EKnockBackType::Radius, false, info.GetKnockBackPower()); x460_knockBackController.DeferKnockBack(EWeaponType::Wave); @@ -178,7 +184,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState } } if (mgr.GetPlayer().GetUniqueId() == proj->GetOwnerId()) - x400_24_ = true; + x400_24_hitByPlayerProjectile = true; } break; } @@ -187,7 +193,7 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState if (TCastToConstPtr proj = mgr.GetObjectById(uid)) { if (proj->GetOwnerId() == mgr.GetPlayer().GetUniqueId()) - x400_24_ = true; + x400_24_hitByPlayerProjectile = true; } break; } @@ -195,12 +201,12 @@ void CPatterned::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState } } -void CPatterned::UpdateFrozenState(bool thawed) +void CPatterned::UpdateThermalFrozenState(bool thawed) { x402_31_thawed = thawed; if (x403_24_keepThermalVisorState) return; - xe6_27_thermalVisorFlags = thawed ? 2 : 1; + xe6_27_thermalVisorFlags = u8(thawed ? 2 : 1); } void CPatterned::Think(float dt, CStateManager& mgr) @@ -208,84 +214,86 @@ void CPatterned::Think(float dt, CStateManager& mgr) if (!GetActive()) return; - if (x402_30_) - UpdateFrozenState(x450_bodyController->GetPercentageFrozen() == 0.f); + if (x402_30_updateThermalFrozenState) + UpdateThermalFrozenState(x450_bodyController->GetPercentageFrozen() == 0.f); if (x64_modelData->GetAnimationData()->GetIceModel()) x510_vertexMorph->Update(dt); - if (x402_26_) + if (x402_26_dieIf80PercFrozen) { float froz = x450_bodyController->GetPercentageFrozen(); if (froz > 0.8f) - x400_29_ = true; + x400_29_pendingMassiveFrozenDeath = true; } - if (x400_25_alive && !x400_28_ && x400_29_) + if (!x400_25_alive) { - if (x3e0_ > 0.f && x400_29_) + if ((x400_28_pendingMassiveDeath || x400_29_pendingMassiveFrozenDeath) && x3e0_xDamageDelay <= 0.f) { - SendScriptMsgs(EScriptObjectState::AboutToDie, mgr, EScriptObjectMessage::None); - DoIceDeath(mgr); + if (x400_29_pendingMassiveFrozenDeath) + { + SendScriptMsgs(EScriptObjectState::AboutToMassivelyDie, mgr, EScriptObjectMessage::None); + MassiveFrozenDeath(mgr); + } + else + { + SendScriptMsgs(EScriptObjectState::AboutToMassivelyDie, mgr, EScriptObjectMessage::None); + MassiveDeath(mgr); + } } else { - SendScriptMsgs(EScriptObjectState::AboutToDie, mgr, EScriptObjectMessage::None); - DoDeath(mgr); - } - } - else if (!x400_29_) - { - x3e0_ -= dt; - if (x403_26_) - { - if (x330_stateMachineState.sub8007FB9C()) + x3e0_xDamageDelay -= dt; + if (x403_26_stateControlledMassiveDeath && x330_stateMachineState.GetName()) { - u32 unk = x330_stateMachineState.sub8007FB9C(); - bool isDead = false; //sub8007A454(unk, "Dead"sv); - - if (!isDead && x330_stateMachineState.x8_time > 15.f) - DoDeath(mgr); + bool isDead = x330_stateMachineState.GetName() == "Dead"sv; + if (isDead && x330_stateMachineState.x8_time > 15.f) + MassiveDeath(mgr); } } } - UpdateAlpha(dt, mgr); + UpdateAlphaDelta(dt, mgr); - x3e4_ = HealthInfo(mgr)->GetHP(); + x3e4_lastHP = HealthInfo(mgr)->GetHP(); if (!x330_stateMachineState.x4_state) x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "Start"sv); - zeus::CVector3f diffVec = x4e4_ - GetTranslation(); - if (!x328_25_) + zeus::CVector3f diffVec = x4e4_latestPredictedTranslation - GetTranslation(); + if (!x328_25_verticalMovement) diffVec.z = 0.f; if (diffVec.magSquared() > (0.1f * dt)) - x4f0_ += dt; + x4f0_predictedLeashTime += dt; else - x4f0_ = 0.f; + x4f0_predictedLeashTime = 0.f; - if (x460_knockBackController.x81_26_enableShock && x401_31_ && x402_24_) - Shock(0.5f + mgr.GetActiveRandom()->Range(0.f, 0.5f), 0.2f); - - x402_24_ = x401_24_; - x401_31_ = false; - if (x450_bodyController->IsElectrocuting()) + if (x460_knockBackController.x81_26_enableShock) { - mgr.GetActorModelParticles()->StartElectric(*this); - if (x3f0_ > 0.f && x400_25_alive) + /* Shock on logical falling edge */ + if (!x401_31_nextPendingShock && x402_24_pendingShock) + Shock(0.5f + mgr.GetActiveRandom()->Range(0.f, 0.5f), 0.2f); + x402_24_pendingShock = x401_31_nextPendingShock; + x401_31_nextPendingShock = false; + + if (x450_bodyController->IsElectrocuting()) { - CDamageInfo dInfo({EWeaponType::Wave}, x3f0_, 0.f, 0.f); - mgr.ApplyDamage(kInvalidUniqueId, GetUniqueId(), kInvalidUniqueId, dInfo, - CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); + mgr.GetActorModelParticles()->StartElectric(*this); + if (x3f0_pendingShockDamage > 0.f && x400_25_alive) + { + CDamageInfo dInfo({EWeaponType::Wave}, x3f0_pendingShockDamage, 0.f, 0.f); + mgr.ApplyDamage(kInvalidUniqueId, GetUniqueId(), kInvalidUniqueId, dInfo, + CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); + } } - } - else - { - if (x3f0_!= 0.f) + else { - x450_bodyController->StopElectrocution(); - mgr.GetActorModelParticles()->StopElectric(*this); + if (x3f0_pendingShockDamage != 0.f) + { + x450_bodyController->StopElectrocution(); + mgr.GetActorModelParticles()->StopElectric(*this); + } } } @@ -294,24 +302,25 @@ void CPatterned::Think(float dt, CStateManager& mgr) if (x400_25_alive) { mgr.GetActorModelParticles()->LightDudeOnFire(*this); - CDamageInfo dInfo({EWeaponType::Wave}, x3f0_, 0.f, 0.f); + CDamageInfo dInfo({EWeaponType::Plasma}, x3ec_pendingFireDamage, 0.f, 0.f); mgr.ApplyDamage(kInvalidUniqueId, GetUniqueId(), kInvalidUniqueId, dInfo, CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); } } - else if (x3ec_ > 0.f) - x3ec_ = 0.f; - - - //if (x450_bodyController->IsFrozen()) - //mgr.GetActorModelParticles()->sub801e5044(*this); - - if (!x401_27_ || x401_28_burning) - x3e8_alphaRate = -0.33333334f; - - if (x401_30_) + else { - x401_30_ = false; + if (x3ec_pendingFireDamage > 0.f) + x3ec_pendingFireDamage = 0.f; + if (x450_bodyController->IsFrozen()) + mgr.GetActorModelParticles()->StopThermalHotParticles(*this); + } + + if (x401_27_phazingOut || x401_28_burning) + x3e8_alphaDelta = -0.33333334f; + + if (x401_30_pendingDeath) + { + x401_30_pendingDeath = false; Death(mgr, GetTransform().frontVector(), EScriptObjectState::DeathRattle); } @@ -323,28 +332,27 @@ void CPatterned::Think(float dt, CStateManager& mgr) x434_posDelta = deltas.x0_posDelta; x440_rotDelta = deltas.xc_rotDelta; - if (x403_25_ && x450_bodyController->GetPercentageFrozen() < 1.f) + if (x403_25_enableStateMachine && x450_bodyController->GetPercentageFrozen() < 1.f) x330_stateMachineState.Update(mgr, *this, thinkDt); - ThinkAboutMove(thinkDt); x460_knockBackController.Update(thinkDt, mgr, *this); - x4e4_ = GetTranslation() + PredictMotion(thinkDt).x0_translation; - x328_26_ = false; - if (x420_curDamageTime > 0.f) - x420_curDamageTime -= dt; + x4e4_latestPredictedTranslation = GetTranslation() + PredictMotion(thinkDt).x0_translation; + x328_26_longJump = false; + if (x420_curDamageRemTime > 0.f) + x420_curDamageRemTime -= dt; if (x401_28_burning && x3f4_burnThinkRateTimer > dt) x3f4_burnThinkRateTimer -= dt; - xd0_thermalMag = x50c_thermalMag; - sub8007a5b8(dt); + xd0_damageMag = x50c_baseDamageMag; + UpdateDamageColor(dt); if (!x450_bodyController->IsFrozen()) { - if (x3a0_ == zeus::CVector3f()) - x3a0_ = GetTranslation(); + if (x3a0_latestLeashPosition == zeus::CVector3f()) + x3a0_latestLeashPosition = GetTranslation(); if (x3cc_playerLeashRadius != 0.f) { @@ -356,10 +364,12 @@ void CPatterned::Think(float dt, CStateManager& mgr) } } else + { RemoveEmitter(); + } - if (x2f8_ > 0.f) - x2f8_ -= dt; + if (x2f8_waypointPauseRemTime > 0.f) + x2f8_waypointPauseRemTime -= dt; } void CPatterned::Touch(CActor& act, CStateManager& mgr) @@ -370,7 +380,7 @@ void CPatterned::Touch(CActor& act, CStateManager& mgr) if (TCastToPtr proj = act) { if (mgr.GetPlayer().GetUniqueId() == proj->GetOwnerId()) - x400_24_ = true; + x400_24_hitByPlayerProjectile = true; } } @@ -414,18 +424,67 @@ void CPatterned::DeathDelete(CStateManager& mgr) SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None); if (x450_bodyController->IsElectrocuting()) { - x3f0_ = 0.f; + x3f0_pendingShockDamage = 0.f; x450_bodyController->StopElectrocution(); mgr.GetActorModelParticles()->StopElectric(*this); } mgr.FreeScriptObject(GetUniqueId()); } +void CPatterned::Death(CStateManager& mgr, const zeus::CVector3f& dir, EScriptObjectState state) +{ + if (x400_25_alive) + { + if (!x450_bodyController->IsOnFire()) + { + x402_25_lostMassiveFrozenHP = (x3e4_lastHP - HealthInfo(mgr)->GetHP()) >= + x3dc_frozenXDamageThreshold; + if (x402_25_lostMassiveFrozenHP && x54c_iceDeathExplosionParticle && + x450_bodyController->GetPercentageFrozen() > 0.8f) + { + x400_29_pendingMassiveFrozenDeath = true; + } + else if ((x3e4_lastHP - HealthInfo(mgr)->GetHP()) >= x3d8_xDamageThreshold) + { + x400_28_pendingMassiveDeath = true; + } + } + if (x400_28_pendingMassiveDeath || x400_29_pendingMassiveFrozenDeath) + { + if (x328_30_lookAtDeathDir && x3e0_xDamageDelay <= 0.f && dir != zeus::CVector3f::skZero) + { + SetTransform(zeus::lookAt(GetTranslation(), GetTranslation() - dir) * + zeus::CTransform::RotateX(zeus::degToRad(45.f))); + } + } + else + { + x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "Dead"sv); + RemoveMaterial(EMaterialTypes::GroundCollider, mgr); + x328_25_verticalMovement = false; + } + x400_25_alive = false; + if (x450_bodyController->HasBodyState(pas::EAnimationState::Hurled) && + x450_bodyController->GetBodyType() == EBodyType::Flyer) + { + x450_bodyController->GetCommandMgr().DeliverCmd(CBCHurledCmd(-dir, zeus::CVector3f::skZero)); + } + else if (x450_bodyController->HasBodyState(pas::EAnimationState::Fall)) + { + x450_bodyController->GetCommandMgr().DeliverCmd(CBCKnockDownCmd(-dir, pas::ESeverity::One)); + } + if (state != EScriptObjectState::Any) + { + SendScriptMsgs(state, mgr, EScriptObjectMessage::None); + } + } +} + void CPatterned::KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, const CDamageInfo& info, EKnockBackType type, bool inDeferred, float magnitude) { CHealthInfo* hInfo = HealthInfo(mgr); - if (!x401_27_ && !x401_28_burning && hInfo) + if (!x401_27_phazingOut && !x401_28_burning && hInfo) { x460_knockBackController.KnockBack(backVec, mgr, *this, info, type, magnitude); if (x450_bodyController->IsFrozen() && x460_knockBackController.GetActiveParms().xc_ >= 0.f) @@ -450,10 +509,10 @@ void CPatterned::KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, c case EKnockBackAnimationFollowUp::BurnDeath: Burn(x460_knockBackController.GetActiveParms().x8_followupMagnitude, -1.f); Death(mgr, zeus::CVector3f::skZero, EScriptObjectState::DeathRattle); - x400_28_ = x400_29_ = false; - x400_27_deleteWhenDoneBurning = x401_28_burning = true; + x400_28_pendingMassiveDeath = x400_29_pendingMassiveFrozenDeath = false; + x400_27_fadeToDeath = x401_28_burning = true; x3f4_burnThinkRateTimer = 1.5f; - x402_29_ = false; + x402_29_drawParticles = false; x450_bodyController->DouseFlames(); mgr.GetActorModelParticles()->StopThermalHotParticles(*this); mgr.GetActorModelParticles()->StartBurnDeath(*this); @@ -469,14 +528,14 @@ void CPatterned::KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, c case EKnockBackAnimationFollowUp::ExplodeDeath: Death(mgr, zeus::CVector3f::skZero, EScriptObjectState::DeathRattle); if (GetDeathExplosionParticle() || x530_deathExplosionElectric) - DoDeath(mgr); + MassiveDeath(mgr); else if (x450_bodyController->IsFrozen()) x450_bodyController->FrozenBreakout(); break; case EKnockBackAnimationFollowUp::IceDeath: Death(mgr, zeus::CVector3f::skZero, EScriptObjectState::DeathRattle); if (x54c_iceDeathExplosionParticle) - DoIceDeath(mgr); + MassiveFrozenDeath(mgr); else if (x450_bodyController->IsFrozen()) x450_bodyController->FrozenBreakout(); default: @@ -485,6 +544,454 @@ void CPatterned::KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, c } } +void CPatterned::TakeDamage(const zeus::CVector3f&, float arg) +{ + x428_damageCooldownTimer = 0.33f; +} + +bool CPatterned::FixedRandom(CStateManager&, float arg) +{ + return x330_stateMachineState.GetRandom() < x330_stateMachineState.x14_; +} + +bool CPatterned::Random(CStateManager&, float arg) +{ + return x330_stateMachineState.GetRandom() < arg; +} + +bool CPatterned::CodeTrigger(CStateManager&, float arg) +{ + return x330_stateMachineState.x18_24_; +} + +bool CPatterned::FixedDelay(CStateManager&, float arg) +{ + return x330_stateMachineState.GetTime() > x330_stateMachineState.GetDelay(); +} + +bool CPatterned::RandomDelay(CStateManager&, float arg) +{ + return x330_stateMachineState.GetTime() > arg * x330_stateMachineState.GetRandom(); +} + +bool CPatterned::Delay(CStateManager&, float arg) +{ + return x330_stateMachineState.GetTime() > arg; +} + +bool CPatterned::PatrolPathOver(CStateManager&, float arg) +{ + return x2dc_destObj == kInvalidUniqueId; +} + +bool CPatterned::Stuck(CStateManager&, float arg) +{ + return x4f0_predictedLeashTime > 0.2f; +} + +bool CPatterned::AnimOver(CStateManager&, float arg) +{ + return x32c_animState == EAnimState::Over; +} + +bool CPatterned::InPosition(CStateManager&, float arg) +{ + return x328_24_inPosition; +} + +bool CPatterned::HasPatrolPath(CStateManager& mgr, float arg) +{ + return GetWaypointForState(mgr, EScriptObjectState::Patrol, + EScriptObjectMessage::Follow) != kInvalidUniqueId; +} + +bool CPatterned::Attacked(CStateManager&, float arg) +{ + return x400_24_hitByPlayerProjectile; +} + +bool CPatterned::PatternShagged(CStateManager&, float arg) +{ + return x400_30_patternShagged; +} + +bool CPatterned::PatternOver(CStateManager&, float arg) +{ + return x38c_patterns.size() <= x39c_curPattern; +} + +bool CPatterned::HasRetreatPattern(CStateManager& mgr, float arg) +{ + return GetWaypointForState(mgr, EScriptObjectState::Retreat, + EScriptObjectMessage::Follow) != kInvalidUniqueId; +} + +bool CPatterned::HasAttackPattern(CStateManager& mgr, float arg) +{ + return GetWaypointForState(mgr, EScriptObjectState::Attack, + EScriptObjectMessage::Follow) != kInvalidUniqueId; +} + +bool CPatterned::NoPathNodes(CStateManager&, float arg) +{ + if (CPathFindSearch* search = GetSearchPath()) + return search->OnPath(GetTranslation()) != CPathFindSearch::EResult::Success; + return true; +} + +static const float skActorApproachDistance = 3.f; + +bool CPatterned::PathShagged(CStateManager&, float arg) +{ + if (CPathFindSearch* search = GetSearchPath()) + { + if (search->IsShagged()) + return true; + if (search->GetCurrentWaypoint() > 0 && x401_24_pathOverCount == 0) + { + zeus::CVector3f origPoint = GetTranslation() + 0.3f * zeus::CVector3f::skUp; + zeus::CVector3f point = origPoint; + search->GetSplinePoint(point, GetTranslation()); + return (point - origPoint).magSquared() > 4.f * + skActorApproachDistance * skActorApproachDistance; + } + } + return false; +} + +bool CPatterned::PathFound(CStateManager&, float arg) +{ + if (CPathFindSearch* search = GetSearchPath()) + if (!search->IsShagged()) + return true; + return false; +} + +bool CPatterned::PathOver(CStateManager&, float arg) +{ + if (CPathFindSearch* search = GetSearchPath()) + if (x328_25_verticalMovement || x328_27_onGround) + if (!search->IsShagged() && search->IsOver()) + return true; + return false; +} + +bool CPatterned::Landed(CStateManager&, float arg) +{ + bool ret = x328_27_onGround && !x328_28_prevOnGround; + x328_28_prevOnGround = x328_27_onGround; + return ret; +} + +bool CPatterned::PlayerSpot(CStateManager& mgr, float arg) +{ + if (mgr.GetPlayer().GetMorphballTransitionState() == + CPlayer::EPlayerMorphBallState::Unmorphed) + { + zeus::CVector3f aimPosition = mgr.GetPlayer().GetAimPosition(mgr, 0.f); + zeus::CVector3f center = GetBoundingBox().center(); + zeus::CVector3f aimToCenter = center - aimPosition; + float aimToCenterMag = aimToCenter.magnitude(); + zeus::CVector3f aimToCenterNorm = aimToCenter * (1.f / aimToCenterMag); + zeus::CVector3f screenSpace = mgr.GetCameraManager()-> + GetFirstPersonCamera()->ConvertToScreenSpace(center); + if (screenSpace.z > 0.f && + screenSpace.x * screenSpace.x < 1.f && + screenSpace.y * screenSpace.y < 1.f) + { + CRayCastResult res = + mgr.RayStaticIntersection(aimPosition, aimToCenterNorm, aimToCenterMag, + CMaterialFilter::MakeInclude(EMaterialTypes::Solid)); + return res.IsInvalid(); + } + } + return false; +} + +bool CPatterned::SpotPlayer(CStateManager& mgr, float arg) +{ + zeus::CVector3f gunToPlayer = mgr.GetPlayer().GetAimPosition(mgr, 0.f) - GetGunEyePos(); + float lookDot = gunToPlayer.dot(x34_transform.basis[1]); + if (lookDot > 0.f) + return lookDot * lookDot > gunToPlayer.magSquared() * x3c4_detectionAngle; + return false; +} + +bool CPatterned::Leash(CStateManager&, float arg) +{ + bool ret = x3d4_curPlayerLeashTime > x3d0_playerLeashTime; + if (ret) + { + float posToLeashMagSq = (x3a0_latestLeashPosition - GetTranslation()).magSquared(); + if (posToLeashMagSq > x3c8_leashRadius * x3c8_leashRadius) + return true; + } + return ret; +} + +bool CPatterned::InDetectionRange(CStateManager& mgr, float arg) +{ + zeus::CVector3f delta = mgr.GetPlayer().GetTranslation() - GetTranslation(); + if (delta.magSquared() < x3bc_detectionRange * x3bc_detectionRange) + { + if (x3c0_detectionHeightRange > 0.f) + return delta.z * delta.z < x3c0_detectionHeightRange * x3c0_detectionHeightRange; + return true; + } + return false; +} + +bool CPatterned::InMaxRange(CStateManager& mgr, float arg) +{ + return (mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() < + x300_maxAttackRange * x300_maxAttackRange; +} + +bool CPatterned::TooClose(CStateManager& mgr, float arg) +{ + return (mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() < + x2fc_minAttackRange * x2fc_minAttackRange; +} + +bool CPatterned::InRange(CStateManager& mgr, float arg) +{ + float range = 0.5f * (x2fc_minAttackRange + x300_maxAttackRange); + return (mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() < range * range; +} + +bool CPatterned::OffLine(CStateManager&, float arg) +{ + zeus::CVector3f curLine = GetTranslation() - x2ec_reflectedDestPos; + zeus::CVector3f pathLine = x2e0_destPos - x2ec_reflectedDestPos; + float distSq; + if (curLine.dot(pathLine) <= 0.f) + { + distSq = curLine.magSquared(); + } + else + { + pathLine.normalize(); + distSq = (curLine - pathLine.dot(curLine) * pathLine).magSquared(); + zeus::CVector3f delta = GetTranslation() - x2e0_destPos; + if (pathLine.dot(delta) > 0.f) + distSq = delta.magSquared(); + } + return distSq > arg * arg; +} + +void CPatterned::PathFind(CStateManager& mgr, EStateMsg msg, float arg) +{ + if (CPathFindSearch* search = GetSearchPath()) + { + u32 curWp = search->GetCurrentWaypoint(); + const auto& waypoints = search->GetWaypoints(); + switch (msg) + { + case EStateMsg::Zero: + { + if (search->Search(GetTranslation(), x2e0_destPos) == CPathFindSearch::EResult::Success) + { + x2ec_reflectedDestPos = GetTranslation(); + zeus::CVector3f destPos; + if (curWp + 1 < waypoints.size()) + destPos = waypoints[curWp + 1]; + else + destPos = waypoints[curWp]; + SetDestPos(destPos); + x328_24_inPosition = false; + ApproachDest(mgr); + } + break; + } + case EStateMsg::One: + { + if (curWp < waypoints.size() - 1) + { + if (x328_24_inPosition || x328_27_onGround) + x401_24_pathOverCount += 1; + zeus::CVector3f biasedPos = GetTranslation() + 0.3f * zeus::CVector3f::skUp; + x2ec_reflectedDestPos = biasedPos - (x2e0_destPos - biasedPos); + ApproachDest(mgr); + zeus::CVector3f biasedForward = x34_transform.basis[1] * x64_modelData->GetScale().y + biasedPos; + search->GetSplinePointWithLookahead(biasedForward, biasedPos, 3.f * x64_modelData->GetScale().y); + SetDestPos(biasedForward); + if (search->SegmentOver(biasedPos)) + search->SetCurrentWaypoint(search->GetCurrentWaypoint() + 1); + } + break; + } + default: + break; + } + } +} + +void CPatterned::Dead(CStateManager& mgr, EStateMsg msg, float arg) +{ + switch (msg) + { + case EStateMsg::Zero: + x31c_faceVec = zeus::CVector3f::skZero; + break; + case EStateMsg::One: + x450_bodyController->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::Die)); + if (!x400_27_fadeToDeath) + { + if (x450_bodyController->GetBodyStateInfo().GetCurrentState()->IsDead()) + { + x400_27_fadeToDeath = true; + x3e8_alphaDelta = -0.333333f; + RemoveMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, + EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + AddMaterial(EMaterialTypes::ProjectilePassthrough, mgr); + } + } + break; + default: + break; + } +} + +void CPatterned::TargetPlayer(CStateManager& mgr, EStateMsg msg, float arg) +{ + if (msg == EStateMsg::Zero) + { + x2dc_destObj = mgr.GetPlayer().GetUniqueId(); + SetDestPos(mgr.GetPlayer().GetTranslation()); + x2ec_reflectedDestPos = GetTranslation(); + x328_24_inPosition = false; + } +} + +void CPatterned::TargetPatrol(CStateManager& mgr, EStateMsg msg, float arg) +{ + if (msg == EStateMsg::Zero) + { + x2dc_destObj = GetWaypointForState(mgr, EScriptObjectState::Patrol, EScriptObjectMessage::Follow); + if (TCastToConstPtr act = mgr.GetObjectById(x2dc_destObj)) + SetDestPos(act->GetTranslation()); + x2ec_reflectedDestPos = GetTranslation(); + x328_24_inPosition = false; + } +} + +void CPatterned::FollowPattern(CStateManager& mgr, EStateMsg msg, float arg) +{ + switch (msg) + { + case EStateMsg::Zero: + SetupPattern(mgr); + if (x328_29_noPatternShagging || !IsPatternObstructed(mgr, GetTranslation(), x2e0_destPos)) + { + ApproachDest(mgr); + } + else + { + x39c_curPattern = x38c_patterns.size(); + x400_30_patternShagged = true; + } + break; + case EStateMsg::One: + if (x328_24_inPosition) + { + x39c_curPattern += 1; + UpdatePatternDestPos(mgr); + if (!x328_29_noPatternShagging && IsPatternObstructed(mgr, GetTranslation(), x2e0_destPos)) + { + x39c_curPattern = x38c_patterns.size(); + x400_30_patternShagged = true; + } + else if (x39c_curPattern < x38c_patterns.size()) + { + x2ec_reflectedDestPos = GetTranslation(); + x328_24_inPosition = false; + x3b0_moveSpeed = x38c_patterns[x39c_curPattern].GetSpeed(); + x380_behaviour = EBehaviour(x38c_patterns[x39c_curPattern].GetBehaviour()); + x30c_behaviourOrient = EBehaviourOrient(x38c_patterns[x39c_curPattern].GetBehaviourOrient()); + x384_behaviourModifiers = EBehaviourModifiers(x38c_patterns[x39c_curPattern].GetBehaviourModifiers()); + } + } + else + { + UpdatePatternDestPos(mgr); + } + ApproachDest(mgr); + break; + case EStateMsg::Two: + x38c_patterns.clear(); + x400_30_patternShagged = false; + } +} + +void CPatterned::Patrol(CStateManager& mgr, EStateMsg msg, float arg) +{ + switch (msg) + { + case EStateMsg::Zero: + if (x3ac_lastPatrolDest == kInvalidUniqueId) + { + x2dc_destObj = GetWaypointForState(mgr, EScriptObjectState::Patrol, EScriptObjectMessage::Follow); + x30c_behaviourOrient = EBehaviourOrient::MoveDir; + x3b0_moveSpeed = 1.f; + if (x2dc_destObj != kInvalidUniqueId) + { + if (TCastToConstPtr wp = mgr.GetObjectById(x2dc_destObj)) + { + x30c_behaviourOrient = EBehaviourOrient(wp->GetBehaviourOrient()); + x3b0_moveSpeed = wp->GetSpeed(); + } + } + } + else + { + x2dc_destObj = x3ac_lastPatrolDest; + } + x2ec_reflectedDestPos = GetTranslation(); + x328_24_inPosition = false; + x2d8_patrolState = EPatrolState::Patrol; + x2f8_waypointPauseRemTime = 0.f; + break; + case EStateMsg::One: + switch (x2d8_patrolState) + { + case EPatrolState::Patrol: + if (x328_24_inPosition && x2dc_destObj != kInvalidUniqueId) + { + if (TCastToConstPtr wp = mgr.GetObjectById(x2dc_destObj)) + { + if (wp->GetPause() > 0.f) + { + x2f8_waypointPauseRemTime = wp->GetPause(); + x2d8_patrolState = EPatrolState::Pause; + } + } + } + if (x2dc_destObj == kInvalidUniqueId) + x2d8_patrolState = EPatrolState::Done; + UpdateDest(mgr); + ApproachDest(mgr); + break; + case EPatrolState::Pause: + if (x2f8_waypointPauseRemTime <= 0.f) + x2d8_patrolState = EPatrolState::Patrol; + break; + case EPatrolState::Done: + if (x2dc_destObj != kInvalidUniqueId) + x2d8_patrolState = EPatrolState::Patrol; + break; + default: + break; + } + break; + case EStateMsg::Two: + x3ac_lastPatrolDest = x2dc_destObj; + x2d8_patrolState = EPatrolState::Invalid; + break; + default: + break; + } +} + void CPatterned::BuildBodyController(EBodyType bodyType) { if (x450_bodyController) @@ -493,8 +1000,7 @@ void CPatterned::BuildBodyController(EBodyType bodyType) x450_bodyController.reset(new CBodyController(*this, x3b8_turnSpeed, bodyType)); auto anim = x450_bodyController->GetPASDatabase().FindBestAnimation(CPASAnimParmData(24, CPASAnimParm::FromEnum(0)), -1); - /* TODO: Double check this */ - x460_knockBackController.x81_26_enableShock = anim.first != 0.f; + x460_knockBackController.x81_26_enableShock = anim.first > 0.f; } void CPatterned::GenerateDeathExplosion(CStateManager& mgr) @@ -519,17 +1025,17 @@ void CPatterned::GenerateDeathExplosion(CStateManager& mgr) } } -void CPatterned::DoDeath(CStateManager& mgr) +void CPatterned::MassiveDeath(CStateManager& mgr) { CSfxManager::AddEmitter(x454_deathSfx, GetTranslation(), zeus::CVector3f::skZero, true, false, 0x7f, kInvalidAreaId); if (!x401_28_burning) { - SendScriptMsgs(EScriptObjectState::DeathExplosion, mgr, EScriptObjectMessage::None); + SendScriptMsgs(EScriptObjectState::MassiveDeath, mgr, EScriptObjectMessage::None); GenerateDeathExplosion(mgr); } DeathDelete(mgr); - x400_28_ = x400_29_ = false; + x400_28_pendingMassiveDeath = x400_29_pendingMassiveFrozenDeath = false; } void CPatterned::GenerateIceDeathExplosion(CStateManager& mgr) @@ -545,20 +1051,20 @@ void CPatterned::GenerateIceDeathExplosion(CStateManager& mgr) } } -void CPatterned::DoIceDeath(CStateManager& mgr) +void CPatterned::MassiveFrozenDeath(CStateManager& mgr) { if (x458_iceShatterSfx == 0xffff) x458_iceShatterSfx = x454_deathSfx; CSfxManager::AddEmitter(x458_iceShatterSfx, GetTranslation(), zeus::CVector3f::skZero, true, false, 0x7f, kInvalidAreaId); - SendScriptMsgs(EScriptObjectState::IceDeathExplosion, mgr, EScriptObjectMessage::None); + SendScriptMsgs(EScriptObjectState::MassiveFrozenDeath, mgr, EScriptObjectMessage::None); GenerateIceDeathExplosion(mgr); float toPlayerDist = (mgr.GetPlayer().GetTranslation() - GetTranslation()).magnitude(); if (toPlayerDist < 40.f) mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData::BuildPatternedExplodeShakeData( GetTranslation(), 0.25f, 0.3f, 40.f), true); DeathDelete(mgr); - x400_28_ = x400_29_ = false; + x400_28_pendingMassiveDeath = x400_29_pendingMassiveFrozenDeath = false; } zeus::CVector3f CPatterned::GetGunEyePos() const @@ -577,30 +1083,30 @@ void CPatterned::SetupPlayerCollision(bool v) CMaterialList* modList = (v ? &exclude : &include); modList->Add(EMaterialTypes::Player); SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude)); - } -void CPatterned::UpdateAlpha(float dt, CStateManager& mgr) +void CPatterned::UpdateAlphaDelta(float dt, CStateManager& mgr) { - if (x3e8_alphaRate == 0.f) + if (x3e8_alphaDelta == 0.f) return; - float alpha = dt * x3e8_alphaRate + x42c_color.a; + float alpha = dt * x3e8_alphaDelta + x42c_color.a; if (alpha > 1.f) { alpha = 1.f; - x3e8_alphaRate = 0.f; + x3e8_alphaDelta = 0.f; } else if (alpha < 0.f) { alpha = 0.f; - x3e8_alphaRate = 0.f; - if (x400_27_deleteWhenDoneBurning) + x3e8_alphaDelta = 0.f; + if (x400_27_fadeToDeath) DeathDelete(mgr); } x94_simpleShadow->SetUserAlpha(alpha); - x42c_color.a = alpha; - x64_modelData->AnimationData()->GetParticleDB().SetModulationColorAllActiveEffects(zeus::CColor(1.f, alpha)); + SetModelAlpha(alpha); + x64_modelData->AnimationData()->GetParticleDB(). + SetModulationColorAllActiveEffects(zeus::CColor(1.f, alpha)); } float CPatterned::CalcDyingThinkRate() @@ -609,6 +1115,386 @@ float CPatterned::CalcDyingThinkRate() return zeus::max(0.1f, f0); } +void CPatterned::UpdateDamageColor(float dt) +{ + if (x428_damageCooldownTimer > 0.f) + { + x428_damageCooldownTimer = std::max(0.f, x428_damageCooldownTimer - dt); + float alpha = x42c_color.a; + x42c_color = zeus::CColor::lerp(zeus::CColor::skBlack, x430_damageColor, + std::min(x428_damageCooldownTimer / 0.33f, 1.f)); + x42c_color.a = alpha; + if (!x450_bodyController->IsFrozen()) + xd0_damageMag = x50c_baseDamageMag + x428_damageCooldownTimer; + } +} + +TUniqueId CPatterned::GetWaypointForState(CStateManager& mgr, EScriptObjectState state, + EScriptObjectMessage msg) const +{ + rstl::reserved_vector ids; + for (const auto& conn : GetConnectionList()) + { + if (conn.x0_state == state && conn.x4_msg == msg) + { + TUniqueId id = mgr.GetIdForScript(conn.x8_objId); + if (const CEntity* ent = mgr.GetObjectById(id)) + if (ent->GetActive()) + ids.push_back(id); + } + } + + if (!ids.empty()) + return ids[mgr.GetActiveRandom()->Next() % ids.size()]; + + return kInvalidUniqueId; +} + +void CPatterned::UpdateActorKeyframe(CStateManager& mgr) const +{ + if (TCastToConstPtr wp = mgr.GetObjectById(x2dc_destObj)) + for (const auto& conn : wp->GetConnectionList()) + if (conn.x0_state == EScriptObjectState::Arrived && conn.x4_msg == EScriptObjectMessage::Action) + if (TCastToPtr kf = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) + if (kf->GetActive() && kf->IsPassive()) + kf->UpdateEntity(GetUniqueId(), mgr); +} + +pas::EStepDirection CPatterned::GetStepDirection(const zeus::CVector3f& moveVec) const +{ + zeus::CVector3f localMove = x34_transform.transposeRotate(moveVec); + float angle = zeus::CVector3f::getAngleDiff(localMove, zeus::CVector3f::skForward); + if (angle < zeus::degToRad(45.f)) + return pas::EStepDirection::Forward; + else if (angle > zeus::degToRad(135.f)) + return pas::EStepDirection::Backward; + else if (localMove.dot(zeus::CVector3f::skRight) > 0.f) + return pas::EStepDirection::Right; + else + return pas::EStepDirection::Left; +} + +bool CPatterned::IsPatternObstructed(CStateManager& mgr, + const zeus::CVector3f& p0, const zeus::CVector3f& p1) const +{ + CMaterialFilter filter = CMaterialFilter::MakeInclude(EMaterialTypes::Character); + zeus::CVector3f delta = p1 - p0; + rstl::reserved_vector nearList; + bool ret = false; + if (delta.canBeNormalized()) + { + zeus::CVector3f deltaNorm = delta.normalized(); + float deltaMag = delta.magnitude(); + mgr.BuildNearList(nearList, p0, deltaNorm, deltaMag, filter, this); + TUniqueId bestId = kInvalidUniqueId; + CRayCastResult res = + mgr.RayWorldIntersection(bestId, p0, deltaNorm, deltaMag, + CMaterialFilter::MakeInclude(EMaterialTypes::Solid), nearList); + ret = res.IsValid(); + } + return ret; +} + +void CPatterned::UpdateDest(CStateManager& mgr) +{ + if (x328_24_inPosition && x2dc_destObj != kInvalidUniqueId) + { + if (TCastToPtr wp = mgr.ObjectById(x2dc_destObj)) + { + UpdateActorKeyframe(mgr); + x2dc_destObj = wp->NextWaypoint(mgr); + if (x2dc_destObj != kInvalidUniqueId) + { + x2ec_reflectedDestPos = GetTranslation(); + x328_24_inPosition = false; + if (TCastToConstPtr wp2 = mgr.GetObjectById(x2dc_destObj)) + { + x3b0_moveSpeed = wp->GetSpeed(); + x30c_behaviourOrient = EBehaviourOrient(wp->GetBehaviourOrient()); + if (wp->GetBehaviourModifiers() & 0x2) + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCJumpCmd(wp2->GetTranslation(), pas::EJumpType::Normal)); + } + else if (wp->GetBehaviourModifiers() & 0x4) + { + TUniqueId wp3Id = wp2->NextWaypoint(mgr); + if (wp3Id != kInvalidUniqueId) + { + if (TCastToConstPtr wp3 = mgr.GetObjectById(wp3Id)) + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCJumpCmd(wp2->GetTranslation(), wp3->GetTranslation(), + pas::EJumpType::Normal)); + } + } + } + } + } + mgr.SendScriptMsg(wp.GetPtr(), GetUniqueId(), EScriptObjectMessage::Arrived); + } + } + + if (x2dc_destObj != kInvalidUniqueId) + if (TCastToConstPtr act = mgr.GetObjectById(x2dc_destObj)) + SetDestPos(act->GetTranslation()); +} + +void CPatterned::ApproachDest(CStateManager& mgr) +{ + zeus::CVector3f faceVec = mgr.GetPlayer().GetTranslation() - GetTranslation(); + zeus::CVector3f moveVec = x2e0_destPos - GetTranslation(); + if (!x328_25_verticalMovement) + moveVec.z = 0.f; + zeus::CVector3f pathLine = x2e0_destPos - x2ec_reflectedDestPos; + if (pathLine.dot(moveVec) <= 0.f) + x328_24_inPosition = true; + else if (moveVec.magSquared() < 3.f * 3.f) + moveVec = pathLine; + if (!x328_24_inPosition) + { + if (moveVec.canBeNormalized()) + moveVec.normalize(); + switch (x30c_behaviourOrient) + { + case EBehaviourOrient::MoveDir: + faceVec = moveVec; + break; + case EBehaviourOrient::Destination: + if (x39c_curPattern && x39c_curPattern < x38c_patterns.size()) + { + faceVec = x38c_patterns[x39c_curPattern].GetForward(); + } + else if (x2dc_destObj != kInvalidUniqueId) + { + if (TCastToConstPtr wp = mgr.GetObjectById(x2dc_destObj)) + faceVec = wp->GetTransform().basis[1]; + } + break; + default: + break; + } + x31c_faceVec = faceVec; + x310_moveVec = x3b0_moveSpeed * moveVec; + pas::EStepDirection stepDir; + if (!KnockbackWhenFrozen()) + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCLocomotionCmd(x310_moveVec, x31c_faceVec, 1.f)); + } + else if (x30c_behaviourOrient == EBehaviourOrient::MoveDir || + !x450_bodyController->HasBodyState(pas::EAnimationState::Step)) + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCLocomotionCmd(x310_moveVec, zeus::CVector3f::skZero, 1.f)); + } + else if ((stepDir = GetStepDirection(x310_moveVec)) != pas::EStepDirection::Forward) + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCStepCmd(stepDir, pas::EStepType::Normal)); + } + else + { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCLocomotionCmd(x310_moveVec, zeus::CVector3f::skZero, 1.f)); + } + x450_bodyController->GetCommandMgr().DeliverTargetVector(x31c_faceVec); + } + else if (x450_bodyController->GetBodyStateInfo().GetMaxSpeed() > FLT_EPSILON) + { + x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd( + (x138_velocity.magnitude() / x450_bodyController->GetBodyStateInfo().GetMaxSpeed()) * + x34_transform.basis[1], zeus::CVector3f::skZero, 1.f)); + } +} + +std::pair CPatterned::GetDestWaypoints(CStateManager& mgr) const +{ + std::pair ret {}; + if (TCastToPtr wp = mgr.ObjectById(x2dc_destObj)) + { + ret.first = wp.GetPtr(); + ret.second = TCastToPtr(mgr.ObjectById(wp->FollowWaypoint(mgr))).GetPtr(); + } + return ret; +} + +zeus::CQuaternion CPatterned::FindPatternRotation(const zeus::CVector3f& dir) const +{ + zeus::CVector3f wpDeltaFlat = x368_destWPDelta; + wpDeltaFlat.z = 0.f; + wpDeltaFlat.normalize(); + zeus::CVector3f dirFlat = dir; + dirFlat.z = 0.f; + dirFlat.normalize(); + + zeus::CQuaternion q; + if ((wpDeltaFlat - dirFlat).magSquared() > 3.99f) + q.rotateZ(zeus::degToRad(180.f)); + else + q = zeus::CQuaternion::shortestRotationArc(wpDeltaFlat, dirFlat); + + if (x328_25_verticalMovement) + { + q = zeus::CQuaternion::shortestRotationArc( + (q * zeus::CQuaternion(0.f, x368_destWPDelta) * q.inverse()).getImaginary().normalized(), + dir.normalized()) * q; + } + + return q; +} + +zeus::CVector3f CPatterned::FindPatternDir(CStateManager& mgr) const +{ + zeus::CVector3f ret; + switch (x378_patternOrient) + { + case EPatternOrient::StartToPlayerStart: + ret = x35c_patternStartPlayerPos - x350_patternStartPos; + break; + case EPatternOrient::StartToPlayer: + ret = mgr.GetPlayer().GetTranslation() - x350_patternStartPos; + break; + case EPatternOrient::ReversePlayerForward: + ret = -mgr.GetPlayer().GetTransform().basis[1]; + break; + case EPatternOrient::Forward: + ret = GetTransform().basis[1]; + break; + default: + break; + } + return ret; +} + +void CPatterned::UpdatePatternDestPos(CStateManager& mgr) +{ + if (x39c_curPattern < x38c_patterns.size()) + { + if (x368_destWPDelta != zeus::CVector3f::skZero) + { + zeus::CVector3f patternDir = FindPatternDir(mgr); + SetDestPos(FindPatternRotation(patternDir).transform(x38c_patterns[x39c_curPattern].GetPos())); + if (x37c_patternFit == EPatternFit::Zero) + { + float magSq; + if (x328_25_verticalMovement) + magSq = patternDir.magSquared() / x368_destWPDelta.magSquared(); + else + magSq = patternDir.toVec2f().magSquared() / x368_destWPDelta.toVec2f().magSquared(); + SetDestPos(std::sqrt(magSq) * x2e0_destPos); + } + } + else + { + SetDestPos(x38c_patterns[x39c_curPattern].GetPos()); + } + } + + switch (x374_patternTranslate) + { + case EPatternTranslate::RelativeStart: + SetDestPos(x2e0_destPos + x350_patternStartPos); + break; + case EPatternTranslate::RelativePlayerStart: + SetDestPos(x2e0_destPos + x35c_patternStartPlayerPos); + break; + case EPatternTranslate::RelativePlayer: + SetDestPos(x2e0_destPos + mgr.GetPlayer().GetTranslation()); + break; + default: + break; + } +} + +void CPatterned::SetupPattern(CStateManager& mgr) +{ + EScriptObjectState state = GetDesiredAttackState(mgr); + x2dc_destObj = GetWaypointForState(mgr, state, EScriptObjectMessage::Follow); + if (x2dc_destObj == kInvalidUniqueId && state != EScriptObjectState::Attack) + x2dc_destObj = GetWaypointForState(mgr, EScriptObjectState::Attack, EScriptObjectMessage::Follow); + x38c_patterns.clear(); + if (x2dc_destObj != kInvalidUniqueId) + { + x350_patternStartPos = GetTranslation(); + x35c_patternStartPlayerPos = mgr.GetPlayer().GetTranslation(); + auto destWPs = GetDestWaypoints(mgr); + if (destWPs.first) + { + x374_patternTranslate = EPatternTranslate(destWPs.first->GetPatternTranslate()); + x378_patternOrient = EPatternOrient(destWPs.first->GetPatternOrient()); + x37c_patternFit = EPatternFit(destWPs.first->GetPatternFit()); + if (destWPs.second) + x368_destWPDelta = destWPs.second->GetTranslation() - destWPs.first->GetTranslation(); + else + x368_destWPDelta = zeus::CVector3f::skZero; + + int numPatterns = 0; + CScriptWaypoint* curWp = destWPs.first; + do + { + ++numPatterns; + curWp = TCastToPtr(mgr.ObjectById(curWp->NextWaypoint(mgr))).GetPtr(); + if (!curWp) + break; + } while (curWp->GetUniqueId() != destWPs.first->GetUniqueId()); + x38c_patterns.reserve(numPatterns); + + zeus::CVector3f basePos; + switch (x374_patternTranslate) + { + case EPatternTranslate::RelativePlayerStart: + if (destWPs.second) + basePos = destWPs.second->GetTranslation(); + break; + case EPatternTranslate::Absolute: + break; + default: + basePos = destWPs.first->GetTranslation(); + break; + } + + curWp = destWPs.first; + do + { + zeus::CVector3f wpForward = curWp->GetTransform().basis[1]; + if (x368_destWPDelta != zeus::CVector3f::skZero) + wpForward = FindPatternRotation(FindPatternDir(mgr)).transform(wpForward); + x38c_patterns.emplace_back(curWp->GetTranslation() - basePos, wpForward, + curWp->GetSpeed(), curWp->GetBehaviour(), + curWp->GetBehaviourOrient(), curWp->GetBehaviourModifiers(), + curWp->GetAnimation()); + curWp = TCastToPtr(mgr.ObjectById(curWp->NextWaypoint(mgr))).GetPtr(); + if (!curWp) + break; + } while (curWp->GetUniqueId() != destWPs.first->GetUniqueId()); + } + } + + x400_30_patternShagged = false; + x39c_curPattern = 0; + x328_24_inPosition = false; + x2ec_reflectedDestPos = GetTranslation(); + if (!x38c_patterns.empty()) + { + x3b0_moveSpeed = x38c_patterns.front().GetSpeed(); + x380_behaviour = EBehaviour(x38c_patterns.front().GetBehaviour()); + x30c_behaviourOrient = EBehaviourOrient(x38c_patterns.front().GetBehaviourOrient()); + x384_behaviourModifiers = EBehaviourModifiers(x38c_patterns.front().GetBehaviourModifiers()); + } +} + +EScriptObjectState CPatterned::GetDesiredAttackState(CStateManager& mgr) const +{ + float deltaMagSq = (GetTranslation() - mgr.GetPlayer().GetTranslation()).magSquared(); + if (deltaMagSq < x2fc_minAttackRange * x2fc_minAttackRange) + return EScriptObjectState::Retreat; + else if (deltaMagSq > x300_maxAttackRange * x300_maxAttackRange) + return EScriptObjectState::CloseIn; + else + return EScriptObjectState::Attack; +} + void CPatterned::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) @@ -621,13 +1507,13 @@ void CPatterned::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) zeus::CColor col = x42c_color; u8 alpha = GetModelAlphau8(mgr); - if (x402_27_ && mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) + if (x402_27_noXrayModel && mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) alpha = 76; if (alpha < 255) { if (col.r == 0.f && col.g == 0.f && col.b == 0.f) - col = zeus::CColor::skWhite; + col = zeus::CColor::skWhite; /* Not being damaged */ if (x401_29_laggedBurnDeath) { @@ -651,6 +1537,7 @@ void CPatterned::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { if (col.r != 0.f || col.g != 0.f || col.b != 0.f) { + /* Being damaged */ zeus::CColor col2 = col; col2.a = alpha / 255.f; xb4_drawFlags = CModelFlags(2, 0, 3, col2); @@ -677,7 +1564,7 @@ void CPatterned::Render(const CStateManager& mgr) const { int mask = 0; int target = 0; - if (x402_29_) + if (x402_29_drawParticles) { mgr.GetCharacterRenderMaskAndTarget(x402_31_thawed, mask, target); x64_modelData->GetAnimationData()->GetParticleDB().RenderSystemsToBeDrawnFirstMasked(mask, target); @@ -728,7 +1615,7 @@ void CPatterned::Render(const CStateManager& mgr) const } } - if (x402_29_) + if (x402_29_drawParticles) { x64_modelData->GetAnimationData()->GetParticleDB().RenderSystemsToBeDrawnLastMasked(mask, target); } @@ -737,66 +1624,62 @@ void CPatterned::Render(const CStateManager& mgr) const void CPatterned::ThinkAboutMove(float dt) { bool doMove = true; - if (!x328_25_ && ! x328_27_onGround) + if (!x328_25_verticalMovement && !x328_27_onGround) { - x310_.zeroOut(); + x310_moveVec.zeroOut(); doMove = false; } - if (doMove && x39c_ < x390_) + if (doMove && x39c_curPattern < x38c_patterns.size()) { zeus::CVector3f frontVec = GetTransform().frontVector(); - zeus::CVector3f x31cCpy = x31c_; - if (x31c_.magSquared() > 0.1f) + zeus::CVector3f x31cCpy = x31c_faceVec; + if (x31c_faceVec.magSquared() > 0.1f) x31cCpy.normalize(); float mag = frontVec.dot(x31cCpy); - switch (x3f8_) + switch (x3f8_moveState) { - case 0: - if (!x328_26_) + case EMoveState::Zero: + if (!x328_26_longJump) break; - case 1: - { + case EMoveState::One: doMove = false; - if (mag > 0.85) + if (mag > 0.85f) { doMove = true; - x3f8_ = 2; + x3f8_moveState = EMoveState::Two; break; } - x3f8_ = 1; - } - case 2: - x3f8_ = 3; - case 3: - { - doMove = true; - if (!x328_26_) - { - x3f8_ = 0; - break; - } - if (mag > 0.89) - x3f8_ = 4; + x3f8_moveState = EMoveState::One; break; - } - case 4: - { - x328_24_ = true; + case EMoveState::Two: + x3f8_moveState = EMoveState::Three; + case EMoveState::Three: + doMove = true; + if (!x328_26_longJump) + { + x3f8_moveState = EMoveState::Zero; + break; + } + if (mag > 0.9f) + x3f8_moveState = EMoveState::Four; + break; + case EMoveState::Four: + x328_24_inPosition = true; doMove = false; - x3f8_ = 0; - } + x3f8_moveState = EMoveState::Zero; + break; default: break; } } - if (!x401_26_ && doMove) + if (!x401_26_disableMove && doMove) { const CBodyState* state = x450_bodyController->GetBodyStateInfo().GetCurrentState(); if (state->ApplyAnimationDeltas() && !zeus::close_enough(x2e0_destPos - GetTranslation(), {})) - MoveToOR((x64_modelData->GetScale() * x434_posDelta) * x55c_, dt); + MoveToOR((x64_modelData->GetScale() * x434_posDelta) * x55c_moveScale, dt); } RotateToOR(x440_rotDelta, dt); diff --git a/Runtime/World/CPatterned.hpp b/Runtime/World/CPatterned.hpp index d5ef89948..594f03017 100644 --- a/Runtime/World/CPatterned.hpp +++ b/Runtime/World/CPatterned.hpp @@ -18,6 +18,7 @@ namespace urde { class CPatternedInfo; class CProjectileInfo; +class CPathFindSearch; class CPatterned : public CAi { @@ -80,52 +81,129 @@ public: Zero = 0, One = 1 }; + enum class EPatternTranslate + { + RelativeStart, + RelativePlayerStart, + RelativePlayer, + Absolute + }; + enum class EPatternOrient + { + StartToPlayer, + StartToPlayerStart, + ReversePlayerForward, + Forward + }; + enum class EPatternFit + { + Zero, + One + }; + enum class EMoveState + { + Zero, + One, + Two, + Three, + Four + }; + enum class EBehaviour + { + Zero + }; + enum class EBehaviourOrient + { + MoveDir, + Constant, + Destination + }; + enum class EBehaviourModifiers + { + Zero + }; + enum class EPatrolState + { + Invalid = -1, + Patrol, + Pause, + Done + }; + enum class EAnimState + { + Zero, + One, + Two, + Over + }; + class CPatternNode + { + zeus::CVector3f x0_pos; + zeus::CVector3f xc_forward; + float x18_speed; + u8 x1c_behaviour; + u8 x1d_behaviourOrient; + u16 x1e_behaviourModifiers; + u32 x20_animation; + public: + CPatternNode(const zeus::CVector3f& pos, const zeus::CVector3f& forward, float speed, + u8 behaviour, u8 behaviourOrient, u16 behaviourModifiers, u32 animation) + : x0_pos(pos), xc_forward(forward), x18_speed(speed), x1c_behaviour(behaviour), + x1d_behaviourOrient(behaviourOrient), x1e_behaviourModifiers(behaviourModifiers), + x20_animation(animation) {} + const zeus::CVector3f& GetPos() const { return x0_pos; } + const zeus::CVector3f& GetForward() const { return xc_forward; } + float GetSpeed() const { return x18_speed; } + u8 GetBehaviour() const { return x1c_behaviour; } + u8 GetBehaviourOrient() const { return x1d_behaviourOrient; } + u16 GetBehaviourModifiers() const { return x1e_behaviourModifiers; } + }; protected: - u32 x2d8_ = -1; - TUniqueId x2dc_ = kInvalidUniqueId; + EPatrolState x2d8_patrolState = EPatrolState::Invalid; + TUniqueId x2dc_destObj = kInvalidUniqueId; zeus::CVector3f x2e0_destPos; - zeus::CVector3f x2ec_; - float x2f8_ = 0.f; + zeus::CVector3f x2ec_reflectedDestPos; + float x2f8_waypointPauseRemTime = 0.f; float x2fc_minAttackRange; float x300_maxAttackRange; float x304_averageAttackTime; float x308_attackTimeVariation; - u32 x30c_ = 0; - zeus::CVector3f x310_; - zeus::CVector3f x31c_; + EBehaviourOrient x30c_behaviourOrient = EBehaviourOrient::MoveDir; + zeus::CVector3f x310_moveVec; + zeus::CVector3f x31c_faceVec; union { struct { - bool x328_24_ : 1; - bool x328_25_ : 1; - bool x328_26_ : 1; + bool x328_24_inPosition : 1; + bool x328_25_verticalMovement : 1; + bool x328_26_longJump : 1; bool x328_27_onGround : 1; + bool x328_28_prevOnGround : 1; + bool x328_29_noPatternShagging : 1; + bool x328_30_lookAtDeathDir : 1; }; u32 _dummy = 0; }; - u32 x32c_; + EAnimState x32c_animState = EAnimState::Zero; CStateMachineState x330_stateMachineState; ECharacter x34c_character; - zeus::CVector3f x350_; - zeus::CVector3f x35c_; - zeus::CVector3f x368_; - u32 x374_ = 0; - u32 x378_ = 2; - u32 x37c_ = 1; - u32 x380_ = 0; - u32 x384_ = 0; + zeus::CVector3f x350_patternStartPos; + zeus::CVector3f x35c_patternStartPlayerPos; + zeus::CVector3f x368_destWPDelta; + EPatternTranslate x374_patternTranslate = EPatternTranslate::RelativeStart; + EPatternOrient x378_patternOrient = EPatternOrient::ReversePlayerForward; + EPatternFit x37c_patternFit = EPatternFit::One; + EBehaviour x380_behaviour = EBehaviour::Zero; + EBehaviourModifiers x384_behaviourModifiers = EBehaviourModifiers::Zero; s32 x388_anim; - /*x38c_*/ - u32 x390_ = 0; - u32 x394_ = 0; - u32 x398_ = 0; - u32 x39c_ = 0; - zeus::CVector3f x3a0_; - TUniqueId x3ac_ = kInvalidUniqueId; - float x3b0_ = 1.f; + std::vector x38c_patterns; + u32 x39c_curPattern = 0; + zeus::CVector3f x3a0_latestLeashPosition; + TUniqueId x3ac_lastPatrolDest = kInvalidUniqueId; + float x3b0_moveSpeed = 1.f; float x3b4_speed; float x3b8_turnSpeed; float x3bc_detectionRange; @@ -135,128 +213,173 @@ protected: float x3cc_playerLeashRadius; float x3d0_playerLeashTime; float x3d4_curPlayerLeashTime = 0.f; - float x3d8_; - float x3dc_; - float x3e0_; - float x3e4_ = 0.f; - float x3e8_alphaRate = 0.f; - float x3ec_ = 0.f; - float x3f0_ = 0.f; + float x3d8_xDamageThreshold; + float x3dc_frozenXDamageThreshold; + float x3e0_xDamageDelay; + float x3e4_lastHP = 0.f; + float x3e8_alphaDelta = 0.f; + float x3ec_pendingFireDamage = 0.f; + float x3f0_pendingShockDamage = 0.f; float x3f4_burnThinkRateTimer = 0.f; - u32 x3f8_ = 0; + EMoveState x3f8_moveState = EMoveState::Zero; EFlavorType x3fc_flavor; union { struct { - bool x400_24_ : 1; + bool x400_24_hitByPlayerProjectile : 1; bool x400_25_alive : 1; // t bool x400_26_ : 1; - bool x400_27_deleteWhenDoneBurning : 1; - bool x400_28_ : 1; - bool x400_29_ : 1; - bool x400_30_ : 1; - bool x400_31_ : 1; // r25 == 1 - bool x401_24_ : 1; - bool x401_25_ : 1; - bool x401_26_ : 1; - bool x401_27_ : 1; + bool x400_27_fadeToDeath : 1; + bool x400_28_pendingMassiveDeath : 1; + bool x400_29_pendingMassiveFrozenDeath : 1; + bool x400_30_patternShagged : 1; + bool x400_31_isFlyer : 1; + bool x401_24_pathOverCount : 2; + bool x401_26_disableMove : 1; + bool x401_27_phazingOut : 1; bool x401_28_burning : 1; bool x401_29_laggedBurnDeath : 1; - bool x401_30_ : 1; - bool x401_31_ : 1; - bool x402_24_ : 1; - bool x402_25_ : 1; - bool x402_26_ : 1; - bool x402_27_ : 1; - bool x402_28_ : 1; - bool x402_29_ : 1; // t - bool x402_30_ : 1; + bool x401_30_pendingDeath : 1; + bool x401_31_nextPendingShock : 1; + bool x402_24_pendingShock : 1; + bool x402_25_lostMassiveFrozenHP : 1; + bool x402_26_dieIf80PercFrozen : 1; + bool x402_27_noXrayModel : 1; + bool x402_28_isMakingBigStrike : 1; + bool x402_29_drawParticles : 1; // t + bool x402_30_updateThermalFrozenState : 1; bool x402_31_thawed : 1; bool x403_24_keepThermalVisorState : 1; - bool x403_25_ : 1; // t - bool x403_26_ : 1; // t + bool x403_25_enableStateMachine : 1; // t + bool x403_26_stateControlledMassiveDeath : 1; // t }; u32 _dummy2 = 0; }; CDamageInfo x404_contactDamage; - float x420_curDamageTime = 0.f; + float x420_curDamageRemTime = 0.f; float x424_damageWaitTime; - float x428_ = -1.f; + float x428_damageCooldownTimer = -1.f; zeus::CColor x42c_color = zeus::CColor::skBlack; - zeus::CColor x430_ = skDamageColor; + zeus::CColor x430_damageColor = skDamageColor; zeus::CVector3f x434_posDelta; zeus::CQuaternion x440_rotDelta; - CSteeringBehaviors x45c_; + CSteeringBehaviors x45c_steeringBehaviors; std::unique_ptr x450_bodyController; u16 x454_deathSfx; u16 x458_iceShatterSfx; CKnockBackController x460_knockBackController; - zeus::CVector3f x4e4_; - float x4f0_ = 0.f; - float x4f4_; - float x4f8_; + zeus::CVector3f x4e4_latestPredictedTranslation; + float x4f0_predictedLeashTime = 0.f; + float x4f4_intoFreezeDur; + float x4f8_outofFreezeDur; float x4fc_; - float x500_ = 0.f; + float x500_preThinkDt = 0.f; float x504_damageDur = 0.f; EColliderType x508_colliderType; - float x50c_thermalMag; + float x50c_baseDamageMag; std::shared_ptr x510_vertexMorph; zeus::CVector3f x514_deathExplosionOffset; std::experimental::optional> x520_deathExplosionParticle; std::experimental::optional> x530_deathExplosionElectric; zeus::CVector3f x540_iceDeathExplosionOffset; std::experimental::optional> x54c_iceDeathExplosionParticle; - zeus::CVector3f x55c_; - void UpdateFrozenState(bool thawed); + zeus::CVector3f x55c_moveScale = zeus::CVector3f::skOne; + + void UpdateThermalFrozenState(bool thawed); void GenerateIceDeathExplosion(CStateManager& mgr); void GenerateDeathExplosion(CStateManager& mgr); void RenderIceModelWithFlags(const CModelFlags& flags) const; + TUniqueId GetWaypointForState(CStateManager& mgr, EScriptObjectState state, EScriptObjectMessage msg) const; + void UpdateActorKeyframe(CStateManager& mgr) const; + pas::EStepDirection GetStepDirection(const zeus::CVector3f& moveVec) const; + bool IsPatternObstructed(CStateManager& mgr, const zeus::CVector3f& p0, const zeus::CVector3f& p1) const; + void UpdateDest(CStateManager& mgr); + void ApproachDest(CStateManager& mgr); + std::pair GetDestWaypoints(CStateManager& mgr) const; + zeus::CQuaternion FindPatternRotation(const zeus::CVector3f& dir) const; + zeus::CVector3f FindPatternDir(CStateManager& mgr) const; + void UpdatePatternDestPos(CStateManager& mgr); + void SetupPattern(CStateManager& mgr); + EScriptObjectState GetDesiredAttackState(CStateManager& mgr) const; public: - CPatterned(ECharacter character, TUniqueId uid, std::string_view name, EFlavorType flavor, const CEntityInfo& info, - const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pinfo, - CPatterned::EMovementType movement, EColliderType collider, EBodyType body, - const CActorParameters& params, EKnockBackVariant kbVariant); + CPatterned(ECharacter character, TUniqueId uid, std::string_view name, EFlavorType flavor, + const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, + const CPatternedInfo& pinfo, CPatterned::EMovementType movement, + EColliderType collider, EBodyType body, const CActorParameters& params, + EKnockBackVariant kbVariant); void Accept(IVisitor&); void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); - void PreThink(float, CStateManager& mgr) { CEntity::Think(x500_, mgr); } + void PreThink(float, CStateManager& mgr) { CEntity::Think(x500_preThinkDt, mgr); } void Think(float, CStateManager&); void PreRender(CStateManager&, const zeus::CFrustum&); void Render(const CStateManager& mgr) const; - void Touch(CActor&, CStateManager&); + void Touch(CActor& act, CStateManager& mgr); std::experimental::optional GetTouchBounds() const; bool CanRenderUnsorted(const CStateManager& mgr) const; zeus::CVector3f GetOrbitPosition(const CStateManager& mgr) const { return GetAimPosition(mgr, 0.f); } - zeus::CVector3f GetAimPosition(const CStateManager& mgr, float) const; void DeathDelete(CStateManager& mgr); - void Death(CStateManager& mgr, const zeus::CVector3f&, EScriptObjectState) {} + void Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state); void KnockBack(const zeus::CVector3f&, CStateManager&, const CDamageInfo& info, EKnockBackType type, bool inDeferred, float magnitude); - void TakeDamage(const zeus::CVector3f&, float) { x428_ = 0.33f;} - bool FixedRandom(CStateManager&, float) { return x330_stateMachineState.GetRandom() < x330_stateMachineState.x14_; } - bool Random(CStateManager&, float dt) { return x330_stateMachineState.GetRandom() < dt; } - //bool FixedDelay(CStateManager&, float dt) { return x330_stateMachineState.GetDelay() == dt; } + void TakeDamage(const zeus::CVector3f&, float arg); + bool FixedRandom(CStateManager&, float arg); + bool Random(CStateManager&, float arg); + bool CodeTrigger(CStateManager&, float arg); + bool FixedDelay(CStateManager&, float arg); + bool RandomDelay(CStateManager&, float arg); + bool Delay(CStateManager&, float arg); + bool PatrolPathOver(CStateManager&, float arg); + bool Stuck(CStateManager&, float arg); + bool AnimOver(CStateManager&, float arg); + bool InPosition(CStateManager&, float arg); + bool HasPatrolPath(CStateManager& mgr, float arg); + bool Attacked(CStateManager&, float arg); + bool PatternShagged(CStateManager&, float arg); + bool PatternOver(CStateManager&, float arg); + bool HasRetreatPattern(CStateManager& mgr, float arg); + bool HasAttackPattern(CStateManager& mgr, float arg); + bool NoPathNodes(CStateManager&, float arg); + bool PathShagged(CStateManager&, float arg); + bool PathFound(CStateManager&, float arg); + bool PathOver(CStateManager&, float arg); + bool Landed(CStateManager&, float arg); + bool PlayerSpot(CStateManager&, float arg); + bool SpotPlayer(CStateManager&, float arg); + bool Leash(CStateManager&, float arg); + bool InDetectionRange(CStateManager&, float arg); + bool InMaxRange(CStateManager&, float arg); + bool TooClose(CStateManager&, float arg); + bool InRange(CStateManager&, float arg); + bool OffLine(CStateManager&, float arg); + bool Default(CStateManager&, float arg) { return true; } + void PathFind(CStateManager&, EStateMsg msg, float arg); + void Dead(CStateManager&, EStateMsg msg, float arg); + void TargetPlayer(CStateManager&, EStateMsg msg, float arg); + void TargetPatrol(CStateManager&, EStateMsg msg, float arg); + void FollowPattern(CStateManager&, EStateMsg msg, float arg); + void Patrol(CStateManager&, EStateMsg msg, float arg); + void Start(CStateManager&, EStateMsg msg, float arg) {} - bool Default() { return true; } - virtual bool KnockbackWhenFrozen() const { return true;} - virtual void DoDeath(CStateManager&); - virtual void DoIceDeath(CStateManager&); + virtual bool KnockbackWhenFrozen() const { return true; } + virtual void MassiveDeath(CStateManager& mgr); + virtual void MassiveFrozenDeath(CStateManager& mgr); virtual void Burn(float, float) {} virtual void Shock(float, float) {} virtual void Freeze(CStateManager& mgr, const zeus::CVector3f& pos, const zeus::CUnitVector3f& dir, float magnitude) {} virtual void ThinkAboutMove(float); - virtual void GetSearchPath() {} + virtual CPathFindSearch* GetSearchPath() { return nullptr; } virtual CDamageInfo GetContactDamage() const { return x404_contactDamage; } virtual u8 GetModelAlphau8(const CStateManager&) const { return u8(x42c_color.a * 255);} virtual bool IsOnGround() const { return x328_27_onGround; } @@ -277,12 +400,13 @@ public: void SetDestPos(const zeus::CVector3f& pos) { x2e0_destPos = pos; } - void UpdateAlpha(float dt, CStateManager& mgr); + void UpdateAlphaDelta(float dt, CStateManager& mgr); + void SetModelAlpha(float a) { x42c_color.a = a; } float CalcDyingThinkRate(); - void sub8007a5b8(float) {} + void UpdateDamageColor(float dt); - bool GetX328_26() const { return x328_26_; } - bool GetX402_28() const { return x402_28_; } + bool CanLongJump() const { return x328_26_longJump; } + bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; } //region Casting Functions diff --git a/Runtime/World/CPatternedInfo.cpp b/Runtime/World/CPatternedInfo.cpp index e946f67af..8ca5cb01b 100644 --- a/Runtime/World/CPatternedInfo.cpp +++ b/Runtime/World/CPatternedInfo.cpp @@ -27,14 +27,14 @@ CPatternedInfo::CPatternedInfo(CInputStream& in, u32 pcount) , xcc_bodyOrigin(zeus::CVector3f::ReadBig(in)) , xd8_stepUpHeight(in.readFloatBig()) , xdc_xDamage(in.readFloatBig()) -, xe0_(in.readFloatBig()) -, xe4_(in.readFloatBig()) +, xe0_frozenXDamage(in.readFloatBig()) +, xe4_xDamageDelay(in.readFloatBig()) , xe8_deathSfx(CSfxManager::TranslateSFXID(in.readUint32Big())) , xec_animParams(in) , xf8_active(in.readBool()) , xfc_stateMachineId(in.readUint32Big()) -, x100_(in.readFloatBig()) -, x104_(in.readFloatBig()) +, x100_intoFreezeDur(in.readFloatBig()) +, x104_outofFreezeDur(in.readFloatBig()) , x108_(in.readFloatBig()) , x10c_particle1Frames(in.readUint32Big()) , x110_particle1Scale(zeus::CVector3f::ReadBig(in)) diff --git a/Runtime/World/CPatternedInfo.hpp b/Runtime/World/CPatternedInfo.hpp index 01c7c225c..a101d988b 100644 --- a/Runtime/World/CPatternedInfo.hpp +++ b/Runtime/World/CPatternedInfo.hpp @@ -35,14 +35,14 @@ class CPatternedInfo zeus::CVector3f xcc_bodyOrigin; float xd8_stepUpHeight; float xdc_xDamage; - float xe0_; - float xe4_; + float xe0_frozenXDamage; + float xe4_xDamageDelay; u16 xe8_deathSfx; CAnimationParameters xec_animParams; bool xf8_active; CAssetId xfc_stateMachineId; - float x100_; - float x104_; + float x100_intoFreezeDur; + float x104_outofFreezeDur; float x108_; u32 x10c_particle1Frames; diff --git a/Runtime/World/CScriptActorKeyframe.cpp b/Runtime/World/CScriptActorKeyframe.cpp index 9c5843dcc..64a8d17d4 100644 --- a/Runtime/World/CScriptActorKeyframe.cpp +++ b/Runtime/World/CScriptActorKeyframe.cpp @@ -8,7 +8,7 @@ namespace urde { CScriptActorKeyframe::CScriptActorKeyframe(TUniqueId uid, std::string_view name, const CEntityInfo& info, s32 animId, - bool looping, float lifetime, bool disableUpdate, u32 fadeOut, bool active, + bool looping, float lifetime, bool isPassive, u32 fadeOut, bool active, float totalPlayback) : CEntity(uid, info, active, name) , x34_animationId(animId) @@ -17,7 +17,7 @@ CScriptActorKeyframe::CScriptActorKeyframe(TUniqueId uid, std::string_view name, , x40_lifetime(lifetime) { x44_24_looping = looping; - x44_25_disableUpdate = disableUpdate; + x44_25_isPassive = isPassive; x44_26_fadeOut = fadeOut; x44_27_timedLoop = fadeOut; x44_28_playing = false; @@ -35,7 +35,7 @@ void CScriptActorKeyframe::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId u { if (GetActive()) { - if (!x44_25_disableUpdate) + if (!x44_25_isPassive) { for (const SConnection& conn : x20_conns) { @@ -63,7 +63,7 @@ void CScriptActorKeyframe::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId u void CScriptActorKeyframe::Think(float dt, CStateManager& mgr) { - if (x44_25_disableUpdate || !x44_24_looping || !x44_27_timedLoop || !x44_28_playing || x40_lifetime <= 0.f) + if (x44_25_isPassive || !x44_24_looping || !x44_27_timedLoop || !x44_28_playing || x40_lifetime <= 0.f) { CEntity::Think(dt, mgr); return; diff --git a/Runtime/World/CScriptActorKeyframe.hpp b/Runtime/World/CScriptActorKeyframe.hpp index c76f416ac..62ea97d7d 100644 --- a/Runtime/World/CScriptActorKeyframe.hpp +++ b/Runtime/World/CScriptActorKeyframe.hpp @@ -15,7 +15,7 @@ private: struct { bool x44_24_looping : 1; - bool x44_25_disableUpdate : 1; + bool x44_25_isPassive : 1; bool x44_26_fadeOut : 1; bool x44_27_timedLoop : 1; bool x44_28_playing : 1; @@ -26,13 +26,14 @@ private: public: CScriptActorKeyframe(TUniqueId uid, std::string_view name, const CEntityInfo& info, s32 animId, - bool looping, float lifetime, bool disableUpdate, u32 fadeOut, bool active, + bool looping, float lifetime, bool isPassive, u32 fadeOut, bool active, float totalPlayback); void Accept(IVisitor& visitor); void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr); void Think(float, CStateManager&); void UpdateEntity(TUniqueId, CStateManager&); + bool IsPassive() const { return x44_25_isPassive; } }; } diff --git a/Runtime/World/CScriptWaypoint.cpp b/Runtime/World/CScriptWaypoint.cpp index 958c5feba..18d9ec0c4 100644 --- a/Runtime/World/CScriptWaypoint.cpp +++ b/Runtime/World/CScriptWaypoint.cpp @@ -7,11 +7,15 @@ namespace urde { CScriptWaypoint::CScriptWaypoint(TUniqueId uid, std::string_view name, const CEntityInfo& info, - const zeus::CTransform& xf, bool active, float f1, float f2, - u32 w1, u32 w2, u32 w3, u32 w4, u32 w5, u32 w6, u32 w7) + const zeus::CTransform& xf, bool active, float speed, float pause, + u32 patternTranslate, u32 patternOrient, u32 patternFit, u32 behaviour, + u32 behaviourOrient, u32 behaviourModifiers, u32 animation) : CActor(uid, active, name, info, xf, CModelData(), CMaterialList(), CActorParameters::None(), kInvalidUniqueId), - xe8_speed(f1), xec_(w7), xf0_(f2), xf4_(w1), xf5_(w2), xf6_(w3), xf7_(w4), xf8_(w5), xfa_jumpFlags(w6) + xe8_speed(speed), xec_animation(animation), xf0_pause(pause), + xf4_patternTranslate(patternTranslate), xf5_patternOrient(patternOrient), + xf6_patternFit(patternFit), xf7_behaviour(behaviour), + xf8_behaviourOrient(behaviourOrient), xfa_behaviourModifiers(behaviourModifiers) { SetUseInSortedLists(false); SetCallTouch(false); diff --git a/Runtime/World/CScriptWaypoint.hpp b/Runtime/World/CScriptWaypoint.hpp index b76629060..dbf2e3adb 100644 --- a/Runtime/World/CScriptWaypoint.hpp +++ b/Runtime/World/CScriptWaypoint.hpp @@ -8,18 +8,19 @@ namespace urde class CScriptWaypoint : public CActor { float xe8_speed; - u32 xec_; - float xf0_; - bool xf4_; - bool xf5_; - bool xf6_; - bool xf7_; - bool xf8_; - u16 xfa_jumpFlags; + u32 xec_animation; + float xf0_pause; + u8 xf4_patternTranslate; + u8 xf5_patternOrient; + u8 xf6_patternFit; + u8 xf7_behaviour; + u8 xf8_behaviourOrient; + u16 xfa_behaviourModifiers; public: - CScriptWaypoint(TUniqueId, std::string_view, const CEntityInfo&, - const zeus::CTransform&, bool, float, float, - u32, u32, u32, u32, u32, u32, u32); + CScriptWaypoint(TUniqueId uid, std::string_view name, const CEntityInfo& info, + const zeus::CTransform& xf, bool active, float speed, float pause, + u32 patternTranslate, u32 patternOrient, u32 patternFit, u32 behaviour, + u32 behaviourOrient, u32 behaviourModifiers, u32 animation); void Accept(IVisitor& visitor); void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr); @@ -27,7 +28,14 @@ public: TUniqueId FollowWaypoint(CStateManager& mgr) const; TUniqueId NextWaypoint(CStateManager& mgr) const; float GetSpeed() const { return xe8_speed; } - float GetF0() const { return xf0_; } + u32 GetAnimation() const { return xec_animation; } + float GetPause() const { return xf0_pause; } + u8 GetPatternTranslate() const { return xf4_patternTranslate; } + u8 GetPatternOrient() const { return xf5_patternOrient; } + u8 GetPatternFit() const { return xf6_patternFit; } + u8 GetBehaviour() const { return xf7_behaviour; } + u8 GetBehaviourOrient() const { return xf8_behaviourOrient; } + u16 GetBehaviourModifiers() const { return xfa_behaviourModifiers; } }; } diff --git a/Runtime/World/CStateMachine.cpp b/Runtime/World/CStateMachine.cpp index b08320f8a..2f8773468 100644 --- a/Runtime/World/CStateMachine.cpp +++ b/Runtime/World/CStateMachine.cpp @@ -53,10 +53,6 @@ s32 CStateMachine::GetStateIndex(std::string_view state) const return it - x0_states.begin(); } -const std::vector& CStateMachine::GetStateVector() const { return x0_states; } - -float CStateMachineState::GetTime() const { return x8_time; } - void CStateMachineState::SetState(CStateManager &, CAi &, s32 idx) { } @@ -87,11 +83,9 @@ void CStateMachineState::Setup(const CStateMachine* machine) x4_state = nullptr; x8_time = 0.f; xc_random = 0.f; - x10_ = 0.f; + x10_delay = 0.f; } -std::string CStateMachineState::GetName() const { return {}; } - CFactoryFnReturn FAiFiniteStateMachineFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms, CObjectReference *) { return TToken::GetIObjObjectFor(std::make_unique(in)); diff --git a/Runtime/World/CStateMachine.hpp b/Runtime/World/CStateMachine.hpp index e5bc5d1d5..4856de087 100644 --- a/Runtime/World/CStateMachine.hpp +++ b/Runtime/World/CStateMachine.hpp @@ -36,16 +36,7 @@ class CAiState { friend class CStateMachineState; CAiStateFunc x0_func; - const char* x4_name; - u32 x8_; - u32 xc_; - u32 x10_; - u32 x14_; - u32 x18_; - u32 x1c_; - u32 x20_; - u32 x24_; - u32 x28_; + char xc_name[32]; u32 x2c_numTriggers; u32 x30_; public: @@ -54,7 +45,7 @@ public: s32 GetNumTriggers() const; CAiTrigger& GetTrig(s32) const; - const char* GetName() const { return x4_name; } + const char* GetName() const { return xc_name; } void SetTriggers(CAiTrigger* triggers); void SetNumTriggers(s32 numTriggers) { x2c_numTriggers = numTriggers; } void CallFunc(CStateManager& mgr, CAi& ai, EStateMsg msg, float delta) const @@ -72,7 +63,7 @@ public: CStateMachine(CInputStream& in); s32 GetStateIndex(std::string_view state) const; - const std::vector& GetStateVector() const; + const std::vector& GetStateVector() const { return x0_states; } }; class CStateMachineState @@ -82,7 +73,7 @@ class CStateMachineState CAiState* x4_state = nullptr; float x8_time = 0.f; float xc_random = 0.f; - float x10_ = 0.f; + float x10_delay = 0.f; float x14_; union { @@ -96,7 +87,6 @@ public: CStateMachineState()=default; CAiState* GetActorState() const { return x4_state; } - float GetTime() const; void Update(CStateManager& mgr, CAi& ai, float delta) { @@ -108,16 +98,16 @@ public: void SetState(CStateManager&, CAi&, const CStateMachine*, std::string_view); const std::vector* GetStateVector() const; void Setup(const CStateMachine* machine); - std::string GetName() const; - void SetDelay(float); + void SetDelay(float delay) { x10_delay = delay; } + float GetTime() const { return x8_time; } float GetRandom() const { return xc_random; } - float GetDelay() const; + float GetDelay() const { return x10_delay; } - u32 sub8007FB9C() const + const char* GetName() const { if (x4_state) - return x4_state->xc_; - return 0; + return x4_state->GetName(); + return nullptr; } }; diff --git a/Runtime/World/CWallWalker.cpp b/Runtime/World/CWallWalker.cpp index 231d19ef5..20f377c7f 100644 --- a/Runtime/World/CWallWalker.cpp +++ b/Runtime/World/CWallWalker.cpp @@ -15,7 +15,7 @@ CWallWalker::CWallWalker(ECharacter chr, TUniqueId uid, std::string_view name, E , x590_colSphere(zeus::CSphere(zeus::CVector3f::skZero, pInfo.GetHalfExtent()), x68_material) , x5b0_(f1) , x5b4_(f2) -, x5c0_(f3) +, x5c0_advanceWpRadius(f3) , x5c4_(f4) , x5cc_bendingHackAnim(GetModelData()->GetAnimationData()->GetCharacterInfo().GetAnimationIndex("BendingAnimationHack"sv)) , x5d0_(w2) @@ -94,15 +94,15 @@ void CWallWalker::Think(float dt, CStateManager& mgr) void CWallWalker::UpdateWPDestination(CStateManager& mgr) { - if (TCastToPtr wp = mgr.ObjectById(x2dc_)) + if (TCastToPtr wp = mgr.ObjectById(x2dc_destObj)) { zeus::CVector3f wpPos = wp->GetTranslation(); - if ((wpPos - GetTranslation()).magSquared() < x5c0_ * x5c0_) + if ((wpPos - GetTranslation()).magSquared() < x5c0_advanceWpRadius * x5c0_advanceWpRadius) { - x2dc_ = wp->NextWaypoint(mgr); - if (std::fabs(wp->GetF0()) > 0.00001f) + x2dc_destObj = wp->NextWaypoint(mgr); + if (std::fabs(wp->GetPause()) > 0.00001f) { - x5bc_ = wp->GetF0(); + x5bc_ = wp->GetPause(); if (x5d0_ == 0) x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); mgr.SendScriptMsg(wp, GetUniqueId(), EScriptObjectMessage::Arrived); diff --git a/Runtime/World/CWallWalker.hpp b/Runtime/World/CWallWalker.hpp index ffcd664be..7b45e60a2 100644 --- a/Runtime/World/CWallWalker.hpp +++ b/Runtime/World/CWallWalker.hpp @@ -17,7 +17,7 @@ protected: float x5b4_; float x5b8_ = 0.f; float x5bc_ = 0.f; - float x5c0_; + float x5c0_advanceWpRadius; float x5c4_; float x5c8_bendingHackWeight = 0.f; s32 x5cc_bendingHackAnim; diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index 0212317ae..dfd383ec7 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -477,18 +477,19 @@ CEntity* ScriptLoader::LoadWaypoint(CStateManager& mgr, CInputStream& in, int pr SActorHead head = LoadActorHead(in, mgr); bool active = in.readBool(); - float f1 = in.readFloatBig(); - float delay = in.readFloatBig(); - u32 w1 = in.readUint32Big(); - u32 w2 = in.readUint32Big(); - u32 w3 = in.readUint32Big(); - u32 w4 = in.readUint32Big(); - u32 w5 = in.readUint32Big(); - u32 w6 = in.readUint32Big(); - u32 w7 = in.readUint32Big(); + float speed = in.readFloatBig(); + float pause = in.readFloatBig(); + u32 patternTranslate = in.readUint32Big(); + u32 patternOrient = in.readUint32Big(); + u32 patternFit = in.readUint32Big(); + u32 behaviour = in.readUint32Big(); + u32 behaviourOrient = in.readUint32Big(); + u32 behaviourModifiers = in.readUint32Big(); + u32 animation = in.readUint32Big(); - return new CScriptWaypoint(mgr.AllocateUniqueId(), head.x0_name, info, head.x10_transform, active, f1, delay, w1, - w2, w3, w4, w5, w6, w7); + return new CScriptWaypoint(mgr.AllocateUniqueId(), head.x0_name, info, head.x10_transform, + active, speed, pause, patternTranslate, patternOrient, patternFit, + behaviour, behaviourOrient, behaviourModifiers, animation); } CEntity* ScriptLoader::LoadDoor(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) diff --git a/Runtime/World/ScriptObjectSupport.cpp b/Runtime/World/ScriptObjectSupport.cpp index a06aa09de..ac638da23 100644 --- a/Runtime/World/ScriptObjectSupport.cpp +++ b/Runtime/World/ScriptObjectSupport.cpp @@ -155,7 +155,7 @@ std::string_view ScriptObjectStateToStr(EScriptObjectState state) case EScriptObjectState::Open: return "Open"sv; case EScriptObjectState::Zero: return "Zero"sv; case EScriptObjectState::Attack: return "Attack"sv; - case EScriptObjectState::UNKS1: return "UNKS1"sv; + case EScriptObjectState::CloseIn: return "CloseIn"sv; case EScriptObjectState::Retreat: return "Retreat"sv; case EScriptObjectState::Patrol: return "Patrol"sv; case EScriptObjectState::Dead: return "Dead"sv; @@ -163,12 +163,12 @@ std::string_view ScriptObjectStateToStr(EScriptObjectState state) case EScriptObjectState::CameraTarget: return "CameraTarget"sv; case EScriptObjectState::UNKS2: return "UNKS2"sv; case EScriptObjectState::Play: return "Play"sv; - case EScriptObjectState::DeathExplosion: return "DeathExplosion"sv; + case EScriptObjectState::MassiveDeath: return "DeathExplosion"sv; case EScriptObjectState::DeathRattle: return "DeathRattle"sv; - case EScriptObjectState::AboutToDie: return "AboutToDie"sv; + case EScriptObjectState::AboutToMassivelyDie: return "AboutToDie"sv; case EScriptObjectState::Damage: return "Damage"sv; case EScriptObjectState::InvulnDamage: return "InvulnDamage"sv; - case EScriptObjectState::IceDeathExplosion: return "IceDeathExplosion"sv; + case EScriptObjectState::MassiveFrozenDeath: return "IceDeathExplosion"sv; case EScriptObjectState::Modify: return "Modify"sv; case EScriptObjectState::ScanStart: return "ScanStart"sv; case EScriptObjectState::ScanProcessing: return "ScanProcessing"sv; diff --git a/Runtime/World/ScriptObjectSupport.hpp b/Runtime/World/ScriptObjectSupport.hpp index 3b2d67c21..4fa58884d 100644 --- a/Runtime/World/ScriptObjectSupport.hpp +++ b/Runtime/World/ScriptObjectSupport.hpp @@ -151,7 +151,7 @@ enum class EScriptObjectState Open = 8, Zero = 9, Attack = 10, - UNKS1 = 11, + CloseIn = 11, Retreat = 12, Patrol = 13, Dead = 14, @@ -159,12 +159,12 @@ enum class EScriptObjectState CameraTarget = 16, UNKS2 = 17, Play = 18, - DeathExplosion = 19, + MassiveDeath = 19, DeathRattle = 20, - AboutToDie = 21, + AboutToMassivelyDie = 21, Damage = 22, InvulnDamage = 23, - IceDeathExplosion = 24, + MassiveFrozenDeath = 24, Modify = 25, ScanStart = 26, ScanProcessing = 27,