| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395 |
- /*
- ** Command & Conquer Generals(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: ParticleUplinkCannonUpdate.cpp //////////////////////////////////////////////////////////////////////////
- // Author: Kris Morness, September 2002
- // Desc: Update module to handle building states and weapon firing of the particle uplink cannon.
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #define DEFINE_DAMAGE_NAMES
- #define DEFINE_DEATH_NAMES
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "Common\ThingTemplate.h"
- #include "Common\ThingFactory.h"
- #include "Common\Player.h"
- #include "Common\PlayerList.h"
- #include "Common\Xfer.h"
- #include "Common\ClientUpdateModule.h"
- #include "GameClient\ControlBar.h"
- #include "GameClient\GameClient.h"
- #include "GameClient\Drawable.h"
- #include "GameClient\ParticleSys.h"
- #include "GameClient\FXList.h"
- #include "GameLogic\GameLogic.h"
- #include "GameLogic\PartitionManager.h"
- #include "GameLogic\Object.h"
- #include "GameLogic\ObjectIter.h"
- #include "GameLogic\Weaponset.h"
- #include "GameLogic\Weapon.h"
- #include "GameLogic\TerrainLogic.h"
- #include "GameLogic\Module\SpecialPowerModule.h"
- #include "GameLogic\Module\ParticleUplinkCannonUpdate.h"
- #include "GameLogic\Module\PhysicsUpdate.h"
- #include "GameLogic\Module\LaserUpdate.h"
- #include "GameLogic\Module\ActiveBody.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- ParticleUplinkCannonUpdateModuleData::ParticleUplinkCannonUpdateModuleData()
- {
- m_specialPowerTemplate = NULL;
- m_beginChargeFrames = 0;
- m_raiseAntennaFrames = 0;
- m_readyDelayFrames = 0;
- m_outerEffectNumBones = 0;
- m_beamTravelFrames = 0;
- m_widthGrowFrames = 0;
- m_totalFiringFrames = 0;
- m_totalScorchMarks = 0;
- m_scorchMarkScalar = 1.0f;
- m_damageRadiusScalar = 1.0f;
- m_groundHitFX = NULL;
- m_beamLaunchFX = NULL;
- m_framesBetweenLaunchFXRefresh = 30;
- m_totalDamagePulses = 0;
- m_damagePerSecond = 0.0f;
- m_damageType = DAMAGE_LASER;
- m_deathType = DEATH_LASERED;
- m_revealRange = 0.0f;
- m_manualDrivingSpeed = 0.0f;
- m_manualFastDrivingSpeed = 0.0f;
- m_doubleClickToFastDriveDelay = 500;
- //Added by Sadullah Nader
- //Initializations inserted
- m_swathOfDeathAmplitude = 0.0f;
- m_swathOfDeathDistance = 0.0f;
- //
- }
- //-------------------------------------------------------------------------------------------------
- /*static*/ void ParticleUplinkCannonUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
- {
- ModuleData::buildFieldParse(p);
- static const FieldParse dataFieldParse[] =
- {
- { "SpecialPowerTemplate", INI::parseSpecialPowerTemplate, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_specialPowerTemplate ) },
- { "BeginChargeTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_beginChargeFrames ) },
- { "RaiseAntennaTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_raiseAntennaFrames ) },
- { "ReadyDelayTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_readyDelayFrames ) },
- { "WidthGrowTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_widthGrowFrames ) },
- { "BeamTravelTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_beamTravelFrames ) },
- { "TotalFiringTime", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_totalFiringFrames ) },
- { "RevealRange", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_revealRange ) },
-
- { "OuterEffectBoneName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_outerEffectBaseBoneName ) },
- { "OuterEffectNumBones", INI::parseUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_outerEffectNumBones ) },
- { "OuterNodesLightFlareParticleSystem", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_outerNodesLightFlareParticleSystemName ) },
- { "OuterNodesMediumFlareParticleSystem", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_outerNodesMediumFlareParticleSystemName ) },
- { "OuterNodesIntenseFlareParticleSystem", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_outerNodesIntenseFlareParticleSystemName ) },
- { "ConnectorBoneName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_connectorBoneName ) },
- { "ConnectorMediumLaserName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_connectorMediumLaserNameName ) },
- { "ConnectorIntenseLaserName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_connectorIntenseLaserNameName ) },
- { "ConnectorMediumFlare", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_connectorMediumFlareParticleSystemName ) },
- { "ConnectorIntenseFlare", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_connectorIntenseFlareParticleSystemName ) },
- { "FireBoneName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_fireBoneName ) },
- { "LaserBaseLightFlareParticleSystemName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_laserBaseLightFlareParticleSystemName ) },
- { "LaserBaseMediumFlareParticleSystemName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_laserBaseMediumFlareParticleSystemName ) },
- { "LaserBaseIntenseFlareParticleSystemName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_laserBaseIntenseFlareParticleSystemName ) },
- { "ParticleBeamLaserName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_particleBeamLaserName ) },
- { "SwathOfDeathDistance", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_swathOfDeathDistance ) },
- { "SwathOfDeathAmplitude", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_swathOfDeathAmplitude ) },
- { "TotalScorchMarks", INI::parseUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_totalScorchMarks ) },
- { "ScorchMarkScalar", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_scorchMarkScalar ) },
- { "BeamLaunchFX", INI::parseFXList, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_beamLaunchFX ) },
- { "DelayBetweenLaunchFX", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_framesBetweenLaunchFXRefresh ) },
- { "GroundHitFX", INI::parseFXList, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_groundHitFX ) },
- { "DamagePerSecond", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_damagePerSecond ) },
- { "TotalDamagePulses", INI::parseUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_totalDamagePulses ) },
- { "DamageType", INI::parseIndexList, TheDamageNames, offsetof( ParticleUplinkCannonUpdateModuleData, m_damageType ) },
- { "DeathType", INI::parseIndexList, TheDeathNames, offsetof( ParticleUplinkCannonUpdateModuleData, m_deathType ) },
- { "DamageRadiusScalar", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_damageRadiusScalar ) },
- { "PoweringUpSoundLoop", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_powerupSoundName ) },
- { "UnpackToIdleSoundLoop", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_unpackToReadySoundName ) },
- { "FiringToPackSoundLoop", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_firingToIdleSoundName ) },
- { "GroundAnnihilationSoundLoop", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_annihilationSoundName ) },
- { "DamagePulseRemnantObjectName", INI::parseAsciiString, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_damagePulseRemnantObjectName ) },
- { "ManualDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualDrivingSpeed ) },
- { "ManualFastDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualFastDrivingSpeed ) },
- { "DoubleClickToFastDriveDelay", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_doubleClickToFastDriveDelay ) },
- { 0, 0, 0, 0 }
- };
- p.add(dataFieldParse);
- }
- //-------------------------------------------------------------------------------------------------
- ParticleUplinkCannonUpdate::ParticleUplinkCannonUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData )
- {
- m_status = STATUS_IDLE;
- m_laserStatus = LASERSTATUS_NONE;
- m_frames = 0;
- m_specialPowerModule = NULL;
- m_groundToOrbitBeamID = INVALID_DRAWABLE_ID;
- m_orbitToTargetBeamID = INVALID_DRAWABLE_ID;
- m_connectorSystemID = INVALID_PARTICLE_SYSTEM_ID;
- m_laserBaseSystemID = INVALID_PARTICLE_SYSTEM_ID;
- m_connectorNodePosition.zero();
- m_laserOriginPosition.zero();
- m_upBonesCached = false;
- m_defaultInfoCached = false;
- m_invalidSettings = false;
- m_manualTargetMode = false;
- m_initialTargetPosition.zero();
- m_currentTargetPosition.zero();
- m_overrideTargetDestination.zero();
- m_scorchMarksMade= 0;
- m_nextScorchMarkFrame = 0;
- m_nextLaunchFXFrame = 0;
- m_damagePulsesMade = 0;
- m_nextDamagePulseFrame = 0;
- m_startAttackFrame = 0;
- m_startDecayFrame = 0;
- m_lastDrivingClickFrame = 0;
- m_2ndLastDrivingClickFrame = 0;
- m_clientShroudedLastFrame = FALSE;
- for( Int i = 0; i < MAX_OUTER_NODES; i++ )
- {
- m_outerSystemIDs[ i ] = INVALID_PARTICLE_SYSTEM_ID;
- m_laserBeamIDs[ i ] = INVALID_DRAWABLE_ID;
- //Initializing (even though they will get cached properly).
- m_outerNodePositions[ i ].zero();
- m_outerNodeOrientations[ i ].Make_Identity();
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::killEverything()
- {
- removeAllEffects();
- //This laser is independent from the other effects and needs to be specially handled.
- if( m_orbitToTargetBeamID )
- {
- Drawable *beam = TheGameClient->findDrawableByID( m_orbitToTargetBeamID );
- if( beam )
- {
- TheGameClient->destroyDrawable( beam );
- }
- m_orbitToTargetBeamID = INVALID_DRAWABLE_ID;
- }
- TheAudio->removeAudioEvent( m_powerupSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_unpackToReadySound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_firingToIdleSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- ParticleUplinkCannonUpdate::~ParticleUplinkCannonUpdate( void )
- {
- killEverything();
- }
- //-------------------------------------------------------------------------------------------------
- // Validate that we have the necessary data from the ini file.
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::onObjectCreated()
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Object *obj = getObject();
- if( !data->m_specialPowerTemplate )
- {
- DEBUG_CRASH( ("%s object's ParticleUplinkCannonUpdate lacks access to the SpecialPowerTemplate. Needs to be specified in ini.", obj->getTemplate()->getName().str() ) );
- m_invalidSettings = true;
- return;
- }
- m_specialPowerModule = obj->getSpecialPowerModule( data->m_specialPowerTemplate );
- m_connectorNodePosition.set( obj->getPosition() );
- m_laserOriginPosition.set( obj->getPosition() );
- //Create instances of the sounds required.
- m_powerupSound.setEventName( data->m_powerupSoundName );
- m_unpackToReadySound.setEventName( data->m_unpackToReadySoundName );
- m_firingToIdleSound.setEventName( data->m_firingToIdleSoundName );
- m_annihilationSound.setEventName( data->m_annihilationSoundName );
- TheAudio->getInfoForAudioEvent( &m_powerupSound );
- TheAudio->getInfoForAudioEvent( &m_unpackToReadySound );
- TheAudio->getInfoForAudioEvent( &m_firingToIdleSound );
- TheAudio->getInfoForAudioEvent( &m_annihilationSound );
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::initiateIntentToDoSpecialPower(const SpecialPowerTemplate *specialPowerTemplate, const Object *targetObj, const Coord3D *targetPos, UnsignedInt commandOptions, Int locationCount )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- if( m_specialPowerModule->getSpecialPowerTemplate() != specialPowerTemplate )
- {
- //Check to make sure our modules are connected.
- return;
- }
- if( !BitTest( commandOptions, COMMAND_FIRED_BY_SCRIPT ) )
- {
- //All human players have manual control and must "drive" the beam around!
- m_startAttackFrame = TheGameLogic->getFrame();
- m_laserStatus = LASERSTATUS_NONE;
- m_manualTargetMode = true;
- m_initialTargetPosition.set( targetPos );
- m_overrideTargetDestination.set( targetPos );
- m_currentTargetPosition.set( targetPos );
- }
- else
- {
- //All computer controlled players have automatic control -- the "S" curve.
- UnsignedInt now = TheGameLogic->getFrame();
- m_initialTargetPosition.set( targetPos );
- m_startAttackFrame = max( now, (UnsignedInt)1 );
- m_laserStatus = LASERSTATUS_NONE;
- setLogicalStatus( STATUS_READY_TO_FIRE );
- m_specialPowerModule->setReadyFrame( now );
- }
- m_startDecayFrame = m_startAttackFrame + data->m_totalFiringFrames;
- SpecialPowerModuleInterface *spmInterface = getObject()->getSpecialPowerModule( specialPowerTemplate );
- if( spmInterface )
- {
- SpecialPowerModule *spModule = (SpecialPowerModule*)spmInterface;
- spModule->markSpecialPowerTriggered( &m_initialTargetPosition );
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool ParticleUplinkCannonUpdate::isPowerCurrentlyInUse( const CommandButton *command ) const
- {
- if( m_startAttackFrame != 0 && m_startAttackFrame <= TheGameLogic->getFrame() )
- {
- return true;
- }
- return false;
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::setSpecialPowerOverridableDestination( const Coord3D *loc )
- {
- if( !getObject()->isDisabled() )
- {
- m_overrideTargetDestination = *loc;
- m_manualTargetMode = true;
- m_2ndLastDrivingClickFrame = m_lastDrivingClickFrame;
- m_lastDrivingClickFrame = TheGameLogic->getFrame();
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** The update callback. */
- //-------------------------------------------------------------------------------------------------
- UpdateSleepTime ParticleUplinkCannonUpdate::update()
- {
- if( m_invalidSettings )
- {
- // can't return UPDATE_SLEEP_FOREVER unless we are sleepy...
- return UPDATE_SLEEP_NONE;
- ///return UPDATE_SLEEP_FOREVER;
- }
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Object *me = getObject();
- // must test SOLD *before* the others.
- if( me->testStatus(OBJECT_STATUS_SOLD))
- {
- if (m_status != STATUS_IDLE)
- {
- setLogicalStatus( STATUS_IDLE );
- killEverything();
- }
- return UPDATE_SLEEP_NONE;
- }
- if( me->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION) )
- {
- return UPDATE_SLEEP_NONE;
- }
- if( me->isEffectivelyDead() )
- {
- return UPDATE_SLEEP_NONE;
- }
- //Check to see what our status is -- there are a couple:
- //1) Idle while waiting to get near the time when we should be preparing to be ready.
- //2) If superweapon delay is nuked (cheat) then we need to make the building ready now.
- UnsignedInt now = TheGameLogic->getFrame();
- UnsignedInt readyToFireFrame = m_specialPowerModule->isReady() ? now : m_specialPowerModule->getReadyFrame();
- UnsignedInt almostReadyFrame = readyToFireFrame - data->m_readyDelayFrames;
- UnsignedInt raiseAntennaFrame = almostReadyFrame - data->m_raiseAntennaFrames;
- UnsignedInt beginChargeFrame = raiseAntennaFrame - data->m_beginChargeFrames;
- if( m_startAttackFrame != 0 && m_startAttackFrame <= now )
- {
- if( m_startDecayFrame > now )
- {
- if( me->isDisabledByType( DISABLED_UNDERPOWERED ) ||
- me->isDisabledByType( DISABLED_EMP ) ||
- me->isDisabledByType( DISABLED_HACKED ) )
- {
- //We must end the special power early! ABORT! ABORT!
- m_startDecayFrame = now;
- }
- }
- UnsignedInt endDecayFrame = m_startDecayFrame + data->m_widthGrowFrames;
- UnsignedInt orbitalBirthFrame = m_startAttackFrame + data->m_beamTravelFrames;
- UnsignedInt orbitalDecayStart = m_startDecayFrame + data->m_beamTravelFrames;
- UnsignedInt orbitalDeathFrame = orbitalDecayStart + data->m_widthGrowFrames;
- switch( m_laserStatus )
- {
- case LASERSTATUS_NONE:
- //Means we are eligible to fire!
- if( orbitalBirthFrame <= now )
- {
- createOrbitToTargetLaser( data->m_widthGrowFrames );
- m_laserStatus = LASERSTATUS_BORN;
- m_scorchMarksMade = 0;
- m_nextScorchMarkFrame = now;
- m_damagePulsesMade = 0;
- m_nextDamagePulseFrame = now;
- }
- break;
- case LASERSTATUS_BORN:
- {
- Drawable *beam = TheGameClient->findDrawableByID( m_orbitToTargetBeamID );
- if( beam )
- {
- //m_annihilationSound.setPosition( beam->getPosition() );
- if( orbitalDecayStart <= now )
- {
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- update->setDecayFrames( data->m_widthGrowFrames );
- }
- m_laserStatus = LASERSTATUS_DECAYING;
- }
- }
- break;
- }
- case LASERSTATUS_DECAYING:
- {
- Drawable *beam = TheGameClient->findDrawableByID( m_orbitToTargetBeamID );
- if( beam )
- {
- //m_annihilationSound.setPosition( beam->getPosition() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- if( orbitalDeathFrame <= now )
- {
- TheGameClient->destroyDrawable( beam );
- m_orbitToTargetBeamID = INVALID_DRAWABLE_ID;
- m_laserStatus = LASERSTATUS_DEAD;
- m_startAttackFrame = 0;
- setLogicalStatus( STATUS_IDLE );
- }
- }
- break;
- }
- case LASERSTATUS_DEAD:
- //Nothing... this is just a wait state.
- break;
- }
- Drawable *beam = TheGameClient->findDrawableByID( m_orbitToTargetBeamID );
- if( beam && orbitalBirthFrame <= now && now <= orbitalDeathFrame )
- {
-
- if( !m_manualTargetMode )
- {
- //Calculate the position of the beam because it swaths -- a nice S curve centering at the target location!
-
- //First determine the factor of time completed (ranges between 0.0 and 1.0)
- Real factor = (Real)(now - orbitalBirthFrame) / (Real)(orbitalDeathFrame - orbitalBirthFrame);
- //We're generating a swath that travels the points between sin( -1PI ) and sin( 1PI )
- Real radians = (factor * TWO_PI) - PI;
- Real cxDistance = (factor * data->m_swathOfDeathDistance ) - (data->m_swathOfDeathDistance * 0.5f); //cx is cartesian x
- //Now calculate the amplitude value.
- Real height = sin( radians );
- Real cxHeight = height * data->m_swathOfDeathAmplitude;
- Coord3D buildingToInitialTargetVector;
- buildingToInitialTargetVector.set( &m_initialTargetPosition );
- buildingToInitialTargetVector.sub( me->getPosition() );
- Real targetDistance = buildingToInitialTargetVector.length();
- //Calculate the point position assuming the target position is on the x axis relative to the building.
- m_currentTargetPosition.x = cxDistance + targetDistance;
- m_currentTargetPosition.y = cxHeight;
- m_currentTargetPosition.z = 0.0f;
- targetDistance = m_currentTargetPosition.length();
- //Now that we have our cartesian offset relative to the target coordinate, we need to rotate that offset
- //so it's aligned to along the building -> target vector.
- Vector2 buildingToTargetVector( m_initialTargetPosition.x - me->getPosition()->x, m_initialTargetPosition.y - me->getPosition()->y );
- buildingToTargetVector.Normalize();
- Vector2 cartesianTargetVector( m_currentTargetPosition.x, m_currentTargetPosition.y );
- cartesianTargetVector.Normalize();
- Real dotProduct = Vector2::Dot_Product( buildingToTargetVector, cartesianTargetVector );
- dotProduct = __min( 0.99999f, __max( -0.99999f, dotProduct ) ); //Account for numerical errors. Also, acos(-1.00000) is coming out QNAN on the superweapon general map. Heh.
- Real angle = (Real)ACos( dotProduct );
- if( buildingToTargetVector.Y >= 0 )
- {
- angle = -angle;
- }
- Matrix3D mtx( Vector3( 1.0f, 0.0f, 0.0f ) );
- mtx.Scale( targetDistance );
- mtx.Rotate_Z( -angle );
- Vector3 v = mtx.Get_X_Vector();
- m_currentTargetPosition.x = me->getPosition()->x + v.X;
- m_currentTargetPosition.y = me->getPosition()->y + v.Y;
- }
- else
- {
- Real speed = data->m_manualDrivingSpeed;
- if( m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay )
- {
- //Because we double clicked, use the faster driving speed.
- speed = data->m_manualFastDrivingSpeed;
- }
- //Convert speed to speed per frame.
- speed /= LOGICFRAMES_PER_SECOND;
- //Calculate the distance from our current position to our target dest.
- Coord3D vector = m_overrideTargetDestination;
- vector.sub( &m_currentTargetPosition );
- Real distance = vector.length();
- if( distance < speed )
- {
- //Don't allow the speed to overshoot the target point if close.
- speed = distance;
- }
- //Unitize the vector then apply the distance we will move.
- vector.normalize();
- vector.scale( speed );
- //Move the current target position in the desired direction and speed.
- m_currentTargetPosition.x += vector.x;
- m_currentTargetPosition.y += vector.y;
- }
- //Regardless of which method we used to set the target position, make sure the z position is at the terrain.
- m_currentTargetPosition.z = TheTerrainLogic->getGroundHeight( m_currentTargetPosition.x, m_currentTargetPosition.y );
- Coord3D orbitPosition;
- orbitPosition.set( &m_currentTargetPosition );
- orbitPosition.z += 500.0f;
- Real scorchRadius = 0.0f;
- Real damageRadius = 0.0f;
- //Reset the laser position
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- update->initLaser( NULL, &orbitPosition, &m_currentTargetPosition );
- scorchRadius = update->getCurrentLaserRadius() * data->m_scorchMarkScalar;
- damageRadius = update->getCurrentLaserRadius() * data->m_damageRadiusScalar;
- }
- //Create scorch marks periodically
- if( m_nextScorchMarkFrame <= now )
- {
- m_scorchMarksMade++;
- //Create the scorch mark now!
- Scorches scorchID = (Scorches)GameClientRandomValue( SCORCH_1, SCORCH_4 ); //Yes, this is just client fluff!
- TheGameClient->addScorch( &m_currentTargetPosition, scorchRadius, scorchID );
- //Calculate next scorch mark frame.
- Real nextFactor = (Real)m_scorchMarksMade / (Real)data->m_totalScorchMarks;
- m_nextScorchMarkFrame = orbitalBirthFrame + nextFactor * (orbitalDeathFrame - orbitalBirthFrame);
- //Generate iteration of fxlist for beam hitting ground.
- if( data->m_groundHitFX )
- {
- FXList::doFXPos( data->m_groundHitFX, &m_currentTargetPosition, NULL );
- }
- //Also reveal vision because the owning player has full rights to watch the carnage he created!
- ThePartitionManager->doShroudReveal( m_currentTargetPosition.x, m_currentTargetPosition.y, data->m_revealRange, me->getControllingPlayer()->getPlayerMask() );
- ThePartitionManager->undoShroudReveal( m_currentTargetPosition.x, m_currentTargetPosition.y, data->m_revealRange, me->getControllingPlayer()->getPlayerMask() );
- }
- //Handle damage pulses
- if( m_nextDamagePulseFrame <= now )
- {
- m_damagePulsesMade++;
- DamageInfo damageInfo;
- Real totalFiringSeconds = data->m_totalFiringFrames / LOGICFRAMES_PER_SECOND;
- Real damagePerPulse = (Real)(totalFiringSeconds * data->m_damagePerSecond) / (Real)data->m_totalDamagePulses;
- damageInfo.in.m_amount = damagePerPulse;
- damageInfo.in.m_sourceID = me->getID();
- damageInfo.in.m_damageType = data->m_damageType;
- damageInfo.in.m_deathType = data->m_deathType;
- PartitionFilterAlive filterAlive;
- PartitionFilter *filters[] = { &filterAlive, NULL };
- ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( &m_currentTargetPosition, damageRadius, FROM_CENTER_2D, filters );
- MemoryPoolObjectHolder hold( iter );
- for( Object *obj = iter->first(); obj; obj = iter->next() )
- {
- BodyModuleInterface *body = obj->getBodyModule();
- if( body )
- {
- body->attemptDamage( &damageInfo );
- }
- }
- if( data->m_damagePulseRemnantObjectName.isNotEmpty() )
- {
- //Create a remnant damaging object that will fade over time to represent the burning trail.
- const ThingTemplate *thing = TheThingFactory->findTemplate( data->m_damagePulseRemnantObjectName );
- if( thing )
- {
- //Fire and forget
- Object *remnant = TheThingFactory->newObject( thing, me->getTeam() );
- if( remnant )
- {
- remnant->setPosition( &m_currentTargetPosition );
- }
- }
- }
- //Calculate next damage pulse frame.
- Real nextFactor = (Real)m_damagePulsesMade / (Real)data->m_totalDamagePulses;
- m_nextDamagePulseFrame = orbitalBirthFrame + nextFactor * (orbitalDeathFrame - orbitalBirthFrame);
- }
- }
-
- if( endDecayFrame <= now )
- {
- setLogicalStatus( STATUS_PACKING );
- }
- else if( m_startDecayFrame <= now )
- {
- setLogicalStatus( STATUS_POSTFIRE );
- }
- else
- {
- setLogicalStatus( STATUS_FIRING );
- }
- }
- else if( readyToFireFrame <= now )
- {
- setLogicalStatus( STATUS_READY_TO_FIRE );
- }
- else if( almostReadyFrame <= now )
- {
- setLogicalStatus( STATUS_ALMOST_READY );
- }
- else if( raiseAntennaFrame <= now )
- {
- setLogicalStatus( STATUS_PREPARING );
- }
- else if( beginChargeFrame <= now )
- {
- setLogicalStatus( STATUS_CHARGING );
- }
- if( m_status == STATUS_FIRING )
- {
- if( m_nextLaunchFXFrame <= now )
- {
- //Generate iteration of fxlist for beam launching
- if( data->m_beamLaunchFX )
- {
- FXList::doFXPos( data->m_beamLaunchFX, &m_laserOriginPosition, NULL );
- }
- m_nextLaunchFXFrame = now + data->m_framesBetweenLaunchFXRefresh;
- }
- }
- //Handle shrouded status changes for the client player.
- Player *localPlayer = ThePlayerList->getLocalPlayer();
- if( localPlayer )
- {
- Bool shrouded = me->getShroudedStatus( localPlayer->getPlayerIndex() ) != OBJECTSHROUD_CLEAR;
- if( shrouded )
- {
- //We can't see it so any client effects that have been added logically needs to be removed!
- removeAllEffects();
- }
- else
- {
- //We can see it -- we only want to do anything if we just started seeing it, which means
- //we want to add client effects again.
- Bool revealThisFrame = m_clientShroudedLastFrame != shrouded;
- if( revealThisFrame )
- {
- //Only if we reveal this frame, will we add client effects. The logic can take it from
- //here on... unless of course we lose sight again.
- setClientStatus( m_status, revealThisFrame );
- }
- }
- m_clientShroudedLastFrame = shrouded;
- }
- return UPDATE_SLEEP_NONE;
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createOuterNodeParticleSystems( IntensityTypes intensity )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- AsciiString str;
- switch( intensity )
- {
- case IT_LIGHT:
- str = data->m_outerNodesLightFlareParticleSystemName;
- break;
- case IT_MEDIUM:
- str = data->m_outerNodesMediumFlareParticleSystemName;
- break;
- case IT_INTENSE:
- str = data->m_outerNodesIntenseFlareParticleSystemName;
- break;
- case IT_FINISH:
- break;
- }
- if( str.isNotEmpty() )
- {
- const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( str );
- if( tmp )
- {
- ParticleSystem *system;
- for( int i = 0; i < data->m_outerEffectNumBones; i++ )
- {
- system = TheParticleSystemManager->createParticleSystem( tmp );
- if( system )
- {
- m_outerSystemIDs[ i ] = system->getSystemID();
- system->setPosition( &m_outerNodePositions[ i ] );
- system->setLocalTransform( &m_outerNodeOrientations[ i ] );
- }
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createConnectorLasers( IntensityTypes intensity )
- {
- //Cache bone positions for the laser when it is ready to fire
- if( !m_upBonesCached )
- {
- calculateUpBonePositions();
- m_upBonesCached = true;
- }
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- AsciiString str;
- switch( intensity )
- {
- case IT_LIGHT:
- break;
- case IT_MEDIUM:
- str = data->m_connectorMediumLaserNameName;;
- break;
- case IT_INTENSE:
- str = data->m_connectorIntenseLaserNameName;
- break;
- case IT_FINISH:
- break;
- }
- if( str.isNotEmpty() )
- {
- const ThingTemplate *thingTemplate = TheThingFactory->findTemplate( str );
- if( thingTemplate )
- {
- for( int i = 0; i < data->m_outerEffectNumBones; i++ )
- {
- Drawable *beam = TheThingFactory->newDrawable( thingTemplate );
- if( beam )
- {
- m_laserBeamIDs[ i ] = beam->getID();
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- update->initLaser( NULL, &m_outerNodePositions[ i ], &m_connectorNodePosition );
- }
- }
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createConnectorFlare( IntensityTypes intensity )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- AsciiString str;
- switch( intensity )
- {
- case IT_LIGHT:
- break;
- case IT_MEDIUM:
- str = data->m_connectorMediumFlareParticleSystemName;
- break;
- case IT_INTENSE:
- str = data->m_connectorIntenseFlareParticleSystemName;
- break;
- case IT_FINISH:
- break;
- }
- if( str.isNotEmpty() )
- {
- const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( str );
- ParticleSystem *system;
- if( tmp )
- {
- system = TheParticleSystemManager->createParticleSystem( tmp );
- if( system )
- {
- m_connectorSystemID = system->getSystemID();
- system->setPosition( &m_connectorNodePosition );
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createLaserBaseFlare( IntensityTypes intensity )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- AsciiString str;
- switch( intensity )
- {
- case IT_LIGHT:
- str = data->m_laserBaseLightFlareParticleSystemName;
- break;
- case IT_MEDIUM:
- str = data->m_laserBaseMediumFlareParticleSystemName;
- break;
- case IT_INTENSE:
- str = data->m_laserBaseIntenseFlareParticleSystemName;
- break;
- case IT_FINISH:
- break;
- }
- if( str.isNotEmpty() )
- {
- const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( str );
- if( tmp )
- {
- ParticleSystem *system = TheParticleSystemManager->createParticleSystem( tmp );
- if( system )
- {
- m_laserBaseSystemID = system->getSystemID();
- system->setPosition( &m_laserOriginPosition );
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createGroundToOrbitLaser( UnsignedInt growthFrames )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Drawable *beam = TheGameClient->findDrawableByID( m_groundToOrbitBeamID );
- if( beam )
- {
- TheGameClient->destroyDrawable( beam );
- m_orbitToTargetBeamID = INVALID_DRAWABLE_ID;
- }
- if( data->m_particleBeamLaserName.isNotEmpty() )
- {
- const ThingTemplate *thingTemplate = TheThingFactory->findTemplate( data->m_particleBeamLaserName );
- if( thingTemplate )
- {
- Drawable *beam = TheThingFactory->newDrawable( thingTemplate );
- if( beam )
- {
- m_groundToOrbitBeamID = beam->getID();
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- Coord3D orbitPosition;
- orbitPosition.set( &m_laserOriginPosition );
- orbitPosition.z += 500.0f;
- update->initLaser( NULL, &m_laserOriginPosition, &orbitPosition, growthFrames );
- }
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createOrbitToTargetLaser( UnsignedInt growthFrames )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Drawable *beam = TheGameClient->findDrawableByID( m_orbitToTargetBeamID );
- if( beam )
- {
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- TheGameClient->destroyDrawable( beam );
- m_orbitToTargetBeamID = INVALID_DRAWABLE_ID;
- }
- if( data->m_particleBeamLaserName.isNotEmpty() )
- {
- const ThingTemplate *thingTemplate = TheThingFactory->findTemplate( data->m_particleBeamLaserName );
- if( thingTemplate )
- {
- Drawable *beam = TheThingFactory->newDrawable( thingTemplate );
- if( beam )
- {
- m_orbitToTargetBeamID = beam->getID();
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- Coord3D orbitPosition;
- orbitPosition.set( &m_initialTargetPosition );
- orbitPosition.z += 500.0f;
- update->initLaser( NULL, &orbitPosition, &m_initialTargetPosition, growthFrames );
- }
- }
- }
- if( m_annihilationSound.getEventName().isNotEmpty() )
- {
- m_annihilationSound.setDrawableID( m_orbitToTargetBeamID );
- //m_annihilationSound.setPosition( &m_initialTargetPosition );
- m_annihilationSound.setPlayingHandle( TheAudio->addAudioEvent( &m_annihilationSound ) );
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::createGroundHitParticleSystem( IntensityTypes intensity )
- {
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::removeAllEffects()
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- for( int i = 0; i < data->m_outerEffectNumBones; i++ )
- {
- if( m_outerSystemIDs && m_outerSystemIDs[ i ] )
- {
- TheParticleSystemManager->destroyParticleSystemByID( m_outerSystemIDs[ i ] );
- m_outerSystemIDs[ i ] = INVALID_PARTICLE_SYSTEM_ID;
- }
- Drawable *beam = TheGameClient->findDrawableByID( m_laserBeamIDs[ i ] );
- if( beam )
- {
- TheGameClient->destroyDrawable( beam );
- m_laserBeamIDs[ i ] = INVALID_DRAWABLE_ID;
- }
- }
- if( m_connectorSystemID )
- {
- TheParticleSystemManager->destroyParticleSystemByID( m_connectorSystemID );
- m_connectorSystemID = INVALID_PARTICLE_SYSTEM_ID;
- }
- if( m_laserBaseSystemID )
- {
- TheParticleSystemManager->destroyParticleSystemByID( m_laserBaseSystemID );
- m_laserBaseSystemID = INVALID_PARTICLE_SYSTEM_ID;
- }
- Drawable *beam = TheGameClient->findDrawableByID( m_groundToOrbitBeamID );
- if( beam )
- {
- TheGameClient->destroyDrawable( beam );
- m_groundToOrbitBeamID = INVALID_DRAWABLE_ID;
- }
- //Remove all sound hooks
- }
- //-------------------------------------------------------------------------------------------------
- Bool ParticleUplinkCannonUpdate::calculateDefaultInformation()
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Object *obj = getObject();
- //Get the local bone positions for each of the outer nodes.
- Coord3D bonePositions[ MAX_OUTER_NODES ];
- Matrix3D boneMatrices[ MAX_OUTER_NODES ];
- int numBones = obj->getMultiLogicalBonePosition( data->m_outerEffectBaseBoneName.str(), data->m_outerEffectNumBones, bonePositions, boneMatrices, FALSE );
- if( numBones != data->m_outerEffectNumBones )
- {
- DEBUG_CRASH( ("Particle cannon requires %d outer node bones, but can only find %d bones.", data->m_outerEffectNumBones, numBones ) );
- m_invalidSettings = true;
- return false;
- }
- for( int i = 0; i < data->m_outerEffectNumBones; i++ )
- {
- m_laserBeamIDs[ i ] = INVALID_DRAWABLE_ID;
- m_outerSystemIDs[ i ] = INVALID_PARTICLE_SYSTEM_ID;
- //Convert the local bone position into world space.
- Matrix3D nodeMatrix;
- getObject()->convertBonePosToWorldPos( &bonePositions[i], &boneMatrices[i], &m_outerNodePositions[ i ], &m_outerNodeOrientations[ i ] );
- }
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- Bool ParticleUplinkCannonUpdate::calculateUpBonePositions()
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- Object *obj = getObject();
- //Due to instant special weapons (or scripting)... it's possible to be in many states that are ready to fire (or firing)
- Drawable *draw = obj->getDrawable();
- Matrix3D mtx;
- Coord3D pos;
- if( draw )
- {
- if( data->m_connectorBoneName.isNotEmpty() && draw->getCurrentClientBonePositions( data->m_connectorBoneName.str(), 0, &pos, &mtx, 1 ) )
- {
- obj->convertBonePosToWorldPos( &pos, &mtx, &m_connectorNodePosition, &mtx );
- }
- if( data->m_connectorBoneName.isNotEmpty() && draw->getCurrentClientBonePositions( data->m_fireBoneName.str(), 0, &pos, &mtx, 1 ) )
- {
- obj->convertBonePosToWorldPos( &pos, &mtx, &m_laserOriginPosition, &mtx );
- }
- }
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::setLogicalStatus( PUCStatus newStatus )
- {
- Object *obj = getObject();
- if( m_status == newStatus )
- {
- return;
- }
- //Handle entering new status
- switch( newStatus )
- {
- case STATUS_IDLE:
- {
- //Set unpacked animation
- obj->clearModelConditionFlags( MAKE_MODELCONDITION_MASK3( MODELCONDITION_PACKING, MODELCONDITION_UNPACKING, MODELCONDITION_DEPLOYED ) );
- TheAudio->removeAudioEvent( m_powerupSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_unpackToReadySound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_firingToIdleSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- break;
- }
- case STATUS_CHARGING:
- {
- m_laserStatus = LASERSTATUS_NONE;
- m_powerupSound.setObjectID( obj->getID() );
- m_powerupSound.setPlayingHandle( TheAudio->addAudioEvent( &m_powerupSound ) );
- TheAudio->removeAudioEvent( m_unpackToReadySound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_firingToIdleSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- break;
- }
- case STATUS_PREPARING:
- {
- //Set unpacking animation
- obj->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK2( MODELCONDITION_PACKING, MODELCONDITION_DEPLOYED ),
- MAKE_MODELCONDITION_MASK( MODELCONDITION_UNPACKING ) );
- if( m_unpackToReadySound.getEventName().isNotEmpty() )
- {
- m_unpackToReadySound.setObjectID( obj->getID() );
- m_unpackToReadySound.setPlayingHandle( TheAudio->addAudioEvent( &m_unpackToReadySound ) );
- }
- TheAudio->removeAudioEvent( m_firingToIdleSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
-
- m_laserStatus = LASERSTATUS_NONE;
- break;
- }
- case STATUS_ALMOST_READY:
- {
- //Set deployed animation
- obj->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK2( MODELCONDITION_PACKING, MODELCONDITION_UNPACKING ),
- MAKE_MODELCONDITION_MASK( MODELCONDITION_DEPLOYED ) );
- m_laserStatus = LASERSTATUS_NONE;
- break;
- }
- case STATUS_READY_TO_FIRE:
- {
- obj->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK2( MODELCONDITION_PACKING, MODELCONDITION_UNPACKING ),
- MAKE_MODELCONDITION_MASK( MODELCONDITION_DEPLOYED ) );
- TheAudio->removeAudioEvent( m_powerupSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_firingToIdleSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- m_laserStatus = LASERSTATUS_NONE;
- break;
- }
- case STATUS_PREFIRE:
- {
- break;
- }
- case STATUS_FIRING:
- {
- obj->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK2( MODELCONDITION_PACKING, MODELCONDITION_UNPACKING ),
- MAKE_MODELCONDITION_MASK( MODELCONDITION_DEPLOYED ) );
- if( m_firingToIdleSound.getEventName().isNotEmpty() )
- {
- m_firingToIdleSound.setObjectID( obj->getID() );
- m_firingToIdleSound.setPlayingHandle( TheAudio->addAudioEvent( &m_firingToIdleSound ) );
- }
- TheAudio->removeAudioEvent( m_powerupSound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_unpackToReadySound.getPlayingHandle() );
- TheAudio->removeAudioEvent( m_annihilationSound.getPlayingHandle() );
- m_nextLaunchFXFrame = 0;
- break;
- }
- case STATUS_POSTFIRE:
- {
- break;
- }
- case STATUS_PACKING:
- {
- //Set packing animation
- obj->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK2( MODELCONDITION_UNPACKING, MODELCONDITION_DEPLOYED ),
- MAKE_MODELCONDITION_MASK( MODELCONDITION_PACKING ) );
- break;
- }
- }
- //Set new status.
- m_status = newStatus;
- setClientStatus( m_status, FALSE );
- }
- //-------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::setClientStatus( PUCStatus newStatus, Bool revealThisFrame )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- //Caches bone positions for positioning the client beams.
- if( !m_defaultInfoCached )
- {
- if( !calculateDefaultInformation() )
- {
- m_invalidSettings = true;
- return;
- }
- m_defaultInfoCached = true;
- }
- //This isn't the most efficient way to do this. Various effects can live in more than
- //one status state, but keeping track of them properly is error-prone and hard to read.
- //Therefore, the new philosophy is to delete EVERYTHING between status changes and
- //create the ones we want!
- removeAllEffects();
- //Handle entering new status
- switch( newStatus )
- {
- case STATUS_IDLE:
- {
- break;
- }
- case STATUS_CHARGING:
- {
- createOuterNodeParticleSystems( IT_LIGHT );
- break;
- }
- case STATUS_PREPARING:
- {
- createOuterNodeParticleSystems( IT_MEDIUM );
- break;
- }
- case STATUS_ALMOST_READY:
- {
- createOuterNodeParticleSystems( IT_MEDIUM );
- createConnectorLasers( IT_MEDIUM );
- createConnectorFlare( IT_MEDIUM );
- break;
- }
- case STATUS_READY_TO_FIRE:
- {
- createOuterNodeParticleSystems( IT_MEDIUM );
- createConnectorLasers( IT_MEDIUM );
- createConnectorFlare( IT_MEDIUM );
- createLaserBaseFlare( IT_LIGHT );
- break;
- }
- case STATUS_PREFIRE:
- {
- break;
- }
- case STATUS_FIRING:
- {
- if( revealThisFrame )
- {
- createGroundToOrbitLaser( 0 );
- }
- else
- {
- createGroundToOrbitLaser( data->m_widthGrowFrames );
- }
- createOuterNodeParticleSystems( IT_INTENSE );
- createConnectorLasers( IT_INTENSE );
- createConnectorFlare( IT_INTENSE );
- createLaserBaseFlare( IT_INTENSE );
- break;
- }
- case STATUS_POSTFIRE:
- {
- createOuterNodeParticleSystems( IT_MEDIUM );
- createConnectorLasers( IT_MEDIUM );
- createConnectorFlare( IT_MEDIUM );
- createLaserBaseFlare( IT_MEDIUM );
- createGroundToOrbitLaser( 0 );
- Drawable *beam = TheGameClient->findDrawableByID( m_groundToOrbitBeamID );
- if( beam )
- {
- static NameKeyType nameKeyClientUpdate = NAMEKEY( "LaserUpdate" );
- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule( nameKeyClientUpdate );
- if( update )
- {
- if( revealThisFrame )
- {
- update->setDecayFrames( 0 );
- }
- else
- {
- update->setDecayFrames( data->m_widthGrowFrames );
- }
- }
- }
- break;
- }
- case STATUS_PACKING:
- {
- break;
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool ParticleUplinkCannonUpdate::doesSpecialPowerHaveOverridableDestinationActive() const
- {
- return m_status == STATUS_PREFIRE || m_status == STATUS_FIRING || m_status == STATUS_POSTFIRE;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::crc( Xfer *xfer )
- {
- // extend base class
- UpdateModule::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::xfer( Xfer *xfer )
- {
- const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData();
- // version
- XferVersion currentVersion = 2;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- UpdateModule::xfer( xfer );
- // status
- xfer->xferUser( &m_status, sizeof( PUCStatus ) );
- // laser status
- xfer->xferUser( &m_laserStatus, sizeof( LaserStatus ) );
- // frames
- xfer->xferUnsignedInt( &m_frames );
- // we do not need to tie up the special power module pointer, it is done on object creation
- // SpecialPowerModuleInterface *m_specialPowerModule;
- // outer system ids
- xfer->xferUser( m_outerSystemIDs, sizeof( ParticleSystemID ) * MAX_OUTER_NODES );
- // laser beam ids
- xfer->xferUser( m_laserBeamIDs, sizeof( DrawableID ) * MAX_OUTER_NODES );
- // ground to orbit beam id
- xfer->xferDrawableID( &m_groundToOrbitBeamID );
- // orbit to target beam
- xfer->xferDrawableID( &m_orbitToTargetBeamID );
- // connector system ID
- xfer->xferUser( &m_connectorSystemID, sizeof( ParticleSystemID ) );
- // laser base system id
- xfer->xferUser( &m_laserBaseSystemID, sizeof( ParticleSystemID ) );
- // outer node positions
- xfer->xferUser( m_outerNodePositions, sizeof( Coord3D ) * MAX_OUTER_NODES );
- // outer node orientations
- xfer->xferUser( m_outerNodeOrientations, sizeof( Matrix3D ) * MAX_OUTER_NODES );
- // connector node position
- xfer->xferCoord3D( &m_connectorNodePosition );
- // laser origin position
- xfer->xferCoord3D( &m_laserOriginPosition );
- // The manual override target destination.
- xfer->xferCoord3D( &m_overrideTargetDestination );
- // up bones cached
- xfer->xferBool( &m_upBonesCached );
- // default info cached
- xfer->xferBool( &m_defaultInfoCached );
- // invalid settings
- xfer->xferBool( &m_invalidSettings );
- // initial target position
- xfer->xferCoord3D( &m_initialTargetPosition );
- // current target position
- xfer->xferCoord3D( &m_currentTargetPosition );
- // scorch marks make
- xfer->xferUnsignedInt( &m_scorchMarksMade );
- // next scorch mark frame
- xfer->xferUnsignedInt( &m_nextScorchMarkFrame );
-
- // next launch FX frame
- xfer->xferUnsignedInt( &m_nextLaunchFXFrame );
- // damage pluses made
- xfer->xferUnsignedInt( &m_damagePulsesMade );
- // next damage pulse frame
- xfer->xferUnsignedInt( &m_nextDamagePulseFrame );
- // start attack frame
- xfer->xferUnsignedInt( &m_startAttackFrame );
- // start attack frame
- if( xfer->getXferMode() == XFER_SAVE || version >= 2 )
- {
- xfer->xferUnsignedInt( &m_startDecayFrame );
- }
- else
- {
- m_startDecayFrame = m_startAttackFrame + data->m_totalFiringFrames;
- }
- // the time of last manual target click
- xfer->xferUnsignedInt( & m_lastDrivingClickFrame );
- // the time of the 2nd last manual target click
- xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void ParticleUplinkCannonUpdate::loadPostProcess( void )
- {
- // extend base class
- UpdateModule::loadPostProcess();
- } // end loadPostProcess
|