2226 lines
47 KiB
C++
2226 lines
47 KiB
C++
/***
|
|
*
|
|
* Copyright (C) 2002 The Wastes Project, All Rights Reserved.
|
|
*
|
|
* This product contains software technology from Valve Software, LLC,
|
|
* Copyright © 1996-2001, Valve LLC, All rights reserved.
|
|
*
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
* The Wastes Project. All other use, distribution, or modification is prohibited
|
|
* without written permission from The Wastes Project.
|
|
*
|
|
***/
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
#include "weapons.h"
|
|
#include "weaponinfo.h"
|
|
#include "player.h"
|
|
#include "soundent.h"
|
|
#include "thewastes.h"
|
|
#include "game.h"
|
|
#include "gamerules.h"
|
|
|
|
// Entity Linkage
|
|
LINK_ENTITY_TO_CLASS(weapon_smg9,CSmg9);
|
|
LINK_ENTITY_TO_CLASS(ammo_smg9,CSmg9Ammo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_fnfal,CFnFal);
|
|
LINK_ENTITY_TO_CLASS(ammo_fnfal,CFnFalAmmo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_tommygun,CTommyGun);
|
|
LINK_ENTITY_TO_CLASS(ammo_tommygun,CTommyGunAmmo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_g11,CG11);
|
|
LINK_ENTITY_TO_CLASS(ammo_g11,CG11Ammo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_boltrifle,CBoltRifle);
|
|
LINK_ENTITY_TO_CLASS(ammo_boltrifle,CBoltRifleAmmo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_sten,CSten);
|
|
LINK_ENTITY_TO_CLASS(ammo_sten,CStenAmmo);
|
|
|
|
/*************
|
|
Automatic weapon
|
|
*************/
|
|
enum automatic_state_e {
|
|
STATE_BURST,
|
|
STATE_FULLAUTO,
|
|
};
|
|
|
|
int CAutomatic::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iPosition = iItemSlot() - 1;
|
|
p->pszName = STRING(pev->classname);
|
|
p->iFlags = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CAutomatic::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
local_data->iuser1 = m_iAllowFire;
|
|
}
|
|
|
|
void CAutomatic::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iState = local_data->m_iWeaponState;
|
|
m_iAllowFire = local_data->iuser1;
|
|
#endif
|
|
}
|
|
|
|
void CAutomatic::ItemPostFrame()
|
|
{
|
|
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) )
|
|
{
|
|
// complete the reload.
|
|
int j = Q_min( iMaxClip(), m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
// account for a bullet in the gun
|
|
if(m_iClip != 0)
|
|
m_iClip = 1;
|
|
|
|
// Add them to the clip
|
|
m_iClip += j;
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
|
|
#ifndef CLIENT_DLL
|
|
m_pPlayer->TabulateAmmo();
|
|
#endif
|
|
m_fInReload = FALSE;
|
|
}
|
|
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
{
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
|
|
CWasteWeapon::ItemPostFrame();
|
|
}
|
|
|
|
void CAutomatic::Holster(int skiplocal)
|
|
{
|
|
m_iState = STATE_BURST;
|
|
m_iAllowFire = TRUE;
|
|
CWasteWeapon::Holster(skiplocal);
|
|
}
|
|
|
|
/*************
|
|
SMG9 - let the whoring begin!
|
|
*************/
|
|
#define SMG9_JUMPPENALTY 2.4 // Accuracy infraction for jumping shooters.
|
|
#define SMG9_DUCKPENALTY 0.65 // Not really a penalty, increases accuracy if your duckin
|
|
#define SMG9_AIM_SECONDARY 0.3
|
|
|
|
#define SMG9_BURST_COUNT 3
|
|
|
|
void CSmg9::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_smg9");
|
|
|
|
m_iId = WEAPON_SMG9;
|
|
m_iDefaultAmmo = AMMO_GIVE_SMG9;
|
|
m_iClipSize = CLIP_SMG9;
|
|
m_iAllowFire = TRUE;
|
|
m_iState = STATE_BURST;
|
|
m_bBurstFire = FALSE;
|
|
|
|
m_flAccuracy = 0.0385f;
|
|
m_flRateOfFire = 0.1;
|
|
|
|
pev->fuser1 = UTIL_WeaponTimeBase();
|
|
|
|
SET_MODEL(ENT(pev),"models/w_smg9.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CSmg9::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_smg9.mdl");
|
|
PRECACHE_MODEL("models/p_smg9.mdl");
|
|
PRECACHE_MODEL("models/w_smg9.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_9x22mm_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_9x22mm_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/smg9_fire1.wav");
|
|
PRECACHE_SOUND("weapons/smg9_fire2.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/smg9.sc");
|
|
}
|
|
|
|
int CSmg9::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_SMG9;
|
|
p->iId = m_iId = WEAPON_SMG9;
|
|
p->iWeight = WEIGHT_SMG9;
|
|
p->iSlot = 2;
|
|
|
|
p->pszAmmo1 = "9mm SMG9 Ammo";
|
|
p->iMaxAmmo1 = AMMO_MAX_SMG9;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return CAutomatic::GetItemInfo(p);
|
|
}
|
|
|
|
void CSmg9::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
local_data->iuser3 = m_bLaserVisible;
|
|
local_data->iuser4 = (m_pPlayer->m_pActiveItem == this) ? 1 : 0;
|
|
|
|
CAutomatic::PackWeapon(weapon_data);
|
|
}
|
|
|
|
void CSmg9::UnpackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
m_bLaserVisible = local_data->iuser3;
|
|
|
|
#ifdef CLIENT_DLL
|
|
// Only do this check if we're active
|
|
if(local_data->iuser4)
|
|
g_iClientLasersEnabled[GetLocalPlayerIndex()] = m_bLaserVisible;
|
|
#endif
|
|
|
|
CAutomatic::UnpackWeapon(weapon_data);
|
|
}
|
|
|
|
float CSmg9::flGetTiltedDamage()
|
|
{
|
|
float fRet = RANDOM_FLOAT(28,38);
|
|
|
|
// 5% Damage increase
|
|
if(m_iState == STATE_BURST)
|
|
fRet *= 1.05f;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
const char *CSmg9::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_SMG9_1 : DEATH_SMG9_2;
|
|
}
|
|
|
|
void CSmg9::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
else if(m_iClip <= 0)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
SendWeaponAnim((m_iState == STATE_BURST) ? SMG9_SHOOT_EMPTY : SMG9_SECONDARY_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
return;
|
|
}
|
|
|
|
float spread = m_flAccuracy;
|
|
float rof = m_flRateOfFire;
|
|
BOOL startburst = FALSE;
|
|
|
|
// Semi-Automatic control
|
|
if(m_iState == STATE_BURST)
|
|
{
|
|
if(pev->fuser1 <= UTIL_WeaponTimeBase())
|
|
{
|
|
m_bBurstFire = TRUE;
|
|
pev->fuser1 = UTIL_WeaponTimeBase() + (SMG9_BURST_COUNT * rof);
|
|
|
|
startburst = TRUE;
|
|
}
|
|
}
|
|
else if(m_iState == STATE_FULLAUTO)
|
|
// Modify gun logic if we're just shooting the gangsta style
|
|
spread /= SMG9_AIM_SECONDARY;
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir;
|
|
|
|
Vector Spread;
|
|
|
|
// Accuracy modifiers
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
Spread = Vector(spread*SMG9_DUCKPENALTY,spread*SMG9_DUCKPENALTY,spread*SMG9_DUCKPENALTY);
|
|
else if(m_pPlayer->pev->flags & FL_ONGROUND)
|
|
Spread = Vector(spread,spread,spread);
|
|
else
|
|
Spread = Vector(spread*SMG9_JUMPPENALTY,spread*SMG9_JUMPPENALTY,spread*SMG9_JUMPPENALTY);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, Spread, 8192, BULLET_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_SMG9);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
if(startburst)
|
|
{
|
|
Vector accVector(m_flAccuracy,0,0);
|
|
|
|
for(int i = 0;i < Q_min(m_iClip,SMG9_BURST_COUNT);i++)
|
|
{
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
rof * i,
|
|
(float*)&g_vecZero,
|
|
(float*)&accVector,
|
|
dir.x,
|
|
dir.y + m_flAccuracy * i,
|
|
(m_iState == STATE_FULLAUTO) ? 1 : 0,
|
|
(m_iClip == 0) ? 1 : 0,
|
|
(m_pPlayer->pev->flags & FL_DUCKING) ? 1 : 0, // Less recoil
|
|
(i > 0) ? 1 : 0);
|
|
}
|
|
}
|
|
else if(!m_bBurstFire)
|
|
{
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
dir.x,
|
|
dir.y,
|
|
(m_iState == STATE_FULLAUTO) ? 1 : 0,
|
|
(m_iClip == 0) ? 1 : 0,
|
|
(m_pPlayer->pev->flags & FL_DUCKING) ? 1 : 0, // Less recoil
|
|
0);
|
|
}
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + rof;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
void CSmg9::SecondaryAttack()
|
|
{
|
|
switch(m_iState)
|
|
{
|
|
case STATE_BURST:
|
|
m_iState = STATE_FULLAUTO;
|
|
SendWeaponAnim(SMG9_GOTO_SECONDARY,UseDecrement() ? 1 : 0);
|
|
m_bLaserVisible = FALSE;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint("Full-automatic fire");
|
|
g_iClientLasersEnabled[GetLocalPlayerIndex()] = 0;
|
|
#endif
|
|
break;
|
|
case STATE_FULLAUTO:
|
|
m_iState = STATE_BURST;
|
|
SendWeaponAnim(SMG9_END_SECONDARY,UseDecrement() ? 1 : 0);
|
|
m_bLaserVisible = TRUE;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint( "Burst fire" );
|
|
g_iClientLasersEnabled[GetLocalPlayerIndex()] = 1;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
m_iAllowFire = TRUE;
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.25;
|
|
}
|
|
|
|
void CSmg9::ItemPostFrame()
|
|
{
|
|
// Burst fire logic
|
|
if(m_iState == STATE_BURST && m_bBurstFire)
|
|
{
|
|
// Player can still fire the gun
|
|
if(pev->fuser1 >= UTIL_WeaponTimeBase())
|
|
{
|
|
// Player will now fire the gun
|
|
if(m_flNextPrimaryAttack <= UTIL_WeaponTimeBase())
|
|
PrimaryAttack();
|
|
}
|
|
else
|
|
{
|
|
m_iAllowFire = FALSE;
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3f;
|
|
}
|
|
}
|
|
|
|
CAutomatic::ItemPostFrame();
|
|
|
|
if(m_iAllowFire && pev->fuser1 <= UTIL_WeaponTimeBase())
|
|
m_bBurstFire = FALSE;
|
|
}
|
|
|
|
void CSmg9::Reload()
|
|
{
|
|
int iResult;
|
|
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation(PLAYER_RELOAD);
|
|
|
|
// Why am i making this function unreadable as hell?
|
|
// BECAUSE I CAN! :D
|
|
iResult = DefaultReload(m_iClipSize,
|
|
(m_iClip == 0)
|
|
? (m_iState == STATE_BURST) ? SMG9_RELOAD_EMPTY : SMG9_SECONDARY_RELOAD
|
|
: (m_iState == STATE_BURST) ? SMG9_RELOAD : SMG9_SECONDARY_RELOAD,
|
|
(m_iClip == 0) ? 3.0f : 2.0f);
|
|
if(iResult)
|
|
{
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL CSmg9::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_smg9.mdl","models/p_smg9.mdl",(m_iState == STATE_BURST) ? SMG9_DRAW : SMG9_SECONDARY_DRAW,"smg9"))
|
|
return FALSE;
|
|
|
|
m_iAllowFire = TRUE;
|
|
|
|
int ret = CAutomatic::Deploy();
|
|
|
|
if(ret && m_iState == STATE_BURST)
|
|
{
|
|
m_bLaserVisible = TRUE;
|
|
|
|
#ifdef CLIENT_DLL
|
|
g_iClientLasersEnabled[GetLocalPlayerIndex()] = 1;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL CSmg9::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CSmg9::Holster(int skiplocal)
|
|
{
|
|
m_bLaserVisible = FALSE;
|
|
|
|
#ifdef CLIENT_DLL
|
|
g_iClientLasersEnabled[GetLocalPlayerIndex()] = 0;
|
|
#endif
|
|
m_iAllowFire = TRUE;
|
|
CWasteWeapon::Holster(skiplocal);
|
|
}
|
|
|
|
BOOL CSmg9::bLaserActive()
|
|
{
|
|
if( m_pPlayer != NULL && m_pPlayer->m_pActiveItem == this )
|
|
return m_bLaserVisible;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CSmg9Ammo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_smg9.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CSmg9Ammo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_smg9.mdl");
|
|
}
|
|
|
|
BOOL CSmg9Ammo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo( AMMO_GIVE_SMG9, "9mm SMG9 Ammo", AMMO_MAX_SMG9) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
FN-FAL
|
|
*************/
|
|
#define FNFAL_JUMPPENALTY 2.4 // Accuracy infraction for jumping shooters.
|
|
#define FNFAL_DUCKPENALTY 0.5 // Not really a penalty, increases accuracy if your duckin
|
|
#define FNFAL_AIM_SECONDARY 0.75
|
|
#define FNFAL_AIM_PRIMARY 0.80
|
|
|
|
void CFnFal::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_fnfal");
|
|
|
|
m_iId = WEAPON_FNFAL;
|
|
m_iDefaultAmmo = AMMO_GIVE_FNFAL;
|
|
m_iClipSize = CLIP_FNFAL;
|
|
m_iAllowFire = TRUE;
|
|
m_iState = STATE_FULLAUTO;
|
|
m_iAim = 0;
|
|
|
|
m_flAccuracy = 0.015;
|
|
m_flRateOfFire = 0.105;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_fnfal.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CFnFal::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_fnfal.mdl");
|
|
PRECACHE_MODEL("models/p_fnfal.mdl");
|
|
PRECACHE_MODEL("models/w_fnfal.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_762mm_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_762mm_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/fnfal_fire1.wav");
|
|
PRECACHE_SOUND("weapons/fnfal_fire2.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/fnfal.sc");
|
|
}
|
|
|
|
void CFnFal::PackWeapon(void *weapon_data)
|
|
{
|
|
CAutomatic::PackWeapon(weapon_data);
|
|
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
local_data->iuser4 = m_iAim;
|
|
}
|
|
|
|
void CFnFal::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
CAutomatic::UnpackWeapon(weapon_data);
|
|
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iAim = local_data->iuser4;
|
|
m_iState = local_data->m_iWeaponState;
|
|
#endif
|
|
}
|
|
|
|
int CFnFal::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_FNFAL;
|
|
p->iId = m_iId = WEAPON_FNFAL;
|
|
p->iWeight = WEIGHT_UNIQUE;
|
|
p->iSlot = 3;
|
|
|
|
p->pszAmmo1 = "FNFAL Ammo";
|
|
p->iMaxAmmo1 = AMMO_MAX_FNFAL;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return CAutomatic::GetItemInfo(p);
|
|
}
|
|
|
|
float CFnFal::flGetTiltedDamage()
|
|
{
|
|
float fRet = RANDOM_FLOAT(45,55);
|
|
|
|
// 5% damage increase
|
|
if(m_iState == STATE_BURST)
|
|
fRet *= 1.05f;
|
|
|
|
// 5% damage increase
|
|
if(m_iAim)
|
|
fRet *= 1.05f;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
const char *CFnFal::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_FNFAL_1 : DEATH_FNFAL_2;
|
|
}
|
|
|
|
void CFnFal::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(m_iClip <= 0)
|
|
{
|
|
if(m_fFireOnEmpty)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
SendWeaponAnim((m_iAim) ? FNFAL_AIM_SHOOT_EMPTY : FNFAL_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
float spread = m_flAccuracy;
|
|
float rof = m_flRateOfFire;
|
|
|
|
// Semi-Automatic control
|
|
if(m_iState == STATE_BURST)
|
|
{
|
|
if( m_iAim )
|
|
spread *= FNFAL_AIM_SECONDARY;
|
|
else
|
|
spread *= FNFAL_AIM_PRIMARY;
|
|
|
|
m_iAllowFire = FALSE;
|
|
rof += 0.15; // Add some time
|
|
}
|
|
else if(m_iState == STATE_FULLAUTO)
|
|
{
|
|
// Increase accuracy for full auto
|
|
if( m_iAim )
|
|
spread *= FNFAL_AIM_SECONDARY;
|
|
}
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir;
|
|
|
|
Vector Spread;
|
|
|
|
// Accuracy modifiers
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
Spread = Vector(spread*FNFAL_DUCKPENALTY,spread*FNFAL_DUCKPENALTY,spread*FNFAL_DUCKPENALTY);
|
|
else if(m_pPlayer->pev->flags & FL_ONGROUND)
|
|
Spread = Vector(spread,spread,spread);
|
|
else
|
|
Spread = Vector(spread*FNFAL_JUMPPENALTY,spread*FNFAL_JUMPPENALTY,spread*FNFAL_JUMPPENALTY);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, Spread, 8192,BULLET_762MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_FNFAL);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
dir.x,
|
|
dir.y,
|
|
0,
|
|
(m_iState == STATE_BURST) ? 1 : 0,
|
|
(m_pPlayer->pev->flags & FL_DUCKING) ? 1 : 0, // Less recoil
|
|
(m_iAim == 1 ) ? 1 : 0 );
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + rof;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
|
|
void CFnFal::SecondaryAttack()
|
|
{
|
|
switch( m_iState )
|
|
{
|
|
case STATE_FULLAUTO:
|
|
m_iState = STATE_BURST;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint( "Semi-automatic fire" );
|
|
#endif
|
|
break;
|
|
case STATE_BURST:
|
|
m_iState = STATE_FULLAUTO;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint( "Full-automatic fire" );
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
m_iAllowFire = TRUE;
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2f;
|
|
}
|
|
|
|
void CFnFal::SpecialMode()
|
|
{
|
|
if( m_iAim == 1)
|
|
{
|
|
m_iAim = 0;
|
|
MODIFY_PLAYER_SPEED( m_pPlayer, 0 );
|
|
SendWeaponAnim( FNFAL_END_AIM, UseDecrement() ? 1 : 0 );
|
|
}
|
|
else
|
|
{
|
|
m_iAim = 1;
|
|
MODIFY_PLAYER_SPEED( m_pPlayer, 0.7 );
|
|
SendWeaponAnim( FNFAL_GOTO_AIM, UseDecrement() ? 1 : 0 );
|
|
}
|
|
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f;
|
|
}
|
|
|
|
void CFnFal::ItemPostFrame()
|
|
{
|
|
// Now we reload
|
|
// A bit of hacking around with state code, but it will do.
|
|
if( m_iAim < 0 && m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() )
|
|
{
|
|
if( m_iAim == -1 )
|
|
{
|
|
m_iAim = -2;
|
|
Reload();
|
|
}
|
|
else if( m_iAim == -2 )
|
|
{
|
|
m_iAim = 0;
|
|
SpecialMode();
|
|
}
|
|
}
|
|
|
|
CAutomatic::ItemPostFrame();
|
|
}
|
|
|
|
void CFnFal::Reload()
|
|
{
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// Revert to normal state if needed
|
|
if( m_iAim == 1 )
|
|
{
|
|
SpecialMode();
|
|
m_iAim = -1;
|
|
return;
|
|
}
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation(PLAYER_RELOAD);
|
|
|
|
if(DefaultReload(m_iClipSize,FNFAL_RELOAD,4.29f))
|
|
{
|
|
m_iAllowFire = TRUE;
|
|
|
|
if( m_iAim == -1 )
|
|
m_iAim = -2;
|
|
}
|
|
}
|
|
|
|
BOOL CFnFal::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_fnfal.mdl","models/p_fnfal.mdl",FNFAL_DRAW,"fnfal"))
|
|
return FALSE;
|
|
|
|
m_iAllowFire = TRUE;
|
|
m_iState = STATE_FULLAUTO;
|
|
m_iAim = FALSE;
|
|
|
|
return CAutomatic::Deploy();
|
|
}
|
|
|
|
void CFnFal::Holster(int skiplocal)
|
|
{
|
|
m_iState = STATE_FULLAUTO;
|
|
MODIFY_PLAYER_SPEED(m_pPlayer,0);
|
|
CAutomatic::Holster(skiplocal);
|
|
}
|
|
|
|
BOOL CFnFal::PlayEmptySound()
|
|
{
|
|
if(m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CFnFalAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_fnfal.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CFnFalAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_fnfal.mdl");
|
|
}
|
|
|
|
BOOL CFnFalAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo(AMMO_GIVE_FNFAL,"FNFAL Ammo",AMMO_MAX_FNFAL) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
Tommy Gun - Damn it feels good to be a gangsta
|
|
*************/
|
|
#define TGUN_JUMPPENALTY 3.2 // Accuracy infraction for jumping shooters.
|
|
#define TGUN_DUCKPENALTY 0.75 // Not really a penalty, increases accuracy if your ducking
|
|
|
|
void CTommyGun::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_tommygun");
|
|
|
|
m_iId = WEAPON_TOMMYGUN;
|
|
m_iDefaultAmmo = AMMO_GIVE_TOMMYGUN;
|
|
m_iClipSize = CLIP_TOMMYGUN;
|
|
m_iAllowFire = TRUE;
|
|
m_iState = STATE_FULLAUTO;
|
|
|
|
m_flAccuracy = 0.0625;
|
|
m_flRateOfFire = 0.1075;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_tommygun.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CTommyGun::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_tommygun.mdl");
|
|
PRECACHE_MODEL("models/p_tommygun.mdl");
|
|
PRECACHE_MODEL("models/w_tommygun.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_45cal_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_45cal_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/tommygun_fire1.wav");
|
|
PRECACHE_SOUND("weapons/tommygun_fire2.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/tommygun.sc");
|
|
}
|
|
|
|
int CTommyGun::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_TOMMYGUN;
|
|
p->iId = m_iId = WEAPON_TOMMYGUN;
|
|
p->iWeight = WEIGHT_UNIQUE;
|
|
p->iSlot = 3;
|
|
|
|
p->pszAmmo1 = "Tommygun Ammo";
|
|
p->iMaxAmmo1 = AMMO_MAX_TOMMYGUN;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return CAutomatic::GetItemInfo(p);
|
|
}
|
|
|
|
float CTommyGun::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(35,45);
|
|
}
|
|
|
|
const char *CTommyGun::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_TOMMYGUN_1 : DEATH_TOMMYGUN_2;
|
|
}
|
|
|
|
void CTommyGun::PrimaryAttack()
|
|
{
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(m_iClip <= 0)
|
|
{
|
|
if(m_fFireOnEmpty)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
SendWeaponAnim(TOMMYGUN_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
float spread = m_flAccuracy;
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir;
|
|
|
|
Vector Spread;
|
|
|
|
// Accuracy modifiers
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
spread *= TGUN_DUCKPENALTY;
|
|
else if(!(m_pPlayer->pev->flags & FL_ONGROUND))
|
|
spread *= TGUN_JUMPPENALTY;
|
|
|
|
Spread = Vector(spread,spread,spread);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, Spread, 8192,BULLET_45ACP, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_TOMMYGUN);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
dir.x,
|
|
dir.y,
|
|
0,
|
|
0,
|
|
(m_pPlayer->pev->flags & FL_DUCKING) ? 1 : 0, // Less recoil
|
|
0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + m_flRateOfFire;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
void CTommyGun::Reload()
|
|
{
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation(PLAYER_RELOAD);
|
|
|
|
if(DefaultReload(m_iClipSize,TOMMYGUN_RELOAD,4.1f))
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
|
|
BOOL CTommyGun::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_tommygun.mdl","models/p_tommygun.mdl",TOMMYGUN_DRAW,"tommygun"))
|
|
return FALSE;
|
|
// m_iAllowFire = TRUE;
|
|
int retval = CAutomatic::Deploy();
|
|
if(retval)
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.8f;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
BOOL CTommyGun::PlayEmptySound()
|
|
{
|
|
if(m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CTommyGunAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_tommygun.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CTommyGunAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_tommygun.mdl");
|
|
}
|
|
|
|
BOOL CTommyGunAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo(AMMO_GIVE_TOMMYGUN,"Tommygun Ammo",AMMO_MAX_TOMMYGUN) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
H&K G11 - New Weapons for a better tomorrow
|
|
*************/
|
|
#define G11_JUMPPENALTY 3.2 // Accuracy infraction for jumping shooters.
|
|
#define G11_DUCKPENALTY 0.8 // Not really a penalty, increases accuracy if your duckin
|
|
|
|
enum g11_state_e {
|
|
G11_BURSTFIRE = 0,
|
|
G11_FULLAUTO = 1,
|
|
};
|
|
|
|
void CG11::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_g11");
|
|
|
|
m_iId = WEAPON_G11;
|
|
m_iDefaultAmmo = AMMO_GIVE_G11;
|
|
m_iClipSize = CLIP_G11;
|
|
m_iAllowFire = TRUE;
|
|
m_iState = STATE_FULLAUTO;
|
|
|
|
m_flAccuracy = 0.04;
|
|
m_flRateOfFire = 0.1;
|
|
m_flBurstAccuracy = 0.03;
|
|
m_bThermal = FALSE;
|
|
m_bActivateThermal = FALSE;
|
|
|
|
m_iWeaponState = G11_FULLAUTO;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_g11.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CG11::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_g11.mdl");
|
|
PRECACHE_MODEL("models/p_g11.mdl");
|
|
PRECACHE_MODEL("models/w_g11.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/g11_ffire1.wav");
|
|
PRECACHE_SOUND("weapons/g11_ffire2.wav");
|
|
PRECACHE_SOUND("weapons/g11_burst.wav");
|
|
PRECACHE_SOUND("weapons/g11_zoom1.wav");
|
|
PRECACHE_SOUND("weapons/g11_zoom2.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/g11.sc");
|
|
}
|
|
|
|
int CG11::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_G11;
|
|
p->iId = m_iId = WEAPON_G11;
|
|
p->iWeight = WEIGHT_UNIQUE;
|
|
p->iSlot = 3;
|
|
|
|
p->pszAmmo1 = "4.7mm Caseless";
|
|
p->iMaxAmmo1 = AMMO_MAX_G11;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return CAutomatic::GetItemInfo(p);
|
|
}
|
|
|
|
float CG11::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(30,40);
|
|
}
|
|
|
|
const char *CG11::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_G11_1 : DEATH_G11_2;
|
|
}
|
|
|
|
void CG11::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iWeaponState;
|
|
local_data->iuser3 = m_bThermal;
|
|
local_data->iuser4 = m_bActivateThermal;
|
|
}
|
|
|
|
void CG11::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_bActivateThermal = local_data->iuser4;
|
|
m_bThermal = local_data->iuser3;
|
|
m_iWeaponState = local_data->m_iWeaponState;
|
|
#endif
|
|
}
|
|
|
|
void CG11::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(m_iClip <= 0)
|
|
{
|
|
if(m_fFireOnEmpty)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
// SendWeaponAnim(G11_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir; // Average of real_dir
|
|
Vector Spread;
|
|
|
|
float spread;
|
|
float rof;
|
|
int bulletcount;
|
|
|
|
if(m_iWeaponState == G11_FULLAUTO)
|
|
{
|
|
spread = m_flAccuracy;
|
|
bulletcount = 1;
|
|
m_iClip--;
|
|
rof = m_flRateOfFire;
|
|
}
|
|
else
|
|
{
|
|
spread = m_flBurstAccuracy;
|
|
bulletcount = Q_min(m_iClip,3);
|
|
m_iClip -= Q_min(m_iClip,3);
|
|
m_iAllowFire = FALSE;
|
|
rof = m_flRateOfFire + 0.2f;
|
|
}
|
|
|
|
// Accuracy modifiers
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
spread *= G11_DUCKPENALTY;
|
|
else if(!(m_pPlayer->pev->flags & FL_ONGROUND))
|
|
spread *= G11_JUMPPENALTY;
|
|
|
|
Spread = Vector(spread,spread,spread);
|
|
|
|
// 3 round burst isnt just a random spray, each bullet goes up alot but horizontal only a little,
|
|
// So we control it this way.
|
|
for(int i = 0;i < bulletcount;i++)
|
|
{
|
|
float xspread = Spread.x;
|
|
Spread.x += RANDOM_FLOAT(-0.015,0.015);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1,vecSrc,vecAiming,Spread,8192,BULLET_47MM,0,0,m_pPlayer->pev,m_pPlayer->random_seed,P_G11);
|
|
|
|
Spread.x = xspread;
|
|
Spread.y += 0.01f;
|
|
}
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
(m_iWeaponState == G11_FULLAUTO) ? dir.x : 0.0f, // send the generic spread on 3 rnd burst (simulate client side)
|
|
(m_iWeaponState == G11_FULLAUTO) ? dir.y : 0.008f, // hopup on each burst bullet
|
|
(m_iWeaponState == G11_BURSTFIRE) ? 1 : 0,
|
|
bulletcount,
|
|
0,
|
|
(m_pPlayer->pev->flags & FL_DUCKING) ? 1 : 0); // Less recoil
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + rof;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT(10,15);
|
|
}
|
|
|
|
void CG11::SecondaryAttack()
|
|
{
|
|
switch(m_iWeaponState)
|
|
{
|
|
case G11_BURSTFIRE:
|
|
m_iWeaponState = G11_FULLAUTO;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint("Full-automatic fire");
|
|
#endif
|
|
break;
|
|
case G11_FULLAUTO:
|
|
m_iWeaponState = G11_BURSTFIRE;
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint("Burst fire");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2f;
|
|
}
|
|
|
|
void CG11::SpecialMode()
|
|
{
|
|
if(m_pPlayer->m_flNextAttack > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
m_bThermal = !m_bThermal;
|
|
|
|
int flags;
|
|
|
|
// Zoom
|
|
switch(m_bThermal)
|
|
{
|
|
case FALSE:
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1, // Zoom sound :)
|
|
1); // Unzoom sound :)
|
|
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
|
|
SendWeaponAnim(G11_ACTIVATE_SCOPE,UseDecrement() ? 1 : 0);
|
|
break;
|
|
case TRUE:
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1, // Zoom sound :)
|
|
0);
|
|
|
|
SendWeaponAnim(G11_DEACTIVATE_SCOPE,UseDecrement() ? 1 : 0);
|
|
m_bActivateThermal = TRUE;
|
|
break;
|
|
}
|
|
|
|
|
|
#ifdef CLIENT_DLL
|
|
if(!m_bThermal)
|
|
{
|
|
ev_thermal = FALSE;
|
|
CenterPrint("Thermal vision deactivated");
|
|
V_StopSway();
|
|
V_DisableFade();
|
|
}
|
|
else
|
|
{
|
|
CenterPrint("Thermal vision activated");
|
|
}
|
|
#endif
|
|
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.5f;
|
|
}
|
|
|
|
void CG11::ItemPostFrame()
|
|
{
|
|
if(m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() && m_bActivateThermal)
|
|
{
|
|
m_bActivateThermal = FALSE;
|
|
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 70;
|
|
|
|
#ifdef CLIENT_DLL
|
|
ev_thermal = TRUE;
|
|
ClientSway();
|
|
#endif
|
|
}
|
|
|
|
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) && m_bThermal)
|
|
{
|
|
m_bThermal = !m_bThermal;
|
|
|
|
SpecialMode();
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase();
|
|
}
|
|
|
|
CAutomatic::ItemPostFrame();
|
|
}
|
|
|
|
void CG11::ClientSway()
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
// Ducking
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
V_SetSway(1.0);
|
|
// On Ground
|
|
else if(m_pPlayer->pev->flags & FL_ONGROUND)
|
|
V_SetSway(2.25);
|
|
// Jumping
|
|
else
|
|
V_SetSway(4.5);
|
|
#endif
|
|
}
|
|
|
|
void CG11::Reload()
|
|
{
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
if(m_bThermal)
|
|
{
|
|
SpecialMode();
|
|
m_bThermal = TRUE; // reset to true so when reload is done we go back to zoom
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint(""); // Hack so player wont see center print text
|
|
#endif
|
|
}
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation(PLAYER_RELOAD);
|
|
|
|
if(DefaultReload(m_iClipSize,G11_RELOAD,5.23f))
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
|
|
BOOL CG11::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_g11.mdl","models/p_g11.mdl",G11_DRAW,"g11"))
|
|
return FALSE;
|
|
m_iAllowFire = TRUE;
|
|
|
|
int retval = CAutomatic::Deploy();
|
|
if(retval)
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.8f;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void CG11::Holster(int skiplocal)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
V_StopSway();
|
|
V_DisableFade();
|
|
#endif
|
|
|
|
m_bThermal = FALSE;
|
|
m_bActivateThermal = FALSE;
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
|
|
|
|
CWasteWeapon::Holster(skiplocal);
|
|
}
|
|
|
|
BOOL CG11::PlayEmptySound()
|
|
{
|
|
if(m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CG11Ammo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_g11.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CG11Ammo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_g11.mdl");
|
|
}
|
|
|
|
BOOL CG11Ammo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo(AMMO_GIVE_G11,"4.7mm Caseless",AMMO_MAX_G11) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
Bolt Rifle - Now u see him, now u dont!
|
|
*************/
|
|
// I know this isnt an automatic, but its probably the best section to put it in for now.
|
|
|
|
enum boltrifle_state_e {
|
|
BR_NOZOOM,
|
|
BR_ZOOM_2X,
|
|
BR_ZOOM_4X,
|
|
BR_ZOOM_6X,
|
|
};
|
|
|
|
#define BR_FOV_2X 45
|
|
#define BR_FOV_4X 23
|
|
#define BR_FOV_6X 11
|
|
|
|
void CBoltRifle::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_boltrifle");
|
|
|
|
m_iBulletType = BULLET_762MM;
|
|
m_iId = WEAPON_BOLTRIFLE;
|
|
m_iDefaultAmmo = AMMO_GIVE_BOLTRIFLE;
|
|
m_iClipSize = CLIP_BOLTRIFLE;
|
|
m_iAllowFire = TRUE;
|
|
|
|
m_iState = BR_NOZOOM;
|
|
m_bReZoom = FALSE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_boltrifle.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CBoltRifle::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_boltrifle.mdl");
|
|
PRECACHE_MODEL("models/p_boltrifle.mdl");
|
|
PRECACHE_MODEL("models/w_boltrifle.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_762mm_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_762mm_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/boltrifle_fire1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/boltrifle.sc");
|
|
}
|
|
|
|
int CBoltRifle::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 2;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "BoltRifle Ammo";
|
|
p->iMaxAmmo1 = AMMO_MAX_BOLTRIFLE;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = CLIP_BOLTRIFLE;
|
|
|
|
p->iPosition = iItemSlot() - 1;
|
|
|
|
p->iId = m_iId = WEAPON_BOLTRIFLE;
|
|
p->iWeight = WEIGHT_BOLTRIFLE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CBoltRifle::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
}
|
|
|
|
void CBoltRifle::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iState = local_data->m_iWeaponState;
|
|
#endif
|
|
}
|
|
|
|
float CBoltRifle::flGetTiltedDamage()
|
|
{
|
|
float fRet = RANDOM_FLOAT(90,100);
|
|
|
|
// 10% accuracy loss if unzoomed and/or moving
|
|
if(m_iState == BR_NOZOOM || m_pPlayer->pev->velocity != Vector(0,0,0))
|
|
fRet *= 0.9f;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
const char *CBoltRifle::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_BOLTRIFLE_1 : DEATH_BOLTRIFLE_2;
|
|
}
|
|
|
|
void CBoltRifle::ItemPostFrame()
|
|
{
|
|
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) )
|
|
{
|
|
// complete the reload.
|
|
int j = Q_min( iMaxClip(), m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
m_iClip = 0;
|
|
|
|
// Add them to the clip
|
|
m_iClip += j;
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
|
|
|
|
#ifndef CLIENT_DLL
|
|
m_pPlayer->TabulateAmmo();
|
|
#endif
|
|
m_fInReload = FALSE;
|
|
}
|
|
|
|
if(m_flNextPrimaryAttack <= UTIL_WeaponTimeBase() && m_bReZoom)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
ClientSway();
|
|
#endif
|
|
|
|
switch(m_iState)
|
|
{
|
|
// ZOOM ZOOM ZOOM!
|
|
case BR_ZOOM_2X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_2X;
|
|
break;
|
|
case BR_ZOOM_4X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_4X;
|
|
break;
|
|
case BR_ZOOM_6X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_6X;
|
|
break;
|
|
}
|
|
|
|
m_bReZoom = FALSE;
|
|
}
|
|
|
|
CWasteWeapon::ItemPostFrame();
|
|
|
|
// Set allow fire mode
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
|
|
void CBoltRifle::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(m_iClip <= 0)
|
|
{
|
|
if(m_fFireOnEmpty)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
// SendWeaponAnim(BOLTRIFLE_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
float spread;
|
|
|
|
// Accuracy modifier
|
|
if(m_iState == BR_NOZOOM || m_pPlayer->pev->velocity != Vector(0,0,0))
|
|
spread = 0.08f;
|
|
else
|
|
spread = 0.0001f;
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
if(m_iState != BR_NOZOOM && m_iClip)
|
|
m_bReZoom = TRUE;
|
|
|
|
if( m_iClip < 1 )
|
|
m_iState = BR_NOZOOM;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir;
|
|
|
|
Vector Spread = Vector(spread,spread,spread);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, Spread, 8192,BULLET_762MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_BOLTRIFLE);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
dir.x,
|
|
dir.y,
|
|
(m_iClip == 0) ? 1 : 0,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
// get out of zoom
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
|
|
#ifdef CLIENT_DLL
|
|
V_StopSway();
|
|
V_DisableFade();
|
|
#endif
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.4f;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
void CBoltRifle::SecondaryAttack()
|
|
{
|
|
if(!m_iAllowFire || m_iState != BR_NOZOOM)
|
|
return;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
#ifndef CLIENT_DLL
|
|
// Attack something
|
|
TraceResult tr;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition();
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;
|
|
|
|
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
|
|
|
|
if ( tr.flFraction >= 1.0 )
|
|
{
|
|
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr );
|
|
if ( tr.flFraction < 1.0 )
|
|
{
|
|
// Calculate the point of intersection of the line (or hull) and the object we hit
|
|
// This is and approximation of the "best" intersection
|
|
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
|
|
if ( !pHit || pHit->IsBSPModel() )
|
|
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
|
|
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
|
|
}
|
|
}
|
|
|
|
// hit
|
|
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
|
|
|
|
ClearMultiDamage( );
|
|
|
|
// first swing does full damage TODO FIX
|
|
pEntity->TraceAttack(m_pPlayer->pev, BOLTRIFLE_DMG_WHIP , gpGlobals->v_forward, &tr, DMG_CLUB|DMG_NEVERGIB );
|
|
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
|
|
|
|
if (pEntity)
|
|
{
|
|
if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE )
|
|
{
|
|
// play thwack or smack sound
|
|
switch( RANDOM_LONG(0,2) )
|
|
{
|
|
case 0:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
|
|
case 1:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
|
|
case 2:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
|
|
}
|
|
m_pPlayer->m_iWeaponVolume = 128;
|
|
}
|
|
|
|
if( pEntity->IsPlayer() )
|
|
{
|
|
// Kickback from rifle
|
|
float flZVel = pEntity->pev->velocity.z;
|
|
pEntity->pev->velocity = pEntity->pev->velocity + gpGlobals->v_forward * 225.0f;
|
|
pEntity->pev->velocity.z = flZVel;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,
|
|
0.0,
|
|
0,
|
|
0,
|
|
1, // Whip boolean
|
|
0);
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.25;
|
|
}
|
|
|
|
void CBoltRifle::SpecialMode()
|
|
{
|
|
if(!m_iAllowFire || !m_iClip)
|
|
return;
|
|
|
|
m_iState ++;
|
|
|
|
if(m_iState > BR_ZOOM_6X)
|
|
{
|
|
m_iState = BR_NOZOOM;
|
|
#ifdef CLIENT_DLL
|
|
V_StopSway();
|
|
V_DisableFade();
|
|
#endif
|
|
}
|
|
#ifdef CLIENT_DLL
|
|
else
|
|
ClientSway();
|
|
#endif
|
|
|
|
switch(m_iState)
|
|
{
|
|
case BR_NOZOOM:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
|
|
break;
|
|
// ZOOM ZOOM ZOOM!
|
|
case BR_ZOOM_2X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_2X;
|
|
break;
|
|
case BR_ZOOM_4X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_4X;
|
|
break;
|
|
case BR_ZOOM_6X:
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = BR_FOV_6X;
|
|
break;
|
|
}
|
|
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.25f;
|
|
m_iAllowFire = FALSE;
|
|
}
|
|
|
|
void CBoltRifle::ClientSway()
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
// Ducking
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
V_SetSway(1.0);
|
|
// On Ground
|
|
else if(m_pPlayer->pev->flags & FL_ONGROUND)
|
|
V_SetSway(2.25);
|
|
// Jumping
|
|
else
|
|
V_SetSway(4.5);
|
|
#endif
|
|
}
|
|
|
|
void CBoltRifle::Reload()
|
|
{
|
|
if(m_flNextPrimaryAttack > 0.0 || m_flNextSecondaryAttack > 0.0)
|
|
return;
|
|
|
|
int iResult;
|
|
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation( PLAYER_RELOAD );
|
|
|
|
if(m_iClip == 0)
|
|
iResult = DefaultReload(m_iClipSize,BOLTRIFLE_RELOAD_EMPTY,2.44f);
|
|
else
|
|
iResult = DefaultReload( m_iClipSize, BOLTRIFLE_RELOAD, 2.0f );
|
|
|
|
if(iResult)
|
|
{
|
|
if(m_iState != BR_NOZOOM)
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->m_flNextAttack;
|
|
m_bReZoom = TRUE;
|
|
}
|
|
|
|
// m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.75f;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
}
|
|
|
|
BOOL CBoltRifle::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_boltrifle.mdl","models/p_boltrifle.mdl",BOLTRIFLE_DRAW,"boltrifle"))
|
|
return FALSE;
|
|
|
|
return CWasteWeapon::Deploy();
|
|
}
|
|
|
|
void CBoltRifle::Holster(int skiplocal)
|
|
{
|
|
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
|
|
m_iState = BR_NOZOOM;
|
|
|
|
#ifdef CLIENT_DLL
|
|
V_DisableFade();
|
|
V_StopSway();
|
|
#endif
|
|
|
|
CWasteWeapon::Holster(skiplocal);
|
|
}
|
|
|
|
BOOL CBoltRifle::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CBoltRifleAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_boltrifle.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CBoltRifleAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_boltrifle.mdl");
|
|
}
|
|
|
|
BOOL CBoltRifleAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo(AMMO_GIVE_BOLTRIFLE,"BoltRifle Ammo",AMMO_MAX_BOLTRIFLE) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
Sten Gun - New meaning to Old Skewl
|
|
*************/
|
|
enum sten_state_e {
|
|
STEN_SILENCER_ON = 0,
|
|
STEN_SILENCER_OFF,
|
|
};
|
|
|
|
#define STEN_CRITICAL_LEVEL 1.35 // Time in seconds a silenced sten can sustain full auto
|
|
|
|
void CSten::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_sten");
|
|
|
|
m_iBulletType = BULLET_9MMP;
|
|
m_iId = WEAPON_STEN;
|
|
m_iDefaultAmmo = AMMO_GIVE_STEN;
|
|
m_iClipSize = CLIP_STEN;
|
|
|
|
m_iState = STEN_SILENCER_OFF;
|
|
pev->fuser1 = 0.0f;
|
|
|
|
m_iAllowFire = 1;
|
|
m_bOverheated = FALSE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_sten.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CSten::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_sten.mdl");
|
|
PRECACHE_MODEL("models/p_sten.mdl");
|
|
PRECACHE_MODEL("models/w_sten.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_9x22mm_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_9x22mm_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/sten_nfire1.wav");
|
|
PRECACHE_SOUND("weapons/sten_nfire2.wav");
|
|
PRECACHE_SOUND("weapons/sten_sfire1.wav");
|
|
PRECACHE_SOUND("weapons/sten_sfire2.wav");
|
|
PRECACHE_SOUND("weapons/sten_overheat.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/sten.sc");
|
|
}
|
|
|
|
int CSten::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 2;
|
|
// p->iSlot = 4;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "Sten Ammo";
|
|
p->iMaxAmmo1 = AMMO_MAX_STEN;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = CLIP_STEN;
|
|
|
|
p->iPosition = iItemSlot() - 1;
|
|
|
|
p->iId = m_iId = WEAPON_STEN;
|
|
p->iWeight = WEIGHT_STEN;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CSten::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
local_data->iuser3 = m_bOverheated;
|
|
}
|
|
|
|
void CSten::UnpackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iState = local_data->m_iWeaponState;
|
|
m_bOverheated = local_data->iuser3;
|
|
}
|
|
|
|
float CSten::flGetTiltedDamage()
|
|
{
|
|
float fRet = RANDOM_FLOAT(25,35);
|
|
|
|
if( m_iState == STEN_SILENCER_ON )
|
|
fRet *= 0.9f;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
const char *CSten::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_STEN_1 : DEATH_STEN_2;
|
|
}
|
|
|
|
void CSten::ItemPostFrame()
|
|
{
|
|
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) )
|
|
{
|
|
// complete the reload.
|
|
int j = Q_min( iMaxClip(), m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
m_iClip = 0;
|
|
|
|
// Add them to the clip
|
|
m_iClip += j;
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
|
|
|
|
#ifndef CLIENT_DLL
|
|
m_pPlayer->TabulateAmmo();
|
|
#endif
|
|
m_fInReload = FALSE;
|
|
}
|
|
|
|
CWasteWeapon::ItemPostFrame();
|
|
|
|
if(pev->fuser1 <= UTIL_WeaponTimeBase())
|
|
{
|
|
m_bOverheated = FALSE;
|
|
|
|
// Set allow fire mode
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
}
|
|
|
|
void CSten::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire)
|
|
return;
|
|
|
|
if(pev->fuser1 > UTIL_WeaponTimeBase() + STEN_CRITICAL_LEVEL && !m_bOverheated)
|
|
{
|
|
// TODO: perhaps a cool animation? :D
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = pev->fuser1 * 2; // Takes twice as long to cool off :)
|
|
m_bOverheated = TRUE;
|
|
m_iAllowFire = FALSE;
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,
|
|
0.0,
|
|
0,
|
|
0,
|
|
0,
|
|
1); // overheat sound
|
|
|
|
return;
|
|
}
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(m_iClip <= 0)
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.4;
|
|
SendWeaponAnim((m_iState == STEN_SILENCER_ON) ? STEN_SHOOT_EMPTY_SILENCED : STEN_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
return;
|
|
}
|
|
|
|
float spread = 0.075f;
|
|
float rof = 0.1f;
|
|
|
|
// Silencer adds a very slight amount of accuracy
|
|
if(m_iState == STEN_SILENCER_ON)
|
|
spread *= 1.15;
|
|
|
|
m_iClip--;
|
|
|
|
if(m_iState == STEN_SILENCER_OFF)
|
|
{
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
pev->fuser1 += UTIL_WeaponTimeBase() + 0.09f; // unsilenced takes a bit longer
|
|
}
|
|
else
|
|
pev->fuser1 += UTIL_WeaponTimeBase() + 0.25f;
|
|
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector dir;
|
|
|
|
Vector Spread;
|
|
|
|
// Accuracy modifiers
|
|
if(m_pPlayer->pev->flags & FL_DUCKING)
|
|
Spread = Vector(spread*0.75,spread*0.75,spread*0.75);
|
|
else if(m_pPlayer->pev->flags & FL_ONGROUND)
|
|
Spread = Vector(spread,spread,spread);
|
|
else
|
|
Spread = Vector(spread*2.4,spread*2.4,spread*2.4);
|
|
|
|
dir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, Spread, 8192, BULLET_9MMP, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_STEN);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
dir.x,
|
|
dir.y,
|
|
0,
|
|
0,
|
|
(m_iState == STEN_SILENCER_ON) ? 1 : 0,
|
|
0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + rof;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
void CSten::SecondaryAttack()
|
|
{
|
|
m_iState = !m_iState;
|
|
|
|
switch(m_iState)
|
|
{
|
|
case STEN_SILENCER_ON:
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint("Adding Silencer");
|
|
#endif
|
|
SendWeaponAnim(STEN_ADDSILENCER,UseDecrement() ? 1 : 0);
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.5f;
|
|
break;
|
|
case STEN_SILENCER_OFF:
|
|
if(!(pev->fuser1 > UTIL_WeaponTimeBase()))
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
CenterPrint("Removing Silencer");
|
|
#endif
|
|
SendWeaponAnim(STEN_REMSILENCER,UseDecrement() ? 1 : 0);
|
|
m_pPlayer->m_flNextAttack = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.5f;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CSten::Reload()
|
|
{
|
|
if(m_flNextPrimaryAttack > 0.0 || m_flNextSecondaryAttack > 0.0)
|
|
return;
|
|
|
|
int iResult;
|
|
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation( PLAYER_RELOAD );
|
|
|
|
iResult = DefaultReload(m_iClipSize,(m_iState == STEN_SILENCER_ON) ? STEN_RELOAD_SILENCED : STEN_RELOAD, 3.15f );
|
|
|
|
if(iResult)
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
|
|
BOOL CSten::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_sten.mdl","models/p_sten.mdl",(m_iState == STEN_SILENCER_ON) ? STEN_DRAW_SILENCED : STEN_DRAW,"sten"))
|
|
return FALSE;
|
|
|
|
return CWasteWeapon::Deploy();
|
|
}
|
|
|
|
BOOL CSten::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CStenAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_sten.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CStenAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_sten.mdl");
|
|
}
|
|
|
|
BOOL CStenAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo(AMMO_GIVE_STEN,"Sten Ammo",AMMO_MAX_STEN) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|