mirror of
https://github.com/ENSL/NS.git
synced 2024-11-30 00:10:57 +00:00
1405 lines
36 KiB
C++
1405 lines
36 KiB
C++
//======== (C) Copyright 2001 Charles G. Cleveland All rights reserved. =========
|
|
//
|
|
// The copyright to the contents herein is the property of Charles G. Cleveland.
|
|
// The contents may be used and/or copied only with the written permission of
|
|
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
|
|
// the agreement/contract under which the contents have been supplied.
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $Workfile: AvHBasePlayerWeapon.cpp$
|
|
// $Date: 2002/11/22 21:28:15 $
|
|
//
|
|
//-------------------------------------------------------------------------------
|
|
// $Log: AvHBasePlayerWeapon.cpp,v $
|
|
// Revision 1.38 2002/11/22 21:28:15 Flayra
|
|
// - mp_consistency changes
|
|
//
|
|
// Revision 1.37 2002/11/03 04:47:23 Flayra
|
|
// - Moved weapon expiring into .dll out of .cfg
|
|
//
|
|
// Revision 1.36 2002/10/24 21:22:10 Flayra
|
|
// - Fixes muzzle-flash showing when firing an empty weapon
|
|
//
|
|
// Revision 1.35 2002/10/17 17:34:14 Flayra
|
|
// - Part 2 of persistent weapons fix (found with Grendel)
|
|
//
|
|
// Revision 1.34 2002/10/16 20:51:17 Flayra
|
|
// - Fixed problem where acid projectile hit player
|
|
//
|
|
// Revision 1.33 2002/10/03 18:39:24 Flayra
|
|
// - Added heavy view models
|
|
//
|
|
// Revision 1.32 2002/09/23 22:10:46 Flayra
|
|
// - Weapons now stick around the way they should (forever when dropped by commander, weapon stay time when dropped by player)
|
|
//
|
|
// Revision 1.31 2002/08/16 02:33:12 Flayra
|
|
// - Added damage types
|
|
//
|
|
// Revision 1.30 2002/07/24 19:11:45 Flayra
|
|
// - Linux issues
|
|
//
|
|
// Revision 1.29 2002/07/24 18:45:40 Flayra
|
|
// - Linux and scripting changes
|
|
//
|
|
// Revision 1.28 2002/07/08 16:47:31 Flayra
|
|
// - Reworked bullet firing to add random spread (bug #236), temporarily hacked shotty player animation, removed old adrenaline, don't allow using weapons when invulnerable
|
|
//
|
|
// Revision 1.27 2002/07/01 21:17:13 Flayra
|
|
// - Removed outdated adrenaline concept, made ROF generic for primal scream
|
|
//
|
|
// Revision 1.26 2002/06/25 17:41:13 Flayra
|
|
// - Reworking for correct player animations and new enable/disable state
|
|
//
|
|
// Revision 1.25 2002/06/10 19:50:37 Flayra
|
|
// - First-pass at level 1 animated view model (different anims when running and walking)
|
|
//
|
|
// Revision 1.24 2002/06/03 16:29:53 Flayra
|
|
// - Added resupply (from arsenal), better animation support (for both view model and player model)
|
|
//
|
|
// Revision 1.23 2002/05/28 17:37:33 Flayra
|
|
// - Max entities fix, added animation empty fire
|
|
//
|
|
// Revision 1.22 2002/05/23 02:34:00 Flayra
|
|
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
|
|
//
|
|
//===============================================================================
|
|
#ifdef AVH_CLIENT
|
|
#include "cl_dll/wrect.h"
|
|
#include "cl_dll/cl_dll.h"
|
|
#include "cl_dll/hud.h"
|
|
#include "cl_dll/cl_util.h"
|
|
#include "cl_dll/ammo.h"
|
|
#include "cl_dll/ammohistory.h"
|
|
extern int g_runfuncs;
|
|
#endif
|
|
|
|
#include "../util/nowarnings.h"
|
|
#include "AvHBasePlayerWeapon.h"
|
|
#include "AvHAlienWeaponConstants.h"
|
|
#include "AvHPlayer.h"
|
|
#include "../common/usercmd.h"
|
|
#include "../pm_shared/pm_defs.h"
|
|
#include "AvHMarineEquipmentConstants.h"
|
|
#include "AvHMarineWeapons.h"
|
|
|
|
#ifdef AVH_SERVER
|
|
#include "AvHServerUtil.h"
|
|
#include "AvHGamerules.h"
|
|
|
|
extern int gWelderConstEventID;
|
|
#endif
|
|
|
|
#ifdef AVH_CLIENT
|
|
#include "cl_dll/com_weapons.h"
|
|
#endif
|
|
|
|
#include "AvHPlayerUpgrade.h"
|
|
#include "AvHSharedUtil.h"
|
|
#include "../types.h"
|
|
#include "../common/vector_util.h"
|
|
#include "../util/MathUtil.h"
|
|
|
|
// extern "C" this guy because delcared in pm_shared.c, not pm_shared.cpp
|
|
extern playermove_t* pmove;
|
|
extern cvar_t weaponstay;
|
|
|
|
Vector UTIL_GetRandomSpreadDir(unsigned int inSeed, int inShotNumber, const Vector& inBaseDirection, const Vector& inRight, const Vector& inUp, const Vector& inSpread)
|
|
{
|
|
// Use player's random seed.
|
|
// get circular gaussian spread
|
|
float x, y;
|
|
|
|
// Check if seed is 0 to fix bot weapon spread.
|
|
if (inSeed == 0)
|
|
{
|
|
x = g_engfuncs.pfnRandomFloat(-0.5, 0.5);
|
|
x = g_engfuncs.pfnRandomFloat(-0.5, 0.5) + x;
|
|
y = g_engfuncs.pfnRandomFloat(-0.5, 0.5);
|
|
y = g_engfuncs.pfnRandomFloat(-0.5, 0.5) + y;
|
|
}
|
|
else
|
|
{
|
|
x = UTIL_SharedRandomFloat(inSeed + inShotNumber, -0.5, 0.5) + UTIL_SharedRandomFloat(inSeed + (1 + inShotNumber), -0.5, 0.5);
|
|
y = UTIL_SharedRandomFloat(inSeed + (2 + inShotNumber), -0.5, 0.5) + UTIL_SharedRandomFloat(inSeed + (3 + inShotNumber), -0.5, 0.5);
|
|
}
|
|
|
|
float z = x * x + y * y;
|
|
|
|
Vector theRandomDir = inBaseDirection + x * inSpread.x * inRight + y * inSpread.y * inUp;
|
|
|
|
return theRandomDir;
|
|
}
|
|
|
|
// test
|
|
Vector UTIL_GetRandomSpreadDirFrom(unsigned int inSeed, int inShotNumber, const Vector& inBaseDirection, const Vector& inRight, const Vector& inUp, const Vector& inSpread, const Vector& inFromSpread)
|
|
{
|
|
// Use player's random seed.
|
|
// get circular gaussian spread
|
|
float x, y;
|
|
|
|
// Check if seed is 0 to fix bot weapon spread.
|
|
if (inSeed == 0)
|
|
{
|
|
x = g_engfuncs.pfnRandomFloat(-0.5, 0.5);
|
|
x = g_engfuncs.pfnRandomFloat(-0.5, 0.5) + x;
|
|
y = g_engfuncs.pfnRandomFloat(-0.5, 0.5);
|
|
y = g_engfuncs.pfnRandomFloat(-0.5, 0.5) + y;
|
|
}
|
|
else
|
|
{
|
|
x = UTIL_SharedRandomFloat(inSeed + inShotNumber, -0.5, 0.5) + UTIL_SharedRandomFloat(inSeed + (1 + inShotNumber), -0.5, 0.5);
|
|
y = UTIL_SharedRandomFloat(inSeed + (2 + inShotNumber), -0.5, 0.5) + UTIL_SharedRandomFloat(inSeed + (3 + inShotNumber), -0.5, 0.5);
|
|
}
|
|
|
|
float z = x * x + y * y;
|
|
float xdir = x / fabs(x);
|
|
float ydir = y / fabs(y);
|
|
|
|
Vector theRandomDir = inBaseDirection + inFromSpread.x * inRight * xdir + x * inSpread.x * inRight + inFromSpread.y * inUp * ydir + y * inSpread.y * inUp;
|
|
|
|
return theRandomDir;
|
|
}
|
|
|
|
AvHBasePlayerWeapon::AvHBasePlayerWeapon()
|
|
{
|
|
// reasonable defaults for everything else
|
|
this->mEvent = 0;
|
|
this->mWeaponAnimationEvent = 0;
|
|
this->mStartEvent = 0;
|
|
this->mEndEvent = 0;
|
|
this->mRange = 8012;
|
|
this->mDamage = 10;
|
|
this->mAttackButtonDownLastFrame = false;
|
|
this->mTimeOfLastResupply = -1;
|
|
this->mTimeOfLastPrime = -1;
|
|
this->mWeaponPrimeStarted = false;
|
|
|
|
#ifdef AVH_SERVER
|
|
this->mInOverwatch = false;
|
|
this->mIsPersistent = false;
|
|
this->mLifetime = -1;
|
|
#endif
|
|
|
|
this->mFireOnAttackUp = false;
|
|
}
|
|
void AvHBasePlayerWeapon::PrintWeaponToClient(CBaseEntity *theAvHPlayer) {
|
|
char msg[1024];
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
sprintf(msg, "%s iuser3=%d\tenabled = %d\n", theItemInfo.pszName, this->pev->iuser3, this->m_iEnabled);
|
|
ClientPrint(theAvHPlayer->pev, HUD_PRINTNOTIFY, msg);
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer )
|
|
{
|
|
// Can we predict weapon pick-ups? I bet we can.
|
|
int theAddedToPlayer = 0;
|
|
|
|
#ifdef AVH_SERVER
|
|
AvHPlayer* inPlayer = dynamic_cast<AvHPlayer*>(pPlayer);
|
|
ASSERT(inPlayer != NULL);
|
|
|
|
if(this->GetAllowedForUser3(inPlayer->GetUser3()))
|
|
{
|
|
// Make sure player doesn't have this weapon already
|
|
if(!pPlayer->HasItem(this))
|
|
{
|
|
// If weapon was placed by mapper
|
|
if(this->GetIsPersistent())
|
|
{
|
|
// Create a new weapon and give it to the player
|
|
pPlayer->GiveNamedItem(STRING(this->pev->classname));
|
|
|
|
this->DestroyItem();
|
|
}
|
|
else
|
|
{
|
|
theAddedToPlayer = CBasePlayerWeapon::AddToPlayer(pPlayer);
|
|
if(theAddedToPlayer)
|
|
{
|
|
// Make sure it's not set for expiration
|
|
SetThink(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return theAddedToPlayer;
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::Deploy()
|
|
{
|
|
// : 0000938
|
|
// removed deploy sounds for all weapons, leaving the sounds to the models
|
|
// char* theDeploySound = this->GetDeploySound();
|
|
// if(theDeploySound)
|
|
// {
|
|
// EMIT_SOUND(ENT(this->pev), CHAN_WEAPON, this->GetDeploySound(), this->GetDeploySoundVolume(), ATTN_NORM);
|
|
//}
|
|
// :
|
|
|
|
char* theAnimExt = this->GetAnimationExtension();
|
|
|
|
BOOL theSuccess = DefaultDeploy(this->GetActiveViewModel(), this->GetPlayerModel(), this->GetDeployAnimation(), theAnimExt);
|
|
|
|
// Set a player animatiom here?
|
|
//this->m_pPlayer->SetAnimation(PLAYER_ANIM(iAnim));
|
|
|
|
// Set deploy time
|
|
this->m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + this->GetDeployTime();
|
|
|
|
this->mTimeOfLastPrime = -1;
|
|
this->mWeaponPrimeStarted = false;
|
|
|
|
return theSuccess;
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body)
|
|
{
|
|
if (!CanDeploy( ))
|
|
return FALSE;
|
|
|
|
m_pPlayer->TabulateAmmo();
|
|
|
|
// This was causing a crash from hl_weapons.cpp only when connected to a dedicated server and switching weapons
|
|
//#ifdef AVH_SERVER
|
|
//m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
|
|
//#endif
|
|
|
|
#ifdef AVH_SERVER
|
|
m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
|
|
m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
|
|
#else
|
|
gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel );
|
|
gEngfuncs.CL_LoadModel( szWeaponModel, &m_pPlayer->pev->weaponmodel );
|
|
#endif
|
|
|
|
strcpy( m_pPlayer->m_szAnimExtention, szAnimExt );
|
|
//SendWeaponAnim( iAnim, skiplocal, body );
|
|
this->SendWeaponAnim(iAnim);
|
|
|
|
// Set the player animation as well
|
|
//this->m_pPlayer->SetAnimation(PLAYER_ANIM(iAnim));
|
|
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + this->GetDeployTime();
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + this->GetDeployTime() + kDeployIdleInterval;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, int body)
|
|
{
|
|
// : 0000996
|
|
if (m_fInReload == TRUE)
|
|
return TRUE;
|
|
// :
|
|
|
|
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
|
|
return FALSE;
|
|
|
|
// Don't reload while we're resupplying
|
|
// if(this->mTimeOfLastResupply > 0)
|
|
// {
|
|
// return FALSE;
|
|
// }
|
|
|
|
int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
if (j == 0)
|
|
return FALSE;
|
|
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay;
|
|
|
|
//!!UNDONE -- reload sound goes here !!!
|
|
// 2021 Ammo networking. Uncommented to not send animations to the client that initiated the reload. This is HL SDK code.
|
|
SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 );
|
|
//// 2021 Ammo networking. Commented below - client was getting sent extra reload animations causing visual stutter.
|
|
//this->SendWeaponAnim(iAnim);
|
|
|
|
//// 2021 Ammo networking. Commented below - client was getting sent extra reload animations causing visual stutter.
|
|
// Send reload to all players. Reloads are initiated server-side, so send down to local client as well
|
|
//this->m_pPlayer->pev->weaponanim = iAnim;
|
|
//this->PlaybackEvent(this->mWeaponAnimationEvent, iAnim, FEV_RELIABLE);
|
|
|
|
//ALERT(at_console, "defaultreload nextattack:%g\n", m_pPlayer->m_flNextAttack);
|
|
// Player model reload animation
|
|
this->m_pPlayer->SetAnimation(PLAYER_RELOAD);
|
|
|
|
m_fInReload = TRUE;
|
|
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
char* AvHBasePlayerWeapon::GetActiveViewModel() const
|
|
{
|
|
return this->GetViewModel();
|
|
}
|
|
|
|
//BOOL AvHBasePlayerWeapon::Deploy(char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, float inNextAttackTime, int skiplocal)
|
|
//{
|
|
// BOOL theSuccess = FALSE;
|
|
//
|
|
// if(CanDeploy())
|
|
// {
|
|
// this->m_pPlayer->TabulateAmmo();
|
|
// this->m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
|
|
// this->m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
|
|
// strcpy( m_pPlayer->m_szAnimExtention, szAnimExt );
|
|
// SendWeaponAnim( iAnim, skiplocal );
|
|
//
|
|
// this->m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + inNextAttackTime;
|
|
// this->m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0;
|
|
//
|
|
// theSuccess = TRUE;
|
|
// }
|
|
//
|
|
// return theSuccess;
|
|
//}
|
|
|
|
char* AvHBasePlayerWeapon::GetAnimationExtension() const
|
|
{
|
|
char* theAnimExt = NULL;
|
|
|
|
AvHWeaponID theWeaponID = (AvHWeaponID)this->m_iId;
|
|
switch(theWeaponID)
|
|
{
|
|
case AVH_WEAPON_BITE:
|
|
case AVH_WEAPON_SPIT:
|
|
case AVH_WEAPON_SPIKE:
|
|
case AVH_WEAPON_BITE2:
|
|
case AVH_WEAPON_SWIPE:
|
|
case AVH_WEAPON_CLAWS:
|
|
theAnimExt = "ability1";
|
|
break;
|
|
|
|
case AVH_WEAPON_PARASITE:
|
|
case AVH_WEAPON_HEALINGSPRAY:
|
|
case AVH_WEAPON_SPORES:
|
|
case AVH_WEAPON_BLINK:
|
|
case AVH_WEAPON_STOMP:
|
|
theAnimExt = "ability2";
|
|
break;
|
|
|
|
case AVH_ABILITY_LEAP:
|
|
case AVH_WEAPON_BILEBOMB:
|
|
case AVH_WEAPON_UMBRA:
|
|
case AVH_WEAPON_METABOLIZE:
|
|
case AVH_WEAPON_DEVOUR:
|
|
theAnimExt = "ability3";
|
|
break;
|
|
|
|
case AVH_WEAPON_DIVINEWIND:
|
|
case AVH_WEAPON_WEBSPINNER:
|
|
case AVH_WEAPON_PRIMALSCREAM:
|
|
case AVH_WEAPON_ACIDROCKET:
|
|
case AVH_ABILITY_CHARGE:
|
|
theAnimExt = "ability4";
|
|
break;
|
|
|
|
case AVH_WEAPON_KNIFE:
|
|
theAnimExt = "knife";
|
|
break;
|
|
case AVH_WEAPON_PISTOL:
|
|
theAnimExt = "pistol";
|
|
break;
|
|
case AVH_WEAPON_MG:
|
|
theAnimExt = "lmg";
|
|
break;
|
|
case AVH_WEAPON_SONIC:
|
|
theAnimExt = "shotgun";
|
|
break;
|
|
case AVH_WEAPON_HMG:
|
|
theAnimExt = "hmg";
|
|
break;
|
|
case AVH_WEAPON_WELDER:
|
|
theAnimExt = "welder";
|
|
break;
|
|
case AVH_WEAPON_MINE:
|
|
theAnimExt = "tripmine";
|
|
break;
|
|
case AVH_WEAPON_GRENADE_GUN:
|
|
theAnimExt = "grenadegun";
|
|
break;
|
|
case AVH_WEAPON_GRENADE:
|
|
theAnimExt = "handgrenade";
|
|
break;
|
|
default:
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
return theAnimExt;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetClipSize() const
|
|
{
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
int theClipSize = theItemInfo.iMaxClip;
|
|
|
|
return theClipSize;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetPrimaryAmmoAmount() const
|
|
{
|
|
int theAmmo = 0;
|
|
|
|
if(this->m_pPlayer && (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0))
|
|
{
|
|
theAmmo = this->m_pPlayer->m_rgAmmo[this->m_iPrimaryAmmoType];
|
|
}
|
|
|
|
return theAmmo;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetDamageType() const
|
|
{
|
|
return NS_DMG_NORMAL;
|
|
}
|
|
|
|
char* AvHBasePlayerWeapon::GetDeploySound() const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetDeploySoundVolume() const
|
|
{
|
|
return 1.0f;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetEmptyShootAnimation() const
|
|
{
|
|
return kShootEmptyAnimation;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::GetEventOrigin(Vector& outOrigin) const
|
|
{
|
|
VectorCopy(this->m_pPlayer->pev->origin, outOrigin);
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::GetEventAngles(Vector& outAngles) const
|
|
{
|
|
outAngles = this->pev->v_angle + this->pev->punchangle;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetFiresUnderwater() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsFiring() const
|
|
{
|
|
return this->mAttackButtonDownLastFrame;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetHasMuzzleFlash() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsCapableOfFiring() const
|
|
{
|
|
//return !this->UsesAmmo() || (this->m_iClip > 0);
|
|
return !this->UsesAmmo() || (this->m_iClip > 0 || this->m_iDefaultAmmo > 0);
|
|
}
|
|
|
|
|
|
int AvHBasePlayerWeapon::GetDeployAnimation() const
|
|
{
|
|
return kDeployAnimation;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetIdleAnimation() const
|
|
{
|
|
int iAnim;
|
|
int theRandomNum = UTIL_SharedRandomLong(this->m_pPlayer->random_seed, 0, 1);
|
|
|
|
switch(theRandomNum)
|
|
{
|
|
case 0:
|
|
iAnim = kIdleAnimationOne;
|
|
break;
|
|
|
|
default:
|
|
case 1:
|
|
iAnim = kIdleAnimationTwo;
|
|
break;
|
|
}
|
|
|
|
return iAnim;
|
|
}
|
|
|
|
Vector AvHBasePlayerWeapon::GetProjectileSpread() const
|
|
{
|
|
return VECTOR_CONE_0DEGREES;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::ComputeAttackInterval() const
|
|
{
|
|
return this->GetRateOfFire();
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetRateOfFire() const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetShootAnimation() const
|
|
{
|
|
return kShootAnimation;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetShotsInClip() const
|
|
{
|
|
int theShotsInClip = -1;
|
|
|
|
if(this->UsesAmmo())
|
|
{
|
|
theShotsInClip = this->m_iClip;
|
|
}
|
|
|
|
return theShotsInClip;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsDroppable() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsPlayerMoving() const
|
|
{
|
|
bool thePlayerIsMoving = false;
|
|
|
|
// float kMovingThresholdVelocity = 100;
|
|
// float theCurrentVelocity = 0;
|
|
//
|
|
// #ifdef AVH_SERVER
|
|
// theCurrentVelocity = this->m_pPlayer->pev->velocity.Length();
|
|
// #endif
|
|
//
|
|
// #ifdef AVH_CLIENT
|
|
// cl_entity_t* theLocalPlayer = gEngfuncs.GetLocalPlayer();
|
|
// if(theLocalPlayer)
|
|
// {
|
|
// theCurrentVelocity = theLocalPlayer->curstate.velocity.Length();
|
|
// }
|
|
// #endif
|
|
//
|
|
// if(theCurrentVelocity > kMovingThresholdVelocity)
|
|
// {
|
|
// thePlayerIsMoving = true;
|
|
// }
|
|
|
|
return thePlayerIsMoving;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetMaxClipsCouldReceive()
|
|
{
|
|
int theMaxClips = 0;
|
|
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
int theClipSize = theItemInfo.iMaxClip;
|
|
|
|
if(theClipSize > 0 && this->UsesAmmo())
|
|
{
|
|
theMaxClips = ((theItemInfo.iMaxAmmo1 - this->m_iClip)/theClipSize) + 1;
|
|
}
|
|
|
|
return theMaxClips;
|
|
}
|
|
|
|
AvHWeaponID AvHBasePlayerWeapon::GetPreviousWeaponID() const
|
|
{
|
|
AvHWeaponID theID = AVH_WEAPON_NONE;
|
|
|
|
// Look at most recently used weapon and see if we can transition from it
|
|
AvHBasePlayerWeapon* theWeapon = dynamic_cast<AvHBasePlayerWeapon*>(this->m_pPlayer->m_pLastItem);
|
|
if(theWeapon)
|
|
{
|
|
theID = (AvHWeaponID)(theWeapon->m_iId);
|
|
}
|
|
|
|
return theID;
|
|
}
|
|
|
|
|
|
float AvHBasePlayerWeapon::GetRange() const
|
|
{
|
|
return this->mRange;
|
|
}
|
|
|
|
vec3_t AvHBasePlayerWeapon::GetWorldBarrelPoint() const
|
|
{
|
|
ASSERT(this->m_pPlayer);
|
|
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector theWorldBarrelPoint = this->m_pPlayer->GetGunPosition() + vecAiming*this->GetBarrelLength();
|
|
|
|
return theWorldBarrelPoint;
|
|
|
|
}
|
|
|
|
char* AvHBasePlayerWeapon::GetPlayerModel() const
|
|
{
|
|
return kNullModel;
|
|
}
|
|
|
|
char* AvHBasePlayerWeapon::GetPrimeSound() const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetPrimeSoundVolume() const
|
|
{
|
|
return 1.0f;
|
|
}
|
|
|
|
char* AvHBasePlayerWeapon::GetViewModel() const
|
|
{
|
|
return kNullModel;
|
|
}
|
|
|
|
char* AvHBasePlayerWeapon::GetWorldModel() const
|
|
{
|
|
return kNullModel;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::Holster( int skiplocal)
|
|
{
|
|
CBasePlayerWeapon::Holster(skiplocal);
|
|
|
|
#ifdef AVH_SERVER
|
|
this->mInOverwatch = false;
|
|
#endif
|
|
|
|
this->m_bAttackQueued = false;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetTimePassedThisTick() const
|
|
{
|
|
float theClientTimePassedThisTick = (pmove->cmd.msec/1000.0f);
|
|
return theClientTimePassedThisTick;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::ItemPostFrame( void )
|
|
{
|
|
CBasePlayerWeapon::ItemPostFrame();
|
|
|
|
float theClientTimePassedThisTick = this->GetTimePassedThisTick();
|
|
|
|
this->m_flNextPrimaryAttack -= theClientTimePassedThisTick;
|
|
this->m_flTimeWeaponIdle -= theClientTimePassedThisTick;
|
|
this->mTimeOfLastResupply -= theClientTimePassedThisTick;
|
|
this->mTimeOfLastPrime -= theClientTimePassedThisTick;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::Precache(void)
|
|
{
|
|
CBasePlayerWeapon::Precache();
|
|
|
|
char* theDeploySound = this->GetDeploySound();
|
|
if(theDeploySound)
|
|
{
|
|
PRECACHE_UNMODIFIED_SOUND(theDeploySound);
|
|
}
|
|
char* thePrimeSound = this->GetPrimeSound();
|
|
if(thePrimeSound)
|
|
{
|
|
PRECACHE_UNMODIFIED_SOUND(thePrimeSound);
|
|
}
|
|
char* thePlayerModel = this->GetPlayerModel();
|
|
if(thePlayerModel)
|
|
{
|
|
PRECACHE_UNMODIFIED_MODEL(thePlayerModel);
|
|
}
|
|
char* theViewModel = this->GetViewModel();
|
|
if(theViewModel)
|
|
{
|
|
PRECACHE_UNMODIFIED_MODEL(theViewModel);
|
|
}
|
|
char* theWorldModel = this->GetWorldModel();
|
|
if(theWorldModel)
|
|
{
|
|
PRECACHE_UNMODIFIED_MODEL(theWorldModel);
|
|
}
|
|
|
|
this->mWeaponAnimationEvent = PRECACHE_EVENT(1, kWeaponAnimationEvent);
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::ProcessValidAttack(void)
|
|
{
|
|
bool theAttackIsValid = false;
|
|
|
|
//#ifdef AVH_CLIENT
|
|
// char sz[ 128 ];
|
|
// sprintf(sz, "during check valid, clip is %d\n", this->m_iClip);
|
|
// gEngfuncs.pfnCenterPrint( sz );
|
|
//
|
|
// //gEngfuncs.Con_Printf("during idle, clip is %d\n", sz);
|
|
//#endif
|
|
|
|
//#ifdef AVH_CLIENT
|
|
// if(gHUD.GetInTopDownMode())
|
|
// {
|
|
// return false;
|
|
// }
|
|
//#endif
|
|
//
|
|
//#ifdef AVH_SERVER
|
|
// AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(this->m_pPlayer);
|
|
// if(thePlayer->GetIsInTopDownMode())
|
|
// {
|
|
// return false;
|
|
// }
|
|
//#endif
|
|
|
|
// Only shoot if deployed and enabled (iuser3 is 0 when disabled, 1 when enabled <from m_fireState>)
|
|
|
|
// : 497 call GetEnabledState instead of testing directly
|
|
int enabledState=this->GetEnabledState();
|
|
|
|
if(this->m_pPlayer->pev->viewmodel && ( enabledState == 1))
|
|
{
|
|
// don't fire underwater
|
|
if((this->m_pPlayer->pev->waterlevel == 3) && !this->GetFiresUnderwater())
|
|
{
|
|
this->PlayEmptySound();
|
|
|
|
//this->m_flNextPrimaryAttack = gpGlobals->time + this->mROF;
|
|
this->m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + this->ComputeAttackInterval();
|
|
}
|
|
else if(this->UsesAmmo())
|
|
{
|
|
ASSERT(this->m_iPrimaryAmmoType >= 0);
|
|
if(this->m_iClip > 0)
|
|
{
|
|
if((this->m_flNextPrimaryAttack <= 0) && !this->m_fInSpecialReload)
|
|
{
|
|
if(!this->GetMustPressTriggerForEachShot() || !this->mAttackButtonDownLastFrame || this->mFireOnAttackUp)
|
|
{
|
|
//ALERT(at_console, "trueattack1 primammo:%d primatype:%d secammo:%d secatype:%d\n", this->m_pPlayer->m_rgAmmo[this->m_iPrimaryAmmoType], this->m_iPrimaryAmmoType, this->m_pPlayer->m_rgAmmo[this->m_iSecondaryAmmoType], this->m_iSecondaryAmmoType);
|
|
theAttackIsValid = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Definitely not firing this pull of the trigger
|
|
theAttackIsValid = false;
|
|
|
|
BOOL theHasAmmo = 0;
|
|
|
|
//// 2021 Ammo networking - Client can't check pszAmmo, removing check since every gun in NS uses pszAmmo1 and it was causing theHasAmmo to fail on client when the player had ammo.
|
|
//if ( pszAmmo1() )
|
|
//{
|
|
theHasAmmo |= (this->m_pPlayer->m_rgAmmo[this->m_iPrimaryAmmoType] != 0);
|
|
//}
|
|
//if ( pszAmmo2() )
|
|
//{
|
|
//theHasAmmo |= (this->m_pPlayer->m_rgAmmo[this->m_iSecondaryAmmoType] != 0);
|
|
//}
|
|
if (this->m_iClip > 0)
|
|
{
|
|
theHasAmmo |= 1;
|
|
}
|
|
|
|
if(theHasAmmo)
|
|
{
|
|
// Trigger reload
|
|
this->Reload();
|
|
//ALERT(at_console, "hasammo m_iprimary: %i\n", this->m_pPlayer->m_rgAmmo[this->m_iPrimaryAmmoType]);
|
|
//ALERT(at_console, "hasammo m_iptype: %i\n", m_iPrimaryAmmoType);
|
|
}
|
|
else
|
|
{
|
|
this->PlayEmptySound();
|
|
|
|
this->SendWeaponAnim(this->GetEmptyShootAnimation());
|
|
//ALERT(at_console, "noammo m_iprimary: %i\n", this->m_pPlayer->m_rgAmmo[this->m_iPrimaryAmmoType]);
|
|
//ALERT(at_console, "noammo m_iptype: %i\n", m_iPrimaryAmmoType);
|
|
|
|
//this->m_pPlayer->SetAnimation(PLAYER_ATTACK1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
theAttackIsValid = true;
|
|
}
|
|
}
|
|
|
|
return theAttackIsValid;
|
|
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsGunPositionValid() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::DeductCostForShot(void)
|
|
{
|
|
this->m_iClip--;
|
|
|
|
// On a successful attack, decloak the player if needed
|
|
#ifdef AVH_SERVER
|
|
AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(this->m_pPlayer);
|
|
if(thePlayer)
|
|
{
|
|
thePlayer->TriggerUncloak();
|
|
}
|
|
|
|
int theResourceCost = this->GetResourceCost();
|
|
if(theResourceCost > 0)
|
|
{
|
|
float theNewResources = (thePlayer->GetResources(false) - theResourceCost);
|
|
theNewResources = max(theNewResources, 0.0f);
|
|
thePlayer->SetResources(theNewResources);
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetReloadTime(void) const
|
|
{
|
|
// TODO: Allow weapons to have different reload times
|
|
return 1.5f;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetReloadAnimation() const
|
|
{
|
|
return kReloadAnimation;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::PlaybackEvent(unsigned short inEvent, int inIparam2, int inFlags) const
|
|
{
|
|
unsigned short theEvent = inEvent;
|
|
if(theEvent != 0)
|
|
{
|
|
// Playback event, sending along enough data so client knows who triggered this event!
|
|
int theWeaponIndex = 0;
|
|
AvHUser3 theUser3 = AVH_USER3_NONE;
|
|
int theUpgrades = 0;
|
|
|
|
// When predicting weapons, play the event locally, then tell everyone else but us to play it back later
|
|
int flags = inFlags;
|
|
edict_t* theEdict;
|
|
|
|
// Pass player random seed to event, so it chooses the right direction for spread
|
|
int theRandomNumber = this->m_pPlayer->random_seed;
|
|
|
|
#if defined( AVH_CLIENT )
|
|
theUser3 = gHUD.GetHUDUser3();
|
|
theUpgrades = gHUD.GetHUDUpgrades();
|
|
theEdict = NULL;
|
|
#else
|
|
theUser3 = dynamic_cast<AvHPlayer*>(this->m_pPlayer)->GetUser3();
|
|
theUpgrades = this->m_pPlayer->pev->iuser4;
|
|
theEdict = this->m_pPlayer->edict();
|
|
#endif
|
|
|
|
// For bullet spread
|
|
//theRandomNumber = UTIL_SharedRandomLong(this->m_pPlayer->random_seed, 1, kBulletSpreadGranularity*kBulletSpreadGranularity);
|
|
|
|
// When in overwatch, the weapon is fired on the server, so the client firing the weapon won't be firing it locally first
|
|
#if defined(AVH_SERVER)
|
|
if(this->mInOverwatch)
|
|
{
|
|
flags = 0;
|
|
}
|
|
#endif
|
|
|
|
// Allow weapon to specify some parameters, so they are available on both client and server
|
|
Vector theEventOrigin;
|
|
this->GetEventOrigin(theEventOrigin);
|
|
|
|
Vector theEventAngles;
|
|
this->GetEventAngles(theEventAngles);
|
|
|
|
float theVolume = AvHPlayerUpgrade::GetSilenceVolumeLevel(theUser3, theUpgrades);
|
|
|
|
//( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
|
|
PLAYBACK_EVENT_FULL(flags, this->m_pPlayer->edict(), theEvent, 0, (float *)&theEventOrigin, (float *)&theEventAngles, theVolume, 0.0, theRandomNumber, inIparam2, 0, 0 );
|
|
}
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SetAnimationAndSound(void)
|
|
{
|
|
this->m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
|
|
this->m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
// player "shoot" animation
|
|
//SendWeaponAnim(this->GetShootAnimation());
|
|
|
|
this->m_pPlayer->SetAnimation(PLAYER_ATTACK1);
|
|
|
|
if(this->GetHasMuzzleFlash())
|
|
{
|
|
this->m_pPlayer->pev->effects = (int)(this->m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
}
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::FireProjectiles(void)
|
|
{
|
|
Vector vecSrc = this->m_pPlayer->GetGunPosition();
|
|
Vector vecAiming = this->m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
|
|
|
// Fire the bullets and apply damage
|
|
int theRange = this->mRange;
|
|
float theDamage = this->mDamage;
|
|
|
|
int theTracerFreq;
|
|
float theDamageMultiplier;
|
|
AvHPlayerUpgrade::GetWeaponUpgrade(this->m_pPlayer->pev->iuser3, this->m_pPlayer->pev->iuser4, &theDamageMultiplier, &theTracerFreq);
|
|
theDamage *= theDamageMultiplier;
|
|
|
|
Vector theSpread = this->GetProjectileSpread();
|
|
this->m_pPlayer->FireBulletsPlayer(1, vecSrc, vecAiming, theSpread, theRange, BULLET_PLAYER_MP5, theTracerFreq, theDamage, this->m_pPlayer->pev, this->m_pPlayer->random_seed);
|
|
|
|
this->mWeaponPrimeStarted = false;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetPrimeAnimation() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetWeaponPrimeTime() const
|
|
{
|
|
return -1.0f;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::PrimeWeapon()
|
|
{
|
|
float thePrimeTime = this->GetWeaponPrimeTime();
|
|
if(thePrimeTime > 0.0f)
|
|
{
|
|
if(!this->GetIsWeaponPriming())
|
|
{
|
|
char* thePrimeSound = this->GetPrimeSound();
|
|
if(thePrimeSound)
|
|
{
|
|
EMIT_SOUND(ENT(this->pev), CHAN_WEAPON, thePrimeSound, this->GetPrimeSoundVolume(), ATTN_NORM);
|
|
}
|
|
|
|
this->PlaybackEvent(this->mWeaponAnimationEvent, this->GetPrimeAnimation());
|
|
|
|
this->mTimeOfLastPrime = UTIL_WeaponTimeBase() + thePrimeTime;
|
|
|
|
this->mWeaponPrimeStarted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::GetIsWeaponPrimed() const
|
|
{
|
|
return ((this->GetWeaponPrimeTime() > 0.0f) && this->mWeaponPrimeStarted && (UTIL_WeaponTimeBase() > this->mTimeOfLastPrime));
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::GetIsWeaponPriming() const
|
|
{
|
|
return ((this->GetWeaponPrimeTime() > 0.0f) && this->mWeaponPrimeStarted && (UTIL_WeaponTimeBase() < this->mTimeOfLastPrime));
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SetNextAttack(void)
|
|
{
|
|
// this->m_flNextPrimaryAttack += this->mROF;
|
|
//
|
|
// if(this->m_flNextPrimaryAttack < 0)
|
|
// this->m_flNextPrimaryAttack = this->mROF;
|
|
|
|
float theRateOfFire = this->ComputeAttackInterval();
|
|
|
|
this->m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + theRateOfFire;
|
|
|
|
if(this->m_flNextPrimaryAttack < 0)
|
|
{
|
|
this->m_flNextPrimaryAttack = theRateOfFire;
|
|
}
|
|
|
|
this->SetNextIdle();
|
|
}
|
|
|
|
|
|
void AvHBasePlayerWeapon::PrimaryAttack(bool fireOnAttackUp)
|
|
{
|
|
if (this->ProcessValidAttack())
|
|
{
|
|
|
|
if (!this->mAttackButtonDownLastFrame)
|
|
{
|
|
this->PlaybackEvent(this->mStartEvent);
|
|
this->mAttackButtonDownLastFrame = true;
|
|
}
|
|
|
|
this->PlaybackEvent(this->mEvent, this->GetShootAnimation());
|
|
this->SetAnimationAndSound();
|
|
|
|
// If player is too close to a wall, don't actually fire the projectile
|
|
if(this->GetIsGunPositionValid())
|
|
{
|
|
this->FireProjectiles();
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
#ifdef AVH_SERVER
|
|
char theMessage[256];
|
|
sprintf(theMessage, "Gun position is not valid, skipping call to FireProjectiles.\n");
|
|
ALERT(at_console, theMessage);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
this->DeductCostForShot();
|
|
this->SetNextAttack();
|
|
|
|
}
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::Reload(void)
|
|
{
|
|
// Move clip sounds out
|
|
int theReloadAnimation = this->GetReloadAnimation();
|
|
float theReloadTime = this->GetReloadTime();
|
|
int theClipSize = this->GetClipSize();
|
|
|
|
this->DefaultReload(theClipSize, theReloadAnimation, theReloadTime);
|
|
|
|
// Don't idle for a bit
|
|
this->SetNextIdle();
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetCanBeResupplied() const
|
|
{
|
|
bool theCanBeResupplied = false;
|
|
|
|
if(this->UsesAmmo())
|
|
{
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
|
|
int theCurrentPrimary = this->m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType];
|
|
int theMaxPrimary = theItemInfo.iMaxAmmo1;
|
|
|
|
// Add some to primary store
|
|
if(theCurrentPrimary < theMaxPrimary)
|
|
{
|
|
theCanBeResupplied = true;
|
|
}
|
|
}
|
|
|
|
return theCanBeResupplied;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::Resupply()
|
|
{
|
|
bool theResupplied = false;
|
|
|
|
if(this->GetCanBeResupplied())
|
|
{
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
|
|
// Get amount to add
|
|
int theMaxClip = theItemInfo.iMaxClip;
|
|
|
|
// Add half the clip each time, rounding up (roughly 3 seconds per clip ()
|
|
int theAmountToAdd = max((theMaxClip+1)/2, 1);
|
|
|
|
int theCurrentPrimary = this->m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType];
|
|
int theMaxPrimary = theItemInfo.iMaxAmmo1;
|
|
|
|
// Add ammo
|
|
this->m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = min(theCurrentPrimary + theAmountToAdd, theMaxPrimary);
|
|
|
|
const float theDelay = 1.0f;
|
|
|
|
if (this->m_iId != AVH_WEAPON_SONIC && this->m_iId != AVH_WEAPON_GRENADE_GUN)
|
|
{
|
|
this->m_flNextPrimaryAttack = max(this->m_flNextPrimaryAttack, (UTIL_WeaponTimeBase() + (theDelay * 2)));// Delay*2 because nextprimary attack gets decremented twice.
|
|
}
|
|
else
|
|
{
|
|
bool startingReload = (this->m_pPlayer->pev->button & IN_RELOAD && (this->m_iClip < this->GetClipSize()));
|
|
//Some edge cases here but it allows staged reload to start or continue while resupplying and adds resupply delay if not reloading.
|
|
if ((this->m_fInSpecialReload == 0 && !startingReload) || (this->m_fInSpecialReload >= 2 && this->m_iClip >= (this->GetClipSize() - 1)))
|
|
this->m_flNextPrimaryAttack = max(this->m_flNextPrimaryAttack, (UTIL_WeaponTimeBase() + (theDelay * 2)));
|
|
}
|
|
this->mTimeOfLastResupply = UTIL_WeaponTimeBase() + theDelay;
|
|
}
|
|
|
|
return theResupplied;
|
|
}
|
|
|
|
float AvHBasePlayerWeapon::GetResupplyTimer() const
|
|
{
|
|
return this->mTimeOfLastResupply;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SendWeaponAnim(int inAnimation, int skiplocal, int body)
|
|
{
|
|
if(inAnimation >= 0)
|
|
{
|
|
this->m_pPlayer->pev->weaponanim = inAnimation;
|
|
|
|
this->PlaybackEvent(this->mWeaponAnimationEvent, inAnimation);
|
|
}
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SecondaryAttack(void)
|
|
{
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::Spawn()
|
|
{
|
|
CBasePlayerWeapon::Spawn();
|
|
|
|
this->pev->solid = SOLID_BBOX;
|
|
this->pev->movetype = MOVETYPE_TOSS;
|
|
UTIL_SetOrigin(this->pev, this->pev->origin);
|
|
UTIL_SetSize(this->pev, kMarineItemMinSize, kMarineItemMaxSize);
|
|
|
|
this->pev->iuser3 = AVH_USER3_MARINEITEM;
|
|
|
|
#ifdef AVH_SERVER
|
|
if(!this->GetIsPersistent())
|
|
{
|
|
this->mLifetime = AvHSUGetWeaponStayTime();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetEnabledState() const
|
|
{
|
|
bool result=false;
|
|
#ifdef AVH_SERVER
|
|
result= (this->m_iEnabled == 1);
|
|
#else
|
|
// : 497 client now uses the enabled state in the appropriate WEAPON
|
|
ItemInfo theItemInfo;
|
|
this->GetItemInfo(&theItemInfo);
|
|
WEAPON *pWeapon = gWR.GetWeapon( theItemInfo.iId );
|
|
if ( pWeapon != 0 ) {
|
|
result=(pWeapon->iEnabled == 1);
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
#ifdef AVH_SERVER
|
|
void AvHBasePlayerWeapon::VirtualMaterialize(void)
|
|
{
|
|
int theLifetime = this->GetGroundLifetime();
|
|
|
|
if(theLifetime >= 0)
|
|
{
|
|
SetThink(&AvHBasePlayerWeapon::DestroyItem);
|
|
this->pev->nextthink = gpGlobals->time + theLifetime;
|
|
}
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetGroundLifetime() const
|
|
{
|
|
return this->mLifetime;
|
|
}
|
|
|
|
// -1 means never expire
|
|
void AvHBasePlayerWeapon::SetGroundLifetime(int inGroundLifetime)
|
|
{
|
|
this->mLifetime = inGroundLifetime;
|
|
}
|
|
|
|
int AvHBasePlayerWeapon::GetResourceCost() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::VirtualDestroyItem(void)
|
|
{
|
|
if(this->GetIsPersistent())
|
|
{
|
|
// Make this weapon invisible until map reset
|
|
this->pev->effects |= EF_NODRAW;
|
|
this->pev->solid = SOLID_NOT;
|
|
this->pev->takedamage = DAMAGE_NO;
|
|
SetThink(NULL);
|
|
}
|
|
else
|
|
{
|
|
CBasePlayerItem::VirtualDestroyItem();
|
|
}
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::ResetEntity()
|
|
{
|
|
CBasePlayerWeapon::ResetEntity();
|
|
|
|
this->pev->effects = 0;
|
|
this->pev->solid = SOLID_BBOX;
|
|
this->pev->movetype = MOVETYPE_TOSS;
|
|
|
|
this->pev->takedamage = DAMAGE_YES;
|
|
|
|
this->VirtualMaterialize();
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SetOverwatchState(bool inState)
|
|
{
|
|
this->mInOverwatch = inState;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::UpdateInventoryEnabledState(int inNumActiveHives)
|
|
{
|
|
// Process here
|
|
int theEnabledState = 1;
|
|
bool theGameStarted = GetGameRules()->GetGameStarted();
|
|
|
|
ItemInfo theItemInfo;
|
|
if(this->GetItemInfo(&theItemInfo) != 0)
|
|
{
|
|
int theWeaponFlags = theItemInfo.iFlags;
|
|
AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(this->m_pPlayer);
|
|
ASSERT(thePlayer);
|
|
|
|
// Pregame alien abilities
|
|
if (!theGameStarted)
|
|
{
|
|
if (!thePlayer->GetIsAbleToAct() ||
|
|
(thePlayer->pev->iuser3 == AVH_USER3_ALIEN_PLAYER5 && (theWeaponFlags & ONE_HIVE_REQUIRED)) ||
|
|
(theWeaponFlags & TWO_HIVES_REQUIRED) ||
|
|
(theWeaponFlags & THREE_HIVES_REQUIRED))
|
|
{
|
|
//// Allow leap
|
|
//if (!(thePlayer->pev->iuser3 == AVH_USER3_ALIEN_PLAYER1 && (theWeaponFlags & TWO_HIVES_REQUIRED)))
|
|
//{
|
|
theEnabledState = 0;
|
|
//}
|
|
}
|
|
}
|
|
// If we don't have the hives required, or we're ensnared
|
|
else if (/*thePlayer->GetIsTemporarilyInvulnerable() ||*/
|
|
!thePlayer->GetIsAbleToAct() ||
|
|
((inNumActiveHives < 1) && (theWeaponFlags & ONE_HIVE_REQUIRED)) ||
|
|
((inNumActiveHives < 2) && (theWeaponFlags & TWO_HIVES_REQUIRED)) ||
|
|
((inNumActiveHives < 3) && (theWeaponFlags & THREE_HIVES_REQUIRED)) ||
|
|
(this->GetResourceCost() > thePlayer->GetResources(false)) )
|
|
{
|
|
// Disable it
|
|
theEnabledState = 0;
|
|
}
|
|
}
|
|
// : 497 save the state for when we send the CurWeapon message
|
|
this->m_iEnabled = theEnabledState;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::KeyValue(KeyValueData* pkvd)
|
|
{
|
|
// Any entity placed by the mapper is persistent
|
|
this->SetPersistent();
|
|
|
|
if(FStrEq(pkvd->szKeyName, "teamchoice"))
|
|
{
|
|
this->pev->team = (AvHTeamNumber)(atoi(pkvd->szValue));
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if(FStrEq(pkvd->szKeyName, "angles"))
|
|
{
|
|
// TODO: Insert code here
|
|
//pkvd->fHandled = TRUE;
|
|
}
|
|
else if(FStrEq(pkvd->szKeyName, "lifetime"))
|
|
{
|
|
this->mLifetime = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CBasePlayerWeapon::KeyValue(pkvd);
|
|
}
|
|
}
|
|
|
|
// 0 means never expire, -1 means no value was set so use default
|
|
int AvHBasePlayerWeapon::GetLifetime() const
|
|
{
|
|
int theLifetime = this->mLifetime;
|
|
|
|
if(theLifetime < 0)
|
|
{
|
|
theLifetime = AvHSUGetWeaponStayTime();
|
|
}
|
|
|
|
return theLifetime;
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::GetIsPersistent() const
|
|
{
|
|
return this->mIsPersistent;
|
|
}
|
|
|
|
void AvHBasePlayerWeapon::SetPersistent()
|
|
{
|
|
this->mIsPersistent = true;
|
|
}
|
|
#endif
|
|
|
|
void AvHBasePlayerWeapon::SetNextIdle(void)
|
|
{
|
|
float theRandomIdle = UTIL_SharedRandomFloat(this->m_pPlayer->random_seed, 10, 15);
|
|
|
|
this->m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + theRandomIdle;
|
|
|
|
// Just added these next two lines 8/8/01 (trying to fix prediction wackiness)
|
|
if(this->m_flTimeWeaponIdle < 0)
|
|
{
|
|
this->m_flTimeWeaponIdle = theRandomIdle;
|
|
}
|
|
}
|
|
|
|
BOOL AvHBasePlayerWeapon::UseDecrement( void )
|
|
{
|
|
// If we're predicting, return true
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void AvHBasePlayerWeapon::WeaponIdle(void)
|
|
{
|
|
//#ifdef AVH_CLIENT
|
|
// char sz[ 128 ];
|
|
// sprintf(sz, "during idle, clip is %d\n", this->m_iClip);
|
|
// gEngfuncs.pfnCenterPrint( sz );
|
|
//
|
|
// //gEngfuncs.Con_Printf("during idle, clip is %d\n", sz);
|
|
//#endif
|
|
|
|
if(this->mAttackButtonDownLastFrame)
|
|
{
|
|
this->PlaybackEvent(this->mEndEvent);
|
|
this->mAttackButtonDownLastFrame = false;
|
|
}
|
|
|
|
ResetEmptySound();
|
|
|
|
this->m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
|
|
|
if(this->m_flTimeWeaponIdle <= UTIL_WeaponTimeBase())
|
|
{
|
|
this->SendWeaponAnim(this->GetIdleAnimation());
|
|
|
|
this->m_pPlayer->SetAnimation(PLAYER_IDLE);
|
|
|
|
this->SetNextIdle();
|
|
}
|
|
}
|
|
|
|
bool AvHBasePlayerWeapon::UsesAmmo(void) const
|
|
{
|
|
return true;
|
|
}
|