You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1052 lines
26 KiB
1052 lines
26 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "gamerules.h" |
|
#include "npcevent.h" |
|
#include "in_buttons.h" |
|
#include "engine/IEngineSound.h" |
|
|
|
#if defined( CLIENT_DLL ) |
|
#include "c_hl2mp_player.h" |
|
#else |
|
#include "hl2mp_player.h" |
|
#include "grenade_tripmine.h" |
|
#include "grenade_satchel.h" |
|
#include "entitylist.h" |
|
#include "eventqueue.h" |
|
#endif |
|
|
|
#include "hl2mp/weapon_slam.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define SLAM_PRIMARY_VOLUME 450 |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( Weapon_SLAM, DT_Weapon_SLAM ) |
|
|
|
BEGIN_NETWORK_TABLE( CWeapon_SLAM, DT_Weapon_SLAM ) |
|
#ifdef CLIENT_DLL |
|
RecvPropInt( RECVINFO( m_tSlamState ) ), |
|
RecvPropBool( RECVINFO( m_bDetonatorArmed ) ), |
|
RecvPropBool( RECVINFO( m_bNeedDetonatorDraw ) ), |
|
RecvPropBool( RECVINFO( m_bNeedDetonatorHolster ) ), |
|
RecvPropBool( RECVINFO( m_bNeedReload ) ), |
|
RecvPropBool( RECVINFO( m_bClearReload ) ), |
|
RecvPropBool( RECVINFO( m_bThrowSatchel ) ), |
|
RecvPropBool( RECVINFO( m_bAttachSatchel ) ), |
|
RecvPropBool( RECVINFO( m_bAttachTripmine ) ), |
|
#else |
|
SendPropInt( SENDINFO( m_tSlamState ) ), |
|
SendPropBool( SENDINFO( m_bDetonatorArmed ) ), |
|
SendPropBool( SENDINFO( m_bNeedDetonatorDraw ) ), |
|
SendPropBool( SENDINFO( m_bNeedDetonatorHolster ) ), |
|
SendPropBool( SENDINFO( m_bNeedReload ) ), |
|
SendPropBool( SENDINFO( m_bClearReload ) ), |
|
SendPropBool( SENDINFO( m_bThrowSatchel ) ), |
|
SendPropBool( SENDINFO( m_bAttachSatchel ) ), |
|
SendPropBool( SENDINFO( m_bAttachTripmine ) ), |
|
#endif |
|
END_NETWORK_TABLE() |
|
|
|
#ifdef CLIENT_DLL |
|
|
|
BEGIN_PREDICTION_DATA( CWeapon_SLAM ) |
|
DEFINE_PRED_FIELD( m_tSlamState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bDetonatorArmed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bNeedDetonatorDraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bNeedDetonatorHolster, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bNeedReload, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bClearReload, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bThrowSatchel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bAttachSatchel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bAttachTripmine, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
END_PREDICTION_DATA() |
|
|
|
#endif |
|
|
|
LINK_ENTITY_TO_CLASS( weapon_slam, CWeapon_SLAM ); |
|
PRECACHE_WEAPON_REGISTER(weapon_slam); |
|
|
|
#ifndef CLIENT_DLL |
|
|
|
BEGIN_DATADESC( CWeapon_SLAM ) |
|
|
|
DEFINE_FIELD( m_tSlamState, FIELD_INTEGER ), |
|
DEFINE_FIELD( m_bDetonatorArmed, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bNeedDetonatorDraw, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bNeedDetonatorHolster, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bNeedReload, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bClearReload, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bThrowSatchel, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bAttachSatchel, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bAttachTripmine, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_flWallSwitchTime, FIELD_TIME ), |
|
|
|
// Function Pointers |
|
DEFINE_FUNCTION( SlamTouch ), |
|
|
|
END_DATADESC() |
|
|
|
acttable_t CWeapon_SLAM::m_acttable[] = |
|
{ |
|
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, |
|
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SLAM, false }, |
|
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_SLAM, false }, |
|
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SLAM, false }, |
|
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SLAM, false }, |
|
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM, false }, |
|
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SLAM, false }, |
|
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SLAM, false }, |
|
}; |
|
|
|
IMPLEMENT_ACTTABLE(CWeapon_SLAM); |
|
#endif |
|
|
|
|
|
void CWeapon_SLAM::Spawn( ) |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
Precache( ); |
|
|
|
FallInit();// get ready to fall down |
|
|
|
m_tSlamState = (int)SLAM_SATCHEL_THROW; |
|
m_flWallSwitchTime = 0; |
|
|
|
// Give 1 piece of default ammo when first picked up |
|
m_iClip2 = 1; |
|
} |
|
|
|
void CWeapon_SLAM::Precache( void ) |
|
{ |
|
BaseClass::Precache(); |
|
|
|
#ifndef CLIENT_DLL |
|
UTIL_PrecacheOther( "npc_tripmine" ); |
|
UTIL_PrecacheOther( "npc_satchel" ); |
|
#endif |
|
|
|
PrecacheScriptSound( "Weapon_SLAM.TripMineMode" ); |
|
PrecacheScriptSound( "Weapon_SLAM.SatchelDetonate" ); |
|
PrecacheScriptSound( "Weapon_SLAM.SatchelThrow" ); |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : Override to use slam's pickup touch function |
|
// Input : |
|
// Output : |
|
//------------------------------------------------------------------------------ |
|
void CWeapon_SLAM::SetPickupTouch( void ) |
|
{ |
|
SetTouch(&CWeapon_SLAM::SlamTouch); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Override so give correct ammo |
|
// Input : pOther - the entity that touched me |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SlamTouch( CBaseEntity *pOther ) |
|
{ |
|
#ifdef GAME_DLL |
|
CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther ); |
|
|
|
// Can I even pick stuff up? |
|
if ( pBCC && !pBCC->IsAllowedToPickupWeapons() ) |
|
return; |
|
#endif |
|
|
|
// --------------------------------------------------- |
|
// First give weapon to touching entity if allowed |
|
// --------------------------------------------------- |
|
BaseClass::DefaultTouch(pOther); |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : |
|
// Input : |
|
// Output : |
|
//------------------------------------------------------------------------------ |
|
bool CWeapon_SLAM::Holster( CBaseCombatWeapon *pSwitchingTo ) |
|
{ |
|
SetThink(NULL); |
|
return BaseClass::Holster(pSwitchingTo); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: SLAM has no reload, but must call weapon idle to update state |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
bool CWeapon_SLAM::Reload( void ) |
|
{ |
|
WeaponIdle( ); |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::PrimaryAttack( void ) |
|
{ |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0) |
|
{ |
|
return; |
|
} |
|
|
|
switch (m_tSlamState) |
|
{ |
|
case SLAM_TRIPMINE_READY: |
|
if (CanAttachSLAM()) |
|
{ |
|
StartTripmineAttach(); |
|
} |
|
break; |
|
case SLAM_SATCHEL_THROW: |
|
StartSatchelThrow(); |
|
break; |
|
case SLAM_SATCHEL_ATTACH: |
|
StartSatchelAttach(); |
|
break; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Secondary attack switches between satchel charge and tripmine mode |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SecondaryAttack( void ) |
|
{ |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
if (m_bDetonatorArmed) |
|
{ |
|
StartSatchelDetonate(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SatchelDetonate() |
|
{ |
|
#ifndef CLIENT_DLL |
|
CBaseEntity *pEntity = NULL; |
|
|
|
while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL) |
|
{ |
|
CSatchelCharge *pSatchel = dynamic_cast<CSatchelCharge *>(pEntity); |
|
if (pSatchel->m_bIsLive && pSatchel->GetThrower() && GetOwner() && pSatchel->GetThrower() == GetOwner()) |
|
{ |
|
//pSatchel->Use( GetOwner(), GetOwner(), USE_ON, 0 ); |
|
//variant_t emptyVariant; |
|
//pSatchel->AcceptInput( "Explode", NULL, NULL, emptyVariant, 5 ); |
|
g_EventQueue.AddEvent( pSatchel, "Explode", 0.20, GetOwner(), GetOwner() ); |
|
} |
|
} |
|
#endif |
|
// Play sound for pressing the detonator |
|
EmitSound( "Weapon_SLAM.SatchelDetonate" ); |
|
|
|
m_bDetonatorArmed = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns true if there are any undetonated charges in the world |
|
// that belong to this player |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
bool CWeapon_SLAM::AnyUndetonatedCharges(void) |
|
{ |
|
#ifndef CLIENT_DLL |
|
CBaseEntity *pEntity = NULL; |
|
|
|
while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL) |
|
{ |
|
CSatchelCharge* pSatchel = dynamic_cast<CSatchelCharge *>(pEntity); |
|
if (pSatchel->m_bIsLive && pSatchel->GetThrower() && pSatchel->GetThrower() == GetOwner()) |
|
{ |
|
return true; |
|
} |
|
} |
|
#endif |
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::StartSatchelDetonate() |
|
{ |
|
|
|
if ( GetActivity() != ACT_SLAM_DETONATOR_IDLE && GetActivity() != ACT_SLAM_THROW_IDLE && !m_bDetonatorArmed ) |
|
return; |
|
|
|
// ----------------------------------------- |
|
// Play detonate animation |
|
// ----------------------------------------- |
|
if (m_bNeedReload) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_DETONATOR_DETONATE); |
|
} |
|
else if (m_tSlamState == SLAM_SATCHEL_ATTACH || m_tSlamState == SLAM_TRIPMINE_READY) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_STICKWALL_DETONATE); |
|
} |
|
else if (m_tSlamState == SLAM_SATCHEL_THROW) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_THROW_DETONATE); |
|
} |
|
else |
|
{ |
|
return; |
|
} |
|
SatchelDetonate(); |
|
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::TripmineAttach( void ) |
|
{ |
|
CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
m_bAttachTripmine = false; |
|
|
|
Vector vecSrc, vecAiming; |
|
|
|
// Take the eye position and direction |
|
vecSrc = pOwner->EyePosition(); |
|
|
|
QAngle angles = pOwner->GetLocalAngles(); |
|
|
|
AngleVectors( angles, &vecAiming ); |
|
|
|
trace_t tr; |
|
|
|
UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if (tr.fraction < 1.0) |
|
{ |
|
CBaseEntity *pEntity = tr.m_pEnt; |
|
if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR)) |
|
{ |
|
|
|
#ifndef CLIENT_DLL |
|
QAngle angles; |
|
VectorAngles(tr.plane.normal, angles); |
|
|
|
angles.x += 90; |
|
|
|
CBaseEntity *pEnt = CBaseEntity::Create( "npc_tripmine", tr.endpos + tr.plane.normal * 3, angles, NULL ); |
|
|
|
CTripmineGrenade *pMine = (CTripmineGrenade *)pEnt; |
|
pMine->m_hOwner = GetOwner(); |
|
|
|
#endif |
|
|
|
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::StartTripmineAttach( void ) |
|
{ |
|
// Only the player fires this way so we can cast |
|
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); |
|
if (!pPlayer) |
|
{ |
|
return; |
|
} |
|
|
|
Vector vecSrc, vecAiming; |
|
|
|
// Take the eye position and direction |
|
vecSrc = pPlayer->EyePosition(); |
|
|
|
QAngle angles = pPlayer->GetLocalAngles(); |
|
|
|
AngleVectors( angles, &vecAiming ); |
|
|
|
trace_t tr; |
|
|
|
UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if (tr.fraction < 1.0) |
|
{ |
|
// ALERT( at_console, "hit %f\n", tr.flFraction ); |
|
|
|
CBaseEntity *pEntity = tr.m_pEnt; |
|
if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR)) |
|
{ |
|
// player "shoot" animation |
|
pPlayer->SetAnimation( PLAYER_ATTACK1 ); |
|
|
|
// ----------------------------------------- |
|
// Play attach animation |
|
// ----------------------------------------- |
|
|
|
if (m_bDetonatorArmed) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_STICKWALL_ATTACH); |
|
} |
|
else |
|
{ |
|
SendWeaponAnim(ACT_SLAM_TRIPMINE_ATTACH); |
|
} |
|
|
|
m_bNeedReload = true; |
|
m_bAttachTripmine = true; |
|
m_bNeedDetonatorDraw = m_bDetonatorArmed; |
|
} |
|
else |
|
{ |
|
// ALERT( at_console, "no deploy\n" ); |
|
} |
|
} |
|
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
// SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SatchelThrow( void ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
m_bThrowSatchel = false; |
|
|
|
// Only the player fires this way so we can cast |
|
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); |
|
|
|
Vector vecSrc = pPlayer->WorldSpaceCenter(); |
|
Vector vecFacing = pPlayer->BodyDirection3D( ); |
|
vecSrc = vecSrc + vecFacing * 18.0; |
|
// BUGBUG: is this because vecSrc is not from Weapon_ShootPosition()??? |
|
vecSrc.z += 24.0f; |
|
|
|
Vector vecThrow; |
|
GetOwner()->GetVelocity( &vecThrow, NULL ); |
|
vecThrow += vecFacing * 500; |
|
|
|
// Player may have turned to face a wall during the throw anim in which case |
|
// we don't want to throw the SLAM into the wall |
|
if (CanAttachSLAM()) |
|
{ |
|
vecThrow = vecFacing; |
|
vecSrc = pPlayer->WorldSpaceCenter() + vecFacing * 5.0; |
|
} |
|
|
|
CSatchelCharge *pSatchel = (CSatchelCharge*)Create( "npc_satchel", vecSrc, vec3_angle, GetOwner() ); |
|
|
|
if ( pSatchel ) |
|
{ |
|
pSatchel->SetThrower( GetOwner() ); |
|
pSatchel->ApplyAbsVelocityImpulse( vecThrow ); |
|
pSatchel->SetLocalAngularVelocity( QAngle( 0, 400, 0 ) ); |
|
pSatchel->m_bIsLive = true; |
|
pSatchel->m_pMyWeaponSLAM = this; |
|
} |
|
|
|
pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType ); |
|
pPlayer->SetAnimation( PLAYER_ATTACK1 ); |
|
|
|
#endif |
|
|
|
// Play throw sound |
|
EmitSound( "Weapon_SLAM.SatchelThrow" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::StartSatchelThrow( void ) |
|
{ |
|
// ----------------------------------------- |
|
// Play throw animation |
|
// ----------------------------------------- |
|
if (m_bDetonatorArmed) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_THROW_THROW); |
|
} |
|
else |
|
{ |
|
SendWeaponAnim(ACT_SLAM_THROW_THROW_ND); |
|
if (!m_bDetonatorArmed) |
|
{ |
|
m_bDetonatorArmed = true; |
|
m_bNeedDetonatorDraw = true; |
|
} |
|
} |
|
|
|
m_bNeedReload = true; |
|
m_bThrowSatchel = true; |
|
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SatchelAttach( void ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
m_bAttachSatchel = false; |
|
|
|
Vector vecSrc = pOwner->Weapon_ShootPosition( ); |
|
Vector vecAiming = pOwner->BodyDirection2D( ); |
|
|
|
trace_t tr; |
|
|
|
UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if (tr.fraction < 1.0) |
|
{ |
|
CBaseEntity *pEntity = tr.m_pEnt; |
|
if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR)) |
|
{ |
|
QAngle angles; |
|
VectorAngles(tr.plane.normal, angles); |
|
angles.y -= 90; |
|
angles.z -= 90; |
|
tr.endpos.z -= 6.0f; |
|
|
|
CSatchelCharge *pSatchel = (CSatchelCharge*)CBaseEntity::Create( "npc_satchel", tr.endpos + tr.plane.normal * 3, angles, NULL ); |
|
pSatchel->SetMoveType( MOVETYPE_FLY ); // no gravity |
|
pSatchel->m_bIsAttached = true; |
|
pSatchel->m_bIsLive = true; |
|
pSatchel->SetThrower( GetOwner() ); |
|
pSatchel->SetOwnerEntity( ((CBaseEntity*)GetOwner()) ); |
|
pSatchel->m_pMyWeaponSLAM = this; |
|
|
|
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType ); |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::StartSatchelAttach( void ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
Vector vecSrc = pOwner->Weapon_ShootPosition( ); |
|
Vector vecAiming = pOwner->BodyDirection2D( ); |
|
|
|
trace_t tr; |
|
|
|
UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if (tr.fraction < 1.0) |
|
{ |
|
CBaseEntity *pEntity = tr.m_pEnt; |
|
if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR)) |
|
{ |
|
// Only the player fires this way so we can cast |
|
CBasePlayer *pPlayer = ToBasePlayer( pOwner ); |
|
|
|
// player "shoot" animation |
|
pPlayer->SetAnimation( PLAYER_ATTACK1 ); |
|
|
|
// ----------------------------------------- |
|
// Play attach animation |
|
// ----------------------------------------- |
|
if (m_bDetonatorArmed) |
|
{ |
|
SendWeaponAnim(ACT_SLAM_STICKWALL_ATTACH); |
|
} |
|
else |
|
{ |
|
SendWeaponAnim(ACT_SLAM_STICKWALL_ND_ATTACH); |
|
if (!m_bDetonatorArmed) |
|
{ |
|
m_bDetonatorArmed = true; |
|
m_bNeedDetonatorDraw = true; |
|
} |
|
} |
|
|
|
m_bNeedReload = true; |
|
m_bAttachSatchel = true; |
|
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SetSlamState( int newState ) |
|
{ |
|
// Set set and set idle time so animation gets updated with state change |
|
m_tSlamState = newState; |
|
SetWeaponIdleTime( gpGlobals->curtime ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::SLAMThink( void ) |
|
{ |
|
if ( m_flWallSwitchTime > gpGlobals->curtime ) |
|
return; |
|
|
|
|
|
// If not in tripmine mode we need to check to see if we are close to |
|
// a wall. If we are we go into satchel_attach mode |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
|
|
if ( (pOwner && pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0)) |
|
{ |
|
if (CanAttachSLAM()) |
|
{ |
|
if (m_tSlamState == SLAM_SATCHEL_THROW) |
|
{ |
|
SetSlamState(SLAM_TRIPMINE_READY); |
|
int iAnim = m_bDetonatorArmed ? ACT_SLAM_THROW_TO_STICKWALL : ACT_SLAM_THROW_TO_TRIPMINE_ND; |
|
SendWeaponAnim( iAnim ); |
|
m_flWallSwitchTime = gpGlobals->curtime + SequenceDuration(); |
|
m_bNeedReload = false; |
|
} |
|
} |
|
else |
|
{ |
|
if (m_tSlamState == SLAM_TRIPMINE_READY) |
|
{ |
|
SetSlamState(SLAM_SATCHEL_THROW); |
|
int iAnim = m_bDetonatorArmed ? ACT_SLAM_STICKWALL_TO_THROW : ACT_SLAM_TRIPMINE_TO_THROW_ND; |
|
SendWeaponAnim( iAnim ); |
|
m_flWallSwitchTime = gpGlobals->curtime + SequenceDuration(); |
|
m_bNeedReload = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
bool CWeapon_SLAM::CanAttachSLAM( void ) |
|
{ |
|
CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); |
|
|
|
if (!pOwner) |
|
{ |
|
return false; |
|
} |
|
|
|
Vector vecSrc, vecAiming; |
|
|
|
// Take the eye position and direction |
|
vecSrc = pOwner->EyePosition(); |
|
|
|
QAngle angles = pOwner->GetLocalAngles(); |
|
|
|
AngleVectors( angles, &vecAiming ); |
|
|
|
trace_t tr; |
|
|
|
Vector vecEnd = vecSrc + (vecAiming * 42); |
|
UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if (tr.fraction < 1.0) |
|
{ |
|
// Don't attach to a living creature |
|
if (tr.m_pEnt) |
|
{ |
|
CBaseEntity *pEntity = tr.m_pEnt; |
|
CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); |
|
if (pBCC) |
|
{ |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
else |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Override so SLAM to so secondary attack when no secondary ammo |
|
// but satchel is in the world |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::ItemPostFrame( void ) |
|
{ |
|
CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
SLAMThink(); |
|
|
|
if ((pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) |
|
{ |
|
SecondaryAttack(); |
|
} |
|
else if (!m_bNeedReload && (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) |
|
{ |
|
PrimaryAttack(); |
|
} |
|
|
|
// ----------------------- |
|
// No buttons down |
|
// ----------------------- |
|
else |
|
{ |
|
WeaponIdle( ); |
|
return; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Switch to next best weapon |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::Weapon_Switch( void ) |
|
{ |
|
// Note that we may pick the SLAM again, when we switch |
|
// weapons, in which case we have to save and restore the |
|
// detonator armed state. |
|
// The SLAMs may be about to blow up, but haven't done so yet |
|
// and the deploy function will find the undetonated charges |
|
// and we are armed |
|
bool saveState = m_bDetonatorArmed; |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
pOwner->SwitchToNextBestWeapon( pOwner->GetActiveWeapon() ); |
|
if (pOwner->GetActiveWeapon() == this) |
|
{ |
|
m_bDetonatorArmed = saveState; |
|
} |
|
|
|
#ifndef CLIENT_DLL |
|
// If not armed and have no ammo |
|
if (!m_bDetonatorArmed && pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0) |
|
{ |
|
pOwner->ClearActiveWeapon(); |
|
} |
|
#endif |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CWeapon_SLAM::WeaponIdle( void ) |
|
{ |
|
// Ready to switch animations? |
|
if ( HasWeaponIdleTimeElapsed() ) |
|
{ |
|
// Don't allow throw to attach switch unless in idle |
|
if (m_bClearReload) |
|
{ |
|
m_bNeedReload = false; |
|
m_bClearReload = false; |
|
} |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return; |
|
} |
|
|
|
int iAnim = 0; |
|
|
|
if (m_bThrowSatchel) |
|
{ |
|
SatchelThrow(); |
|
if (m_bDetonatorArmed && !m_bNeedDetonatorDraw) |
|
{ |
|
iAnim = ACT_SLAM_THROW_THROW2; |
|
} |
|
else |
|
{ |
|
iAnim = ACT_SLAM_THROW_THROW_ND2; |
|
} |
|
} |
|
else if (m_bAttachSatchel) |
|
{ |
|
SatchelAttach(); |
|
if (m_bDetonatorArmed && !m_bNeedDetonatorDraw) |
|
{ |
|
iAnim = ACT_SLAM_STICKWALL_ATTACH2; |
|
} |
|
else |
|
{ |
|
iAnim = ACT_SLAM_STICKWALL_ND_ATTACH2; |
|
} |
|
} |
|
else if (m_bAttachTripmine) |
|
{ |
|
TripmineAttach(); |
|
iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_STICKWALL_ATTACH2 : ACT_SLAM_TRIPMINE_ATTACH2; |
|
} |
|
else if ( m_bNeedReload ) |
|
{ |
|
// If owner had ammo draw the correct SLAM type |
|
if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0) |
|
{ |
|
switch( m_tSlamState) |
|
{ |
|
case SLAM_TRIPMINE_READY: |
|
{ |
|
iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_STICKWALL_DRAW : ACT_SLAM_TRIPMINE_DRAW; |
|
} |
|
break; |
|
case SLAM_SATCHEL_ATTACH: |
|
{ |
|
if (m_bNeedDetonatorHolster) |
|
{ |
|
iAnim = ACT_SLAM_STICKWALL_DETONATOR_HOLSTER; |
|
m_bNeedDetonatorHolster = false; |
|
} |
|
else if (m_bDetonatorArmed) |
|
{ |
|
iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_STICKWALL_DRAW : ACT_SLAM_STICKWALL_DRAW; |
|
m_bNeedDetonatorDraw = false; |
|
} |
|
else |
|
{ |
|
iAnim = ACT_SLAM_STICKWALL_ND_DRAW; |
|
} |
|
} |
|
break; |
|
case SLAM_SATCHEL_THROW: |
|
{ |
|
if (m_bNeedDetonatorHolster) |
|
{ |
|
iAnim = ACT_SLAM_THROW_DETONATOR_HOLSTER; |
|
m_bNeedDetonatorHolster = false; |
|
} |
|
else if (m_bDetonatorArmed) |
|
{ |
|
iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_THROW_DRAW : ACT_SLAM_THROW_DRAW; |
|
m_bNeedDetonatorDraw = false; |
|
} |
|
else |
|
{ |
|
iAnim = ACT_SLAM_THROW_ND_DRAW; |
|
} |
|
} |
|
break; |
|
} |
|
m_bClearReload = true; |
|
} |
|
// If no ammo and armed, idle with only the detonator |
|
else if (m_bDetonatorArmed) |
|
{ |
|
iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_DRAW : ACT_SLAM_DETONATOR_IDLE; |
|
m_bNeedDetonatorDraw = false; |
|
} |
|
else |
|
{ |
|
#ifndef CLIENT_DLL |
|
pOwner->Weapon_Drop( this ); |
|
UTIL_Remove(this); |
|
#endif |
|
} |
|
} |
|
else if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0) |
|
{ |
|
#ifndef CLIENT_DLL |
|
pOwner->Weapon_Drop( this ); |
|
UTIL_Remove(this); |
|
#endif |
|
} |
|
|
|
// If I don't need to reload just do the appropriate idle |
|
else |
|
{ |
|
switch( m_tSlamState) |
|
{ |
|
case SLAM_TRIPMINE_READY: |
|
{ |
|
iAnim = m_bDetonatorArmed ? ACT_SLAM_STICKWALL_IDLE : ACT_SLAM_TRIPMINE_IDLE; |
|
m_flWallSwitchTime = 0; |
|
} |
|
break; |
|
case SLAM_SATCHEL_THROW: |
|
{ |
|
if (m_bNeedDetonatorHolster) |
|
{ |
|
iAnim = ACT_SLAM_THROW_DETONATOR_HOLSTER; |
|
m_bNeedDetonatorHolster = false; |
|
} |
|
else |
|
{ |
|
iAnim = m_bDetonatorArmed ? ACT_SLAM_THROW_IDLE : ACT_SLAM_THROW_ND_IDLE; |
|
m_flWallSwitchTime = 0; |
|
} |
|
} |
|
break; |
|
case SLAM_SATCHEL_ATTACH: |
|
{ |
|
if (m_bNeedDetonatorHolster) |
|
{ |
|
iAnim = ACT_SLAM_STICKWALL_DETONATOR_HOLSTER; |
|
m_bNeedDetonatorHolster = false; |
|
} |
|
else |
|
{ |
|
iAnim = m_bDetonatorArmed ? ACT_SLAM_STICKWALL_IDLE : ACT_SLAM_TRIPMINE_IDLE; |
|
m_flWallSwitchTime = 0; |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
SendWeaponAnim( iAnim ); |
|
} |
|
} |
|
|
|
bool CWeapon_SLAM::Deploy( void ) |
|
{ |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
{ |
|
return false; |
|
} |
|
|
|
m_bDetonatorArmed = AnyUndetonatedCharges(); |
|
|
|
|
|
SetModel( GetViewModel() ); |
|
|
|
m_tSlamState = (int)SLAM_SATCHEL_THROW; |
|
|
|
// ------------------------------ |
|
// Pick the right draw animation |
|
// ------------------------------ |
|
int iActivity; |
|
|
|
// If detonator is already armed |
|
m_bNeedReload = false; |
|
if (m_bDetonatorArmed) |
|
{ |
|
if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0) |
|
{ |
|
iActivity = ACT_SLAM_DETONATOR_DRAW; |
|
m_bNeedReload = true; |
|
} |
|
else if (CanAttachSLAM()) |
|
{ |
|
iActivity = ACT_SLAM_DETONATOR_STICKWALL_DRAW; |
|
SetSlamState(SLAM_TRIPMINE_READY); |
|
} |
|
else |
|
{ |
|
iActivity = ACT_SLAM_DETONATOR_THROW_DRAW; |
|
SetSlamState(SLAM_SATCHEL_THROW); |
|
} |
|
} |
|
else |
|
{ |
|
if (CanAttachSLAM()) |
|
{ |
|
iActivity = ACT_SLAM_TRIPMINE_DRAW; |
|
SetSlamState(SLAM_TRIPMINE_READY); |
|
} |
|
else |
|
{ |
|
iActivity = ACT_SLAM_THROW_ND_DRAW; |
|
SetSlamState(SLAM_SATCHEL_THROW); |
|
} |
|
} |
|
|
|
return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), iActivity, (char*)GetAnimPrefix() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
CWeapon_SLAM::CWeapon_SLAM(void) |
|
{ |
|
m_tSlamState = (int)SLAM_SATCHEL_THROW; |
|
m_bDetonatorArmed = false; |
|
m_bNeedReload = true; |
|
m_bClearReload = false; |
|
m_bThrowSatchel = false; |
|
m_bAttachSatchel = false; |
|
m_bAttachTripmine = false; |
|
m_bNeedDetonatorDraw = false; |
|
m_bNeedDetonatorHolster = false; |
|
}
|
|
|