feat: spawner weights (#2006)

* feat: spawner weights

* remove ref

* default weights to 1
This commit is contained in:
David Markowitz
2026-06-19 19:08:15 -07:00
committed by GitHub
parent 308412f46e
commit 7456d6b5c1
5 changed files with 94 additions and 53 deletions

View File

@@ -6,8 +6,10 @@
#include <functional>
#include "GeneralUtils.h"
#include "dZoneManager.h"
#include <algorithm>
#include <ranges>
Spawner::Spawner(const SpawnerInfo info) {
Spawner::Spawner(const SpawnerInfo& info) {
m_Info = info;
m_Active = m_Info.activeOnLoad && info.spawnActivator;
m_EntityInfo = EntityInfo();
@@ -62,10 +64,6 @@ Spawner::Spawner(const SpawnerInfo info) {
}
}
Spawner::~Spawner() {
}
Entity* Spawner::Spawn() {
std::vector<SpawnerNode*> freeNodes;
for (SpawnerNode* node : m_Info.nodes) {
@@ -77,9 +75,25 @@ Entity* Spawner::Spawn() {
return Spawn(freeNodes);
}
Entity* Spawner::Spawn(std::vector<SpawnerNode*> freeNodes, const bool force) {
if (force || ((m_Entities.size() < m_Info.amountMaintained) && (freeNodes.size() > 0) && (m_AmountSpawned < m_Info.maxToSpawn || m_Info.maxToSpawn == -1))) {
SpawnerNode* spawnNode = freeNodes[GeneralUtils::GenerateRandomNumber<int>(0, freeNodes.size() - 1)];
Entity* Spawner::Spawn(const std::vector<SpawnerNode*>& freeNodes, const bool force) {
Entity* spawnedEntity = nullptr;
if (force || ((m_Entities.size() < m_Info.amountMaintained) && !freeNodes.empty() && (m_AmountSpawned < m_Info.maxToSpawn || m_Info.maxToSpawn == -1))) {
// first sum the weights we were provided
int32_t spawnWeight = 0;
for (const auto* const node : freeNodes) spawnWeight += node->weight;
auto chosenWeight = GeneralUtils::GenerateRandomNumber<int32_t>(1, spawnWeight);
// Default to 0 incase something goes wrong in this calc
// Roll the spawner nodes based on their weights, higher weights = more likely to spawn
SpawnerNode* spawnNode = freeNodes[0];
for (auto* const node : freeNodes) {
chosenWeight -= node->weight;
if (chosenWeight <= 0) {
spawnNode = node;
break; // we rolled a spawner
}
}
++m_AmountSpawned;
m_EntityInfo.pos = spawnNode->position;
m_EntityInfo.rot = spawnNode->rotation;
@@ -93,26 +107,24 @@ Entity* Spawner::Spawn(std::vector<SpawnerNode*> freeNodes, const bool force) {
m_EntityInfo.spawnerID = m_Info.spawnerID;
}
Entity* rezdE = Game::entityManager->CreateEntity(m_EntityInfo, nullptr);
spawnedEntity = Game::entityManager->CreateEntity(m_EntityInfo, nullptr);
rezdE->GetGroups() = m_Info.groups;
spawnedEntity->GetGroups() = m_Info.groups;
Game::entityManager->ConstructEntity(rezdE);
Game::entityManager->ConstructEntity(spawnedEntity);
m_Entities.insert({ rezdE->GetObjectID(), spawnNode });
spawnNode->entities.push_back(rezdE->GetObjectID());
m_Entities[spawnedEntity->GetObjectID()] = spawnNode;
spawnNode->entities.push_back(spawnedEntity->GetObjectID());
if (m_Entities.size() == m_Info.amountMaintained) {
m_NeedsUpdate = false;
}
for (const auto& cb : m_EntitySpawnedCallbacks) {
cb(rezdE);
cb(spawnedEntity);
}
return rezdE;
}
return nullptr;
return spawnedEntity;
}
void Spawner::AddSpawnedEntityDieCallback(std::function<void()> callback) {
@@ -148,18 +160,18 @@ void Spawner::SoftReset() {
m_NeedsUpdate = true;
}
void Spawner::SetRespawnTime(float time) {
void Spawner::SetRespawnTime(const float time) {
m_Info.respawnTime = time;
for (size_t i = 0; i < m_WaitTimes.size(); ++i) {
m_WaitTimes[i] = 0;
};
}
m_Start = true;
m_NeedsUpdate = true;
}
void Spawner::SetNumToMaintain(int32_t value) {
void Spawner::SetNumToMaintain(const int32_t value) {
m_Info.amountMaintained = value;
}
@@ -177,15 +189,8 @@ void Spawner::Update(const float deltaTime) {
return;
}
if (!m_NeedsUpdate) return;
if (!m_Active) return;
//if (m_Info.noTimedSpawn) return;
if (m_Info.spawnsOnSmash) {
if (!m_SpawnSmashFoundGroup) {
if (!m_NeedsUpdate || !m_Active || m_Info.spawnsOnSmash) return;
}
return;
}
for (size_t i = 0; i < m_WaitTimes.size(); ) {
m_WaitTimes[i] += deltaTime;
if (m_WaitTimes[i] >= m_Info.respawnTime) {
@@ -198,22 +203,21 @@ void Spawner::Update(const float deltaTime) {
}
}
std::vector<LWOOBJID> Spawner::GetSpawnedObjectIDs() const {
const std::vector<LWOOBJID> Spawner::GetSpawnedObjectIDs() const {
std::vector<LWOOBJID> ids;
ids.reserve(m_Entities.size());
for (const auto& [objId, spawnerNode] : m_Entities) {
for (const auto objId : m_Entities | std::views::keys) {
ids.push_back(objId);
}
return ids;
}
void Spawner::NotifyOfEntityDeath(const LWOOBJID& objectID) {
for (std::function<void()> cb : m_SpawnedEntityDieCallbacks) {
for (const auto& cb : m_SpawnedEntityDieCallbacks) {
cb();
}
m_NeedsUpdate = true;
//m_RespawnTime = 10.0f;
m_WaitTimes.push_back(0.0f);
SpawnerNode* node;
@@ -221,9 +225,7 @@ void Spawner::NotifyOfEntityDeath(const LWOOBJID& objectID) {
if (it != m_Entities.end()) node = it->second;
else return;
if (!node) {
return;
}
if (!node) return;
for (size_t i = 0; i < node->entities.size();) {
if (node->entities[i] && node->entities[i] == objectID)
@@ -249,6 +251,6 @@ void Spawner::Activate() {
}
}
void Spawner::SetSpawnLot(LOT lot) {
void Spawner::SetSpawnLot(const LOT lot) {
m_EntityInfo.lot = lot;
}