quake4-sdk/source/game/weapon/WeaponGauntlet.cpp
2007-06-15 00:00:00 +00:00

514 lines
12 KiB
C++

#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<idClass*&>( 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<idActor*>(ent);
} else if (ent->IsType ( idAFAttachment::GetClassType()) ) {
actor_ent = static_cast<idActor*>(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;
return SRESULT_STAGE(STAGE_START_WAIT);
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;
}