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