#include "../../idlib/precompiled.h" #pragma hdrstop #include "../Game_local.h" #include "../Weapon.h" #include "../Projectile.h" class rvWeaponDarkMatterGun : public rvWeapon { public: CLASS_PROTOTYPE( rvWeaponDarkMatterGun ); rvWeaponDarkMatterGun ( void ); ~rvWeaponDarkMatterGun ( void ); virtual void Spawn ( void ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); void PreSave ( void ); void PostSave ( void ); #ifdef _XENON virtual bool AllowAutoAim ( void ) const { return false; } #endif protected: enum darkMatterRing_t { RING_OUTER, RING_MIDDLE, RING_INNER, RING_MAX }; struct rings_s { idAngles angularVelocity; jointHandle_t joint; }; rings_s rings[ RING_MAX ]; int nextRotateTime; int ringStartTime; int chargeDuration; bool clientReload; rvClientEffectPtr coreEffect; rvClientEffectPtr coreStartEffect; jointHandle_t jointCore; void InitRing ( darkMatterRing_t ring, const char* name ); void StartRings ( bool chargeUp ); void StopRings ( void ); private: stateResult_t State_Idle ( const stateParms_t& parms ); stateResult_t State_Fire ( const stateParms_t& parms ); stateResult_t State_Reload ( const stateParms_t& parms ); CLASS_STATES_PROTOTYPE ( rvWeaponDarkMatterGun ); }; CLASS_DECLARATION( rvWeapon, rvWeaponDarkMatterGun ) END_CLASS /* ================ rvWeaponDarkMatterGun::rvWeaponDarkMatterGun ================ */ rvWeaponDarkMatterGun::rvWeaponDarkMatterGun ( void ) { coreStartEffect = NULL; coreEffect = NULL; ringStartTime = -1; clientReload = false; } /* ================ rvWeaponDarkMatterGun::~rvWeaponDarkMatterGun ================ */ rvWeaponDarkMatterGun::~rvWeaponDarkMatterGun ( void ) { StopRings ( ); } /* ================ rvWeaponDarkMatterGun::Spawn ================ */ void rvWeaponDarkMatterGun::Spawn ( void ) { SetState ( "Raise", 0 ); InitRing ( RING_OUTER, "outer" ); InitRing ( RING_INNER, "inner" ); InitRing ( RING_MIDDLE, "middle" ); nextRotateTime = 0; chargeDuration = SEC2MS ( spawnArgs.GetFloat ( "chargeDuration", ".5" ) ); jointCore = viewModel->GetAnimator()->GetJointHandle ( spawnArgs.GetString ( "joint_core" ) ); } /* ================ rvWeaponDarkMatterGun::Save ================ */ void rvWeaponDarkMatterGun::Save ( idSaveGame *savefile ) const { for ( int i = 0; i < RING_MAX; i++ ) { savefile->WriteAngles ( rings[ i ].angularVelocity ); savefile->WriteJoint ( rings[ i ].joint ); } savefile->WriteInt ( nextRotateTime ); savefile->WriteInt ( ringStartTime ); savefile->WriteInt ( chargeDuration ); savefile->WriteObject( coreEffect.GetEntity() ); savefile->WriteObject( coreStartEffect.GetEntity() ); savefile->WriteJoint ( jointCore ); } /* ================ rvWeaponDarkMatterGun::Restore ================ */ void rvWeaponDarkMatterGun::Restore ( idRestoreGame *savefile ) { for ( int i = 0; i < RING_MAX; i++ ) { savefile->ReadAngles ( rings[ i ].angularVelocity ); savefile->ReadJoint ( rings[ i ].joint ); } savefile->ReadInt ( nextRotateTime ); savefile->ReadInt ( ringStartTime ); savefile->ReadInt ( chargeDuration ); savefile->ReadObject( reinterpret_cast( coreEffect ) ); savefile->ReadObject( reinterpret_cast( coreStartEffect ) ); savefile->ReadJoint ( jointCore ); } /* ================ rvWeaponDarkMatterGun::PreSave ================ */ void rvWeaponDarkMatterGun::PreSave ( void ) { //disable sounds StopSound( SND_CHANNEL_ANY, false); } /* ================ rvWeaponDarkMatterGun::PostSave ================ */ void rvWeaponDarkMatterGun::PostSave ( void ) { //start the ring sounds StartSound ( "snd_rings", SND_CHANNEL_VOICE, 0, false, NULL ); } /* ================ rvWeaponDarkMatterGun::InitRing ================ */ void rvWeaponDarkMatterGun::InitRing ( darkMatterRing_t ring, const char* name ) { rings[ring].angularVelocity = spawnArgs.GetAngles ( va("ring_%s_velocity", name ) ); rings[ring].joint = viewModel->GetAnimator()->GetJointHandle ( spawnArgs.GetString ( va("ring_%s_joint", name ) ) ); } /* ================ rvWeaponDarkMatterGun::StartRings ================ */ void rvWeaponDarkMatterGun::StartRings ( bool chargeUp ) { int i; if ( ringStartTime == -1 ) { StartSound ( "snd_rings", SND_CHANNEL_VOICE, 0, false, NULL ); ringStartTime = gameLocal.time; } if ( chargeUp ) { coreStartEffect = viewModel->PlayEffect( "fx_core_start", jointCore ); for ( i = 0; i < RING_MAX; i ++ ) { viewModel->GetAnimator()->SetJointAngularVelocity ( rings[i].joint, rings[i].angularVelocity, gameLocal.time, chargeDuration / 2 ); } } else if ( !coreEffect ) { coreEffect = viewModel->PlayEffect( "fx_core", jointCore, true ); for ( i = 0; i < RING_MAX; i ++ ) { viewModel->GetAnimator()->SetJointAngularVelocity ( rings[i].joint, rings[i].angularVelocity, gameLocal.time, 0 ); } } } /* ================ rvWeaponDarkMatterGun::StopRings ================ */ void rvWeaponDarkMatterGun::StopRings ( void ) { int i; if ( !viewModel ) { return; } viewModel->StopSound ( SND_CHANNEL_VOICE, false ); if ( coreEffect ) { coreEffect->Stop ( ); coreEffect = NULL; } if ( coreStartEffect ) { coreStartEffect->Stop ( ); coreStartEffect = NULL; } for ( i = 0; i < RING_MAX; i ++ ) { viewModel->GetAnimator()->ClearJoint ( rings[i].joint ); } ringStartTime = -1; } /* =============================================================================== States =============================================================================== */ CLASS_STATES_DECLARATION ( rvWeaponDarkMatterGun ) STATE ( "Idle", rvWeaponDarkMatterGun::State_Idle) STATE ( "Fire", rvWeaponDarkMatterGun::State_Fire ) STATE ( "Reload", rvWeaponDarkMatterGun::State_Reload ) END_CLASS_STATES /* ================ rvWeaponDarkMatterGun::State_Idle ================ */ stateResult_t rvWeaponDarkMatterGun::State_Idle( const stateParms_t& parms ) { enum { STAGE_INIT, STAGE_WAIT, }; switch ( parms.stage ) { case STAGE_INIT: if ( !AmmoAvailable ( ) ) { SetStatus ( WP_OUTOFAMMO ); } else { SetStatus ( WP_READY ); } // Auto reload? if ( !AmmoInClip ( ) && AmmoAvailable () && !clientReload ) { SetState ( "reload", 2 ); return SRESULT_DONE; } clientReload = false; StartRings ( false ); PlayCycle( ANIMCHANNEL_ALL, "idle", parms.blendFrames ); return SRESULT_STAGE ( STAGE_WAIT ); case STAGE_WAIT: if ( wsfl.lowerWeapon ) { SetState ( "Lower", 4 ); return SRESULT_DONE; } if ( gameLocal.time > nextAttackTime && wsfl.attack && AmmoInClip ( ) ) { SetState ( "Fire", 0 ); return SRESULT_DONE; } if ( wsfl.netReload ) { if ( owner->entityNumber != gameLocal.localClientNum ) { SetState ( "Reload", 4 ); return SRESULT_DONE; } else { wsfl.netReload = false; } } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvWeaponDarkMatterGun::State_Fire ================ */ stateResult_t rvWeaponDarkMatterGun::State_Fire ( const stateParms_t& parms ) { enum { STAGE_INIT, STAGE_WAIT, }; switch ( parms.stage ) { case STAGE_INIT: StopRings ( ); nextAttackTime = gameLocal.time + (fireRate * owner->PowerUpModifier ( PMOD_FIRERATE )); Attack ( false, 1, spread, 0, 1.0f ); PlayAnim ( ANIMCHANNEL_ALL, "fire", 0 ); return SRESULT_STAGE ( STAGE_WAIT ); case STAGE_WAIT: if ( AnimDone ( ANIMCHANNEL_ALL, 2 ) || (gameLocal.isMultiplayer && gameLocal.time >= nextAttackTime) ) { SetState ( "Idle", 0 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvWeaponDarkMatterGun::State_Reload ================ */ stateResult_t rvWeaponDarkMatterGun::State_Reload ( const stateParms_t& parms ) { enum { STAGE_INIT, STAGE_WAIT, }; switch ( parms.stage ) { case STAGE_INIT: if ( wsfl.netReload ) { wsfl.netReload = false; } else { NetReload ( ); } StartRings ( true ); SetStatus ( WP_RELOAD ); PlayAnim ( ANIMCHANNEL_ALL, "reload", parms.blendFrames ); return SRESULT_STAGE ( STAGE_WAIT ); case STAGE_WAIT: if ( AnimDone ( ANIMCHANNEL_ALL, 4 ) ) { AddToClip ( ClipSize() ); clientReload = true; SetState ( "Idle", 4 ); return SRESULT_DONE; } if ( gameLocal.isMultiplayer && gameLocal.time > nextAttackTime && wsfl.attack ) { AddToClip ( ClipSize() ); SetStatus ( WP_READY ); SetState ( "Fire", 4 ); return SRESULT_DONE; } if ( wsfl.lowerWeapon ) { SetState ( "Lower", 4 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* =============================================================================== rvDarkMatterProjectile =============================================================================== */ class rvDarkMatterProjectile : public idProjectile { public : CLASS_PROTOTYPE( rvDarkMatterProjectile ); rvDarkMatterProjectile ( void ); ~rvDarkMatterProjectile ( void ); void Spawn ( void ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); virtual void Think ( void ); protected: int nextDamageTime; const idDict* radiusDamageDef; }; CLASS_DECLARATION( idProjectile, rvDarkMatterProjectile ) END_CLASS /* ================ rvDarkMatterProjectile::rvDarkMatterProjectile ================ */ rvDarkMatterProjectile::rvDarkMatterProjectile ( void ) { radiusDamageDef = NULL; } /* ================ rvDarkMatterProjectile::~rvDarkMatterProjectile ================ */ rvDarkMatterProjectile::~rvDarkMatterProjectile ( void ) { } /* ================ rvDarkMatterProjectile::Spawn ================ */ void rvDarkMatterProjectile::Spawn ( void ) { nextDamageTime = 0; radiusDamageDef = gameLocal.FindEntityDefDict ( spawnArgs.GetString ( "def_radius_damage" ) ); } /* ================ rvDarkMatterProjectile::Save ================ */ void rvDarkMatterProjectile::Save ( idSaveGame *savefile ) const { savefile->WriteInt ( nextDamageTime ); } /* ================ rvDarkMatterProjectile::Restore ================ */ void rvDarkMatterProjectile::Restore ( idRestoreGame *savefile ) { savefile->ReadInt ( nextDamageTime ); radiusDamageDef = gameLocal.FindEntityDefDict ( spawnArgs.GetString ( "def_radius_damage" ) ); } /* ================ rvDarkMatterProjectile::Think ================ */ void rvDarkMatterProjectile::Think ( void ) { physicsObj.SetClipMask( MASK_DMGSOLID ); idProjectile::Think ( ); if ( gameLocal.time > nextDamageTime ) { gameLocal.RadiusDamage ( GetPhysics()->GetOrigin(), this, owner, owner, NULL, spawnArgs.GetString( "def_radius_damage" ), 1.0f, &hitCount ); nextDamageTime = gameLocal.time + SEC2MS ( spawnArgs.GetFloat ( "damageRate", ".05" ) ); } }