From 6fe99a7ddf347c5fcd019b89fe1289e0b8b2ff44 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sun, 16 Dec 2018 21:40:27 -0800 Subject: [PATCH 1/2] Finish CFlickerBat imps --- Runtime/CStateManager.cpp | 20 ++++ Runtime/CStateManager.hpp | 5 +- Runtime/Character/CBodyStateCmdMgr.hpp | 1 + Runtime/MP1/World/CFlickerBat.cpp | 128 +++++++++++++++++++++++-- Runtime/MP1/World/CFlickerBat.hpp | 5 +- 5 files changed, 147 insertions(+), 12 deletions(-) diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index 0515bd1a8..913639886 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -860,6 +860,14 @@ void CStateManager::SetupFogForArea(TAreaId area) const { SetupFogForArea(*areaObj); } +void CStateManager::SetupFogForAreaNonCurrent(TAreaId area) const { + if (area == kInvalidAreaId) + area = x8cc_nextAreaId; + const CGameArea* areaObj = x850_world->GetAreaAlways(area); + if (areaObj->IsPostConstructed()) + SetupFogForAreaNonCurrent(*areaObj); +} + void CStateManager::SetupFogForArea(const CGameArea& area) const { if (SetupFogForDraw()) return; @@ -874,6 +882,18 @@ void CStateManager::SetupFogForArea(const CGameArea& area) const { } } +void CStateManager::SetupFogForAreaNonCurrent(const CGameArea& area) const { + if (SetupFogForDraw()) + return; + + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::EPlayerVisor::XRay) { + float fogDist = area.GetXRayFogDistance(); + float farz = g_tweakGui->GetXRayFogNearZ() * (1.f - fogDist) + g_tweakGui->GetXRayFogFarZ() * fogDist; + g_Renderer->SetWorldFog(ERglFogMode(g_tweakGui->GetXRayFogMode()), g_tweakGui->GetXRayFogNearZ(), farz, + g_tweakGui->GetXRayFogColor()); + } +} + bool CStateManager::SetupFogForDraw() const { switch (x8b8_playerState->GetActiveVisor(*this)) { case CPlayerState::EPlayerVisor::Thermal: diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 1e762108b..0acfc513a 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -172,7 +172,7 @@ private: zeus::CVector2f xf2c_viewportScale = {1.f, 1.f}; EThermalDrawFlag xf34_thermalFlag = EThermalDrawFlag::Bypass; TUniqueId xf38_skipCineSpecialFunc = kInvalidUniqueId; - std::list xf3c_; + std::list xf3c_activeFlickerBats; std::list xf54_activeParasites; TUniqueId xf6c_playerActorHead = kInvalidUniqueId; u32 xf70_ = 0; @@ -248,7 +248,9 @@ public: void ResetViewAfterDraw(const SViewport& backupViewport, const zeus::CTransform& backupViewMatrix) const; void DrawWorld() const; void SetupFogForArea(TAreaId area) const; + void SetupFogForAreaNonCurrent(TAreaId area) const; void SetupFogForArea(const CGameArea& area) const; + void SetupFogForAreaNonCurrent(const CGameArea& area) const; bool SetupFogForDraw() const; void PreRender(); void GetCharacterRenderMaskAndTarget(bool thawed, int& mask, int& target) const; @@ -429,6 +431,7 @@ public: } TUniqueId GetPlayerActorHead() const { return xf6c_playerActorHead; } void SetPlayerActorHead(TUniqueId id) { xf6c_playerActorHead = id; } + std::list& GetActiveFlickerBats() { return xf3c_activeFlickerBats; } std::list& GetActiveParasites() { return xf54_activeParasites; } std::shared_ptr& WorldLayerStateNC() { return x8c8_worldLayerState; } static float g_EscapeShakeCountdown; diff --git a/Runtime/Character/CBodyStateCmdMgr.hpp b/Runtime/Character/CBodyStateCmdMgr.hpp index 620b8a92e..e301f1d8d 100644 --- a/Runtime/Character/CBodyStateCmdMgr.hpp +++ b/Runtime/Character/CBodyStateCmdMgr.hpp @@ -430,6 +430,7 @@ public: DeliverCmd(EBodyStateCmd::AdditiveReaction); } void DeliverCmd(const CBCLocomotionCmd& cmd); + void DeliverFaceVector(const zeus::CVector3f& f) { xc_face = f; } void DeliverTargetVector(const zeus::CVector3f& t) { x18_target = t; } void DeliverAdditiveTargetVector(const zeus::CVector3f& t) { x24_additiveTarget = t; } void SetSteeringBlendSpeed(float s) { x3c_steeringSpeed = s; } diff --git a/Runtime/MP1/World/CFlickerBat.cpp b/Runtime/MP1/World/CFlickerBat.cpp index 2816a489d..10c3f3961 100644 --- a/Runtime/MP1/World/CFlickerBat.cpp +++ b/Runtime/MP1/World/CFlickerBat.cpp @@ -13,7 +13,7 @@ CFlickerBat::CFlickerBat(TUniqueId uid, std::string_view name, CPatterned::EFlav EColliderType colType, bool b1, const CActorParameters& actParms, bool b2) : CPatterned(ECharacter::FlickerBat, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Flyer, colType, EBodyType::Pitchable, actParms, EKnockBackVariant::Small) -, x580_24_(false) +, x580_24_wasInXray(false) , x580_25_heardShot(false) , x580_26_(false) , x580_27_(b2) @@ -31,11 +31,11 @@ void CFlickerBat::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStat if (msg == EScriptObjectMessage::Registered) { RemoveMaterial(EMaterialTypes::Solid, mgr); - /* TODO: Implement xf3c_ in CStateManager (skipping 801311B8 - 80131224) */ + mgr.GetActiveFlickerBats().push_back(GetUniqueId()); x450_bodyController->Activate(mgr); x450_bodyController->BodyStateInfo().SetMaximumPitch(zeus::degToRad(60.f)); } else if (msg == EScriptObjectMessage::Deleted) { - /* sub80125D88(mgr.xf3c_, uid) */ + mgr.GetActiveFlickerBats().remove(GetUniqueId()); } } @@ -55,15 +55,84 @@ void CFlickerBat::Think(float dt, CStateManager& mgr) { } } + bool inXray = mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay; + if (inXray != x580_24_wasInXray) { + if (inXray) { + if (GetFlickerBatState() == EFlickerBatState::One) { + AddMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + SetMuted(false); + } + CreateShadow(false); + } else { + if (GetFlickerBatState() == EFlickerBatState::One) { + RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + SetMuted(true); + } + CreateShadow(true); + } + x580_24_wasInXray = inXray; + } + + float alpha = 0.f; + if (!x580_24_wasInXray) { + if (GetFlickerBatState() == EFlickerBatState::Zero) + alpha = 1.f; + else if (GetFlickerBatState() == EFlickerBatState::Two || GetFlickerBatState() == EFlickerBatState::Three) { + alpha = x578_ * x57c_; + if (GetFlickerBatState() == EFlickerBatState::Two) + alpha = 1.f - alpha; + } + } else + alpha = 1.f; + + x42c_color.a() = alpha; + x94_simpleShadow->SetUserAlpha(alpha); + + bool targetable = true; + if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay && + (x574_state == EFlickerBatState::Zero || x574_state == EFlickerBatState::Two)) + targetable = false; + xe7_31_targetable = targetable; CPatterned::Think(dt, mgr); } -void CFlickerBat::Render(const CStateManager& mgr) const { CPatterned::Render(mgr); } +void CFlickerBat::Render(const CStateManager& mgr) const { + if (!x580_24_wasInXray && x580_26_ && + (GetFlickerBatState() == EFlickerBatState::Two || GetFlickerBatState() == EFlickerBatState::Three)) { + float strength = 0.f; + if (GetFlickerBatState() == EFlickerBatState::Two) { + strength = 4.f * (x578_ - .75f); + } else if (GetFlickerBatState() == EFlickerBatState::Three) { + strength = 4.f * x578_; + } + if (strength > 0.f && strength < 1.f) + mgr.DrawSpaceWarp(GetTranslation(), 0.3f * std::sin(M_PIF * strength)); + } -void CFlickerBat::Touch(CActor& act, CStateManager& mgr) { CPatterned::Touch(act, mgr); } + if (x580_26_) { + mgr.SetupFogForAreaNonCurrent(GetAreaIdAlways()); + CPatterned::Render(mgr); + mgr.SetupFogForArea(GetAreaIdAlways()); + } else + CPatterned::Render(mgr); +} + +void CFlickerBat::Touch(CActor& act, CStateManager& mgr) { + if (TCastToPtr pl = act) { + if (x420_curDamageRemTime <= 0.f) { + mgr.ApplyDamage(GetUniqueId(), pl->GetUniqueId(), GetUniqueId(), GetContactDamage(), + CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); + x420_curDamageRemTime = x424_damageWaitTime; + } + } + CPatterned::Touch(act, mgr); +} void CFlickerBat::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { - CPatterned::DoUserAnimEvent(mgr, node, type, dt); + if (type == EUserEventType::FadeIn) + ToggleVisible(mgr); + else + CPatterned::DoUserAnimEvent(mgr, node, type, dt); } void CFlickerBat::Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state) { @@ -76,13 +145,35 @@ bool CFlickerBat::CanBeShot(CStateManager& mgr, int) { mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay); } -void CFlickerBat::Patrol(CStateManager& mgr, EStateMsg state, float dt) { CPatterned::Patrol(mgr, state, dt); } +void CFlickerBat::Patrol(CStateManager& mgr, EStateMsg state, float dt) +{ + CPatterned::Patrol(mgr, state, dt); + x450_bodyController->GetCommandMgr().DeliverFaceVector((x2e0_destPos - GetTranslation()).normalized()); +} -void CFlickerBat::Attack(CStateManager&, EStateMsg, float) {} +void CFlickerBat::Attack(CStateManager&, EStateMsg msg, float) { + if (msg == EStateMsg::Update) { + x450_bodyController->GetCommandMgr().DeliverCmd( + CBCLocomotionCmd((x2e0_destPos - GetTranslation()).normalized(), {}, 1.f)); + } +} -void CFlickerBat::Shuffle(CStateManager&, EStateMsg, float) {} +void CFlickerBat::Shuffle(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + CRandom16* rnd = mgr.GetActiveRandom(); + SetDestPos(GetTranslation() + + zeus::CVector3f(100.f * rnd->Float() - 50.f, 100.f * rnd->Float() - 50.f, 100.f * rnd->Float() - 50.f)); + } else if (msg == EStateMsg::Update) { + ApproachDest(mgr); + } +} -void CFlickerBat::Taunt(CStateManager&, EStateMsg, float) {} +void CFlickerBat::Taunt(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + NotifyNeighbors(mgr); + x400_24_hitByPlayerProjectile = false; + } +} bool CFlickerBat::InPosition(CStateManager& mgr, float arg) { return GetTransform().frontVector().dot(mgr.GetPlayer().GetAimPosition(mgr, 0.f) - GetTranslation()) > 0.f; @@ -145,4 +236,21 @@ void CFlickerBat::CheckStaticIntersection(CStateManager& mgr) { CMaterialFilter::MakeExclude({EMaterialTypes::SeeThrough})); } +void CFlickerBat::NotifyNeighbors(CStateManager& mgr) { + for (TUniqueId uid : mgr.GetActiveFlickerBats()) { + if (CFlickerBat* flick = CPatterned::CastTo(mgr.ObjectById(uid))) + if ((GetTranslation() - flick->GetTranslation()).magnitude() < 100.f) + flick->SetHeardShot(true); + } +} + +void CFlickerBat::ToggleVisible(CStateManager& mgr) { + if (GetFlickerBatState() == EFlickerBatState::Zero || GetFlickerBatState() == EFlickerBatState::Two) + SetFlickerBatState(EFlickerBatState::Three, mgr); + else + SetFlickerBatState(EFlickerBatState::Two, mgr); + + x578_ = 1.f; + x57c_ = 1.f / x578_; +} } // namespace urde::MP1 \ No newline at end of file diff --git a/Runtime/MP1/World/CFlickerBat.hpp b/Runtime/MP1/World/CFlickerBat.hpp index 12e9c08d7..812b44daf 100644 --- a/Runtime/MP1/World/CFlickerBat.hpp +++ b/Runtime/MP1/World/CFlickerBat.hpp @@ -14,11 +14,14 @@ private: EFlickerBatState x574_state; float x578_ = 1.f; float x57c_ = 0.f; - bool x580_24_ : 1; + bool x580_24_wasInXray : 1; bool x580_25_heardShot : 1; bool x580_26_ : 1; bool x580_27_ : 1; + void NotifyNeighbors(CStateManager&); + void ToggleVisible(CStateManager&); + void SetHeardShot(bool heardShot) { x580_25_heardShot = heardShot; } public: DEFINE_PATTERNED(FlickerBat) CFlickerBat(TUniqueId, std::string_view name, EFlavorType, const CEntityInfo&, const zeus::CTransform&, CModelData&&, From d657a8ecf6dd9a8d99b5177fe3aec093a022a83a Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Mon, 17 Dec 2018 20:42:17 -0800 Subject: [PATCH 2/2] Implement CAtomicAlpha --- Runtime/Collision/CCollisionResponseData.cpp | 4 +- Runtime/Collision/CCollisionResponseData.hpp | 4 +- Runtime/MP1/World/CAtomicAlpha.cpp | 154 ++++++++++++++++++- Runtime/MP1/World/CAtomicAlpha.hpp | 48 ++++++ Runtime/MP1/World/CBabygoth.cpp | 7 + Runtime/MP1/World/CBabygoth.hpp | 1 + Runtime/Weapon/CEnergyProjectile.cpp | 2 +- Runtime/World/ScriptLoader.cpp | 5 +- 8 files changed, 215 insertions(+), 10 deletions(-) diff --git a/Runtime/Collision/CCollisionResponseData.cpp b/Runtime/Collision/CCollisionResponseData.cpp index cd8270d4e..9f96f4362 100644 --- a/Runtime/Collision/CCollisionResponseData.cpp +++ b/Runtime/Collision/CCollisionResponseData.cpp @@ -215,7 +215,7 @@ EWeaponCollisionResponseTypes CCollisionResponseData::GetWorldCollisionResponseT } bool CCollisionResponseData::ResponseTypeIsEnemyNormal(EWeaponCollisionResponseTypes type) { - return (type >= EWeaponCollisionResponseTypes::Unknown19 && type <= EWeaponCollisionResponseTypes::Unknown43); + return (type >= EWeaponCollisionResponseTypes::Unknown19 && type <= EWeaponCollisionResponseTypes::AtomicAlpha); } bool CCollisionResponseData::ResponseTypeIsEnemySpecial(EWeaponCollisionResponseTypes type) { @@ -223,7 +223,7 @@ bool CCollisionResponseData::ResponseTypeIsEnemySpecial(EWeaponCollisionResponse } bool CCollisionResponseData::ResponseTypeIsEnemyShielded(EWeaponCollisionResponseTypes type) { - return (type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::Unknown93); + return (type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect); } FourCC CCollisionResponseData::UncookedResType() { return SBIG('CRSM'); } diff --git a/Runtime/Collision/CCollisionResponseData.hpp b/Runtime/Collision/CCollisionResponseData.hpp index e94fdf755..a45424875 100644 --- a/Runtime/Collision/CCollisionResponseData.hpp +++ b/Runtime/Collision/CCollisionResponseData.hpp @@ -56,7 +56,7 @@ enum class EWeaponCollisionResponseTypes { Unknown40, Unknown41, Unknown42, - Unknown43, + AtomicAlpha, Unknown44, Unknown45, Unknown46, @@ -106,7 +106,7 @@ enum class EWeaponCollisionResponseTypes { Unknown90, Unknown91, Unknown92, - Unknown93 + AtomicAlphaReflect }; class CCollisionResponseData { diff --git a/Runtime/MP1/World/CAtomicAlpha.cpp b/Runtime/MP1/World/CAtomicAlpha.cpp index d1e6bb761..29eafa464 100644 --- a/Runtime/MP1/World/CAtomicAlpha.cpp +++ b/Runtime/MP1/World/CAtomicAlpha.cpp @@ -1,10 +1,158 @@ #include "CAtomicAlpha.hpp" +#include "World/CWorld.hpp" +#include "World/CGameArea.hpp" +#include "World/CPlayer.hpp" +#include "World/CPatternedInfo.hpp" +#include "Weapon/CPlayerGun.hpp" +#include "CStateManager.hpp" namespace urde::MP1 { +const std::string_view CAtomicAlpha::skBombLocators[4] = { + "bomb1_LCTR"sv, + "bomb2_LCTR"sv, + "bomb3_LCTR"sv, + "bomb4_LCTR"sv +}; + CAtomicAlpha::CAtomicAlpha(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo, - CAssetId wpsc, const CDamageInfo& dInfo, float f1, float f2, float f3, CAssetId cmdl, - bool b1, bool b2) + CAssetId bombWeapon, const CDamageInfo& bombDamage, float bombDropDelay, float f2, float f3, CAssetId cmdl, + bool invisible, bool b2) : CPatterned(ECharacter::AtomicAlpha, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, - EMovementType::Flyer, EColliderType::One, EBodyType::Flyer, actParms, EKnockBackVariant::Medium) {} + EMovementType::Flyer, EColliderType::One, EBodyType::Flyer, actParms, EKnockBackVariant::Medium) +, x568_24_inRange(false) +, x568_25_invisible(invisible) +, x568_26_applyBeamAttraction(b2) +, x56c_bomdDropDelay(bombDropDelay) +, x570_bombReappearDelay(f2) +, x574_bombRappearTime(f3) +, x580_pathFind(nullptr, 3, pInfo.GetPathfindingIndex(), 1.f, 1.f) +, x668_bombProjectile(bombWeapon, bombDamage) +, x690_bombModel(CStaticRes(cmdl, GetModelData()->GetScale())) { + const_cast*>(&x668_bombProjectile.Token())->Lock(); + for (u32 i = 0; i < skBombCount; ++i) { + x6dc_bombLocators.push_back( + SBomb(skBombLocators[i], pas::ELocomotionType(u32(pas::ELocomotionType::Internal10) + i))); + } +} + +void CAtomicAlpha::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + CPatterned::AcceptScriptMsg(msg, uid, mgr); + if (msg == EScriptObjectMessage::InitializedInArea) { + x580_pathFind.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea); + } else if (msg == EScriptObjectMessage::Registered) { + x450_bodyController->Activate(mgr); + } else if (msg == EScriptObjectMessage::AddSplashInhabitant) { + if (x400_25_alive) + x401_30_pendingDeath = true; + } +} + +void CAtomicAlpha::Render(const CStateManager& mgr) const { + if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible) + return; + + CPatterned::Render(mgr); + for (const SBomb& bomb : x6dc_bombLocators) { + zeus::CTransform locatorXf = GetTransform() * GetScaledLocatorTransform(bomb.x0_locatorName) * + zeus::CTransform::Scale(std::min(1.f, std::max(0.f, bomb.x14_scaleTime - x570_bombReappearDelay) / x570_bombReappearDelay)); + CModelFlags flags; + flags.x2_flags = 1 | 2; + flags.x4_color = zeus::CColor::skWhite; + x690_bombModel.Render(mgr, locatorXf, x90_actorLights.get(), flags); + } +} +void CAtomicAlpha::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const { + if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible) + return; + CPatterned::AddToRenderer(frustum, mgr); +} + +void CAtomicAlpha::Think(float dt, CStateManager& mgr) { + CPatterned::Think(dt, mgr); + if (!GetActive()) + return; + + x578_bombTime += dt; + + for (SBomb& bomb : x6dc_bombLocators) { + bomb.x14_scaleTime += dt; + } +} + +void CAtomicAlpha::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { + if (type == EUserEventType::Projectile) { + zeus::CVector3f origin = GetLctrTransform(node.GetLocatorName()).origin; + zeus::CTransform xf = zeus::lookAt(origin, origin + zeus::CVector3f::skDown, zeus::CVector3f::skUp); + LaunchProjectile(xf, mgr, 4, EProjectileAttrib::None, false, {}, 0xFFFF, false, zeus::CVector3f(1.f)); + x578_bombTime = 0.f; + x57c_curBomb = (x57c_curBomb + 1) & (x6dc_bombLocators.size() - 1); + } else + CPatterned::DoUserAnimEvent(mgr, node, type, dt); +} + +bool CAtomicAlpha::Leash(CStateManager& mgr, float) { + if ((mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() <= + x3cc_playerLeashRadius * x3cc_playerLeashRadius) + return false; + + return x3d4_curPlayerLeashTime > x3d0_playerLeashTime; +} + +bool CAtomicAlpha::AggressionCheck(CStateManager& mgr, float) { + const CPlayerGun* playerGun = mgr.GetPlayer().GetPlayerGun(); + float factor = 0.f; + if (x568_26_applyBeamAttraction && playerGun->IsCharging()) + factor = playerGun->GetChargeBeamFactor(); + return factor > 0.1f; +} + +void CAtomicAlpha::CollidedWith(TUniqueId uid, const CCollisionInfoList& list, CStateManager& mgr) { + if (IsAlive()) { + if (TCastToConstPtr pl = mgr.GetObjectById(uid)) { + if (x420_curDamageRemTime <= 0.f) { + mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.5f, 0.25f); + for (SBomb& bomb : x6dc_bombLocators) { + bomb.x14_scaleTime = 0.f; + } + } + } + } + CPatterned::CollidedWith(uid, list, mgr); +} + +void CAtomicAlpha::Patrol(CStateManager& mgr, EStateMsg msg, float arg) { + CPatterned::Patrol(mgr, msg, arg); + if (msg == EStateMsg::Activate) { + x578_bombTime = 0.f; + } else if (msg == EStateMsg::Update) { + if (x568_24_inRange) { + if (x578_bombTime >= x56c_bomdDropDelay && + x6dc_bombLocators[0].x14_scaleTime > (x570_bombReappearDelay + x574_bombRappearTime)) { + x450_bodyController->SetLocomotionType(x6dc_bombLocators[x57c_curBomb].x10_locomotionType); + } else { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); + } + if (Leash(mgr, arg)) + x568_24_inRange = false; + } else { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); + if (InMaxRange(mgr, arg)) + x568_24_inRange = true; + } + } else if (msg == EStateMsg::Deactivate) { + x568_24_inRange = false; + } +} + +void CAtomicAlpha::Attack(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8); + } else if (msg == EStateMsg::Update) { + zeus::CVector3f seekVec = x664_steeringBehaviors.Seek(*this, mgr.GetPlayer().GetEyePosition()); + x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(seekVec, {}, 1.f)); + } else if (msg == EStateMsg::Deactivate) { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); + } +} } // namespace urde::MP1 diff --git a/Runtime/MP1/World/CAtomicAlpha.hpp b/Runtime/MP1/World/CAtomicAlpha.hpp index cf3b30de1..5b5e15012 100644 --- a/Runtime/MP1/World/CAtomicAlpha.hpp +++ b/Runtime/MP1/World/CAtomicAlpha.hpp @@ -1,13 +1,61 @@ #pragma once #include "World/CPatterned.hpp" +#include "World/CPathFindSearch.hpp" +#include "Weapon/CProjectileInfo.hpp" namespace urde::MP1 { class CAtomicAlpha : public CPatterned { + static const std::string_view skBombLocators[4]; + static constexpr u32 skBombCount = 4; + struct SBomb { + std::string x0_locatorName; + pas::ELocomotionType x10_locomotionType; + float x14_scaleTime = FLT_MAX; + SBomb(const std::string_view locator, pas::ELocomotionType locomotionType) + : x0_locatorName(locator.data()) + , x10_locomotionType(locomotionType) {} + }; + bool x568_24_inRange : 1; + bool x568_25_invisible : 1; + bool x568_26_applyBeamAttraction : 1; + float x56c_bomdDropDelay; + float x570_bombReappearDelay; + float x574_bombRappearTime; + float x578_bombTime = 0.f; + u32 x57c_curBomb = 0; + CPathFindSearch x580_pathFind; + CSteeringBehaviors x664_steeringBehaviors; + CProjectileInfo x668_bombProjectile; + CModelData x690_bombModel; + rstl::reserved_vector x6dc_bombLocators; public: DEFINE_PATTERNED(AtomicAlpha) + CAtomicAlpha(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&, const CActorParameters&, const CPatternedInfo&, CAssetId, const CDamageInfo&, float, float, float, CAssetId, bool, bool); + + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); + void Render(const CStateManager&) const; + void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const; + void Think(float, CStateManager&); + void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt); + + CPathFindSearch* GetSearchPath() { return &x580_pathFind; } + + EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&, + const CWeaponMode& wMode, EProjectileAttrib) const { + return GetDamageVulnerability()->WeaponHits(wMode, false) ? EWeaponCollisionResponseTypes::AtomicAlpha + : EWeaponCollisionResponseTypes::AtomicAlphaReflect; + } + + bool Leash(CStateManager& mgr, float); + bool AggressionCheck(CStateManager&, float); + void CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager&); + void Patrol(CStateManager&, EStateMsg, float); + void Attack(CStateManager&, EStateMsg, float); + + CProjectileInfo* GetProjectileInfo() { return &x668_bombProjectile; } }; } // namespace urde::MP1 diff --git a/Runtime/MP1/World/CBabygoth.cpp b/Runtime/MP1/World/CBabygoth.cpp index be3ac1b8e..641e9bf38 100644 --- a/Runtime/MP1/World/CBabygoth.cpp +++ b/Runtime/MP1/World/CBabygoth.cpp @@ -34,4 +34,11 @@ CBabygoth::CBabygoth(TUniqueId uid, std::string_view name, const CEntityInfo& in const CBabygothData& babyData) : CPatterned(ECharacter::Babygoth, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, EMovementType::Ground, EColliderType::One, EBodyType::BiPedal, actParms, EKnockBackVariant::Medium) {} + +void CBabygoth::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + CPatterned::AcceptScriptMsg(msg, uid, mgr); + if (msg == EScriptObjectMessage::Registered) { + x450_bodyController->Activate(mgr); + } +} } // namespace urde::MP1 diff --git a/Runtime/MP1/World/CBabygoth.hpp b/Runtime/MP1/World/CBabygoth.hpp index be7b0acf6..f89027e3b 100644 --- a/Runtime/MP1/World/CBabygoth.hpp +++ b/Runtime/MP1/World/CBabygoth.hpp @@ -50,6 +50,7 @@ public: DEFINE_PATTERNED(Babygoth) CBabygoth(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&, const CPatternedInfo&, const CActorParameters&, const CBabygothData&); + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr); }; } // namespace urde::MP1 diff --git a/Runtime/Weapon/CEnergyProjectile.cpp b/Runtime/Weapon/CEnergyProjectile.cpp index 27bd35e8a..9d8be2320 100644 --- a/Runtime/Weapon/CEnergyProjectile.cpp +++ b/Runtime/Weapon/CEnergyProjectile.cpp @@ -269,7 +269,7 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3 if (vulnType != EVulnerability::Immune && !deflect) { deflect = (type == EWeaponCollisionResponseTypes::Unknown15 || type == EWeaponCollisionResponseTypes::EnemyShielded || - (type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::Unknown93)); + (type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect)); } SetTranslation(offsetPos); diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index da4b61ee4..ba678091c 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -1789,10 +1789,11 @@ CEntity* ScriptLoader::LoadActorRotate(CStateManager& mgr, CInputStream& in, int zeus::CVector3f rotation = zeus::CVector3f::ReadBig(in); float scale = in.readFloatBig(); bool updateActors = in.readBool(); - bool b2 = in.readBool(); + bool updateOnCreation = in.readBool(); bool active = in.readBool(); - return new CScriptActorRotate(mgr.AllocateUniqueId(), name, info, rotation, scale, updateActors, b2, active); + return new CScriptActorRotate(mgr.AllocateUniqueId(), name, info, rotation, scale, updateActors, updateOnCreation, + active); } CEntity* ScriptLoader::LoadSpecialFunction(CStateManager& mgr, CInputStream& in, int propCount,