/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: Module.cpp /////////////////////////////////////////////////////////////////////////////// // Author: Colin Day, September 2001 // Desc: Object and drawable modules and actions. These are simply just class // instances that we can assign to objects, drawables, and things to contain // data and code for specific events, or just to hold data /////////////////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "Common/Module.h" #include "Common/Thing.h" #include "Common/INI.h" #include "Common/ThingTemplate.h" #include "Common/Upgrade.h" #include "Common/Xfer.h" #include "GameLogic/Object.h" #include "GameLogic/GameLogic.h" #include "GameLogic/Module/BodyModule.h" #include "GameLogic/Module/CollideModule.h" #include "GameLogic/Module/ContainModule.h" #include "GameLogic/Module/DamageModule.h" #include "GameLogic/Module/DieModule.h" #include "GameLogic/Module/UpdateModule.h" #include "GameLogic/Module/UpgradeModule.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma message("************************************** WARNING, optimization disabled for debugging purposes") #endif /////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- // this method should NEVER be overridden by user code, only via the MAKE_STANDARD_MODULE_xxx macros! // it should also NEVER be called directly; it's only for use by ModuleFactory! /*static*/ ModuleData* Module::friend_newModuleData(INI* ini) { ModuleData* data = MSGNEW("Module::friend_newModuleData") ModuleData; // no need to memorypool these since we never allocate more than one of each if (ini) ini->initFromINI(data, 0); // this is just so that an "end" token is required return data; } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ Module::~Module() { } // end ~Module // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void Module::crc( Xfer *xfer ) { } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void Module::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); } // end xfer // ------------------------------------------------------------------------------------------------ /** load post process */ // ------------------------------------------------------------------------------------------------ void Module::loadPostProcess( void ) { } // end loadPostProcess //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- ObjectModule::ObjectModule( Thing *thing, const ModuleData* moduleData ) : Module(moduleData) { if (!moduleData) { DEBUG_CRASH(("module data may not be null\n")); throw INI_INVALID_DATA; } DEBUG_ASSERTCRASH( thing, ("Thing passed to ObjectModule is NULL!\n") ); m_object = AsObject(thing); DEBUG_ASSERTCRASH( m_object, ("Thing passed to ObjectModule is not an Object!\n") ); } // end ObjectModule //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- ObjectModule::~ObjectModule( void ) { } // end ~ObjectModule // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void ObjectModule::crc( Xfer *xfer ) { // extend base class Module::crc( xfer ); } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void ObjectModule::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // extend base class Module::xfer( xfer ); } // end xfer // ------------------------------------------------------------------------------------------------ /** load post process */ // ------------------------------------------------------------------------------------------------ void ObjectModule::loadPostProcess( void ) { // extend base class Module::loadPostProcess(); } // end loadPostProcess //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- DrawableModule::DrawableModule( Thing *thing, const ModuleData* moduleData ) : Module(moduleData) { if (!moduleData) { DEBUG_CRASH(("module data may not be null\n")); throw INI_INVALID_DATA; } DEBUG_ASSERTCRASH( thing, ("Thing passed to DrawableModule is NULL!\n") ); m_drawable = AsDrawable(thing); DEBUG_ASSERTCRASH( m_drawable, ("Thing passed to DrawableModule is not a Drawable!\n") ); } // end ~DrawableModule //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- DrawableModule::~DrawableModule( void ) { } // end ~DrawableModule // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void DrawableModule::crc( Xfer *xfer ) { // extend base class Module::crc( xfer ); } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void DrawableModule::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // extend base class Module::xfer( xfer ); } // end xfer // ------------------------------------------------------------------------------------------------ /** load post process */ // ------------------------------------------------------------------------------------------------ void DrawableModule::loadPostProcess( void ) { // extend base class Module::loadPostProcess(); } // end loadPostProcess //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void UpgradeMuxData::performUpgradeFX(Object* obj) const { if (m_fxListUpgrade) { FXList::doFXObj(m_fxListUpgrade, obj); } } //------------------------------------------------------------------------------------------------- void UpgradeMuxData::muxDataProcessUpgradeRemoval(Object* obj) const { if( !m_removalUpgradeNames.empty() ) { std::vector::const_iterator it; for( it = m_removalUpgradeNames.begin(); it != m_removalUpgradeNames.end(); it++) { const UpgradeTemplate* theTemplate = TheUpgradeCenter->findUpgrade( *it ); if( !theTemplate && !it->isEmpty() && !it->isNone()) { DEBUG_CRASH(("An upgrade module references %s, which is not an Upgrade", it->str())); throw INI_INVALID_DATA; } obj->removeUpgrade(theTemplate); } } } //------------------------------------------------------------------------------------------------- Bool UpgradeMuxData::isTriggeredBy(const std::string &upgrade) const { std::vector::const_iterator it; for( it = m_triggerUpgradeNames.begin(); it != m_triggerUpgradeNames.end(); ++it) { AsciiString trigger = *it; if (stricmp(trigger.str(), upgrade.c_str()) == 0) { return TRUE; } } return FALSE; } //------------------------------------------------------------------------------------------------- void UpgradeMuxData::getUpgradeActivationMasks(UpgradeMaskType& activation, UpgradeMaskType& conflicting) const { // already computed. if (!m_activationUpgradeNames.empty() || !m_conflictingUpgradeNames.empty()) { m_activationMask.clear(); m_conflictingMask.clear(); std::vector::const_iterator it; for( it = m_activationUpgradeNames.begin(); it != m_activationUpgradeNames.end(); it++) { const UpgradeTemplate* theTemplate = TheUpgradeCenter->findUpgrade( *it ); if( !theTemplate && !it->isEmpty() && !it->isNone()) { DEBUG_CRASH(("An upgrade module references %s, which is not an Upgrade", it->str())); throw INI_INVALID_DATA; } m_activationMask.set( theTemplate->getUpgradeMask() ); } for( it = m_conflictingUpgradeNames.begin(); it != m_conflictingUpgradeNames.end(); it++) { const UpgradeTemplate* theTemplate = TheUpgradeCenter->findUpgrade( *it ); if( !theTemplate && !it->isEmpty() && !it->isNone()) { DEBUG_CRASH(("An upgrade module references %s, which is not an Upgrade", it->str())); throw INI_INVALID_DATA; } m_conflictingMask.set( theTemplate->getUpgradeMask() ); } // We set the trigger upgrade names with the activationUpgradeNames entries to be used later. // We have to do this because the activationUpgradeNames are toasted just below. m_triggerUpgradeNames = m_activationUpgradeNames; //Clear the names now that we've cached the values! m_activationUpgradeNames.clear(); m_conflictingUpgradeNames.clear(); } activation = m_activationMask; conflicting = m_conflictingMask; }