Skip to content

Commit 04af4f6

Browse files
committed
bugfix(opencontain): Restore retail compatibility after crash fix in OpenContain::killAllContained.
1 parent b18feac commit 04af4f6

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -452,27 +452,42 @@ void OpenContain::killAllContained()
452452
// This scenario can happen if the killed occupant(s) apply deadly damage on death
453453
// to the host container, which then attempts to remove all remaining occupants
454454
// on the death of the host container. This is reproducible by shooting with
455-
// Neutron Shells on a GLA Technical containing GLA Terrorists.
455+
// Neutron Shells on a GLA Technical containing GLA Toxin Terrorists
456+
// with the Chem_SuicideWeapon upgrade, which is automatically granted by the GLA Toxin Command Center.
456457

457-
ContainedItemsList list;
458-
list.swap(m_containList);
459-
m_containListSize = 0;
460-
461-
ContainedItemsList::iterator it = list.begin();
462-
463-
while ( it != list.end() )
458+
ContainedItemsList::iterator it = m_containList.begin();
459+
while ( it != m_containList.end() )
464460
{
465-
Object *rider = *it++;
461+
Object *rider = *it;
466462

467463
DEBUG_ASSERTCRASH( rider, ("Contain list must not contain null element"));
468464
if ( rider )
469465
{
466+
// TheSuperHackers @bugfix Caball009 11/03/2026 The contain list must be updated while iterating over it.
467+
// Swapping the list with a temporary one for safety reasons causes the GLA Demolition Suicide upgrade to apply damage to civilian buildings
468+
// for all garrisoned units instead of the last one that's killed by Neutron Shells.
469+
it = m_containList.erase(it);
470+
--m_containListSize;
471+
470472
onRemoving( rider );
471473
rider->onRemovedFrom( getObject() );
472474
rider->kill();
475+
476+
// After Object::kill, the iterator may or may not be invalidated and the list may or may not be empty.
477+
// Set the iterator to the beginning of the list.
478+
DEBUG_ASSERTCRASH(m_containList.empty() || it == m_containList.begin(), ("Object::kill made an unexpected change to the contain list"));
479+
it = m_containList.begin();
480+
}
481+
else
482+
{
483+
++it;
473484
}
474485
}
475486

487+
DEBUG_ASSERTCRASH(m_containList.empty(), ("killAllContained should have emptied the contain list"));
488+
489+
m_containList.clear();
490+
m_containListSize = 0;
476491
}
477492

478493
//--------------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)