289 lines
6.6 KiB
C++
289 lines
6.6 KiB
C++
#include "../../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "../Game_local.h"
|
|
#include "../Weapon.h"
|
|
|
|
const int SHOTGUN_MOD_AMMO = BIT(0);
|
|
|
|
class rvWeaponShotgun : public rvWeapon {
|
|
public:
|
|
|
|
CLASS_PROTOTYPE( rvWeaponShotgun );
|
|
|
|
rvWeaponShotgun ( void );
|
|
|
|
virtual void Spawn ( void );
|
|
void Save ( idSaveGame *savefile ) const;
|
|
void Restore ( idRestoreGame *savefile );
|
|
void PreSave ( void );
|
|
void PostSave ( void );
|
|
|
|
protected:
|
|
int hitscans;
|
|
|
|
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( rvWeaponShotgun );
|
|
};
|
|
|
|
CLASS_DECLARATION( rvWeapon, rvWeaponShotgun )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::rvWeaponShotgun
|
|
================
|
|
*/
|
|
rvWeaponShotgun::rvWeaponShotgun( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::Spawn
|
|
================
|
|
*/
|
|
void rvWeaponShotgun::Spawn( void ) {
|
|
hitscans = spawnArgs.GetFloat( "hitscans" );
|
|
|
|
SetState( "Raise", 0 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::Save
|
|
================
|
|
*/
|
|
void rvWeaponShotgun::Save( idSaveGame *savefile ) const {
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::Restore
|
|
================
|
|
*/
|
|
void rvWeaponShotgun::Restore( idRestoreGame *savefile ) {
|
|
hitscans = spawnArgs.GetFloat( "hitscans" );
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::PreSave
|
|
================
|
|
*/
|
|
void rvWeaponShotgun::PreSave ( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::PostSave
|
|
================
|
|
*/
|
|
void rvWeaponShotgun::PostSave ( void ) {
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
States
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_STATES_DECLARATION( rvWeaponShotgun )
|
|
STATE( "Idle", rvWeaponShotgun::State_Idle)
|
|
STATE( "Fire", rvWeaponShotgun::State_Fire )
|
|
STATE( "Reload", rvWeaponShotgun::State_Reload )
|
|
END_CLASS_STATES
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::State_Idle
|
|
================
|
|
*/
|
|
stateResult_t rvWeaponShotgun::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 );
|
|
}
|
|
|
|
PlayCycle( ANIMCHANNEL_ALL, "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;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::State_Fire
|
|
================
|
|
*/
|
|
stateResult_t rvWeaponShotgun::State_Fire( const stateParms_t& parms ) {
|
|
enum {
|
|
STAGE_INIT,
|
|
STAGE_WAIT,
|
|
};
|
|
switch ( parms.stage ) {
|
|
case STAGE_INIT:
|
|
nextAttackTime = gameLocal.time + (fireRate * owner->PowerUpModifier ( PMOD_FIRERATE ));
|
|
Attack( false, hitscans, spread, 0, 1.0f );
|
|
PlayAnim( ANIMCHANNEL_ALL, "fire", 0 );
|
|
return SRESULT_STAGE( STAGE_WAIT );
|
|
|
|
case STAGE_WAIT:
|
|
if ( (!gameLocal.isMultiplayer && (wsfl.lowerWeapon || AnimDone( ANIMCHANNEL_ALL, 0 )) ) || AnimDone( ANIMCHANNEL_ALL, 0 ) ) {
|
|
SetState( "Idle", 0 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( wsfl.attack && gameLocal.time >= nextAttackTime && AmmoInClip() ) {
|
|
SetState( "Fire", 0 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( clipSize ) {
|
|
if ( (wsfl.netReload || (wsfl.reload && AmmoInClip() < ClipSize() && AmmoAvailable()>AmmoInClip())) ) {
|
|
SetState( "Reload", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
}
|
|
return SRESULT_WAIT;
|
|
}
|
|
return SRESULT_ERROR;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvWeaponShotgun::State_Reload
|
|
================
|
|
*/
|
|
stateResult_t rvWeaponShotgun::State_Reload ( const stateParms_t& parms ) {
|
|
enum {
|
|
STAGE_INIT,
|
|
STAGE_WAIT,
|
|
STAGE_RELOADSTARTWAIT,
|
|
STAGE_RELOADLOOP,
|
|
STAGE_RELOADLOOPWAIT,
|
|
STAGE_RELOADDONE,
|
|
STAGE_RELOADDONEWAIT
|
|
};
|
|
switch ( parms.stage ) {
|
|
case STAGE_INIT:
|
|
if ( wsfl.netReload ) {
|
|
wsfl.netReload = false;
|
|
} else {
|
|
NetReload ( );
|
|
}
|
|
|
|
SetStatus ( WP_RELOAD );
|
|
|
|
if ( mods & SHOTGUN_MOD_AMMO ) {
|
|
PlayAnim ( ANIMCHANNEL_ALL, "reload_clip", parms.blendFrames );
|
|
} else {
|
|
PlayAnim ( ANIMCHANNEL_ALL, "reload_start", parms.blendFrames );
|
|
return SRESULT_STAGE ( STAGE_RELOADSTARTWAIT );
|
|
}
|
|
return SRESULT_STAGE ( STAGE_WAIT );
|
|
|
|
case STAGE_WAIT:
|
|
if ( AnimDone ( ANIMCHANNEL_ALL, 4 ) ) {
|
|
AddToClip ( ClipSize() );
|
|
SetState ( "Idle", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( wsfl.lowerWeapon ) {
|
|
SetState ( "Lower", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
return SRESULT_WAIT;
|
|
|
|
case STAGE_RELOADSTARTWAIT:
|
|
if ( AnimDone ( ANIMCHANNEL_ALL, 0 ) ) {
|
|
return SRESULT_STAGE ( STAGE_RELOADLOOP );
|
|
}
|
|
if ( wsfl.lowerWeapon ) {
|
|
SetState ( "Lower", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
return SRESULT_WAIT;
|
|
|
|
case STAGE_RELOADLOOP:
|
|
if ( (wsfl.attack && AmmoInClip() ) || AmmoAvailable ( ) <= AmmoInClip ( ) || AmmoInClip() == ClipSize() ) {
|
|
return SRESULT_STAGE ( STAGE_RELOADDONE );
|
|
}
|
|
PlayAnim ( ANIMCHANNEL_ALL, "reload_loop", 0 );
|
|
return SRESULT_STAGE ( STAGE_RELOADLOOPWAIT );
|
|
|
|
case STAGE_RELOADLOOPWAIT:
|
|
if ( (wsfl.attack && AmmoInClip() ) || wsfl.netEndReload ) {
|
|
return SRESULT_STAGE ( STAGE_RELOADDONE );
|
|
}
|
|
if ( wsfl.lowerWeapon ) {
|
|
SetState ( "Lower", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( AnimDone ( ANIMCHANNEL_ALL, 0 ) ) {
|
|
AddToClip( 1 );
|
|
return SRESULT_STAGE ( STAGE_RELOADLOOP );
|
|
}
|
|
return SRESULT_WAIT;
|
|
|
|
case STAGE_RELOADDONE:
|
|
NetEndReload ( );
|
|
PlayAnim ( ANIMCHANNEL_ALL, "reload_end", 0 );
|
|
return SRESULT_STAGE ( STAGE_RELOADDONEWAIT );
|
|
|
|
case STAGE_RELOADDONEWAIT:
|
|
if ( wsfl.lowerWeapon ) {
|
|
SetState ( "Lower", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( wsfl.attack && AmmoInClip ( ) && gameLocal.time > nextAttackTime ) {
|
|
SetState ( "Fire", 0 );
|
|
return SRESULT_DONE;
|
|
}
|
|
if ( AnimDone ( ANIMCHANNEL_ALL, 4 ) ) {
|
|
SetState ( "Idle", 4 );
|
|
return SRESULT_DONE;
|
|
}
|
|
return SRESULT_WAIT;
|
|
}
|
|
return SRESULT_ERROR;
|
|
}
|
|
|