/* ** 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: OverchargeBehavior.cpp /////////////////////////////////////////////////////////////////// // Author: Colin Day, June 2002 // Desc: Objects with this behavior module will get the ability to produce more power // for a short amount of time, during this "overcharge" state object health is // slowly reduced /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/Radar.h" #include "Common/Xfer.h" #include "GameLogic/GameLogic.h" #include "GameLogic/Object.h" #include "GameLogic/Module/BodyModule.h" #include "GameLogic/Module/OverchargeBehavior.h" #include "GameLogic/Module/PowerPlantUpdate.h" #include "GameClient/InGameUI.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif //------------------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------ OverchargeBehaviorModuleData::OverchargeBehaviorModuleData( void ) { m_healthPercentToDrainPerSecond = 0.0f; m_notAllowedWhenHealthBelowPercent = 0.0f; } // end OverchargeBehaviorModuleData //------------------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------ /*static*/ void OverchargeBehaviorModuleData::buildFieldParse( MultiIniFieldParse &p ) { UpdateModuleData::buildFieldParse( p ); static const FieldParse dataFieldParse[] = { { "HealthPercentToDrainPerSecond", INI::parsePercentToReal, NULL, offsetof( OverchargeBehaviorModuleData, m_healthPercentToDrainPerSecond ) }, { "NotAllowedWhenHealthBelowPercent", INI::parsePercentToReal, NULL, offsetof( OverchargeBehaviorModuleData, m_notAllowedWhenHealthBelowPercent ) }, { 0, 0, 0, 0 } }; p.add( dataFieldParse ); } // end buildFieldParse /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- OverchargeBehavior::OverchargeBehavior( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData ) { m_overchargeActive = FALSE; // start off sleeping forever until we become active setWakeFrame( getObject(), UPDATE_SLEEP_FOREVER ); } // end OverchargeBehavior //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- OverchargeBehavior::~OverchargeBehavior( void ) { } // end ~OverchargeBehavior //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- UpdateSleepTime OverchargeBehavior::update( void ) { // if the overcharge is active we need to take away some life if( m_overchargeActive ) { Object *us = getObject(); // get mod data const OverchargeBehaviorModuleData *modData = getOverchargeBehaviorModuleData(); // do some damage BodyModuleInterface *body = us->getBodyModule(); DamageInfo damageInfo; damageInfo.in.m_amount = (body->getMaxHealth() * modData->m_healthPercentToDrainPerSecond) / LOGICFRAMES_PER_SECOND; damageInfo.in.m_sourceID = us->getID(); damageInfo.in.m_damageType = DAMAGE_PENALTY; damageInfo.in.m_deathType = DEATH_NORMAL; us->attemptDamage( &damageInfo ); // see if our health is below the allowable threshold if( body->getHealth() < body->getMaxHealth() * modData->m_notAllowedWhenHealthBelowPercent ) { // turn off the overcharge enable( FALSE ); // do some UI info for the local user if this is theirs if( ThePlayerList->getLocalPlayer() == us->getControllingPlayer() ) { // print msg TheInGameUI->message( "GUI:OverchargeExhausted" ); // do radar event TheRadar->createEvent( us->getPosition(), RADAR_EVENT_INFORMATION ); } // end of // do nothing else return UPDATE_SLEEP_NONE; } // end if } // end if return UPDATE_SLEEP_NONE; } // end update // ------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------- void OverchargeBehavior::onDamage( DamageInfo *damageInfo ) { } // end onDie // ------------------------------------------------------------------------------------------------ /** Flip the state of our 'overcharge-ness' */ // ------------------------------------------------------------------------------------------------ void OverchargeBehavior::toggle( void ) { // just toggle using enable() enable( !m_overchargeActive ); } // end toggle // ------------------------------------------------------------------------------------------------ /** Enable or disable an overcharge */ // ------------------------------------------------------------------------------------------------ void OverchargeBehavior::enable( Bool enable ) { Object *us = getObject(); if( enable == FALSE ) { // if we're turned on, turn off if( m_overchargeActive == TRUE ) { // make sure to NOT extend rods for purpose of maintaining proper model condition PowerPlantUpdateInterface *ppui; for( BehaviorModule **umi = getObject()->getBehaviorModules(); *umi; ++umi) { ppui = (*umi)->getPowerPlantUpdateInterface(); if( ppui ) ppui->extendRods(FALSE); } Player *player = us->getControllingPlayer(); if ( player ) player->removePowerBonus(us); // we are no longer active m_overchargeActive = FALSE; // sleep forever setWakeFrame( us, UPDATE_SLEEP_FOREVER ); } // end if } // end if else { // if we're turned off, turn on if( m_overchargeActive == FALSE ) { // make sure to extend rods for purpose of maintaining proper model condition PowerPlantUpdateInterface *ppui; for( BehaviorModule **umi = getObject()->getBehaviorModules(); *umi; ++umi) { ppui = (*umi)->getPowerPlantUpdateInterface(); if( ppui ) ppui->extendRods(TRUE); } // add the power bonus Player *player = us->getControllingPlayer(); if ( player ) player->addPowerBonus(us); // we are now active m_overchargeActive = TRUE; // need to update every frame now setWakeFrame( us, UPDATE_SLEEP_NONE ); } // end if } // end else } // end enable //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void OverchargeBehavior::onDelete( void ) { // if we haven't been upgraded there is nothing to clean up if( m_overchargeActive == FALSE ) return; // remove the power bonus from the player Player *player = getObject()->getControllingPlayer(); if( player ) player->removePowerBonus( getObject() ); m_overchargeActive = FALSE; } // end onDelete //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void OverchargeBehavior::onCapture( Player *oldOwner, Player *newOwner ) { // do nothing if we haven't upgraded yet if( m_overchargeActive == FALSE ) return; if (getObject()->isDisabled()) return; // remove power bonus from old owner if( oldOwner ) oldOwner->removePowerBonus( getObject() ); // add power bonus to the new owner if( newOwner ) newOwner->addPowerBonus( getObject() ); } // end onCapture // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void OverchargeBehavior::crc( Xfer *xfer ) { // extend base class UpdateModule::crc( xfer ); } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void OverchargeBehavior::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // extend base class UpdateModule::xfer( xfer ); // overcharge active xfer->xferBool( &m_overchargeActive ); } // end xfer // ------------------------------------------------------------------------------------------------ /** Load post process */ // ------------------------------------------------------------------------------------------------ void OverchargeBehavior::loadPostProcess( void ) { // extend base class UpdateModule::loadPostProcess(); // Our effect is a fire and forget effect, not an upgrade state that is itself saved, so need to re-fire. if( m_overchargeActive && getObject()->getControllingPlayer() ) getObject()->getControllingPlayer()->addPowerBonus( getObject() ); } // end loadPostProcess