#include "../../idlib/precompiled.h" #pragma hdrstop #include "../Game_local.h" #include "../Weapon.h" class rvWeaponGauntlet : public rvWeapon { public: CLASS_PROTOTYPE( rvWeaponGauntlet ); rvWeaponGauntlet( void ); ~rvWeaponGauntlet( void ); virtual void Spawn ( void ); virtual void CleanupWeapon ( void ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); void PreSave ( void ); void PostSave ( void ); protected: idAngles bladeSpinFast; idAngles bladeSpinSlow; jointHandle_t bladeJoint; jointHandle_t bladeJoint_world; int bladeAccel; float range; rvClientEffectPtr impactEffect; int impactMaterial; void Attack ( void ); void StartBlade ( void ); void StopBlade ( void ); private: void PlayLoopSound ( int sndType ); int loopSound; enum { LOOP_NONE, LOOP_WALL, LOOP_FLESH }; stateResult_t State_Raise ( const stateParms_t& parms ); stateResult_t State_Lower ( const stateParms_t& parms ); stateResult_t State_Idle ( const stateParms_t& parms ); stateResult_t State_Fire ( const stateParms_t& parms ); CLASS_STATES_PROTOTYPE ( rvWeaponGauntlet ); }; CLASS_DECLARATION( rvWeapon, rvWeaponGauntlet ) END_CLASS /* ================ rvWeaponGauntlet::rvWeaponGauntlet ================ */ rvWeaponGauntlet::rvWeaponGauntlet( void ) { loopSound = LOOP_NONE; } /* ================ rvWeaponGauntlet::~rvWeaponGauntlet ================ */ rvWeaponGauntlet::~rvWeaponGauntlet(void) { if ( viewModel ) { StopSound( SND_CHANNEL_WEAPON, false ); } if ( impactEffect ) { impactEffect->Stop( ); impactEffect = NULL; } impactMaterial = -1; } /* ================ rvWeaponGauntlet::Spawn ================ */ void rvWeaponGauntlet::Spawn ( void ) { SetState ( "Raise", 0 ); bladeJoint = viewModel->GetAnimator()->GetJointHandle ( spawnArgs.GetString ( "joint_blade", "center" ) ); bladeJoint_world= GetWorldModel()->GetAnimator()->GetJointHandle ( spawnArgs.GetString ( "joint_blade", "center" ) ); bladeSpinFast = spawnArgs.GetAngles ( "blade_spinfast" ); bladeSpinSlow = spawnArgs.GetAngles ( "blade_spinslow" ); bladeAccel = SEC2MS ( spawnArgs.GetFloat ( "blade_accel", ".25" ) ); range = spawnArgs.GetFloat ( "range", "32" ); impactMaterial = -1; impactEffect = NULL; loopSound = LOOP_NONE; } /* ================ rvWeaponGauntlet::Save ================ */ void rvWeaponGauntlet::Save ( idSaveGame *savefile ) const { savefile->WriteAngles ( bladeSpinFast ); savefile->WriteAngles ( bladeSpinSlow ); savefile->WriteJoint ( bladeJoint ); savefile->WriteJoint ( bladeJoint_world ); savefile->WriteInt ( bladeAccel ); savefile->WriteFloat ( range ); savefile->WriteObject ( impactEffect ); savefile->WriteInt ( impactMaterial ); savefile->WriteInt ( loopSound ); } /* ================ rvWeaponGauntlet::Restore ================ */ void rvWeaponGauntlet::Restore ( idRestoreGame *savefile ) { savefile->ReadAngles ( bladeSpinFast ); savefile->ReadAngles ( bladeSpinSlow ); savefile->ReadJoint ( bladeJoint ); savefile->ReadJoint ( bladeJoint_world ); savefile->ReadInt ( bladeAccel ); savefile->ReadFloat ( range ); savefile->ReadObject ( reinterpret_cast( impactEffect ) ); savefile->ReadInt ( impactMaterial ); savefile->ReadInt ( loopSound ); } /* ================ rvWeaponGauntlet::PreSave ================ */ void rvWeaponGauntlet::PreSave ( void ) { } /* ================ rvWeaponGauntlet::PostSave ================ */ void rvWeaponGauntlet::PostSave( void ) { } void rvWeaponGauntlet::PlayLoopSound( int sndType ) { if ( loopSound == sndType ) { return; } const char *loopSoundString = NULL; switch ( sndType ) { case LOOP_NONE: default: loopSoundString = "snd_spin_loop"; break; case LOOP_WALL: loopSoundString = "snd_spin_wall"; break; case LOOP_FLESH: loopSoundString = "snd_spin_flesh"; break; } if ( loopSoundString ) { loopSound = sndType; StartSound( loopSoundString, SND_CHANNEL_WEAPON, 0, false, 0 ); } } /* ================ rvWeaponGauntlet::CleanupWeapon ================ */ void rvWeaponGauntlet::CleanupWeapon( void ) { if ( impactEffect ) { impactEffect->Stop( ); impactEffect = NULL; } impactMaterial = -1; PlayLoopSound( LOOP_NONE ); } /* ================ rvWeaponGauntlet::Attack ================ */ void rvWeaponGauntlet::Attack ( void ) { trace_t tr; idEntity* ent; // Cast a ray out to the lock range // RAVEN BEGIN // ddynerman: multiple clip worlds gameLocal.TracePoint( owner, tr, playerViewOrigin, playerViewOrigin + playerViewAxis[0] * range, MASK_SHOT_RENDERMODEL, owner ); // RAVEN END owner->WeaponFireFeedback( &weaponDef->dict ); if ( tr.fraction >= 1.0f ) { if ( impactEffect ) { impactEffect->Stop ( ); impactEffect = NULL; } impactMaterial = -1; PlayLoopSound( LOOP_NONE ); return; } // Entity we hit? ent = gameLocal.entities[tr.c.entityNum]; // If the impact material changed then stop the impact effect if ( (tr.c.materialType && tr.c.materialType->Index ( ) != impactMaterial) || (!tr.c.materialType && impactMaterial != -1) ) { if ( impactEffect ) { impactEffect->Stop ( ); impactEffect = NULL; } impactMaterial = -1; } // In singleplayer-- the gauntlet never effects marine AI if( !gameLocal.isMultiplayer ) { idActor* actor_ent = 0; //ignore both the body and the head. if (ent->IsType( idActor::GetClassType()) ) { actor_ent = static_cast(ent); } else if (ent->IsType ( idAFAttachment::GetClassType()) ) { actor_ent = static_cast(ent->GetBindMaster()); } if ( actor_ent && actor_ent->team == gameLocal.GetLocalPlayer()->team ) { PlayLoopSound( LOOP_NONE ); return; } } //multiplayer-- don't gauntlet dead stuff if( gameLocal.isMultiplayer ) { idPlayer * player; if ( ent->IsType( idPlayer::GetClassType() )) { player = static_cast< idPlayer* >(ent); if (player->health <= 0) { return; } } } if ( !impactEffect ) { impactMaterial = tr.c.materialType ? tr.c.materialType->Index() : -1; impactEffect = gameLocal.PlayEffect ( gameLocal.GetEffect ( spawnArgs, "fx_impact", tr.c.materialType ), tr.endpos, tr.c.normal.ToMat3(), true ); } else { impactEffect->SetOrigin ( tr.endpos ); impactEffect->SetAxis ( tr.c.normal.ToMat3() ); } // Do damage? if ( gameLocal.time > nextAttackTime ) { if ( ent ) { if ( ent->fl.takedamage ) { float dmgScale = 1.0f; dmgScale *= owner->PowerUpModifier( PMOD_MELEE_DAMAGE ); ent->Damage ( owner, owner, playerViewAxis[0], spawnArgs.GetString ( "def_damage" ), dmgScale, 0 ); StartSound( "snd_hit", SND_CHANNEL_ANY, 0, false, NULL ); if ( ent->spawnArgs.GetBool( "bleed" ) ) { PlayLoopSound( LOOP_FLESH ); } else { PlayLoopSound( LOOP_WALL ); } } else { PlayLoopSound( LOOP_WALL ); } } else { PlayLoopSound( LOOP_NONE ); } nextAttackTime = gameLocal.time + fireRate; } } /* ================ rvWeaponGauntlet::StartBlade ================ */ void rvWeaponGauntlet::StartBlade ( void ) { if ( viewModel ) { viewModel->GetAnimator()->SetJointAngularVelocity ( bladeJoint, bladeSpinFast, gameLocal.time, bladeAccel ); } if ( GetWorldModel() ) { GetWorldModel()->GetAnimator()->SetJointAngularVelocity ( bladeJoint_world, bladeSpinFast, gameLocal.time, bladeAccel ); } StopSound ( SND_CHANNEL_ITEM, false ); // StartSound ( "snd_blade_fast", SND_CHANNEL_ITEM, 0, false, NULL ); StartSound( "snd_spin_up", SND_CHANNEL_ITEM, 0, false, 0 ); } /* ================ rvWeaponGauntlet::StopBlade ================ */ void rvWeaponGauntlet::StopBlade ( void ) { if ( viewModel ) { viewModel->GetAnimator()->SetJointAngularVelocity ( bladeJoint, bladeSpinSlow, gameLocal.time, bladeAccel ); } if ( GetWorldModel() ) { GetWorldModel()->GetAnimator()->SetJointAngularVelocity ( bladeJoint_world, bladeSpinSlow, gameLocal.time, bladeAccel ); } StopSound ( SND_CHANNEL_WEAPON, false ); // StartSound ( "snd_blade_slow", SND_CHANNEL_ITEM, 0, false, NULL ); if ( impactEffect ) { impactEffect->Stop ( ); impactEffect = NULL; } impactMaterial = -1; } /* =============================================================================== States =============================================================================== */ CLASS_STATES_DECLARATION ( rvWeaponGauntlet ) STATE ( "Raise", rvWeaponGauntlet::State_Raise ) STATE ( "Lower", rvWeaponGauntlet::State_Lower ) STATE ( "Idle", rvWeaponGauntlet::State_Idle) STATE ( "Fire", rvWeaponGauntlet::State_Fire ) END_CLASS_STATES /* ================ rvWeaponGauntlet::State_Raise ================ */ stateResult_t rvWeaponGauntlet::State_Raise( const stateParms_t& parms ) { enum { RAISE_INIT, RAISE_WAIT, }; switch ( parms.stage ) { case RAISE_INIT: SetStatus( WP_RISING ); PlayAnim( ANIMCHANNEL_ALL, "raise", parms.blendFrames ); return SRESULT_STAGE( RAISE_WAIT ); case RAISE_WAIT: if ( AnimDone( ANIMCHANNEL_ALL, 4 ) ) { SetState( "Idle", 4 ); return SRESULT_DONE; } if ( wsfl.lowerWeapon ) { SetState( "Lower", 4 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvWeaponGauntlet::State_Lower ================ */ stateResult_t rvWeaponGauntlet::State_Lower( const stateParms_t& parms ) { enum { LOWER_INIT, LOWER_WAIT, LOWER_WAITRAISE }; switch ( parms.stage ) { case LOWER_INIT: SetStatus ( WP_LOWERING ); PlayAnim( ANIMCHANNEL_ALL, "lower", parms.blendFrames ); return SRESULT_STAGE(LOWER_WAIT); case LOWER_WAIT: if ( AnimDone ( ANIMCHANNEL_ALL, 0 ) ) { SetStatus ( WP_HOLSTERED ); return SRESULT_STAGE(LOWER_WAITRAISE); } return SRESULT_WAIT; case LOWER_WAITRAISE: if ( wsfl.raiseWeapon ) { SetState ( "Raise", 0 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvWeaponGauntlet::State_Idle ================ */ stateResult_t rvWeaponGauntlet::State_Idle( const stateParms_t& parms ) { enum { IDLE_INIT, IDLE_WAIT, }; switch ( parms.stage ) { case IDLE_INIT: SetStatus( WP_READY ); StopBlade(); PlayCycle( ANIMCHANNEL_ALL, "idle", parms.blendFrames ); return SRESULT_STAGE( IDLE_WAIT ); case IDLE_WAIT: if ( wsfl.lowerWeapon ) { SetState( "Lower", 4 ); return SRESULT_DONE; } if ( wsfl.attack ) { SetState( "Fire", 2 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvWeaponGauntlet::State_Fire ================ */ stateResult_t rvWeaponGauntlet::State_Fire( const stateParms_t& parms ) { enum { STAGE_START, STAGE_START_WAIT, STAGE_LOOP, STAGE_LOOP_WAIT, STAGE_END, STAGE_END_WAIT }; switch ( parms.stage ) { case STAGE_START: PlayAnim( ANIMCHANNEL_ALL, "attack_start", parms.blendFrames ); StartBlade(); loopSound = LOOP_NONE; // #32 - no gauntlet spin up //return SRESULT_STAGE( STAGE_START_WAIT ); return SRESULT_STAGE( STAGE_LOOP ); case STAGE_START_WAIT: if ( !wsfl.attack ) { return SRESULT_STAGE( STAGE_END ); } if ( AnimDone( ANIMCHANNEL_ALL, parms.blendFrames ) ) { return SRESULT_STAGE( STAGE_LOOP ); } return SRESULT_WAIT; case STAGE_LOOP: PlayCycle( ANIMCHANNEL_ALL, "attack_loop", parms.blendFrames ); StartSound( "snd_spin_loop", SND_CHANNEL_WEAPON, 0, false, 0 ); return SRESULT_STAGE(STAGE_LOOP_WAIT); case STAGE_LOOP_WAIT: if ( !wsfl.attack || wsfl.lowerWeapon ) { return SRESULT_STAGE( STAGE_END ); } Attack(); return SRESULT_WAIT; case STAGE_END: PlayAnim( ANIMCHANNEL_ALL, "attack_end", parms.blendFrames ); StopBlade(); StartSound( "snd_spin_down", SND_CHANNEL_WEAPON, 0, false, 0 ); return SRESULT_STAGE( STAGE_END_WAIT ); case STAGE_END_WAIT: if ( wsfl.attack || AnimDone( ANIMCHANNEL_ALL, parms.blendFrames ) ) { PostState( "Idle", parms.blendFrames ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; }