/***
*
* Copyright ( c ) 1996 - 2002 , Valve LLC . All rights reserved .
*
* This product contains software technology licensed from Id
* Software , Inc . ( " Id Technology " ) . Id Technology ( c ) 1996 Id Software , Inc .
* 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
* Valve LLC . All other use , distribution , or modification is prohibited
* without written permission from Valve LLC .
*
* * * */
/*
= = = = = weapons . cpp = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
functions governing the selection / use of weapons for players
*/
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "player.h"
# include "monsters.h"
# include "weapons.h"
# include "nodes.h"
# include "soundent.h"
# include "decals.h"
# include "gamerules.h"
extern CGraph WorldGraph ;
extern int gEvilImpulse101 ;
# define NOT_USED 255
DLL_GLOBAL short g_sModelIndexLaser ; // holds the index for the laser beam
DLL_GLOBAL const char * g_pModelNameLaser = " sprites/laserbeam.spr " ;
DLL_GLOBAL short g_sModelIndexLaserDot ; // holds the index for the laser beam dot
DLL_GLOBAL short g_sModelIndexFireball ; // holds the index for the fireball
DLL_GLOBAL short g_sModelIndexSmoke ; // holds the index for the smoke cloud
DLL_GLOBAL short g_sModelIndexWExplosion ; // holds the index for the underwater explosion
DLL_GLOBAL short g_sModelIndexBubbles ; // holds the index for the bubbles model
DLL_GLOBAL short g_sModelIndexBloodDrop ; // holds the sprite index for the initial blood
DLL_GLOBAL short g_sModelIndexBloodSpray ; // holds the sprite index for splattered blood
//modif de Julien
DLL_GLOBAL short g_sModelIndexBlastCircle ; // sprite de l'onde de choc
ItemInfo CBasePlayerItem : : ItemInfoArray [ MAX_WEAPONS ] ;
AmmoInfo CBasePlayerItem : : AmmoInfoArray [ MAX_AMMO_SLOTS ] ;
extern int gmsgCurWeapon ;
MULTIDAMAGE gMultiDamage ;
# define TRACER_FREQ 4 // Tracers fire every fourth bullet
//=========================================================
// MaxAmmoCarry - pass in a name and this function will tell
// you the maximum amount of that type of ammunition that a
// player can carry.
//=========================================================
int MaxAmmoCarry ( int iszName )
{
for ( int i = 0 ; i < MAX_WEAPONS ; i + + )
{
if ( CBasePlayerItem : : ItemInfoArray [ i ] . pszAmmo1 & & ! strcmp ( STRING ( iszName ) , CBasePlayerItem : : ItemInfoArray [ i ] . pszAmmo1 ) )
return CBasePlayerItem : : ItemInfoArray [ i ] . iMaxAmmo1 ;
if ( CBasePlayerItem : : ItemInfoArray [ i ] . pszAmmo2 & & ! strcmp ( STRING ( iszName ) , CBasePlayerItem : : ItemInfoArray [ i ] . pszAmmo2 ) )
return CBasePlayerItem : : ItemInfoArray [ i ] . iMaxAmmo2 ;
}
ALERT ( at_console , " MaxAmmoCarry() doesn't recognize '%s'! \n " , STRING ( iszName ) ) ;
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
MULTI - DAMAGE
Collects multiple small damages into a single damage
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//
// ClearMultiDamage - resets the global multi damage accumulator
//
void ClearMultiDamage ( void )
{
gMultiDamage . pEntity = NULL ;
gMultiDamage . amount = 0 ;
gMultiDamage . type = 0 ;
}
//
// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity
//
// GLOBALS USED:
// gMultiDamage
void ApplyMultiDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker )
{
Vector vecSpot1 ; //where blood comes from
Vector vecDir ; //direction blood should go
TraceResult tr ;
if ( ! gMultiDamage . pEntity )
return ;
gMultiDamage . pEntity - > TakeDamage ( pevInflictor , pevAttacker , gMultiDamage . amount , gMultiDamage . type ) ;
}
// GLOBALS USED:
// gMultiDamage
void AddMultiDamage ( entvars_t * pevInflictor , CBaseEntity * pEntity , float flDamage , int bitsDamageType )
{
if ( ! pEntity )
return ;
gMultiDamage . type | = bitsDamageType ;
if ( pEntity ! = gMultiDamage . pEntity )
{
ApplyMultiDamage ( pevInflictor , pevInflictor ) ; // UNDONE: wrong attacker!
gMultiDamage . pEntity = pEntity ;
gMultiDamage . amount = 0 ;
}
gMultiDamage . amount + = flDamage ;
}
/*
= = = = = = = = = = = = = = = =
SpawnBlood
= = = = = = = = = = = = = = = =
*/
void SpawnBlood ( Vector vecSpot , int bloodColor , float flDamage )
{
UTIL_BloodDrips ( vecSpot , g_vecAttackDir , bloodColor , ( int ) flDamage ) ;
}
int DamageDecal ( CBaseEntity * pEntity , int bitsDamageType )
{
if ( ! pEntity )
return ( DECAL_GUNSHOT1 + RANDOM_LONG ( 0 , 4 ) ) ;
return pEntity - > DamageDecal ( bitsDamageType ) ;
}
void DecalGunshot ( TraceResult * pTrace , int iBulletType )
{
// Is the entity valid
if ( ! UTIL_IsValidEntity ( pTrace - > pHit ) )
return ;
if ( VARS ( pTrace - > pHit ) - > solid = = SOLID_BSP | | VARS ( pTrace - > pHit ) - > movetype = = MOVETYPE_PUSHSTEP )
{
CBaseEntity * pEntity = NULL ;
// Decal the wall with a gunshot
if ( ! FNullEnt ( pTrace - > pHit ) )
pEntity = CBaseEntity : : Instance ( pTrace - > pHit ) ;
switch ( iBulletType )
{
case BULLET_PLAYER_9MM :
case BULLET_MONSTER_9MM :
case BULLET_PLAYER_MP5 :
case BULLET_MONSTER_MP5 :
case BULLET_PLAYER_BUCKSHOT :
case BULLET_PLAYER_BUCKSHOT_DOUBLE :
case BULLET_PLAYER_357 :
// modif. de Julien
case BULLET_PLAYER_M16 :
case BULLET_PLAYER_SNIPER :
case BULLET_PLAYER_IRGUN :
//fin modif.
default :
// smoke and decal
UTIL_GunshotDecalTrace ( pTrace , DamageDecal ( pEntity , DMG_BULLET ) ) ;
break ;
case BULLET_MONSTER_12MM :
// smoke and decal
UTIL_GunshotDecalTrace ( pTrace , DamageDecal ( pEntity , DMG_BULLET ) ) ;
break ;
case BULLET_PLAYER_CROWBAR :
// wall decal
UTIL_DecalTrace ( pTrace , DamageDecal ( pEntity , DMG_CLUB ) ) ;
break ;
}
}
}
//
// modif de Julien
//
// Client Decal
// active le syst
extern int gmsgClientDecal ;
void ClientDecal ( TraceResult * pTrace , Vector vecSrc , Vector vecEnd , int crowbar = 0 )
{
// le worldspawn est compt
if ( ! UTIL_IsValidEntity ( pTrace - > pHit ) )
return ;
// entites brush-based seulement
if ( VARS ( pTrace - > pHit ) - > solid = = SOLID_BSP | | VARS ( pTrace - > pHit ) - > movetype = = MOVETYPE_PUSHSTEP )
{
// pas sur le tank
if ( FClassnameIs ( pTrace - > pHit , " vehicle_tank " ) )
return ;
// trouve la texture touchee
char chTextureType ;
char szbuffer [ 64 ] ;
const char * pTextureName ;
float rgfl1 [ 3 ] ;
float rgfl2 [ 3 ] ;
CBaseEntity * pEntity = CBaseEntity : : Instance ( pTrace - > pHit ) ;
chTextureType = 0 ;
vecSrc . CopyToArray ( rgfl1 ) ;
vecEnd . CopyToArray ( rgfl2 ) ;
if ( pEntity )
pTextureName = TRACE_TEXTURE ( ENT ( pEntity - > pev ) , rgfl1 , rgfl2 ) ;
else
pTextureName = TRACE_TEXTURE ( ENT ( 0 ) , rgfl1 , rgfl2 ) ;
// trouve texture
if ( pTextureName )
{
if ( * pTextureName = = ' - ' | | * pTextureName = = ' + ' )
pTextureName + = 2 ;
if ( * pTextureName = = ' { ' | | * pTextureName = = ' ! ' | | * pTextureName = = ' ~ ' | | * pTextureName = = ' ' )
pTextureName + + ;
strcpy ( szbuffer , pTextureName ) ;
szbuffer [ CBTEXTURENAMEMAX - 1 ] = 0 ;
chTextureType = TEXTURETYPE_Find ( szbuffer ) ;
int decal = 1 + crowbar ;
//message au client
MESSAGE_BEGIN ( MSG_ALL , gmsgClientDecal ) ;
WRITE_COORD ( pTrace - > vecEndPos . x ) ; // xyz source
WRITE_COORD ( pTrace - > vecEndPos . y ) ;
WRITE_COORD ( pTrace - > vecEndPos . z ) ;
WRITE_COORD ( pTrace - > vecPlaneNormal . x ) ; // xyz norme
WRITE_COORD ( pTrace - > vecPlaneNormal . y ) ;
WRITE_COORD ( pTrace - > vecPlaneNormal . z ) ;
WRITE_CHAR ( chTextureType ) ; // type de texture
WRITE_BYTE ( decal ) ; // decal ( 1 == oui ; 2 == crowbar ; 3 == crowbar ; 4 == electro-rocket )
MESSAGE_END ( ) ;
}
}
}
//
// EjectBrass - tosses a brass shell from passed origin at passed velocity
//
void EjectBrass ( const Vector & vecOrigin , const Vector & vecVelocity , float rotation , int model , int soundtype )
{
// FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see.
MESSAGE_BEGIN ( MSG_PVS , SVC_TEMPENTITY , vecOrigin ) ;
WRITE_BYTE ( TE_MODEL ) ;
WRITE_COORD ( vecOrigin . x ) ;
WRITE_COORD ( vecOrigin . y ) ;
WRITE_COORD ( vecOrigin . z ) ;
WRITE_COORD ( vecVelocity . x ) ;
WRITE_COORD ( vecVelocity . y ) ;
WRITE_COORD ( vecVelocity . z ) ;
WRITE_ANGLE ( rotation ) ;
WRITE_SHORT ( model ) ;
WRITE_BYTE ( soundtype ) ;
WRITE_BYTE ( 25 ) ; // 2.5 seconds
MESSAGE_END ( ) ;
}
#if 0
// UNDONE: This is no longer used?
void ExplodeModel ( const Vector & vecOrigin , float speed , int model , int count )
{
MESSAGE_BEGIN ( MSG_PVS , SVC_TEMPENTITY , vecOrigin ) ;
WRITE_BYTE ( TE_EXPLODEMODEL ) ;
WRITE_COORD ( vecOrigin . x ) ;
WRITE_COORD ( vecOrigin . y ) ;
WRITE_COORD ( vecOrigin . z ) ;
WRITE_COORD ( speed ) ;
WRITE_SHORT ( model ) ;
WRITE_SHORT ( count ) ;
WRITE_BYTE ( 15 ) ; // 1.5 seconds
MESSAGE_END ( ) ;
}
# endif
int giAmmoIndex = 0 ;
// Precaches the ammo and queues the ammo info for sending to clients
void AddAmmoNameToAmmoRegistry ( const char * szAmmoname )
{
// make sure it's not already in the registry
for ( int i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
{
if ( ! CBasePlayerItem : : AmmoInfoArray [ i ] . pszName )
continue ;
if ( stricmp ( CBasePlayerItem : : AmmoInfoArray [ i ] . pszName , szAmmoname ) = = 0 )
return ; // ammo already in registry, just quite
}
giAmmoIndex + + ;
ASSERT ( giAmmoIndex < MAX_AMMO_SLOTS ) ;
if ( giAmmoIndex > = MAX_AMMO_SLOTS )
giAmmoIndex = 0 ;
CBasePlayerItem : : AmmoInfoArray [ giAmmoIndex ] . pszName = szAmmoname ;
CBasePlayerItem : : AmmoInfoArray [ giAmmoIndex ] . iId = giAmmoIndex ; // yes, this info is redundant
}
// Precaches the weapon and queues the weapon info for sending to clients
void UTIL_PrecacheOtherWeapon ( const char * szClassname )
{
edict_t * pent ;
pent = CREATE_NAMED_ENTITY ( MAKE_STRING ( szClassname ) ) ;
if ( FNullEnt ( pent ) )
{
ALERT ( at_console , " NULL Ent in UTIL_PrecacheOtherWeapon \n " ) ;
return ;
}
CBaseEntity * pEntity = CBaseEntity : : Instance ( VARS ( pent ) ) ;
if ( pEntity )
{
ItemInfo II = { 0 } ;
pEntity - > Precache ( ) ;
if ( ( ( CBasePlayerItem * ) pEntity ) - > GetItemInfo ( & II ) )
{
CBasePlayerItem : : ItemInfoArray [ II . iId ] = II ;
if ( II . pszAmmo1 & & * II . pszAmmo1 )
{
AddAmmoNameToAmmoRegistry ( II . pszAmmo1 ) ;
}
if ( II . pszAmmo2 & & * II . pszAmmo2 )
{
AddAmmoNameToAmmoRegistry ( II . pszAmmo2 ) ;
}
}
}
REMOVE_ENTITY ( pent ) ;
}
// called by worldspawn
void W_Precache ( void )
{
memset ( CBasePlayerItem : : ItemInfoArray , 0 , sizeof ( CBasePlayerItem : : ItemInfoArray ) ) ;
memset ( CBasePlayerItem : : AmmoInfoArray , 0 , sizeof ( CBasePlayerItem : : AmmoInfoArray ) ) ;
giAmmoIndex = 0 ;
// custom items...
// common world objects
UTIL_PrecacheOther ( " item_suit " ) ;
UTIL_PrecacheOther ( " item_healthkit " ) ;
UTIL_PrecacheOther ( " item_battery " ) ;
UTIL_PrecacheOther ( " item_healthkit " ) ; // modif de Julien
UTIL_PrecacheOther ( " item_antidote " ) ;
UTIL_PrecacheOther ( " item_security " ) ;
UTIL_PrecacheOther ( " item_longjump " ) ;
// shotgun
UTIL_PrecacheOtherWeapon ( " weapon_shotgun " ) ;
UTIL_PrecacheOther ( " ammo_buckshot " ) ;
// crowbar
UTIL_PrecacheOtherWeapon ( " weapon_crowbar " ) ;
// glock
UTIL_PrecacheOtherWeapon ( " weapon_9mmhandgun " ) ;
UTIL_PrecacheOther ( " ammo_9mmclip " ) ;
// mp5
UTIL_PrecacheOtherWeapon ( " weapon_9mmAR " ) ;
UTIL_PrecacheOther ( " ammo_9mmAR " ) ;
UTIL_PrecacheOther ( " ammo_ARgrenades " ) ;
// modif. de Julien
//m16
UTIL_PrecacheOtherWeapon ( " weapon_m16 " ) ;
UTIL_PrecacheOther ( " ammo_m16 " ) ;
//fusil sniper
UTIL_PrecacheOtherWeapon ( " weapon_fsniper " ) ;
UTIL_PrecacheOther ( " ammo_fsniper " ) ;
// fusil infra rouge
UTIL_PrecacheOtherWeapon ( " weapon_irgun " ) ;
UTIL_PrecacheOther ( " ammo_irgun " ) ;
// grenade
UTIL_PrecacheOtherWeapon ( " weapon_fgrenade " ) ;
// lance flammes
UTIL_PrecacheOtherWeapon ( " weapon_lflammes " ) ;
UTIL_PrecacheOther ( " ammo_lflammes " ) ;
// supergun
UTIL_PrecacheOtherWeapon ( " weapon_supergun " ) ;
UTIL_PrecacheOther ( " ammo_supergun " ) ;
// briquet
UTIL_PrecacheOtherWeapon ( " weapon_briquet " ) ;
//fin modif.
// 9mm ammo box
UTIL_PrecacheOther ( " ammo_9mmbox " ) ;
# if !OEM_BUILD && !HLDEMO_BUILD
// python
UTIL_PrecacheOtherWeapon ( " weapon_357 " ) ;
UTIL_PrecacheOther ( " ammo_357 " ) ;
// gauss
UTIL_PrecacheOtherWeapon ( " weapon_gauss " ) ;
UTIL_PrecacheOther ( " ammo_gaussclip " ) ;
// rpg
UTIL_PrecacheOtherWeapon ( " weapon_rpg " ) ;
UTIL_PrecacheOther ( " ammo_rpgclip " ) ;
/*
// crossbow
UTIL_PrecacheOtherWeapon ( " weapon_crossbow " ) ;
UTIL_PrecacheOther ( " ammo_crossbow " ) ;
// egon
UTIL_PrecacheOtherWeapon ( " weapon_egon " ) ;
*/
# endif
// tripmine
UTIL_PrecacheOtherWeapon ( " weapon_tripmine " ) ;
# if !OEM_BUILD && !HLDEMO_BUILD
// satchel charge
UTIL_PrecacheOtherWeapon ( " weapon_satchel " ) ;
# endif
// hand grenade
UTIL_PrecacheOtherWeapon ( " weapon_handgrenade " ) ;
# if !OEM_BUILD && !HLDEMO_BUILD
/*
// squeak grenade
UTIL_PrecacheOtherWeapon ( " weapon_snark " ) ;
// hornetgun
UTIL_PrecacheOtherWeapon ( " weapon_hornetgun " ) ;
*/
if ( g_pGameRules - > IsDeathmatch ( ) )
{
UTIL_PrecacheOther ( " weaponbox " ) ; // container for dropped deathmatch weapons
}
# endif
g_sModelIndexFireball = PRECACHE_MODEL ( " sprites/zerogxplode.spr " ) ; // fireball
g_sModelIndexWExplosion = PRECACHE_MODEL ( " sprites/WXplo1.spr " ) ; // underwater fireball
g_sModelIndexSmoke = PRECACHE_MODEL ( " sprites/steam1.spr " ) ; // smoke
g_sModelIndexBubbles = PRECACHE_MODEL ( " sprites/bubble.spr " ) ; //bubbles
g_sModelIndexBloodSpray = PRECACHE_MODEL ( " sprites/bloodspray.spr " ) ; // initial blood
g_sModelIndexBloodDrop = PRECACHE_MODEL ( " sprites/blood.spr " ) ; // splattered blood
g_sModelIndexLaser = PRECACHE_MODEL ( g_pModelNameLaser ) ;
g_sModelIndexLaserDot = PRECACHE_MODEL ( " sprites/laserdot.spr " ) ;
//modif de Julien
g_sModelIndexBlastCircle = PRECACHE_MODEL ( " sprites/white.spr " ) ;
PRECACHE_MODEL ( " sprites/stmbal1.spr " ) ;
//modif de julien - particules pour le client
PRECACHE_MODEL ( " sprites/particules/particule_dirt01.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_dirt02.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_dirt03.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_dirt04.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_dirt05.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_dirt06.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass01.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass02.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass03.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass04.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass05.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_glass06.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal01.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal02.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal03.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal04.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal05.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_metal06.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood01.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood02.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood03.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood04.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood05.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_wood06.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete01.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete02.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete03.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete04.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete05.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_concrete06.spr " ) ;
PRECACHE_MODEL ( " sprites/particules/particule_xen.spr " ) ;
// modif de Julien - decals pour le client
PRECACHE_MODEL ( " sprites/decals/decal_metal01.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_metal02.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_metal03.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_dirt01.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_dirt02.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_dirt03.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_wood01.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_wood02.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_wood03.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_glass01.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_glass02.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_glass03.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_concrete01.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_concrete02.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_concrete03.spr " ) ;
PRECACHE_MODEL ( " sprites/decals/decal_crowbar01.spr " ) ;
// used by explosions
PRECACHE_MODEL ( " models/grenade.mdl " ) ;
PRECACHE_MODEL ( " sprites/explode1.spr " ) ;
PRECACHE_SOUND ( " weapons/debris1.wav " ) ; // explosion aftermaths
PRECACHE_SOUND ( " weapons/debris2.wav " ) ; // explosion aftermaths
PRECACHE_SOUND ( " weapons/debris3.wav " ) ; // explosion aftermaths
PRECACHE_SOUND ( " weapons/grenade_hit1.wav " ) ; //grenade
PRECACHE_SOUND ( " weapons/grenade_hit2.wav " ) ; //grenade
PRECACHE_SOUND ( " weapons/grenade_hit3.wav " ) ; //grenade
PRECACHE_SOUND ( " weapons/bullet_hit1.wav " ) ; // hit by bullet
PRECACHE_SOUND ( " weapons/bullet_hit2.wav " ) ; // hit by bullet
PRECACHE_SOUND ( " items/weapondrop1.wav " ) ; // weapon falls to the ground
PRECACHE_SOUND ( " sentences/blip.wav " ) ; // modif de Julien
PRECACHE_SOUND ( " buttons/blip2.wav " ) ; // modif de Julien
}
TYPEDESCRIPTION CBasePlayerItem : : m_SaveData [ ] =
{
DEFINE_FIELD ( CBasePlayerItem , m_pPlayer , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CBasePlayerItem , m_pNext , FIELD_CLASSPTR ) ,
//DEFINE_FIELD( CBasePlayerItem, m_fKnown, FIELD_INTEGER ),Reset to zero on load
DEFINE_FIELD ( CBasePlayerItem , m_iId , FIELD_INTEGER ) ,
// DEFINE_FIELD( CBasePlayerItem, m_iIdPrimary, FIELD_INTEGER ),
// DEFINE_FIELD( CBasePlayerItem, m_iIdSecondary, FIELD_INTEGER ),
} ;
IMPLEMENT_SAVERESTORE ( CBasePlayerItem , CBaseAnimating )
TYPEDESCRIPTION CBasePlayerWeapon : : m_SaveData [ ] = //modif de Julien, restore version from the previous SDK version
{
DEFINE_FIELD ( CBasePlayerWeapon , m_flNextPrimaryAttack , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_flNextSecondaryAttack , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_flTimeWeaponIdle , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_iPrimaryAmmoType , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_iSecondaryAmmoType , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_iClip , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayerWeapon , m_iDefaultAmmo , FIELD_INTEGER ) ,
// DEFINE_FIELD( CBasePlayerWeapon, m_iClientClip, FIELD_INTEGER ) , reset to zero on load so hud gets updated correctly
// DEFINE_FIELD( CBasePlayerWeapon, m_iClientWeaponState, FIELD_INTEGER ), reset to zero on load so hud gets updated correctly
} ;
IMPLEMENT_SAVERESTORE ( CBasePlayerWeapon , CBasePlayerItem )
void CBasePlayerItem : : SetObjectCollisionBox ( void )
{
pev - > absmin = pev - > origin + Vector ( - 24 , - 24 , 0 ) ;
pev - > absmax = pev - > origin + Vector ( 24 , 24 , 16 ) ;
}
//=========================================================
// Sets up movetype, size, solidtype for a new weapon.
//=========================================================
void CBasePlayerItem : : FallInit ( void )
{
pev - > movetype = MOVETYPE_TOSS ;
pev - > solid = SOLID_BBOX ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
UTIL_SetSize ( pev , Vector ( 0 , 0 , 0 ) , Vector ( 0 , 0 , 0 ) ) ; //pointsize until it lands on the ground.
SetTouch ( & CBasePlayerItem : : DefaultTouch ) ;
SetThink ( & CBasePlayerItem : : FallThink ) ;
pev - > nextthink = gpGlobals - > time + 0.1f ;
}
//=========================================================
// FallThink - Items that have just spawned run this think
// to catch them when they hit the ground. Once we're sure
// that the object is grounded, we change its solid type
// to trigger and set it in a large box that helps the
// player get it.
//=========================================================
void CBasePlayerItem : : FallThink ( void )
{
pev - > nextthink = gpGlobals - > time + 0.1f ;
if ( pev - > flags & FL_ONGROUND )
{
// clatter if we have an owner (i.e., dropped by someone)
// don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!)
if ( ! FNullEnt ( pev - > owner ) )
{
int pitch = 95 + RANDOM_LONG ( 0 , 29 ) ;
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_VOICE , " items/weapondrop1.wav " , 1 , ATTN_NORM , 0 , pitch ) ;
}
// lie flat
pev - > angles . x = 0 ;
pev - > angles . z = 0 ;
Materialize ( ) ;
}
}
//=========================================================
// Materialize - make a CBasePlayerItem visible and tangible
//=========================================================
void CBasePlayerItem : : Materialize ( void )
{
if ( pev - > effects & EF_NODRAW )
{
// changing from invisible state to visible.
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_WEAPON , " items/suitchargeok1.wav " , 1 , ATTN_NORM , 0 , 150 ) ;
pev - > effects & = ~ EF_NODRAW ;
pev - > effects | = EF_MUZZLEFLASH ;
}
pev - > solid = SOLID_TRIGGER ;
UTIL_SetOrigin ( pev , pev - > origin ) ; // link into world.
SetTouch ( & CBasePlayerItem : : DefaultTouch ) ;
SetThink ( NULL ) ;
}
//=========================================================
// AttemptToMaterialize - the item is trying to rematerialize,
// should it do so now or wait longer?
//=========================================================
void CBasePlayerItem : : AttemptToMaterialize ( void )
{
float time = g_pGameRules - > FlWeaponTryRespawn ( this ) ;
if ( time = = 0 )
{
Materialize ( ) ;
return ;
}
pev - > nextthink = gpGlobals - > time + time ;
}
//=========================================================
// CheckRespawn - a player is taking this weapon, should
// it respawn?
//=========================================================
void CBasePlayerItem : : CheckRespawn ( void )
{
switch ( g_pGameRules - > WeaponShouldRespawn ( this ) )
{
case GR_WEAPON_RESPAWN_YES :
Respawn ( ) ;
break ;
case GR_WEAPON_RESPAWN_NO :
return ;
break ;
}
}
//=========================================================
// Respawn- this item is already in the world, but it is
// invisible and intangible. Make it visible and tangible.
//=========================================================
CBaseEntity * CBasePlayerItem : : Respawn ( void )
{
// make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
// will decide when to make the weapon visible and touchable.
CBaseEntity * pNewWeapon = CBaseEntity : : Create ( STRING ( pev - > classname ) , g_pGameRules - > VecWeaponRespawnSpot ( this ) , pev - > angles , pev - > owner ) ;
if ( pNewWeapon )
{
pNewWeapon - > pev - > effects | = EF_NODRAW ; // invisible for now
pNewWeapon - > SetTouch ( NULL ) ; // no touch
pNewWeapon - > SetThink ( & CBasePlayerItem : : AttemptToMaterialize ) ;
DROP_TO_FLOOR ( ENT ( pev ) ) ;
// not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
// but when it should respawn is based on conditions belonging to the weapon that was taken.
pNewWeapon - > pev - > nextthink = g_pGameRules - > FlWeaponRespawnTime ( this ) ;
}
else
{
ALERT ( at_console , " Respawn failed to create %s! \n " , STRING ( pev - > classname ) ) ;
}
return pNewWeapon ;
}
void CBasePlayerItem : : DefaultTouch ( CBaseEntity * pOther )
{
// modif de Julien - la fonction think ne peut etre declaree virtuelle
ItemTouch ( pOther ) ;
// if it's not a player, ignore
if ( ! pOther - > IsPlayer ( ) )
return ;
CBasePlayer * pPlayer = ( CBasePlayer * ) pOther ;
// can I have this?
if ( ! g_pGameRules - > CanHavePlayerItem ( pPlayer , this ) )
{
if ( gEvilImpulse101 )
{
UTIL_Remove ( this ) ;
}
return ;
}
if ( pOther - > AddPlayerItem ( this ) )
{
AttachToPlayer ( pPlayer ) ;
EMIT_SOUND ( ENT ( pPlayer - > pev ) , CHAN_ITEM , " items/gunpickup2.wav " , 1 , ATTN_NORM ) ;
}
SUB_UseTargets ( pOther , USE_TOGGLE , 0 ) ; // UNDONE: when should this happen?
}
BOOL CanAttack ( float attack_time , float curtime , BOOL isPredicted )
{
# if CLIENT_WEAPONS
if ( ! isPredicted )
# else
if ( 1 )
# endif
{
return ( attack_time < = curtime ) ? TRUE : FALSE ;
}
else
{
return ( ( static_cast < int > ( : : floor ( attack_time * 1000.0f ) ) * 1000.0f ) < = 0.0f ) ? TRUE : FALSE ;
}
}
void CBasePlayerWeapon : : ItemPostFrame ( void )
{
if ( ( m_fInReload ) & & ( m_pPlayer - > m_flNextAttack < = UTIL_WeaponTimeBase ( ) ) )
{
// complete the reload.
int j = Q_min ( iMaxClip ( ) - m_iClip , m_pPlayer - > m_rgAmmo [ m_iPrimaryAmmoType ] ) ;
// Add them to the clip
m_iClip + = j ;
m_pPlayer - > m_rgAmmo [ m_iPrimaryAmmoType ] - = j ;
m_pPlayer - > TabulateAmmo ( ) ;
m_fInReload = FALSE ;
}
if ( ! ( m_pPlayer - > pev - > button & IN_ATTACK ) )
{
m_flLastFireTime = 0.0f ;
}
if ( ( m_pPlayer - > pev - > button & IN_ATTACK2 ) & & CanAttack ( m_flNextSecondaryAttack , gpGlobals - > time , UseDecrement ( ) ) & & m_pPlayer - > m_iDrivingTank = = FALSE ) //modif de Julien
{
if ( pszAmmo2 ( ) & & ! m_pPlayer - > m_rgAmmo [ SecondaryAmmoIndex ( ) ] )
{
m_fFireOnEmpty = TRUE ;
}
m_pPlayer - > TabulateAmmo ( ) ;
SecondaryAttack ( ) ;
m_pPlayer - > pev - > button & = ~ IN_ATTACK2 ;
}
else if ( ( m_pPlayer - > pev - > button & IN_ATTACK ) & & CanAttack ( m_flNextPrimaryAttack , gpGlobals - > time , UseDecrement ( ) ) & & m_pPlayer - > m_iDrivingTank = = FALSE ) //modif de Julien
{
if ( ( m_iClip = = 0 & & pszAmmo1 ( ) ) | | ( iMaxClip ( ) = = - 1 & & ! m_pPlayer - > m_rgAmmo [ PrimaryAmmoIndex ( ) ] ) )
{
m_fFireOnEmpty = TRUE ;
}
m_pPlayer - > TabulateAmmo ( ) ;
PrimaryAttack ( ) ;
}
else if ( m_pPlayer - > pev - > button & IN_RELOAD & & iMaxClip ( ) ! = WEAPON_NOCLIP & & ! m_fInReload )
{
// reload when reload is pressed, or if no buttons are down and weapon is empty.
Reload ( ) ;
}
else if ( ! ( m_pPlayer - > pev - > button & ( IN_ATTACK | IN_ATTACK2 ) ) )
{
// no fire buttons down
m_fFireOnEmpty = FALSE ;
if ( ! IsUseable ( ) & & m_flNextPrimaryAttack < ( UseDecrement ( ) ? 0.0f : gpGlobals - > time ) )
{
// weapon isn't useable, switch.
if ( ! ( iFlags ( ) & ITEM_FLAG_NOAUTOSWITCHEMPTY ) & & g_pGameRules - > GetNextBestWeapon ( m_pPlayer , this ) )
{
m_flNextPrimaryAttack = ( UseDecrement ( ) ? 0.0f : gpGlobals - > time ) + 0.3f ;
return ;
}
}
else
{
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
if ( m_iClip = = 0 & & ! ( iFlags ( ) & ITEM_FLAG_NOAUTORELOAD ) & & m_flNextPrimaryAttack < ( UseDecrement ( ) ? 0.0f : gpGlobals - > time ) )
{
Reload ( ) ;
return ;
}
}
WeaponIdle ( ) ;
return ;
}
// catch all
if ( ShouldWeaponIdle ( ) )
{
WeaponIdle ( ) ;
}
}
void CBasePlayerItem : : DestroyItem ( void )
{
if ( m_pPlayer )
{
// if attached to a player, remove.
m_pPlayer - > RemovePlayerItem ( this , false ) ;
}
Kill ( ) ;
}
int CBasePlayerItem : : AddToPlayer ( CBasePlayer * pPlayer )
{
m_pPlayer = pPlayer ;
return TRUE ;
}
void CBasePlayerItem : : Drop ( void )
{
SetTouch ( NULL ) ;
SetThink ( & CBaseEntity : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time + 0.1f ;
}
void CBasePlayerItem : : Kill ( void )
{
SetTouch ( NULL ) ;
SetThink ( & CBaseEntity : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time + 0.1f ;
}
void CBasePlayerItem : : Holster ( int skiplocal /* = 0 */ )
{
m_pPlayer - > pev - > viewmodel = 0 ;
m_pPlayer - > pev - > weaponmodel = 0 ;
}
void CBasePlayerItem : : AttachToPlayer ( CBasePlayer * pPlayer )
{
pev - > movetype = MOVETYPE_FOLLOW ;
pev - > solid = SOLID_NOT ;
pev - > aiment = pPlayer - > edict ( ) ;
pev - > effects = EF_NODRAW ; // ??
pev - > modelindex = 0 ; // server won't send down to clients if modelindex == 0
pev - > model = iStringNull ;
pev - > owner = pPlayer - > edict ( ) ;
pev - > nextthink = 0 ; // Remove think - prevents futher attempts to materialize
SetTouch ( NULL ) ;
SetThink ( NULL ) ;
}
// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal
int CBasePlayerWeapon : : AddDuplicate ( CBasePlayerItem * pOriginal )
{
if ( m_iDefaultAmmo )
{
return ExtractAmmo ( ( CBasePlayerWeapon * ) pOriginal ) ;
}
else
{
// a dead player dropped this.
return ExtractClipAmmo ( ( CBasePlayerWeapon * ) pOriginal ) ;
}
}
int CBasePlayerWeapon : : AddToPlayer ( CBasePlayer * pPlayer )
{
int bResult = CBasePlayerItem : : AddToPlayer ( pPlayer ) ;
pPlayer - > pev - > weapons | = ( 1 < < m_iId ) ;
if ( ! m_iPrimaryAmmoType )
{
m_iPrimaryAmmoType = pPlayer - > GetAmmoIndex ( pszAmmo1 ( ) ) ;
m_iSecondaryAmmoType = pPlayer - > GetAmmoIndex ( pszAmmo2 ( ) ) ;
}
if ( bResult )
return AddWeapon ( ) ;
return FALSE ;
}
int CBasePlayerWeapon : : UpdateClientData ( CBasePlayer * pPlayer )
{
BOOL bSend = FALSE ;
int state = 0 ;
if ( pPlayer - > m_pActiveItem = = this )
{
if ( pPlayer - > m_fOnTarget )
state = WEAPON_IS_ONTARGET ;
else
state = 1 ;
}
// Forcing send of all data!
if ( ! pPlayer - > m_fWeapon )
{
bSend = TRUE ;
}
// This is the current or last weapon, so the state will need to be updated
if ( this = = pPlayer - > m_pActiveItem | | this = = pPlayer - > m_pClientActiveItem )
{
if ( pPlayer - > m_pActiveItem ! = pPlayer - > m_pClientActiveItem )
{
bSend = TRUE ;
}
}
// If the ammo, state, or fov has changed, update the weapon
if ( m_iClip ! = m_iClientClip | | state ! = m_iClientWeaponState | | pPlayer - > m_iFOV ! = pPlayer - > m_iClientFOV )
{
bSend = TRUE ;
}
if ( bSend )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgCurWeapon , NULL , pPlayer - > pev ) ;
WRITE_BYTE ( state ) ;
WRITE_BYTE ( m_iId ) ;
WRITE_BYTE ( m_iClip ) ;
MESSAGE_END ( ) ;
m_iClientClip = m_iClip ;
m_iClientWeaponState = state ;
pPlayer - > m_fWeapon = TRUE ;
}
if ( m_pNext )
m_pNext - > UpdateClientData ( pPlayer ) ;
return 1 ;
}
void CBasePlayerWeapon : : SendWeaponAnim ( int iAnim , int skiplocal , int body )
{
if ( UseDecrement ( ) )
skiplocal = 1 ;
else
skiplocal = 0 ;
m_pPlayer - > pev - > weaponanim = iAnim ;
# if CLIENT_WEAPONS
if ( skiplocal & & ENGINE_CANSKIP ( m_pPlayer - > edict ( ) ) )
return ;
# endif
MESSAGE_BEGIN ( MSG_ONE , SVC_WEAPONANIM , NULL , m_pPlayer - > pev ) ;
WRITE_BYTE ( iAnim ) ; // sequence number
WRITE_BYTE ( pev - > body ) ; // weaponmodel bodygroup.
MESSAGE_END ( ) ;
}
BOOL CBasePlayerWeapon : : AddPrimaryAmmo ( int iCount , char * szName , int iMaxClip , int iMaxCarry )
{
int iIdAmmo ;
if ( iMaxClip < 1 )
{
m_iClip = - 1 ;
iIdAmmo = m_pPlayer - > GiveAmmo ( iCount , szName , iMaxCarry ) ;
}
else if ( m_iClip = = 0 )
{
int i ;
i = Q_min ( m_iClip + iCount , iMaxClip ) - m_iClip ;
m_iClip + = i ;
iIdAmmo = m_pPlayer - > GiveAmmo ( iCount - i , szName , iMaxCarry ) ;
}
else
{
iIdAmmo = m_pPlayer - > GiveAmmo ( iCount , szName , iMaxCarry ) ;
}
// m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing
if ( iIdAmmo > 0 )
{
m_iPrimaryAmmoType = iIdAmmo ;
if ( m_pPlayer - > HasPlayerItem ( this ) )
{
// play the "got ammo" sound only if we gave some ammo to a player that already had this gun.
// if the player is just getting this gun for the first time, DefaultTouch will play the "picked up gun" sound for us.
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " items/9mmclip1.wav " , 1 , ATTN_NORM ) ;
}
}
return iIdAmmo > 0 ? TRUE : FALSE ;
}
BOOL CBasePlayerWeapon : : AddSecondaryAmmo ( int iCount , char * szName , int iMax )
{
int iIdAmmo ;
iIdAmmo = m_pPlayer - > GiveAmmo ( iCount , szName , iMax ) ;
//m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing
if ( iIdAmmo > 0 )
{
m_iSecondaryAmmoType = iIdAmmo ;
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " items/9mmclip1.wav " , 1 , ATTN_NORM ) ;
}
return iIdAmmo > 0 ? TRUE : FALSE ;
}
//=========================================================
// IsUseable - this function determines whether or not a
// weapon is useable by the player in its current state.
// (does it have ammo loaded? do I have any ammo for the
// weapon?, etc)
//=========================================================
BOOL CBasePlayerWeapon : : IsUseable ( void )
{
if ( m_iClip > 0 )
{
return TRUE ;
}
// Player has unlimited ammo for this weapon or does not use magazines
if ( iMaxAmmo1 ( ) = = WEAPON_NOCLIP )
{
return TRUE ;
}
if ( m_pPlayer - > m_rgAmmo [ PrimaryAmmoIndex ( ) ] > 0 )
{
return TRUE ;
}
if ( pszAmmo2 ( ) )
{
// Player has unlimited ammo for this weapon or does not use magazines
if ( iMaxAmmo2 ( ) = = WEAPON_NOCLIP )
{
return TRUE ;
}
if ( m_pPlayer - > m_rgAmmo [ SecondaryAmmoIndex ( ) ] > 0 )
{
return TRUE ;
}
}
// clip is empty (or nonexistant) and the player has no more ammo of this type.
return FALSE ;
}
BOOL CBasePlayerWeapon : : CanDeploy ( void )
{
BOOL bHasAmmo = 0 ;
if ( ! pszAmmo1 ( ) )
{
// this weapon doesn't use ammo, can always deploy.
return TRUE ;
}
if ( pszAmmo1 ( ) )
{
bHasAmmo | = ( m_pPlayer - > m_rgAmmo [ m_iPrimaryAmmoType ] ! = 0 ) ;
}
if ( pszAmmo2 ( ) )
{
bHasAmmo | = ( m_pPlayer - > m_rgAmmo [ m_iSecondaryAmmoType ] ! = 0 ) ;
}
if ( m_iClip > 0 )
{
bHasAmmo | = 1 ;
}
if ( ! bHasAmmo )
{
return FALSE ;
}
return TRUE ;
}
BOOL CBasePlayerWeapon : : DefaultDeploy ( const char * szViewModel , const char * szWeaponModel , int iAnim , const char * szAnimExt , int skiplocal /* = 0 */ , int body )
{
if ( ! CanDeploy ( ) )
return FALSE ;
m_pPlayer - > TabulateAmmo ( ) ;
m_pPlayer - > pev - > viewmodel = MAKE_STRING ( szViewModel ) ;
m_pPlayer - > pev - > weaponmodel = MAKE_STRING ( szWeaponModel ) ;
strcpy ( m_pPlayer - > m_szAnimExtention , szAnimExt ) ;
SendWeaponAnim ( iAnim , skiplocal , body ) ;
m_pPlayer - > m_flNextAttack = UTIL_WeaponTimeBase ( ) + 0.5f ;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase ( ) + 1.0f ;
m_flLastFireTime = 0.0f ;
return TRUE ;
}
BOOL CBasePlayerWeapon : : DefaultReload ( int iClipSize , int iAnim , float fDelay , int body )
{
if ( m_pPlayer - > m_rgAmmo [ m_iPrimaryAmmoType ] < = 0 )
return FALSE ;
int j = Q_min ( iClipSize - m_iClip , m_pPlayer - > m_rgAmmo [ m_iPrimaryAmmoType ] ) ;
if ( j = = 0 )
return FALSE ;
m_pPlayer - > m_flNextAttack = UTIL_WeaponTimeBase ( ) + fDelay ;
//!!UNDONE -- reload sound goes here !!!
SendWeaponAnim ( iAnim , UseDecrement ( ) ? 1 : 0 ) ;
m_fInReload = TRUE ;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase ( ) + 3.0f ;
return TRUE ;
}
BOOL CBasePlayerWeapon : : PlayEmptySound ( void )
{
if ( m_iPlayEmptySound )
{
EMIT_SOUND ( ENT ( m_pPlayer - > pev ) , CHAN_WEAPON , " weapons/357_cock1.wav " , 0.8 , ATTN_NORM ) ;
m_iPlayEmptySound = 0 ;
return 0 ;
}
return 0 ;
}
void CBasePlayerWeapon : : ResetEmptySound ( void )
{
m_iPlayEmptySound = 1 ;
}
//=========================================================
//=========================================================
int CBasePlayerWeapon : : PrimaryAmmoIndex ( void )
{
return m_iPrimaryAmmoType ;
}
//=========================================================
//=========================================================
int CBasePlayerWeapon : : SecondaryAmmoIndex ( void )
{
return - 1 ;
}
void CBasePlayerWeapon : : Holster ( int skiplocal /* = 0 */ )
{
m_fInReload = FALSE ; // cancel any reload in progress.
m_pPlayer - > pev - > viewmodel = 0 ;
m_pPlayer - > pev - > weaponmodel = 0 ;
}
void CBasePlayerAmmo : : Spawn ( void )
{
pev - > movetype = MOVETYPE_TOSS ;
pev - > solid = SOLID_TRIGGER ;
UTIL_SetSize ( pev , Vector ( - 16 , - 16 , 0 ) , Vector ( 16 , 16 , 16 ) ) ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
SetTouch ( & CBasePlayerAmmo : : DefaultTouch ) ;
}
CBaseEntity * CBasePlayerAmmo : : Respawn ( void )
{
pev - > effects | = EF_NODRAW ;
SetTouch ( NULL ) ;
UTIL_SetOrigin ( pev , g_pGameRules - > VecAmmoRespawnSpot ( this ) ) ; // move to wherever I'm supposed to repawn.
SetThink ( & CBasePlayerAmmo : : Materialize ) ;
pev - > nextthink = g_pGameRules - > FlAmmoRespawnTime ( this ) ;
return this ;
}
void CBasePlayerAmmo : : Materialize ( void )
{
if ( pev - > effects & EF_NODRAW )
{
// changing from invisible state to visible.
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_WEAPON , " items/suitchargeok1.wav " , 1 , ATTN_NORM , 0 , 150 ) ;
pev - > effects & = ~ EF_NODRAW ;
pev - > effects | = EF_MUZZLEFLASH ;
}
SetTouch ( & CBasePlayerAmmo : : DefaultTouch ) ;
SetThink ( NULL ) ;
}
void CBasePlayerAmmo : : DefaultTouch ( CBaseEntity * pOther )
{
if ( ! pOther - > IsPlayer ( ) )
{
return ;
}
if ( AddAmmo ( pOther ) )
{
if ( g_pGameRules - > AmmoShouldRespawn ( this ) = = GR_AMMO_RESPAWN_YES )
{
Respawn ( ) ;
}
else
{
SetTouch ( NULL ) ;
SetThink ( & CBaseEntity : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time + 0.1f ;
}
}
else if ( gEvilImpulse101 )
{
// evil impulse 101 hack, kill always
SetTouch ( NULL ) ;
SetThink ( & CBaseEntity : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time + 0.1f ;
}
}
//=========================================================
// called by the new item with the existing item as parameter
//
// if we call ExtractAmmo(), it's because the player is picking up this type of weapon for
// the first time. If it is spawned by the world, m_iDefaultAmmo will have a default ammo amount in it.
// if this is a weapon dropped by a dying player, has 0 m_iDefaultAmmo, which means only the ammo in
// the weapon clip comes along.
//=========================================================
int CBasePlayerWeapon : : ExtractAmmo ( CBasePlayerWeapon * pWeapon )
{
int iReturn = 0 ;
if ( pszAmmo1 ( ) ! = NULL )
{
// blindly call with m_iDefaultAmmo. It's either going to be a value or zero. If it is zero,
// we only get the ammo in the weapon's clip, which is what we want.
iReturn | = pWeapon - > AddPrimaryAmmo ( m_iDefaultAmmo , ( char * ) pszAmmo1 ( ) , iMaxClip ( ) , iMaxAmmo1 ( ) ) ;
m_iDefaultAmmo = 0 ;
}
if ( pszAmmo2 ( ) ! = NULL )
{
iReturn | = pWeapon - > AddSecondaryAmmo ( 0 , ( char * ) pszAmmo2 ( ) , iMaxAmmo2 ( ) ) ;
}
return iReturn ;
}
//=========================================================
// called by the new item's class with the existing item as parameter
//=========================================================
int CBasePlayerWeapon : : ExtractClipAmmo ( CBasePlayerWeapon * pWeapon )
{
int iAmmo ;
if ( m_iClip = = WEAPON_NOCLIP )
{
iAmmo = 0 ; // guns with no clips always come empty if they are second-hand
}
else
{
iAmmo = m_iClip ;
}
return pWeapon - > m_pPlayer - > GiveAmmo ( iAmmo , ( char * ) pszAmmo1 ( ) , iMaxAmmo1 ( ) ) ; // , &m_iPrimaryAmmoType
}
//=========================================================
// RetireWeapon - no more ammo for this gun, put it away.
//=========================================================
void CBasePlayerWeapon : : RetireWeapon ( void )
{
// first, no viewmodel at all.
m_pPlayer - > pev - > viewmodel = iStringNull ;
m_pPlayer - > pev - > weaponmodel = iStringNull ;
//m_pPlayer->pev->viewmodelindex = NULL;
if ( ! g_pGameRules - > GetNextBestWeapon ( m_pPlayer , this ) )
{
// Another weapon wasn't selected. Get rid of current one
if ( m_pPlayer - > m_pActiveItem = = this )
{
m_pPlayer - > ResetAutoaim ( ) ;
m_pPlayer - > m_pActiveItem - > Holster ( ) ;
m_pPlayer - > m_pLastItem = NULL ;
m_pPlayer - > m_pActiveItem = NULL ;
}
}
}
//=========================================================================
// GetNextAttackDelay - An accurate way of calcualting the next attack time.
//=========================================================================
float CBasePlayerWeapon : : GetNextAttackDelay ( float delay )
{
if ( m_flLastFireTime = = 0 | | m_flNextPrimaryAttack = = - 1.0f )
{
// At this point, we are assuming that the client has stopped firing
// and we are going to reset our book keeping variables.
m_flLastFireTime = gpGlobals - > time ;
m_flPrevPrimaryAttack = delay ;
}
// calculate the time between this shot and the previous
float flTimeBetweenFires = gpGlobals - > time - m_flLastFireTime ;
float flCreep = 0.0f ;
if ( flTimeBetweenFires > 0 )
flCreep = flTimeBetweenFires - m_flPrevPrimaryAttack ; // postive or negative
// save the last fire time
m_flLastFireTime = gpGlobals - > time ;
float flNextAttack = UTIL_WeaponTimeBase ( ) + delay - flCreep ;
// we need to remember what the m_flNextPrimaryAttack time is set to for each shot,
// store it as m_flPrevPrimaryAttack.
m_flPrevPrimaryAttack = flNextAttack - UTIL_WeaponTimeBase ( ) ;
//char szMsg[256];
//_snprintf( szMsg, sizeof(szMsg), "next attack time: %0.4f\n", gpGlobals->time + flNextAttack );
//OutputDebugString( szMsg );
return flNextAttack ;
}
//*********************************************************
// weaponbox code:
//*********************************************************
LINK_ENTITY_TO_CLASS ( weaponbox , CWeaponBox )
TYPEDESCRIPTION CWeaponBox : : m_SaveData [ ] =
{
DEFINE_ARRAY ( CWeaponBox , m_rgAmmo , FIELD_INTEGER , MAX_AMMO_SLOTS ) ,
DEFINE_ARRAY ( CWeaponBox , m_rgiszAmmo , FIELD_STRING , MAX_AMMO_SLOTS ) ,
DEFINE_ARRAY ( CWeaponBox , m_rgpPlayerItems , FIELD_CLASSPTR , MAX_ITEM_TYPES ) ,
DEFINE_FIELD ( CWeaponBox , m_cAmmoTypes , FIELD_INTEGER ) ,
} ;
IMPLEMENT_SAVERESTORE ( CWeaponBox , CBaseEntity )
//=========================================================
//
//=========================================================
void CWeaponBox : : Precache ( void )
{
PRECACHE_MODEL ( " models/w_weaponbox.mdl " ) ;
}
//=========================================================
//=========================================================
void CWeaponBox : : KeyValue ( KeyValueData * pkvd )
{
if ( m_cAmmoTypes < MAX_AMMO_SLOTS )
{
PackAmmo ( ALLOC_STRING ( pkvd - > szKeyName ) , atoi ( pkvd - > szValue ) ) ;
m_cAmmoTypes + + ; // count this new ammo type.
pkvd - > fHandled = TRUE ;
}
else
{
ALERT ( at_console , " WeaponBox too full! only %d ammotypes allowed \n " , MAX_AMMO_SLOTS ) ;
}
}
//=========================================================
// CWeaponBox - Spawn
//=========================================================
void CWeaponBox : : Spawn ( void )
{
Precache ( ) ;
pev - > movetype = MOVETYPE_TOSS ;
pev - > solid = SOLID_TRIGGER ;
UTIL_SetSize ( pev , g_vecZero , g_vecZero ) ;
SET_MODEL ( ENT ( pev ) , " models/w_weaponbox.mdl " ) ;
}
//=========================================================
// CWeaponBox - Kill - the think function that removes the
// box from the world.
//=========================================================
void CWeaponBox : : Kill ( void )
{
CBasePlayerItem * pWeapon ;
int i ;
// destroy the weapons
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
pWeapon = m_rgpPlayerItems [ i ] ;
while ( pWeapon )
{
pWeapon - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
pWeapon - > pev - > nextthink = gpGlobals - > time + 0.1f ;
pWeapon = pWeapon - > m_pNext ;
}
}
// remove the box
UTIL_Remove ( this ) ;
}
static const char * IsAmmoForExhaustibleWeapon ( const char * ammoName , int & weaponId )
{
for ( int i = 0 ; i < MAX_WEAPONS ; + + i ) {
ItemInfo & II = CBasePlayerItem : : ItemInfoArray [ i ] ;
if ( ( II . iFlags & ITEM_FLAG_EXHAUSTIBLE ) & & II . pszAmmo1 & & FStrEq ( ammoName , II . pszAmmo1 ) ) {
weaponId = II . iId ;
return II . pszName ;
}
}
return 0 ;
}
//=========================================================
// CWeaponBox - Touch: try to add my contents to the toucher
// if the toucher is a player.
//=========================================================
void CWeaponBox : : Touch ( CBaseEntity * pOther )
{
if ( ! ( pev - > flags & FL_ONGROUND ) )
{
return ;
}
if ( ! pOther - > IsPlayer ( ) )
{
// only players may touch a weaponbox.
return ;
}
if ( ! pOther - > IsAlive ( ) )
{
// no dead guys.
return ;
}
CBasePlayer * pPlayer = ( CBasePlayer * ) pOther ;
int i ;
// dole out ammo
for ( i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
{
if ( ! FStringNull ( m_rgiszAmmo [ i ] ) )
{
// horrific HACK to give player an exhaustible weapon as a real weapon, not just ammo
int exhaustibleWeaponId ;
const char * weaponName = IsAmmoForExhaustibleWeapon ( STRING ( m_rgiszAmmo [ i ] ) , exhaustibleWeaponId ) ;
if ( weaponName ) {
bool foundWeapon = false ;
for ( int j = 0 ; j < MAX_ITEM_TYPES & & ! foundWeapon ; j + + )
{
CBasePlayerItem * pPlayerItem = pPlayer - > m_rgpPlayerItems [ j ] ;
while ( pPlayerItem )
{
if ( pPlayerItem - > m_iId = = exhaustibleWeaponId ) {
foundWeapon = true ;
break ;
}
pPlayerItem = pPlayerItem - > m_pNext ;
}
}
if ( ! foundWeapon ) {
CBasePlayerWeapon * weapon = ( CBasePlayerWeapon * ) Create ( weaponName , pev - > origin , pev - > angles ) ;
if ( weapon ) {
weapon - > pev - > spawnflags | = SF_NORESPAWN ;
weapon - > m_iDefaultAmmo = 0 ;
if ( pPlayer - > AddPlayerItem ( weapon ) ) {
weapon - > AttachToPlayer ( pPlayer ) ;
}
}
}
}
// there's some ammo of this type.
pPlayer - > GiveAmmo ( m_rgAmmo [ i ] , STRING ( m_rgiszAmmo [ i ] ) , MaxAmmoCarry ( m_rgiszAmmo [ i ] ) ) ;
//ALERT( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING( m_rgiszAmmo[i] ) );
// now empty the ammo from the weaponbox since we just gave it to the player
m_rgiszAmmo [ i ] = iStringNull ;
m_rgAmmo [ i ] = 0 ;
}
}
// go through my weapons and try to give the usable ones to the player.
// it's important the the player be given ammo first, so the weapons code doesn't refuse
// to deploy a better weapon that the player may pick up because he has no ammo for it.
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] )
{
CBasePlayerItem * pItem ;
// have at least one weapon in this slot
while ( m_rgpPlayerItems [ i ] )
{
//ALERT( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[i]->pev->classname ) );
pItem = m_rgpPlayerItems [ i ] ;
m_rgpPlayerItems [ i ] = m_rgpPlayerItems [ i ] - > m_pNext ; // unlink this weapon from the box
if ( pPlayer - > AddPlayerItem ( pItem ) )
{
pItem - > AttachToPlayer ( pPlayer ) ;
}
}
}
}
EMIT_SOUND ( pOther - > edict ( ) , CHAN_ITEM , " items/gunpickup2.wav " , 1 , ATTN_NORM ) ;
SetTouch ( NULL ) ;
UTIL_Remove ( this ) ;
}
//=========================================================
// CWeaponBox - PackWeapon: Add this weapon to the box
//=========================================================
BOOL CWeaponBox : : PackWeapon ( CBasePlayerItem * pWeapon )
{
// is one of these weapons already packed in this box?
if ( HasWeapon ( pWeapon ) )
{
return FALSE ; // box can only hold one of each weapon type
}
if ( pWeapon - > m_pPlayer )
{
if ( ! pWeapon - > m_pPlayer - > RemovePlayerItem ( pWeapon , true ) )
{
// failed to unhook the weapon from the player!
return FALSE ;
}
}
int iWeaponSlot = pWeapon - > iItemSlot ( ) ;
if ( m_rgpPlayerItems [ iWeaponSlot ] )
{
// there's already one weapon in this slot, so link this into the slot's column
pWeapon - > m_pNext = m_rgpPlayerItems [ iWeaponSlot ] ;
m_rgpPlayerItems [ iWeaponSlot ] = pWeapon ;
}
else
{
// first weapon we have for this slot
m_rgpPlayerItems [ iWeaponSlot ] = pWeapon ;
pWeapon - > m_pNext = NULL ;
}
pWeapon - > pev - > spawnflags | = SF_NORESPAWN ; // never respawn
pWeapon - > pev - > movetype = MOVETYPE_NONE ;
pWeapon - > pev - > solid = SOLID_NOT ;
pWeapon - > pev - > effects = EF_NODRAW ;
pWeapon - > pev - > modelindex = 0 ;
pWeapon - > pev - > model = iStringNull ;
pWeapon - > pev - > owner = edict ( ) ;
pWeapon - > SetThink ( NULL ) ; // crowbar may be trying to swing again, etc.
pWeapon - > SetTouch ( NULL ) ;
pWeapon - > m_pPlayer = NULL ;
//ALERT( at_console, "packed %s\n", STRING( pWeapon->pev->classname ) );
return TRUE ;
}
//=========================================================
// CWeaponBox - PackAmmo
//=========================================================
BOOL CWeaponBox : : PackAmmo ( int iszName , int iCount )
{
int iMaxCarry ;
if ( FStringNull ( iszName ) )
{
// error here
ALERT ( at_console , " NULL String in PackAmmo! \n " ) ;
return FALSE ;
}
iMaxCarry = MaxAmmoCarry ( iszName ) ;
if ( iMaxCarry ! = - 1 & & iCount > 0 )
{
//ALERT( at_console, "Packed %d rounds of %s\n", iCount, STRING( iszName ) );
GiveAmmo ( iCount , STRING ( iszName ) , iMaxCarry ) ;
return TRUE ;
}
return FALSE ;
}
//=========================================================
// CWeaponBox - GiveAmmo
//=========================================================
int CWeaponBox : : GiveAmmo ( int iCount , const char * szName , int iMax , int * pIndex /* = NULL*/ )
{
int i ;
for ( i = 1 ; i < MAX_AMMO_SLOTS & & ! FStringNull ( m_rgiszAmmo [ i ] ) ; i + + )
{
if ( stricmp ( szName , STRING ( m_rgiszAmmo [ i ] ) ) = = 0 )
{
if ( pIndex )
* pIndex = i ;
int iAdd = Q_min ( iCount , iMax - m_rgAmmo [ i ] ) ;
if ( iCount = = 0 | | iAdd > 0 )
{
m_rgAmmo [ i ] + = iAdd ;
return i ;
}
return - 1 ;
}
}
if ( i < MAX_AMMO_SLOTS )
{
if ( pIndex )
* pIndex = i ;
m_rgiszAmmo [ i ] = MAKE_STRING ( szName ) ;
m_rgAmmo [ i ] = iCount ;
return i ;
}
ALERT ( at_console , " out of named ammo slots \n " ) ;
return i ;
}
//=========================================================
// CWeaponBox::HasWeapon - is a weapon of this type already
// packed in this box?
//=========================================================
BOOL CWeaponBox : : HasWeapon ( CBasePlayerItem * pCheckItem )
{
CBasePlayerItem * pItem = m_rgpPlayerItems [ pCheckItem - > iItemSlot ( ) ] ;
while ( pItem )
{
if ( FClassnameIs ( pItem - > pev , STRING ( pCheckItem - > pev - > classname ) ) )
{
return TRUE ;
}
pItem = pItem - > m_pNext ;
}
return FALSE ;
}
//=========================================================
// CWeaponBox::IsEmpty - is there anything in this box?
//=========================================================
BOOL CWeaponBox : : IsEmpty ( void )
{
int i ;
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] )
{
return FALSE ;
}
}
for ( i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
{
if ( ! FStringNull ( m_rgiszAmmo [ i ] ) )
{
// still have a bit of this type of ammo
return FALSE ;
}
}
return TRUE ;
}
//=========================================================
//=========================================================
void CWeaponBox : : SetObjectCollisionBox ( void )
{
pev - > absmin = pev - > origin + Vector ( - 16 , - 16 , 0 ) ;
pev - > absmax = pev - > origin + Vector ( 16 , 16 , 16 ) ;
}
void CBasePlayerWeapon : : PrintState ( void )
{
ALERT ( at_console , " primary: %f \n " , ( double ) m_flNextPrimaryAttack ) ;
ALERT ( at_console , " idle : %f \n " , ( double ) m_flTimeWeaponIdle ) ;
//ALERT( at_console, "nextrl : %f\n", m_flNextReload );
//ALERT( at_console, "nextpum: %f\n", m_flPumpTime );
//ALERT( at_console, "m_frt : %f\n", m_fReloadTime );
ALERT ( at_console , " m_finre: %i \n " , m_fInReload ) ;
//ALERT( at_console, "m_finsr: %i\n", m_fInSpecialReload );
ALERT ( at_console , " m_iclip: %i \n " , m_iClip ) ;
}
TYPEDESCRIPTION CShotgun : : m_SaveData [ ] =
{
DEFINE_FIELD ( CShotgun , m_fInReload , FIELD_INTEGER ) ,
DEFINE_FIELD ( CShotgun , m_flNextReload , FIELD_TIME ) ,
// DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ),
DEFINE_FIELD ( CShotgun , m_flPumpTime , FIELD_TIME ) ,
} ;
IMPLEMENT_SAVERESTORE ( CShotgun , CBasePlayerWeapon ) ;
TYPEDESCRIPTION CGauss : : m_SaveData [ ] =
{
DEFINE_FIELD ( CGauss , m_fInAttack , FIELD_INTEGER ) ,
//DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ),
//DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ),
//DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ),
DEFINE_FIELD ( CGauss , m_fPrimaryFire , FIELD_BOOLEAN ) ,
} ;
IMPLEMENT_SAVERESTORE ( CGauss , CBasePlayerWeapon )
/*TYPEDESCRIPTION CEgon::m_SaveData[] = //modif de Julien will cause "unimplemented symbol" error in game if not commented out
{
//DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ),
//DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ),
//DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ),
DEFINE_FIELD ( CEgon , m_shootTime , FIELD_TIME ) ,
DEFINE_FIELD ( CEgon , m_fireState , FIELD_INTEGER ) ,
DEFINE_FIELD ( CEgon , m_fireMode , FIELD_INTEGER ) ,
DEFINE_FIELD ( CEgon , m_shakeTime , FIELD_TIME ) ,
DEFINE_FIELD ( CEgon , m_flAmmoUseTime , FIELD_TIME ) ,
} ;
IMPLEMENT_SAVERESTORE ( CEgon , CBasePlayerWeapon ) */
/*TYPEDESCRIPTION CHgun::m_SaveData[] = //modif de Julien
{
DEFINE_FIELD ( CHgun , m_flRechargeTime , FIELD_TIME ) ,
DEFINE_FIELD ( CHgun , m_iFirePhase , FIELD_INTEGER ) ,
} ; */
//IMPLEMENT_SAVERESTORE( CHgun, CBasePlayerWeapon )
TYPEDESCRIPTION CSatchel : : m_SaveData [ ] =
{
DEFINE_FIELD ( CSatchel , m_chargeReady , FIELD_INTEGER ) ,
} ;
IMPLEMENT_SAVERESTORE ( CSatchel , CBasePlayerWeapon )