diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index f9f5b5a0a18..3d27e808a26 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -20,6 +20,7 @@ // not const -- we might override from INI static PoolSizeRec PoolSizes[] = { + { "ArmorTemplatePool", 64, 8 }, { "PartitionContactListNode", 2048, 512 }, { "BattleshipUpdate", 32, 32 }, { "FlyToDestAndDestroyUpdate", 32, 32 }, diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h index b98b2ba8d9e..2daf3747bef 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h @@ -32,6 +32,7 @@ // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "Common/NameKeyGenerator.h" #include "Common/STLTypedefs.h" +#include "Common/Overridable.h" #include "GameLogic/Damage.h" // FORWARD REFERENCES ///////////////////////////////////////////////////////////////////////////// @@ -43,8 +44,19 @@ class ArmorStore; to simulate different materials, and to help make game balance easier to adjust. */ //------------------------------------------------------------------------------------------------- -class ArmorTemplate +class ArmorTemplate : public Overridable { + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ArmorTemplate, "ArmorTemplatePool") + +#if defined(_MSC_VER) && _MSC_VER < 1300 + ArmorTemplate(const ArmorTemplate&) + { + DEBUG_CRASH(("This should never be called")); + } +#else + ArmorTemplate(const ArmorTemplate& that) = delete; +#endif + public: ArmorTemplate(); @@ -99,10 +111,10 @@ class ArmorStore : public SubsystemInterface public: ArmorStore(); - ~ArmorStore(); + virtual ~ArmorStore(); void init() { } - void reset() { } + void reset(); void update() { } const ArmorTemplate* findArmorTemplate(NameKeyType namekey) const; @@ -121,7 +133,9 @@ class ArmorStore : public SubsystemInterface private: - typedef std::hash_map< NameKeyType, ArmorTemplate, rts::hash, rts::equal_to > ArmorTemplateMap; + ArmorTemplate* newOverride(ArmorTemplate *armorTemplate, const char* name); + + typedef std::hash_map< NameKeyType, ArmorTemplate*, rts::hash, rts::equal_to > ArmorTemplateMap; ArmorTemplateMap m_armorTemplates; }; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Armor.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Armor.cpp index 6d4578d1971..f2987b9604f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Armor.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Armor.cpp @@ -54,6 +54,12 @@ ArmorTemplate::ArmorTemplate() clear(); } +//------------------------------------------------------------------------------------------------- +ArmorTemplate::~ArmorTemplate() +{ + +} + //------------------------------------------------------------------------------------------------- void ArmorTemplate::clear() { @@ -112,6 +118,11 @@ ArmorStore::ArmorStore() //------------------------------------------------------------------------------------------------- ArmorStore::~ArmorStore() { + for (ArmorTemplateMap::iterator it = m_armorTemplates.begin(); it != m_armorTemplates.end(); ++it) + { + deleteInstance(it->second); + } + m_armorTemplates.clear(); } @@ -125,7 +136,7 @@ const ArmorTemplate* ArmorStore::findArmorTemplate(NameKeyType namekey) const } else { - return &(*it).second; + return (*it).second; } } @@ -149,11 +160,85 @@ const ArmorTemplate* ArmorStore::findArmorTemplate(const char* name) const { "Armor", ArmorTemplate::parseArmorCoefficients, NULL, 0 } }; - const char *c = ini->getNextToken(); - NameKeyType key = TheNameKeyGenerator->nameToKey(c); - ArmorTemplate& armorTmpl = TheArmorStore->m_armorTemplates[key]; - armorTmpl.clear(); - ini->initFromINI(&armorTmpl, myFieldParse); + const char *name = ini->getNextToken(); + const NameKeyType key = TheNameKeyGenerator->nameToKey(name); + + // TheSuperHackers @bugfix Caball009 04/01/2025 Avoid mismatches by creating overrides instead of overwriting the default data. + // The code resembles the code of the ThingFactory. + ArmorTemplate *armorTmpl = TheArmorStore->m_armorTemplates[key]; + if (!armorTmpl) + { + // no item is present, create a new one + armorTmpl = newInstance(ArmorTemplate); + armorTmpl->clear(); + + if (ini->getLoadType() == INI_LOAD_CREATE_OVERRIDES) + { + // This ArmorTemplate is actually an override, so we will mark it as such so that it properly + // gets deleted on ::reset(). + armorTmpl->markAsOverride(); + } + + TheArmorStore->m_armorTemplates[key] = armorTmpl; + } + else if (ini->getLoadType() != INI_LOAD_CREATE_OVERRIDES) + { + DEBUG_CRASH(( "[LINE: %d in '%s'] Duplicate armor definition %s found!", ini->getLineNum(), ini->getFilename().str(), name )); + } + else + { + armorTmpl = TheArmorStore->newOverride(armorTmpl, name); + } + + ini->initFromINI(armorTmpl, myFieldParse); +} + +//------------------------------------------------------------------------------------------------- +ArmorTemplate* ArmorStore::newOverride(ArmorTemplate *armorTemplate, const char *name) +{ + // sanity + DEBUG_ASSERTCRASH( armorTemplate, ("newOverride(): NULL 'parent' armor template") ); + + // sanity just for debuging, the armor must be in the master list to do overrides + DEBUG_ASSERTCRASH( findArmorTemplate( name ) != NULL, + ("newOverride(): Armor template '%s' not in master list", name) ); + + // find final override of the 'parent' template + ArmorTemplate *child = static_cast(armorTemplate->friend_getFinalOverride()); + + // allocate new template + ArmorTemplate *newTemplate = newInstance(ArmorTemplate); + + // copy data from final override to 'newTemplate' as a set of initial default values + *newTemplate = *child; + + newTemplate->markAsOverride(); + child->setNextOverride(newTemplate); + + // return the newly created override for us to set values with etc + return newTemplate; +} + +//------------------------------------------------------------------------------------------------- +void ArmorStore::reset() +{ + ArmorTemplateMap::iterator it = m_armorTemplates.begin(); + + while (it != m_armorTemplates.end()) + { + ArmorTemplateMap::iterator next = it; + ++next; + + const Overridable *stillValid = it->second->deleteOverrides(); + + if (stillValid == NULL) + { + // Also needs to be removed from the Hash map. + m_armorTemplates.erase(it); + } + + it = next; + } } //-------------------------------------------------------------------------------------------------