Files
HL2Overcharged/game/server/overcharged/weapon_slam.cpp
2025-05-21 21:20:08 +03:00

1023 lines
24 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "gamerules.h"
#include "npcevent.h"
#include "in_buttons.h"
#include "engine/IEngineSound.h"
#include "hl2_player.h"
#include "grenade_tripmine.h"
#include "grenade_satchel.h"
#include "entitylist.h"
#include "eventqueue.h"
#include "weapon_slam.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SLAM_PRIMARY_VOLUME 450
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()
IMPLEMENT_SERVERCLASS_ST(CWeapon_SLAM, DT_Weapon_SLAM)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS(weapon_slam, CWeapon_SLAM);
PRECACHE_WEAPON_REGISTER(weapon_slam);
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);
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();
UTIL_PrecacheOther("npc_tripmine");
UTIL_PrecacheOther("npc_satchel");
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_iPrimaryAmmoType) <= 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();
}
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
PrimaryAttackPostUpdate();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeapon_SLAM::SatchelDetonate()
{
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());
}
}
// 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)
{
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;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeapon_SLAM::StartSatchelDetonate()
{
if (GetActivity() != ACT_SLAM_DETONATOR_IDLE && GetActivity() != ACT_SLAM_THROW_IDLE)
return;
// -----------------------------------------
// Play detonate animation
// -----------------------------------------
if (m_bNeedReload)
{
SendWeaponAnim(ACT_SLAM_DETONATOR_DETONATE);
}
else if (m_tSlamState == SLAM_SATCHEL_ATTACH)
{
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)
{
CBasePlayer *pOwner = ToBasePlayer(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))
{
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();
RemoveAmmo(GetPrimaryAmmoType(), 1); //pOwner->RemoveAmmo(1, m_iPrimaryAmmoType);
}
}
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
PrimaryAttackPostUpdate();
}
//-----------------------------------------------------------------------------
// 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)
{
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;
}
RemoveAmmo(GetPrimaryAmmoType(), 1); //pPlayer->RemoveAmmo(1, m_iPrimaryAmmoType);
pPlayer->SetAnimation(PLAYER_ATTACK1);
// 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)
{
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;
RemoveAmmo(GetPrimaryAmmoType(), 1); //pOwner->RemoveAmmo(1, m_iPrimaryAmmoType);
}
}
}
//-----------------------------------------------------------------------------
// 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_iPrimaryAmmoType) > 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)
{
CBasePlayer *pOwner = ToBasePlayer(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;
}
//CheckAdmireAnimations(pOwner);
SLAMThink();
#ifdef MAPBASE
if (pOwner->HasSpawnFlags(SF_PLAYER_SUPPRESS_FIRING))
{
WeaponIdle();
return;
}
#endif
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();
PrimaryAttackPostUpdate();
}
// -----------------------
// 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();
if (!pOwner)
return;
pOwner->SwitchToNextBestWeapon(pOwner->GetActiveWeapon());
if (pOwner->GetActiveWeapon() == this)
{
m_bDetonatorArmed = saveState;
}
// If not armed and have no ammo
if (!m_bDetonatorArmed && pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
pOwner->ClearActiveWeapon();
}
}
//-----------------------------------------------------------------------------
// 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_iPrimaryAmmoType) > 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
{
pOwner->Weapon_Drop(this);
UTIL_Remove(this);
}
}
else if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
pOwner->Weapon_Drop(this);
UTIL_Remove(this);
}
// 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_iPrimaryAmmoType) <= 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;
}