CSnakeWeedSwarm: Cleanup, renaming & fixes

This commit is contained in:
Luke Street 2020-02-24 02:55:19 -05:00
parent 34a80aab81
commit 046fbe7760
2 changed files with 280 additions and 297 deletions

View File

@ -15,6 +15,9 @@
namespace urde { namespace urde {
static CMaterialFilter matFilter =
CMaterialFilter::MakeInclude(CMaterialList(EMaterialTypes::Solid, EMaterialTypes::Character));
CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, 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 zeus::CVector3f& pos, const zeus::CVector3f& scale, const CAnimRes& animRes,
const CActorParameters& actParms, float f1, float f2, float f3, float f4, float f5, const CActorParameters& actParms, float f1, float f2, float f3, float f4, float f5,
@ -24,10 +27,10 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na
: CActor(uid, active, name, info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(), : CActor(uid, active, name, info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(),
CMaterialList(EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable), actParms, kInvalidUniqueId) CMaterialList(EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable), actParms, kInvalidUniqueId)
, xe8_scale(scale) , xe8_scale(scale)
, xf4_(f1) , xf4_boidSpacing(f1)
, xf8_(f2) , xf8_height(f2)
, xfc_(f3) , xfc_(f3)
, x100_(f4) , x100_weaponDamageRadius(f4)
, x104_(f5) , x104_(f5)
, x108_(f6) , x108_(f6)
, x10c_(f7) , x10c_(f7)
@ -38,9 +41,9 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na
, x120_(f12) , x120_(f12)
, x124_(f13) , x124_(f13)
, x128_(f14) , x128_(f14)
, x15c_dInfo(dInfo) , x15c_damageInfo(dInfo)
, x1c8_(std::make_unique<std::vector<zeus::CVector3f>>()) , x1c8_boidPositions(std::make_unique<std::vector<zeus::CVector3f>>())
, x1cc_(std::make_unique<std::vector<int>>()) , x1cc_boidPlacement(std::make_unique<std::vector<EBoidPlacement>>())
, x1d0_sfx1(CSfxManager::TranslateSFXID(sfxId1)) , x1d0_sfx1(CSfxManager::TranslateSFXID(sfxId1))
, x1d2_sfx2(CSfxManager::TranslateSFXID(sfxId2)) , x1d2_sfx2(CSfxManager::TranslateSFXID(sfxId2))
, x1d4_sfx3(CSfxManager::TranslateSFXID(sfxId3)) , x1d4_sfx3(CSfxManager::TranslateSFXID(sfxId3))
@ -62,39 +65,33 @@ CSnakeWeedSwarm::CSnakeWeedSwarm(TUniqueId uid, bool active, std::string_view na
x140_25_modelAssetDirty = true; x140_25_modelAssetDirty = true;
} }
if (w4.IsValid()) { if (w4.IsValid()) {
x1dc_ = g_SimplePool->GetObj({FOURCC('PART'), w4}); x1dc_particleGenDesc = g_SimplePool->GetObj({FOURCC('PART'), w4});
x1ec_particleGen1 = std::make_unique<CElementGen>(x1dc_); x1ec_particleGen1 = std::make_unique<CElementGen>(x1dc_particleGenDesc);
} }
if (w6.IsValid()) { if (w6.IsValid()) {
x1dc_ = g_SimplePool->GetObj({FOURCC('PART'), w6}); x1dc_particleGenDesc = g_SimplePool->GetObj({FOURCC('PART'), w6});
x1f4_particleGen2 = std::make_unique<CElementGen>(x1dc_); x1f4_particleGen2 = std::make_unique<CElementGen>(x1dc_particleGenDesc);
} }
} }
void CSnakeWeedSwarm::Accept(urde::IVisitor& visitor) { visitor.Visit(this); } void CSnakeWeedSwarm::Accept(urde::IVisitor& visitor) { visitor.Visit(this); }
void CSnakeWeedSwarm::AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which) { void CSnakeWeedSwarm::AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which) {
// x178_.clear();
// x19c_.clear();
for (int i = 0; i < 4; ++i) { 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]->EnableLooping(true);
x1b0_modelData[i]->AdvanceAnimation( x1b0_modelData[i]->AdvanceAnimation(x1b0_modelData[i]->GetAnimationData()->GetAnimTimeRemaining("Whole Body"sv) *
// TODO calculation may be wrong (i * 0.25f),
x1b0_modelData[i]->GetAnimationData()->GetAnimTimeRemaining("Whole Body"sv) * (i * 0.25f), mgr, x4_areaId, mgr, x4_areaId, true);
true);
} }
x1c4_ = which; x1c4_which = which;
} }
void CSnakeWeedSwarm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId id, CStateManager& mgr) { void CSnakeWeedSwarm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId id, CStateManager& mgr) {
CActor::AcceptScriptMsg(msg, id, mgr); CActor::AcceptScriptMsg(msg, id, mgr);
if (msg == EScriptObjectMessage::Deleted) { if (msg == EScriptObjectMessage::Deleted) {
if (x1d8_) { if (x1d8_sfxHandle) {
CSfxManager::RemoveEmitter(x1d8_); CSfxManager::RemoveEmitter(x1d8_sfxHandle);
x1d8_.reset(); x1d8_sfxHandle.reset();
} }
} else if (msg == EScriptObjectMessage::InitializedInArea) { } else if (msg == EScriptObjectMessage::InitializedInArea) {
AllocateSkinnedModels(mgr, CModelData::EWhichModel::Normal); AllocateSkinnedModels(mgr, CModelData::EWhichModel::Normal);
@ -102,93 +99,86 @@ void CSnakeWeedSwarm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId id, CS
x90_actorLights->SetCastShadows(true); x90_actorLights->SetCastShadows(true);
} }
} }
void CSnakeWeedSwarm::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { void CSnakeWeedSwarm::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
if (frustum.aabbFrustumTest(x144_)) { if (!frustum.aabbFrustumTest(x144_touchBounds)) {
SetCalculateLighting(false); SetCalculateLighting(true);
for (int i = 0; i < 4; ++i) { return;
x1b0_modelData[i]->GetAnimationData()->PreRender(); }
SetCalculateLighting(false);
for (int i = 0; i < 4; ++i) {
x1b0_modelData[i]->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;
} }
bool bVar2 = false; if (xe4_31_calculateLighting && x90_actorLights) {
if (x90_actorLights) { auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
if (x140_24_) { if (visor == CPlayerState::EPlayerVisor::Thermal) {
if (!xe4_29_actorLightsDirty) { x90_actorLights->BuildConstantAmbientLighting(zeus::skWhite);
if (x90_actorLights->GetIsDirty()) { } else if (buildLights && x4_areaId != kInvalidAreaId) {
bVar2 = true; CGameArea* area = mgr.GetWorld()->GetArea(x4_areaId);
} if (area != nullptr) {
} else { x90_actorLights->BuildAreaLightList(mgr, *area, x144_touchBounds);
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_);
}
} }
} }
x90_actorLights->BuildDynamicLightList(mgr, x144_touchBounds);
} }
} else {
SetCalculateLighting(true);
} }
} }
void CSnakeWeedSwarm::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const { void CSnakeWeedSwarm::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
if (!xe4_30_outOfFrustum) { if (xe4_30_outOfFrustum)
if (x1ec_particleGen1) { return;
g_Renderer->AddParticleGen(*x1ec_particleGen1);
} if (x1ec_particleGen1)
if (x1f4_particleGen2) { g_Renderer->AddParticleGen(*x1ec_particleGen1);
g_Renderer->AddParticleGen(*x1f4_particleGen2); if (x1f4_particleGen2)
} g_Renderer->AddParticleGen(*x1f4_particleGen2);
if (x90_actorLights) {
for (auto modelData : x1b0_modelData) { if (x90_actorLights) {
x90_actorLights->ActivateLights(*modelData->PickAnimatedModel(x1c4_).GetModelInst()); for (auto modelData : x1b0_modelData) {
} x90_actorLights->ActivateLights(*modelData->PickAnimatedModel(x1c4_which).GetModelInst());
} 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);
} }
} else {
CGraphics::DisableAllLights(); 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) { void CSnakeWeedSwarm::Touch(CActor& actor, CStateManager& mgr) {
if (TCastToPtr<CGameProjectile> proj = actor) { if (TCastToPtr<CGameProjectile> proj = actor) {
if (proj->GetDamageInfo().GetWeaponMode().GetType() != EWeaponType::AI) { if (proj->GetDamageInfo().GetWeaponMode().GetType() != EWeaponType::AI)
sub_8023ca48(x100_, mgr, proj->GetTransform().origin); HandleRadiusDamage(x100_weaponDamageRadius, mgr, proj->GetTransform().origin);
}
} }
if (TCastToPtr<CPlayer> player = actor) { if (TCastToPtr<CPlayer> player = actor) {
for (auto boid : x134_boids) { for (auto boid : x134_boids) {
float m = (boid.GetPosition() - player->GetTransform().origin).magnitude(); float m = (boid.GetPosition() - player->GetTransform().origin).magnitude();
if (m < x104_ && boid.GetState() == EBoidState::x0) { if (m < x104_ && boid.GetState() == EBoidState::Raised) {
mgr.SendScriptMsg(player, kInvalidUniqueId, EScriptObjectMessage::InSnakeWeed); mgr.SendScriptMsg(player, kInvalidUniqueId, EScriptObjectMessage::InSnakeWeed);
x140_26_ = true; x140_26_playerTouching = true;
} }
} }
} }
} }
void CSnakeWeedSwarm::sub_8023ca48(float radius, CStateManager& mgr, const zeus::CVector3f& pos) { void CSnakeWeedSwarm::HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos) {
float dVar8 = radius * radius; float radiusSquared = radius * radius;
for (auto boid : x134_boids) { for (auto boid : x134_boids) {
const zeus::CVector3f& boidPosition = boid.GetPosition(); const zeus::CVector3f& boidPosition = boid.GetPosition();
if ((boidPosition - pos).magSquared() < dVar8 && if ((boidPosition - pos).magSquared() < radiusSquared &&
(boid.GetState() == EBoidState::x0 || boid.GetState() == EBoidState::x1)) { (boid.GetState() == EBoidState::Raised || boid.GetState() == EBoidState::x1)) {
boid.SetState(EBoidState::x3); boid.SetState(EBoidState::x3);
float random = mgr.GetActiveRandom()->Float(); float random = mgr.GetActiveRandom()->Float();
boid.Set_x18(x118_ * random + x114_); boid.Set_x18(x118_ * random + x114_);
@ -200,240 +190,229 @@ void CSnakeWeedSwarm::sub_8023ca48(float radius, CStateManager& mgr, const zeus:
void CSnakeWeedSwarm::Think(float dt, CStateManager& mgr) { void CSnakeWeedSwarm::Think(float dt, CStateManager& mgr) {
CEntity::Think(dt, mgr); CEntity::Think(dt, mgr);
if (x30_24_active) { if (!x30_24_active)
if (x1ec_particleGen1) { return;
x1ec_particleGen1->Update(dt);
} if (x1ec_particleGen1)
if (x1f4_particleGen2) { x1ec_particleGen1->Update(dt);
x1f4_particleGen2->Update(dt); if (x1f4_particleGen2)
} x1f4_particleGen2->Update(dt);
x204_ -= dt;
bool bVar5 = x204_ < 0.f; x204_particleTimer -= dt;
if (bVar5) { bool emitParticle = false;
x204_ = 0.f; if (x204_particleTimer < 0.f) {
} x204_particleTimer = 0.f;
x204_ = std::max(x204_ - dt, 0.f); emitParticle = true;
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;
} }
if (!x140_24_hasGround)
FindGround(mgr);
if (x140_24_hasGround && x1c8_boidPositions && !x1c8_boidPositions->empty()) {
int n = (u64)(dt * x1cc_boidPlacement->size()) >> 0x20; // TODO ?
CreateBoids(mgr, n + 1);
}
CModelData::EWhichModel model = CModelData::GetRenderingModel(mgr);
if (x140_25_modelAssetDirty && x1c4_which != 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 raisedBoids = 0;
for (auto boid : x134_boids) {
const zeus::CVector3f& pos = boid.GetPosition();
EBoidState state = boid.GetState();
if (state == EBoidState::Raised) {
raisedBoids++;
if (x1f4_particleGen2 && emitParticle) {
EmitParticles2(pos);
}
} else if (state == EBoidState::x1) {
float x14 = boid.Get_x14() - dt * boid.Get_x18();
if (x14 <= 0.f) {
boid.Set_x14(0.f);
boid.SetState(EBoidState::Raised);
} else {
boid.Set_x14(x14);
}
} 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();
float max = x110_ * boid.Get_x20();
if (x14 >= max) {
boid.Set_x14(max);
float random = mgr.GetActiveRandom()->Float();
boid.Set_x10(x10c_ * random + x108_);
boid.SetState(EBoidState::x2);
} else {
boid.Set_x14(x14);
}
}
}
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::sub_8023d3f4() { zeus::CAABox CSnakeWeedSwarm::GetBoidBox() {
const zeus::CVector3f& scale = xe8_scale * 0.75f; const zeus::CVector3f& scale = xe8_scale * 0.75f;
const zeus::CVector3f& min = GetTransform().origin - scale; return zeus::CAABox(GetTransform().origin - scale, GetTransform().origin + scale);
const zeus::CVector3f& max = GetTransform().origin + scale;
return zeus::CAABox(min, max);
} }
static CMaterialList matList1 = CMaterialList(EMaterialTypes::RadarObject, EMaterialTypes::Stone); void CSnakeWeedSwarm::FindGround(const CStateManager& mgr) {
static CMaterialFilter matFilter1 = CMaterialFilter::MakeInclude(matList1); const zeus::CAABox& box = GetBoidBox();
void CSnakeWeedSwarm::sub_8023c238(const CStateManager& mgr) {
const zeus::CAABox& box = sub_8023d3f4();
const CRayCastResult& result = const CRayCastResult& result =
mgr.RayStaticIntersection(box.center(), zeus::skDown, box.max.z() - box.min.z(), matFilter1); mgr.RayStaticIntersection(box.center(), zeus::skDown, box.max.z() - box.min.z(), matFilter);
if (result.IsValid()) { if (result.IsValid()) {
int ct = sub_8023c154() * sub_8023c0fc(); int ct = GetNumBoidsX() * GetNumBoidsY();
x134_boids.reserve(ct); x134_boids.reserve(ct);
x1c8_->reserve(ct); x1c8_boidPositions->reserve(ct);
x1cc_->resize(ct, 0); x1c8_boidPositions->push_back(result.GetPoint());
x1c8_->push_back(result.GetPoint()); x1cc_boidPlacement->resize(ct, EBoidPlacement::None);
x140_24_ = true; x140_24_hasGround = true;
} }
// matFilter.IncludeList().Add(CMaterialList(matFilter.IncludeList().GetValue() >> 0x20));
} }
int CSnakeWeedSwarm::sub_8023c0fc() { int CSnakeWeedSwarm::GetNumBoidsY() {
const zeus::CAABox& box = sub_8023d3f4(); const zeus::CAABox& box = GetBoidBox();
return (int)((box.max.y() - box.min.y()) / xf4_) + 1; return (int)((box.max.y() - box.min.y()) / xf4_boidSpacing) + 1;
} }
int CSnakeWeedSwarm::sub_8023c154() { int CSnakeWeedSwarm::GetNumBoidsX() {
const zeus::CAABox& box = sub_8023d3f4(); const zeus::CAABox& box = GetBoidBox();
return (int)((box.max.x() - box.min.x()) / xf4_) + 1; return (int)((box.max.x() - box.min.x()) / xf4_boidSpacing) + 1;
} }
void CSnakeWeedSwarm::sub_8023bca8(CStateManager& mgr, int v) { void CSnakeWeedSwarm::CreateBoids(CStateManager& mgr, int num) {
int n = sub_8023c154(); int width = GetNumBoidsX();
for (int i = 0; i < v; ++i) { for (int i = 0; i < num; ++i) {
if (x1c8_->empty()) if (x1c8_boidPositions->empty())
break; break;
zeus::CVector3f vec = x1c8_->back(); const zeus::CVector3f pos = x1c8_boidPositions->back();
x1c8_->pop_back(); x1c8_boidPositions->pop_back();
const zeus::CVector2i& v2i = sub_8023c1ac(vec); const zeus::CVector2i& idx = GetBoidIndex(pos);
if (CreateBoid(vec, mgr)) { if (CreateBoid(pos, mgr)) {
x1cc_->at(v2i.x + n * v2i.y) = 3; x1cc_boidPlacement->at(idx.x + width * idx.y) = EBoidPlacement::Placed;
sub_8023bfb8(zeus::CVector3f(vec.x(), vec.y() - xf4_, vec.z())); AddBoidPosition(zeus::CVector3f(pos.x(), pos.y() - xf4_boidSpacing, pos.z()));
sub_8023bfb8(zeus::CVector3f(vec.x(), xf4_ + vec.y(), vec.z())); AddBoidPosition(zeus::CVector3f(pos.x(), xf4_boidSpacing + pos.y(), pos.z()));
sub_8023bfb8(zeus::CVector3f(vec.x() - xf4_, vec.y(), vec.z())); AddBoidPosition(zeus::CVector3f(pos.x() - xf4_boidSpacing, pos.y(), pos.z()));
sub_8023bfb8(zeus::CVector3f(xf4_ + vec.x(), vec.y(), vec.z())); AddBoidPosition(zeus::CVector3f(xf4_boidSpacing + pos.x(), pos.y(), pos.z()));
} else { } else {
x1cc_->at(v2i.x + n * v2i.y) = 2; x1cc_boidPlacement->at(idx.x + width * idx.y) = EBoidPlacement::Invalid;
} }
} }
sub_8023d204(); CalculateTouchBounds();
if (x1c8_->empty()) { if (x1c8_boidPositions->empty()) {
x1c8_ = nullptr; x1c8_boidPositions = nullptr;
x1cc_ = nullptr; x1cc_boidPlacement = nullptr;
} }
} }
zeus::CVector2i CSnakeWeedSwarm::sub_8023c1ac(const zeus::CVector3f& vec) { zeus::CVector2i CSnakeWeedSwarm::GetBoidIndex(const zeus::CVector3f& pos) {
const zeus::CAABox& box = sub_8023d3f4(); const zeus::CAABox& box = GetBoidBox();
int x = (vec.x() - box.min.x()) / xf4_; int x = (pos.x() - box.min.x()) / xf4_boidSpacing;
int y = (vec.y() - box.min.y()) / xf4_; int y = (pos.y() - box.min.y()) / xf4_boidSpacing;
return zeus::CVector2i(x, y); 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) { bool CSnakeWeedSwarm::CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr) {
const zeus::CVector3f pos = vec + zeus::CVector3f(sub_8023bc38(vec), sub_8023bbc8(vec), xf8_); const zeus::CVector3f& pos = vec + zeus::CVector3f(GetBoidOffsetX(vec), GetBoidOffsetY(vec), xf8_height);
const CRayCastResult result = mgr.RayStaticIntersection(pos, zeus::skDown, 2.f * xf8_, matFilter2); const CRayCastResult& result = mgr.RayStaticIntersection(pos, zeus::skDown, 2.f * xf8_height, matFilter);
if (result.IsInvalid() || result.GetPlane().normal().dot(zeus::skUp) <= x11c_) { if (result.IsValid() && result.GetPlane().normal().dot(zeus::skUp) > x11c_) {
return false; const zeus::CVector3f& boidPosition = result.GetPoint() - zeus::CVector3f(0.f, 0.f, x128_);
} else {
const zeus::CVector3f boidPosition = result.GetPoint() - zeus::CVector3f(0.f, 0.f, x128_);
float random = mgr.GetActiveRandom()->Float(); float random = mgr.GetActiveRandom()->Float();
const CBoid boid(boidPosition, x110_, x114_ + x118_, (x124_ - x120_) * random + x120_); const CBoid boid(boidPosition, x110_, x114_ + x118_, (x124_ - x120_) * random + x120_);
x134_boids.push_back(boid); 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; return true;
} }
return false;
} }
float CSnakeWeedSwarm::sub_8023bbc8(const zeus::CVector3f& vec) { float CSnakeWeedSwarm::GetBoidOffsetY(const zeus::CVector3f& pos) {
float f = 2.4729404f * vec.y() + 0.3478602f * vec.x() * vec.x(); float f = 2.4729404f * pos.y() + 0.3478602f * pos.x() * pos.x();
return xfc_ * (2.f * std::abs(f - (int)f) - 1.f); return xfc_ * (2.f * std::abs(f - (int)f) - 1.f);
} }
float CSnakeWeedSwarm::sub_8023bc38(const zeus::CVector3f& vec) { float CSnakeWeedSwarm::GetBoidOffsetX(const zeus::CVector3f& pos) {
float f = 8.21395f * vec.x() + 0.112869f * vec.y() * vec.y(); float f = 8.21395f * pos.x() + 0.112869f * pos.y() * pos.y();
return xfc_ * (2.f * std::abs(f - (int)f) - 1.f); return xfc_ * (2.f * std::abs(f - (int)f) - 1.f);
} }
void CSnakeWeedSwarm::sub_8023bfb8(const zeus::CVector3f& vec) { void CSnakeWeedSwarm::AddBoidPosition(const zeus::CVector3f& pos) {
int x = sub_8023c154(); int x = GetNumBoidsX();
int y = sub_8023c0fc(); int y = GetNumBoidsY();
zeus::CVector2i v = sub_8023c1ac(vec); const zeus::CVector2i& v = GetBoidIndex(pos);
if (-1 < v.x && v.x < x && -1 < v.y && v.y < y) { if (-1 < v.x && v.x < x && -1 < v.y && v.y < y) {
v.x += x * v.y; int idx = v.x + x * v.y;
if (x1cc_->at(v.x) == 0) { if (x1cc_boidPlacement->at(idx) == EBoidPlacement::None) {
x1cc_->at(v.x) = 1; x1cc_boidPlacement->at(idx) = EBoidPlacement::Ready;
x1c8_->push_back(vec); x1c8_boidPositions->push_back(pos);
} }
} }
} }
void CSnakeWeedSwarm::sub_8023d204() { void CSnakeWeedSwarm::CalculateTouchBounds() {
if (x134_boids.empty()) { if (x134_boids.empty()) {
x144_ = zeus::CAABox(GetTransform().origin, GetTransform().origin); x144_touchBounds = zeus::CAABox(GetTransform().origin, GetTransform().origin);
} else { } else {
x144_ = zeus::skInvertedBox; x144_touchBounds = zeus::skInvertedBox;
for (auto boid : x134_boids) { for (auto boid : x134_boids) {
x144_.accumulateBounds(boid.GetPosition() - x100_); x144_touchBounds.accumulateBounds(boid.GetPosition() - x100_weaponDamageRadius);
x144_.accumulateBounds(boid.GetPosition() + x100_); x144_touchBounds.accumulateBounds(boid.GetPosition() + x100_weaponDamageRadius);
} }
} }
xe4_27_notInSortedLists = true; xe4_27_notInSortedLists = true;
} }
void CSnakeWeedSwarm::EmitParticles1(const zeus::CVector3f& pos) { void CSnakeWeedSwarm::EmitParticles1(const zeus::CVector3f& pos) {
if (x1ec_particleGen1) { if (!x1ec_particleGen1)
x1ec_particleGen1->SetParticleEmission(true); return;
x1ec_particleGen1->SetTranslation(pos);
x1ec_particleGen1->ForceParticleCreation(x1fc_); x1ec_particleGen1->SetParticleEmission(true);
x1ec_particleGen1->SetParticleEmission(false); x1ec_particleGen1->SetTranslation(pos);
} x1ec_particleGen1->ForceParticleCreation(x1fc_);
x1ec_particleGen1->SetParticleEmission(false);
} }
void CSnakeWeedSwarm::EmitParticles2(const zeus::CVector3f& pos) { void CSnakeWeedSwarm::EmitParticles2(const zeus::CVector3f& pos) {
if (x1f4_particleGen2) { if (!x1f4_particleGen2)
x1f4_particleGen2->SetParticleEmission(true); return;
x1f4_particleGen2->SetTranslation(pos);
x1f4_particleGen2->ForceParticleCreation(1); x1f4_particleGen2->SetParticleEmission(true);
x1f4_particleGen2->SetParticleEmission(false); x1f4_particleGen2->SetTranslation(pos);
} x1f4_particleGen2->ForceParticleCreation(1);
x1f4_particleGen2->SetParticleEmission(false);
} }
void CSnakeWeedSwarm::RenderBoid(u32 p1, const CBoid* boid, u32* p3) const { void CSnakeWeedSwarm::RenderBoid(u32 p1, const CBoid* boid, u32& posesToBuild) const {
u32 idx = p1 & 3; u32 modelIdx = p1 & 3;
u32 var3 = *p3; auto modelData = x1b0_modelData[modelIdx];
auto modelData = x1b0_modelData[idx]; CSkinnedModel& model = modelData->PickAnimatedModel(x1c4_which);
CSkinnedModel& model = modelData->PickAnimatedModel(x1c4_);
CModelFlags useFlags(0, 0, 3, zeus::skWhite); CModelFlags useFlags(0, 0, 3, zeus::skWhite);
if ((var3 & 1 << idx) != 0) { if ((posesToBuild & 1 << modelIdx) != 0) {
var3 &= ~(1 << idx); posesToBuild &= ~(1 << modelIdx);
modelData->GetAnimationData()->BuildPose(); modelData->GetAnimationData()->BuildPose();
model.Calculate(modelData->GetAnimationData()->GetPose(), useFlags, {}, nullptr); model.Calculate(modelData->GetAnimationData()->GetPose(), useFlags, {}, nullptr);
} }
@ -443,14 +422,18 @@ void CSnakeWeedSwarm::RenderBoid(u32 p1, const CBoid* boid, u32* p3) const {
zeus::CTransform::Scale(boid->Get_x20()); zeus::CTransform::Scale(boid->Get_x20());
g_Renderer->SetModelMatrix(xf); g_Renderer->SetModelMatrix(xf);
model.Draw(useFlags); model.Draw(useFlags);
*p3 = var3;
} }
void CSnakeWeedSwarm::ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& mgr) { void CSnakeWeedSwarm::ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& mgr) {
EWeaponType type = info.GetWeaponMode().GetType(); EWeaponType type = info.GetWeaponMode().GetType();
if (type == EWeaponType::Bomb || type == EWeaponType::PowerBomb) { if (type == EWeaponType::Bomb || type == EWeaponType::PowerBomb)
sub_8023ca48(info.GetRadius(), mgr, pos); HandleRadiusDamage(info.GetRadius(), mgr, pos);
} }
std::optional<zeus::CAABox> CSnakeWeedSwarm::GetTouchBounds() const {
if (x140_24_hasGround)
return x144_touchBounds;
return {};
} }
} // namespace urde } // namespace urde

View File

@ -11,12 +11,19 @@ class CAnimationParameters;
class CSnakeWeedSwarm : public CActor { class CSnakeWeedSwarm : public CActor {
public: public:
enum class EBoidState : u32 { enum class EBoidState : u32 {
x0 = 0, Raised = 0,
x1 = 1, x1 = 1,
x2 = 2, x2 = 2,
x3 = 3, x3 = 3,
}; };
enum class EBoidPlacement : u32 {
None = 0,
Ready = 1,
Invalid = 2,
Placed = 3,
};
class CBoid { class CBoid {
zeus::CVector3f x0_pos; zeus::CVector3f x0_pos;
EBoidState xc_state; EBoidState xc_state;
@ -44,10 +51,10 @@ public:
private: private:
zeus::CVector3f xe8_scale; zeus::CVector3f xe8_scale;
float xf4_; float xf4_boidSpacing;
float xf8_; float xf8_height;
float xfc_; float xfc_;
float x100_; float x100_weaponDamageRadius;
float x104_; float x104_;
float x108_; float x108_;
float x10c_; float x10c_;
@ -58,31 +65,29 @@ private:
float x120_; float x120_;
float x124_; float x124_;
float x128_; float x128_;
u32 x12c_ = 0; // u32 x12c_ = 0;
// x130_
std::vector<CBoid> x134_boids; std::vector<CBoid> x134_boids;
bool x140_24_ : 1; bool x140_24_hasGround : 1;
bool x140_25_modelAssetDirty : 1; bool x140_25_modelAssetDirty : 1;
bool x140_26_ : 1; bool x140_26_playerTouching : 1;
zeus::CAABox x144_ = zeus::skInvertedBox; zeus::CAABox x144_touchBounds = zeus::skInvertedBox;
CDamageInfo x15c_dInfo; CDamageInfo x15c_damageInfo;
// std::vector<std::shared_ptr<CSkinnedModel>> x178_; // x178_ / x19c_: vectors of CSkinnedModel, not needed
// std::vector<std::unique_ptr<CSkinnedModel>> x19c_;
rstl::reserved_vector<std::shared_ptr<CModelData>, 4> x1b0_modelData; rstl::reserved_vector<std::shared_ptr<CModelData>, 4> x1b0_modelData;
CModelData::EWhichModel x1c4_; CModelData::EWhichModel x1c4_which;
std::unique_ptr<std::vector<zeus::CVector3f>> x1c8_; std::unique_ptr<std::vector<zeus::CVector3f>> x1c8_boidPositions;
std::unique_ptr<std::vector<int>> x1cc_; std::unique_ptr<std::vector<EBoidPlacement>> x1cc_boidPlacement;
u16 x1d0_sfx1; u16 x1d0_sfx1;
u16 x1d2_sfx2; u16 x1d2_sfx2;
u16 x1d4_sfx3; u16 x1d4_sfx3;
CSfxHandle x1d8_ = 0; CSfxHandle x1d8_sfxHandle = 0;
TLockedToken<CGenDescription> x1dc_; TLockedToken<CGenDescription> x1dc_particleGenDesc;
// TLockedToken<CGenDescription> x1e4_; both assign to x1dc_? // TLockedToken<CGenDescription> x1e4_; both assign to x1dc_
std::unique_ptr<CElementGen> x1ec_particleGen1; std::unique_ptr<CElementGen> x1ec_particleGen1;
std::unique_ptr<CElementGen> x1f4_particleGen2; std::unique_ptr<CElementGen> x1f4_particleGen2;
u32 x1fc_; u32 x1fc_;
float x200_; float x200_;
float x204_ = 0.f; float x204_particleTimer = 0.f;
public: public:
CSnakeWeedSwarm(TUniqueId, bool, std::string_view, const CEntityInfo&, const zeus::CVector3f&, const zeus::CVector3f&, CSnakeWeedSwarm(TUniqueId, bool, std::string_view, const CEntityInfo&, const zeus::CVector3f&, const zeus::CVector3f&,
@ -92,12 +97,7 @@ public:
void Accept(IVisitor&) override; void Accept(IVisitor&) override;
void ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& stateMgr); void ApplyRadiusDamage(const zeus::CVector3f& pos, const CDamageInfo& info, CStateManager& stateMgr);
std::optional<zeus::CAABox> GetTouchBounds() const override { std::optional<zeus::CAABox> GetTouchBounds() const override;
if (x140_24_) {
return {};
}
return x144_;
}
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override; void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override;
void PreRender(CStateManager&, const zeus::CFrustum&) override; void PreRender(CStateManager&, const zeus::CFrustum&) override;
void AddToRenderer(const zeus::CFrustum&, const CStateManager&) const override; void AddToRenderer(const zeus::CFrustum&, const CStateManager&) const override;
@ -106,20 +106,20 @@ public:
private: private:
void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which); void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which);
void sub_8023ca48(float radius, CStateManager& mgr, const zeus::CVector3f& pos); void HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos);
void sub_8023c238(const CStateManager& mgr); void FindGround(const CStateManager& mgr);
zeus::CAABox sub_8023d3f4(); zeus::CAABox GetBoidBox();
int sub_8023c0fc(); int GetNumBoidsY();
int sub_8023c154(); int GetNumBoidsX();
void sub_8023bca8(CStateManager& mgr, int v); void CreateBoids(CStateManager& mgr, int num);
zeus::CVector2i sub_8023c1ac(const zeus::CVector3f& vec); zeus::CVector2i GetBoidIndex(const zeus::CVector3f& pos);
bool CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr); bool CreateBoid(const zeus::CVector3f& vec, CStateManager& mgr);
float sub_8023bbc8(const zeus::CVector3f& vec); float GetBoidOffsetY(const zeus::CVector3f& pos);
float sub_8023bc38(const zeus::CVector3f& vec); float GetBoidOffsetX(const zeus::CVector3f& pos);
void sub_8023bfb8(const zeus::CVector3f& vec); void AddBoidPosition(const zeus::CVector3f& pos);
void sub_8023d204(); void CalculateTouchBounds();
void EmitParticles1(const zeus::CVector3f& pos); void EmitParticles1(const zeus::CVector3f& pos);
void EmitParticles2(const zeus::CVector3f& pos); void EmitParticles2(const zeus::CVector3f& pos);
void RenderBoid(u32 p1, const CBoid* boid, u32 *p3) const; void RenderBoid(u32 p1, const CBoid* boid, u32& posesToBuild) const;
}; };
} // namespace urde } // namespace urde