2016-06-04 15:24:23 +02:00
/***
*
* 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 .
*
* * * */
/*
= = = = = combat . cpp = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
functions dealing with damage infliction & death
*/
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "monsters.h"
# include "soundent.h"
# include "decals.h"
# include "animation.h"
# include "weapons.h"
# include "func_break.h"
2022-06-06 17:51:03 +02:00
# include "game.h"
2016-06-04 15:24:23 +02:00
extern DLL_GLOBAL Vector g_vecAttackDir ;
extern DLL_GLOBAL int g_iSkillLevel ;
2016-07-31 15:48:50 +02:00
extern Vector VecBModelOrigin ( entvars_t * pevBModel ) ;
2016-06-04 15:24:23 +02:00
extern entvars_t * g_pevLastInflictor ;
# define GERMAN_GIB_COUNT 4
# define HUMAN_GIB_COUNT 6
# define ALIEN_GIB_COUNT 4
// HACKHACK -- The gib velocity equations don't work
2016-07-31 15:48:50 +02:00
void CGib : : LimitVelocity ( void )
2016-06-04 15:24:23 +02:00
{
float length = pev - > velocity . Length ( ) ;
// ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it
// in 3 separate places again, I'll just limit it here.
2019-10-13 13:49:25 +02:00
if ( length > 1500.0f )
pev - > velocity = pev - > velocity . Normalize ( ) * 1500.0f ; // This should really be sv_maxvelocity * 0.75 or something
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
void CGib : : SpawnStickyGibs ( entvars_t * pevVictim , Vector vecOrigin , int cGibs )
2016-06-04 15:24:23 +02:00
{
int i ;
2016-07-31 15:48:50 +02:00
for ( i = 0 ; i < cGibs ; i + + )
2016-06-04 15:24:23 +02:00
{
CGib * pGib = GetClassPtr ( ( CGib * ) NULL ) ;
pGib - > Spawn ( " models/stickygib.mdl " ) ;
2016-07-31 15:48:50 +02:00
pGib - > pev - > body = RANDOM_LONG ( 0 , 2 ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pevVictim )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > origin . x = vecOrigin . x + RANDOM_FLOAT ( - 3.0f , 3.0f ) ;
pGib - > pev - > origin . y = vecOrigin . y + RANDOM_FLOAT ( - 3.0f , 3.0f ) ;
pGib - > pev - > origin . z = vecOrigin . z + RANDOM_FLOAT ( - 3.0f , 3.0f ) ;
2016-06-04 15:24:23 +02:00
/*
2016-07-31 15:48:50 +02:00
pGib - > pev - > origin . x = pevVictim - > absmin . x + pevVictim - > size . x * ( RANDOM_FLOAT ( 0 , 1 ) ) ;
pGib - > pev - > origin . y = pevVictim - > absmin . y + pevVictim - > size . y * ( RANDOM_FLOAT ( 0 , 1 ) ) ;
pGib - > pev - > origin . z = pevVictim - > absmin . z + pevVictim - > size . z * ( RANDOM_FLOAT ( 0 , 1 ) ) ;
2016-06-04 15:24:23 +02:00
*/
// make the gib fly away from the attack vector
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = g_vecAttackDir * - 1.0f ;
2016-06-04 15:24:23 +02:00
// mix in some noise
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity . x + = RANDOM_FLOAT ( - 0.15f , 0.15f ) ;
pGib - > pev - > velocity . y + = RANDOM_FLOAT ( - 0.15f , 0.15f ) ;
pGib - > pev - > velocity . z + = RANDOM_FLOAT ( - 0.15f , 0.15f ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 900.0f ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
pGib - > pev - > avelocity . x = RANDOM_FLOAT ( 250.0f , 400.0f ) ;
pGib - > pev - > avelocity . y = RANDOM_FLOAT ( 250.0f , 400.0f ) ;
2016-06-04 15:24:23 +02:00
// copy owner's blood color
2016-07-31 15:48:50 +02:00
pGib - > m_bloodColor = ( CBaseEntity : : Instance ( pevVictim ) ) - > BloodColor ( ) ;
if ( pevVictim - > health > - 50 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 0.7f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
else if ( pevVictim - > health > - 200 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 2.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 4.0f ;
2016-06-04 15:24:23 +02:00
}
pGib - > pev - > movetype = MOVETYPE_TOSS ;
pGib - > pev - > solid = SOLID_BBOX ;
2016-07-31 15:48:50 +02:00
UTIL_SetSize ( pGib - > pev , Vector ( 0 , 0 , 0 ) , Vector ( 0 , 0 , 0 ) ) ;
2016-06-04 15:24:23 +02:00
pGib - > SetTouch ( & CGib : : StickyGibTouch ) ;
pGib - > SetThink ( NULL ) ;
}
pGib - > LimitVelocity ( ) ;
}
}
2016-07-31 15:48:50 +02:00
void CGib : : SpawnHeadGib ( entvars_t * pevVictim )
2016-06-04 15:24:23 +02:00
{
CGib * pGib = GetClassPtr ( ( CGib * ) NULL ) ;
2024-02-23 23:22:52 +01:00
pGib - > Spawn ( " models/hgibs.mdl " ) ; // throw one head
pGib - > pev - > body = 0 ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pevVictim )
2016-06-04 15:24:23 +02:00
{
pGib - > pev - > origin = pevVictim - > origin + pevVictim - > view_ofs ;
2016-07-31 15:48:50 +02:00
edict_t * pentPlayer = FIND_CLIENT_IN_PVS ( pGib - > edict ( ) ) ;
if ( RANDOM_LONG ( 0 , 100 ) < = 5 & & pentPlayer )
2016-06-04 15:24:23 +02:00
{
// 5% chance head will be thrown at player's face.
2016-07-31 15:48:50 +02:00
entvars_t * pevPlayer ;
2016-06-04 15:24:23 +02:00
pevPlayer = VARS ( pentPlayer ) ;
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = ( ( pevPlayer - > origin + pevPlayer - > view_ofs ) - pGib - > pev - > origin ) . Normalize ( ) * 300.0f ;
pGib - > pev - > velocity . z + = 100.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 100.0f , 100.0f ) , RANDOM_FLOAT ( - 100.0f , 100.0f ) , RANDOM_FLOAT ( 200.0f , 300.0f ) ) ;
2016-06-04 15:24:23 +02:00
}
2019-10-13 13:49:25 +02:00
pGib - > pev - > avelocity . x = RANDOM_FLOAT ( 100.0f , 200.0f ) ;
pGib - > pev - > avelocity . y = RANDOM_FLOAT ( 100.0f , 300.0f ) ;
2016-06-04 15:24:23 +02:00
// copy owner's blood color
2016-07-31 15:48:50 +02:00
pGib - > m_bloodColor = ( CBaseEntity : : Instance ( pevVictim ) ) - > BloodColor ( ) ;
if ( pevVictim - > health > - 50 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 0.7f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
else if ( pevVictim - > health > - 200 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 2.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 4.0f ;
2016-06-04 15:24:23 +02:00
}
}
pGib - > LimitVelocity ( ) ;
}
2016-07-31 15:48:50 +02:00
void CGib : : SpawnRandomGibs ( entvars_t * pevVictim , int cGibs , int human )
2016-06-04 15:24:23 +02:00
{
int cSplat ;
2016-07-31 15:48:50 +02:00
for ( cSplat = 0 ; cSplat < cGibs ; cSplat + + )
2016-06-04 15:24:23 +02:00
{
CGib * pGib = GetClassPtr ( ( CGib * ) NULL ) ;
2024-02-23 23:22:52 +01:00
if ( human )
2016-06-04 15:24:23 +02:00
{
2024-02-23 23:22:52 +01:00
// human pieces
pGib - > Spawn ( " models/hgibs.mdl " ) ;
pGib - > pev - > body = RANDOM_LONG ( 1 , HUMAN_GIB_COUNT - 1 ) ; // start at one to avoid throwing random amounts of skulls (0th gib)
2016-06-04 15:24:23 +02:00
}
else
{
2024-02-23 23:22:52 +01:00
// aliens
pGib - > Spawn ( " models/agibs.mdl " ) ;
pGib - > pev - > body = RANDOM_LONG ( 0 , ALIEN_GIB_COUNT - 1 ) ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
if ( pevVictim )
2016-06-04 15:24:23 +02:00
{
// spawn the gib somewhere in the monster's bounding volume
2019-10-13 13:49:25 +02:00
pGib - > pev - > origin . x = pevVictim - > absmin . x + pevVictim - > size . x * ( RANDOM_FLOAT ( 0.0f , 1.0f ) ) ;
pGib - > pev - > origin . y = pevVictim - > absmin . y + pevVictim - > size . y * ( RANDOM_FLOAT ( 0.0f , 1.0f ) ) ;
pGib - > pev - > origin . z = pevVictim - > absmin . z + pevVictim - > size . z * ( RANDOM_FLOAT ( 0.0f , 1.0f ) ) + 1.0f ; // absmin.z is in the floor because the engine subtracts 1 to enlarge the box
2016-06-04 15:24:23 +02:00
// make the gib fly away from the attack vector
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = g_vecAttackDir * - 1.0f ;
2016-06-04 15:24:23 +02:00
// mix in some noise
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity . x + = RANDOM_FLOAT ( - 0.25f , 0.25f ) ;
pGib - > pev - > velocity . y + = RANDOM_FLOAT ( - 0.25f , 0.25f ) ;
pGib - > pev - > velocity . z + = RANDOM_FLOAT ( - 0.25f , 0.25f ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * RANDOM_FLOAT ( 300.0f , 400.0f ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
pGib - > pev - > avelocity . x = RANDOM_FLOAT ( 100.0f , 200.0f ) ;
pGib - > pev - > avelocity . y = RANDOM_FLOAT ( 100.0f , 300.0f ) ;
2016-06-04 15:24:23 +02:00
// copy owner's blood color
2016-07-31 15:48:50 +02:00
pGib - > m_bloodColor = ( CBaseEntity : : Instance ( pevVictim ) ) - > BloodColor ( ) ;
if ( pevVictim - > health > - 50 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 0.7f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
else if ( pevVictim - > health > - 200 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 2.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
pGib - > pev - > velocity = pGib - > pev - > velocity * 4.0f ;
2016-06-04 15:24:23 +02:00
}
pGib - > pev - > solid = SOLID_BBOX ;
2016-07-31 15:48:50 +02:00
UTIL_SetSize ( pGib - > pev , Vector ( 0 , 0 , 0 ) , Vector ( 0 , 0 , 0 ) ) ;
2016-06-04 15:24:23 +02:00
}
pGib - > LimitVelocity ( ) ;
}
}
2016-07-31 15:48:50 +02:00
BOOL CBaseMonster : : HasHumanGibs ( void )
2016-06-04 15:24:23 +02:00
{
int myClass = Classify ( ) ;
2016-07-31 15:48:50 +02:00
if ( myClass = = CLASS_HUMAN_MILITARY | |
myClass = = CLASS_PLAYER_ALLY | |
myClass = = CLASS_HUMAN_PASSIVE | |
myClass = = CLASS_PLAYER )
2016-06-04 15:24:23 +02:00
return TRUE ;
return FALSE ;
}
2016-07-31 15:48:50 +02:00
BOOL CBaseMonster : : HasAlienGibs ( void )
2016-06-04 15:24:23 +02:00
{
int myClass = Classify ( ) ;
2016-07-31 15:48:50 +02:00
if ( myClass = = CLASS_ALIEN_MILITARY | |
myClass = = CLASS_ALIEN_MONSTER | |
myClass = = CLASS_ALIEN_PASSIVE | |
myClass = = CLASS_INSECT | |
myClass = = CLASS_ALIEN_PREDATOR | |
myClass = = CLASS_ALIEN_PREY )
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
return TRUE ;
2016-06-04 15:24:23 +02:00
return FALSE ;
}
void CBaseMonster : : FadeMonster ( void )
{
StopAnimation ( ) ;
pev - > velocity = g_vecZero ;
pev - > movetype = MOVETYPE_NONE ;
pev - > avelocity = g_vecZero ;
pev - > animtime = gpGlobals - > time ;
pev - > effects | = EF_NOINTERP ;
SUB_StartFadeOut ( ) ;
}
//=========================================================
// GibMonster - create some gore and get rid of a monster's
// model.
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster : : GibMonster ( void )
2016-06-04 15:24:23 +02:00
{
TraceResult tr ;
BOOL gibbed = FALSE ;
2016-07-31 15:48:50 +02:00
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " common/bodysplat.wav " , 1 , ATTN_NORM ) ;
2016-06-04 15:24:23 +02:00
// only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs
2016-07-31 15:48:50 +02:00
if ( HasHumanGibs ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( CVAR_GET_FLOAT ( " violence_hgibs " ) ! = 0 ) // Only the player will ever get here
2016-06-04 15:24:23 +02:00
{
CGib : : SpawnHeadGib ( pev ) ;
CGib : : SpawnRandomGibs ( pev , 4 , 1 ) ; // throw some human gibs.
}
gibbed = TRUE ;
}
2016-07-31 15:48:50 +02:00
else if ( HasAlienGibs ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( CVAR_GET_FLOAT ( " violence_agibs " ) ! = 0 ) // Should never get here, but someone might call it directly
2016-06-04 15:24:23 +02:00
{
CGib : : SpawnRandomGibs ( pev , 4 , 0 ) ; // Throw alien gibs
}
gibbed = TRUE ;
}
2016-07-31 15:48:50 +02:00
if ( ! IsPlayer ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( gibbed )
2016-06-04 15:24:23 +02:00
{
// don't remove players!
SetThink ( & CBaseEntity : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time ;
}
else
{
FadeMonster ( ) ;
}
}
}
//=========================================================
// GetDeathActivity - determines the best type of death
// anim to play.
//=========================================================
2016-07-31 15:48:50 +02:00
Activity CBaseMonster : : GetDeathActivity ( void )
2016-06-04 15:24:23 +02:00
{
Activity deathActivity ;
BOOL fTriedDirection ;
float flDot ;
TraceResult tr ;
Vector vecSrc ;
2016-07-31 15:48:50 +02:00
if ( pev - > deadflag ! = DEAD_NO )
2016-06-04 15:24:23 +02:00
{
// don't run this while dying.
return m_IdealActivity ;
}
vecSrc = Center ( ) ;
fTriedDirection = FALSE ;
deathActivity = ACT_DIESIMPLE ; // in case we can't find any special deaths to do.
2016-07-31 15:48:50 +02:00
UTIL_MakeVectors ( pev - > angles ) ;
2019-10-13 13:49:25 +02:00
flDot = DotProduct ( gpGlobals - > v_forward , g_vecAttackDir * - 1.0f ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
switch ( m_LastHitGroup )
2016-06-04 15:24:23 +02:00
{
// try to pick a region-specific death.
case HITGROUP_HEAD :
deathActivity = ACT_DIE_HEADSHOT ;
break ;
case HITGROUP_STOMACH :
deathActivity = ACT_DIE_GUTSHOT ;
break ;
case HITGROUP_GENERIC :
// try to pick a death based on attack direction
fTriedDirection = TRUE ;
2019-10-13 13:49:25 +02:00
if ( flDot > 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEFORWARD ;
}
2019-10-13 13:49:25 +02:00
else if ( flDot < = - 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEBACKWARD ;
}
break ;
default :
// try to pick a death based on attack direction
fTriedDirection = TRUE ;
2019-10-13 13:49:25 +02:00
if ( flDot > 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEFORWARD ;
}
2019-10-13 13:49:25 +02:00
else if ( flDot < = - 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEBACKWARD ;
}
break ;
}
// can we perform the prescribed death?
2016-07-31 15:48:50 +02:00
if ( LookupActivity ( deathActivity ) = = ACTIVITY_NOT_AVAILABLE )
2016-06-04 15:24:23 +02:00
{
// no! did we fail to perform a directional death?
2016-07-31 15:48:50 +02:00
if ( fTriedDirection )
2016-06-04 15:24:23 +02:00
{
// if yes, we're out of options. Go simple.
deathActivity = ACT_DIESIMPLE ;
}
else
{
// cannot perform the ideal region-specific death, so try a direction.
2019-10-13 13:49:25 +02:00
if ( flDot > 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEFORWARD ;
}
2019-10-13 13:49:25 +02:00
else if ( flDot < = - 0.3f )
2016-06-04 15:24:23 +02:00
{
deathActivity = ACT_DIEBACKWARD ;
}
}
}
2016-07-31 15:48:50 +02:00
if ( LookupActivity ( deathActivity ) = = ACTIVITY_NOT_AVAILABLE )
2016-06-04 15:24:23 +02:00
{
// if we're still invalid, simple is our only option.
deathActivity = ACT_DIESIMPLE ;
}
2016-07-31 15:48:50 +02:00
if ( deathActivity = = ACT_DIEFORWARD )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
// make sure there's room to fall forward
2019-10-13 13:49:25 +02:00
UTIL_TraceHull ( vecSrc , vecSrc + gpGlobals - > v_forward * 64.0f , dont_ignore_monsters , head_hull , edict ( ) , & tr ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-07-31 15:48:50 +02:00
{
deathActivity = ACT_DIESIMPLE ;
}
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
if ( deathActivity = = ACT_DIEBACKWARD )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
// make sure there's room to fall backward
2019-10-13 13:49:25 +02:00
UTIL_TraceHull ( vecSrc , vecSrc - gpGlobals - > v_forward * 64.0f , dont_ignore_monsters , head_hull , edict ( ) , & tr ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-07-31 15:48:50 +02:00
{
deathActivity = ACT_DIESIMPLE ;
}
2016-06-04 15:24:23 +02:00
}
return deathActivity ;
}
//=========================================================
// GetSmallFlinchActivity - determines the best type of flinch
// anim to play.
//=========================================================
2016-07-31 15:48:50 +02:00
Activity CBaseMonster : : GetSmallFlinchActivity ( void )
2016-06-04 15:24:23 +02:00
{
Activity flinchActivity ;
2019-11-16 09:54:30 +01:00
// BOOL fTriedDirection;
2017-06-29 15:56:03 +02:00
//float flDot;
2016-06-04 15:24:23 +02:00
2019-11-16 09:54:30 +01:00
// fTriedDirection = FALSE;
2016-07-31 15:48:50 +02:00
UTIL_MakeVectors ( pev - > angles ) ;
2019-10-13 13:49:25 +02:00
//flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1.0f );
2016-07-31 15:48:50 +02:00
switch ( m_LastHitGroup )
2016-06-04 15:24:23 +02:00
{
// pick a region-specific flinch
case HITGROUP_HEAD :
flinchActivity = ACT_FLINCH_HEAD ;
break ;
case HITGROUP_STOMACH :
flinchActivity = ACT_FLINCH_STOMACH ;
break ;
case HITGROUP_LEFTARM :
flinchActivity = ACT_FLINCH_LEFTARM ;
break ;
case HITGROUP_RIGHTARM :
flinchActivity = ACT_FLINCH_RIGHTARM ;
break ;
case HITGROUP_LEFTLEG :
flinchActivity = ACT_FLINCH_LEFTLEG ;
break ;
case HITGROUP_RIGHTLEG :
flinchActivity = ACT_FLINCH_RIGHTLEG ;
break ;
case HITGROUP_GENERIC :
default :
// just get a generic flinch.
flinchActivity = ACT_SMALL_FLINCH ;
break ;
}
// do we have a sequence for the ideal activity?
2016-07-31 15:48:50 +02:00
if ( LookupActivity ( flinchActivity ) = = ACTIVITY_NOT_AVAILABLE )
2016-06-04 15:24:23 +02:00
{
flinchActivity = ACT_SMALL_FLINCH ;
}
return flinchActivity ;
}
void CBaseMonster : : BecomeDead ( void )
{
pev - > takedamage = DAMAGE_YES ; // don't let autoaim aim at corpses.
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// give the corpse half of the monster's original maximum health.
pev - > health = pev - > max_health / 2 ;
pev - > max_health = 5 ; // max_health now becomes a counter for how many blood decals the corpse can place.
// make the corpse fly away from the attack vector
pev - > movetype = MOVETYPE_TOSS ;
2022-06-06 17:51:03 +02:00
if ( corpsephysics . value & &
// affect only dying monsters, not initially dead ones
m_IdealMonsterState = = MONSTERSTATE_DEAD )
{
pev - > flags & = ~ FL_ONGROUND ;
pev - > origin . z + = 2.0f ;
pev - > velocity = g_vecAttackDir * - 1.0f ;
pev - > velocity = pev - > velocity * RANDOM_FLOAT ( 300.0f , 400.0f ) ;
}
2016-06-04 15:24:23 +02:00
}
BOOL CBaseMonster : : ShouldGibMonster ( int iGib )
{
2016-07-31 15:48:50 +02:00
if ( ( iGib = = GIB_NORMAL & & pev - > health < GIB_HEALTH_VALUE ) | | ( iGib = = GIB_ALWAYS ) )
2016-06-04 15:24:23 +02:00
return TRUE ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
return FALSE ;
}
void CBaseMonster : : CallGibMonster ( void )
{
BOOL fade = FALSE ;
2016-07-31 15:48:50 +02:00
if ( HasHumanGibs ( ) )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
if ( CVAR_GET_FLOAT ( " violence_hgibs " ) = = 0.0f )
2016-06-04 15:24:23 +02:00
fade = TRUE ;
}
2016-07-31 15:48:50 +02:00
else if ( HasAlienGibs ( ) )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
if ( CVAR_GET_FLOAT ( " violence_agibs " ) = = 0.0f )
2016-06-04 15:24:23 +02:00
fade = TRUE ;
}
pev - > takedamage = DAMAGE_NO ;
pev - > solid = SOLID_NOT ; // do something with the body. while monster blows up
2016-07-31 15:48:50 +02:00
if ( fade )
2016-06-04 15:24:23 +02:00
{
FadeMonster ( ) ;
}
else
{
pev - > effects = EF_NODRAW ; // make the model invisible.
GibMonster ( ) ;
}
pev - > deadflag = DEAD_DEAD ;
FCheckAITrigger ( ) ;
// don't let the status bar glitch for players.with <0 health.
2016-07-31 15:48:50 +02:00
if ( pev - > health < - 99 )
2016-06-04 15:24:23 +02:00
{
pev - > health = 0 ;
}
2016-07-31 15:48:50 +02:00
if ( ShouldFadeOnDeath ( ) & & ! fade )
UTIL_Remove ( this ) ;
}
2016-06-04 15:24:23 +02:00
/*
= = = = = = = = = = = =
Killed
= = = = = = = = = = = =
*/
2016-07-31 15:48:50 +02:00
void CBaseMonster : : Killed ( entvars_t * pevAttacker , int iGib )
2016-06-04 15:24:23 +02:00
{
2017-06-29 15:56:03 +02:00
//unsigned int cCount = 0;
//BOOL fDone = FALSE;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( HasMemory ( bits_MEMORY_KILLED ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ShouldGibMonster ( iGib ) )
2016-06-04 15:24:23 +02:00
CallGibMonster ( ) ;
return ;
}
Remember ( bits_MEMORY_KILLED ) ;
// clear the deceased's sound channels.(may have been firing or reloading when killed)
2016-07-31 15:48:50 +02:00
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " common/null.wav " , 1 , ATTN_NORM ) ;
2016-06-04 15:24:23 +02:00
m_IdealMonsterState = MONSTERSTATE_DEAD ;
// Make sure this condition is fired too (TakeDamage breaks out before this happens on death)
SetConditions ( bits_COND_LIGHT_DAMAGE ) ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
2016-07-31 15:48:50 +02:00
CBaseEntity * pOwner = CBaseEntity : : Instance ( pev - > owner ) ;
if ( pOwner )
2016-06-04 15:24:23 +02:00
{
pOwner - > DeathNotice ( pev ) ;
}
2016-07-31 15:48:50 +02:00
if ( ShouldGibMonster ( iGib ) )
2016-06-04 15:24:23 +02:00
{
CallGibMonster ( ) ;
return ;
}
2016-07-31 15:48:50 +02:00
else if ( pev - > flags & FL_MONSTER )
2016-06-04 15:24:23 +02:00
{
SetTouch ( NULL ) ;
BecomeDead ( ) ;
}
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// don't let the status bar glitch for players.with <0 health.
2016-07-31 15:48:50 +02:00
if ( pev - > health < - 99 )
2016-06-04 15:24:23 +02:00
{
pev - > health = 0 ;
}
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
//pev->enemy = ENT( pevAttacker );//why? (sjb)
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
m_IdealMonsterState = MONSTERSTATE_DEAD ;
}
//
// fade out - slowly fades a entity out, then removes it.
//
// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER!
// SET A FUTURE THINK AND A RENDERMODE!!
2016-07-31 15:48:50 +02:00
void CBaseEntity : : SUB_StartFadeOut ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pev - > rendermode = = kRenderNormal )
2016-06-04 15:24:23 +02:00
{
pev - > renderamt = 255 ;
pev - > rendermode = kRenderTransTexture ;
}
pev - > solid = SOLID_NOT ;
pev - > avelocity = g_vecZero ;
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 0.1f ;
2016-06-04 15:24:23 +02:00
SetThink ( & CBaseEntity : : SUB_FadeOut ) ;
}
2016-07-31 15:48:50 +02:00
void CBaseEntity : : SUB_FadeOut ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pev - > renderamt > 7 )
2016-06-04 15:24:23 +02:00
{
pev - > renderamt - = 7 ;
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 0.1f ;
2016-06-04 15:24:23 +02:00
}
else
{
pev - > renderamt = 0 ;
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 0.2f ;
2016-06-04 15:24:23 +02:00
SetThink ( & CBaseEntity : : SUB_Remove ) ;
}
}
//=========================================================
// WaitTillLand - in order to emit their meaty scent from
// the proper location, gibs should wait until they stop
// bouncing to emit their scent. That's what this function
// does.
//=========================================================
2016-07-31 15:48:50 +02:00
void CGib : : WaitTillLand ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! IsInWorld ( ) )
2016-06-04 15:24:23 +02:00
{
UTIL_Remove ( this ) ;
return ;
}
2016-07-31 15:48:50 +02:00
if ( pev - > velocity = = g_vecZero )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SetThink ( & CBaseEntity : : SUB_StartFadeOut ) ;
2016-06-04 15:24:23 +02:00
pev - > nextthink = gpGlobals - > time + m_lifeTime ;
// If you bleed, you stink!
2016-07-31 15:48:50 +02:00
if ( m_bloodColor ! = DONT_BLEED )
2016-06-04 15:24:23 +02:00
{
// ok, start stinkin!
2016-07-31 15:48:50 +02:00
CSoundEnt : : InsertSound ( bits_SOUND_MEAT , pev - > origin , 384 , 25 ) ;
2016-06-04 15:24:23 +02:00
}
}
else
{
// wait and check again in another half second.
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 0.5f ;
2016-06-04 15:24:23 +02:00
}
}
//
// Gib bounces on the ground or wall, sponges some blood down, too!
//
2016-07-31 15:48:50 +02:00
void CGib : : BounceGibTouch ( CBaseEntity * pOther )
2016-06-04 15:24:23 +02:00
{
Vector vecSpot ;
TraceResult tr ;
2016-07-31 15:48:50 +02:00
//if( RANDOM_LONG( 0, 1 ) )
2016-06-04 15:24:23 +02:00
// return;// don't bleed everytime
2016-07-31 15:48:50 +02:00
if ( pev - > flags & FL_ONGROUND )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
pev - > velocity = pev - > velocity * 0.9f ;
pev - > angles . x = 0.0f ;
pev - > angles . z = 0.0f ;
pev - > avelocity . x = 0.0f ;
pev - > avelocity . z = 0.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
2024-02-23 23:22:52 +01:00
if ( m_cBloodDecals > 0 & & m_bloodColor ! = DONT_BLEED )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
vecSpot = pev - > origin + Vector ( 0.0f , 0.0f , 8.0f ) ; //move up a bit, and trace down.
UTIL_TraceLine ( vecSpot , vecSpot + Vector ( 0.0f , 0.0f , - 24.0f ) , ignore_monsters , ENT ( pev ) , & tr ) ;
2016-06-04 15:24:23 +02:00
UTIL_BloodDecalTrace ( & tr , m_bloodColor ) ;
m_cBloodDecals - - ;
}
2016-07-31 15:48:50 +02:00
if ( m_material ! = matNone & & RANDOM_LONG ( 0 , 2 ) = = 0 )
2016-06-04 15:24:23 +02:00
{
float volume ;
2016-07-31 15:48:50 +02:00
float zvel = fabs ( pev - > velocity . z ) ;
2019-10-13 13:49:25 +02:00
volume = 0.8f * Q_min ( 1.0f , zvel / 450.0f ) ;
2016-06-04 15:24:23 +02:00
CBreakable : : MaterialSoundRandom ( edict ( ) , ( Materials ) m_material , volume ) ;
}
}
}
//
// Sticky gib puts blood on the wall and stays put.
//
2016-07-31 15:48:50 +02:00
void CGib : : StickyGibTouch ( CBaseEntity * pOther )
2016-06-04 15:24:23 +02:00
{
Vector vecSpot ;
TraceResult tr ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
SetThink ( & CBaseEntity : : SUB_Remove ) ;
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 10.0f ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( ! FClassnameIs ( pOther - > pev , " worldspawn " ) )
2016-06-04 15:24:23 +02:00
{
pev - > nextthink = gpGlobals - > time ;
return ;
}
2019-10-13 13:49:25 +02:00
UTIL_TraceLine ( pev - > origin , pev - > origin + pev - > velocity * 32.0f , ignore_monsters , ENT ( pev ) , & tr ) ;
2016-06-04 15:24:23 +02:00
UTIL_BloodDecalTrace ( & tr , m_bloodColor ) ;
2019-10-13 13:49:25 +02:00
pev - > velocity = tr . vecPlaneNormal * - 1.0f ;
2016-07-31 15:48:50 +02:00
pev - > angles = UTIL_VecToAngles ( pev - > velocity ) ;
pev - > velocity = g_vecZero ;
2016-06-04 15:24:23 +02:00
pev - > avelocity = g_vecZero ;
pev - > movetype = MOVETYPE_NONE ;
}
//
// Throw a chunk
//
2016-07-31 15:48:50 +02:00
void CGib : : Spawn ( const char * szGibModel )
2016-06-04 15:24:23 +02:00
{
pev - > movetype = MOVETYPE_BOUNCE ;
2019-10-13 13:49:25 +02:00
pev - > friction = 0.55f ; // deading the bounce a bit
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// sometimes an entity inherits the edict from a former piece of glass,
// and will spawn using the same render FX or rendermode! bad!
pev - > renderamt = 255 ;
pev - > rendermode = kRenderNormal ;
pev - > renderfx = kRenderFxNone ;
pev - > solid = SOLID_SLIDEBOX ; /// hopefully this will fix the VELOCITY TOO LOW crap
2016-07-31 15:48:50 +02:00
pev - > classname = MAKE_STRING ( " gib " ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
SET_MODEL ( ENT ( pev ) , szGibModel ) ;
UTIL_SetSize ( pev , Vector ( 0 , 0 , 0 ) , Vector ( 0 , 0 , 0 ) ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
pev - > nextthink = gpGlobals - > time + 4.0f ;
2016-06-04 15:24:23 +02:00
m_lifeTime = 25 ;
SetThink ( & CGib : : WaitTillLand ) ;
SetTouch ( & CGib : : BounceGibTouch ) ;
m_material = matNone ;
m_cBloodDecals = 5 ; // how many blood decals this gib can place (1 per bounce until none remain).
}
// take health
2016-07-31 15:48:50 +02:00
int CBaseMonster : : TakeHealth ( float flHealth , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! pev - > takedamage )
2016-06-04 15:24:23 +02:00
return 0 ;
// clear out any damage types we healed.
// UNDONE: generic health should not heal any
// UNDONE: time-based damage
2016-07-31 15:48:50 +02:00
m_bitsDamageType & = ~ ( bitsDamageType & ~ DMG_TIMEBASED ) ;
return CBaseEntity : : TakeHealth ( flHealth , bitsDamageType ) ;
2016-06-04 15:24:23 +02:00
}
/*
= = = = = = = = = = = =
TakeDamage
The damage is coming from inflictor , but get mad at attacker
This should be the only function that ever reduces health .
bitsDamageType indicates the type of damage sustained , ie : DMG_SHOCK
Time - based damage : only occurs while the monster is within the trigger_hurt .
When a monster is poisoned via an arrow etc it takes all the poison damage at once .
GLOBALS ASSUMED SET : g_iSkillLevel
= = = = = = = = = = = =
*/
2016-07-31 15:48:50 +02:00
int CBaseMonster : : TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
float flTake ;
Vector vecDir ;
2016-07-31 15:48:50 +02:00
if ( ! pev - > takedamage )
2016-06-04 15:24:23 +02:00
return 0 ;
2016-07-31 15:48:50 +02:00
if ( ! IsAlive ( ) )
2016-06-04 15:24:23 +02:00
{
return DeadTakeDamage ( pevInflictor , pevAttacker , flDamage , bitsDamageType ) ;
}
2016-07-31 15:48:50 +02:00
if ( pev - > deadflag = = DEAD_NO )
2016-06-04 15:24:23 +02:00
{
// no pain sound during death animation.
PainSound ( ) ; // "Ouch!"
}
//!!!LATER - make armor consideration here!
flTake = flDamage ;
// set damage type sustained
m_bitsDamageType | = bitsDamageType ;
// grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit).
vecDir = Vector ( 0 , 0 , 0 ) ;
2016-07-31 15:48:50 +02:00
if ( ! FNullEnt ( pevInflictor ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CBaseEntity * pInflictor = CBaseEntity : : Instance ( pevInflictor ) ;
if ( pInflictor )
2016-06-04 15:24:23 +02:00
{
vecDir = ( pInflictor - > Center ( ) - Vector ( 0 , 0 , 10 ) - Center ( ) ) . Normalize ( ) ;
vecDir = g_vecAttackDir = vecDir . Normalize ( ) ;
}
}
// add to the damage total for clients, which will be sent as a single
// message at the end of the frame
// todo: remove after combining shotgun blasts?
2016-07-31 15:48:50 +02:00
if ( IsPlayer ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pevInflictor )
pev - > dmg_inflictor = ENT ( pevInflictor ) ;
2016-06-04 15:24:23 +02:00
pev - > dmg_take + = flTake ;
// check for godmode or invincibility
2016-07-31 15:48:50 +02:00
if ( pev - > flags & FL_GODMODE )
2016-06-04 15:24:23 +02:00
{
return 0 ;
}
}
// if this is a player, move him around!
2016-07-31 15:48:50 +02:00
if ( ( ! FNullEnt ( pevInflictor ) ) & & ( pev - > movetype = = MOVETYPE_WALK ) & & ( ! pevAttacker | | pevAttacker - > solid ! = SOLID_TRIGGER ) )
2016-06-04 15:24:23 +02:00
{
pev - > velocity = pev - > velocity + vecDir * - DamageForce ( flDamage ) ;
}
// do the damage
pev - > health - = flTake ;
// HACKHACK Don't kill monsters in a script. Let them break their scripts first
2016-07-31 15:48:50 +02:00
if ( m_MonsterState = = MONSTERSTATE_SCRIPT )
2016-06-04 15:24:23 +02:00
{
SetConditions ( bits_COND_LIGHT_DAMAGE ) ;
return 0 ;
}
2016-07-31 15:48:50 +02:00
if ( pev - > health < = 0 )
2016-06-04 15:24:23 +02:00
{
g_pevLastInflictor = pevInflictor ;
2016-07-31 15:48:50 +02:00
if ( bitsDamageType & DMG_ALWAYSGIB )
2016-06-04 15:24:23 +02:00
{
Killed ( pevAttacker , GIB_ALWAYS ) ;
}
2016-07-31 15:48:50 +02:00
else if ( bitsDamageType & DMG_NEVERGIB )
2016-06-04 15:24:23 +02:00
{
Killed ( pevAttacker , GIB_NEVER ) ;
}
else
{
Killed ( pevAttacker , GIB_NORMAL ) ;
}
g_pevLastInflictor = NULL ;
return 0 ;
}
// react to the damage (get mad)
2016-07-31 15:48:50 +02:00
if ( ( pev - > flags & FL_MONSTER ) & & ! FNullEnt ( pevAttacker ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pevAttacker - > flags & ( FL_MONSTER | FL_CLIENT ) )
{
// only if the attack was a monster or client!
2016-06-04 15:24:23 +02:00
// enemy's last known position is somewhere down the vector that the attack came from.
2016-07-31 15:48:50 +02:00
if ( pevInflictor )
2016-06-04 15:24:23 +02:00
{
2017-06-29 15:56:03 +02:00
if ( m_hEnemy = = 0 | | pevInflictor = = m_hEnemy - > pev | | ! HasConditions ( bits_COND_SEE_ENEMY ) )
2016-06-04 15:24:23 +02:00
{
m_vecEnemyLKP = pevInflictor - > origin ;
}
}
else
{
2019-10-13 13:49:25 +02:00
m_vecEnemyLKP = pev - > origin + ( g_vecAttackDir * 64.0f ) ;
2016-06-04 15:24:23 +02:00
}
MakeIdealYaw ( m_vecEnemyLKP ) ;
// add pain to the conditions
// !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and
// heavy damage per monster class?
2019-10-13 13:49:25 +02:00
if ( flDamage > 0.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SetConditions ( bits_COND_LIGHT_DAMAGE ) ;
2016-06-04 15:24:23 +02:00
}
2019-10-13 13:49:25 +02:00
if ( flDamage > = 20.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SetConditions ( bits_COND_HEAVY_DAMAGE ) ;
2016-06-04 15:24:23 +02:00
}
}
}
return 1 ;
}
//=========================================================
// DeadTakeDamage - takedamage function called when a monster's
// corpse is damaged.
//=========================================================
2016-07-31 15:48:50 +02:00
int CBaseMonster : : DeadTakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
Vector vecDir ;
2016-06-04 15:24:23 +02:00
// grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit).
vecDir = Vector ( 0 , 0 , 0 ) ;
2016-07-31 15:48:50 +02:00
if ( ! FNullEnt ( pevInflictor ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CBaseEntity * pInflictor = CBaseEntity : : Instance ( pevInflictor ) ;
if ( pInflictor )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
vecDir = ( pInflictor - > Center ( ) - Vector ( 0.0f , 0.0f , 10.0f ) - Center ( ) ) . Normalize ( ) ;
2016-06-04 15:24:23 +02:00
vecDir = g_vecAttackDir = vecDir . Normalize ( ) ;
}
}
#if 0 // turn this back on when the bounding box issues are resolved.
pev - > flags & = ~ FL_ONGROUND ;
2019-10-13 13:49:25 +02:00
pev - > origin . z + = 1.0f ;
2016-06-04 15:24:23 +02:00
// let the damage scoot the corpse around a bit.
2016-07-31 15:48:50 +02:00
if ( ! FNullEnt ( pevInflictor ) & & ( pevAttacker - > solid ! = SOLID_TRIGGER ) )
2016-06-04 15:24:23 +02:00
{
pev - > velocity = pev - > velocity + vecDir * - DamageForce ( flDamage ) ;
}
# endif
// kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse.
2016-07-31 15:48:50 +02:00
if ( bitsDamageType & DMG_GIB_CORPSE )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pev - > health < = flDamage )
2016-06-04 15:24:23 +02:00
{
pev - > health = - 50 ;
Killed ( pevAttacker , GIB_ALWAYS ) ;
return 0 ;
}
// Accumulate corpse gibbing damage, so you can gib with multiple hits
2019-10-13 13:49:25 +02:00
pev - > health - = flDamage * 0.1f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
return 1 ;
}
2016-07-31 15:48:50 +02:00
float CBaseMonster : : DamageForce ( float damage )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
float force = damage * ( ( 32.0f * 32.0f * 72.0f ) / ( pev - > size . x * pev - > size . y * pev - > size . z ) ) * 5.0f ;
2016-07-31 15:48:50 +02:00
2019-10-13 13:49:25 +02:00
if ( force > 1000.0f )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
force = 1000.0f ;
2016-06-04 15:24:23 +02:00
}
return force ;
}
//
// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range.
//
// only damage ents that can clearly be seen by the explosion!
void RadiusDamage ( Vector vecSrc , entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , float flRadius , int iClassIgnore , int bitsDamageType )
{
CBaseEntity * pEntity = NULL ;
TraceResult tr ;
float flAdjustedDamage , falloff ;
Vector vecSpot ;
2016-07-31 15:48:50 +02:00
if ( flRadius )
2016-06-04 15:24:23 +02:00
falloff = flDamage / flRadius ;
else
2019-10-13 13:49:25 +02:00
falloff = 1.0f ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
int bInWater = ( UTIL_PointContents ( vecSrc ) = = CONTENTS_WATER ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
vecSrc . z + = 1.0f ; // in case grenade is lying on the ground
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( ! pevAttacker )
2016-06-04 15:24:23 +02:00
pevAttacker = pevInflictor ;
// iterate on all entities in the vicinity.
2016-07-31 15:48:50 +02:00
while ( ( pEntity = UTIL_FindEntityInSphere ( pEntity , vecSrc , flRadius ) ) ! = NULL )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pEntity - > pev - > takedamage ! = DAMAGE_NO )
2016-06-04 15:24:23 +02:00
{
// UNDONE: this should check a damage mask, not an ignore
2016-07-31 15:48:50 +02:00
if ( iClassIgnore ! = CLASS_NONE & & pEntity - > Classify ( ) = = iClassIgnore )
{
// houndeyes don't hurt other houndeyes with their attack
2016-06-04 15:24:23 +02:00
continue ;
}
// blast's don't tavel into or out of water
2016-07-31 15:48:50 +02:00
if ( bInWater & & pEntity - > pev - > waterlevel = = 0 )
2016-06-04 15:24:23 +02:00
continue ;
2016-07-31 15:48:50 +02:00
if ( ! bInWater & & pEntity - > pev - > waterlevel = = 3 )
2016-06-04 15:24:23 +02:00
continue ;
vecSpot = pEntity - > BodyTarget ( vecSrc ) ;
2016-07-31 15:48:50 +02:00
UTIL_TraceLine ( vecSrc , vecSpot , dont_ignore_monsters , ENT ( pevInflictor ) , & tr ) ;
2019-10-13 13:49:25 +02:00
if ( tr . flFraction = = 1.0f | | tr . pHit = = pEntity - > edict ( ) )
2016-07-31 15:48:50 +02:00
{
// the explosion can 'see' this entity, so hurt them!
if ( tr . fStartSolid )
2016-06-04 15:24:23 +02:00
{
// if we're stuck inside them, fixup the position and distance
tr . vecEndPos = vecSrc ;
2019-10-13 13:49:25 +02:00
tr . flFraction = 0.0f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// decrease damage for an ent that's farther from the bomb.
flAdjustedDamage = ( vecSrc - tr . vecEndPos ) . Length ( ) * falloff ;
flAdjustedDamage = flDamage - flAdjustedDamage ;
2016-07-31 15:48:50 +02:00
2019-10-13 13:49:25 +02:00
if ( flAdjustedDamage < 0.0f )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
flAdjustedDamage = 0.0f ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ClearMultiDamage ( ) ;
pEntity - > TraceAttack ( pevInflictor , flAdjustedDamage , ( tr . vecEndPos - vecSrc ) . Normalize ( ) , & tr , bitsDamageType ) ;
2016-06-04 15:24:23 +02:00
ApplyMultiDamage ( pevInflictor , pevAttacker ) ;
}
else
{
pEntity - > TakeDamage ( pevInflictor , pevAttacker , flAdjustedDamage , bitsDamageType ) ;
}
}
}
}
}
2016-07-31 15:48:50 +02:00
void CBaseMonster : : RadiusDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int iClassIgnore , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
: : RadiusDamage ( pev - > origin , pevInflictor , pevAttacker , flDamage , flDamage * 2.5f , iClassIgnore , bitsDamageType ) ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
void CBaseMonster : : RadiusDamage ( Vector vecSrc , entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int iClassIgnore , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
: : RadiusDamage ( vecSrc , pevInflictor , pevAttacker , flDamage , flDamage * 2.5f , iClassIgnore , bitsDamageType ) ;
2016-06-04 15:24:23 +02:00
}
//=========================================================
// CheckTraceHullAttack - expects a length to trace, amount
// of damage to do, and damage type. Returns a pointer to
// the damaged entity in case the monster wishes to do
// other stuff to the victim (punchangle, etc)
//
// Used for many contact-range melee attacks. Bites, claws, etc.
//=========================================================
2016-07-31 15:48:50 +02:00
CBaseEntity * CBaseMonster : : CheckTraceHullAttack ( float flDist , int iDamage , int iDmgType )
2016-06-04 15:24:23 +02:00
{
TraceResult tr ;
2016-07-31 15:48:50 +02:00
if ( IsPlayer ( ) )
2016-06-04 15:24:23 +02:00
UTIL_MakeVectors ( pev - > angles ) ;
else
UTIL_MakeAimVectors ( pev - > angles ) ;
Vector vecStart = pev - > origin ;
2019-10-13 13:49:25 +02:00
vecStart . z + = pev - > size . z * 0.5f ;
2016-07-31 15:48:50 +02:00
Vector vecEnd = vecStart + ( gpGlobals - > v_forward * flDist ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
UTIL_TraceHull ( vecStart , vecEnd , dont_ignore_monsters , head_hull , ENT ( pev ) , & tr ) ;
if ( tr . pHit )
2016-06-04 15:24:23 +02:00
{
CBaseEntity * pEntity = CBaseEntity : : Instance ( tr . pHit ) ;
2016-07-31 15:48:50 +02:00
if ( iDamage > 0 )
2016-06-04 15:24:23 +02:00
{
pEntity - > TakeDamage ( pev , pev , iDamage , iDmgType ) ;
}
return pEntity ;
}
return NULL ;
}
//=========================================================
// FInViewCone - returns true is the passed ent is in
// the caller's forward view cone. The dot product is performed
// in 2d, making the view cone infinitely tall.
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CBaseMonster : : FInViewCone ( CBaseEntity * pEntity )
2016-06-04 15:24:23 +02:00
{
Vector2D vec2LOS ;
float flDot ;
2016-07-31 15:48:50 +02:00
UTIL_MakeVectors ( pev - > angles ) ;
2016-06-04 15:24:23 +02:00
vec2LOS = ( pEntity - > pev - > origin - pev - > origin ) . Make2D ( ) ;
vec2LOS = vec2LOS . Normalize ( ) ;
2016-07-31 15:48:50 +02:00
flDot = DotProduct ( vec2LOS , gpGlobals - > v_forward . Make2D ( ) ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( flDot > m_flFieldOfView )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
else
{
return FALSE ;
}
}
//=========================================================
// FInViewCone - returns true is the passed vector is in
// the caller's forward view cone. The dot product is performed
// in 2d, making the view cone infinitely tall.
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CBaseMonster : : FInViewCone ( Vector * pOrigin )
2016-06-04 15:24:23 +02:00
{
Vector2D vec2LOS ;
float flDot ;
2016-07-31 15:48:50 +02:00
UTIL_MakeVectors ( pev - > angles ) ;
2016-06-04 15:24:23 +02:00
vec2LOS = ( * pOrigin - pev - > origin ) . Make2D ( ) ;
vec2LOS = vec2LOS . Normalize ( ) ;
2016-07-31 15:48:50 +02:00
flDot = DotProduct ( vec2LOS , gpGlobals - > v_forward . Make2D ( ) ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( flDot > m_flFieldOfView )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
else
{
return FALSE ;
}
}
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the target
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CBaseEntity : : FVisible ( CBaseEntity * pEntity )
2016-06-04 15:24:23 +02:00
{
TraceResult tr ;
Vector vecLookerOrigin ;
Vector vecTargetOrigin ;
2016-07-31 15:48:50 +02:00
if ( ! pEntity )
2016-02-29 21:04:01 +01:00
return FALSE ;
2016-07-31 15:48:50 +02:00
if ( ! pEntity - > pev )
2016-02-29 21:04:01 +01:00
return FALSE ;
2016-07-31 15:48:50 +02:00
if ( FBitSet ( pEntity - > pev - > flags , FL_NOTARGET ) )
2016-06-04 15:24:23 +02:00
return FALSE ;
// don't look through water
2016-07-31 15:48:50 +02:00
if ( ( pev - > waterlevel ! = 3 & & pEntity - > pev - > waterlevel = = 3 )
| | ( pev - > waterlevel = = 3 & & pEntity - > pev - > waterlevel = = 0 ) )
2016-06-04 15:24:23 +02:00
return FALSE ;
vecLookerOrigin = pev - > origin + pev - > view_ofs ; //look through the caller's 'eyes'
vecTargetOrigin = pEntity - > EyePosition ( ) ;
2016-07-31 15:48:50 +02:00
UTIL_TraceLine ( vecLookerOrigin , vecTargetOrigin , ignore_monsters , ignore_glass , ENT ( pev ) /*pentIgnore*/ , & tr ) ;
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
return FALSE ; // Line of sight is not established
}
else
{
return TRUE ; // line of sight is valid.
}
}
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the target vector
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CBaseEntity : : FVisible ( const Vector & vecOrigin )
2016-06-04 15:24:23 +02:00
{
TraceResult tr ;
Vector vecLookerOrigin ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
vecLookerOrigin = EyePosition ( ) ; //look through the caller's 'eyes'
2016-07-31 15:48:50 +02:00
UTIL_TraceLine ( vecLookerOrigin , vecOrigin , ignore_monsters , ignore_glass , ENT ( pev ) /*pentIgnore*/ , & tr ) ;
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
return FALSE ; // Line of sight is not established
}
else
{
return TRUE ; // line of sight is valid.
}
}
/*
= = = = = = = = = = = = = = = =
TraceAttack
= = = = = = = = = = = = = = = =
*/
void CBaseEntity : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
{
2019-10-13 13:49:25 +02:00
Vector vecOrigin = ptr - > vecEndPos - vecDir * 4.0f ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pev - > takedamage )
2016-06-04 15:24:23 +02:00
{
AddMultiDamage ( pevAttacker , this , flDamage , bitsDamageType ) ;
int blood = BloodColor ( ) ;
2016-07-31 15:48:50 +02:00
if ( blood ! = DONT_BLEED )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SpawnBlood ( vecOrigin , blood , flDamage ) ; // a little surface blood.
2016-06-04 15:24:23 +02:00
TraceBleed ( flDamage , vecDir , ptr , bitsDamageType ) ;
}
}
}
/*
//=========================================================
// TraceAttack
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
Vector vecOrigin = ptr - > vecEndPos - vecDir * 4.0f ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
ALERT ( at_console , " %d \n " , ptr - > iHitgroup ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pev - > takedamage )
2016-06-04 15:24:23 +02:00
{
AddMultiDamage ( pevAttacker , this , flDamage , bitsDamageType ) ;
int blood = BloodColor ( ) ;
2016-07-31 15:48:50 +02:00
if ( blood ! = DONT_BLEED )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SpawnBlood ( vecOrigin , blood , flDamage ) ; // a little surface blood.
2016-06-04 15:24:23 +02:00
}
}
}
*/
//=========================================================
// TraceAttack
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pev - > takedamage )
2016-06-04 15:24:23 +02:00
{
m_LastHitGroup = ptr - > iHitgroup ;
2016-07-31 15:48:50 +02:00
switch ( ptr - > iHitgroup )
2016-06-04 15:24:23 +02:00
{
case HITGROUP_GENERIC :
break ;
case HITGROUP_HEAD :
flDamage * = gSkillData . monHead ;
break ;
case HITGROUP_CHEST :
flDamage * = gSkillData . monChest ;
break ;
case HITGROUP_STOMACH :
flDamage * = gSkillData . monStomach ;
break ;
case HITGROUP_LEFTARM :
case HITGROUP_RIGHTARM :
flDamage * = gSkillData . monArm ;
break ;
case HITGROUP_LEFTLEG :
case HITGROUP_RIGHTLEG :
flDamage * = gSkillData . monLeg ;
break ;
default :
break ;
}
2016-07-31 15:48:50 +02:00
SpawnBlood ( ptr - > vecEndPos , BloodColor ( ) , flDamage ) ; // a little surface blood.
2016-06-04 15:24:23 +02:00
TraceBleed ( flDamage , vecDir , ptr , bitsDamageType ) ;
AddMultiDamage ( pevAttacker , this , flDamage , bitsDamageType ) ;
}
}
/*
= = = = = = = = = = = = = = = =
FireBullets
Go to the trouble of combining multiple pellets into a single damage call .
This version is used by Monsters .
= = = = = = = = = = = = = = = =
*/
2016-07-31 15:48:50 +02:00
void CBaseEntity : : FireBullets ( ULONG cShots , Vector vecSrc , Vector vecDirShooting , Vector vecSpread , float flDistance , int iBulletType , int iTracerFreq , int iDamage , entvars_t * pevAttacker )
2016-06-04 15:24:23 +02:00
{
static int tracerCount ;
int tracer ;
TraceResult tr ;
Vector vecRight = gpGlobals - > v_right ;
Vector vecUp = gpGlobals - > v_up ;
2016-07-31 15:48:50 +02:00
if ( pevAttacker = = NULL )
2016-06-04 15:24:23 +02:00
pevAttacker = pev ; // the default attacker is ourselves
ClearMultiDamage ( ) ;
gMultiDamage . type = DMG_BULLET | DMG_NEVERGIB ;
2016-07-31 15:48:50 +02:00
for ( ULONG iShot = 1 ; iShot < = cShots ; iShot + + )
2016-06-04 15:24:23 +02:00
{
// get circular gaussian spread
float x , y , z ;
do {
2019-10-13 13:49:25 +02:00
x = RANDOM_FLOAT ( - 0.5f , 0.5f ) + RANDOM_FLOAT ( - 0.5f , 0.5f ) ;
y = RANDOM_FLOAT ( - 0.5f , 0.5f ) + RANDOM_FLOAT ( - 0.5f , 0.5f ) ;
2016-07-31 15:48:50 +02:00
z = x * x + y * y ;
2016-06-04 15:24:23 +02:00
} while ( z > 1 ) ;
Vector vecDir = vecDirShooting +
x * vecSpread . x * vecRight +
y * vecSpread . y * vecUp ;
Vector vecEnd ;
vecEnd = vecSrc + vecDir * flDistance ;
2016-07-31 15:48:50 +02:00
UTIL_TraceLine ( vecSrc , vecEnd , dont_ignore_monsters , ENT ( pev ) /*pentIgnore*/ , & tr ) ;
2016-06-04 15:24:23 +02:00
tracer = 0 ;
2016-07-31 15:48:50 +02:00
if ( iTracerFreq ! = 0 & & ( tracerCount + + % iTracerFreq ) = = 0 )
2016-06-04 15:24:23 +02:00
{
Vector vecTracerSrc ;
2016-07-31 15:48:50 +02:00
if ( IsPlayer ( ) )
{
// adjust tracer position for player
2019-10-13 13:49:25 +02:00
vecTracerSrc = vecSrc + Vector ( 0.0f , 0.0f , - 4.0f ) + gpGlobals - > v_right * 2.0f + gpGlobals - > v_forward * 16.0f ;
2016-06-04 15:24:23 +02:00
}
else
{
vecTracerSrc = vecSrc ;
}
2016-07-31 15:48:50 +02:00
if ( iTracerFreq ! = 1 ) // guns that always trace also always decal
2016-06-04 15:24:23 +02:00
tracer = 1 ;
switch ( iBulletType )
{
case BULLET_MONSTER_MP5 :
case BULLET_MONSTER_9MM :
case BULLET_MONSTER_12MM :
default :
MESSAGE_BEGIN ( MSG_PAS , SVC_TEMPENTITY , vecTracerSrc ) ;
WRITE_BYTE ( TE_TRACER ) ;
WRITE_COORD ( vecTracerSrc . x ) ;
WRITE_COORD ( vecTracerSrc . y ) ;
WRITE_COORD ( vecTracerSrc . z ) ;
WRITE_COORD ( tr . vecEndPos . x ) ;
WRITE_COORD ( tr . vecEndPos . y ) ;
WRITE_COORD ( tr . vecEndPos . z ) ;
MESSAGE_END ( ) ;
break ;
}
}
// do damage, paint decals
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CBaseEntity * pEntity = CBaseEntity : : Instance ( tr . pHit ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( iDamage )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
pEntity - > TraceAttack ( pevAttacker , iDamage , vecDir , & tr , DMG_BULLET | ( ( iDamage > 16 ) ? DMG_ALWAYSGIB : DMG_NEVERGIB ) ) ;
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
2016-06-04 15:24:23 +02:00
DecalGunshot ( & tr , iBulletType ) ;
}
2016-07-31 15:48:50 +02:00
else switch ( iBulletType )
2016-06-04 15:24:23 +02:00
{
default :
case BULLET_MONSTER_9MM :
2016-07-31 15:48:50 +02:00
pEntity - > TraceAttack ( pevAttacker , gSkillData . monDmg9MM , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
DecalGunshot ( & tr , iBulletType ) ;
2016-06-04 15:24:23 +02:00
break ;
case BULLET_MONSTER_MP5 :
2016-07-31 15:48:50 +02:00
pEntity - > TraceAttack ( pevAttacker , gSkillData . monDmgMP5 , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
DecalGunshot ( & tr , iBulletType ) ;
2016-06-04 15:24:23 +02:00
break ;
2016-07-31 15:48:50 +02:00
case BULLET_MONSTER_12MM :
pEntity - > TraceAttack ( pevAttacker , gSkillData . monDmg12MM , vecDir , & tr , DMG_BULLET ) ;
if ( ! tracer )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
2016-06-04 15:24:23 +02:00
DecalGunshot ( & tr , iBulletType ) ;
}
break ;
2016-07-31 15:48:50 +02:00
case BULLET_NONE : // FIX
pEntity - > TraceAttack ( pevAttacker , 50 , vecDir , & tr , DMG_CLUB ) ;
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
2016-06-04 15:24:23 +02:00
// only decal glass
2016-07-31 15:48:50 +02:00
if ( ! FNullEnt ( tr . pHit ) & & VARS ( tr . pHit ) - > rendermode ! = 0 )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
UTIL_DecalTrace ( & tr , DECAL_GLASSBREAK1 + RANDOM_LONG ( 0 , 2 ) ) ;
2016-06-04 15:24:23 +02:00
}
break ;
}
}
// make bullet trails
2019-10-13 13:49:25 +02:00
UTIL_BubbleTrail ( vecSrc , tr . vecEndPos , ( int ) ( ( flDistance * tr . flFraction ) / 64.0f ) ) ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
ApplyMultiDamage ( pev , pevAttacker ) ;
2016-06-04 15:24:23 +02:00
}
/*
= = = = = = = = = = = = = = = =
FireBullets
Go to the trouble of combining multiple pellets into a single damage call .
This version is used by Players , uses the random seed generator to sync client and server side shots .
= = = = = = = = = = = = = = = =
*/
2016-07-31 15:48:50 +02:00
Vector CBaseEntity : : FireBulletsPlayer ( ULONG cShots , Vector vecSrc , Vector vecDirShooting , Vector vecSpread , float flDistance , int iBulletType , int iTracerFreq , int iDamage , entvars_t * pevAttacker , int shared_rand )
2016-06-04 15:24:23 +02:00
{
static int tracerCount ;
TraceResult tr ;
Vector vecRight = gpGlobals - > v_right ;
Vector vecUp = gpGlobals - > v_up ;
2017-06-29 15:56:03 +02:00
float x = 0.0f , y = 0.0f ;
2021-06-18 10:00:09 +02:00
//float z;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pevAttacker = = NULL )
2016-06-04 15:24:23 +02:00
pevAttacker = pev ; // the default attacker is ourselves
ClearMultiDamage ( ) ;
gMultiDamage . type = DMG_BULLET | DMG_NEVERGIB ;
2016-07-31 15:48:50 +02:00
for ( ULONG iShot = 1 ; iShot < = cShots ; iShot + + )
2016-06-04 15:24:23 +02:00
{
//Use player's random seed.
// get circular gaussian spread
2019-10-13 13:49:25 +02:00
x = UTIL_SharedRandomFloat ( shared_rand + iShot , - 0.5f , 0.5f ) + UTIL_SharedRandomFloat ( shared_rand + ( 1 + iShot ) , - 0.5f , 0.5f ) ;
y = UTIL_SharedRandomFloat ( shared_rand + ( 2 + iShot ) , - 0.5f , 0.5f ) + UTIL_SharedRandomFloat ( shared_rand + ( 3 + iShot ) , - 0.5f , 0.5f ) ;
2017-06-29 15:56:03 +02:00
//z = x * x + y * y;
2016-06-04 15:24:23 +02:00
Vector vecDir = vecDirShooting +
x * vecSpread . x * vecRight +
y * vecSpread . y * vecUp ;
Vector vecEnd ;
vecEnd = vecSrc + vecDir * flDistance ;
2016-07-31 15:48:50 +02:00
UTIL_TraceLine ( vecSrc , vecEnd , dont_ignore_monsters , ENT ( pev ) /*pentIgnore*/ , & tr ) ;
2016-06-04 15:24:23 +02:00
// do damage, paint decals
2019-10-13 13:49:25 +02:00
if ( tr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CBaseEntity * pEntity = CBaseEntity : : Instance ( tr . pHit ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( iDamage )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
pEntity - > TraceAttack ( pevAttacker , iDamage , vecDir , & tr , DMG_BULLET | ( ( iDamage > 16 ) ? DMG_ALWAYSGIB : DMG_NEVERGIB ) ) ;
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
2016-06-04 15:24:23 +02:00
DecalGunshot ( & tr , iBulletType ) ;
}
2016-07-31 15:48:50 +02:00
else switch ( iBulletType )
2016-06-04 15:24:23 +02:00
{
default :
2016-07-31 15:48:50 +02:00
case BULLET_PLAYER_9MM :
pEntity - > TraceAttack ( pevAttacker , gSkillData . plrDmg9MM , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
break ;
2016-07-31 15:48:50 +02:00
case BULLET_PLAYER_MP5 :
pEntity - > TraceAttack ( pevAttacker , gSkillData . plrDmgMP5 , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
break ;
2016-07-31 15:48:50 +02:00
case BULLET_PLAYER_BUCKSHOT :
2016-06-04 15:24:23 +02:00
// make distance based!
2016-07-31 15:48:50 +02:00
pEntity - > TraceAttack ( pevAttacker , gSkillData . plrDmgBuckshot , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
break ;
2016-07-31 15:48:50 +02:00
case BULLET_PLAYER_357 :
pEntity - > TraceAttack ( pevAttacker , gSkillData . plrDmg357 , vecDir , & tr , DMG_BULLET ) ;
2016-06-04 15:24:23 +02:00
break ;
2016-07-31 15:48:50 +02:00
case BULLET_NONE : // FIX
pEntity - > TraceAttack ( pevAttacker , 50 , vecDir , & tr , DMG_CLUB ) ;
TEXTURETYPE_PlaySound ( & tr , vecSrc , vecEnd , iBulletType ) ;
2016-06-04 15:24:23 +02:00
// only decal glass
2016-07-31 15:48:50 +02:00
if ( ! FNullEnt ( tr . pHit ) & & VARS ( tr . pHit ) - > rendermode ! = 0 )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
UTIL_DecalTrace ( & tr , DECAL_GLASSBREAK1 + RANDOM_LONG ( 0 , 2 ) ) ;
2016-06-04 15:24:23 +02:00
}
break ;
}
}
// make bullet trails
2019-10-13 13:49:25 +02:00
UTIL_BubbleTrail ( vecSrc , tr . vecEndPos , ( int ) ( ( flDistance * tr . flFraction ) / 64.0f ) ) ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
ApplyMultiDamage ( pev , pevAttacker ) ;
2016-06-04 15:24:23 +02:00
return Vector ( x * vecSpread . x , y * vecSpread . y , 0.0 ) ;
}
2016-07-31 15:48:50 +02:00
void CBaseEntity : : TraceBleed ( float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( BloodColor ( ) = = DONT_BLEED )
2016-06-04 15:24:23 +02:00
return ;
2016-07-31 15:48:50 +02:00
if ( flDamage = = 0 )
2016-06-04 15:24:23 +02:00
return ;
2016-07-31 15:48:50 +02:00
if ( ! ( bitsDamageType & ( DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR ) ) )
2016-06-04 15:24:23 +02:00
return ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// make blood decal on the wall!
TraceResult Bloodtr ;
Vector vecTraceDir ;
float flNoise ;
int cCount ;
int i ;
/*
2016-07-31 15:48:50 +02:00
if ( ! IsAlive ( ) )
2016-06-04 15:24:23 +02:00
{
// dealing with a dead monster.
2016-07-31 15:48:50 +02:00
if ( pev - > max_health < = 0 )
2016-06-04 15:24:23 +02:00
{
// no blood decal for a monster that has already decalled its limit.
return ;
}
else
{
pev - > max_health - - ;
}
}
*/
2019-10-13 13:49:25 +02:00
if ( flDamage < 10.0f )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
flNoise = 0.1f ;
2016-06-04 15:24:23 +02:00
cCount = 1 ;
}
2019-10-13 13:49:25 +02:00
else if ( flDamage < 25.0f )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
flNoise = 0.2f ;
2016-06-04 15:24:23 +02:00
cCount = 2 ;
}
else
{
2019-10-13 13:49:25 +02:00
flNoise = 0.3f ;
2016-06-04 15:24:23 +02:00
cCount = 4 ;
}
2016-07-31 15:48:50 +02:00
for ( i = 0 ; i < cCount ; i + + )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
vecTraceDir = vecDir * - 1.0f ; // trace in the opposite direction the shot came from (the direction the shot is going)
2016-06-04 15:24:23 +02:00
vecTraceDir . x + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
vecTraceDir . y + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
vecTraceDir . z + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
2019-10-13 13:49:25 +02:00
UTIL_TraceLine ( ptr - > vecEndPos , ptr - > vecEndPos + vecTraceDir * - 172.0f , ignore_monsters , ENT ( pev ) , & Bloodtr ) ;
2016-06-04 15:24:23 +02:00
2019-10-13 13:49:25 +02:00
if ( Bloodtr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
UTIL_BloodDecalTrace ( & Bloodtr , BloodColor ( ) ) ;
}
}
}
//=========================================================
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster : : MakeDamageBloodDecal ( int cCount , float flNoise , TraceResult * ptr , const Vector & vecDir )
2016-06-04 15:24:23 +02:00
{
// make blood decal on the wall!
TraceResult Bloodtr ;
Vector vecTraceDir ;
int i ;
2016-07-31 15:48:50 +02:00
if ( ! IsAlive ( ) )
2016-06-04 15:24:23 +02:00
{
// dealing with a dead monster.
2016-07-31 15:48:50 +02:00
if ( pev - > max_health < = 0 )
2016-06-04 15:24:23 +02:00
{
// no blood decal for a monster that has already decalled its limit.
return ;
}
else
{
pev - > max_health - - ;
}
}
2016-07-31 15:48:50 +02:00
for ( i = 0 ; i < cCount ; i + + )
2016-06-04 15:24:23 +02:00
{
vecTraceDir = vecDir ;
vecTraceDir . x + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
vecTraceDir . y + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
vecTraceDir . z + = RANDOM_FLOAT ( - flNoise , flNoise ) ;
2019-10-13 13:49:25 +02:00
UTIL_TraceLine ( ptr - > vecEndPos , ptr - > vecEndPos + vecTraceDir * 172.0f , ignore_monsters , ENT ( pev ) , & Bloodtr ) ;
2016-06-04 15:24:23 +02:00
/*
MESSAGE_BEGIN ( MSG_BROADCAST , SVC_TEMPENTITY ) ;
WRITE_BYTE ( TE_SHOWLINE ) ;
WRITE_COORD ( ptr - > vecEndPos . x ) ;
WRITE_COORD ( ptr - > vecEndPos . y ) ;
WRITE_COORD ( ptr - > vecEndPos . z ) ;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
WRITE_COORD ( Bloodtr . vecEndPos . x ) ;
WRITE_COORD ( Bloodtr . vecEndPos . y ) ;
WRITE_COORD ( Bloodtr . vecEndPos . z ) ;
MESSAGE_END ( ) ;
*/
2019-10-13 13:49:25 +02:00
if ( Bloodtr . flFraction ! = 1.0f )
2016-06-04 15:24:23 +02:00
{
UTIL_BloodDecalTrace ( & Bloodtr , BloodColor ( ) ) ;
}
}
}