Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1892 lines
50 KiB

9 years ago
/***
*
* 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"
#include "game.h"
9 years ago
extern DLL_GLOBAL Vector g_vecAttackDir;
extern DLL_GLOBAL int g_iSkillLevel;
8 years ago
extern Vector VecBModelOrigin( entvars_t *pevBModel );
9 years ago
extern entvars_t *g_pevLastInflictor;
//modif de Julien
extern void ClientDecal ( TraceResult *pTrace, Vector vecSrc, Vector vecEnd, int crowbar = 0 );
9 years ago
#define GERMAN_GIB_COUNT 4
#define HUMAN_GIB_COUNT 6
#define ALIEN_GIB_COUNT 4
// HACKHACK -- The gib velocity equations don't work
8 years ago
void CGib::LimitVelocity( void )
9 years ago
{
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.
if( length > 1500.0f )
pev->velocity = pev->velocity.Normalize() * 1500.0f; // This should really be sv_maxvelocity * 0.75 or something
9 years ago
}
8 years ago
void CGib::SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs )
9 years ago
{
int i;
8 years ago
if( g_Language == LANGUAGE_GERMAN )
9 years ago
{
// no sticky gibs in germany right now!
return;
}
8 years ago
for( i = 0; i < cGibs; i++ )
9 years ago
{
CGib *pGib = GetClassPtr( (CGib *)NULL );
pGib->Spawn( "models/stickygib.mdl" );
8 years ago
pGib->pev->body = RANDOM_LONG( 0, 2 );
9 years ago
8 years ago
if( pevVictim )
9 years ago
{
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 );
9 years ago
/*
8 years ago
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 ) );
9 years ago
*/
// make the gib fly away from the attack vector
pGib->pev->velocity = g_vecAttackDir * -1.0f;
9 years ago
// mix in some noise
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 );
9 years ago
pGib->pev->velocity = pGib->pev->velocity * 900.0f;
9 years ago
pGib->pev->avelocity.x = RANDOM_FLOAT( 250.0f, 400.0f );
pGib->pev->avelocity.y = RANDOM_FLOAT( 250.0f, 400.0f );
9 years ago
// copy owner's blood color
8 years ago
pGib->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor();
if( pevVictim->health > -50 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 0.7f;
9 years ago
}
8 years ago
else if( pevVictim->health > -200 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 2.0f;
9 years ago
}
else
{
pGib->pev->velocity = pGib->pev->velocity * 4.0f;
9 years ago
}
pGib->pev->movetype = MOVETYPE_TOSS;
pGib->pev->solid = SOLID_BBOX;
8 years ago
UTIL_SetSize( pGib->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
9 years ago
pGib->SetTouch( &CGib::StickyGibTouch );
pGib->SetThink( NULL );
}
pGib->LimitVelocity();
}
}
8 years ago
void CGib::SpawnHeadGib( entvars_t *pevVictim )
9 years ago
{
CGib *pGib = GetClassPtr( (CGib *)NULL );
8 years ago
if( g_Language == LANGUAGE_GERMAN )
9 years ago
{
pGib->Spawn( "models/germangibs.mdl" );// throw one head
pGib->pev->body = 0;
}
else
{
pGib->Spawn( "models/hgibs.mdl" );// throw one head
pGib->pev->body = 0;
}
8 years ago
if( pevVictim )
9 years ago
{
pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs;
8 years ago
edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict() );
if( RANDOM_LONG( 0, 100 ) <= 5 && pentPlayer )
9 years ago
{
// 5% chance head will be thrown at player's face.
8 years ago
entvars_t *pevPlayer;
9 years ago
pevPlayer = VARS( pentPlayer );
pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300.0f;
pGib->pev->velocity.z += 100.0f;
9 years ago
}
else
{
pGib->pev->velocity = Vector( RANDOM_FLOAT( -100.0f, 100.0f ), RANDOM_FLOAT( -100.0f, 100.0f ), RANDOM_FLOAT( 200.0f, 300.0f ) );
9 years ago
}
pGib->pev->avelocity.x = RANDOM_FLOAT( 100.0f, 200.0f );
pGib->pev->avelocity.y = RANDOM_FLOAT( 100.0f, 300.0f );
9 years ago
// copy owner's blood color
8 years ago
pGib->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor();
if( pevVictim->health > -50 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 0.7f;
9 years ago
}
8 years ago
else if( pevVictim->health > -200 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 2.0f;
9 years ago
}
else
{
pGib->pev->velocity = pGib->pev->velocity * 4.0f;
9 years ago
}
}
pGib->LimitVelocity();
}
8 years ago
void CGib::SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human )
9 years ago
{
int cSplat;
8 years ago
for( cSplat = 0; cSplat < cGibs; cSplat++ )
9 years ago
{
CGib *pGib = GetClassPtr( (CGib *)NULL );
8 years ago
if( g_Language == LANGUAGE_GERMAN )
9 years ago
{
pGib->Spawn( "models/germangibs.mdl" );
8 years ago
pGib->pev->body = RANDOM_LONG( 0, GERMAN_GIB_COUNT - 1 );
9 years ago
}
else
{
8 years ago
if( human )
9 years ago
{
// human pieces
pGib->Spawn( "models/hgibs.mdl" );
8 years ago
pGib->pev->body = RANDOM_LONG( 1, HUMAN_GIB_COUNT - 1 );// start at one to avoid throwing random amounts of skulls (0th gib)
9 years ago
}
else
{
// aliens
pGib->Spawn( "models/agibs.mdl" );
8 years ago
pGib->pev->body = RANDOM_LONG( 0, ALIEN_GIB_COUNT - 1 );
9 years ago
}
}
8 years ago
if( pevVictim )
9 years ago
{
// spawn the gib somewhere in the monster's bounding volume
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
9 years ago
// make the gib fly away from the attack vector
pGib->pev->velocity = g_vecAttackDir * -1.0f;
9 years ago
// mix in some noise
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 );
9 years ago
pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT( 300.0f, 400.0f );
9 years ago
pGib->pev->avelocity.x = RANDOM_FLOAT( 100.0f, 200.0f );
pGib->pev->avelocity.y = RANDOM_FLOAT( 100.0f, 300.0f );
9 years ago
// copy owner's blood color
8 years ago
pGib->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor();
if( pevVictim->health > -50 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 0.7f;
9 years ago
}
8 years ago
else if( pevVictim->health > -200 )
9 years ago
{
pGib->pev->velocity = pGib->pev->velocity * 2.0f;
9 years ago
}
else
{
pGib->pev->velocity = pGib->pev->velocity * 4.0f;
9 years ago
}
pGib->pev->solid = SOLID_BBOX;
8 years ago
UTIL_SetSize( pGib->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
9 years ago
}
pGib->LimitVelocity();
}
}
8 years ago
BOOL CBaseMonster::HasHumanGibs( void )
9 years ago
{
int myClass = Classify();
8 years ago
if( myClass == CLASS_HUMAN_MILITARY ||
myClass == CLASS_PLAYER_ALLY ||
myClass == CLASS_HUMAN_PASSIVE ||
myClass == CLASS_PLAYER )
9 years ago
return TRUE;
return FALSE;
}
8 years ago
BOOL CBaseMonster::HasAlienGibs( void )
9 years ago
{
int myClass = Classify();
8 years ago
if( myClass == CLASS_ALIEN_MILITARY ||
myClass == CLASS_ALIEN_MONSTER ||
myClass == CLASS_ALIEN_PASSIVE ||
myClass == CLASS_INSECT ||
myClass == CLASS_ALIEN_PREDATOR ||
myClass == CLASS_ALIEN_PREY )
9 years ago
8 years ago
return TRUE;
9 years ago
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.
//=========================================================
8 years ago
void CBaseMonster::GibMonster( void )
9 years ago
{
TraceResult tr;
BOOL gibbed = FALSE;
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM );
9 years ago
// only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs
8 years ago
if( HasHumanGibs() )
9 years ago
{
8 years ago
if( CVAR_GET_FLOAT( "violence_hgibs" ) != 0 ) // Only the player will ever get here
9 years ago
{
CGib::SpawnHeadGib( pev );
CGib::SpawnRandomGibs( pev, 4, 1 ); // throw some human gibs.
}
gibbed = TRUE;
}
8 years ago
else if( HasAlienGibs() )
9 years ago
{
8 years ago
if( CVAR_GET_FLOAT( "violence_agibs" ) != 0 ) // Should never get here, but someone might call it directly
9 years ago
{
CGib::SpawnRandomGibs( pev, 4, 0 ); // Throw alien gibs
}
gibbed = TRUE;
}
8 years ago
if( !IsPlayer() )
9 years ago
{
8 years ago
if( gibbed )
9 years ago
{
// don't remove players!
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time;
}
else
{
FadeMonster();
}
}
}
//=========================================================
// GetDeathActivity - determines the best type of death
// anim to play.
//=========================================================
8 years ago
Activity CBaseMonster::GetDeathActivity( void )
9 years ago
{
9 years ago
Activity deathActivity;
BOOL fTriedDirection;
float flDot;
TraceResult tr;
Vector vecSrc;
8 years ago
if( pev->deadflag != DEAD_NO )
9 years ago
{
// 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.
8 years ago
UTIL_MakeVectors( pev->angles );
flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1.0f );
9 years ago
8 years ago
switch( m_LastHitGroup )
9 years ago
{
// 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;
if( flDot > 0.3f )
9 years ago
{
deathActivity = ACT_DIEFORWARD;
}
else if( flDot <= -0.3f )
9 years ago
{
deathActivity = ACT_DIEBACKWARD;
}
break;
default:
// try to pick a death based on attack direction
fTriedDirection = TRUE;
if( flDot > 0.3f )
9 years ago
{
deathActivity = ACT_DIEFORWARD;
}
else if( flDot <= -0.3f )
9 years ago
{
deathActivity = ACT_DIEBACKWARD;
}
break;
}
// can we perform the prescribed death?
8 years ago
if( LookupActivity( deathActivity ) == ACTIVITY_NOT_AVAILABLE )
9 years ago
{
// no! did we fail to perform a directional death?
8 years ago
if( fTriedDirection )
9 years ago
{
// if yes, we're out of options. Go simple.
deathActivity = ACT_DIESIMPLE;
}
else
{
// cannot perform the ideal region-specific death, so try a direction.
if( flDot > 0.3f )
9 years ago
{
deathActivity = ACT_DIEFORWARD;
}
else if( flDot <= -0.3f )
9 years ago
{
deathActivity = ACT_DIEBACKWARD;
}
}
}
8 years ago
if( LookupActivity( deathActivity ) == ACTIVITY_NOT_AVAILABLE )
9 years ago
{
// if we're still invalid, simple is our only option.
deathActivity = ACT_DIESIMPLE;
}
8 years ago
if( deathActivity == ACT_DIEFORWARD )
9 years ago
{
8 years ago
// make sure there's room to fall forward
UTIL_TraceHull( vecSrc, vecSrc + gpGlobals->v_forward * 64.0f, dont_ignore_monsters, head_hull, edict(), &tr );
9 years ago
if( tr.flFraction != 1.0f )
8 years ago
{
deathActivity = ACT_DIESIMPLE;
}
9 years ago
}
8 years ago
if( deathActivity == ACT_DIEBACKWARD )
9 years ago
{
8 years ago
// make sure there's room to fall backward
UTIL_TraceHull( vecSrc, vecSrc - gpGlobals->v_forward * 64.0f, dont_ignore_monsters, head_hull, edict(), &tr );
9 years ago
if( tr.flFraction != 1.0f )
8 years ago
{
deathActivity = ACT_DIESIMPLE;
}
9 years ago
}
return deathActivity;
}
//=========================================================
// GetSmallFlinchActivity - determines the best type of flinch
// anim to play.
//=========================================================
8 years ago
Activity CBaseMonster::GetSmallFlinchActivity( void )
9 years ago
{
Activity flinchActivity;
// BOOL fTriedDirection;
//float flDot;
9 years ago
// fTriedDirection = FALSE;
8 years ago
UTIL_MakeVectors( pev->angles );
//flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1.0f );
8 years ago
switch( m_LastHitGroup )
9 years ago
{
// 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?
8 years ago
if( LookupActivity( flinchActivity ) == ACTIVITY_NOT_AVAILABLE )
9 years ago
{
flinchActivity = ACT_SMALL_FLINCH;
}
return flinchActivity;
}
void CBaseMonster::BecomeDead( void )
{
pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses.
8 years ago
9 years ago
// 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;
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 );
}
9 years ago
}
BOOL CBaseMonster::ShouldGibMonster( int iGib )
{
8 years ago
if( ( iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE ) || ( iGib == GIB_ALWAYS ) )
9 years ago
return TRUE;
8 years ago
9 years ago
return FALSE;
}
void CBaseMonster::CallGibMonster( void )
{
BOOL fade = FALSE;
8 years ago
if( HasHumanGibs() )
9 years ago
{
if( CVAR_GET_FLOAT( "violence_hgibs" ) == 0.0f )
9 years ago
fade = TRUE;
}
8 years ago
else if( HasAlienGibs() )
9 years ago
{
if( CVAR_GET_FLOAT( "violence_agibs" ) == 0.0f )
9 years ago
fade = TRUE;
}
pev->takedamage = DAMAGE_NO;
pev->solid = SOLID_NOT;// do something with the body. while monster blows up
8 years ago
if( fade )
9 years ago
{
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.
8 years ago
if( pev->health < -99 )
9 years ago
{
pev->health = 0;
}
8 years ago
if( ShouldFadeOnDeath() && !fade )
UTIL_Remove( this );
}
9 years ago
/*
============
Killed
============
*/
8 years ago
void CBaseMonster::Killed( entvars_t *pevAttacker, int iGib )
9 years ago
{
//unsigned int cCount = 0;
//BOOL fDone = FALSE;
// modif de Julien - lance flammes
if ( pev->renderfx == kRenderFxGlowShell )
pev->renderfx = kRenderFxNone;
//----
9 years ago
8 years ago
if( HasMemory( bits_MEMORY_KILLED ) )
9 years ago
{
8 years ago
if( ShouldGibMonster( iGib ) )
9 years ago
CallGibMonster();
return;
}
Remember( bits_MEMORY_KILLED );
// clear the deceased's sound channels.(may have been firing or reloading when killed)
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM );
9 years ago
m_IdealMonsterState = MONSTERSTATE_DEAD;
// Make sure this condition is fired too (TakeDamage breaks out before this happens on death)
SetConditions( bits_COND_LIGHT_DAMAGE );
8 years ago
9 years ago
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
8 years ago
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
if( pOwner )
9 years ago
{
pOwner->DeathNotice( pev );
}
8 years ago
if( ShouldGibMonster( iGib ) )
9 years ago
{
CallGibMonster();
return;
}
8 years ago
else if( pev->flags & FL_MONSTER )
9 years ago
{
SetTouch( NULL );
BecomeDead();
}
8 years ago
9 years ago
// don't let the status bar glitch for players.with <0 health.
8 years ago
if( pev->health < -99 )
9 years ago
{
pev->health = 0;
}
8 years ago
9 years ago
//pev->enemy = ENT( pevAttacker );//why? (sjb)
8 years ago
9 years ago
m_IdealMonsterState = MONSTERSTATE_DEAD;
// modif de Julien
pev->solid = SOLID_BBOX; // ne pas bloquer les gibs
9 years ago
}
//
// 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!!
8 years ago
void CBaseEntity::SUB_StartFadeOut( void )
9 years ago
{
8 years ago
if( pev->rendermode == kRenderNormal )
9 years ago
{
pev->renderamt = 255;
pev->rendermode = kRenderTransTexture;
}
pev->solid = SOLID_NOT;
pev->avelocity = g_vecZero;
pev->nextthink = gpGlobals->time + 0.1f;
9 years ago
SetThink( &CBaseEntity::SUB_FadeOut );
}
8 years ago
void CBaseEntity::SUB_FadeOut( void )
9 years ago
{
8 years ago
if( pev->renderamt > 7 )
9 years ago
{
pev->renderamt -= 7;
pev->nextthink = gpGlobals->time + 0.1f;
9 years ago
}
else
{
pev->renderamt = 0;
pev->nextthink = gpGlobals->time + 0.2f;
9 years ago
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.
//=========================================================
8 years ago
void CGib::WaitTillLand( void )
9 years ago
{
8 years ago
if( !IsInWorld() )
9 years ago
{
UTIL_Remove( this );
return;
}
8 years ago
if( pev->velocity == g_vecZero )
9 years ago
{
if ( m_instant == 1 ) //modif de Julien
{
pev->nextthink = gpGlobals->time + m_lifeTime;
SetThink ( &CBaseEntity::SUB_Remove ); //added &CBaseEntity::
return;
}
8 years ago
SetThink( &CBaseEntity::SUB_StartFadeOut );
9 years ago
pev->nextthink = gpGlobals->time + m_lifeTime;
// If you bleed, you stink!
8 years ago
if( m_bloodColor != DONT_BLEED )
9 years ago
{
// ok, start stinkin!
8 years ago
CSoundEnt::InsertSound( bits_SOUND_MEAT, pev->origin, 384, 25 );
9 years ago
}
}
else
{
// wait and check again in another half second.
pev->nextthink = gpGlobals->time + 0.5f;
9 years ago
}
}
//
// Gib bounces on the ground or wall, sponges some blood down, too!
//
8 years ago
void CGib::BounceGibTouch( CBaseEntity *pOther )
9 years ago
{
Vector vecSpot;
TraceResult tr;
8 years ago
//if( RANDOM_LONG( 0, 1 ) )
9 years ago
// return;// don't bleed everytime
8 years ago
if( pev->flags & FL_ONGROUND )
9 years ago
{
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;
9 years ago
}
else
{
8 years ago
if( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED )
9 years ago
{
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 );
9 years ago
UTIL_BloodDecalTrace( &tr, m_bloodColor );
m_cBloodDecals--;
}
8 years ago
if( m_material != matNone && RANDOM_LONG( 0, 2 ) == 0 )
9 years ago
{
float volume;
8 years ago
float zvel = fabs( pev->velocity.z );
volume = 0.8f * Q_min( 1.0f, zvel / 450.0f );
9 years ago
CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume );
}
}
}
//
// Sticky gib puts blood on the wall and stays put.
//
8 years ago
void CGib::StickyGibTouch( CBaseEntity *pOther )
9 years ago
{
Vector vecSpot;
TraceResult tr;
8 years ago
9 years ago
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time + 10.0f;
9 years ago
8 years ago
if( !FClassnameIs( pOther->pev, "worldspawn" ) )
9 years ago
{
pev->nextthink = gpGlobals->time;
return;
}
UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 32.0f, ignore_monsters, ENT( pev ), &tr );
9 years ago
UTIL_BloodDecalTrace( &tr, m_bloodColor );
pev->velocity = tr.vecPlaneNormal * -1.0f;
8 years ago
pev->angles = UTIL_VecToAngles( pev->velocity );
pev->velocity = g_vecZero;
9 years ago
pev->avelocity = g_vecZero;
pev->movetype = MOVETYPE_NONE;
}
//
// Throw a chunk
//
8 years ago
void CGib::Spawn( const char *szGibModel )
9 years ago
{
pev->movetype = MOVETYPE_BOUNCE;
pev->friction = 0.55f; // deading the bounce a bit
8 years ago
9 years ago
// 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
8 years ago
pev->classname = MAKE_STRING( "gib" );
9 years ago
8 years ago
SET_MODEL( ENT( pev ), szGibModel );
UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
9 years ago
pev->nextthink = gpGlobals->time + 4.0f;
9 years ago
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
8 years ago
int CBaseMonster::TakeHealth( float flHealth, int bitsDamageType )
9 years ago
{
8 years ago
if( !pev->takedamage )
9 years ago
return 0;
// clear out any damage types we healed.
// UNDONE: generic health should not heal any
// UNDONE: time-based damage
8 years ago
m_bitsDamageType &= ~( bitsDamageType & ~DMG_TIMEBASED );
return CBaseEntity::TakeHealth( flHealth, bitsDamageType );
9 years ago
}
/*
============
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
============
*/
8 years ago
int CBaseMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
9 years ago
{
float flTake;
Vector vecDir;
8 years ago
if( !pev->takedamage )
9 years ago
return 0;
8 years ago
if( !IsAlive() )
9 years ago
{
return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}
8 years ago
if( pev->deadflag == DEAD_NO )
9 years ago
{
// 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 );
8 years ago
if( !FNullEnt( pevInflictor ) )
9 years ago
{
8 years ago
CBaseEntity *pInflictor = CBaseEntity::Instance( pevInflictor );
if( pInflictor )
9 years ago
{
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?
8 years ago
if( IsPlayer() )
9 years ago
{
8 years ago
if( pevInflictor )
pev->dmg_inflictor = ENT( pevInflictor );
9 years ago
pev->dmg_take += flTake;
// check for godmode or invincibility
8 years ago
if( pev->flags & FL_GODMODE )
9 years ago
{
return 0;
}
}
// if this is a player, move him around!
8 years ago
if( ( !FNullEnt( pevInflictor ) ) && ( pev->movetype == MOVETYPE_WALK ) && ( !pevAttacker || pevAttacker->solid != SOLID_TRIGGER ) )
9 years ago
{
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
8 years ago
if( m_MonsterState == MONSTERSTATE_SCRIPT )
9 years ago
{
SetConditions( bits_COND_LIGHT_DAMAGE );
return 0;
}
8 years ago
if( pev->health <= 0 )
9 years ago
{
g_pevLastInflictor = pevInflictor;
// if( bitsDamageType & DMG_ALWAYSGIB )
if ( bitsDamageType & DMG_ALWAYSGIB && !(bitsDamageType & DMG_BULLET) ) // modif de Julien
9 years ago
{
Killed( pevAttacker, GIB_ALWAYS );
}
// else if( bitsDamageType & DMG_NEVERGIB )
else if ( bitsDamageType & DMG_NEVERGIB || bitsDamageType & DMG_BULLET ) // modif de Julien
9 years ago
{
Killed( pevAttacker, GIB_NEVER );
}
else
{
Killed( pevAttacker, GIB_NORMAL );
}
g_pevLastInflictor = NULL;
return 0;
}
// react to the damage (get mad)
8 years ago
if( ( pev->flags & FL_MONSTER ) && !FNullEnt( pevAttacker ) )
9 years ago
{
8 years ago
if( pevAttacker->flags & ( FL_MONSTER | FL_CLIENT ) )
{
// only if the attack was a monster or client!
9 years ago
// enemy's last known position is somewhere down the vector that the attack came from.
8 years ago
if( pevInflictor )
9 years ago
{
if( m_hEnemy == 0 || pevInflictor == m_hEnemy->pev || !HasConditions( bits_COND_SEE_ENEMY ) )
9 years ago
{
m_vecEnemyLKP = pevInflictor->origin;
}
}
else
{
m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64.0f );
9 years ago
}
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?
if( flDamage > 0.0f )
9 years ago
{
8 years ago
SetConditions( bits_COND_LIGHT_DAMAGE );
9 years ago
}
if( flDamage >= 20.0f )
9 years ago
{
8 years ago
SetConditions( bits_COND_HEAVY_DAMAGE );
9 years ago
}
}
}
return 1;
}
//=========================================================
// DeadTakeDamage - takedamage function called when a monster's
// corpse is damaged.
//=========================================================
8 years ago
int CBaseMonster::DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
9 years ago
{
8 years ago
Vector vecDir;
9 years ago
// 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 );
8 years ago
if( !FNullEnt( pevInflictor ) )
9 years ago
{
8 years ago
CBaseEntity *pInflictor = CBaseEntity::Instance( pevInflictor );
if( pInflictor )
9 years ago
{
vecDir = ( pInflictor->Center() - Vector ( 0.0f, 0.0f, 10.0f ) - Center() ).Normalize();
9 years ago
vecDir = g_vecAttackDir = vecDir.Normalize();
}
}
#if 0// turn this back on when the bounding box issues are resolved.
pev->flags &= ~FL_ONGROUND;
pev->origin.z += 1.0f;
9 years ago
// let the damage scoot the corpse around a bit.
8 years ago
if( !FNullEnt( pevInflictor ) && ( pevAttacker->solid != SOLID_TRIGGER ) )
9 years ago
{
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.
8 years ago
if( bitsDamageType & DMG_GIB_CORPSE )
9 years ago
{
8 years ago
if( pev->health <= flDamage )
9 years ago
{
pev->health = -50;
Killed( pevAttacker, GIB_ALWAYS );
return 0;
}
// Accumulate corpse gibbing damage, so you can gib with multiple hits
pev->health -= flDamage * 0.1f;
9 years ago
}
8 years ago
9 years ago
return 1;
}
8 years ago
float CBaseMonster::DamageForce( float damage )
9 years ago
{
float force = damage * ( ( 32.0f * 32.0f * 72.0f ) / ( pev->size.x * pev->size.y * pev->size.z ) ) * 5.0f;
8 years ago
if( force > 1000.0f )
9 years ago
{
force = 1000.0f;
9 years ago
}
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;
8 years ago
if( flRadius )
9 years ago
falloff = flDamage / flRadius;
else
falloff = 1.0f;
9 years ago
8 years ago
int bInWater = ( UTIL_PointContents( vecSrc ) == CONTENTS_WATER );
9 years ago
vecSrc.z += 1.0f;// in case grenade is lying on the ground
9 years ago
8 years ago
if( !pevAttacker )
9 years ago
pevAttacker = pevInflictor;
// iterate on all entities in the vicinity.
8 years ago
while( ( pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius ) ) != NULL )
9 years ago
{
8 years ago
if( pEntity->pev->takedamage != DAMAGE_NO )
9 years ago
{
// UNDONE: this should check a damage mask, not an ignore
8 years ago
if( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore )
{
// houndeyes don't hurt other houndeyes with their attack
9 years ago
continue;
}
// blast's don't tavel into or out of water
8 years ago
if( bInWater && pEntity->pev->waterlevel == 0 )
9 years ago
continue;
8 years ago
if( !bInWater && pEntity->pev->waterlevel == 3 )
9 years ago
continue;
vecSpot = pEntity->BodyTarget( vecSrc );
8 years ago
UTIL_TraceLine( vecSrc, vecSpot, dont_ignore_monsters, ENT( pevInflictor ), &tr );
// if( tr.flFraction == 1.0f || tr.pHit == pEntity->edict() )
// {
if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() || FClassnameIs(tr.pHit, "info_tank_model") ) // modif de Julien
8 years ago
{
8 years ago
// the explosion can 'see' this entity, so hurt them!
// // the explosion can 'see' this entity, so hurt them!
8 years ago
if( tr.fStartSolid )
9 years ago
{
// if we're stuck inside them, fixup the position and distance
tr.vecEndPos = vecSrc;
tr.flFraction = 0.0f;
9 years ago
}
8 years ago
9 years ago
// decrease damage for an ent that's farther from the bomb.
flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff;
flAdjustedDamage = flDamage - flAdjustedDamage;
8 years ago
if( flAdjustedDamage < 0.0f )
9 years ago
{
flAdjustedDamage = 0.0f;
9 years ago
}
8 years ago
9 years ago
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
if( tr.flFraction != 1.0f )
9 years ago
{
8 years ago
ClearMultiDamage();
pEntity->TraceAttack( pevInflictor, flAdjustedDamage, ( tr.vecEndPos - vecSrc ).Normalize(), &tr, bitsDamageType );
9 years ago
ApplyMultiDamage( pevInflictor, pevAttacker );
}
else
{
pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
}
}
}
}
}
8 years ago
void CBaseMonster::RadiusDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType )
9 years ago
{
::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5f, iClassIgnore, bitsDamageType );
9 years ago
}
8 years ago
void CBaseMonster::RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType )
9 years ago
{
::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5f, iClassIgnore, bitsDamageType );
9 years ago
}
//=========================================================
// 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.
//=========================================================
8 years ago
CBaseEntity* CBaseMonster::CheckTraceHullAttack( float flDist, int iDamage, int iDmgType )
9 years ago
{
TraceResult tr;
8 years ago
if( IsPlayer() )
9 years ago
UTIL_MakeVectors( pev->angles );
else
UTIL_MakeAimVectors( pev->angles );
Vector vecStart = pev->origin;
vecStart.z += pev->size.z * 0.5f;
8 years ago
Vector vecEnd = vecStart + ( gpGlobals->v_forward * flDist );
9 years ago
8 years ago
UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr );
if( tr.pHit )
9 years ago
{
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
8 years ago
if( iDamage > 0 )
9 years ago
{
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.
//=========================================================
8 years ago
BOOL CBaseMonster::FInViewCone( CBaseEntity *pEntity )
9 years ago
{
Vector2D vec2LOS;
float flDot;
8 years ago
UTIL_MakeVectors( pev->angles );
9 years ago
vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D();
vec2LOS = vec2LOS.Normalize();
8 years ago
flDot = DotProduct( vec2LOS, gpGlobals->v_forward.Make2D() );
9 years ago
8 years ago
if( flDot > m_flFieldOfView )
9 years ago
{
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.
//=========================================================
8 years ago
BOOL CBaseMonster::FInViewCone( Vector *pOrigin )
9 years ago
{
Vector2D vec2LOS;
float flDot;
8 years ago
UTIL_MakeVectors( pev->angles );
9 years ago
vec2LOS = ( *pOrigin - pev->origin ).Make2D();
vec2LOS = vec2LOS.Normalize();
8 years ago
flDot = DotProduct( vec2LOS, gpGlobals->v_forward.Make2D() );
9 years ago
8 years ago
if( flDot > m_flFieldOfView )
9 years ago
{
return TRUE;
}
else
{
return FALSE;
}
}
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the target
//=========================================================
8 years ago
BOOL CBaseEntity::FVisible( CBaseEntity *pEntity )
9 years ago
{
TraceResult tr;
Vector vecLookerOrigin;
Vector vecTargetOrigin;
8 years ago
if( !pEntity )
return FALSE;
8 years ago
if( !pEntity->pev )
return FALSE;
8 years ago
if( FBitSet( pEntity->pev->flags, FL_NOTARGET ) )
9 years ago
return FALSE;
// don't look through water
8 years ago
if( ( pev->waterlevel != 3 && pEntity->pev->waterlevel == 3 )
|| ( pev->waterlevel == 3 && pEntity->pev->waterlevel == 0 ) )
9 years ago
return FALSE;
vecLookerOrigin = pev->origin + pev->view_ofs;//look through the caller's 'eyes'
vecTargetOrigin = pEntity->EyePosition();
8 years ago
UTIL_TraceLine( vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT( pev )/*pentIgnore*/, &tr );
//modif de Julien pour le tank
if ( FClassnameIs ( pEntity->pev , "vehicle_tank" ) )
UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT(pEntity->pev), &tr);
if( tr.flFraction != 1.0f )
9 years ago
{
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
//=========================================================
8 years ago
BOOL CBaseEntity::FVisible( const Vector &vecOrigin )
9 years ago
{
TraceResult tr;
Vector vecLookerOrigin;
8 years ago
9 years ago
vecLookerOrigin = EyePosition();//look through the caller's 'eyes'
8 years ago
UTIL_TraceLine( vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT( pev )/*pentIgnore*/, &tr );
if( tr.flFraction != 1.0f )
9 years ago
{
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)
{
Vector vecOrigin = ptr->vecEndPos - vecDir * 4.0f;
9 years ago
8 years ago
if( pev->takedamage )
9 years ago
{
AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
int blood = BloodColor();
8 years ago
if( blood != DONT_BLEED )
9 years ago
{
8 years ago
SpawnBlood( vecOrigin, blood, flDamage );// a little surface blood.
9 years ago
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
}
}
}
/*
//=========================================================
// TraceAttack
//=========================================================
8 years ago
void CBaseMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
9 years ago
{
Vector vecOrigin = ptr->vecEndPos - vecDir * 4.0f;
9 years ago
8 years ago
ALERT( at_console, "%d\n", ptr->iHitgroup );
9 years ago
8 years ago
if( pev->takedamage )
9 years ago
{
AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
int blood = BloodColor();
8 years ago
if( blood != DONT_BLEED )
9 years ago
{
8 years ago
SpawnBlood( vecOrigin, blood, flDamage );// a little surface blood.
9 years ago
}
}
}
*/
//=========================================================
// TraceAttack
//=========================================================
8 years ago
void CBaseMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
9 years ago
{
8 years ago
if( pev->takedamage )
9 years ago
{
m_LastHitGroup = ptr->iHitgroup;
8 years ago
switch( ptr->iHitgroup )
9 years ago
{
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;
}
8 years ago
SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood.
9 years ago
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.
================
*/
//void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker )
void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int iTraverseMur )
9 years ago
{
static int tracerCount;
int tracer;
TraceResult tr;
Vector vecRight = gpGlobals->v_right;
Vector vecUp = gpGlobals->v_up;
8 years ago
if( pevAttacker == NULL )
9 years ago
pevAttacker = pev; // the default attacker is ourselves
ClearMultiDamage();
gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;
8 years ago
for( ULONG iShot = 1; iShot <= cShots; iShot++ )
9 years ago
{
// get circular gaussian spread
float x, y, z;
do {
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 );
8 years ago
z = x * x + y * y;
9 years ago
} while (z > 1);
Vector vecDir = vecDirShooting +
x * vecSpread.x * vecRight +
y * vecSpread.y * vecUp;
Vector vecEnd;
vecEnd = vecSrc + vecDir * flDistance;
8 years ago
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( pev )/*pentIgnore*/, &tr );
9 years ago
tracer = 0;
8 years ago
if( iTracerFreq != 0 && ( tracerCount++ % iTracerFreq ) == 0 )
9 years ago
{
Vector vecTracerSrc;
8 years ago
if( IsPlayer() )
{
// adjust tracer position for player
vecTracerSrc = vecSrc + Vector( 0.0f, 0.0f, -4.0f ) + gpGlobals->v_right * 2.0f + gpGlobals->v_forward * 16.0f;
9 years ago
}
else
{
vecTracerSrc = vecSrc;
}
8 years ago
if( iTracerFreq != 1 ) // guns that always trace also always decal
9 years ago
tracer = 1;
switch( iBulletType )
{
case BULLET_PLAYER_MP5: // ??? HLINVASION modif de Julien Wasn't there originally. Re-added.
case BULLET_PLAYER_M16: // modif. de Julien
case BULLET_PLAYER_SNIPER: // modif. de Julien
case BULLET_PLAYER_IRGUN: // modif. de Julien
9 years ago
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
if( tr.flFraction != 1.0f )
9 years ago
{
8 years ago
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
9 years ago
8 years ago
if( iDamage )
9 years ago
{
8 years ago
pEntity->TraceAttack( pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ( ( iDamage > 16 ) ? DMG_ALWAYSGIB : DMG_NEVERGIB ) );
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
//DecalGunshot( &tr, iBulletType ); //modif de Julien
ClientDecal ( &tr, vecSrc, vecEnd );
9 years ago
}
8 years ago
else switch( iBulletType )
9 years ago
{
//default:
case BULLET_PLAYER_9MM: //HLINVASION modif de Julien, Julien's original code clearly expects these to be here, so copy them here.
//pEntity->TraceAttack( pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET );
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); // modif de Julien HLINVASION copied here from the block above, due to obvious discrepancy, likely due to API / SDK versions.
break;
case BULLET_PLAYER_MP5:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET );
break;
case BULLET_PLAYER_BUCKSHOT:
// make distance based!
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET );
break;
case BULLET_PLAYER_357:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET );
break;
//end Julien legacy code block copy
// modif. de Julien //also see player function below for BULLET_PLAYER_9MM section, moved it there (seems more appropriate), left these here, as it's likely Julien's code will expect them here.
case BULLET_PLAYER_M16:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgM16, vecDir, &tr, DMG_BULLET);
break;
case BULLET_PLAYER_SNIPER:
{
// pour ne pas d
float damage = gSkillData.plrDmgSniper;
if ( pEntity->MyMonsterPointer() == NULL || FClassnameIs ( pEntity->edict(), "monster_apache" ) ) //was MyMonsterPointer (sans braces), probably obsolete
damage *= 0.3;
pEntity->TraceAttack(pevAttacker, damage, vecDir, &tr, DMG_BULLET);
break;
}
case BULLET_PLAYER_IRGUN:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgIRgun, vecDir, &tr, DMG_BULLET);
break;
//fin modif.
case BULLET_PLAYER_BUCKSHOT_DOUBLE: //modif de Julien - pour le demembrage du grunt
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB );
break;
default: //HLINVASION -- re-added here, because something is definitely off here. modif de Julien
9 years ago
case BULLET_MONSTER_9MM:
8 years ago
pEntity->TraceAttack( pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET );
9 years ago
8 years ago
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
// DecalGunshot( &tr, iBulletType ); //modif de Julien
ClientDecal ( &tr, vecSrc, vecEnd );
9 years ago
break;
case BULLET_MONSTER_MP5:
8 years ago
pEntity->TraceAttack( pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET );
9 years ago
8 years ago
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
// DecalGunshot( &tr, iBulletType ); //modif de Julien
ClientDecal ( &tr, vecSrc, vecEnd );
9 years ago
break;
8 years ago
case BULLET_MONSTER_12MM:
pEntity->TraceAttack( pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET );
if( !tracer )
9 years ago
{
8 years ago
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
// DecalGunshot( &tr, iBulletType ); //modif de Julien
ClientDecal ( &tr, vecSrc, vecEnd );
9 years ago
}
break;
8 years ago
case BULLET_NONE: // FIX
pEntity->TraceAttack( pevAttacker, 50, vecDir, &tr, DMG_CLUB );
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
9 years ago
// only decal glass
8 years ago
if( !FNullEnt( tr.pHit ) && VARS( tr.pHit )->rendermode != 0 )
9 years ago
{
8 years ago
UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG( 0, 2 ) );
9 years ago
}
break;
}
// tir a travers les murs //modif de Julien
if ( iTraverseMur == 0 )
{
float distance;
switch(iBulletType)
{
default:
case BULLET_PLAYER_9MM:
case BULLET_PLAYER_MP5:
case BULLET_PLAYER_SNIPER :
case BULLET_PLAYER_M16 :
case BULLET_PLAYER_BUCKSHOT_DOUBLE:
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_357:
distance = 16;
break;
case BULLET_PLAYER_IRGUN :
distance = 32;
break;
}
//
vec3_t vecSource = vecSrc;
vec3_t vecTraceDir = (tr.vecEndPos - vecSource).Normalize();
vecSource = tr.vecEndPos + vecTraceDir * distance;
TraceResult trTir;
UTIL_TraceLine(vecSource, vecSource + vecTraceDir, dont_ignore_monsters, ENT(pev), &trTir);
if ( trTir.fStartSolid != 1 )
{
ApplyMultiDamage(pev, pevAttacker);
FireBullets ( 1, vecSource, vecTraceDir, vecSpread, flDistance, iBulletType, 0, 0, pev, 1 );
}
} //fin modif de Julien
9 years ago
}
// make bullet trails
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0f ) );
9 years ago
}
8 years ago
ApplyMultiDamage( pev, pevAttacker );
//modif de Julien
if ( IsPlayer() )
{
if ( IsInGaz() == TRUE )
m_bFireInGaz = TRUE;
}
9 years ago
}
/*
================
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.
================
*/
8 years ago
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 )
9 years ago
{
static int tracerCount;
int iTraverseMur = 0; //HLINVASION modif de Julien, Julien's default, this function is unlikely to be called from Julien's code.
9 years ago
TraceResult tr;
Vector vecRight = gpGlobals->v_right;
Vector vecUp = gpGlobals->v_up;
float x = 0.0f, y = 0.0f;
//float z;
9 years ago
8 years ago
if( pevAttacker == NULL )
9 years ago
pevAttacker = pev; // the default attacker is ourselves
ClearMultiDamage();
gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;
8 years ago
for( ULONG iShot = 1; iShot <= cShots; iShot++ )
9 years ago
{
//Use player's random seed.
// get circular gaussian spread
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 );
//z = x * x + y * y;
9 years ago
Vector vecDir = vecDirShooting +
x * vecSpread.x * vecRight +
y * vecSpread.y * vecUp;
Vector vecEnd;
vecEnd = vecSrc + vecDir * flDistance;
8 years ago
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( pev )/*pentIgnore*/, &tr );
9 years ago
// do damage, paint decals
if( tr.flFraction != 1.0f )
9 years ago
{
8 years ago
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
9 years ago
8 years ago
if( iDamage )
9 years ago
{
8 years ago
pEntity->TraceAttack( pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ( ( iDamage > 16 ) ? DMG_ALWAYSGIB : DMG_NEVERGIB ) );
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
9 years ago
DecalGunshot( &tr, iBulletType );
}
8 years ago
else switch( iBulletType )
9 years ago
{
default:
8 years ago
case BULLET_PLAYER_9MM:
//pEntity->TraceAttack( pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET );
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); // modif de Julien HLINVASION copied here from the block above, due to obvious discrepancy, likely due to API / SDK versions.
9 years ago
break;
8 years ago
case BULLET_PLAYER_MP5:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET );
9 years ago
break;
// HLINVASION modif de Julien legacy copy for compatibility
// modif. de Julien //also see monster function above. This is a compatibility copy.
case BULLET_PLAYER_M16:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgM16, vecDir, &tr, DMG_BULLET);
break;
case BULLET_PLAYER_SNIPER:
{
// pour ne pas d
float damage = gSkillData.plrDmgSniper;
if ( pEntity->MyMonsterPointer() == NULL || FClassnameIs ( pEntity->edict(), "monster_apache" ) ) //was MyMonsterPointer (sans braces), probably obsolete
damage *= 0.3;
pEntity->TraceAttack(pevAttacker, damage, vecDir, &tr, DMG_BULLET);
break;
}
case BULLET_PLAYER_IRGUN:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgIRgun, vecDir, &tr, DMG_BULLET);
break;
//fin modif.
case BULLET_PLAYER_BUCKSHOT_DOUBLE: //modif de Julien - pour le demembrage du grunt
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB );
break;
// HLINVASION modif de Julien fin de legacy copy for compatibility
8 years ago
case BULLET_PLAYER_BUCKSHOT:
9 years ago
// make distance based!
8 years ago
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET );
9 years ago
break;
8 years ago
case BULLET_PLAYER_357:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET );
9 years ago
break;
8 years ago
case BULLET_NONE: // FIX
pEntity->TraceAttack( pevAttacker, 50, vecDir, &tr, DMG_CLUB );
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );
9 years ago
// only decal glass
8 years ago
if( !FNullEnt( tr.pHit ) && VARS( tr.pHit )->rendermode != 0 )
9 years ago
{
8 years ago
UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG( 0, 2 ) );
9 years ago
}
break;
}
// tir a travers les murs //modif de Julien HLINVASION copied from the monster version above for compatibility.
if ( iTraverseMur == 0 ) //This is always zero here, since this function will likely not be called from Julien's code, which uses this var. Thus, we assume it to be zero, since it's Julien's default. See above.
{
float distance;
switch(iBulletType)
{
default:
case BULLET_PLAYER_9MM:
case BULLET_PLAYER_MP5:
case BULLET_PLAYER_SNIPER :
case BULLET_PLAYER_M16 :
case BULLET_PLAYER_BUCKSHOT_DOUBLE:
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_357:
distance = 16;
break;
case BULLET_PLAYER_IRGUN :
distance = 32;
break;
}
//
vec3_t vecSource = vecSrc;
vec3_t vecTraceDir = (tr.vecEndPos - vecSource).Normalize();
vecSource = tr.vecEndPos + vecTraceDir * distance;
TraceResult trTir;
UTIL_TraceLine(vecSource, vecSource + vecTraceDir, dont_ignore_monsters, ENT(pev), &trTir);
if ( trTir.fStartSolid != 1 )
{
ApplyMultiDamage(pev, pevAttacker);
FireBullets ( 1, vecSource, vecTraceDir, vecSpread, flDistance, iBulletType, 0, 0, pev, 1 );
}
} //fin modif de Julien
9 years ago
}
// make bullet trails
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0f ) );
9 years ago
}
8 years ago
ApplyMultiDamage( pev, pevAttacker );
9 years ago
//modif de Julien HLINVASION copied from monster version above for compatibility.
if ( IsPlayer() )
{
if ( IsInGaz() == TRUE )
m_bFireInGaz = TRUE;
}
9 years ago
return Vector( x * vecSpread.x, y * vecSpread.y, 0.0 );
}
8 years ago
void CBaseEntity::TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
9 years ago
{
8 years ago
if( BloodColor() == DONT_BLEED )
9 years ago
return;
8 years ago
if( flDamage == 0 )
9 years ago
return;
8 years ago
if( !( bitsDamageType & ( DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR ) ) )
9 years ago
return;
8 years ago
9 years ago
// make blood decal on the wall!
TraceResult Bloodtr;
Vector vecTraceDir;
float flNoise;
int cCount;
int i;
/*
8 years ago
if( !IsAlive() )
9 years ago
{
// dealing with a dead monster.
8 years ago
if( pev->max_health <= 0 )
9 years ago
{
// no blood decal for a monster that has already decalled its limit.
return;
}
else
{
pev->max_health--;
}
}
*/
if( flDamage < 10.0f )
9 years ago
{
flNoise = 0.1f;
9 years ago
cCount = 1;
}
else if( flDamage < 25.0f )
9 years ago
{
flNoise = 0.2f;
9 years ago
cCount = 2;
}
else
{
flNoise = 0.3f;
9 years ago
cCount = 4;
}
8 years ago
for( i = 0; i < cCount; i++ )
9 years ago
{
vecTraceDir = vecDir * -1.0f;// trace in the opposite direction the shot came from (the direction the shot is going)
9 years ago
vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise );
vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise );
vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise );
UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172.0f, ignore_monsters, ENT( pev ), &Bloodtr );
9 years ago
if( Bloodtr.flFraction != 1.0f )
9 years ago
{
UTIL_BloodDecalTrace( &Bloodtr, BloodColor() );
}
}
}
//=========================================================
//=========================================================
8 years ago
void CBaseMonster::MakeDamageBloodDecal( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir )
9 years ago
{
// make blood decal on the wall!
TraceResult Bloodtr;
Vector vecTraceDir;
int i;
8 years ago
if( !IsAlive() )
9 years ago
{
// dealing with a dead monster.
8 years ago
if( pev->max_health <= 0 )
9 years ago
{
// no blood decal for a monster that has already decalled its limit.
return;
}
else
{
pev->max_health--;
}
}
8 years ago
for( i = 0; i < cCount; i++ )
9 years ago
{
vecTraceDir = vecDir;
vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise );
vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise );
vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise );
UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172.0f, ignore_monsters, ENT( pev ), &Bloodtr );
9 years ago
/*
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 );
8 years ago
9 years ago
WRITE_COORD( Bloodtr.vecEndPos.x );
WRITE_COORD( Bloodtr.vecEndPos.y );
WRITE_COORD( Bloodtr.vecEndPos.z );
MESSAGE_END();
*/
if( Bloodtr.flFraction != 1.0f )
9 years ago
{
UTIL_BloodDecalTrace( &Bloodtr, BloodColor() );
}
}
}