/* ** 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: BunkerBusterBehavior.cpp //////////////////////////////////////////////////////////////// // Author: Mark Lorenzen, June 2003 // Desc: Behavior module for Bunker Buster... it kills garrisoned objects /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" #include "Common/Upgrade.h" #include "Common/Player.h" #include "Common/Xfer.h" #include "GameLogic/Module/BunkerBusterBehavior.h" #include "GameLogic/Module/ContainModule.h" #include "GameLogic/Module/AIUpdate.h" #include "GameLogic/GameLogic.h" #include "GameLogic/Object.h" #include "GameLogic/Weapon.h" #include "GameClient/TerrainVisual.h"//Seismic simulations! #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif static DomeStyleSeismicFilter bunkerBusterHeavingEarthSeismicFilter; // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ BunkerBusterBehaviorModuleData::BunkerBusterBehaviorModuleData( void ) { m_upgradeRequired = NULL; m_detonationFX = NULL; m_crashThroughBunkerFX = NULL; m_crashThroughBunkerFXFrequency = 4; m_seismicEffectRadius = 140.0f; m_seismicEffectMagnitude = 6.0f; m_shockwaveWeaponTemplate = NULL; m_occupantDamageWeaponTemplate = NULL; } // end BunkerBusterBehaviorModuleData // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ /*static*/ void BunkerBusterBehaviorModuleData::buildFieldParse( MultiIniFieldParse &p ) { UpdateModuleData::buildFieldParse( p ); static const FieldParse dataFieldParse[] = { { "UpgradeRequired", INI::parseAsciiString, NULL, offsetof( BunkerBusterBehaviorModuleData, m_upgradeRequired ) }, { "DetonationFX", INI::parseFXList, NULL, offsetof( BunkerBusterBehaviorModuleData, m_detonationFX ) }, { "CrashThroughBunkerFX", INI::parseFXList, NULL, offsetof( BunkerBusterBehaviorModuleData, m_crashThroughBunkerFX ) }, { "CrashThroughBunkerFXFrequency", INI::parseDurationUnsignedInt, NULL, offsetof( BunkerBusterBehaviorModuleData, m_crashThroughBunkerFXFrequency ) }, { "SeismicEffectRadius", INI::parseReal, NULL, offsetof( BunkerBusterBehaviorModuleData, m_seismicEffectRadius ) }, { "SeismicEffectMagnitude", INI::parseReal, NULL, offsetof( BunkerBusterBehaviorModuleData, m_seismicEffectMagnitude ) }, { "ShockwaveWeaponTemplate", INI::parseWeaponTemplate, NULL, offsetof( BunkerBusterBehaviorModuleData, m_shockwaveWeaponTemplate ) }, { "OccupantDamageWeaponTemplate", INI::parseWeaponTemplate, NULL, offsetof( BunkerBusterBehaviorModuleData, m_occupantDamageWeaponTemplate ) }, { 0, 0, 0, 0 } }; p.add( dataFieldParse ); } // end buildFieldParse /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ BunkerBusterBehavior::BunkerBusterBehavior( Thing *thing, const ModuleData *modData ) : UpdateModule( thing, modData ) { // THIS HAS AN UPDATE... BECAUSE I FORSEE THE NEED FOR ONE, BUT RIGHT NOW IT DOES NOTHING setWakeFrame( getObject(), UPDATE_SLEEP_NONE ); m_victimID = INVALID_ID; m_upgradeRequired = NULL; } // end BunkerBusterBehavior // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ BunkerBusterBehavior::~BunkerBusterBehavior( void ) { } // end ~BunkerBusterBehavior void BunkerBusterBehavior::onObjectCreated( void ) { const BunkerBusterBehaviorModuleData *modData = getBunkerBusterBehaviorModuleData(); // convert module upgrade name to a pointer m_upgradeRequired = TheUpgradeCenter->findUpgrade( modData->m_upgradeRequired ); } // end onObjectCreated // ------------------------------------------------------------------------------------------------ /** The update callback */ // ------------------------------------------------------------------------------------------------ UpdateSleepTime BunkerBusterBehavior::update( void ) { const BunkerBusterBehaviorModuleData *modData = getBunkerBusterBehaviorModuleData(); AIUpdateInterface *ai = getObject()->getAI(); if ( ai )// is this a SMART bomb? { if ( m_victimID == INVALID_ID ) { Object *victim = ai->getCurrentVictim(); if ( victim ) m_victimID = victim->getID(); DEBUG_ASSERTCRASH( victim, ("BunkerBusterBehavior::update... AIUpdateInterface reports no victim." ) ); } DEBUG_ASSERTCRASH( ai, ("BunkerBusterBehavior::update could not find an AIUpdateInterface." ) ); if ( TheGameLogic->getFrame()%modData->m_crashThroughBunkerFXFrequency == 1 )// not too much { const FXList *crashFX = modData->m_crashThroughBunkerFX; if ( getObject()->testStatus( OBJECT_STATUS_MISSILE_KILLING_SELF ) && crashFX ) FXList::doFXObj( crashFX, getObject() );// CrashFX done on the missile/bomb } } return UPDATE_SLEEP_NONE; } // end update // ------------------------------------------------------------------------------------------------ /** The death callback */ // ------------------------------------------------------------------------------------------------ void BunkerBusterBehavior::onDie( const DamageInfo *damageInfo ) { // do what we came here to do! bustTheBunker(); } // ------------------------------------------------------------------------------------------------ /** The bunker-busting effect callback */ // ------------------------------------------------------------------------------------------------ void BunkerBusterBehavior::bustTheBunker( void ) { const BunkerBusterBehaviorModuleData *modData = getBunkerBusterBehaviorModuleData(); if ( m_upgradeRequired != NULL ) { Bool weaponUpgraded = getObject()->getControllingPlayer()->hasUpgradeComplete( m_upgradeRequired ); if ( ! weaponUpgraded ) return; } // here is where we kill everyone inside any targeted garrisoned buildings // AIUpdateInterface *ai = getObject()->getAI(); Object *target = TheGameLogic->findObjectByID( m_victimID ); Object *objectForFX = getObject(); if ( target ) // Was the pilot aiming at an object? { objectForFX = target; ContainModuleInterface *contain = target->getContain(); if ( contain && contain->isBustable() ) // Was that object something that bunkerbusters bust? { if ( modData->m_occupantDamageWeaponTemplate ) { DamageInfo damageInfo; damageInfo.in.m_damageType = modData->m_occupantDamageWeaponTemplate->getDamageType(); damageInfo.in.m_deathType = modData->m_occupantDamageWeaponTemplate->getDeathType(); damageInfo.in.m_sourceID = getObject()->getID(); damageInfo.in.m_sourcePlayerMask = getObject()->getControllingPlayer()->getPlayerMask(); damageInfo.in.m_amount = 100.0f; contain->harmAndForceExitAllContained( &damageInfo ); // Ouch! } else contain->killAllContained(); } } const FXList *detonationFX = modData->m_detonationFX; if ( detonationFX ) FXList::doFXObj( detonationFX, objectForFX );//DetonationFX done on the building #ifdef DO_SEISMIC_SIMULATIONS // Okay, the right proper way to do this is to add SeismicSim support to FXList... // But until that day, I'm just gonna do it here, sorry, M Lorenzen 6/26/03 SeismicSimulationNode sim( objectForFX->getPosition(), modData->m_seismicEffectRadius, modData->m_seismicEffectMagnitude, &bunkerBusterHeavingEarthSeismicFilter ); TheTerrainVisual->addSeismicSimulation( sim ); #endif if ( modData->m_shockwaveWeaponTemplate ) TheWeaponStore->createAndFireTempWeapon(modData->m_shockwaveWeaponTemplate, objectForFX, objectForFX->getPosition()); } // end onDie // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void BunkerBusterBehavior::crc( Xfer *xfer ) { // extend base class UpdateModule::crc( xfer ); } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void BunkerBusterBehavior::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // extend base class UpdateModule::xfer( xfer ); } // end xfer // ------------------------------------------------------------------------------------------------ /** Load post process */ // ------------------------------------------------------------------------------------------------ void BunkerBusterBehavior::loadPostProcess( void ) { // extend base class UpdateModule::loadPostProcess(); } // end loadPostProcess