| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: FirestormDynamicGeometryInfoUpdate.cpp //////////////////////////////////////////////////////////////////////////
- // Author: Graham Smallwood, April 2002
- // Desc: Update module adds the molestation of a particle system to Geometry changing
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/Player.h"
- #include "Common/Xfer.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/InGameUI.h"
- #include "GameClient/FXList.h"
- #include "GameClient/ParticleSys.h"
- #include "GameLogic/Damage.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #include "GameLogic/TerrainLogic.h"
- #include "GameLogic/Module/FirestormDynamicGeometryInfoUpdate.h"
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- FirestormDynamicGeometryInfoUpdateModuleData::FirestormDynamicGeometryInfoUpdateModuleData() : DynamicGeometryInfoUpdateModuleData()
- {
-
- for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
- m_particleSystem[ i ] = NULL;
- m_fxList = NULL;
- m_particleOffsetZ = 0.0f;
- m_scorchSize = 0.0f;
- m_delayBetweenDamageFrames = 0.0f;
- m_damageAmount = 0.0f;
- m_maxHeightForDamage = 20.0f;
- }
- //-------------------------------------------------------------------------------------------------
- /*static*/ void FirestormDynamicGeometryInfoUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
- {
- DynamicGeometryInfoUpdateModuleData::buildFieldParse(p);
- static const FieldParse dataFieldParse[] =
- {
- { "DelayBetweenDamageFrames", INI::parseDurationReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_delayBetweenDamageFrames ) },
- { "DamageAmount", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_damageAmount ) },
- { "MaxHeightForDamage", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_maxHeightForDamage ) },
- { "ParticleSystem1", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 0 ] ) },
- { "ParticleSystem2", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 1 ] ) },
- { "ParticleSystem3", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 2 ] ) },
- { "ParticleSystem4", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 3 ] ) },
- { "ParticleSystem5", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 4 ] ) },
- { "ParticleSystem6", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 5 ] ) },
- { "ParticleSystem7", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 6 ] ) },
- { "ParticleSystem8", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 7 ] ) },
- { "ParticleSystem9", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 8 ] ) },
- { "ParticleSystem10", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 9 ] ) },
- { "ParticleSystem11", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 10 ] ) },
- { "ParticleSystem12", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 11 ] ) },
- { "ParticleSystem13", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 12 ] ) },
- { "ParticleSystem14", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 13 ] ) },
- { "ParticleSystem15", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 14 ] ) },
- { "ParticleSystem16", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 15 ] ) },
- { "FXList", INI::parseFXList, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_fxList ) },
- { "ParticleOffsetZ", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleOffsetZ ) },
- { "ScorchSize", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_scorchSize ) },
- { 0, 0, 0, 0 }
- };
- p.add(dataFieldParse);
- }
- //-------------------------------------------------------------------------------------------------
- FirestormDynamicGeometryInfoUpdate::FirestormDynamicGeometryInfoUpdate( Thing *thing, const ModuleData* moduleData ) : DynamicGeometryInfoUpdate( thing, moduleData )
- {
-
- for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
- m_myParticleSystemID[ i ] = INVALID_PARTICLE_SYSTEM_ID;
- m_effectsFired = FALSE;
- m_scorchPlaced = FALSE;
- m_lastDamageFrame = 0;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- FirestormDynamicGeometryInfoUpdate::~FirestormDynamicGeometryInfoUpdate( void )
- {
- }
- //-------------------------------------------------------------------------------------------------
- /** The update callback. */
- //-------------------------------------------------------------------------------------------------
- UpdateSleepTime FirestormDynamicGeometryInfoUpdate::update( void )
- {
-
- // extend functionality
- DynamicGeometryInfoUpdate::update();
- // get out of here if we haven't fired yet
- if( m_startingDelayCountdown > 0 )
- return UPDATE_SLEEP_NONE;
- // get the module data
- const FirestormDynamicGeometryInfoUpdateModuleData *modData = getFirestormDynamicGeometryInfoUpdateModuleData();
- // start effects for the first time
- if( m_effectsFired == FALSE )
- {
- ParticleSystem *sys;
- //
- // construct a position to play the particle effects ... that is on the ground, but
- // note that we add a small amount to it to avoid particles from the system (especially
- // flat XY particles) from popping up through the terrain
- //
- Coord3D pos;
- pos.x = getObject()->getPosition()->x;
- pos.y = getObject()->getPosition()->y;
- pos.z = modData->m_particleOffsetZ + TheTerrainLogic->getGroundHeight( pos.x, pos.y );
- // do the particle systems
- for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
- {
- sys = TheParticleSystemManager->createParticleSystem( modData->m_particleSystem[ i ] );
- if( sys )
- {
- sys->setPosition( &pos );
- m_myParticleSystemID[ i ] = sys->getSystemID();
- } // end if
- } // end for i
- // do the FX list
- FXList::doFXObj( modData->m_fxList, getObject() );
- // effects have been fired
- m_effectsFired = TRUE;
- getObject()->getControllingPlayer()->getAcademyStats()->recordFirestormCreated();
- }
- //
- // Parent goes first, and we use part of what he did to alter our bound particle system
- // get and update our running particle system if we have one
- //
- for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
- {
- if( m_myParticleSystemID[ i ] )
- {
- ParticleSystem *sys = TheParticleSystemManager->findParticleSystem( m_myParticleSystemID[ i ] );
-
- if( sys )
- {
- ParticleSystemInfo::EmissionVolumeType type = sys->getEmisionVolumeType();
- if( type == ParticleSystemInfo::EmissionVolumeType::SPHERE )
- sys->setEmissionVolumeSphereRadius( getObject()->getGeometryInfo().getMajorRadius() );
- else if( type == ParticleSystemInfo::EmissionVolumeType::CYLINDER )
- sys->setEmissionVolumeCylinderRadius( getObject()->getGeometryInfo().getMajorRadius() );
- } // end if
- else
- {
- // this system not found (it probably died)... stop trying to find it in the future
- m_myParticleSystemID[ i ] = INVALID_PARTICLE_SYSTEM_ID;
- } // end else
- } // end if
- } // end for, i
- // when we first start running backward ... make a scorch mark
- if( m_switchedDirections == TRUE && m_scorchPlaced == FALSE )
- {
- TheGameClient->addScorch( getObject()->getPosition(), modData->m_scorchSize, SCORCH_1 );
- m_scorchPlaced = TRUE;
- } // end if
- // scan and do some damage every once in a while
- if( TheGameLogic->getFrame() - m_lastDamageFrame >= modData->m_delayBetweenDamageFrames )
- {
- doDamageScan();
- m_lastDamageFrame = TheGameLogic->getFrame();
- } // end if
- return UPDATE_SLEEP_NONE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void FirestormDynamicGeometryInfoUpdate::doDamageScan( void )
- {
- // get the module data
- const FirestormDynamicGeometryInfoUpdateModuleData *modData = getFirestormDynamicGeometryInfoUpdateModuleData();
- // get the object and position
- Object *firestorm = getObject();
- const Coord3D *firestormPos = firestorm->getPosition();
- // setup a damage info structure to do some damage
- DamageInfo damageInfo;
- damageInfo.in.m_damageType = DAMAGE_FLAME;
- damageInfo.in.m_deathType = DEATH_BURNED;
- damageInfo.in.m_sourceID = firestorm->getID();
- damageInfo.in.m_amount = modData->m_damageAmount;
- // get the current bounding circle size for the firestorm
- Real boundingCircle = firestorm->getGeometryInfo().getBoundingCircleRadius();
- // scan objects around us and do damage to objects we have "passed over"
- if( boundingCircle )
- {
- ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( firestormPos,
- boundingCircle,
- FROM_BOUNDINGSPHERE_2D,
- NULL );
- MemoryPoolObjectHolder hold( iter );
- Object *other;
- for( other = iter->first(); other; other = iter->next() )
- {
- // it's too high above us. skip it.
- if (other->getPosition()->z > firestorm->getPosition()->z + modData->m_maxHeightForDamage)
- continue;
- // do damage
- other->attemptDamage( &damageInfo );
- } // end for, other
- } // end if, an boundingCircle radius exists
- } // end doDamageScan
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void FirestormDynamicGeometryInfoUpdate::crc( Xfer *xfer )
- {
- // extend base class
- DynamicGeometryInfoUpdate::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void FirestormDynamicGeometryInfoUpdate::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- DynamicGeometryInfoUpdate::xfer( xfer );
- // particle system ids
- xfer->xferUser( m_myParticleSystemID, sizeof( ParticleSystemID ) * MAX_FIRESTORM_SYSTEMS );
- // effects fired
- xfer->xferBool( &m_effectsFired );
- // scorch placed
- xfer->xferBool( &m_scorchPlaced );
- // last damage frame
- xfer->xferUnsignedInt( &m_lastDamageFrame );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void FirestormDynamicGeometryInfoUpdate::loadPostProcess( void )
- {
- // extend base class
- DynamicGeometryInfoUpdate::loadPostProcess();
- } // end loadPostProcess
|