/*** * * Copyright (c) 1996-2001, 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. * ****/ /* ===== weapons.cpp ======================================================== functions governing the selection/use of weapons for players */ #include "extdll.h" #include "util.h" #include "cmbase.h" #include "cmbasemonster.h" #include "monsters.h" #include "weapons.h" #include "nodes.h" #include "decals.h" extern CGraph WorldGraph; MULTIDAMAGE gMultiDamage; #define TRACER_FREQ 4 // Tracers fire every fourth bullet /* ============================================================================== 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; if (UTIL_IsPlayer(gMultiDamage.pEntity)) UTIL_TakeDamage(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); else if (gMultiDamage.pEntity->v.euser4 != NULL) { CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity)); pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); } else UTIL_TakeDamageExternal(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); } // GLOBALS USED: // gMultiDamage void AddMultiDamage( entvars_t *pevInflictor, edict_t *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; } /* ================ SpawnBlood ================ */ void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); } int DamageDecal( CMBaseEntity *pEntity, int bitsDamageType ) { if ( !pEntity ) return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); return pEntity->DamageDecal( bitsDamageType ); } 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 ) { CMBaseEntity *pEntity = NULL; // Decal the wall with a gunshot if ( !FNullEnt(pTrace->pHit) ) pEntity = CMBaseEntity::Instance(pTrace->pHit); switch( iBulletType ) { case BULLET_PLAYER_CROWBAR: { // wall decal UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); break; } default: { // smoke and decal UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); break; } /* why the duplicate case? case BULLET_PLAYER_9MM: case BULLET_MONSTER_9MM: case BULLET_PLAYER_MP5: case BULLET_MONSTER_MP5: case BULLET_PLAYER_BUCKSHOT: case BULLET_PLAYER_357: default: // smoke and decal UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); break; case BULLET_MONSTER_12MM: // smoke and decal UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); break; case BULLET_PLAYER_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, SVC_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(); } #if 0 // UNDONE: This is no longer used? void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) { MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); WRITE_BYTE ( TE_EXPLODEMODEL ); WRITE_COORD( vecOrigin.x ); WRITE_COORD( vecOrigin.y ); WRITE_COORD( vecOrigin.z ); WRITE_COORD( speed ); WRITE_SHORT( model ); WRITE_SHORT( count ); WRITE_BYTE ( 15 );// 1.5 seconds MESSAGE_END(); } #endif BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) { #if defined( CLIENT_WEAPONS ) if ( !isPredicted ) #else if ( 1 ) #endif { return ( attack_time <= curtime ) ? TRUE : FALSE; } else { return ( attack_time <= 0.0 ) ? TRUE : FALSE; } }