| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- ** 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: TransitionDamageFX.cpp ///////////////////////////////////////////////////////////////////
- // Author: Colin Day, March 2002
- // Desc: Damage module capable of launching various effects on damage transitions
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/Xfer.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/FXList.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/ObjectCreationList.h"
- #include "GameLogic/Module/TransitionDamageFX.h"
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- TransitionDamageFXModuleData::TransitionDamageFXModuleData( void )
- {
- Int i, j;
- for( i = 0; i < BODYDAMAGETYPE_COUNT; i++ )
- {
- for( j = 0; j < DAMAGE_MODULE_MAX_FX; j++ )
- {
- m_fxList[ i ][ j ].fx = NULL;
- m_fxList[ i ][ j ].locInfo.loc.x = 0.0f;
- m_fxList[ i ][ j ].locInfo.loc.y = 0.0f;
- m_fxList[ i ][ j ].locInfo.loc.z = 0.0f;
- m_fxList[ i ][ j ].locInfo.locType = FX_DAMAGE_LOC_TYPE_COORD;
- m_fxList[ i ][ j ].locInfo.randomBone = FALSE;
- m_OCL[ i ][ j ].ocl = NULL;
- m_OCL[ i ][ j ].locInfo.loc.x = 0.0f;
- m_OCL[ i ][ j ].locInfo.loc.y = 0.0f;
- m_OCL[ i ][ j ].locInfo.loc.z = 0.0f;
- m_OCL[ i ][ j ].locInfo.locType = FX_DAMAGE_LOC_TYPE_COORD;
- m_OCL[ i ][ j ].locInfo.randomBone = FALSE;
- m_particleSystem[ i ][ j ].particleSysTemplate = NULL;
- m_particleSystem[ i ][ j ].locInfo.loc.x = 0.0f;
- m_particleSystem[ i ][ j ].locInfo.loc.y = 0.0f;
- m_particleSystem[ i ][ j ].locInfo.loc.z = 0.0f;
- m_particleSystem[ i ][ j ].locInfo.locType = FX_DAMAGE_LOC_TYPE_COORD;
- m_particleSystem[ i ][ j ].locInfo.randomBone = FALSE;
- } // end for j
- } // end for i
- m_damageFXTypes = DAMAGE_TYPE_FLAGS_NONE;
- m_damageFXTypes.flip();
- m_damageOCLTypes = DAMAGE_TYPE_FLAGS_NONE;
- m_damageOCLTypes.flip();
- m_damageParticleTypes = DAMAGE_TYPE_FLAGS_NONE;
- m_damageParticleTypes.flip();
- } // end TransitionDamageFXModuleData
- //-------------------------------------------------------------------------------------------------
- /** Parse fx location info ... that is a named bone or a coord3d position */
- //-------------------------------------------------------------------------------------------------
- static void parseFXLocInfo( INI *ini, void *instance, FXLocInfo *locInfo )
- {
- const char *token = ini->getNextToken( ini->getSepsColon() );
- if( stricmp( token, "bone" ) == 0 )
- {
- // save bone name and location type
- locInfo->boneName = AsciiString( ini->getNextToken() );
- locInfo->locType = FX_DAMAGE_LOC_TYPE_BONE;
- //
- // bones are followed by RandomBone:<Yes|No>, if random bone is yes, the bone name is
- // assumed to be a "base bone name" and we will find all the bones with that prefix
- // when picking an effect position. If it's no, the bone name is assumed to be explicit
- //
- token = ini->getNextToken( ini->getSepsColon() );
- if( stricmp( token, "randombone" ) != 0 )
- {
- DEBUG_CRASH(( "parseFXLocInfo: Bone name not followed by RandomBone specifier\nPress IGNORE to see which INI file and line # is incorrect." ));
- throw INI_INVALID_DATA;
- } // end if
- // parse the Bool definition
- ini->parseBool( ini, instance, &locInfo->randomBone, NULL );
- } // end if
- else if( stricmp( token, "loc" ) == 0 )
- {
- // save location and location type
- locInfo->loc.x = ini->scanReal( ini->getNextSubToken("X") );
- locInfo->loc.y = ini->scanReal( ini->getNextSubToken("Y") );
- locInfo->loc.z = ini->scanReal( ini->getNextSubToken("Z") );
- locInfo->locType = FX_DAMAGE_LOC_TYPE_COORD;
- } // end else
- else
- {
- // error
- throw INI_INVALID_DATA;
- } // end else
- } // end parseFXLocInfo
- //-------------------------------------------------------------------------------------------------
- /** In the form of:
- * FXListSlot = <<Bone:BoneName BoneRandom:<Yes|No>> | <Loc: X:x Y:y Z:z>> FXList:FXListName */
- //-------------------------------------------------------------------------------------------------
- void TransitionDamageFXModuleData::parseFXList( INI *ini, void *instance,
- void *store, const void *userData )
- {
- const char *token;
- FXDamageFXListInfo *info = (FXDamageFXListInfo *)store;
- // parse the location bone or location
- parseFXLocInfo( ini, instance, &info->locInfo );
- // make sure we have an "FXList:" token
- token = ini->getNextToken( ini->getSepsColon() );
- if( stricmp( token, "fxlist" ) != 0 )
- {
- // error
- throw INI_INVALID_DATA;
- } // end if
- // parse the fx list name
- ini->parseFXList( ini, instance, &info->fx, NULL );
- } // end parseFXList
- //-------------------------------------------------------------------------------------------------
- /** In the form of:
- * OCLSlot = <<Bone:BoneName BoneRandom:<Yes|No>> | <Loc: X:x Y:y Z:z>> OCL:OCLName */
- //-------------------------------------------------------------------------------------------------
- void TransitionDamageFXModuleData::parseObjectCreationList( INI *ini, void *instance,
- void *store, const void *userData )
- {
- const char *token;
- FXDamageOCLInfo *info = (FXDamageOCLInfo *)store;
- // parse the location bone or location
- parseFXLocInfo( ini, instance, &info->locInfo );
- // make sure we have an "OCL:" token
- token = ini->getNextToken( ini->getSepsColon() );
- if( stricmp( token, "ocl" ) != 0 )
- {
- // error
- throw INI_INVALID_DATA;
- } // end if
- // parse the ocl name
- ini->parseObjectCreationList( ini, instance, store, &info->ocl );
- } // end parseObjectCreationList
- //-------------------------------------------------------------------------------------------------
- /** In the form of:
- * ParticleSlot = <<Bone:BoneName BoneRandom:<Yes|No>> | <Loc: X:x Y:y Z:z>> PSys:PSysName */
- //-------------------------------------------------------------------------------------------------
- void TransitionDamageFXModuleData::parseParticleSystem( INI *ini, void *instance,
- void *store, const void *userData )
- {
- const char *token;
- FXDamageParticleSystemInfo *info = (FXDamageParticleSystemInfo *)store;
- // parse the location bone or location
- parseFXLocInfo( ini, instance, &info->locInfo );
- // make sure we have an "PSys:" token
- token = ini->getNextToken( ini->getSepsColon() );
- if( stricmp( token, "psys" ) != 0 )
- {
- // error
- throw INI_INVALID_DATA;
- } // end if
- // parse the particle system name
- ini->parseParticleSystemTemplate( ini, instance, store, &info->particleSysTemplate );
- } // end parseParticleSystem
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- TransitionDamageFX::TransitionDamageFX( Thing *thing, const ModuleData* moduleData )
- : DamageModule( thing, moduleData )
- {
- Int i, j;
- for( i = 0; i < BODYDAMAGETYPE_COUNT; i++ )
- for( j = 0; j < DAMAGE_MODULE_MAX_FX; j++ )
- m_particleSystemID[ i ][ j ] = INVALID_PARTICLE_SYSTEM_ID;
- } // end TransitionDamageFX
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- TransitionDamageFX::~TransitionDamageFX( void )
- {
- } // end ~TransitionDamageFX
- /*
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void TransitionDamageFX::onDelete( void )
- {
- //
- // we would in theory delete any particle systems we have created and attached, but the
- // particle system will automatically delete itself when the object is destroyed
- //
- } // end onDelete
- */
- //-------------------------------------------------------------------------------------------------
- /** Given an FXLoc info struct, return the effect position that we are supposed to use.
- * The position is local to to the object */
- //-------------------------------------------------------------------------------------------------
- static Coord3D getLocalEffectPos( const FXLocInfo *locInfo, Drawable *draw )
- {
- DEBUG_ASSERTCRASH( locInfo, ("getLocalEffectPos: locInfo is NULL\n") );
- if( locInfo->locType == FX_DAMAGE_LOC_TYPE_BONE && draw )
- {
- if( locInfo->randomBone == FALSE )
- {
- Coord3D pos;
-
- // get the bone position
- Int count = draw->getPristineBonePositions( locInfo->boneName.str(), 0, &pos, NULL, 1 );
- // sanity, if bone not found revert back to location defined in struct (which is 0,0,0)
- if( count == 0 )
- return locInfo->loc;
- // return the position retrieved
- return pos;
- } // end if
- else
- {
- const Int MAX_BONES = 32;
- Coord3D positions[ MAX_BONES ];
- // get the bone positions
- Int boneCount;
- boneCount = draw->getPristineBonePositions( locInfo->boneName.str(), 1, positions, NULL, MAX_BONES );
- // sanity, if bone not found revert back to location defined in struct (which is 0,0,0)
- if( boneCount == 0 )
- return locInfo->loc;
- // pick one of the bone positions
- Int pick = GameLogicRandomValue( 0, boneCount - 1 );
- return positions[ pick ];
- } // end else
- } // end if
- else
- return locInfo->loc;
- } // end getLocalEffectPos
- //-------------------------------------------------------------------------------------------------
- /** Switching damage states */
- //-------------------------------------------------------------------------------------------------
- void TransitionDamageFX::onBodyDamageStateChange( const DamageInfo* damageInfo,
- BodyDamageType oldState,
- BodyDamageType newState )
- {
- Object *damageSource = NULL;
- Int i;
- Drawable *draw = getObject()->getDrawable();
- const TransitionDamageFXModuleData *modData = getTransitionDamageFXModuleData();
- // get the source of the damage if present
- if( damageInfo )
- damageSource = TheGameLogic->findObjectByID( damageInfo->in.m_sourceID );
-
- // remove any particle systems that might be emitting from our old state
- for( i = 0; i < DAMAGE_MODULE_MAX_FX; i++ )
- {
- if( m_particleSystemID[ oldState ][ i ] != INVALID_PARTICLE_SYSTEM_ID )
- {
- TheParticleSystemManager->destroyParticleSystemByID( m_particleSystemID[ oldState ][ i ] );
- m_particleSystemID[ oldState ][ i ] = INVALID_PARTICLE_SYSTEM_ID;
- } // end if
- } // end for i
- //
- // when we are transitioning to a "worse" state we will play a set of effects for that
- // new state to make the transition
- //
- if( IS_CONDITION_WORSE( newState, oldState ) )
- {
- const ParticleSystemTemplate *pSystemT;
- Coord3D pos;
- // if we are restricted by the damage type executing effect, bail out of here
- const DamageInfo *lastDamageInfo = getObject()->getBodyModule()->getLastDamageInfo();
- for( i = 0; i < DAMAGE_MODULE_MAX_FX; i++ )
- {
- // play fx list for our new state
- if( modData->m_fxList[ newState ][ i ].fx )
- {
- if( lastDamageInfo == NULL ||
- getDamageTypeFlag( modData->m_damageFXTypes, lastDamageInfo->in.m_damageType ) )
- {
- pos = getLocalEffectPos( &modData->m_fxList[ newState ][ i ].locInfo, draw );
- getObject()->convertBonePosToWorldPos( &pos, NULL, &pos, NULL );
- FXList::doFXPos( modData->m_fxList[ newState ][ i ].fx, &pos );
- } // end if
- } // end if
-
- // do any object creation list for our new state
- if( modData->m_OCL[ newState ][ i ].ocl )
- {
- if( lastDamageInfo == NULL ||
- getDamageTypeFlag( modData->m_damageOCLTypes, lastDamageInfo->in.m_damageType ) )
- {
- pos = getLocalEffectPos( &modData->m_OCL[ newState ][ i ].locInfo, draw );
- getObject()->convertBonePosToWorldPos( &pos, NULL, &pos, NULL );
- ObjectCreationList::create( modData->m_OCL[ newState ][ i ].ocl,
- getObject(), &pos, damageSource->getPosition(), INVALID_ANGLE );
- } // end if
- } // end if
- // get the template of the system to create
- pSystemT = modData->m_particleSystem[ newState ][ i ].particleSysTemplate;
- if( pSystemT )
- {
- if( lastDamageInfo == NULL ||
- getDamageTypeFlag( modData->m_damageParticleTypes, lastDamageInfo->in.m_damageType ) )
- {
- // create a new particle system based on the template provided
- ParticleSystem* pSystem = TheParticleSystemManager->createParticleSystem( pSystemT );
- if( pSystem )
- {
-
- // get the what is the position we're going to playe the effect at
- pos = getLocalEffectPos( &modData->m_particleSystem[ newState ][ i ].locInfo, draw );
- //
- // set position on system given any bone position provided, the bone position is
- // local to the object and that's what we want for the particle system ... the
- // transormation into world space using the object position is taken care of in
- // the particle system attachToObject method
- //
- pSystem->setPosition( &pos );
- // attach to object
- pSystem->attachToObject( getObject() );
- // save the id of this particle system so we can remove it later if it still exists
- m_particleSystemID[ newState ][ i ] = pSystem->getSystemID();
- } // end if
- } // end if
- } // end if
-
- } // end for i
- } // end if
-
- } // end onBodyDamageStateChange
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void TransitionDamageFX::crc( Xfer *xfer )
- {
- // extend base class
- DamageModule::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void TransitionDamageFX::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- DamageModule::xfer( xfer );
- // particle systems ids
- xfer->xferUser( m_particleSystemID, sizeof( ParticleSystemID ) * BODYDAMAGETYPE_COUNT * DAMAGE_MODULE_MAX_FX );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void TransitionDamageFX::loadPostProcess( void )
- {
- // extend base class
- DamageModule::loadPostProcess();
- } // end loadPostProcess
|