262 lines
6.8 KiB
C++
262 lines
6.8 KiB
C++
/***
|
|
*
|
|
* 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 "utils.h"
|
|
#include "cbase.h"
|
|
#include "client.h"
|
|
#include "monsters.h"
|
|
#include "soundent.h"
|
|
#include "decals.h"
|
|
#include "animation.h"
|
|
#include "baseweapon.h"
|
|
#include "basebrush.h"
|
|
#include "defaults.h"
|
|
|
|
extern DLL_GLOBAL Vector g_vecAttackDir;
|
|
|
|
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
|
|
|
MULTIDAMAGE gMultiDamage;
|
|
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
MULTI-DAMAGE
|
|
|
|
Collects multiple small damages into a single damage
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
//
|
|
// ClearMultiDamage - resets the global multi damage accumulator
|
|
//
|
|
void ClearMultiDamage(void)
|
|
{
|
|
gMultiDamage.pEntity = NULL;
|
|
gMultiDamage.amount = 0;
|
|
gMultiDamage.type = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity
|
|
//
|
|
// GLOBALS USED:
|
|
// gMultiDamage
|
|
|
|
void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker )
|
|
{
|
|
Vector vecSpot1;//where blood comes from
|
|
Vector vecDir;//direction blood should go
|
|
TraceResult tr;
|
|
|
|
if ( !gMultiDamage.pEntity )
|
|
return;
|
|
|
|
gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
|
}
|
|
|
|
|
|
// GLOBALS USED:
|
|
// gMultiDamage
|
|
|
|
void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType)
|
|
{
|
|
if ( !pEntity )
|
|
return;
|
|
|
|
gMultiDamage.type |= bitsDamageType;
|
|
|
|
if ( pEntity != gMultiDamage.pEntity )
|
|
{
|
|
ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker!
|
|
gMultiDamage.pEntity = pEntity;
|
|
gMultiDamage.amount = 0;
|
|
}
|
|
|
|
gMultiDamage.amount += flDamage;
|
|
}
|
|
|
|
void DecalGunshot( TraceResult *pTrace, int iBulletType )
|
|
{
|
|
// Is the entity valid
|
|
if ( !UTIL_IsValidEntity( pTrace->pHit ) )
|
|
return;
|
|
|
|
if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP )
|
|
{
|
|
CBaseEntity *pEntity = NULL;
|
|
// Decal the wall with a gunshot
|
|
if ( !FNullEnt(pTrace->pHit) )
|
|
pEntity = CBaseEntity::Instance(pTrace->pHit);
|
|
|
|
switch( iBulletType )
|
|
{
|
|
case BULLET_9MM:
|
|
case BULLET_MP5:
|
|
case BULLET_BUCKSHOT:
|
|
case BULLET_357:
|
|
default:
|
|
// smoke and decal
|
|
UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) );
|
|
break;
|
|
case BULLET_12MM:
|
|
// smoke and decal
|
|
UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) );
|
|
break;
|
|
case BULLET_CROWBAR:
|
|
// wall decal
|
|
UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// EjectBrass - tosses a brass shell from passed origin at passed velocity
|
|
//
|
|
void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype )
|
|
{
|
|
// FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see.
|
|
|
|
MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, vecOrigin );
|
|
WRITE_BYTE( TE_MODEL);
|
|
WRITE_COORD( vecOrigin.x);
|
|
WRITE_COORD( vecOrigin.y);
|
|
WRITE_COORD( vecOrigin.z);
|
|
WRITE_COORD( vecVelocity.x);
|
|
WRITE_COORD( vecVelocity.y);
|
|
WRITE_COORD( vecVelocity.z);
|
|
WRITE_ANGLE( rotation );
|
|
WRITE_SHORT( model );
|
|
WRITE_BYTE ( soundtype);
|
|
WRITE_BYTE ( 25 );// 2.5 seconds
|
|
MESSAGE_END();
|
|
}
|
|
|
|
/*
|
|
================
|
|
SpawnBlood
|
|
================
|
|
*/
|
|
void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage)
|
|
{
|
|
UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage );
|
|
}
|
|
|
|
|
|
int DamageDecal( CBaseEntity *pEntity, int bitsDamageType )
|
|
{
|
|
if ( !pEntity )
|
|
return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4));
|
|
|
|
return pEntity->DamageDecal( bitsDamageType );
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
if ( flRadius )
|
|
falloff = flDamage / flRadius;
|
|
else
|
|
falloff = 1.0;
|
|
|
|
int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER);
|
|
|
|
vecSrc.z += 1;// in case grenade is lying on the ground
|
|
|
|
if ( !pevAttacker )
|
|
pevAttacker = pevInflictor;
|
|
|
|
// iterate on all entities in the vicinity.
|
|
while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL)
|
|
{
|
|
if ( pEntity->pev->takedamage != DAMAGE_NO )
|
|
{
|
|
// UNDONE: this should check a damage mask, not an ignore
|
|
if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore )
|
|
{// houndeyes don't hurt other houndeyes with their attack
|
|
continue;
|
|
}
|
|
|
|
// blast's don't tavel into or out of water
|
|
if (bInWater && pEntity->pev->waterlevel == 0)
|
|
continue;
|
|
if (!bInWater && pEntity->pev->waterlevel == 3)
|
|
continue;
|
|
|
|
vecSpot = pEntity->BodyTarget( vecSrc );
|
|
|
|
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr );
|
|
|
|
if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() )
|
|
{// the explosion can 'see' this entity, so hurt them!
|
|
if (tr.fStartSolid)
|
|
{
|
|
// if we're stuck inside them, fixup the position and distance
|
|
tr.vecEndPos = vecSrc;
|
|
tr.flFraction = 0.0;
|
|
}
|
|
|
|
// decrease damage for an ent that's farther from the bomb.
|
|
flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff;
|
|
flAdjustedDamage = flDamage - flAdjustedDamage;
|
|
|
|
if ( flAdjustedDamage < 0 )
|
|
{
|
|
flAdjustedDamage = 0;
|
|
}
|
|
|
|
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
|
|
if (tr.flFraction != 1.0)
|
|
{
|
|
ClearMultiDamage( );
|
|
pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType );
|
|
ApplyMultiDamage( pevInflictor, pevAttacker );
|
|
}
|
|
else
|
|
{
|
|
pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|