diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp index 460e6d25116..15dfaaadd42 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp @@ -225,6 +225,11 @@ void WeaponSet::xfer( Xfer *xfer ) if (tt == nullptr) throw INI_INVALID_DATA; + // TheSuperHackers @fix bobtista 27/01/2026 findTemplate returns the base template, but Object + // uses getFinalOverride() in its constructor. We must do the same here so m_curWeaponTemplateSet + // points to the same ThingTemplate's weapon sets, avoiding unnecessary reallocation in updateWeaponSet. + tt = static_cast(tt->getFinalOverride()); + m_curWeaponTemplateSet = tt->findWeaponTemplateSet(wsFlags); if (m_curWeaponTemplateSet == nullptr) throw INI_INVALID_DATA; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h b/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h index b7971930c16..98232ecca8a 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h @@ -73,6 +73,9 @@ class ThingFactory : public SubsystemInterface get a template given template database name. return null if not found. note, this is now substantially faster (does a hash-table lookup) */ + // TheSuperHackers @info bobtista 12/08/2026 Keep returning the base template from the hash map. + // Some callers cache this pointer across matches, while reset() deletes map overrides. Code that + // needs the current override must call getFinalOverride() without caching the result. const ThingTemplate *findTemplate( const AsciiString& name, Bool check = TRUE ) { return findTemplateInternal( name, check ); } /** diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp index b8e79f7e9fa..6d87d4d2359 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp @@ -93,6 +93,8 @@ Thing::~Thing() //============================================================================= const ThingTemplate *Thing::getTemplate() const { + // TheSuperHackers @info bobtista 12/08/2026 Resolve the current override here. + // m_template holds the original template pointer and OVERRIDE follows the override chain each time. return m_template; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp index 96b6da59e4d..55dad0973ed 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp @@ -232,6 +232,12 @@ void WeaponSet::xfer( Xfer *xfer ) if (tt == nullptr) throw INI_INVALID_DATA; + // TheSuperHackers @fix bobtista 27/01/2026 Resolve the final override before restoring + // the weapon set. Object::getTemplate() returns the final override, otherwise the next + // updateWeaponSet() sees a different WeaponTemplateSet pointer and recreates the weapons, + // replacing the ammo and reload timing just loaded. + tt = static_cast(tt->getFinalOverride()); + m_curWeaponTemplateSet = tt->findWeaponTemplateSet(wsFlags); if (m_curWeaponTemplateSet == nullptr) throw INI_INVALID_DATA; @@ -294,6 +300,8 @@ void WeaponSet::loadPostProcess( void ) //------------------------------------------------------------------------------------------------- void WeaponSet::updateWeaponSet(const Object* obj) { + // TheSuperHackers @info bobtista 12/08/2026 Compare the set pointers to detect a weapon set change. + // m_curWeaponTemplateSet must belong to obj->getTemplate(), including its final override. const WeaponTemplateSet* set = obj->getTemplate()->findWeaponTemplateSet(obj->getWeaponSetFlags()); DEBUG_ASSERTCRASH(set, ("findWeaponSet should never return null")); if (set && set != m_curWeaponTemplateSet)