cs16-client-legacy/dlls/combat.cpp
2016-03-05 22:29:55 +03:00

1562 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***
*
* 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.
*
****/
#include "stdafx.h"
#include "cbase.h"
#include "monsters.h"
#include "soundent.h"
#include "decals.h"
#include "animation.h"
#include "weapons.h"
#include "func_break.h"
#include "pm_materials.h"
#include "player.h"
#include "game.h"
extern DLL_GLOBAL Vector g_vecAttackDir;
extern entvars_t *g_pevLastInflictor;
#define GERMAN_GIB_COUNT 4
#define HUMAN_GIB_COUNT 6
#define ALIEN_GIB_COUNT 4
void CGib::LimitVelocity(void)
{
float length = pev->velocity.Length();
if (length > 1500)
pev->velocity = pev->velocity.Normalize() * 1500;
}
void CGib::SpawnStickyGibs(entvars_t *pevVictim, Vector vecOrigin, int cGibs)
{
if (g_Language == LANGUAGE_GERMAN)
return;
for (int i = 0; i < cGibs; i++)
{
CGib *pGib = GetClassPtr((CGib *)NULL);
pGib->Spawn("models/stickygib.mdl");
pGib->pev->body = RANDOM_LONG(0, 2);
if (pevVictim)
{
pGib->pev->origin.x = vecOrigin.x + RANDOM_FLOAT(-3, 3);
pGib->pev->origin.y = vecOrigin.y + RANDOM_FLOAT(-3, 3);
pGib->pev->origin.z = vecOrigin.z + RANDOM_FLOAT(-3, 3);
pGib->pev->velocity = g_vecAttackDir * -1;
pGib->pev->velocity.x += RANDOM_FLOAT(-0.15, 0.15);
pGib->pev->velocity.y += RANDOM_FLOAT(-0.15, 0.15);
pGib->pev->velocity.z += RANDOM_FLOAT(-0.15, 0.15);
pGib->pev->velocity = pGib->pev->velocity * 900;
pGib->pev->avelocity.x = RANDOM_FLOAT(250, 400);
pGib->pev->avelocity.y = RANDOM_FLOAT(250, 400);
pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor();
if (pevVictim->health > -50)
pGib->pev->velocity = pGib->pev->velocity * 0.7;
else if (pevVictim->health > -200)
pGib->pev->velocity = pGib->pev->velocity * 2;
else
pGib->pev->velocity = pGib->pev->velocity * 4;
pGib->pev->movetype = MOVETYPE_TOSS;
pGib->pev->solid = SOLID_BBOX;
UTIL_SetSize(pGib->pev, Vector(0, 0, 0), Vector(0, 0, 0));
pGib->SetTouch(&CGib::StickyGibTouch);
pGib->SetThink(NULL);
}
pGib->LimitVelocity();
}
}
void CGib::SpawnHeadGib(entvars_t *pevVictim)
{
CGib *pGib = GetClassPtr((CGib *)NULL);
if (g_Language == LANGUAGE_GERMAN)
{
pGib->Spawn("models/germangibs.mdl");
pGib->pev->body = 0;
}
else
{
pGib->Spawn("models/hgibs.mdl");
pGib->pev->body = 0;
}
if (pevVictim)
{
pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs;
edict_t *pentPlayer = FIND_CLIENT_IN_PVS(pGib->edict());
if (RANDOM_LONG(0, 100) <= 5 && pentPlayer)
{
entvars_t *pevPlayer = VARS(pentPlayer);
pGib->pev->velocity = ((pevPlayer->origin + pevPlayer->view_ofs) - pGib->pev->origin).Normalize() * 300;
pGib->pev->velocity.z += 100;
}
else
pGib->pev->velocity = Vector(RANDOM_FLOAT(-100, 100), RANDOM_FLOAT(-100, 100), RANDOM_FLOAT(200, 300));
pGib->pev->avelocity.x = RANDOM_FLOAT(100, 200);
pGib->pev->avelocity.y = RANDOM_FLOAT(100, 300);
pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor();
if (pevVictim->health > -50)
pGib->pev->velocity = pGib->pev->velocity * 0.7;
else if (pevVictim->health > -200)
pGib->pev->velocity = pGib->pev->velocity * 2;
else
pGib->pev->velocity = pGib->pev->velocity * 4;
}
pGib->LimitVelocity();
}
void CGib::SpawnRandomGibs(entvars_t *pevVictim, int cGibs, int human)
{
for (int cSplat = 0; cSplat < cGibs; cSplat++)
{
CGib *pGib = GetClassPtr((CGib *)NULL);
if (g_Language == LANGUAGE_GERMAN)
{
pGib->Spawn("models/germangibs.mdl");
pGib->pev->body = RANDOM_LONG(0, GERMAN_GIB_COUNT - 1);
}
else
{
if (human)
{
pGib->Spawn("models/hgibs.mdl");
pGib->pev->body = RANDOM_LONG(1, HUMAN_GIB_COUNT - 1);
}
else
{
pGib->Spawn("models/agibs.mdl");
pGib->pev->body = RANDOM_LONG(0, ALIEN_GIB_COUNT - 1);
}
}
if (pevVictim)
{
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) + 1;
pGib->pev->velocity = g_vecAttackDir * -1;
pGib->pev->velocity.x += RANDOM_FLOAT(-0.25, 0.25);
pGib->pev->velocity.y += RANDOM_FLOAT(-0.25, 0.25);
pGib->pev->velocity.z += RANDOM_FLOAT(-0.25, 0.25);
pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT(300, 400);
pGib->pev->avelocity.x = RANDOM_FLOAT(100, 200);
pGib->pev->avelocity.y = RANDOM_FLOAT(100, 300);
pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor();
if (pevVictim->health > -50)
pGib->pev->velocity = pGib->pev->velocity * 0.7;
else if (pevVictim->health > -200)
pGib->pev->velocity = pGib->pev->velocity * 2;
else
pGib->pev->velocity = pGib->pev->velocity * 4;
pGib->pev->solid = SOLID_BBOX;
UTIL_SetSize(pGib->pev, Vector(0, 0, 0), Vector(0, 0, 0));
}
pGib->LimitVelocity();
}
}
BOOL CBaseMonster::HasHumanGibs(void)
{
int myClass = Classify();
if (myClass == CLASS_HUMAN_MILITARY || myClass == CLASS_PLAYER_ALLY || myClass == CLASS_HUMAN_PASSIVE || myClass == CLASS_PLAYER)
return TRUE;
return FALSE;
}
BOOL CBaseMonster::HasAlienGibs(void)
{
int myClass = Classify();
if (myClass == CLASS_ALIEN_MILITARY || myClass == CLASS_ALIEN_MONSTER || myClass == CLASS_ALIEN_PASSIVE || myClass == CLASS_INSECT || myClass == CLASS_ALIEN_PREDATOR || myClass == CLASS_ALIEN_PREY)
return TRUE;
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();
}
void CBaseMonster::GibMonster(void)
{
BOOL gibbed = FALSE;
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM);
if (HasHumanGibs())
{
if (CVAR_GET_FLOAT("violence_hgibs") != 0)
{
CGib::SpawnHeadGib(pev);
CGib::SpawnRandomGibs(pev, 4, 1);
}
gibbed = TRUE;
}
else if (HasAlienGibs())
{
if (CVAR_GET_FLOAT("violence_agibs") != 0)
CGib::SpawnRandomGibs(pev, 4, 0);
gibbed = TRUE;
}
if (!IsPlayer())
{
if (gibbed)
{
SetThink(&CBaseEntity::SUB_Remove);
pev->nextthink = gpGlobals->time;
}
else
FadeMonster();
}
}
Activity CBaseMonster::GetDeathActivity(void)
{
Activity deathActivity;
BOOL fTriedDirection;
float flDot;
TraceResult tr;
Vector vecSrc;
if (pev->deadflag != DEAD_NO)
return m_IdealActivity;
vecSrc = Center();
fTriedDirection = FALSE;
deathActivity = ACT_DIESIMPLE;
UTIL_MakeVectors(pev->angles);
flDot = DotProduct(gpGlobals->v_forward, g_vecAttackDir * -1);
switch (m_LastHitGroup)
{
case HITGROUP_HEAD: deathActivity = ACT_DIE_HEADSHOT; break;
case HITGROUP_STOMACH: deathActivity = ACT_DIE_GUTSHOT; break;
case HITGROUP_GENERIC:
default:
{
fTriedDirection = TRUE;
if (flDot > 0.3)
deathActivity = ACT_DIEFORWARD;
else if (flDot <= -0.3)
deathActivity = ACT_DIEBACKWARD;
break;
}
}
if (LookupActivity(deathActivity) == ACTIVITY_NOT_AVAILABLE)
{
if (!fTriedDirection)
{
if (flDot > 0.3)
deathActivity = ACT_DIEFORWARD;
else if (flDot <= -0.3)
deathActivity = ACT_DIEBACKWARD;
}
else
deathActivity = ACT_DIESIMPLE;
}
if (LookupActivity(deathActivity) == ACTIVITY_NOT_AVAILABLE)
deathActivity = ACT_DIESIMPLE;
if (deathActivity == ACT_DIEFORWARD)
{
UTIL_TraceHull(vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr);
if (tr.flFraction != 1)
deathActivity = ACT_DIESIMPLE;
}
if (deathActivity == ACT_DIEBACKWARD)
{
UTIL_TraceHull(vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr);
if (tr.flFraction != 1)
deathActivity = ACT_DIESIMPLE;
}
return deathActivity;
}
Activity CBaseMonster::GetSmallFlinchActivity(void)
{
Activity flinchActivity;
BOOL fTriedDirection;
float flDot;
fTriedDirection = FALSE;
UTIL_MakeVectors(pev->angles);
flDot = DotProduct(gpGlobals->v_forward, g_vecAttackDir * -1);
switch (m_LastHitGroup)
{
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: flinchActivity = ACT_SMALL_FLINCH; break;
}
if (LookupActivity(flinchActivity) == ACTIVITY_NOT_AVAILABLE)
flinchActivity = ACT_SMALL_FLINCH;
return flinchActivity;
}
void CBaseMonster::BecomeDead(void)
{
pev->takedamage = DAMAGE_YES;
pev->health = pev->max_health / 2;
pev->max_health = 5;
pev->movetype = MOVETYPE_TOSS;
}
BOOL CBaseMonster::ShouldGibMonster(int iGib)
{
if ((iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE) || iGib == GIB_ALWAYS)
return TRUE;
return FALSE;
}
void CBaseMonster::CallGibMonster(void)
{
BOOL fade = FALSE;
if (HasHumanGibs())
{
if (!CVAR_GET_FLOAT("violence_hgibs"))
fade = TRUE;
}
else if (HasAlienGibs())
{
if (!CVAR_GET_FLOAT("violence_agibs"))
fade = TRUE;
}
pev->takedamage = DAMAGE_NO;
pev->solid = SOLID_NOT;
if (!fade)
{
pev->effects = EF_NODRAW;
GibMonster();
}
else
FadeMonster();
pev->deadflag = DEAD_DEAD;
FCheckAITrigger();
if (pev->health < -99)
pev->health = 0;
if (ShouldFadeOnDeath() && !fade)
UTIL_Remove(this);
}
void CBaseMonster::Killed(entvars_t *pevAttacker, int iGib)
{
if (HasMemory(bits_MEMORY_KILLED))
{
if (ShouldGibMonster(iGib))
CallGibMonster();
return;
}
Remember(bits_MEMORY_KILLED);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", VOL_NORM, ATTN_NORM);
m_IdealMonsterState = MONSTERSTATE_DEAD;
SetConditions(bits_COND_LIGHT_DAMAGE);
CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner);
if (pOwner)
pOwner->DeathNotice(pev);
if (ShouldGibMonster(iGib))
{
CallGibMonster();
return;
}
else if (pev->flags & FL_MONSTER)
{
SetTouch(NULL);
BecomeDead();
}
if (pev->health < -99)
pev->health = 0;
m_IdealMonsterState = MONSTERSTATE_DEAD;
}
void CBaseEntity::SUB_StartFadeOut(void)
{
if (pev->rendermode == kRenderNormal)
{
pev->renderamt = 255;
pev->rendermode = kRenderTransTexture;
}
pev->solid = SOLID_NOT;
pev->avelocity = g_vecZero;
pev->nextthink = gpGlobals->time + 0.1;
SetThink(&CBaseEntity::SUB_FadeOut);
}
void CBaseEntity::SUB_FadeOut(void)
{
if (pev->renderamt > 7)
{
pev->renderamt -= 7;
pev->nextthink = gpGlobals->time + 0.1;
}
else
{
pev->renderamt = 0;
pev->nextthink = gpGlobals->time + 0.2;
SetThink(&CBaseEntity::SUB_Remove);
}
}
void CGib::WaitTillLand(void)
{
if (!IsInWorld())
{
UTIL_Remove(this);
return;
}
if (pev->velocity == g_vecZero)
{
SetThink(&CBaseEntity::SUB_StartFadeOut);
pev->nextthink = gpGlobals->time + m_lifeTime;
if (m_bloodColor != DONT_BLEED)
CSoundEnt::InsertSound(bits_SOUND_MEAT, pev->origin, 384, 25);
}
else
pev->nextthink = gpGlobals->time + 0.5;
}
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
//GCC почему-СРѕ РЅРµ РІРёРґРёС‚ этот дефайн РІ extdll.h
void CGib::BounceGibTouch(CBaseEntity *pOther)
{
if (pev->flags & FL_ONGROUND)
{
pev->velocity = pev->velocity * 0.9;
pev->angles.x = 0;
pev->angles.z = 0;
pev->avelocity.x = 0;
pev->avelocity.z = 0;
}
else
{
if (g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED)
{
TraceResult tr;
Vector vecSpot = pev->origin + Vector(0, 0, 8);
UTIL_TraceLine(vecSpot, vecSpot + Vector(0, 0, -24), ignore_monsters, ENT(pev), &tr);
UTIL_BloodDecalTrace(&tr, m_bloodColor);
m_cBloodDecals--;
}
if (m_material != matNone && !RANDOM_LONG(0, 2))
{
float zvel = fabs(pev->velocity.z);
float volume = 0.8 * min(1, zvel / 450);
CBreakable::MaterialSoundRandom(edict(), (Materials)m_material, volume);
}
}
}
void CGib::StickyGibTouch(CBaseEntity *pOther)
{
SetThink(&CBaseEntity::SUB_Remove);
pev->nextthink = gpGlobals->time + 10;
if (!FClassnameIs(pOther->pev, "worldspawn"))
{
pev->nextthink = gpGlobals->time;
return;
}
TraceResult tr;
UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), &tr);
UTIL_BloodDecalTrace(&tr, m_bloodColor);
pev->velocity = tr.vecPlaneNormal * -1;
pev->angles = UTIL_VecToAngles(pev->velocity);
pev->velocity = g_vecZero;
pev->avelocity = g_vecZero;
pev->movetype = MOVETYPE_NONE;
}
void CGib::Spawn(const char *szGibModel)
{
pev->movetype = MOVETYPE_BOUNCE;
pev->friction = 0.55;
pev->renderamt = 255;
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->solid = SOLID_SLIDEBOX;
if (pev->classname)
RemoveEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
pev->classname = MAKE_STRING("gib");
AddEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
SET_MODEL(ENT(pev), szGibModel);
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
pev->nextthink = gpGlobals->time + 4;
m_lifeTime = 25;
SetThink(&CGib::WaitTillLand);
SetTouch(&CGib::BounceGibTouch);
m_material = matNone;
m_cBloodDecals = 5;
}
int CBaseMonster::TakeHealth(float flHealth, int bitsDamageType)
{
if (!pev->takedamage)
return 0;
m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED);
return CBaseEntity::TakeHealth(flHealth, bitsDamageType);
}
int CBaseMonster::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
float flTake;
Vector vecDir;
if (!pev->takedamage)
return 0;
if (!IsAlive())
return DeadTakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
if (pev->deadflag == DEAD_NO)
PainSound();
flTake = flDamage;
m_bitsDamageType |= bitsDamageType;
vecDir = Vector(0, 0, 0);
if (!FNullEnt(pevInflictor))
{
CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor);
if (pInflictor)
{
vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize();
vecDir = g_vecAttackDir = vecDir.Normalize();
}
}
if (IsPlayer())
{
if (pevInflictor)
pev->dmg_inflictor = ENT(pevInflictor);
pev->dmg_take += flTake;
}
pev->health -= flTake;
if (m_MonsterState == MONSTERSTATE_SCRIPT)
{
SetConditions(bits_COND_LIGHT_DAMAGE);
return 0;
}
if (pev->health <= 0)
{
g_pevLastInflictor = pevInflictor;
if (bitsDamageType & DMG_ALWAYSGIB)
Killed(pevAttacker, GIB_ALWAYS);
else if (bitsDamageType & DMG_NEVERGIB)
Killed(pevAttacker, GIB_NEVER);
else
Killed(pevAttacker, GIB_NORMAL);
g_pevLastInflictor = NULL;
return 0;
}
if ((pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker))
{
if (pevAttacker->flags & (FL_MONSTER | FL_CLIENT))
{
if (pevInflictor)
{
if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY))
m_vecEnemyLKP = pevInflictor->origin;
}
else
m_vecEnemyLKP = pev->origin + (g_vecAttackDir * 64);
MakeIdealYaw(m_vecEnemyLKP);
if (flDamage > 0)
SetConditions(bits_COND_LIGHT_DAMAGE);
if (flDamage >= 20)
SetConditions(bits_COND_HEAVY_DAMAGE);
}
}
return 1;
}
int CBaseMonster::DeadTakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
Vector vecDir = Vector(0, 0, 0);
if (!FNullEnt(pevInflictor))
{
CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor);
if (pInflictor)
{
vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize();
vecDir = g_vecAttackDir = vecDir.Normalize();
}
}
if (bitsDamageType & DMG_GIB_CORPSE)
{
if (pev->health <= flDamage)
{
pev->health = -50;
Killed(pevAttacker, GIB_ALWAYS);
return 0;
}
pev->health -= flDamage * 0.1;
}
return 1;
}
float CBaseMonster::DamageForce(float damage)
{
float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
if (force > 1000)
force = 1000;
return force;
}
void RadiusFlash(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage)
{
CBaseEntity *pEntity = NULL;
TraceResult tr;
float flAdjustedDamage, falloff;
Vector vecSpot;
float flRadius = 1500;
if (flRadius)
falloff = flDamage / flRadius;
else
falloff = 1;
int bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER);
vecSrc.z += 1;
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL)
{
TraceResult tr2;
Vector vecLOS;
float flDot;
float fadeTime;
float fadeHold;
int alpha;
CBasePlayer *pPlayer;
float currentHoldTime;
if (!pEntity->IsPlayer())
break;
pPlayer = (CBasePlayer *)pEntity;
if (pPlayer->pev->takedamage == DAMAGE_NO || pPlayer->pev->deadflag != DEAD_NO)
continue;
if (bInWater && !pPlayer->pev->waterlevel)
continue;
if (!bInWater && pPlayer->pev->waterlevel == 3)
continue;
vecSpot = pPlayer->BodyTarget(vecSrc);
UTIL_TraceLine(vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr);
if (tr.flFraction == 1 || tr.pHit == pPlayer->edict())
{
UTIL_TraceLine(vecSpot, vecSrc, dont_ignore_monsters, tr.pHit, &tr2);
if (tr2.flFraction < 1)
continue;
if (tr.fStartSolid)
{
tr.vecEndPos = vecSrc;
tr.flFraction = 0;
}
flAdjustedDamage = (vecSrc - tr2.vecEndPos).Length() * falloff;
flAdjustedDamage = flDamage - flAdjustedDamage;
if (flAdjustedDamage < 0)
flAdjustedDamage = 0;
UTIL_MakeVectors(pPlayer->pev->v_angle);
vecLOS = vecSrc - pPlayer->EarPosition();
flDot = DotProduct(vecLOS, gpGlobals->v_forward);
if (flDot >= 0)
{
fadeTime = flAdjustedDamage * 3;
fadeHold = flAdjustedDamage / 1.5;
alpha = 255;
}
else
{
fadeTime = flAdjustedDamage * 1.75;
fadeHold = flAdjustedDamage / 3.5;
alpha = 200;
}
currentHoldTime = pPlayer->m_blindStartTime + pPlayer->m_blindHoldTime - gpGlobals->time;
if (currentHoldTime > 0 && alpha == 255)
fadeHold += currentHoldTime;
if (pPlayer->m_blindStartTime != 0 && pPlayer->m_blindFadeTime != 0)
{
if (pPlayer->m_blindStartTime + pPlayer->m_blindFadeTime + pPlayer->m_blindHoldTime > gpGlobals->time)
{
if (pPlayer->m_blindFadeTime > fadeTime)
fadeTime = pPlayer->m_blindFadeTime;
if (pPlayer->m_blindAlpha > alpha)
alpha = pPlayer->m_blindAlpha;
}
}
UTIL_ScreenFade(pPlayer, Vector(255, 255, 255), fadeTime, fadeHold, alpha, 0);
currentHoldTime = 1;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pObserver = (CBasePlayer *)UTIL_PlayerByIndex(i);
if (pObserver && pObserver->IsObservingPlayer(pPlayer) && fadetoblack.value == 0)
UTIL_ScreenFade(pPlayer, Vector(255, 255, 255), fadeTime, fadeHold, alpha, 0);
currentHoldTime++;
}
pPlayer->Blind(fadeTime / 3, fadeHold, fadeTime, alpha);
}
}
}
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;
if (flRadius)
falloff = flDamage / flRadius;
else
falloff = 1;
int bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER);
vecSrc.z += 1;
if (!pevAttacker)
pevAttacker = pevInflictor;
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL)
{
if (pEntity->pev->takedamage == DAMAGE_NO)
continue;
if (iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore)
continue;
if (bInWater && !pEntity->pev->waterlevel)
continue;
if (!bInWater && pEntity->pev->waterlevel == 3)
continue;
flAdjustedDamage = (vecSrc - pEntity->pev->origin).Length() * falloff;
flAdjustedDamage = flDamage - flAdjustedDamage;
if (flAdjustedDamage < 0)
flAdjustedDamage = 0;
pEntity->TakeDamage(pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType);
}
}
void RadiusDamage2(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;
if (flRadius)
falloff = flDamage / flRadius;
else
falloff = 1;
int bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER);
vecSrc.z += 1;
if (!pevAttacker)
pevAttacker = pevInflictor;
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL)
{
if (pEntity->pev->takedamage == DAMAGE_NO)
continue;
if (iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore)
continue;
if (bInWater && !pEntity->pev->waterlevel)
continue;
if (!bInWater && pEntity->pev->waterlevel == 3)
continue;
if (!pEntity->IsPlayer())
break;
vecSpot = pEntity->BodyTarget(vecSrc);
UTIL_TraceLine(vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr);
if (tr.flFraction == 1 || tr.pHit == pEntity->edict())
{
if (tr.fStartSolid)
{
tr.vecEndPos = vecSrc;
tr.flFraction = 0;
}
flAdjustedDamage = (vecSrc - pEntity->pev->origin).Length() * falloff;
flAdjustedDamage = flDamage - flAdjustedDamage;
if (flAdjustedDamage < 0)
flAdjustedDamage = 0;
else if (flAdjustedDamage > 75)
flAdjustedDamage = 75;
if (tr.flFraction != 1)
{
ClearMultiDamage();
pEntity->TraceAttack(pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType);
ApplyMultiDamage(pevInflictor, pevAttacker);
}
else
pEntity->TakeDamage(pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType);
}
}
}
void CBaseMonster::RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType)
{
if (flDamage <= 80)
::RadiusDamage2(pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * (RANDOM_FLOAT(0.5, 1.5) + 3), iClassIgnore, bitsDamageType);
else
::RadiusDamage(pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 3.5, iClassIgnore, bitsDamageType);
}
void CBaseMonster::RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType)
{
if (flDamage <= 80)
::RadiusDamage2(vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * (RANDOM_FLOAT(0.5, 1.5) + 3), iClassIgnore, bitsDamageType);
else
::RadiusDamage(vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 3.5, iClassIgnore, bitsDamageType);
}
CBaseEntity *CBaseMonster::CheckTraceHullAttack(float flDist, int iDamage, int iDmgType)
{
if (IsPlayer())
UTIL_MakeVectors(pev->angles);
else
UTIL_MakeAimVectors(pev->angles);
Vector vecStart = pev->origin;
vecStart.z += pev->size.z * 0.5;
Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist);
TraceResult tr;
UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr);
if (tr.pHit)
{
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
if (iDamage > 0)
pEntity->TakeDamage(pev, pev, iDamage, iDmgType);
return pEntity;
}
return NULL;
}
BOOL CBaseMonster::FInViewCone(CBaseEntity *pEntity)
{
UTIL_MakeVectors(pev->angles);
Vector2D vec2LOS = (pEntity->pev->origin - pev->origin).Make2D();
vec2LOS = vec2LOS.Normalize();
float flDot = DotProduct(vec2LOS, gpGlobals->v_forward.Make2D());
if (flDot > m_flFieldOfView)
return TRUE;
return FALSE;
}
BOOL CBaseMonster::FInViewCone(Vector *pOrigin)
{
UTIL_MakeVectors(pev->angles);
Vector2D vec2LOS = (*pOrigin - pev->origin).Make2D();
vec2LOS = vec2LOS.Normalize();
float flDot = DotProduct(vec2LOS, gpGlobals->v_forward.Make2D());
if (flDot > m_flFieldOfView)
return TRUE;
return FALSE;
}
BOOL CBaseEntity::FVisible(CBaseEntity *pEntity)
{
if (FBitSet(pEntity->pev->flags, FL_NOTARGET))
return FALSE;
if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) || (pev->waterlevel == 3 && !pEntity->pev->waterlevel))
return FALSE;
TraceResult tr;
Vector vecLookerOrigin = pev->origin + pev->view_ofs;
Vector vecTargetOrigin = pEntity->EyePosition();
UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT(pev), &tr);
if (tr.flFraction != 1)
return FALSE;
return TRUE;
}
BOOL CBaseEntity::FVisible(const Vector &vecOrigin)
{
TraceResult tr;
Vector vecLookerOrigin = EyePosition();
UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT(pev), &tr);
if (tr.flFraction != 1)
return FALSE;
return TRUE;
}
void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, const Vector &vecDir, TraceResult *ptr, int bitsDamageType)
{
Vector vecOrigin = ptr->vecEndPos - vecDir * 4;
if (!pev->takedamage)
return;
AddMultiDamage(pevAttacker, this, flDamage, bitsDamageType);
int blood = BloodColor();
if (blood != DONT_BLEED)
{
SpawnBlood(vecOrigin, blood, flDamage);
TraceBleed(flDamage, vecDir, ptr, bitsDamageType);
}
}
void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, const Vector &vecDir, TraceResult *ptr, int bitsDamageType)
{
if (!pev->takedamage)
return;
m_LastHitGroup = ptr->iHitgroup;
switch (ptr->iHitgroup)
{
case HITGROUP_GENERIC: break;
case HITGROUP_HEAD: flDamage *= 3; break;
case HITGROUP_CHEST:
case HITGROUP_STOMACH: flDamage *= 1.5; break;
case HITGROUP_LEFTARM:
case HITGROUP_RIGHTARM: flDamage *= 1.0; break;
case HITGROUP_LEFTLEG:
case HITGROUP_RIGHTLEG: flDamage *= 0.75; break;
case HITGROUP_SHIELD: flDamage = 0; break;
default: break;
}
CBaseEntity::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
}
void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker)
{
static int tracerCount;
int tracer;
TraceResult tr;
Vector vecRight = gpGlobals->v_right;
Vector vecUp = gpGlobals->v_up;
if (!pevAttacker)
pevAttacker = pev;
ClearMultiDamage();
gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;
for (ULONG iShot = 1; iShot <= cShots; iShot++)
{
float x, y, z;
do
{
x = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5);
y = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5);
z = x * x + y * y;
}
while (z > 1);
TraceResult tr;
Vector vecDir = vecDirShooting + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp;
Vector vecEnd = vecSrc + vecDir * flDistance;
UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &tr);
tracer = 0;
if (iTracerFreq != 0 && !(tracerCount++ % iTracerFreq))
{
Vector vecTracerSrc;
if (IsPlayer())
vecTracerSrc = vecSrc + Vector(0, 0, -4) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16;
else
vecTracerSrc = vecSrc;
if (iTracerFreq != 1)
tracer = 1;
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();
}
if (tr.flFraction != 1)
{
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
if (iDamage)
{
pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB));
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
DecalGunshot(&tr, iBulletType, FALSE, pev, FALSE);
}
else switch (iBulletType)
{
case BULLET_PLAYER_MP5:
{
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET);
break;
}
case BULLET_PLAYER_BUCKSHOT:
{
pEntity->TraceAttack(pevAttacker, (int)((1 - tr.flFraction) * 20), vecDir, &tr, DMG_BULLET);
break;
}
case BULLET_PLAYER_357:
{
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET);
break;
}
case BULLET_MONSTER_9MM:
{
pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET);
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
DecalGunshot(&tr, iBulletType, false, pev, false);
break;
}
case BULLET_MONSTER_MP5:
{
pEntity->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET);
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
DecalGunshot(&tr, iBulletType, false, pev, false);
break;
}
case BULLET_MONSTER_12MM:
{
pEntity->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET);
if (!tracer)
{
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
DecalGunshot(&tr, iBulletType, false, pev, false);
}
break;
}
case BULLET_NONE:
{
pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
if (!FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
UTIL_DecalTrace(&tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0, 2));
break;
}
default:
{
pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET);
break;
}
}
}
UTIL_BubbleTrail(vecSrc, tr.vecEndPos, (int)((flDistance * tr.flFraction) / 64));
}
ApplyMultiDamage(pev, pevAttacker);
}
#pragma optimize("", off)
Vector CBaseEntity::FireBullets3(Vector vecSrc, Vector vecDirShooting, float flSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand)
{
int iOriginalPenetration = iPenetration;
int iPenetrationPower;
float flPenetrationDistance;
int iCurrentDamage = iDamage;
float flCurrentDistance;
TraceResult tr, tr2;
Vector vecRight = gpGlobals->v_right;
Vector vecUp = gpGlobals->v_up;
CBaseEntity *pEntity;
bool bHitMetal = false;
int iSparksAmount;
switch (iBulletType)
{
case BULLET_PLAYER_9MM:
{
iPenetrationPower = 21;
flPenetrationDistance = 800;
iSparksAmount = 15;
iCurrentDamage += (-4 + RANDOM_LONG(0, 10));
break;
}
case BULLET_PLAYER_45ACP:
{
iPenetrationPower = 15;
flPenetrationDistance = 500;
iSparksAmount = 20;
iCurrentDamage += (-2 + RANDOM_LONG(0, 4));
break;
}
case BULLET_PLAYER_50AE:
{
iPenetrationPower = 30;
flPenetrationDistance = 1000;
iSparksAmount = 20;
iCurrentDamage += (-4 + RANDOM_LONG(0, 10));
break;
}
case BULLET_PLAYER_762MM:
{
iPenetrationPower = 39;
flPenetrationDistance = 5000;
iSparksAmount = 30;
iCurrentDamage += (-2 + RANDOM_LONG(0, 4));
break;
}
case BULLET_PLAYER_556MM:
{
iPenetrationPower = 35;
flPenetrationDistance = 4000;
iSparksAmount = 30;
iCurrentDamage += (-3 + RANDOM_LONG(0, 6));
break;
}
case BULLET_PLAYER_338MAG:
{
iPenetrationPower = 45;
flPenetrationDistance = 8000;
iSparksAmount = 30;
iCurrentDamage += (-4 + RANDOM_LONG(0, 8));
break;
}
case BULLET_PLAYER_57MM:
{
iPenetrationPower = 30;
flPenetrationDistance = 2000;
iSparksAmount = 20;
iCurrentDamage += (-4 + RANDOM_LONG(0, 10));
break;
}
case BULLET_PLAYER_357SIG:
{
iPenetrationPower = 25;
flPenetrationDistance = 800;
iSparksAmount = 20;
iCurrentDamage += (-4 + RANDOM_LONG(0, 10));
break;
}
default:
{
iPenetrationPower = 0;
flPenetrationDistance = 0;
break;
}
}
if (!pevAttacker)
pevAttacker = pev;
gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;
float x, y, z;
if (IsPlayer())
{
x = UTIL_SharedRandomFloat(shared_rand, -0.5, 0.5) + UTIL_SharedRandomFloat(shared_rand + 1, -0.5, 0.5);
y = UTIL_SharedRandomFloat(shared_rand + 2, -0.5, 0.5) + UTIL_SharedRandomFloat(shared_rand + 3, -0.5, 0.5);
}
else
{
do
{
x = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5);
y = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5);
z = x * x + y * y;
}
while (z > 1);
}
Vector vecDir = vecDirShooting + x * flSpread * vecRight + y * flSpread * vecUp;
Vector vecEnd = vecSrc + vecDir * flDistance;
Vector vecOldSrc;
Vector vecNewSrc;
float flDamageModifier = 0.5;
while (iPenetration != 0)
{
ClearMultiDamage();
UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &tr);
char cTextureType = UTIL_TextureHit(&tr, vecSrc, vecEnd);
bool bSparks = false;
switch (cTextureType)
{
case CHAR_TEX_METAL:
{
bSparks = true;
bHitMetal = true;
iPenetrationPower *= 0.15;
flDamageModifier = 0.2;
break;
}
case CHAR_TEX_CONCRETE:
{
iPenetrationPower *= 0.25;
flDamageModifier = 0.25;
break;
}
case CHAR_TEX_GRATE:
{
bSparks = true;
bHitMetal = true;
iPenetrationPower *= 0.5;
flDamageModifier = 0.4;
break;
}
case CHAR_TEX_VENT:
{
bSparks = true;
bHitMetal = true;
iPenetrationPower *= 0.5;
flDamageModifier = 0.45;
break;
}
case CHAR_TEX_TILE:
{
iPenetrationPower *= 0.65;
flDamageModifier = 0.3;
break;
}
case CHAR_TEX_COMPUTER:
{
bSparks = true;
bHitMetal = true;
iPenetrationPower *= 0.4;
flDamageModifier = 0.45;
break;
}
case CHAR_TEX_WOOD:
{
iPenetrationPower *= 1;
flDamageModifier = 0.6;
break;
}
default:
{
bSparks = false;
break;
}
}
if (tr.flFraction != 1.0)
{
pEntity = CBaseEntity::Instance(tr.pHit);
iPenetration--;
flCurrentDistance = tr.flFraction * flDistance;
iCurrentDamage *= pow(flRangeModifier, flCurrentDistance / 500);
if (flCurrentDistance > flPenetrationDistance)
iPenetration = 0;
if (tr.iHitgroup == HITGROUP_SHIELD)
{
iPenetration = 0;
if (tr.flFraction != 1.0)
{
if (RANDOM_LONG(0, 1))
EMIT_SOUND(pEntity->edict(), CHAN_VOICE, "weapons/ric_metal-1.wav", 1, ATTN_NORM);
else
EMIT_SOUND(pEntity->edict(), CHAN_VOICE, "weapons/ric_metal-2.wav", 1, ATTN_NORM);
UTIL_Sparks(tr.vecEndPos);
pEntity->pev->punchangle.x = iCurrentDamage * RANDOM_FLOAT(-0.15, 0.15);
pEntity->pev->punchangle.z = iCurrentDamage * RANDOM_FLOAT(-0.15, 0.15);
if (pEntity->pev->punchangle.x < 4)
pEntity->pev->punchangle.x = 4;
if (pEntity->pev->punchangle.z < -5)
pEntity->pev->punchangle.z = -5;
else if (pEntity->pev->punchangle.z > 5)
pEntity->pev->punchangle.z = 5;
}
break;
}
if ((VARS(tr.pHit)->solid == SOLID_BSP) && (iPenetration != 0))
{
if (bPistol)
DecalGunshot(&tr, iBulletType, false, pev, bHitMetal);
else if (RANDOM_LONG(0, 3))
DecalGunshot(&tr, iBulletType, true, pev, bHitMetal);
vecSrc = tr.vecEndPos + (vecDir * iPenetrationPower);
flDistance = (flDistance - flCurrentDistance) * 0.5;
vecEnd = vecSrc + (vecDir * flDistance);
pEntity->TraceAttack(pevAttacker, iCurrentDamage, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB);
iCurrentDamage *= flDamageModifier;
}
else
{
if (bPistol)
DecalGunshot(&tr, iBulletType, false, pev, bHitMetal);
else if (RANDOM_LONG(0, 3))
DecalGunshot(&tr, iBulletType, true, pev, bHitMetal);
vecSrc = tr.vecEndPos + (vecDir * 42);
flDistance = (flDistance - flCurrentDistance) * 0.75;
vecEnd = vecSrc + (vecDir * flDistance);
pEntity->TraceAttack(pevAttacker, iCurrentDamage, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB);
iCurrentDamage *= 0.75;
}
}
else
iPenetration = 0;
ApplyMultiDamage(pev, pevAttacker);
}
return Vector(x * flSpread, y * flSpread, 0);
}
#pragma optimize("", on)
void CBaseEntity::TraceBleed(float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
if (BloodColor() == DONT_BLEED)
return;
if (!flDamage)
return;
if (!(bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR)))
return;
float flNoise;
int cCount;
if (flDamage < 10)
{
flNoise = 0.1;
cCount = 1;
}
else if (flDamage < 25)
{
flNoise = 0.2;
cCount = 2;
}
else
{
flNoise = 0.3;
cCount = 4;
}
for (int i = 0; i < cCount; i++)
{
Vector vecTraceDir = vecDir * -1;
vecTraceDir.x += RANDOM_FLOAT(-flNoise, flNoise);
vecTraceDir.y += RANDOM_FLOAT(-flNoise, flNoise);
vecTraceDir.z += RANDOM_FLOAT(-flNoise, flNoise);
TraceResult Bloodtr;
UTIL_TraceLine(ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr);
if (Bloodtr.flFraction != 1)
{
if (!RANDOM_LONG(0, 2))
UTIL_BloodDecalTrace(&Bloodtr, BloodColor());
}
}
}
void CBaseMonster::BloodSplat(const Vector &vecPos, const Vector &vecDir, int hitgroup, int iDamage)
{
if (hitgroup != HITGROUP_HEAD)
return;
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecPos);
WRITE_BYTE(TE_BLOODSTREAM);
WRITE_COORD(vecPos.x);
WRITE_COORD(vecPos.y);
WRITE_COORD(vecPos.z);
WRITE_COORD(vecDir.x);
WRITE_COORD(vecDir.y);
WRITE_COORD(vecDir.z);
WRITE_BYTE(223);
WRITE_BYTE(iDamage + RANDOM_LONG(0, 100));
MESSAGE_END();
}