235 lines
5.8 KiB
C++
235 lines
5.8 KiB
C++
/***
|
|
*
|
|
* 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;
|
|
}
|
|
}
|