halflife-thewastes-sdk/dlls/wpn_shared/tw_automatics.cpp

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;
}