Merge pull request #176 from AxioDL/csnakeweedswarm

Implement CSnakeWeedSwarm
This commit is contained in:
Phillip Stephens 2020-03-01 05:10:13 -08:00 committed by GitHub
commit b0b663f71f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 471 additions and 43 deletions

View File

@ -1,13 +1,22 @@
#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 {
static constexpr CMaterialFilter matFilter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid});
CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info,
const zeus::CVector3f& pos, const zeus::CVector3f& scale, const CAnimRes& animRes,
const CActorParameters& actParms, float f1, float f2, float f3, float f4, float f5,
@ -17,10 +26,10 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na
: CActor(uid, active, name, info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(),
CMaterialList(EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable), actParms, kInvalidUniqueId)
, xe8_scale(scale)
, xf4_(f1)
, xf8_(f2)
, xf4_boidSpacing(f1)
, xf8_height(f2)
, xfc_(f3)
, x100_(f4)
, x100_weaponDamageRadius(f4)
, x104_(f5)
, x108_(f6)
, x10c_(f7)
@ -31,37 +40,393 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na
, x120_(f12)
, x124_(f13)
, x128_(f14)
, x15c_dInfo(dInfo)
, x140_24_hasGround(false)
, x140_25_modelAssetDirty(false)
, x140_26_playerTouching(false)
, x15c_damageInfo(dInfo)
, x1c8_boidPositions(std::make_unique<std::vector<zeus::CVector3f>>())
, x1cc_boidPlacement(std::make_unique<std::vector<EBoidPlacement>>())
, 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<CModelData>(animRes));
x1b4_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b4_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b4_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b0_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b0_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b0_modelData.emplace_back(std::make_unique<CModelData>(animRes));
x1b0_modelData.emplace_back(std::make_unique<CModelData>(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<CElementGen>(x1dc_);
x1dc_particleGenDesc = g_SimplePool->GetObj({FOURCC('PART'), w4});
x1ec_particleGen1 = std::make_unique<CElementGen>(x1dc_particleGenDesc);
}
if (w6.IsValid()) {
x1dc_ = g_SimplePool->GetObj({FOURCC('PART'), w6});
x1f4_ = std::make_unique<CElementGen>(x1dc_);
x1dc_particleGenDesc = g_SimplePool->GetObj({FOURCC('PART'), w6});
x1f4_particleGen2 = std::make_unique<CElementGen>(x1dc_particleGenDesc);
}
}
void CSnakeWeedSwarm::Accept(urde::IVisitor& visitor) { visitor.Visit(this); }
void CSnakeWeedSwarm::AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which) {
for (int i = 0; i < 4; ++i) {
const auto& modelData = x1b0_modelData[i];
modelData->EnableLooping(true);
modelData->AdvanceAnimation(modelData->GetAnimationData()->GetAnimTimeRemaining("Whole Body"sv) * (i * 0.25f), mgr,
x4_areaId, true);
}
x1c4_which = which;
}
void CSnakeWeedSwarm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId id, CStateManager& mgr) {
CActor::AcceptScriptMsg(msg, id, mgr);
if (msg == EScriptObjectMessage::Deleted) {
if (x1d8_sfxHandle) {
CSfxManager::RemoveEmitter(x1d8_sfxHandle);
x1d8_sfxHandle.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_touchBounds)) {
xe4_30_outOfFrustum = true;
return;
}
xe4_30_outOfFrustum = false;
for (const auto& modelData : x1b0_modelData) {
modelData->GetAnimationData()->PreRender();
}
if (x90_actorLights && x140_24_hasGround) {
bool buildLights = false;
if (xe4_29_actorLightsDirty) {
buildLights = true;
xe4_29_actorLightsDirty = false;
} else if (x90_actorLights->GetIsDirty()) {
buildLights = true;
}
if (xe4_31_calculateLighting && x90_actorLights) {
auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
if (visor == CPlayerState::EPlayerVisor::Thermal) {
x90_actorLights->BuildConstantAmbientLighting(zeus::skWhite);
} else if (buildLights && x4_areaId != kInvalidAreaId) {
CGameArea* area = mgr.GetWorld()->GetArea(x4_areaId);
if (area != nullptr) {
x90_actorLights->BuildAreaLightList(mgr, *area, x144_touchBounds);
}
}
x90_actorLights->BuildDynamicLightList(mgr, x144_touchBounds);
}
}
}
void CSnakeWeedSwarm::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
if (xe4_30_outOfFrustum)
return;
if (x1ec_particleGen1)
g_Renderer->AddParticleGen(*x1ec_particleGen1);
if (x1f4_particleGen2)
g_Renderer->AddParticleGen(*x1f4_particleGen2);
if (x90_actorLights) {
for (const auto& modelData : x1b0_modelData) {
x90_actorLights->ActivateLights(*modelData->PickAnimatedModel(x1c4_which).GetModelInst());
}
} else {
CGraphics::DisableAllLights();
g_Renderer->SetAmbientColor(zeus::skWhite);
}
u32 posesToBuild = -1;
for (u32 i = 0; i < x134_boids.size(); ++i)
RenderBoid(i, x134_boids[i], posesToBuild);
CGraphics::DisableAllLights();
}
void CSnakeWeedSwarm::Touch(CActor& actor, CStateManager& mgr) {
if (TCastToPtr<CGameProjectile> proj = actor) {
if (proj->GetDamageInfo().GetWeaponMode().GetType() != EWeaponType::AI)
HandleRadiusDamage(x100_weaponDamageRadius, mgr, proj->GetTransform().origin);
}
if (TCastToPtr<CPlayer> player = actor) {
for (const auto& boid : x134_boids) {
float m = (boid.GetPosition() - player->GetTransform().origin).magnitude();
if (m < x104_ && boid.GetState() == EBoidState::Raised) {
mgr.SendScriptMsg(player, kInvalidUniqueId, EScriptObjectMessage::InSnakeWeed);
x140_26_playerTouching = true;
}
}
}
}
void CSnakeWeedSwarm::HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos) {
float radiusSquared = radius * radius;
for (auto& boid : x134_boids) {
const zeus::CVector3f& boidPosition = boid.GetPosition();
if ((boidPosition - pos).magSquared() < radiusSquared &&
(boid.GetState() == EBoidState::Raised || boid.GetState() == EBoidState::Raising)) {
boid.SetState(EBoidState::x3);
boid.Set_x18(x118_ * mgr.GetActiveRandom()->Float() + 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)
return;
if (x1ec_particleGen1)
x1ec_particleGen1->Update(dt);
if (x1f4_particleGen2)
x1f4_particleGen2->Update(dt);
x204_particleTimer -= dt;
bool emitParticle = false;
if (x204_particleTimer < 0.f) {
x204_particleTimer = 0.f;
emitParticle = true;
}
if (!x140_24_hasGround)
FindGround(mgr);
if (x140_24_hasGround && x1c8_boidPositions && !x1c8_boidPositions->empty()) {
int n = (u64)(dt * x1cc_boidPlacement->size()) >> 0x20;
CreateBoids(mgr, n + 1);
}
CModelData::EWhichModel model = CModelData::GetRenderingModel(mgr);
if (x140_25_modelAssetDirty && x1c4_which != model)
AllocateSkinnedModels(mgr, model);
for (const auto& modelData : x1b0_modelData) {
modelData->GetAnimationData()->SetPlaybackRate(1.f);
modelData->AdvanceAnimation(dt, mgr, x4_areaId, true);
}
int raisedBoids = 0;
for (auto& boid : x134_boids) {
const zeus::CVector3f& pos = boid.GetPosition();
const EBoidState state = boid.GetState();
if (state == EBoidState::Raised) {
raisedBoids++;
if (x1f4_particleGen2 && emitParticle) {
EmitParticles2(pos);
}
} else if (state == EBoidState::Raising) {
boid.SetYOffset(boid.GetYOffset() - dt * boid.Get_x18());
if (boid.GetYOffset() <= 0.f) {
boid.SetYOffset(0.f);
boid.SetState(EBoidState::Raised);
}
} else if (state == EBoidState::x2) {
boid.Set_x10(boid.Get_x10() - dt);
if (boid.Get_x10() <= 0.f) {
boid.SetState(EBoidState::Raising);
CSfxManager::AddEmitter(x1d4_sfx3, pos, zeus::skZero3f, true, false, 0x7f, x4_areaId);
EmitParticles1(pos);
}
} else if (state == EBoidState::x3) {
boid.SetYOffset(dt * boid.Get_x18() + boid.GetYOffset());
const float max = x110_ * boid.Get_x20();
if (boid.GetYOffset() >= max) {
boid.SetYOffset(max);
boid.Set_x10(x10c_ * mgr.GetActiveRandom()->Float() + x108_);
boid.SetState(EBoidState::x2);
}
}
}
if (raisedBoids == 0) {
if (x1d8_sfxHandle) {
CSfxManager::RemoveEmitter(x1d8_sfxHandle);
x1d8_sfxHandle.reset();
}
} else if (!x1d8_sfxHandle) {
x1d8_sfxHandle =
CSfxManager::AddEmitter(x1d0_sfx1, GetTransform().origin, zeus::skZero3f, true, true, 0x7f, x4_areaId);
}
if (x140_26_playerTouching) {
mgr.ApplyDamage(x8_uid, mgr.GetPlayer().GetUniqueId(), x8_uid, CDamageInfo(x15c_damageInfo, dt), matFilter,
zeus::skZero3f);
}
x140_26_playerTouching = false;
}
zeus::CAABox CSnakeWeedSwarm::GetBoidBox() {
const zeus::CVector3f& scale = xe8_scale * 0.75f;
return zeus::CAABox(GetTransform().origin - scale, GetTransform().origin + scale);
}
void CSnakeWeedSwarm::FindGround(const CStateManager& mgr) {
const zeus::CAABox& box = GetBoidBox();
const CRayCastResult& result =
mgr.RayStaticIntersection(box.center(), zeus::skDown, box.max.z() - box.min.z(), matFilter);
if (result.IsValid()) {
int ct = GetNumBoidsX() * GetNumBoidsY();
x134_boids.reserve(ct);
x1c8_boidPositions->reserve(ct);
x1c8_boidPositions->push_back(result.GetPoint());
x1cc_boidPlacement->resize(ct, EBoidPlacement::None);
x140_24_hasGround = true;
}
}
int CSnakeWeedSwarm::GetNumBoidsY() {
const zeus::CAABox& box = GetBoidBox();
return (int)((box.max.y() - box.min.y()) / xf4_boidSpacing) + 1;
}
int CSnakeWeedSwarm::GetNumBoidsX() {
const zeus::CAABox& box = GetBoidBox();
return (int)((box.max.x() - box.min.x()) / xf4_boidSpacing) + 1;
}
void CSnakeWeedSwarm::CreateBoids(CStateManager& mgr, int num) {
int width = GetNumBoidsX();
for (int i = 0; i < num; ++i) {
if (x1c8_boidPositions->empty())
break;
const zeus::CVector3f pos = x1c8_boidPositions->back();
x1c8_boidPositions->pop_back();
const zeus::CVector2i& idx = GetBoidIndex(pos);
if (CreateBoid(pos, mgr)) {
x1cc_boidPlacement->at(idx.x + width * idx.y) = EBoidPlacement::Placed;
AddBoidPosition(zeus::CVector3f(pos.x(), pos.y() - xf4_boidSpacing, pos.z()));
AddBoidPosition(zeus::CVector3f(pos.x(), xf4_boidSpacing + pos.y(), pos.z()));
AddBoidPosition(zeus::CVector3f(pos.x() - xf4_boidSpacing, pos.y(), pos.z()));
AddBoidPosition(zeus::CVector3f(xf4_boidSpacing + pos.x(), pos.y(), pos.z()));
} else {
x1cc_boidPlacement->at(idx.x + width * idx.y) = EBoidPlacement::Invalid;
}
}
CalculateTouchBounds();
if (x1c8_boidPositions->empty()) {
x1c8_boidPositions = nullptr;
x1cc_boidPlacement = nullptr;
}
}
zeus::CVector2i CSnakeWeedSwarm::GetBoidIndex(const zeus::CVector3f& pos) {
const zeus::CAABox& box = GetBoidBox();
int x = (pos.x() - box.min.x()) / xf4_boidSpacing;
int y = (pos.y() - box.min.y()) / xf4_boidSpacing;
return zeus::CVector2i(x, y);
}
bool CSnakeWeedSwarm::CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr) {
const zeus::CVector3f& pos = vec + zeus::CVector3f(GetBoidOffsetX(vec), GetBoidOffsetY(vec), xf8_height);
const CRayCastResult& result = mgr.RayStaticIntersection(pos, zeus::skDown, 2.f * xf8_height, matFilter);
if (result.IsValid() && result.GetPlane().normal().dot(zeus::skUp) > x11c_) {
const zeus::CVector3f& boidPosition = result.GetPoint() - zeus::CVector3f(0.f, 0.f, x128_);
x134_boids.push_back(
{boidPosition, x110_, x114_ + x118_, (x124_ - x120_) * mgr.GetActiveRandom()->Float() + x120_});
return true;
}
return false;
}
float CSnakeWeedSwarm::GetBoidOffsetY(const zeus::CVector3f& pos) {
float f = 2.4729404f * pos.y() + 0.3478602f * pos.x() * pos.x();
return xfc_ * (2.f * std::abs(f - std::trunc(f)) - 1.f);
}
float CSnakeWeedSwarm::GetBoidOffsetX(const zeus::CVector3f& pos) {
float f = 8.21395f * pos.x() + 0.112869f * pos.y() * pos.y();
return xfc_ * (2.f * std::abs(f - std::trunc(f)) - 1.f);
}
void CSnakeWeedSwarm::AddBoidPosition(const zeus::CVector3f& pos) {
int x = GetNumBoidsX();
int y = GetNumBoidsY();
const zeus::CVector2i& v = GetBoidIndex(pos);
if (-1 < v.x && v.x < x && -1 < v.y && v.y < y) {
int idx = v.x + x * v.y;
if (x1cc_boidPlacement->at(idx) == EBoidPlacement::None) {
x1cc_boidPlacement->at(idx) = EBoidPlacement::Ready;
x1c8_boidPositions->push_back(pos);
}
}
}
void CSnakeWeedSwarm::CalculateTouchBounds() {
if (x134_boids.empty()) {
x144_touchBounds = zeus::CAABox(GetTransform().origin, GetTransform().origin);
} else {
x144_touchBounds = zeus::skInvertedBox;
for (const auto& boid : x134_boids) {
x144_touchBounds.accumulateBounds(boid.GetPosition() - x100_weaponDamageRadius);
x144_touchBounds.accumulateBounds(boid.GetPosition() + x100_weaponDamageRadius);
}
}
xe4_27_notInSortedLists = true;
}
void CSnakeWeedSwarm::EmitParticles1(const zeus::CVector3f& pos) {
if (!x1ec_particleGen1)
return;
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)
return;
x1f4_particleGen2->SetParticleEmission(true);
x1f4_particleGen2->SetTranslation(pos);
x1f4_particleGen2->ForceParticleCreation(1);
x1f4_particleGen2->SetParticleEmission(false);
}
void CSnakeWeedSwarm::RenderBoid(u32 idx, const CBoid& boid, u32& posesToBuild) const {
const u32 modelIdx = idx & 3;
const auto& modelData = x1b0_modelData[modelIdx];
CSkinnedModel& model = modelData->PickAnimatedModel(x1c4_which);
const CModelFlags useFlags(0, 0, 3, zeus::skWhite);
if (posesToBuild & 1 << modelIdx) {
posesToBuild &= ~(1 << modelIdx);
modelData->GetAnimationData()->BuildPose();
model.Calculate(modelData->GetAnimationData()->GetPose(), useFlags, {}, nullptr);
}
const zeus::CTransform& xf =
zeus::CTransform::Translate(boid.GetPosition() - zeus::CVector3f(0.f, 0.f, boid.GetYOffset())) *
zeus::CTransform::Scale(boid.Get_x20());
CGraphics::SetModelMatrix(xf);
modelData->GetAnimationData()->Render(model, useFlags, {}, nullptr);
}
void CSnakeWeedSwarm::ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& mgr) {
EWeaponType type = info.GetWeaponMode().GetType();
if (type == EWeaponType::Bomb || type == EWeaponType::PowerBomb)
HandleRadiusDamage(info.GetRadius(), mgr, pos);
}
std::optional<zeus::CAABox> CSnakeWeedSwarm::GetTouchBounds() const {
if (x140_24_hasGround)
return x144_touchBounds;
return std::nullopt;
}
} // namespace urde

View File

@ -9,11 +9,52 @@ namespace urde {
class CAnimationParameters;
class CSnakeWeedSwarm : public CActor {
public:
enum class EBoidState : u32 {
Raised = 0,
Raising = 1,
x2 = 2,
x3 = 3,
};
enum class EBoidPlacement : u32 {
None = 0,
Ready = 1,
Invalid = 2,
Placed = 3,
};
class CBoid {
zeus::CVector3f x0_pos;
EBoidState xc_state;
float x10_ = 0.f; // some timer
float x14_yOffset;
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::Raising), x14_yOffset(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 GetYOffset() const { return x14_yOffset; }
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 SetYOffset(float v) { x14_yOffset = v; }
constexpr void Set_x18(float v) { x18_ = v; }
};
private:
zeus::CVector3f xe8_scale;
float xf4_;
float xf8_;
float xf4_boidSpacing;
float xf8_height;
float xfc_;
float x100_;
float x100_weaponDamageRadius;
float x104_;
float x108_;
float x10c_;
@ -24,30 +65,29 @@ class CSnakeWeedSwarm : public CActor {
float x120_;
float x124_;
float x128_;
u32 x12c_ = 0;
// x130_
u32 x134_ = 0;
u32 x138_ = 0;
u32 x13c_ = 0;
bool x13c_xbf_modelAssetDirty : 1;
zeus::CAABox x144_ = zeus::skInvertedBox;
CDamageInfo x15c_dInfo;
// x178_ = 0
// x19c_ = 0
rstl::reserved_vector<std::shared_ptr<CModelData>, 4> x1b4_modelData;
// x1c8_ = ptr to 0x10 sz?
// x1cc_ = ptr to 0x10 sz?
// u32 x12c_ = 0;
std::vector<CBoid> x134_boids;
bool x140_24_hasGround : 1;
bool x140_25_modelAssetDirty : 1;
bool x140_26_playerTouching : 1;
zeus::CAABox x144_touchBounds = zeus::skInvertedBox;
CDamageInfo x15c_damageInfo;
// x178_ / x19c_: vectors of CSkinnedModel*, not needed
rstl::reserved_vector<std::shared_ptr<CModelData>, 4> x1b0_modelData;
CModelData::EWhichModel x1c4_which;
std::unique_ptr<std::vector<zeus::CVector3f>> x1c8_boidPositions;
std::unique_ptr<std::vector<EBoidPlacement>> x1cc_boidPlacement;
u16 x1d0_sfx1;
u16 x1d2_sfx2;
u16 x1d4_sfx3;
u32 x1d8_ = 0;
TLockedToken<CGenDescription> x1dc_;
// TLockedToken<CGenDescription> x1e4_; both assign to x1dc_?
std::unique_ptr<CElementGen> x1ec_;
std::unique_ptr<CElementGen> x1f4_;
CSfxHandle x1d8_sfxHandle = 0;
TLockedToken<CGenDescription> x1dc_particleGenDesc;
// TLockedToken<CGenDescription> x1e4_; both assign to x1dc_
std::unique_ptr<CElementGen> x1ec_particleGen1;
std::unique_ptr<CElementGen> x1f4_particleGen2;
u32 x1fc_;
float x200_;
float x204_ = 0.f;
float x204_particleTimer = 0.f;
public:
CSnakeWeedSwarm(TUniqueId, bool, std::string_view, const CEntityInfo&, const zeus::CVector3f&, const zeus::CVector3f&,
@ -56,7 +96,30 @@ public:
CAssetId, float);
void Accept(IVisitor&) override;
void ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& stateMgr) {}
std::optional<zeus::CAABox> GetTouchBounds() const override { /* FIXME check flags */ return x144_; }
void ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& stateMgr);
std::optional<zeus::CAABox> GetTouchBounds() const override;
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 HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos);
void FindGround(const CStateManager& mgr);
zeus::CAABox GetBoidBox();
int GetNumBoidsY();
int GetNumBoidsX();
void CreateBoids(CStateManager& mgr, int num);
zeus::CVector2i GetBoidIndex(const zeus::CVector3f& pos);
bool CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr);
float GetBoidOffsetY(const zeus::CVector3f& pos);
float GetBoidOffsetX(const zeus::CVector3f& pos);
void AddBoidPosition(const zeus::CVector3f& pos);
void CalculateTouchBounds();
void EmitParticles1(const zeus::CVector3f& pos);
void EmitParticles2(const zeus::CVector3f& pos);
void RenderBoid(u32 idx, const CBoid& boid, u32& posesToBuild) const;
};
} // namespace urde

View File

@ -3054,9 +3054,9 @@ CEntity* ScriptLoader::LoadSnakeWeedSwarm(CStateManager& mgr, CInputStream& in,
u32 w1 = in.readUint32Big();
u32 w2 = in.readUint32Big();
u32 w3 = in.readUint32Big();
CAssetId w4 = (propCount < 29 ? -1 : in.readUint32Big());
u32 w5 = (propCount < 29 ? -1 : in.readUint32Big());
CAssetId w6 = (propCount < 29 ? -1 : in.readUint32Big());
CAssetId w4 = (propCount < 29 ? CAssetId() : in.readUint32Big());
u32 w5 = (propCount < 29 ? 0 : in.readUint32Big());
CAssetId w6 = (propCount < 29 ? CAssetId() : in.readUint32Big());
float f16 = (propCount < 29 ? 0.f : in.readFloatBig());
CAnimRes animRes(animParms.GetACSFile(), animParms.GetCharacter(), zeus::skOne3f, animParms.GetInitialAnimation(),