@@ -255,66 +255,69 @@ void PoolGroup<Pool>::RemoveOneRelation(uint32 child_pool_id)
255255template <class T >
256256void PoolGroup<T>::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 triggerFrom)
257257{
258- int count = limit - spawns.GetActiveObjectCount (poolId);
259-
260- // If triggered from some object respawn this object is still marked as spawned
261- // and also counted into m_SpawnedPoolAmount so we need increase count to be
262- // spawned by 1
258+ // First clear the object that triggered the respawn, if any.
259+ // DespawnObject is responsible for decrementing the active object counter.
263260 if (triggerFrom)
264- ++count ;
261+ DespawnObject (spawns, triggerFrom) ;
265262
266- if (count > 0 )
267- {
268- PoolObjectList rolledObjects;
269- rolledObjects.reserve (count);
263+ int32 count = limit - spawns.GetActiveObjectCount (poolId);
264+ if (count <= 0 )
265+ return ;
270266
271- // roll objects to be spawned
272- if (!ExplicitlyChanced.empty ())
273- {
274- float roll = (float )rand_chance ();
267+ PoolObjectList candidates;
268+ candidates.reserve (EqualChanced.size () + ExplicitlyChanced.size ());
275269
276- for (PoolObject& obj : ExplicitlyChanced)
277- {
278- roll -= obj.chance ;
279- // Triggering object is marked as spawned at this time and can be also rolled (respawn case)
280- // so this need explicit check for this case
281- if (roll < 0 && (obj.guid == triggerFrom || !spawns.IsActiveObject <T>(obj.guid )))
282- {
283- rolledObjects.push_back (obj);
284- break ;
285- }
286- }
287- }
270+ // Add all not already active candidates.
271+ for (PoolObject& obj : EqualChanced)
272+ if (!spawns.IsActiveObject <T>(obj.guid ))
273+ candidates.push_back (obj);
288274
289- if (!EqualChanced.empty () && rolledObjects.empty ())
290- {
291- std::copy_if (EqualChanced.begin (), EqualChanced.end (), std::back_inserter (rolledObjects), [triggerFrom, &spawns](PoolObject const & object)
292- {
293- return object.guid == triggerFrom || !spawns.IsActiveObject <T>(object.guid );
294- });
275+ for (PoolObject& obj : ExplicitlyChanced)
276+ if (!spawns.IsActiveObject <T>(obj.guid ))
277+ candidates.push_back (obj);
295278
296- Trinity::Containers::RandomResize (rolledObjects, count);
297- }
279+ if (candidates.empty ())
280+ return ;
281+
282+ PoolObjectList rolledObjects;
283+ rolledObjects.reserve (count);
298284
299- // try to spawn rolled objects
300- for (PoolObject& obj : rolledObjects)
285+ // Attempt to select one object based on explicit chance.
286+ if (!ExplicitlyChanced.empty ())
287+ {
288+ float roll = (float )rand_chance ();
289+ for (PoolObject& candidate : candidates)
301290 {
302- if (obj. guid == triggerFrom )
291+ if (candidate. chance > 0 )
303292 {
304- ReSpawn1Object (&obj);
305- triggerFrom = 0 ;
306- }
307- else
308- {
309- spawns.ActivateObject <T>(obj.guid , poolId);
310- Spawn1Object (&obj);
293+ roll -= candidate.chance ;
294+ if (roll < 0 )
295+ {
296+ rolledObjects.push_back (candidate);
297+ std::swap (candidate, candidates.back ());
298+ candidates.pop_back ();
299+ break ; // We only roll for one chanced object.
300+ }
311301 }
312302 }
313303 }
314304
315- // One spawn one despawn no count increase
316- if (triggerFrom)
317- DespawnObject (spawns, triggerFrom);
305+ // Fill the remaining slots with random selections from the rest of the candidates.
306+ uint32 remainingCount = count - rolledObjects.size ();
307+ if (remainingCount > 0 && !candidates.empty ())
308+ {
309+ if (candidates.size () > remainingCount)
310+ Trinity::Containers::RandomResize (candidates, remainingCount);
311+
312+ rolledObjects.insert (rolledObjects.end (), candidates.begin (), candidates.end ());
313+ }
314+
315+ // Spawn all the objects we've selected.
316+ for (PoolObject& objToSpawn : rolledObjects)
317+ {
318+ spawns.ActivateObject <T>(objToSpawn.guid , poolId);
319+ Spawn1Object (&objToSpawn);
320+ }
318321}
319322
320323// Method that is actualy doing the spawn job on 1 creature
0 commit comments