From f50f5cedef299ae0bf8981df18ce278717d22a52 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 23 Feb 2020 18:30:46 -0500 Subject: [PATCH] CSnakeWeedSwarm: Implement remaining methods --- Runtime/World/CSnakeWeedSwarm.cpp | 400 +++++++++++++++++++++++++++++- Runtime/World/CSnakeWeedSwarm.hpp | 89 ++++++- 2 files changed, 466 insertions(+), 23 deletions(-) diff --git a/Runtime/World/CSnakeWeedSwarm.cpp b/Runtime/World/CSnakeWeedSwarm.cpp index b79327cbb..24f882ba5 100644 --- a/Runtime/World/CSnakeWeedSwarm.cpp +++ b/Runtime/World/CSnakeWeedSwarm.cpp @@ -1,9 +1,16 @@ #include "Runtime/World/CSnakeWeedSwarm.hpp" #include "Runtime/CSimplePool.hpp" +#include "Runtime/CStateManager.hpp" #include "Runtime/GameGlobalObjects.hpp" +#include "Runtime/Graphics/CBooRenderer.hpp" +#include "Runtime/Graphics/CSkinnedModel.hpp" +#include "Runtime/Graphics/CVertexMorphEffect.hpp" +#include "Runtime/Weapon/CGameProjectile.hpp" #include "Runtime/World/CActorParameters.hpp" #include "Runtime/World/CAnimationParameters.hpp" +#include "Runtime/World/CPlayer.hpp" +#include "Runtime/World/CWorld.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path namespace urde { @@ -32,36 +39,409 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na , x124_(f13) , x128_(f14) , x15c_dInfo(dInfo) +, x1c8_(std::make_unique>()) +, x1cc_(std::make_unique>()) , x1d0_sfx1(CSfxManager::TranslateSFXID(sfxId1)) , x1d2_sfx2(CSfxManager::TranslateSFXID(sfxId2)) , x1d4_sfx3(CSfxManager::TranslateSFXID(sfxId3)) , x1fc_(w5) , x200_(f16) { SetActorLights(actParms.GetLightParameters().MakeActorLights()); - x1b4_modelData.emplace_back(std::make_unique(animRes)); - x1b4_modelData.emplace_back(std::make_unique(animRes)); - x1b4_modelData.emplace_back(std::make_unique(animRes)); - x1b4_modelData.emplace_back(std::make_unique(animRes)); + x1b0_modelData.emplace_back(std::make_unique(animRes)); + x1b0_modelData.emplace_back(std::make_unique(animRes)); + x1b0_modelData.emplace_back(std::make_unique(animRes)); + x1b0_modelData.emplace_back(std::make_unique(animRes)); if (actParms.GetXRayAssets().first.IsValid()) { for (int i = 0; i < 4; ++i) - x1b4_modelData[i]->SetXRayModel(actParms.GetXRayAssets()); - x13c_xbf_modelAssetDirty = true; + x1b0_modelData[i]->SetXRayModel(actParms.GetXRayAssets()); + x140_25_modelAssetDirty = true; } if (actParms.GetThermalAssets().first.IsValid()) { for (int i = 0; i < 4; ++i) - x1b4_modelData[i]->SetInfraModel(actParms.GetThermalAssets()); - x13c_xbf_modelAssetDirty = true; + x1b0_modelData[i]->SetInfraModel(actParms.GetThermalAssets()); + x140_25_modelAssetDirty = true; } if (w4.IsValid()) { x1dc_ = g_SimplePool->GetObj({FOURCC('PART'), w4}); - x1ec_ = std::make_unique(x1dc_); + x1ec_particleGen1 = std::make_unique(x1dc_); } if (w6.IsValid()) { x1dc_ = g_SimplePool->GetObj({FOURCC('PART'), w6}); - x1f4_ = std::make_unique(x1dc_); + x1f4_particleGen2 = std::make_unique(x1dc_); } } void CSnakeWeedSwarm::Accept(urde::IVisitor& visitor) { visitor.Visit(this); } +void CSnakeWeedSwarm::AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which) { + // x178_.clear(); + // x19c_.clear(); + for (int i = 0; i < 4; ++i) { + // CSkinnedModel& skinnedModel = x1b0_modelData[i]->PickAnimatedModel(which); + // x178_.push_back(skinnedModel.Clone()); + // x19c_.push_back(ptr); + x1b0_modelData[i]->EnableLooping(true); + x1b0_modelData[i]->AdvanceAnimation( + // TODO calculation may be wrong + x1b0_modelData[i]->GetAnimationData()->GetAnimTimeRemaining("Whole Body"sv) * (i * 0.25f), mgr, x4_areaId, + true); + } + x1c4_ = which; +} + +void CSnakeWeedSwarm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId id, CStateManager& mgr) { + CActor::AcceptScriptMsg(msg, id, mgr); + if (msg == EScriptObjectMessage::Deleted) { + if (x1d8_) { + CSfxManager::RemoveEmitter(x1d8_); + x1d8_.reset(); + } + } else if (msg == EScriptObjectMessage::InitializedInArea) { + AllocateSkinnedModels(mgr, CModelData::EWhichModel::Normal); + SetCalculateLighting(true); + x90_actorLights->SetCastShadows(true); + } +} +void CSnakeWeedSwarm::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { + if (frustum.aabbFrustumTest(x144_)) { + SetCalculateLighting(false); + for (int i = 0; i < 4; ++i) { + x1b0_modelData[i]->GetAnimationData()->PreRender(); + } + bool bVar2 = false; + if (x90_actorLights) { + if (x140_24_) { + if (!xe4_29_actorLightsDirty) { + if (x90_actorLights->GetIsDirty()) { + bVar2 = true; + } + } else { + bVar2 = true; + xe4_29_actorLightsDirty = false; + } + if (xe4_31_calculateLighting && x90_actorLights) { + auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr); + if (visor == CPlayerState::EPlayerVisor::Thermal) { + x90_actorLights->BuildConstantAmbientLighting(zeus::skWhite); + } else { + if (bVar2) { + if (x4_areaId != kInvalidAreaId) { + CGameArea* area = mgr.GetWorld()->GetArea(x4_areaId); + if (area != nullptr) { + x90_actorLights->BuildAreaLightList(mgr, *area, x144_); + } + } + } + x90_actorLights->BuildDynamicLightList(mgr, x144_); + } + } + } + } + } else { + SetCalculateLighting(true); + } +} + +void CSnakeWeedSwarm::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const { + if (!xe4_30_outOfFrustum) { + if (x1ec_particleGen1) { + g_Renderer->AddParticleGen(*x1ec_particleGen1); + } + if (x1f4_particleGen2) { + g_Renderer->AddParticleGen(*x1f4_particleGen2); + } + if (x90_actorLights) { + // x90_actorLights->ActivateLights(); FIXME pass what here? + } else { + CGraphics::DisableAllLights(); + g_Renderer->SetAmbientColor(zeus::skWhite); + } + u32 l18 = -1; + for (u32 i = 0; i < x134_boids.size(); ++i) { + RenderBoid(i, &x134_boids[i], &l18); + } + CGraphics::DisableAllLights(); + } +} + +void CSnakeWeedSwarm::Touch(CActor& actor, CStateManager& mgr) { + if (TCastToPtr proj = actor) { + if (proj->GetDamageInfo().GetWeaponMode().GetType() != EWeaponType::AI) { + sub_8023ca48(x100_, mgr, proj->GetTransform().origin); + } + } + if (TCastToPtr player = actor) { + for (auto boid : x134_boids) { + float m = (boid.GetPosition() - player->GetTransform().origin).magnitude(); + if (m < x104_ && boid.GetState() == EBoidState::x0) { + mgr.SendScriptMsg(player, kInvalidUniqueId, EScriptObjectMessage::InSnakeWeed); + x140_26_ = true; + } + } + } +} + +void CSnakeWeedSwarm::sub_8023ca48(float param_1, CStateManager& mgr, const zeus::CVector3f& pos) { + float dVar8 = param_1 * param_1; + for (auto boid : x134_boids) { + const zeus::CVector3f& boidPosition = boid.GetPosition(); + if ((boidPosition - pos).magSquared() < dVar8 && + (boid.GetState() == EBoidState::x0 || boid.GetState() == EBoidState::x1)) { + boid.SetState(EBoidState::x3); + float random = mgr.GetActiveRandom()->Float(); + boid.Set_x18(x118_ * random + x114_); + CSfxManager::AddEmitter(x1d2_sfx2, boidPosition, zeus::skZero3f, true, false, 0x7f, x4_areaId); + EmitParticles1(boidPosition); + } + } +} + +void CSnakeWeedSwarm::Think(float dt, CStateManager& mgr) { + CEntity::Think(dt, mgr); + if (x30_24_active) { + if (x1ec_particleGen1) { + x1ec_particleGen1->Update(dt); + } + if (x1f4_particleGen2) { + x1f4_particleGen2->Update(dt); + } + x204_ -= dt; + bool bVar5 = x204_ < 0.f; + if (bVar5) { + x204_ = 0.f; + } + x204_ = std::max(x204_ - dt, 0.f); + if (!x140_24_) { + sub_8023c238(mgr); + } + if (x140_24_ && x1c8_ && !x1c8_->empty()) { + int v = (u64)(dt * x1cc_->size()) >> 0x20; // TODO ? + sub_8023bca8(mgr, v + 1); + } + CModelData::EWhichModel model = CModelData::GetRenderingModel(mgr); + if (x140_26_ && x1c4_ != model) { + AllocateSkinnedModels(mgr, model); + } + for (int i = 0; i < 4; ++i) { + x1b0_modelData[i]->GetAnimationData()->SetPlaybackRate(1.f); + x1b0_modelData[i]->AdvanceAnimation(dt, mgr, x4_areaId, true); + } + int numBoidsInx0 = 0; + for (auto boid : x134_boids) { + const zeus::CVector3f& pos = boid.GetPosition(); + EBoidState state = boid.GetState(); + if (state == EBoidState::x0) { + numBoidsInx0++; + if (x1f4_particleGen2 && bVar5) { + EmitParticles2(pos); + } + } else if (state == EBoidState::x1) { + float x14 = boid.Get_x14() - dt * boid.Get_x18(); + boid.Set_x14(x14); + // printf("setting x14 to %f (dt %f)\n", x14, dt * boid.Get_x18()); + if (x14 <= 0.f) { + boid.Set_x14(0.f); + boid.SetState(EBoidState::x0); + } + } else if (state == EBoidState::x2) { + float x10 = boid.Get_x10() - dt; + boid.Set_x10(x10); + if (x10 <= 0.f) { + boid.SetState(EBoidState::x1); + CSfxManager::AddEmitter(x1d4_sfx3, pos, zeus::skZero3f, true, false, 0x7f, x4_areaId); + EmitParticles1(pos); + } + } else if (state == EBoidState::x3) { + float x14 = dt * boid.Get_x18() + boid.Get_x14(); + boid.Set_x14(x14); + float dVar8 = x110_ * boid.Get_x20(); + if (dVar8 < x14) { + boid.Set_x14(dVar8); + float random = mgr.GetActiveRandom()->Float(); + boid.Set_x10(x10c_ * random + x108_); + boid.SetState(EBoidState::x2); + } + } + } + if (numBoidsInx0 == 0) { + if (x1d8_) { + CSfxManager::RemoveEmitter(x1d8_); + x1d8_.reset(); + } + } else { + if (!x1d8_) { + x1d8_ = CSfxManager::AddEmitter(x1d0_sfx1, GetTransform().origin, zeus::skZero3f, true, true, 0x7f, x4_areaId); + } + } + if (x140_26_) { + mgr.ApplyDamage(x8_uid, mgr.GetPlayer().GetUniqueId(), x8_uid, CDamageInfo(x15c_dInfo, dt), + CMaterialFilter::MakeInclude(CMaterialList(EMaterialTypes::Player, EMaterialTypes::Stone)), + zeus::skZero3f); + } + x140_26_ = false; + } +} + +zeus::CAABox CSnakeWeedSwarm::sub_8023d3f4() { + const zeus::CVector3f& scale = xe8_scale * 0.75f; + const zeus::CVector3f& min = GetTransform().origin - scale; + const zeus::CVector3f& max = GetTransform().origin + scale; + return zeus::CAABox(min, max); +} + +static CMaterialList matList1 = CMaterialList(EMaterialTypes::RadarObject, EMaterialTypes::Stone); +static CMaterialFilter matFilter1 = CMaterialFilter::MakeInclude(matList1); + +void CSnakeWeedSwarm::sub_8023c238(const CStateManager& mgr) { + const zeus::CAABox& box = sub_8023d3f4(); + const CRayCastResult& result = + mgr.RayStaticIntersection(box.center(), zeus::skDown, box.max.z() - box.min.z(), matFilter1); + if (result.IsValid()) { + int ct = sub_8023c154() * sub_8023c0fc(); + x134_boids.reserve(ct); + x1c8_->reserve(ct); + x1cc_->resize(ct, 0); + x1c8_->push_back(result.GetPoint()); + x140_24_ = true; + } + + // matFilter.IncludeList().Add(CMaterialList(matFilter.IncludeList().GetValue() >> 0x20)); +} + +int CSnakeWeedSwarm::sub_8023c0fc() { + const zeus::CAABox& box = sub_8023d3f4(); + return (int)((box.max.y() - box.min.y()) / xf4_) + 1; +} + +int CSnakeWeedSwarm::sub_8023c154() { + const zeus::CAABox& box = sub_8023d3f4(); + return (int)((box.max.x() - box.min.x()) / xf4_) + 1; +} + +void CSnakeWeedSwarm::sub_8023bca8(CStateManager& mgr, int v) { + int n = sub_8023c154(); + for (int i = 0; i < v; ++i) { + if (x1c8_->empty()) + break; + zeus::CVector3f vec = x1c8_->back(); + x1c8_->pop_back(); + const zeus::CVector2i& v2i = sub_8023c1ac(vec); + if (CreateBoid(vec, mgr)) { + x1cc_->at(v2i.x + n * v2i.y) = 3; + sub_8023bfb8(zeus::CVector3f(vec.x(), vec.y() - xf4_, vec.z())); + sub_8023bfb8(zeus::CVector3f(vec.x(), xf4_ + vec.y(), vec.z())); + sub_8023bfb8(zeus::CVector3f(vec.x() - xf4_, vec.y(), vec.z())); + sub_8023bfb8(zeus::CVector3f(xf4_ + vec.x(), vec.y(), vec.z())); + } else { + x1cc_->at(v2i.x + n * v2i.y) = 2; + } + } + sub_8023d204(); + if (x1c8_->empty()) { + x1c8_ = nullptr; + x1cc_ = nullptr; + } +} + +zeus::CVector2i CSnakeWeedSwarm::sub_8023c1ac(const zeus::CVector3f& vec) { + const zeus::CAABox& box = sub_8023d3f4(); + int x = (vec.x() - box.min.x()) / xf4_; + int y = (vec.y() - box.min.y()) / xf4_; + return zeus::CVector2i(x, y); +} + +// TODO double check these params +static CMaterialList matList2 = CMaterialList(EMaterialTypes::RadarObject, EMaterialTypes::Stone); +static CMaterialFilter matFilter2 = CMaterialFilter::MakeInclude(matList2); + +bool CSnakeWeedSwarm::CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr) { + const zeus::CVector3f pos = vec + zeus::CVector3f(sub_8023bc38(vec), sub_8023bbc8(vec), xf8_); + const CRayCastResult result = mgr.RayStaticIntersection(pos, zeus::skDown, 2.f * xf8_, matFilter2); + if (result.IsInvalid() || result.GetPlane().normal().dot(zeus::skUp) <= x11c_) { + return false; + } else { + const zeus::CVector3f boidPosition = result.GetPoint() - zeus::CVector3f(0.f, 0.f, x128_); + float random = mgr.GetActiveRandom()->Float(); + const CBoid boid(boidPosition, x110_, x114_ + x118_, (x124_ - x120_) * random + x120_); + x134_boids.push_back(boid); +// printf("created boid @ %f|%f|%f, new size %zu\n", boidPosition.x(), boidPosition.y(), boidPosition.z(), +// x134_boids.size()); + return true; + } +} + +float CSnakeWeedSwarm::sub_8023bbc8(const zeus::CVector3f& vec) { + float f = 2.4729404f * vec.y() + 0.3478602f * vec.x() * vec.x(); + return xfc_ * (2.f * std::abs(f - (int)f) - 1.f); +} + +float CSnakeWeedSwarm::sub_8023bc38(const zeus::CVector3f& vec) { + float f = 8.21395f * vec.x() + 0.112869f * vec.y() * vec.y(); + return xfc_ * (2.f * std::abs(f - (int)f) - 1.f); +} + +void CSnakeWeedSwarm::sub_8023bfb8(const zeus::CVector3f& vec) { + int x = sub_8023c154(); + int y = sub_8023c0fc(); + zeus::CVector2i v = sub_8023c1ac(vec); + if (-1 < v.x && v.x < x && -1 < v.y && v.y < y) { + v.x += x * v.y; + if (x1cc_->at(v.x) == 0) { + x1cc_->at(v.x) = 1; + x1c8_->push_back(vec); + } + } +} + +void CSnakeWeedSwarm::sub_8023d204() { + if (x134_boids.empty()) { + x144_ = zeus::CAABox(GetTransform().origin, GetTransform().origin); + } else { + x144_ = zeus::skInvertedBox; + for (auto boid : x134_boids) { + x144_.accumulateBounds(boid.GetPosition() - x100_); + x144_.accumulateBounds(boid.GetPosition() + x100_); + } + } + xe4_27_notInSortedLists = true; +} + +void CSnakeWeedSwarm::EmitParticles1(const zeus::CVector3f& pos) { + if (x1ec_particleGen1) { + x1ec_particleGen1->SetParticleEmission(true); + x1ec_particleGen1->SetTranslation(pos); + x1ec_particleGen1->ForceParticleCreation(x1fc_); + x1ec_particleGen1->SetParticleEmission(false); + } +} + +void CSnakeWeedSwarm::EmitParticles2(const zeus::CVector3f& pos) { + if (x1f4_particleGen2) { + x1f4_particleGen2->SetParticleEmission(true); + x1f4_particleGen2->SetTranslation(pos); + x1f4_particleGen2->ForceParticleCreation(1); + x1f4_particleGen2->SetParticleEmission(false); + } +} + +void CSnakeWeedSwarm::RenderBoid(u32 p1, const CBoid* boid, u32* p3) const { + u32 idx = p1 & 3; + u32 var3 = *p3; + auto modelData = x1b0_modelData[idx]; + CSkinnedModel& model = modelData->PickAnimatedModel(x1c4_); + CModelFlags useFlags(0, 0, 3, zeus::skWhite); + if ((var3 & 1 << idx) != 0) { + var3 &= ~(1 << idx); + modelData->GetAnimationData()->BuildPose(); + model.Calculate(modelData->GetAnimationData()->GetPose(), useFlags, {}, nullptr); + } + // printf("rendering boid with x14 %f\n", boid->Get_x14()); + const zeus::CTransform& xf = + zeus::CTransform::Translate(boid->GetPosition() /*- zeus::CVector3f(0.f, 0.f, boid->Get_x14())*/) * + zeus::CTransform::Scale(boid->Get_x20()); + g_Renderer->SetModelMatrix(xf); + model.Draw(useFlags); + *p3 = var3; +} + } // namespace urde diff --git a/Runtime/World/CSnakeWeedSwarm.hpp b/Runtime/World/CSnakeWeedSwarm.hpp index c05bc1ac2..484b18ffe 100644 --- a/Runtime/World/CSnakeWeedSwarm.hpp +++ b/Runtime/World/CSnakeWeedSwarm.hpp @@ -9,6 +9,40 @@ namespace urde { class CAnimationParameters; class CSnakeWeedSwarm : public CActor { +public: + enum class EBoidState : u32 { + x0 = 0, + x1 = 1, + x2 = 2, + x3 = 3, + }; + + class CBoid { + zeus::CVector3f x0_pos; + EBoidState xc_state; + float x10_ = 0.f; // some timer + float x14_; // height? + float x18_; + float x1c_ = 0.f; + float x20_; + + public: + constexpr CBoid(const zeus::CVector3f& pos, float f1, float f2, float f3) + : x0_pos(pos), xc_state(EBoidState::x1), x14_(f1), x18_(f2), x20_(f3) {} + + constexpr const zeus::CVector3f& GetPosition() const { return x0_pos; } + constexpr EBoidState GetState() const { return xc_state; } + constexpr float Get_x10() const { return x10_; } + constexpr float Get_x14() const { return x14_; } + constexpr float Get_x18() const { return x18_; } + constexpr float Get_x20() const { return x20_; } + constexpr void SetState(EBoidState v) { xc_state = v; } + constexpr void Set_x10(float v) { x10_ = v; } + constexpr void Set_x14(float v) { x14_ = v; } + constexpr void Set_x18(float v) { x18_ = v; } + }; + +private: zeus::CVector3f xe8_scale; float xf4_; float xf8_; @@ -26,25 +60,26 @@ class CSnakeWeedSwarm : public CActor { float x128_; u32 x12c_ = 0; // x130_ - u32 x134_ = 0; - u32 x138_ = 0; - u32 x13c_ = 0; - bool x13c_xbf_modelAssetDirty : 1; + std::vector x134_boids; + bool x140_24_ : 1; + bool x140_25_modelAssetDirty : 1; + bool x140_26_ : 1; zeus::CAABox x144_ = zeus::skInvertedBox; CDamageInfo x15c_dInfo; - // x178_ = 0 - // x19c_ = 0 - rstl::reserved_vector, 4> x1b4_modelData; - // x1c8_ = ptr to 0x10 sz? - // x1cc_ = ptr to 0x10 sz? +// std::vector> x178_; +// std::vector> x19c_; + rstl::reserved_vector, 4> x1b0_modelData; + CModelData::EWhichModel x1c4_; + std::unique_ptr> x1c8_; + std::unique_ptr> x1cc_; u16 x1d0_sfx1; u16 x1d2_sfx2; u16 x1d4_sfx3; - u32 x1d8_ = 0; + CSfxHandle x1d8_ = 0; TLockedToken x1dc_; // TLockedToken x1e4_; both assign to x1dc_? - std::unique_ptr x1ec_; - std::unique_ptr x1f4_; + std::unique_ptr x1ec_particleGen1; + std::unique_ptr x1f4_particleGen2; u32 x1fc_; float x200_; float x204_ = 0.f; @@ -57,6 +92,34 @@ public: void Accept(IVisitor&) override; void ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& stateMgr) {} - std::optional GetTouchBounds() const override { /* FIXME check flags */ return x144_; } + std::optional GetTouchBounds() const override { + if (x140_24_) { + return {}; + } + return x144_; + } + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override; + void PreRender(CStateManager&, const zeus::CFrustum&) override; + void AddToRenderer(const zeus::CFrustum&, const CStateManager&) const override; + void Touch(CActor&, CStateManager&) override; + void Think(float, CStateManager&) override; + +private: + void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which); + void sub_8023ca48(float param_1, CStateManager& mgr, const zeus::CVector3f& pos); + void sub_8023c238(const CStateManager& mgr); + zeus::CAABox sub_8023d3f4(); + int sub_8023c0fc(); + int sub_8023c154(); + void sub_8023bca8(CStateManager& mgr, int v); + zeus::CVector2i sub_8023c1ac(const zeus::CVector3f& vec); + bool CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr); + float sub_8023bbc8(const zeus::CVector3f& vec); + float sub_8023bc38(const zeus::CVector3f& vec); + void sub_8023bfb8(const zeus::CVector3f& vec); + void sub_8023d204(); + void EmitParticles1(const zeus::CVector3f& pos); + void EmitParticles2(const zeus::CVector3f& pos); + void RenderBoid(u32 p1, const CBoid* boid, u32 *p3) const; }; } // namespace urde