forked from valve/halflife-sdk
1066 lines
25 KiB
C++
1066 lines
25 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(ammo_buckshot,CShotgunAmmo);
|
|
LINK_ENTITY_TO_CLASS(ammo_winchester,CWinchesterAmmo);
|
|
LINK_ENTITY_TO_CLASS(ammo_jackhammer,CJackHammerAmmo);
|
|
|
|
LINK_ENTITY_TO_CLASS(weapon_sawedoff,CSawedOff);
|
|
LINK_ENTITY_TO_CLASS(weapon_mossberg,CMossberg);
|
|
LINK_ENTITY_TO_CLASS(weapon_winchester,CWinchester);
|
|
LINK_ENTITY_TO_CLASS(weapon_jackhammer,CJackHammer);
|
|
|
|
#define SHOTGUN_SHOOT_STATE 1
|
|
#define SHOTGUN_RELOAD_STATE 2
|
|
|
|
enum reload_state_e
|
|
{
|
|
RELOAD_NONE,
|
|
RELOAD_START,
|
|
RELOAD_END,
|
|
};
|
|
|
|
/*************
|
|
Shotgun
|
|
*************/
|
|
int CShotgun::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 2;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "Buckshot";
|
|
p->iMaxAmmo1 = AMMO_MAX_BUCKSHOT;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CShotgun::ItemPostFrame()
|
|
{
|
|
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) )
|
|
{
|
|
// complete the reload.
|
|
int j = min( 1, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
// 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();
|
|
|
|
// Set allow fire mode
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
m_iAllowFire = TRUE;
|
|
|
|
// Handle reloads if needed
|
|
//#ifndef CLIENT_DLL
|
|
if(m_iState == SHOTGUN_RELOAD_STATE && m_flNextPrimaryAttack <= UTIL_WeaponTimeBase())
|
|
{
|
|
switch(m_iReloadState)
|
|
{
|
|
case RELOAD_START:
|
|
Reload();
|
|
|
|
// User must hold down button to reload.
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
m_iReloadState = RELOAD_END;
|
|
break;
|
|
case RELOAD_END:
|
|
Reload();
|
|
break;
|
|
}
|
|
}
|
|
//#endif
|
|
}
|
|
|
|
void CShotgun::WeaponIdle()
|
|
{
|
|
ResetEmptySound();
|
|
}
|
|
|
|
void CShotgun::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
}
|
|
|
|
void CShotgun::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iState = local_data->m_iWeaponState;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CShotgunAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_buckshot.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CShotgunAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_buckshot.mdl");
|
|
}
|
|
|
|
BOOL CShotgunAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo( AMMO_GIVE_BUCKSHOT, "Buckshot", AMMO_MAX_BUCKSHOT) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
Mossberg 12 Gauge
|
|
*************/
|
|
void CMossberg::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_mossberg");
|
|
|
|
m_iBulletType = BULLET_12GAUGE;
|
|
m_iId = WEAPON_MOSSBERG;
|
|
m_iDefaultAmmo = AMMO_GIVE_BUCKSHOT;
|
|
m_iClipSize = CLIP_MOSSBERG;
|
|
|
|
m_iAllowFire = TRUE;
|
|
m_iState = SHOTGUN_SHOOT_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_mossberg.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CMossberg::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_mossberg.mdl");
|
|
PRECACHE_MODEL("models/p_mossberg.mdl");
|
|
PRECACHE_MODEL("models/w_mossberg.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/mossberg_draw.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_fire_empty.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_fire1.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_fire2.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_holster.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_pump.wav");
|
|
PRECACHE_SOUND("weapons/mossberg_reload.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/mossberg.sc");
|
|
}
|
|
|
|
int CMossberg::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_MOSSBERG;
|
|
|
|
p->iPosition = 0;
|
|
|
|
p->iId = m_iId = WEAPON_MOSSBERG;
|
|
p->iWeight = WEIGHT_MOSSBERG;
|
|
|
|
return CShotgun::GetItemInfo(p);
|
|
}
|
|
|
|
float CMossberg::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(14,19);
|
|
}
|
|
|
|
char *CMossberg::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_MOSSBERG_1 : DEATH_MOSSBERG_2;
|
|
}
|
|
|
|
void CMossberg::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire || m_iState == SHOTGUN_RELOAD_STATE)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(!m_iClip)
|
|
{
|
|
PlayEmptySound();
|
|
SendWeaponAnim(MOSSBERG_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3;
|
|
return;
|
|
}
|
|
|
|
int random_long = UTIL_SharedRandomLong(m_pPlayer->random_seed,0,1);
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecDir;
|
|
|
|
Vector vecSpread = Vector(MOSSBERG_SPREAD,MOSSBERG_SPREAD,MOSSBERG_SPREAD);
|
|
|
|
vecDir = m_pPlayer->FireBulletsPlayer(this,MOSSBERG_SHOTCOUNT, vecSrc, vecAiming, vecSpread, 1280, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );
|
|
|
|
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,
|
|
MOSSBERG_SPREAD,
|
|
MOSSBERG_SPREAD,
|
|
MOSSBERG_SHOTCOUNT*2,
|
|
1, // Shotgun blast
|
|
0,
|
|
random_long);
|
|
|
|
m_iAllowFire = FALSE;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 2, 4 ); // how long till we do this again.
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75f;
|
|
}
|
|
|
|
void CMossberg::SecondaryAttack()
|
|
{
|
|
if(!m_iAllowFire || m_iState == SHOTGUN_RELOAD_STATE)
|
|
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, MOSSBERG_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;
|
|
}
|
|
|
|
// Kickback from stock
|
|
if( pEntity->IsPlayer() )
|
|
{
|
|
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, // Stock whip
|
|
0,
|
|
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 CMossberg::Reload()
|
|
{
|
|
if(m_flNextPrimaryAttack > UTIL_WeaponTimeBase() || m_flNextSecondaryAttack > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
if(m_iState != SHOTGUN_RELOAD_STATE && (m_iClip == m_iClipSize || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0))
|
|
return;
|
|
|
|
if(m_iState != SHOTGUN_RELOAD_STATE)
|
|
{
|
|
m_iState = SHOTGUN_RELOAD_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
}
|
|
|
|
// if we're full, just go to the end.
|
|
if(m_iClipSize == m_iClip)
|
|
m_iReloadState = RELOAD_END;
|
|
|
|
switch(m_iReloadState)
|
|
{
|
|
case RELOAD_NONE:
|
|
SendWeaponAnim( MOSSBERG_GOTO_RELOAD, UseDecrement() ? 1 : 0 );
|
|
|
|
m_iReloadState = RELOAD_START;
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.6;
|
|
|
|
break;
|
|
case RELOAD_START:
|
|
if(DefaultReload( m_iClipSize,MOSSBERG_RELOAD, 0.45 ))
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.565;
|
|
EMIT_SOUND(ENT(m_pPlayer->pev),CHAN_WEAPON,"weapons/mossberg_reload.wav",0.8,ATTN_NORM);
|
|
|
|
break;
|
|
}
|
|
case RELOAD_END:
|
|
m_iState = SHOTGUN_SHOOT_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.825;
|
|
SendWeaponAnim( MOSSBERG_END_RELOAD, UseDecrement() ? 1 : 0 );
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 4,5 ); // how long till we do this again.break;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL CMossberg::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_mossberg.mdl","models/p_mossberg.mdl",MOSSBERG_DRAW,"mossberg"))
|
|
return FALSE;
|
|
|
|
return CShotgun::Deploy();
|
|
}
|
|
|
|
BOOL CMossberg::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CMossberg::WeaponIdle()
|
|
{
|
|
CShotgun::WeaponIdle();
|
|
|
|
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() || m_iState != SHOTGUN_SHOOT_STATE)
|
|
return;
|
|
|
|
SendWeaponAnim( (RANDOM_LONG(0,1) == 0)? MOSSBERG_IDLE2 : MOSSBERG_IDLE3, UseDecrement() ? 1 : 0 );
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
}
|
|
|
|
void CMossberg::Holster(int skiplocal)
|
|
{
|
|
CShotgun::Holster(skiplocal);
|
|
}
|
|
|
|
/*************
|
|
Winchester
|
|
*************/
|
|
void CWinchester::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_winchester");
|
|
|
|
m_iBulletType = BULLET_SLUG;
|
|
m_iId = WEAPON_WINCHESTER;
|
|
m_iDefaultAmmo = AMMO_GIVE_BUCKSHOT;
|
|
m_iClipSize = CLIP_WINCHESTER;
|
|
|
|
m_iState = SHOTGUN_SHOOT_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_winchester.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CWinchester::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_winchester.mdl");
|
|
PRECACHE_MODEL("models/p_winchester.mdl");
|
|
PRECACHE_MODEL("models/w_winchester.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_slug_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_slug_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/winchester_draw.wav");
|
|
PRECACHE_SOUND("weapons/winchester_fire_empty.wav");
|
|
PRECACHE_SOUND("weapons/winchester_fire1.wav");
|
|
PRECACHE_SOUND("weapons/winchester_fire2.wav");
|
|
PRECACHE_SOUND("weapons/winchester_pump.wav");
|
|
PRECACHE_SOUND("weapons/winchester_reload.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/winchester.sc");
|
|
}
|
|
|
|
int CWinchester::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iMaxClip = CLIP_WINCHESTER;
|
|
|
|
p->iPosition = 1;
|
|
|
|
p->iId = m_iId = WEAPON_WINCHESTER;
|
|
p->iWeight = WEIGHT_WINCHESTER;
|
|
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 2;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "WinchesterAmmo";
|
|
p->iMaxAmmo1 = AMMO_MAX_WINCHESTER;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
float CWinchester::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(75,85);
|
|
}
|
|
|
|
char *CWinchester::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_WINCHESTER_1 : DEATH_WINCHESTER_2;
|
|
}
|
|
|
|
|
|
void CWinchester::PrimaryAttack()
|
|
{
|
|
if(!m_iAllowFire || m_iState == SHOTGUN_RELOAD_STATE)
|
|
return;
|
|
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(!m_iClip)
|
|
{
|
|
PlayEmptySound();
|
|
// SendWeaponAnim(WINNY_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3;
|
|
return;
|
|
}
|
|
|
|
int iAnimations = UTIL_SharedRandomLong(m_pPlayer->random_seed,0,1);
|
|
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0f;
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
m_iClip--;
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecDir;
|
|
|
|
Vector vecSpread = Vector(WINCHESTER_SPREAD,WINCHESTER_SPREAD,WINCHESTER_SPREAD);
|
|
|
|
vecDir = m_pPlayer->FireBulletsPlayer(this,1, vecSrc, vecAiming, vecSpread, 8192, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_WINCHESTER );
|
|
|
|
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,
|
|
vecDir.x,
|
|
vecDir.y,
|
|
iAnimations,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
m_iAllowFire = FALSE;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 2, 4 ); // how long till we do this again.
|
|
}
|
|
|
|
void CWinchester::SecondaryAttack()
|
|
{
|
|
}
|
|
|
|
void CWinchester::Reload()
|
|
{
|
|
if(m_flNextPrimaryAttack > UTIL_WeaponTimeBase() || m_flNextSecondaryAttack > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
if(m_iState != SHOTGUN_RELOAD_STATE && (m_iClip == m_iClipSize || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0))
|
|
return;
|
|
|
|
if(m_iState != SHOTGUN_RELOAD_STATE)
|
|
{
|
|
m_iState = SHOTGUN_RELOAD_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
}
|
|
|
|
// if we're full, just go to the end.
|
|
if(m_iClipSize == m_iClip)
|
|
m_iReloadState = RELOAD_END;
|
|
|
|
switch(m_iReloadState)
|
|
{
|
|
case RELOAD_NONE:
|
|
SendWeaponAnim( WINNY_RELOAD_START, UseDecrement() ? 1 : 0 );
|
|
m_iReloadState = RELOAD_START;
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.7;
|
|
break;
|
|
case RELOAD_START:
|
|
if(DefaultReload( m_iClipSize,WINNY_RELOAD_MIDDLE, 0.525 ))
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.525;
|
|
EMIT_SOUND(ENT(m_pPlayer->pev),CHAN_WEAPON,"weapons/winchester_reload.wav",0.8,ATTN_NORM);
|
|
break;
|
|
}
|
|
case RELOAD_END:
|
|
m_iState = SHOTGUN_SHOOT_STATE;
|
|
m_iReloadState = RELOAD_NONE;
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.825;
|
|
SendWeaponAnim( WINNY_RELOAD_END, UseDecrement() ? 1 : 0 );
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 4,5 ); // how long till we do this again.break;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL CWinchester::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_winchester.mdl","models/p_winchester.mdl",WINNY_DRAW,"winchester"))
|
|
return FALSE;
|
|
|
|
return CShotgun::Deploy();
|
|
}
|
|
|
|
BOOL CWinchester::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CWinchesterAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_winchester.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CWinchesterAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_winchester.mdl");
|
|
}
|
|
|
|
BOOL CWinchesterAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo( AMMO_GIVE_WINCHESTER, "WinchesterAmmo", AMMO_MAX_WINCHESTER) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*************
|
|
Sawed Off Shotgun (Mad Max Babey!)
|
|
*************/
|
|
void CSawedOff::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_sawedoff");
|
|
|
|
m_iBulletType = BULLET_20GAUGE;
|
|
m_iId = WEAPON_SAWEDOFF;
|
|
m_iDefaultAmmo = AMMO_GIVE_BUCKSHOT;
|
|
m_iClipSize = CLIP_SAWEDOFF;
|
|
m_iAllowFire = TRUE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_sawedoff.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CSawedOff::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_sawedoff.mdl");
|
|
PRECACHE_MODEL("models/p_sawedoff.mdl");
|
|
PRECACHE_MODEL("models/w_sawedoff.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/sawedoff_draw.wav");
|
|
PRECACHE_SOUND("weapons/sawedoff_fire1.wav");
|
|
PRECACHE_SOUND("weapons/sawedoff_fire2.wav");
|
|
PRECACHE_SOUND("weapons/sawedoff_fire_empty.wav");
|
|
PRECACHE_SOUND("weapons/sawedoff_reload1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/sawedoff.sc");
|
|
}
|
|
|
|
int CSawedOff::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 1;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "Buckshot";
|
|
p->iMaxAmmo1 = AMMO_MAX_BUCKSHOT;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = CLIP_SAWEDOFF;
|
|
|
|
p->iPosition = 5;
|
|
|
|
p->iId = m_iId = WEAPON_SAWEDOFF;
|
|
p->iWeight = WEIGHT_SAWEDOFF;
|
|
|
|
return 1;
|
|
}
|
|
|
|
float CSawedOff::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT( 16, 19 );
|
|
}
|
|
|
|
char *CSawedOff::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_SAWEDOFF_1 : DEATH_SAWEDOFF_2;
|
|
}
|
|
|
|
void CSawedOff::ItemPostFrame()
|
|
{
|
|
CWasteWeapon::ItemPostFrame();
|
|
|
|
// Set allow fire mode
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
m_iAllowFire = TRUE;
|
|
}
|
|
|
|
void CSawedOff::FireShotgun(int barrels)
|
|
{
|
|
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)
|
|
{
|
|
SendWeaponAnim(SAWED_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3;
|
|
return;
|
|
}
|
|
else if(barrels == 2 && m_iClip == 1)
|
|
{
|
|
// If we dont have enough to go all out,
|
|
// settle for second best. :)
|
|
FireShotgun(1);
|
|
return;
|
|
}
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
|
|
|
if(barrels == 2)
|
|
m_iClip -= 2;
|
|
else
|
|
m_iClip--;
|
|
|
|
// OMG kickback!
|
|
#ifndef CLIENT_DLL
|
|
float flZVel = m_pPlayer->pev->velocity.z;
|
|
float kickback = (barrels == 1) ? 175 : 262.5;
|
|
|
|
m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * kickback;
|
|
|
|
// clamp the z velocity so people
|
|
// cant sawnoff jump with the gun :)
|
|
m_pPlayer->pev->velocity.z = flZVel;
|
|
#endif
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecDir;
|
|
|
|
int shotCount = (barrels == 1) ? 7 : 12;
|
|
float spread = (barrels == 1) ? 0.13 : 0.18;
|
|
|
|
Vector vecSpread = Vector(spread,spread,spread);
|
|
|
|
vecDir = m_pPlayer->FireBulletsPlayer(this, shotCount, vecSrc, vecAiming, vecSpread, 1280, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
spread,
|
|
spread,
|
|
barrels,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
m_iAllowFire = FALSE;
|
|
}
|
|
|
|
void CSawedOff::PrimaryAttack()
|
|
{
|
|
FireShotgun(1);
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.20;
|
|
}
|
|
|
|
void CSawedOff::SecondaryAttack()
|
|
{
|
|
FireShotgun(2);
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.50;
|
|
}
|
|
|
|
void CSawedOff::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, SAWED_RELOAD, 1.6f );
|
|
|
|
if(iResult)
|
|
{
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.6f;
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 );
|
|
}
|
|
}
|
|
|
|
BOOL CSawedOff::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_sawedoff.mdl","models/p_sawedoff.mdl",SAWED_DRAW,"sawedoff"))
|
|
return FALSE;
|
|
|
|
return CWasteWeapon::Deploy();
|
|
}
|
|
|
|
BOOL CSawedOff::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*************
|
|
Pancor Jackhammer
|
|
*************/
|
|
void CJackHammer::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_jackhammer");
|
|
|
|
m_iId = WEAPON_JACKHAMMER;
|
|
m_iDefaultAmmo = AMMO_GIVE_JACKHAMMER;
|
|
m_iClipSize = CLIP_JACKHAMMER;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_jackhammer.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CJackHammer::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_jackhammer.mdl");
|
|
PRECACHE_MODEL("models/p_jackhammer.mdl");
|
|
PRECACHE_MODEL("models/w_jackhammer.mdl");
|
|
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_lo.mdl");
|
|
PRECACHE_MODEL("models/shells/shell_buckshot_hi.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/jackhammer_fire1.wav");
|
|
PRECACHE_SOUND("weapons/jackhammer_fire2.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/jackhammer.sc");
|
|
}
|
|
|
|
int CJackHammer::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 3;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = "JackhammerAmmo";
|
|
p->iMaxAmmo1 = AMMO_MAX_JACKHAMMER;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = CLIP_JACKHAMMER;
|
|
|
|
p->iPosition = iItemSlot() - 1;
|
|
|
|
p->iId = m_iId = WEAPON_JACKHAMMER;
|
|
p->iWeight = WEIGHT_UNIQUE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
float CJackHammer::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_LONG(14,19);
|
|
}
|
|
|
|
char *CJackHammer::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_JACKHAMMER_1 : DEATH_JACKHAMMER_2;
|
|
}
|
|
|
|
void CJackHammer::PrimaryAttack()
|
|
{
|
|
// don't fire underwater
|
|
if (m_pPlayer->pev->waterlevel == 3)
|
|
{
|
|
PlayEmptySound( );
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
|
|
return;
|
|
}
|
|
|
|
if(!m_iClip)
|
|
{
|
|
// SendWeaponAnim(SAWED_SHOOT_EMPTY,UseDecrement() ? 1 : 0);
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.10;
|
|
return;
|
|
}
|
|
|
|
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
|
|
|
m_iClip--;
|
|
|
|
HALT_PLAYER(m_pPlayer,25,-1);
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition( );
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecDir;
|
|
|
|
float spread = MOSSBERG_SPREAD;
|
|
|
|
Vector vecSpread = Vector(spread,spread,spread);
|
|
|
|
vecDir = m_pPlayer->FireBulletsPlayer(this,MOSSBERG_SHOTCOUNT, vecSrc, vecAiming, vecSpread, 1280, BULLET_10GAUGE, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
spread,
|
|
spread,
|
|
MOSSBERG_SHOTCOUNT,
|
|
(m_pPlayer->pev->flags & FL_DUCKING), // is the player ducking or not
|
|
0,
|
|
0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.13;
|
|
}
|
|
|
|
void CJackHammer::SecondaryAttack()
|
|
{
|
|
}
|
|
|
|
void CJackHammer::Reload()
|
|
{
|
|
if(m_flNextPrimaryAttack > 0.0 || m_flNextSecondaryAttack > 0.0)
|
|
return;
|
|
|
|
// See if we need to reload
|
|
if(m_iClip == m_iClipSize)
|
|
return;
|
|
|
|
// player "reload" animation
|
|
m_pPlayer->SetAnimation( PLAYER_RELOAD );
|
|
|
|
int iResult = DefaultReload( m_iClipSize, JACKHAMMER_RELOAD, 3.34f );
|
|
}
|
|
|
|
BOOL CJackHammer::Deploy()
|
|
{
|
|
if(!DefaultDeploy("models/v_jackhammer.mdl","models/p_jackhammer.mdl",JACKHAMMER_DRAW,"jackhammer"))
|
|
return FALSE;
|
|
return CWasteWeapon::Deploy();
|
|
}
|
|
|
|
BOOL CJackHammer::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ammo Box
|
|
//
|
|
void CJackHammerAmmo::Spawn()
|
|
{
|
|
Precache();
|
|
SET_MODEL(ENT(pev),"models/ammo_jackhammer.mdl");
|
|
CWasteAmmo::Spawn();
|
|
}
|
|
|
|
void CJackHammerAmmo::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/ammo_jackhammer.mdl");
|
|
}
|
|
|
|
BOOL CJackHammerAmmo::AddAmmo(CBaseEntity *pOther)
|
|
{
|
|
if(pOther->GiveAmmo( AMMO_GIVE_JACKHAMMER, "JackhammerAmmo", AMMO_MAX_JACKHAMMER) != -1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|