quake4-sdk/source/mpgame/weapon/WeaponNailgun.cpp
2007-06-15 00:00:00 +00:00

929 lines
24 KiB
C++

#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "../Weapon.h"
#include "../client/ClientEffect.h"
#include "../Projectile.h"
// Available drum speeds
const int NAILGUN_DRUMSPEED_STOPPED = 0;
const int NAILGUN_DRUMSPEED_SLOW = 1;
const int NAILGUN_DRUMSPEED_FAST = 2;
// Spinup and spindown times
const int NAILGUN_SPINDOWN_TIME = 1000;
const int NAILGUN_SPINUP_TIME = 1000;
// Nailgun shader parms
const int NAILGUN_SPARM_PLAYLEADIN = 7;
// Nailgun weapon modifications
const int NAILGUN_MOD_ROF_AMMO = BIT(0); // power mod combines Rate of fire and ammoo
const int NAILGUN_MOD_SEEK = BIT(1);
//const int NAILGUN_MOD_AMMO = BIT(2);
const int NAILGUN_SPIN_SNDCHANNEL = SND_CHANNEL_BODY2;
class rvWeaponNailgun : public rvWeapon {
public:
CLASS_PROTOTYPE( rvWeaponNailgun );
rvWeaponNailgun ( void );
~rvWeaponNailgun ( void );
virtual void Spawn ( void );
virtual void Think ( void );
void Save ( idSaveGame *savefile ) const;
void Restore ( idRestoreGame *savefile );
void PreSave ( void );
void PostSave ( void );
protected:
idEntityPtr<idEntity> guideEnt;
int guideTime;
int guideStartTime;
rvClientEntityPtr<rvClientEffect> guideEffect;
bool guideLocked;
float guideRange;
int guideHoldTime;
int guideAquireTime;
jointHandle_t jointDrumView;
jointHandle_t jointPinsView;
jointHandle_t jointSteamRightView;
jointHandle_t jointSteamLeftView;
jointHandle_t jointGuideEnt;
int drumSpeed;
int drumSpeedIdeal;
float drumMultiplier;
virtual void OnLaunchProjectile ( idProjectile* proj );
private:
void UpdateGuideStatus ( float range = 0.0f );
void CancelGuide ( void );
bool DrumSpin ( int speed, int blendFrames );
stateResult_t State_Idle ( const stateParms_t& parms );
stateResult_t State_Fire ( const stateParms_t& parms );
stateResult_t State_Reload ( const stateParms_t& parms );
stateResult_t State_Raise ( const stateParms_t& parms );
stateResult_t State_Lower ( const stateParms_t& parms );
stateResult_t State_DrumSpinDown ( const stateParms_t& parms );
stateResult_t State_DrumSpinUp ( const stateParms_t& parms );
stateResult_t Frame_ClaspOpen ( const stateParms_t& parms );
stateResult_t Frame_ClaspClose ( const stateParms_t& parms );
CLASS_STATES_PROTOTYPE ( rvWeaponNailgun );
};
CLASS_DECLARATION( rvWeapon, rvWeaponNailgun )
END_CLASS
/*
================
rvWeaponNailgun::rvWeaponNailgun
================
*/
rvWeaponNailgun::rvWeaponNailgun ( void ) {
}
/*
================
rvWeaponNailgun::~rvWeaponNailgun
================
*/
rvWeaponNailgun::~rvWeaponNailgun ( void ) {
if ( guideEffect ) {
guideEffect->Stop();
}
if( viewModel ) {
viewModel->StopSound( NAILGUN_SPIN_SNDCHANNEL, false );
}
}
/*
================
rvWeaponNailgun::Spawn
================
*/
void rvWeaponNailgun::Spawn ( void ) {
spawnArgs.GetFloat ( "lockRange", "1000", guideRange );
guideHoldTime = SEC2MS ( spawnArgs.GetFloat ( "lockHoldTime", "10" ) );
guideAquireTime = SEC2MS ( spawnArgs.GetFloat ( "lockAquireTime", ".1" ) );
jointDrumView = viewAnimator->GetJointHandle ( spawnArgs.GetString ( "joint_view_drum" ) );
jointPinsView = viewAnimator->GetJointHandle ( spawnArgs.GetString ( "joint_view_pins" ) );
jointSteamRightView = viewAnimator->GetJointHandle ( spawnArgs.GetString ( "joint_view_steamRight" ) );
jointSteamLeftView = viewAnimator->GetJointHandle ( spawnArgs.GetString ( "joint_view_steamLeft" ) );
jointGuideEnt = INVALID_JOINT;
drumSpeed = NAILGUN_DRUMSPEED_STOPPED;
drumSpeedIdeal = drumSpeed;
drumMultiplier = spawnArgs.GetFloat ( "drumSpeed" );
ExecuteState ( "ClaspClose" );
SetState ( "Raise", 0 );
}
/*
================
rvWeaponNailgun::Save
================
*/
void rvWeaponNailgun::Save ( idSaveGame *savefile ) const {
guideEnt.Save( savefile );
savefile->WriteInt( guideTime );
savefile->WriteInt( guideStartTime );
guideEffect.Save( savefile );
savefile->WriteBool ( guideLocked );
savefile->WriteFloat ( guideRange );
savefile->WriteInt ( guideHoldTime );
savefile->WriteInt ( guideAquireTime );
savefile->WriteJoint ( jointDrumView );
savefile->WriteJoint ( jointPinsView );
savefile->WriteJoint ( jointSteamRightView );
savefile->WriteJoint ( jointSteamLeftView );
savefile->WriteJoint ( jointGuideEnt );
savefile->WriteInt ( drumSpeed );
savefile->WriteInt ( drumSpeedIdeal );
savefile->WriteFloat ( drumMultiplier );
}
/*
================
rvWeaponNailgun::Restore
================
*/
void rvWeaponNailgun::Restore ( idRestoreGame *savefile ) {
guideEnt.Restore( savefile );
savefile->ReadInt( guideTime );
savefile->ReadInt( guideStartTime );
guideEffect.Restore( savefile );
savefile->ReadBool ( guideLocked );
savefile->ReadFloat ( guideRange );
savefile->ReadInt ( guideHoldTime );
savefile->ReadInt ( guideAquireTime );
savefile->ReadJoint ( jointDrumView );
savefile->ReadJoint ( jointPinsView );
savefile->ReadJoint ( jointSteamRightView );
savefile->ReadJoint ( jointSteamLeftView );
savefile->ReadJoint ( jointGuideEnt );
savefile->ReadInt ( drumSpeed );
savefile->ReadInt ( drumSpeedIdeal );
savefile->ReadFloat ( drumMultiplier );
}
/*
================
rvWeaponNailgun::PreSave
================
*/
void rvWeaponNailgun::PreSave ( void ) {
//disable sounds
StopSound( SND_CHANNEL_ANY, false);
//remove the guide gui cursor if there is one.
if ( guideEffect ) {
guideEffect->Stop();
guideEffect->Event_Remove();
guideEffect = NULL;
}
}
/*
================
rvWeaponNailgun::PostSave
================
*/
void rvWeaponNailgun::PostSave ( void ) {
//restore sounds-- but which one?
if( drumSpeed == NAILGUN_DRUMSPEED_FAST ) {
viewModel->StartSound ( "snd_spinfast", NAILGUN_SPIN_SNDCHANNEL, 0, false, NULL );
} else if( drumSpeed == NAILGUN_DRUMSPEED_SLOW ) {
viewModel->StartSound ( "snd_spinslow", NAILGUN_SPIN_SNDCHANNEL, 0, false, NULL );
}
//the guide gui effect will restore itself naturally
}
/*
================
rvWeaponNailgun::CancelGuide
================
*/
void rvWeaponNailgun::CancelGuide ( void ) {
if ( zoomGui && guideEnt ) {
zoomGui->HandleNamedEvent ( "lockStop" );
}
guideEnt = NULL;
guideLocked = false;
jointGuideEnt = INVALID_JOINT;
UpdateGuideStatus ( );
}
/*
================
rvWeaponNailgun::UpdateGuideStatus
================
*/
void rvWeaponNailgun::UpdateGuideStatus ( float range ) {
// Update the zoom GUI variables
if ( zoomGui ) {
float lockStatus;
if ( guideEnt ) {
if ( guideLocked ) {
lockStatus = 1.0f;
} else {
lockStatus = Min((float)(gameLocal.time - guideStartTime)/(float)guideTime, 1.0f);
}
} else {
lockStatus = 0.0f;
}
if ( owner == gameLocal.GetLocalPlayer( ) ) {
zoomGui->SetStateFloat ( "lockStatus", lockStatus );
zoomGui->SetStateFloat ( "playerYaw", playerViewAxis.ToAngles().yaw );
}
if ( guideEnt ) {
idVec3 diff;
diff = guideEnt->GetPhysics()->GetOrigin ( ) - playerViewOrigin;
diff.NormalizeFast ( );
zoomGui->SetStateFloat ( "lockYaw", idMath::AngleDelta ( diff.ToAngles ( ).yaw, playerViewAxis.ToAngles().yaw ) );
zoomGui->SetStateString ( "lockRange", va("%4.2f", range) );
zoomGui->SetStateString ( "lockTime", va("%02d", (int)MS2SEC(guideStartTime + guideTime - gameLocal.time) + 1) );
}
}
// Update the guide effect
if ( guideEnt ) {
idVec3 eyePos = static_cast<idActor *>(guideEnt.GetEntity())->GetEyePosition();
if( jointGuideEnt == INVALID_JOINT ) {
eyePos += guideEnt->GetPhysics()->GetAbsBounds().GetCenter ( );
} else {
idMat3 jointAxis;
idVec3 jointLoc;
static_cast<idAnimatedEntity *>(guideEnt.GetEntity())->GetJointWorldTransform( jointGuideEnt, gameLocal.GetTime(),jointLoc,jointAxis );
eyePos += jointLoc;
}
eyePos *= 0.5f;
if ( guideEffect ) {
guideEffect->SetOrigin ( eyePos );
guideEffect->SetAxis ( playerViewAxis.Transpose() );
} else {
guideEffect = gameLocal.PlayEffect (
gameLocal.GetEffect( spawnArgs, guideLocked ? "fx_guide" : "fx_guidestart" ),
eyePos, playerViewAxis.Transpose(), true, vec3_origin, false );
if ( guideEffect ) {
guideEffect->GetRenderEffect()->weaponDepthHackInViewID = owner->entityNumber + 1;
guideEffect->GetRenderEffect()->allowSurfaceInViewID = owner->entityNumber + 1;
}
}
} else {
if ( guideEffect ) {
guideEffect->Stop();
guideEffect = NULL;
}
}
}
/*
================
rvWeaponNailgun::Think
================
*/
void rvWeaponNailgun::Think ( void ) {
idEntity* ent;
trace_t tr;
// Let the real weapon think first
rvWeapon::Think ( );
// If no guide range is set then we dont have the mod yet
if ( !guideRange ) {
return;
}
// If the zoom button isnt down then dont update the lock
if ( !wsfl.zoom || IsReloading ( ) || IsHolstered ( ) ) {
CancelGuide ( );
return;
}
// Dont update the target if the current target is still alive, unhidden and we have already locked
if ( guideEnt && guideEnt->health > 0 && !guideEnt->IsHidden() && guideLocked ) {
float range;
range = (guideEnt->GetPhysics()->GetOrigin() - playerViewOrigin).LengthFast();
if ( range > guideRange || gameLocal.time > guideStartTime + guideTime ) {
CancelGuide ( );
} else {
UpdateGuideStatus ( range );
return;
}
}
// Cast a ray out to the lock range
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.TracePoint( owner, tr,
playerViewOrigin,
playerViewOrigin + playerViewAxis[0] * guideRange,
MASK_SHOT_BOUNDINGBOX, owner );
// RAVEN END
if ( tr.fraction >= 1.0f ) {
CancelGuide( );
return;
}
ent = gameLocal.entities[tr.c.entityNum];
//if we're using a target nailable...
if( ent->IsType ( rvTarget_Nailable::GetClassType() ) ) {
const char* jointName = ent->spawnArgs.GetString("lock_joint");
ent = ent->targets[ 0 ].GetEntity();
if( !ent) {
CancelGuide( );
return;
}
if( ent->GetAnimator() ) {
jointGuideEnt = ent->GetAnimator()->GetJointHandle( jointName );
}
}
if ( !ent->IsType ( idActor::GetClassType() ) ) {
CancelGuide( );
return;
}
if ( gameLocal.GetLocalPlayer() && static_cast<idActor *>(ent)->team == gameLocal.GetLocalPlayer()->team ) {
CancelGuide( );
return;
}
if ( guideEnt != ent ) {
guideStartTime = gameLocal.time;
guideTime = guideAquireTime;
guideEnt = ent;
if ( zoomGui ) {
zoomGui->HandleNamedEvent ( "lockStart" );
}
} else if ( gameLocal.time > guideStartTime + guideTime ) {
// Stop the guide effect since it was just the guide_Start effect
if ( guideEffect ) {
guideEffect->Stop();
guideEffect = NULL;
}
guideLocked = true;
guideTime = guideHoldTime;
guideStartTime = gameLocal.time;
if ( zoomGui ) {
zoomGui->HandleNamedEvent ( "lockAquired" );
}
}
UpdateGuideStatus ( (ent->GetPhysics()->GetOrigin() - playerViewOrigin).LengthFast() );
}
/*
================
rvWeaponNailgun::OnLaunchProjectile
================
*/
void rvWeaponNailgun::OnLaunchProjectile ( idProjectile* proj ) {
rvWeapon::OnLaunchProjectile(proj);
idGuidedProjectile* guided;
guided = dynamic_cast<idGuidedProjectile*>(proj);
if ( guided ) {
guided->GuideTo ( guideEnt, jointGuideEnt );
}
}
/*
================
rvWeaponNailgun::DrumSpin
Set the drum spin speed
================
*/
bool rvWeaponNailgun::DrumSpin ( int speed, int blendFrames ) {
// Dont bother if the drum is already spinning at the desired speed
if ( drumSpeedIdeal == speed ) {
return false;
}
drumSpeedIdeal = speed;
switch ( speed ) {
case NAILGUN_DRUMSPEED_STOPPED:
viewModel->StopSound ( NAILGUN_SPIN_SNDCHANNEL, false );
viewAnimator->SetJointAngularVelocity ( jointDrumView, idAngles(0,0,0), gameLocal.time, 250 );
viewAnimator->SetJointAngularVelocity ( jointPinsView, idAngles(0,0,0), gameLocal.time, 250 );
// Spin the barrel down if we were spinning fast
if ( drumSpeed == NAILGUN_DRUMSPEED_FAST ) {
PostState ( "DrumSpinDown", blendFrames );
return true;
}
break;
case NAILGUN_DRUMSPEED_SLOW:
viewAnimator->SetJointAngularVelocity ( jointDrumView, idAngles(0,0,45), gameLocal.time, NAILGUN_SPINDOWN_TIME );
viewAnimator->SetJointAngularVelocity ( jointPinsView, idAngles(0,0,-35), gameLocal.time, NAILGUN_SPINDOWN_TIME );
viewModel->StopSound ( NAILGUN_SPIN_SNDCHANNEL, false );
viewModel->StartSound ( "snd_spinslow", NAILGUN_SPIN_SNDCHANNEL, 0, false, NULL );
// Spin the barrel down if we were spinning fast
if ( drumSpeed == NAILGUN_DRUMSPEED_FAST ) {
PostState ( "DrumSpinDown", blendFrames );
return true;
}
break;
case NAILGUN_DRUMSPEED_FAST:
// Start the barrel spinning faster
viewAnimator->SetJointAngularVelocity ( jointDrumView, idAngles(0,0,360.0f * drumMultiplier), gameLocal.time, NAILGUN_SPINUP_TIME );
viewAnimator->SetJointAngularVelocity ( jointPinsView, idAngles(0,0,-300.0f * drumMultiplier), gameLocal.time, NAILGUN_SPINUP_TIME );
PostState ( "DrumSpinUp", blendFrames );
return true;
}
drumSpeed = drumSpeedIdeal;
return false;
}
/*
===============================================================================
States
===============================================================================
*/
CLASS_STATES_DECLARATION ( rvWeaponNailgun )
STATE ( "Raise", rvWeaponNailgun::State_Raise )
STATE ( "Lower", rvWeaponNailgun::State_Lower )
STATE ( "Idle", rvWeaponNailgun::State_Idle)
STATE ( "Fire", rvWeaponNailgun::State_Fire )
STATE ( "Reload", rvWeaponNailgun::State_Reload )
STATE ( "DrumSpinDown", rvWeaponNailgun::State_DrumSpinDown )
STATE ( "DrumSpinUp", rvWeaponNailgun::State_DrumSpinUp )
STATE ( "ClaspOpen", rvWeaponNailgun::Frame_ClaspOpen )
STATE ( "ClaspClose", rvWeaponNailgun::Frame_ClaspClose )
END_CLASS_STATES
/*
================
rvWeaponNailgun::State_Raise
Raise the weapon
================
*/
stateResult_t rvWeaponNailgun::State_Raise ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
};
switch ( parms.stage ) {
// Start the weapon raising
case STAGE_INIT:
SetStatus ( WP_RISING );
PlayAnim( ANIMCHANNEL_LEGS, "raise", 0 );
DrumSpin ( NAILGUN_DRUMSPEED_SLOW, 0 );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) {
SetState ( "Idle", 4 );
return SRESULT_DONE;
}
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_Lower
Lower the weapon
================
*/
stateResult_t rvWeaponNailgun::State_Lower ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
STAGE_WAITRAISE
};
switch ( parms.stage ) {
case STAGE_INIT:
// Stop any looping sounds
viewModel->StopSound ( NAILGUN_SPIN_SNDCHANNEL, false );
SetStatus ( WP_LOWERING );
PlayAnim ( ANIMCHANNEL_LEGS, "putaway", parms.blendFrames );
return SRESULT_STAGE(STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 0 ) ) {
SetStatus ( WP_HOLSTERED );
return SRESULT_STAGE(STAGE_WAITRAISE);
}
return SRESULT_WAIT;
case STAGE_WAITRAISE:
if ( wsfl.raiseWeapon ) {
SetState ( "Raise", 0 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_Idle
Manage the idle state of the weapon
================
*/
stateResult_t rvWeaponNailgun::State_Idle( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
};
switch ( parms.stage ) {
case STAGE_INIT:
if ( !AmmoInClip ( ) ) {
SetStatus ( WP_OUTOFAMMO );
} else {
SetStatus ( WP_READY );
}
// Do we need to spin the drum down?
if ( DrumSpin ( NAILGUN_DRUMSPEED_SLOW, parms.blendFrames ) ) {
PostState ( "Idle", parms.blendFrames );
return SRESULT_DONE;
}
PlayCycle( ANIMCHANNEL_LEGS, "idle", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
if ( !clipSize ) {
if ( gameLocal.time > nextAttackTime && wsfl.attack && AmmoAvailable ( ) ) {
SetState ( "Fire", 0 );
return SRESULT_DONE;
}
} else {
if ( gameLocal.time > nextAttackTime && wsfl.attack && AmmoInClip ( ) ) {
SetState ( "Fire", 0 );
return SRESULT_DONE;
}
if ( wsfl.attack && AutoReload() && !AmmoInClip ( ) && AmmoAvailable () ) {
SetState ( "Reload", 4 );
return SRESULT_DONE;
}
if ( wsfl.netReload || (wsfl.reload && AmmoInClip() < ClipSize() && AmmoAvailable()>AmmoInClip()) ) {
SetState ( "Reload", 4 );
return SRESULT_DONE;
}
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_Fire
Fire the weapon
================
*/
stateResult_t rvWeaponNailgun::State_Fire( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_FIRE,
STAGE_FIREWAIT,
STAGE_DONE,
STAGE_SPINEMPTY,
};
switch ( parms.stage ) {
case STAGE_INIT:
if ( !wsfl.attack ) {
SetState ( "Idle", parms.blendFrames );
return SRESULT_DONE;
}
if ( DrumSpin ( NAILGUN_DRUMSPEED_FAST, 2 ) ) {
PostState ( "Fire", 2 );
return SRESULT_DONE;
}
nextAttackTime = gameLocal.time;
return SRESULT_STAGE ( STAGE_FIRE );
case STAGE_FIRE:
if ( !wsfl.attack || wsfl.reload || wsfl.lowerWeapon || !AmmoInClip ( ) ) {
return SRESULT_STAGE ( STAGE_DONE );
}
if ( mods & NAILGUN_MOD_ROF_AMMO ) {
PlayCycle ( ANIMCHANNEL_LEGS, "fire_fast", 4 );
} else {
PlayCycle ( ANIMCHANNEL_LEGS, "fire_slow", 4 );
}
if ( wsfl.zoom ) {
Attack ( true, 1, spread, 0.0f, 1.0f );
nextAttackTime = gameLocal.time + (altFireRate * owner->PowerUpModifier ( PMOD_FIRERATE ));
} else {
Attack ( false, 1, spread, 0.0f, 1.0f );
nextAttackTime = gameLocal.time + (fireRate * owner->PowerUpModifier ( PMOD_FIRERATE ));
}
// Play the exhaust effects
viewModel->PlayEffect ( "fx_exhaust", jointSteamRightView, false );
viewModel->PlayEffect ( "fx_exhaust", jointSteamLeftView, false );
viewModel->StartSound ( "snd_fire", SND_CHANNEL_WEAPON, 0, false, NULL );
viewModel->StartSound ( "snd_fireStereo", SND_CHANNEL_ITEM, 0, false, NULL );
return SRESULT_STAGE ( STAGE_FIREWAIT );
case STAGE_FIREWAIT:
if ( !wsfl.attack || wsfl.reload || wsfl.lowerWeapon || !AmmoInClip ( ) ) {
return SRESULT_STAGE ( STAGE_DONE );
}
if ( gameLocal.time >= nextAttackTime ) {
return SRESULT_STAGE ( STAGE_FIRE );
}
return SRESULT_WAIT;
case STAGE_DONE:
if ( clipSize && wsfl.attack && !wsfl.lowerWeapon && !wsfl.reload ) {
PlayCycle ( ANIMCHANNEL_LEGS, "spinempty", 4 );
return SRESULT_STAGE ( STAGE_SPINEMPTY );
}
DrumSpin ( NAILGUN_DRUMSPEED_SLOW, 4 );
if ( !wsfl.attack && !AmmoInClip() && AmmoAvailable() && AutoReload ( ) && !wsfl.lowerWeapon ) {
PostState ( "Reload", 4 );
} else {
PostState ( "Idle", 4 );
}
return SRESULT_DONE;
case STAGE_SPINEMPTY:
if ( !wsfl.attack || wsfl.reload || wsfl.lowerWeapon ) {
return SRESULT_STAGE ( STAGE_DONE );
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_Reload
================
*/
stateResult_t rvWeaponNailgun::State_Reload ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_RELOAD,
STAGE_RELOADWAIT,
STAGE_RELOADLEFT,
STAGE_RELOADLEFTWAIT,
STAGE_RELOADRIGHT,
STAGE_RELOADRIGHTWAIT,
STAGE_RELOADDONE,
STAGE_RELOADDONEWAIT,
};
switch ( parms.stage ) {
case STAGE_INIT:
if ( DrumSpin ( NAILGUN_DRUMSPEED_STOPPED, parms.blendFrames ) ) {
PostState ( "reload", parms.blendFrames );
return SRESULT_DONE;
}
SetStatus ( WP_RELOAD );
if ( wsfl.netReload ) {
wsfl.netReload = false;
} else {
NetReload ( );
}
if ( mods & NAILGUN_MOD_ROF_AMMO ) {
return SRESULT_STAGE( STAGE_RELOADLEFT );
}
return SRESULT_STAGE( STAGE_RELOAD );
case STAGE_RELOAD:
PlayAnim( ANIMCHANNEL_LEGS, "reload", parms.blendFrames );
return SRESULT_STAGE( STAGE_RELOADWAIT );
case STAGE_RELOADWAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) {
AddToClip( ClipSize ( ) );
SetState ( "Idle", 4 );
return SRESULT_DONE;
}
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
case STAGE_RELOADLEFT:
PlayAnim ( ANIMCHANNEL_LEGS, "reload_clip1hold", parms.blendFrames );
return SRESULT_STAGE ( STAGE_RELOADLEFTWAIT );
case STAGE_RELOADLEFTWAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 0 ) ) {
AddToClip ( ClipSize() / 2 );
return SRESULT_STAGE ( STAGE_RELOADRIGHT );
}
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
case STAGE_RELOADRIGHT:
if ( wsfl.attack || AmmoInClip() >= ClipSize() || !AmmoAvailable() ) {
return SRESULT_STAGE ( STAGE_RELOADDONE );
}
PlayAnim ( ANIMCHANNEL_LEGS, "reload_clip2", 0 );
return SRESULT_STAGE ( STAGE_RELOADRIGHTWAIT );
case STAGE_RELOADRIGHTWAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) {
AddToClip( ClipSize() / 2 );
SetState ( "Idle", 4 );
return SRESULT_DONE;
}
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
case STAGE_RELOADDONE:
PlayAnim ( ANIMCHANNEL_LEGS, "reload_clip1finish", 0 );
return SRESULT_STAGE ( STAGE_RELOADDONEWAIT );
case STAGE_RELOADDONEWAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) {
SetState ( "Idle", 4 );
return SRESULT_DONE;
}
if ( wsfl.lowerWeapon ) {
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_DrumSpinUp
Spin the drum from a slow speed to a fast speed
================
*/
stateResult_t rvWeaponNailgun::State_DrumSpinUp ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
};
switch ( parms.stage ) {
case STAGE_INIT:
viewModel->StartSound ( "snd_spinup", NAILGUN_SPIN_SNDCHANNEL, 0, false, NULL);
PlayAnim ( ANIMCHANNEL_LEGS, "spinup", 4 );
return SRESULT_STAGE(STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 0 ) ) {
viewModel->StartSound ( "snd_spinfast", NAILGUN_SPIN_SNDCHANNEL, 0, false, NULL );
drumSpeed = drumSpeedIdeal;
return SRESULT_DONE;
}
if ( !wsfl.attack ) {
int oldSpeed = drumSpeed;
drumSpeed = drumSpeedIdeal;
DrumSpin ( oldSpeed, 0 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::State_DrumSpinDown
Spin the drum down from a faster speed
================
*/
stateResult_t rvWeaponNailgun::State_DrumSpinDown ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
};
switch ( parms.stage ) {
case STAGE_INIT:
viewModel->StartSound ( "snd_spindown", SND_CHANNEL_ANY, 0, false, 0 );
// Spin down animation
PlayAnim( ANIMCHANNEL_LEGS, "spindown", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) {
drumSpeed = drumSpeedIdeal;
return SRESULT_DONE;
}
if ( wsfl.lowerWeapon ) {
viewModel->StopSound ( NAILGUN_SPIN_SNDCHANNEL, false );
SetState ( "Lower", 4 );
return SRESULT_DONE;
}
if ( wsfl.attack && AmmoInClip ( ) ) {
viewModel->StopSound ( NAILGUN_SPIN_SNDCHANNEL, false );
SetState ( "Fire", 4 );
return SRESULT_DONE;
}
if ( wsfl.netReload || (wsfl.reload && AmmoAvailable() > AmmoInClip() && AmmoInClip() < ClipSize()) ) {
SetState ( "Reload", 4 );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvWeaponNailgun::Frame_ClaspOpen
Open the clasp that holds in the clips
================
*/
stateResult_t rvWeaponNailgun::Frame_ClaspOpen ( const stateParms_t& parms ) {
PlayAnim ( ANIMCHANNEL_TORSO, "clasp_open", 0 );
return SRESULT_OK;
}
/*
================
rvWeaponNailgun::Frame_ClaspOpen
Close the clasp that holds in the clips and make sure to use the
correct positioning depending on whether you have one or two clips
in the gun.
================
*/
stateResult_t rvWeaponNailgun::Frame_ClaspClose ( const stateParms_t& parms ) {
if ( mods & NAILGUN_MOD_ROF_AMMO ) {
PlayAnim( ANIMCHANNEL_TORSO, "clasp_2clip", 0 );
} else {
PlayAnim( ANIMCHANNEL_TORSO, "clasp_1clip", 0 );
}
return SRESULT_OK;
}