halflife-sdk/cl_dll/ev_hldm.cpp

1133 lines
30 KiB
C++
Raw Normal View History

2000-06-05 00:00:00 +00:00
/***
*
* Copyright (c) 1999, 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.
*
****/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "entity_types.h"
#include "usercmd.h"
#include "pm_defs.h"
#include "pm_materials.h"
#include "eventscripts.h"
#include "ev_hldm.h"
#include "r_efx.h"
#include "event_api.h"
#include "event_args.h"
#include "in_defs.h"
#include <string.h>
static int tracerCount[ 32 ];
extern "C" char PM_FindTextureType( char *name );
void V_PunchAxis( int axis, float punch );
extern "C"
{
// HLDM
void EV_FireGlock1( struct event_args_s *args );
void EV_FireGlock2( struct event_args_s *args );
void EV_FireShotGunSingle( struct event_args_s *args );
void EV_FireShotGunDouble( struct event_args_s *args );
void EV_FireMP5( struct event_args_s *args );
void EV_FirePython( struct event_args_s *args );
void EV_FireGauss( struct event_args_s *args );
void EV_SpinGauss( struct event_args_s *args );
void EV_TrainPitchAdjust( struct event_args_s *args );
}
#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 )
#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 )
#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 )
#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 )
#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 )
#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 )
#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 )
#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 )
#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 )
#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 )
#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 )
#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 )
// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the
// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture.
// returns volume of strike instrument (crowbar) to play
float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType )
{
// hit the world, try to play sound based on texture material type
char chTextureType = CHAR_TEX_CONCRETE;
float fvol;
float fvolbar;
char *rgsz[4];
int cnt;
float fattn = ATTN_NORM;
int entity;
char *pTextureName;
char texname[ 64 ];
char szbuffer[ 64 ];
entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr );
// FIXME check if playtexture sounds movevar is set
//
chTextureType = 0;
// Player
if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() )
{
// hit body
chTextureType = CHAR_TEX_FLESH;
}
else if ( entity == 0 )
{
// get texture from entity or world (world is ent(0))
pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd );
if ( pTextureName )
{
strcpy( texname, pTextureName );
pTextureName = texname;
// strip leading '-0' or '+0~' or '{' or '!'
if (*pTextureName == '-' || *pTextureName == '+')
{
pTextureName += 2;
}
if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ')
{
pTextureName++;
}
// '}}'
strcpy( szbuffer, pTextureName );
szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0;
// get texture type
chTextureType = PM_FindTextureType( szbuffer );
}
}
switch (chTextureType)
{
default:
case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6;
rgsz[0] = "player/pl_step1.wav";
rgsz[1] = "player/pl_step2.wav";
cnt = 2;
break;
case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3;
rgsz[0] = "player/pl_metal1.wav";
rgsz[1] = "player/pl_metal2.wav";
cnt = 2;
break;
case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1;
rgsz[0] = "player/pl_dirt1.wav";
rgsz[1] = "player/pl_dirt2.wav";
rgsz[2] = "player/pl_dirt3.wav";
cnt = 3;
break;
case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3;
rgsz[0] = "player/pl_duct1.wav";
rgsz[1] = "player/pl_duct1.wav";
cnt = 2;
break;
case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5;
rgsz[0] = "player/pl_grate1.wav";
rgsz[1] = "player/pl_grate4.wav";
cnt = 2;
break;
case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2;
rgsz[0] = "player/pl_tile1.wav";
rgsz[1] = "player/pl_tile3.wav";
rgsz[2] = "player/pl_tile2.wav";
rgsz[3] = "player/pl_tile4.wav";
cnt = 4;
break;
case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0;
rgsz[0] = "player/pl_slosh1.wav";
rgsz[1] = "player/pl_slosh3.wav";
rgsz[2] = "player/pl_slosh2.wav";
rgsz[3] = "player/pl_slosh4.wav";
cnt = 4;
break;
case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2;
rgsz[0] = "debris/wood1.wav";
rgsz[1] = "debris/wood2.wav";
rgsz[2] = "debris/wood3.wav";
cnt = 3;
break;
case CHAR_TEX_GLASS:
case CHAR_TEX_COMPUTER:
fvol = 0.8; fvolbar = 0.2;
rgsz[0] = "debris/glass1.wav";
rgsz[1] = "debris/glass2.wav";
rgsz[2] = "debris/glass3.wav";
cnt = 3;
break;
case CHAR_TEX_FLESH:
if (iBulletType == BULLET_PLAYER_CROWBAR)
return 0.0; // crowbar already makes this sound
fvol = 1.0; fvolbar = 0.2;
rgsz[0] = "weapons/bullet_hit1.wav";
rgsz[1] = "weapons/bullet_hit2.wav";
fattn = 1.0;
cnt = 2;
break;
}
// play material hit sound
gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) );
return fvolbar;
}
char *EV_HLDM_DamageDecal( physent_t *pe )
{
static char decalname[ 32 ];
int idx;
if ( pe->classnumber == 1 )
{
idx = gEngfuncs.pfnRandomLong( 0, 2 );
sprintf( decalname, "{break%i", idx + 1 );
}
else if ( pe->rendermode != kRenderNormal )
{
sprintf( decalname, "{bproof1" );
}
else
{
idx = gEngfuncs.pfnRandomLong( 0, 4 );
sprintf( decalname, "{shot%i", idx + 1 );
}
return decalname;
}
void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName )
{
int iRand;
physent_t *pe;
gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos );
iRand = gEngfuncs.pfnRandomLong(0,0x7FFF);
if ( iRand < (0x7fff/2) )// not every bullet makes a sound.
{
switch( iRand % 5)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent );
// Only decal brush models such as the world etc.
if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) )
{
if ( CVAR_GET_FLOAT( "r_decals" ) )
{
gEngfuncs.pEfxAPI->R_DecalShoot(
gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ),
gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 );
}
}
}
void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType )
{
physent_t *pe;
pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent );
if ( pe && pe->solid == SOLID_BSP )
{
switch( iBulletType )
{
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
EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) );
break;
}
}
}
int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount )
{
int tracer = 0;
int i;
qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false;
if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 )
{
vec3_t vecTracerSrc;
if ( player )
{
vec3_t offset( 0, 0, -4 );
// adjust tracer position for player
for ( i = 0; i < 3; i++ )
{
vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16;
}
}
else
{
VectorCopy( vecSrc, vecTracerSrc );
}
if ( iTracerFreq != 1 ) // guns that always trace also always decal
tracer = 1;
switch( iBulletType )
{
case BULLET_PLAYER_MP5:
case BULLET_MONSTER_MP5:
case BULLET_MONSTER_9MM:
case BULLET_MONSTER_12MM:
default:
EV_CreateTracer( vecTracerSrc, end );
break;
}
}
return tracer;
}
/*
================
FireBullets
Go to the trouble of combining multiple pellets into a single damage call.
================
*/
void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float *vecSpread, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount )
{
int i;
pmtrace_t tr;
int iShot;
vec3_t vecRight, vecUp;
int tracer;
VectorCopy( right, vecRight );
VectorCopy( up, vecUp );
for ( iShot = 1; iShot <= cShots; iShot++ )
{
vec3_t vecDir, vecEnd;
// get circular gaussian spread
vec3_t spread;
do {
spread[0] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5);
spread[1] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5);
spread[2] = spread[0] * spread[0] + spread[1] *spread[1];
} while (spread[2] > 1);
for ( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + spread[ 0 ] * vecSpread[ 0 ] * vecRight[ i ] + spread[ 1 ] * vecSpread[ 1 ] * up [ i ];
vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ];
}
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount );
// do damage, paint decals
if ( tr.fraction != 1.0 )
{
switch(iBulletType)
{
default:
case BULLET_PLAYER_9MM:
if ( !tracer )
{
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
}
break;
case BULLET_PLAYER_MP5:
if ( !tracer )
{
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
}
break;
case BULLET_PLAYER_BUCKSHOT:
if ( !tracer )
{
EV_HLDM_DecalGunshot( &tr, iBulletType );
}
break;
case BULLET_PLAYER_357:
if ( !tracer )
{
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
}
break;
}
}
gEngfuncs.pEventAPI->EV_PopPMStates();
}
}
void EV_FireGlock1( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int empty;
int i;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
empty = args->bparam1;
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell
if ( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
for ( i = 0; i < 3; i++ )
{
vecSpread[ i ] = flSpread;
}
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] );
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -2.0 );
}
}
void EV_FireGlock2( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int i;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
vec3_t up, right, forward;
float flSpread = 0.1;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
for ( i = 0; i < 3; i++ )
{
vecSpread[ i ] = flSpread;
}
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] );
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -2.0 );
}
}
void EV_FireShotGunDouble( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int i, j;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 );
}
for ( j = 0; j < 2; j++ )
{
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 );
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
if ( gEngfuncs.GetMaxClients() > 1 )
{
for ( i = 0; i < 3; i++ )
{
vecSpread[0] = 0.17365;
vecSpread[1] = 0.04362;
vecSpread[2] = 0.00;
}
EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] );
}
else
{
EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] );
}
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -10.0 );
}
}
void EV_FireShotGunSingle( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int i;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 );
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
if ( gEngfuncs.GetMaxClients() > 1 )
{
for ( i = 0; i < 3; i++ )
{
vecSpread[0] = 0.08716;
vecSpread[1] = 0.04362;
vecSpread[2] = 0.00;
}
EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] );
}
else
{
EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] );
}
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -5.0 );
}
}
void EV_FireMP5( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
switch( gEngfuncs.pfnRandomLong( 0, 1 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
}
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
if ( gEngfuncs.GetMaxClients() > 1 )
{
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1] );
}
else
{
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1] );
}
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) );
}
}
void EV_FirePython( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
if ( EV_IsLocal( idx ) )
{
// Python uses different body in multiplayer versus single player
int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1;
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 );
}
switch( gEngfuncs.pfnRandomLong( 0, 1 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM );
break;
}
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, &tracerCount[idx-1] );
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -10.0 );
}
}
#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch
void EV_SpinGauss( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int iSoundState = 0;
int pitch;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
pitch = args->iparam1;
iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0;
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch );
}
2000-11-07 00:00:00 +00:00
/*
==============================
EV_StopPreviousGauss
==============================
*/
void EV_StopPreviousGauss( int idx )
{
// Make sure we don't have a gauss spin event in the queue for this guy
gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" );
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" );
if ( EV_IsLocal( idx ) )
{
gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 );
}
}
2000-06-05 00:00:00 +00:00
void EV_FireGauss( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
float flDamage = args->fparam1;
int primaryfire = args->bparam1;
int m_fPrimaryFire = args->bparam1;
int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME;
vec3_t vecSrc;
vec3_t vecDest;
edict_t *pentIgnore;
pmtrace_t tr, beam_tr;
float flMaxFrac = 1.0;
int nTotal = 0;
int fHasPunched = 0;
int fFirstBeam = 1;
int nMaxHits = 10;
physent_t *pEntity;
int m_iBeam, m_iGlow, m_iBalls;
vec3_t up, right, forward;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
2000-11-07 00:00:00 +00:00
if ( args->bparam2 )
{
EV_StopPreviousGauss( idx );
return;
}
2000-06-05 00:00:00 +00:00
// Make sure we don't have a gauss spin event in the queue for this guy
gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" );
// Con_Printf( "Firing gauss with %f\n", flDamage );
EV_GetGunPosition( args, vecSrc, origin );
m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" );
m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" );
AngleVectors( angles, forward, right, up );
VectorMA( vecSrc, 8192, forward, vecDest );
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -2.0 );
gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
while (flDamage > 10 && nMaxHits > 0)
{
nMaxHits--;
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();
if ( tr.allsolid )
break;
pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent );
if ( pEntity == NULL )
break;
if (fFirstBeam)
{
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
}
fFirstBeam = 0;
gEngfuncs.pEfxAPI->R_BeamEntPoint(
idx | 0x1000,
tr.endpos,
m_iBeam,
0.1,
m_fPrimaryFire ? 1.0 : 2.5,
0.0,
m_fPrimaryFire ? 128.0 : flDamage,
0,
0,
0,
m_fPrimaryFire ? 255 : 255,
m_fPrimaryFire ? 128 : 255,
m_fPrimaryFire ? 0 : 255
);
}
else
{
gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc,
tr.endpos,
m_iBeam,
0.1,
m_fPrimaryFire ? 1.0 : 2.5,
0.0,
m_fPrimaryFire ? 128.0 : flDamage,
0,
0,
0,
m_fPrimaryFire ? 255 : 255,
m_fPrimaryFire ? 128 : 255,
m_fPrimaryFire ? 0 : 255
);
}
if ( pEntity->solid == SOLID_BSP )
{
float n;
pentIgnore = NULL;
n = -DotProduct( tr.plane.normal, forward );
if (n < 0.5) // 60 degrees
{
// ALERT( at_console, "reflect %f\n", n );
// reflect
vec3_t r;
VectorMA( forward, 2.0 * n, tr.plane.normal, r );
flMaxFrac = flMaxFrac - tr.fraction;
VectorCopy( r, forward );
VectorMA( tr.endpos, 8.0, forward, vecSrc );
VectorMA( vecSrc, 8192.0, forward, vecDest );
gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT );
{
vec3_t fwd;
VectorAdd( tr.endpos, tr.plane.normal, fwd );
gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, (int)(n * flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100,
255, 200 );
}
// lose energy
if ( n == 0 )
{
n = 0.1;
}
flDamage = flDamage * (1 - n);
}
else
{
// tunnel
EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM );
gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT );
// limit it to one hole punch
if (fHasPunched)
{
break;
}
fHasPunched = 1;
// try punching through wall if secondary attack (primary is incapable of breaking through)
if ( !m_fPrimaryFire )
{
vec3_t start;
VectorMA( tr.endpos, 8.0, forward, start );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr );
if ( !beam_tr.allsolid )
{
vec3_t delta;
float n;
// trace backwards to find exit point
gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr );
VectorSubtract( beam_tr.endpos, tr.endpos, delta );
n = Length( delta );
if (n < flDamage)
{
if (n == 0)
n = 1;
flDamage -= n;
// absorption balls
{
vec3_t fwd;
VectorSubtract( tr.endpos, forward, fwd );
gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100,
255, 100 );
}
//////////////////////////////////// WHAT TO DO HERE
// CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 );
EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM );
gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT );
// balls
{
vec3_t fwd;
VectorSubtract( beam_tr.endpos, forward, fwd );
gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200,
255, 40 );
}
VectorAdd( beam_tr.endpos, forward, vecSrc );
}
}
else
{
flDamage = 0;
}
gEngfuncs.pEventAPI->EV_PopPMStates();
}
else
{
if ( m_fPrimaryFire )
{
// slug doesn't punch through ever with primary
// fire, so leave a little glowy bit and make some balls
gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT );
{
vec3_t fwd;
VectorAdd( tr.endpos, tr.plane.normal, fwd );
gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100,
255, 200 );
}
}
flDamage = 0;
}
}
}
else
{
VectorAdd( tr.endpos, forward, vecSrc );
}
}
}
void EV_TrainPitchAdjust( event_args_t *args )
{
int idx;
vec3_t origin;
unsigned short us_params;
int noise;
float m_flVolume;
int pitch;
int stop;
char sz[ 256 ];
idx = args->entindex;
VectorCopy( args->origin, origin );
us_params = (unsigned short)args->iparam1;
stop = args->bparam1;
m_flVolume = (float)(us_params & 0x003f)/40.0;
noise = (int)(((us_params) >> 12 ) & 0x0007);
pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) );
switch ( noise )
{
case 1: strcpy( sz, "plats/ttrain1.wav"); break;
case 2: strcpy( sz, "plats/ttrain2.wav"); break;
case 3: strcpy( sz, "plats/ttrain3.wav"); break;
case 4: strcpy( sz, "plats/ttrain4.wav"); break;
case 5: strcpy( sz, "plats/ttrain6.wav"); break;
case 6: strcpy( sz, "plats/ttrain7.wav"); break;
default:
// no sound
strcpy( sz, "" );
return;
}
if ( stop )
{
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz );
}
else
{
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch );
}
}
int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 )
{
return 0;
}