This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/server/monsters/combat.cpp

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 );
}
}
}
}
}