You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1615 lines
37 KiB
1615 lines
37 KiB
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
#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> |
|
|
|
// QUAKECLASSIC |
|
#define Q_SMALL_PUNCHANGLE_KICK -2 |
|
#define Q_BIG_PUNCHANGLE_KICK -4 |
|
|
|
extern "C" char PM_FindTextureType( char *name ); |
|
|
|
extern void EV_Quake_DecalTrace( pmtrace_t *pTrace, const char *decalName ); |
|
extern void V_PunchAxis( int axis, float punch ); |
|
extern vec3_t v_origin; |
|
|
|
extern "C" |
|
{ |
|
|
|
// HLDM |
|
void EV_FireShotGunSingle( struct event_args_s *args ); |
|
void EV_FireShotGunDouble( struct event_args_s *args ); |
|
void EV_FireAxe( struct event_args_s *args ); |
|
void EV_FireAxeSwing( struct event_args_s *args ); |
|
void EV_FireRocket( struct event_args_s *args ); |
|
void EV_FireLightning( struct event_args_s *args ); |
|
void EV_FireSpike( struct event_args_s *args ); |
|
void EV_FireSuperSpike( struct event_args_s *args ); |
|
void EV_FireGrenade( struct event_args_s *args ); |
|
void EV_Gibbed( event_args_t *args ); |
|
void EV_Teleport( event_args_t *args ); |
|
void EV_Trail( event_args_t *args ); |
|
void EV_Explosion( event_args_t *args ); |
|
|
|
void EV_PlayerPowerup( struct event_args_s *args ); |
|
|
|
void EV_DMC_DoorGoUp( struct event_args_s *args ); |
|
void EV_DMC_DoorGoDown( struct event_args_s *args ); |
|
void EV_DMC_DoorHitTop( struct event_args_s *args ); |
|
void EV_DMC_DoorHitBottom( struct event_args_s *args ); |
|
|
|
void EV_Hook( event_args_t *args ); |
|
void EV_Cable( struct event_args_s *args ); |
|
void EV_FollowCarrier( struct event_args_s *args ); |
|
void EV_FlagSpawn( struct event_args_s *args ); |
|
|
|
void EV_TrainPitchAdjust( struct event_args_s *args ); |
|
} |
|
|
|
#define VECTOR_CONE_1DEGREES Vector( 0.00873f, 0.00873f, 0.00873f ) |
|
#define VECTOR_CONE_2DEGREES Vector( 0.01745f, 0.01745f, 0.01745f ) |
|
#define VECTOR_CONE_3DEGREES Vector( 0.02618f, 0.02618f, 0.02618f ) |
|
#define VECTOR_CONE_4DEGREES Vector( 0.03490f, 0.03490f, 0.03490f ) |
|
#define VECTOR_CONE_5DEGREES Vector( 0.04362f, 0.04362f, 0.04362f ) |
|
#define VECTOR_CONE_6DEGREES Vector( 0.05234f, 0.05234f, 0.05234f ) |
|
#define VECTOR_CONE_7DEGREES Vector( 0.06105f, 0.06105f, 0.06105f ) |
|
#define VECTOR_CONE_8DEGREES Vector( 0.06976f, 0.06976f, 0.06976f ) |
|
#define VECTOR_CONE_9DEGREES Vector( 0.07846f, 0.07846f, 0.07846f ) |
|
#define VECTOR_CONE_10DEGREES Vector( 0.08716f, 0.08716f, 0.08716f ) |
|
#define VECTOR_CONE_15DEGREES Vector( 0.13053f, 0.13053f, 0.13053f ) |
|
#define VECTOR_CONE_20DEGREES Vector( 0.17365f, 0.17365f, 0.17365f ) |
|
|
|
// 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; |
|
const char *rgsz[4]; |
|
int cnt; |
|
float fattn = ATTN_NORM; |
|
int entity; |
|
const 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 = 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; |
|
} |
|
|
|
//CheckPVS see if playerIndex is in same PVS as localplayer |
|
bool CheckPVS( int playerIndex ) |
|
{ |
|
//returns true if the player is in the same PVS |
|
cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); |
|
cl_entity_t *player = gEngfuncs.GetEntityByIndex( playerIndex ); |
|
|
|
if( !player || !localPlayer ) |
|
return false; |
|
|
|
if( player == localPlayer ) |
|
return true; |
|
|
|
if( player->curstate.messagenum < localPlayer->curstate.messagenum ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
const char *EV_HLDM_RocketDamageDecal() |
|
{ |
|
const char *pszDecalName; |
|
int idx; |
|
|
|
idx = gEngfuncs.pfnRandomLong( 0, 2 ); |
|
switch( idx + 1 ) |
|
{ |
|
case 1: |
|
pszDecalName = "{scorch1"; |
|
break; |
|
case 2: |
|
pszDecalName = "{scorch2"; |
|
break; |
|
case 3: |
|
pszDecalName = "{scorch3"; |
|
break; |
|
} |
|
|
|
return pszDecalName; |
|
} |
|
|
|
const char *EV_HLDM_DamageDecal() |
|
{ |
|
const char *pszDecalName; |
|
int idx = gEngfuncs.pfnRandomLong( 0, 4 ); |
|
|
|
switch( idx + 1 ) |
|
{ |
|
case 1: |
|
pszDecalName = "{shot1"; |
|
break; |
|
case 2: |
|
pszDecalName = "{shot2"; |
|
break; |
|
case 3: |
|
pszDecalName = "{shot3"; |
|
break; |
|
case 4: |
|
pszDecalName = "{shot4"; |
|
break; |
|
case 5: |
|
pszDecalName = "{shot5"; |
|
break; |
|
} |
|
return pszDecalName; |
|
} |
|
|
|
|
|
const char *EV_Lightning_DamageDecal( void ) |
|
{ |
|
const char *pszDecalName; |
|
int idx; |
|
|
|
idx = gEngfuncs.pfnRandomLong( 0, 2 ); |
|
switch( idx + 1 ) |
|
{ |
|
case 1: |
|
pszDecalName = "{smscorch1"; |
|
break; |
|
case 2: |
|
pszDecalName = "{smscorch2"; |
|
break; |
|
case 3: |
|
pszDecalName = "{smscorch3"; |
|
break; |
|
} |
|
|
|
return pszDecalName; |
|
} |
|
|
|
const char *EV_Quake_DamageDecalClub() |
|
{ |
|
return EV_HLDM_DamageDecal(); |
|
} |
|
|
|
void EV_Quake_GunshotDecalTrace( pmtrace_t *pTrace, const char *decalName ) |
|
{ |
|
int iRand; |
|
|
|
gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); |
|
|
|
iRand = gEngfuncs.pfnRandomLong( 0, 0x7FFF ); |
|
if( iRand < ( 0x7fff / 2 ) )// not every bullet makes a sound. |
|
{ |
|
const char *pszSound; |
|
|
|
switch( iRand % 5 ) |
|
{ |
|
case 0: |
|
pszSound = "weapons/ric1.wav"; |
|
break; |
|
case 1: |
|
pszSound = "weapons/ric2.wav"; |
|
break; |
|
case 2: |
|
pszSound = "weapons/ric3.wav"; |
|
break; |
|
case 3: |
|
pszSound = "weapons/ric4.wav"; |
|
break; |
|
case 4: |
|
pszSound = "weapons/ric5.wav"; |
|
break; |
|
} |
|
gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, pszSound, 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
EV_Quake_DecalTrace( pTrace, decalName ); |
|
} |
|
|
|
void EV_Quake_DecalTrace( pmtrace_t *pTrace, const char *decalName ) |
|
{ |
|
physent_t *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 = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); |
|
|
|
// if( pe && pe->solid == SOLID_BSP ) |
|
{ |
|
switch( iBulletType ) |
|
{ |
|
case BULLET_PLAYER_CROWBAR: |
|
EV_Quake_DecalTrace( pTrace, EV_Quake_DamageDecalClub() ); |
|
break; |
|
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_Quake_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal() ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
void EV_Quake_PlayQuadSound ( int idx, float *origin, int iFlag ) |
|
{ |
|
const char *pszSound; |
|
|
|
switch( iFlag ) |
|
{ |
|
case 1: |
|
pszSound = "items/damage3.wav"; |
|
break; |
|
case 2: |
|
pszSound = "rune/rune2.wav"; |
|
break; |
|
case 3: |
|
pszSound = "rune/rune22.wav"; |
|
break; |
|
case 4: |
|
pszSound = "rune/rune3.wav"; |
|
break; |
|
default: |
|
return; |
|
} |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, pszSound, 1, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
/* |
|
================ |
|
FireBullets |
|
|
|
Go to the trouble of combining multiple pellets into a single damage call. |
|
================ |
|
*/ |
|
void EV_Quake_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float *vecSpread ) |
|
{ |
|
int i; |
|
pmtrace_t tr; |
|
int iShot; |
|
vec3_t vecRight, vecUp; |
|
|
|
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( -1.0, 1.0 ) + gEngfuncs.pfnRandomFloat( -1.0, 1.0 ); |
|
spread[1] = gEngfuncs.pfnRandomFloat( -1.0, 1.0 ) + gEngfuncs.pfnRandomFloat( -1.0, 1.0 ); |
|
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] + 2048.0f * 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 ); |
|
|
|
int iBulletType = BULLET_PLAYER_BUCKSHOT; |
|
|
|
// do damage, paint decals |
|
if( tr.fraction != 1.0f ) |
|
{ |
|
switch( iBulletType ) |
|
{ |
|
default: |
|
case BULLET_PLAYER_9MM: |
|
case BULLET_PLAYER_357: |
|
case BULLET_PLAYER_MP5: |
|
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); |
|
EV_HLDM_DecalGunshot( &tr, iBulletType ); |
|
break; |
|
case BULLET_PLAYER_BUCKSHOT: |
|
EV_HLDM_DecalGunshot( &tr, iBulletType ); |
|
break; |
|
} |
|
} |
|
|
|
gEngfuncs.pEventAPI->EV_PopPMStates(); |
|
} |
|
} |
|
|
|
void EV_FireShotGunDouble( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
vec3_t angles; |
|
vec3_t velocity; |
|
|
|
int i; |
|
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 ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/shotgn2.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
EV_GetGunPosition( args, vecSrc, origin ); |
|
VectorCopy( forward, vecAiming ); |
|
|
|
vecSpread[0] = 0.04; |
|
vecSpread[1] = 0.04; |
|
vecSpread[2] = 0.00; |
|
|
|
EV_Quake_FireBullets( idx, forward, right, up, 14, vecSrc, vecAiming, vecSpread ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_BIG_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
void EV_FireShotGunSingle( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
vec3_t angles; |
|
vec3_t velocity; |
|
|
|
int i; |
|
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 ); |
|
int empty = args->bparam1; |
|
|
|
AngleVectors( angles, forward, right, up ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/guncock.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
EV_GetGunPosition( args, vecSrc, origin ); |
|
VectorCopy( forward, vecAiming ); |
|
|
|
vecSpread[0] = 0.04; |
|
vecSpread[1] = 0.04; |
|
vecSpread[2] = 0.00; |
|
|
|
EV_Quake_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, vecSpread ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
enum soundtypes_e |
|
{ |
|
SOUND_MISS, |
|
SOUND_HIT_BODY, |
|
SOUND_HIT_WALL |
|
}; |
|
|
|
void EV_Quake_PlayAxeSound( int idx, float *origin, int iSoundType ) |
|
{ |
|
const char *pszSound; |
|
|
|
switch( iSoundType ) |
|
{ |
|
case SOUND_HIT_BODY: |
|
pszSound = "player/axhitbod.wav"; |
|
break; |
|
case SOUND_HIT_WALL: |
|
pszSound = "player/axhit2.wav"; |
|
break; |
|
default: |
|
return; |
|
} |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, pszSound, 1, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
void EV_FireAxe( event_args_t *args ) |
|
{ |
|
int ent; |
|
|
|
int fDidHit = 0; |
|
int m_bHullHit = 1; |
|
|
|
vec3_t vecSrc, vecEnd; |
|
vec3_t up, right, forward; |
|
pmtrace_t tr; |
|
|
|
int idx; |
|
vec3_t origin; |
|
vec3_t angles; |
|
vec3_t velocity; |
|
|
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
VectorCopy( args->angles, angles ); |
|
VectorCopy( args->velocity, velocity ); |
|
|
|
AngleVectors( angles, forward, right, up ); |
|
|
|
EV_GetGunPosition( args, vecSrc, origin ); |
|
|
|
VectorMA( vecSrc, 64, forward, vecEnd ); |
|
|
|
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_NORMAL, -1, &tr ); |
|
|
|
if( tr.fraction < 1.0f ) |
|
{ |
|
ent = gEngfuncs.pEventAPI->EV_IndexFromTrace( &tr ); |
|
|
|
if( !EV_IsPlayer( ent ) ) |
|
{ |
|
EV_Quake_PlayAxeSound( idx, origin, SOUND_HIT_WALL ); |
|
EV_HLDM_DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); |
|
} |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
} |
|
|
|
gEngfuncs.pEventAPI->EV_PopPMStates(); |
|
} |
|
|
|
void EV_FireAxeSwing( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/ax1.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
} |
|
|
|
void EV_Hook( event_args_t *args ) |
|
{ |
|
return; |
|
} |
|
|
|
void EV_Cable( event_args_t *args ) |
|
{ |
|
int idx, attached, team, modelIndex; |
|
|
|
float r, g, b; |
|
|
|
idx = args->entindex; |
|
attached = args->iparam1; |
|
team = args->iparam2; |
|
|
|
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); |
|
|
|
if( !modelIndex ) |
|
return; |
|
|
|
if( team == 1 ) |
|
{ |
|
r = 500; |
|
g = 0; |
|
b = 0; |
|
} |
|
else if( team == 2 ) |
|
{ |
|
r = 0; |
|
g = 0; |
|
b = 500; |
|
} |
|
|
|
if( args->bparam1 == 1 ) |
|
gEngfuncs.pEfxAPI->R_BeamKill( attached ); |
|
else |
|
gEngfuncs.pEfxAPI->R_BeamEnts( idx, attached, modelIndex, 9999, 1, 0.001, 0.8, 0.0, 0.0, 0.0, r, g, b ); |
|
} |
|
|
|
void EV_GenericParticleCallback( struct particle_s *particle, float frametime ) |
|
{ |
|
int i; |
|
|
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
particle->org[i] += particle->vel[i] * frametime; |
|
} |
|
} |
|
|
|
void EV_TrailCallback( struct tempent_s *ent, float frametime, float currenttime ) |
|
{ |
|
// If the Player is not on our PVS, then go back |
|
if( !CheckPVS( ent->clientIndex ) ) |
|
return; |
|
|
|
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); |
|
|
|
cl_entity_t *player = gEngfuncs.GetEntityByIndex( ent->clientIndex ); |
|
|
|
if( !player ) |
|
return; |
|
|
|
VectorCopy( player->origin, dl->origin ); |
|
|
|
dl->radius = 240; |
|
dl->die = gEngfuncs.GetClientTime() + 0.001f; // Kill it right away |
|
|
|
if( ent->entity.baseline.movetype == 2 ) |
|
{ |
|
dl->color.r = 240; |
|
dl->color.g = 25; |
|
dl->color.b = 25; |
|
} |
|
else |
|
{ |
|
dl->color.r = 25; |
|
dl->color.g = 25; |
|
dl->color.b = 240; |
|
} |
|
|
|
// I know what you are thinking and yes, this was the only place I could find on where to put the timer |
|
// Hacky; Yes, Works; Yes!. |
|
if( ent->entity.baseline.animtime > gEngfuncs.GetClientTime() ) |
|
return; |
|
|
|
for( int i = 0; i < 4; i++ ) |
|
{ |
|
particle_t *bPart = gEngfuncs.pEfxAPI->R_AllocParticle( EV_GenericParticleCallback ); |
|
|
|
if( bPart ) |
|
{ |
|
VectorCopy( ent->entity.origin, bPart->org ); |
|
bPart->org[0] += gEngfuncs.pfnRandomFloat( -2, 2 ); |
|
bPart->org[1] += gEngfuncs.pfnRandomFloat( -2, 2 ); |
|
bPart->org[2] += gEngfuncs.pfnRandomFloat( -2, 2 ); |
|
bPart->vel[0] = gEngfuncs.pfnRandomFloat( -50, 50 ); |
|
bPart->vel[1] = gEngfuncs.pfnRandomFloat( -50, 50 ); |
|
bPart->vel[2] = gEngfuncs.pfnRandomFloat( 75, 80 ); |
|
|
|
//Check team and color the particle correctly |
|
if( ent->entity.baseline.movetype == 2 ) |
|
bPart->color = 70; |
|
else |
|
bPart->color = 43; |
|
|
|
bPart->type = pt_slowgrav; |
|
bPart->die = gEngfuncs.GetClientTime() + 0.5f; |
|
} |
|
} |
|
|
|
ent->entity.baseline.animtime = gEngfuncs.GetClientTime() + 0.3f; |
|
} |
|
|
|
|
|
void EV_FollowCarrier( event_args_t *args ) |
|
{ |
|
int iEntIndex = args->iparam1; |
|
int iTeam = args->iparam2; |
|
float r, g, b; |
|
|
|
int modelIndex; |
|
const char *model = "sprites/smoke.spr"; |
|
|
|
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( model ); |
|
|
|
if( iTeam == 2 ) |
|
{ |
|
r = 500; |
|
g = 0; |
|
b = 0; |
|
} |
|
else if( iTeam == 1 ) |
|
{ |
|
r = 0; |
|
g = 0; |
|
b = 500; |
|
} |
|
|
|
if( args->bparam1 == 1 ) |
|
gEngfuncs.pEfxAPI->R_KillAttachedTents( iEntIndex ); |
|
else |
|
{ |
|
TEMPENTITY *pTrailSpawner = NULL; |
|
pTrailSpawner = gEngfuncs.pEfxAPI->R_TempModel( args->origin, args->velocity, args->angles, 9999, modelIndex, TE_BOUNCE_NULL ); |
|
|
|
if( pTrailSpawner != NULL ) |
|
{ |
|
pTrailSpawner->flags |= ( FTENT_PLYRATTACHMENT | FTENT_PERSIST | FTENT_NOMODEL | FTENT_CLIENTCUSTOM ); |
|
pTrailSpawner->clientIndex = iEntIndex; |
|
|
|
pTrailSpawner->entity.baseline.movetype = iTeam; // Hack to store the team number on this temp ent. |
|
pTrailSpawner->entity.baseline.animtime = gEngfuncs.GetClientTime() + 0.3f; |
|
pTrailSpawner->callback = EV_TrailCallback; |
|
} |
|
} |
|
} |
|
|
|
void EV_FlagSpawn( event_args_t *args ) |
|
{ |
|
vec3_t origin; |
|
VectorCopy( args->origin, origin ); |
|
|
|
gEngfuncs.pEfxAPI->R_Implosion( origin, 50, 20, 0.5 ); |
|
|
|
for( int i = 0; i < 20; i++ ) |
|
{ |
|
particle_t *bPart = gEngfuncs.pEfxAPI->R_AllocParticle( EV_GenericParticleCallback ); |
|
|
|
if( bPart ) |
|
{ |
|
VectorCopy ( args->origin, bPart->org); |
|
bPart->org[0] += gEngfuncs.pfnRandomFloat( -4, 4 ); |
|
bPart->org[1] += gEngfuncs.pfnRandomFloat( -4, 4 ); |
|
bPart->org[2] += gEngfuncs.pfnRandomFloat( -4, 4 ); |
|
bPart->vel[0] = gEngfuncs.pfnRandomFloat( -50, 50 ); |
|
bPart->vel[1] = gEngfuncs.pfnRandomFloat( -50, 50 ); |
|
bPart->vel[2] = gEngfuncs.pfnRandomFloat( 250, 350 ); |
|
|
|
//Check team and color the particle correctly |
|
if( args->iparam1 == 1 ) |
|
bPart->color = 70; |
|
else |
|
bPart->color = 43; |
|
|
|
bPart->type = pt_grav; |
|
bPart->die = gEngfuncs.GetClientTime() + 3; |
|
} |
|
} |
|
} |
|
|
|
void EV_PowerupCallback( struct tempent_s *ent, float frametime, float currenttime ) |
|
{ |
|
//If the Player is not on our PVS, then go back |
|
if( !CheckPVS( ent->clientIndex ) ) |
|
return; |
|
|
|
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); |
|
|
|
cl_entity_t *player = gEngfuncs.GetEntityByIndex( ent->clientIndex ); |
|
|
|
if( !player ) |
|
return; |
|
|
|
VectorCopy( player->origin, dl->origin ); |
|
|
|
dl->radius = 270; |
|
dl->dark = true; |
|
dl->die = gEngfuncs.GetClientTime() + 0.001f; //Kill it right away |
|
|
|
if( ent->entity.baseline.iuser2 == 1 ) |
|
{ |
|
if( ent->entity.baseline.iuser1 == 1 ) |
|
{ |
|
dl->color.r = 255; |
|
dl->color.g = 128; |
|
dl->color.b = 128; |
|
} |
|
else |
|
{ |
|
dl->color.r = 0; |
|
dl->color.g = 75; |
|
dl->color.b = 255; |
|
} |
|
} |
|
else if( ent->entity.baseline.iuser2 == 2 ) |
|
{ |
|
if( ent->entity.baseline.iuser1 == 1 ) |
|
{ |
|
dl->color.r = 255; |
|
dl->color.g = 128; |
|
dl->color.b = 0; |
|
} |
|
else if( ent->entity.baseline.iuser1 == 2 ) |
|
{ |
|
dl->color.r = 0; |
|
dl->color.g = 128; |
|
dl->color.b = 250; |
|
} |
|
else |
|
{ |
|
dl->color.r = 255; |
|
dl->color.g = 75; |
|
dl->color.b = 0; |
|
} |
|
} |
|
else if( ent->entity.baseline.iuser2 == 3 ) |
|
{ |
|
dl->color.r = 255; |
|
dl->color.g = 125; |
|
dl->color.b = 255; |
|
} |
|
} |
|
|
|
void EV_PlayerPowerup( event_args_t *args ) |
|
{ |
|
int iEntIndex = args->iparam1; |
|
int iTeam = args->iparam2; |
|
int iPowerUp = (int)args->fparam1; |
|
|
|
int modelIndex; |
|
const char *model = "sprites/smoke.spr"; |
|
|
|
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( model ); |
|
|
|
if( args->bparam1 == 1 ) |
|
gEngfuncs.pEfxAPI->R_KillAttachedTents( iEntIndex ); |
|
|
|
if( iPowerUp ) |
|
{ |
|
TEMPENTITY *pTrailSpawner = NULL; |
|
pTrailSpawner = gEngfuncs.pEfxAPI->R_TempModel( args->origin, args->velocity, args->angles, 9999, modelIndex, TE_BOUNCE_NULL ); |
|
|
|
if( pTrailSpawner != NULL ) |
|
{ |
|
pTrailSpawner->flags |= ( FTENT_PLYRATTACHMENT | FTENT_PERSIST | FTENT_NOMODEL | FTENT_CLIENTCUSTOM ); |
|
pTrailSpawner->clientIndex = iEntIndex; |
|
|
|
pTrailSpawner->entity.baseline.iuser1 = iTeam; |
|
pTrailSpawner->entity.baseline.iuser2 = iPowerUp; |
|
|
|
pTrailSpawner->callback = EV_PowerupCallback; |
|
} |
|
} |
|
} |
|
|
|
float g_flLightTime; |
|
BEAM *pBeam; |
|
|
|
void EV_FireLightning( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin, endorigin; |
|
vec3_t angles; |
|
vec3_t up, right, forward; |
|
int iShutDown; |
|
|
|
cl_entity_t *player; |
|
|
|
int modelIndex; |
|
|
|
bool bSound = false; |
|
|
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
VectorCopy( args->angles, angles ); |
|
bSound = args->bparam1 ? true : false; |
|
iShutDown = args->iparam2; |
|
|
|
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/laserbeam.spr" ); |
|
|
|
// Load it up with some bogus data |
|
player = gEngfuncs.GetLocalPlayer(); |
|
|
|
AngleVectors( angles, forward, right, up ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
if ( g_flLightTime <= gEngfuncs.GetClientTime() ) |
|
{ |
|
gEngfuncs.pfnWeaponAnim( 1, 0 ); |
|
g_flLightTime = gEngfuncs.GetClientTime() + 0.5f; |
|
} |
|
|
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
|
|
player = gEngfuncs.GetViewModel(); |
|
origin = player->attachment[0]; |
|
} |
|
else |
|
{ |
|
origin = origin + Vector( 0, 0, 16 ); |
|
} |
|
|
|
if( bSound ) |
|
{ |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/lhit.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
} |
|
|
|
if( iShutDown == 0 && EV_IsLocal( idx ) && pBeam == NULL ) |
|
{ |
|
vec3_t vecSrc, vecEnd; |
|
pmtrace_t tr; |
|
|
|
cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); |
|
|
|
if( pl ) |
|
{ |
|
VectorCopy( gHUD.m_vecAngles, angles ); |
|
|
|
AngleVectors( angles, forward, right, up ); |
|
|
|
EV_GetGunPosition( args, vecSrc, pl->origin ); |
|
|
|
VectorMA( vecSrc, 2048, forward, vecEnd ); |
|
|
|
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 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PopPMStates(); |
|
|
|
pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, modelIndex, 99999, 5.0, 0.15, 2.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0 ); |
|
} |
|
} |
|
else if( iShutDown == 1 ) |
|
{ |
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
if( pBeam ) |
|
{ |
|
pBeam->die = 0.0; |
|
pBeam = NULL; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
void EV_FireRocket( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sgun1.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
void EV_FireGrenade( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
|
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/grenade.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
void EV_Quake_NailTouch( struct tempent_s *ent, pmtrace_t *ptr ) |
|
{ |
|
//physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( ptr->ent ); |
|
|
|
//if( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) |
|
{ |
|
EV_Quake_GunshotDecalTrace( ptr, EV_HLDM_DamageDecal() ); |
|
} |
|
} |
|
|
|
void EV_Quake_ClientProjectile( float *vecOrigin, float *vecVelocity, short sModelIndex, int iOwnerIndex, int iLife, void (*hitcallback)( struct tempent_s *ent, pmtrace_t *ptr ) ) |
|
{ |
|
gEngfuncs.pEfxAPI->R_Projectile( vecOrigin, vecVelocity, sModelIndex, iLife, iOwnerIndex, hitcallback ); |
|
} |
|
|
|
void EV_FireSpike( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
vec3_t angles; |
|
vec3_t up, right, forward; |
|
vec3_t vecVelocity; |
|
float offset = args->bparam1 ? 2.0f : -2.0f; |
|
|
|
int shell; |
|
|
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
VectorCopy( args->angles, angles ); |
|
|
|
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/spike.mdl" ); |
|
AngleVectors( angles, forward, right, up ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocket1i.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
// make nails |
|
VectorScale( forward, 1000, vecVelocity ); |
|
EV_Quake_ClientProjectile( origin + Vector( 0, 0, 10 ) + ( right * offset ), vecVelocity, (short)shell, idx, 6, EV_Quake_NailTouch ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
void EV_FireSuperSpike( event_args_t *args ) |
|
{ |
|
int idx; |
|
vec3_t origin; |
|
vec3_t angles; |
|
vec3_t up, right, forward; |
|
vec3_t vecVelocity; |
|
|
|
int shell; |
|
|
|
idx = args->entindex; |
|
VectorCopy( args->origin, origin ); |
|
VectorCopy( args->angles, angles ); |
|
|
|
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/spike.mdl" ); |
|
AngleVectors( angles, forward, right, up ); |
|
|
|
EV_Quake_PlayQuadSound( idx, origin, args->iparam1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/spike2.wav", 1.0, ATTN_NORM, 0, 100 ); |
|
|
|
// make nails |
|
VectorScale( forward, 1000, vecVelocity ); |
|
EV_Quake_ClientProjectile( origin + Vector( 0, 0, 16 ), vecVelocity, (short)shell, idx, 6, EV_Quake_NailTouch ); |
|
|
|
if( EV_IsLocal( idx ) ) |
|
{ |
|
V_PunchAxis( 0, Q_SMALL_PUNCHANGLE_KICK ); |
|
} |
|
} |
|
|
|
#define SND_CHANGE_PITCH ( 1 << 7 ) |
|
|
|
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; |
|
|
|
const char *pszSound; |
|
|
|
idx = args->entindex; |
|
|
|
VectorCopy( args->origin, origin ); |
|
|
|
us_params = (unsigned short)args->iparam1; |
|
stop = args->bparam1; |
|
|
|
m_flVolume = (float)(us_params & 0x003f)/40.0f; |
|
noise = (int)(((us_params) >> 12 ) & 0x0007); |
|
pitch = (int)( 10.0f * (float)( ( us_params >> 6 ) & 0x003f ) ); |
|
|
|
switch( noise ) |
|
{ |
|
case 1: |
|
pszSound = "plats/ttrain1.wav"; |
|
break; |
|
case 2: |
|
pszSound = "plats/ttrain2.wav"; |
|
break; |
|
case 3: |
|
pszSound = "plats/ttrain3.wav"; |
|
break; |
|
case 4: |
|
pszSound = "plats/ttrain4.wav"; |
|
break; |
|
case 5: |
|
pszSound = "plats/ttrain6.wav"; |
|
break; |
|
case 6: |
|
pszSound = "plats/ttrain7.wav"; |
|
break; |
|
default: |
|
// no sound |
|
return; |
|
} |
|
|
|
if( stop ) |
|
{ |
|
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, pszSound ); |
|
} |
|
else |
|
{ |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, pszSound, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); |
|
} |
|
} |
|
|
|
const char *DMC_BloodDecal() |
|
{ |
|
const char *pszDecalName; |
|
int idx = gEngfuncs.pfnRandomLong( 0, 5 ); |
|
|
|
switch( idx + 1 ) |
|
{ |
|
case 1: |
|
pszDecalName = "{blood1"; |
|
break; |
|
case 2: |
|
pszDecalName = "{blood2"; |
|
break; |
|
case 3: |
|
pszDecalName = "{blood3"; |
|
break; |
|
case 4: |
|
pszDecalName = "{blood4"; |
|
break; |
|
case 5: |
|
pszDecalName = "{blood5"; |
|
break; |
|
case 6: |
|
pszDecalName = "{blood6"; |
|
break; |
|
} |
|
return pszDecalName; |
|
} |
|
|
|
void DMC_DecalTrace( pmtrace_t *pTrace, const char *decalName ) |
|
{ |
|
EV_Quake_DecalTrace( pTrace, decalName ); |
|
} |
|
|
|
void EV_GibTouch( struct tempent_s *ent, struct pmtrace_s *ptr ) |
|
{ |
|
const char *pszSound; |
|
|
|
DMC_DecalTrace( ptr, DMC_BloodDecal() ); |
|
|
|
// 1 in 5 chance of squishy sound |
|
if( gEngfuncs.pfnRandomLong( 0, 4 ) > 0 ) |
|
return; |
|
|
|
switch( gEngfuncs.pfnRandomLong( 0, 5 ) ) |
|
{ |
|
case 0: |
|
pszSound = "debris/flesh1.wav"; |
|
break; |
|
case 1: |
|
pszSound = "debris/flesh2.wav"; |
|
break; |
|
case 2: |
|
pszSound = "debris/flesh3.wav"; |
|
break; |
|
case 3: |
|
pszSound = "debris/flesh5.wav"; |
|
break; |
|
case 4: |
|
pszSound = "debris/flesh6.wav"; |
|
break; |
|
case 5: |
|
pszSound = "debris/flesh7.wav"; |
|
break; |
|
} |
|
gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, pszSound, 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
void EV_GibParticleCallback( struct particle_s *particle, float frametime ) |
|
{ |
|
for( int i = 0; i < 3; i++ ) |
|
{ |
|
particle->org[i] += particle->vel[i] * frametime; |
|
} |
|
} |
|
|
|
void EV_Gibbed( event_args_t *args ) |
|
{ |
|
vec3_t origin, velocity, angles, rotate; |
|
int modelindex, i; |
|
TEMPENTITY *pGib = NULL; |
|
int gibs = 5; |
|
|
|
VectorCopy( args->origin, origin ); |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( 0, origin, CHAN_STATIC, "player/gib.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
|
|
rotate[0] = gEngfuncs.pfnRandomLong( -100, 100 ); |
|
rotate[1] = gEngfuncs.pfnRandomLong( -100, 100 ); |
|
rotate[2] = gEngfuncs.pfnRandomLong( -100, 100 ); |
|
|
|
for( i = 0; i < gibs; i++ ) |
|
{ |
|
const char *pszModel; |
|
|
|
switch( gEngfuncs.pfnRandomLong( 1, 3 ) ) |
|
{ |
|
//Just in case |
|
default: |
|
case 1: |
|
pszModel = "models/gib_1.mdl"; |
|
break; |
|
case 2: |
|
pszModel = "models/gib_2.mdl"; |
|
break; |
|
case 3: |
|
pszModel = "models/gib_3.mdl"; |
|
break; |
|
} |
|
|
|
modelindex = gEngfuncs.pEventAPI->EV_FindModelIndex( pszModel ); |
|
|
|
if( !modelindex ) |
|
return; |
|
|
|
VectorCopy( args->angles, angles ); |
|
|
|
VectorScale( angles, -1.0, angles ); |
|
|
|
angles[0] += gEngfuncs.pfnRandomFloat( -0.30, 0.30 ); |
|
angles[1] += gEngfuncs.pfnRandomFloat( -0.30, 0.30 ); |
|
angles[2] += gEngfuncs.pfnRandomFloat( -0.30, 0.30 ); |
|
|
|
VectorScale( angles, gEngfuncs.pfnRandomFloat( 500, 1200 ), velocity ); |
|
velocity[2] += 600; |
|
|
|
pGib = gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, rotate, 15, modelindex, TE_BOUNCE_NULL ); |
|
|
|
if( pGib ) |
|
{ |
|
pGib->flags |= ( FTENT_COLLIDEWORLD | FTENT_ROTATE | FTENT_FADEOUT | FTENT_CLIENTCUSTOM | FTENT_SMOKETRAIL ); |
|
pGib->hitcallback = EV_GibTouch; |
|
} |
|
} |
|
} |
|
|
|
//Spawns the teleport effect. |
|
void EV_Teleport( event_args_t *args ) |
|
{ |
|
const char *pszSound; |
|
vec3_t vecOrg; |
|
|
|
VectorCopy( args->origin, vecOrg ); |
|
|
|
switch( gEngfuncs.pfnRandomLong( 0, 4 ) ) |
|
{ |
|
case 0: |
|
pszSound = "misc/r_tele1.wav"; |
|
break; |
|
case 1: |
|
pszSound = "misc/r_tele2.wav"; |
|
break; |
|
case 2: |
|
pszSound = "misc/r_tele3.wav"; |
|
break; |
|
case 3: |
|
pszSound = "misc/r_tele4.wav"; |
|
break; |
|
case 4: |
|
pszSound = "misc/r_tele5.wav"; |
|
break; |
|
} |
|
|
|
gEngfuncs.pEventAPI->EV_PlaySound( 0, vecOrg, CHAN_STATIC, pszSound, 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
gEngfuncs.pEfxAPI->R_TeleportSplash( vecOrg ); |
|
} |
|
|
|
int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; |
|
|
|
void EV_RocketTrailCallback( struct tempent_s *ent, float frametime, float currenttime ) |
|
{ |
|
if( currenttime < ent->entity.baseline.fuser1 ) |
|
return; |
|
|
|
if( ent->entity.origin == ent->entity.attachment[0] ) |
|
ent->die = gEngfuncs.GetClientTime(); |
|
else |
|
VectorCopy( ent->entity.origin, ent->entity.attachment[0] ); |
|
|
|
//Make the Rocket light up. ( And only rockets, no Grenades ). |
|
if( ent->entity.baseline.sequence == 70 ) |
|
{ |
|
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); |
|
VectorCopy( ent->entity.origin, dl->origin ); |
|
|
|
dl->radius = 160; |
|
dl->dark = true; |
|
dl->die = gEngfuncs.GetClientTime() + 0.001f; //Kill it right away |
|
|
|
dl->color.r = 255; |
|
dl->color.g = 255; |
|
dl->color.b = 255; |
|
} |
|
} |
|
|
|
#define GRENADE_TRAIL 1 |
|
#define ROCKET_TRAIL 2 |
|
|
|
void EV_Trail( event_args_t *args ) |
|
{ |
|
int iEntIndex = args->iparam1; |
|
TEMPENTITY *pTrailSpawner = NULL; |
|
|
|
pTrailSpawner = gEngfuncs.pEfxAPI->CL_TempEntAllocNoModel( args->origin ); |
|
|
|
if( pTrailSpawner != NULL ) |
|
{ |
|
pTrailSpawner->flags |= ( FTENT_PLYRATTACHMENT | FTENT_COLLIDEKILL | FTENT_CLIENTCUSTOM | FTENT_SMOKETRAIL | FTENT_COLLIDEWORLD ); |
|
pTrailSpawner->callback = EV_RocketTrailCallback; |
|
pTrailSpawner->clientIndex = iEntIndex; |
|
|
|
if( args->iparam2 == GRENADE_TRAIL ) |
|
pTrailSpawner->entity.baseline.sequence = 69; |
|
else if ( args->iparam2 == ROCKET_TRAIL ) |
|
pTrailSpawner->entity.baseline.sequence = 70; |
|
|
|
pTrailSpawner->die = gEngfuncs.GetClientTime() + 10; // Just in case |
|
pTrailSpawner->entity.baseline.fuser1 = gEngfuncs.GetClientTime() + 0.5f; // Don't try to die till 500ms ahead |
|
} |
|
} |
|
|
|
void EV_Explosion( event_args_t *args ) |
|
{ |
|
vec3_t origin, scorch_origin, velocity, forward, right, up; |
|
int modelIndex; |
|
const char *model = "sprites/zerogxplode.spr"; |
|
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( model ); |
|
pmtrace_t tr; |
|
|
|
//Make decals and Explosions |
|
//Might not work for grenades. |
|
VectorCopy( args->origin, origin ); |
|
VectorCopy( args->angles, velocity ); //Velocity |
|
|
|
scorch_origin = origin - velocity.Normalize() * 32; |
|
|
|
gEngfuncs.pEfxAPI->R_Explosion( origin, modelIndex, 2.5, 15, TE_EXPLFLAG_NONE ); |
|
gEngfuncs.pEfxAPI->R_ParticleExplosion2( origin, 111, 8 ); |
|
|
|
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); |
|
|
|
gEngfuncs.pEventAPI->EV_PushPMStates(); |
|
gEngfuncs.pEventAPI->EV_SetSolidPlayers( -1 ); |
|
|
|
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); |
|
gEngfuncs.pEventAPI->EV_PlayerTrace( scorch_origin, scorch_origin + velocity.Normalize() * 64, PM_STUDIO_BOX | PM_WORLD_ONLY , -1, &tr ); |
|
|
|
gEngfuncs.pEventAPI->EV_PopPMStates(); |
|
|
|
DMC_DecalTrace( &tr, EV_HLDM_RocketDamageDecal() ); |
|
} |
|
|
|
#define EV_DMC_MOVE_SOUND 0 |
|
#define EV_DMC_STOP_SOUND 1 |
|
const char *EV_DMC_LookupDoorSound( int type, int index ) |
|
{ |
|
const char *pszSound; |
|
int idx; |
|
|
|
// Assume the worst |
|
pszSound = "common/null.wav"; |
|
|
|
if( type == EV_DMC_MOVE_SOUND ) |
|
{ |
|
idx = ( index >> 8 ) & 0xff; |
|
|
|
switch( idx ) |
|
{ |
|
default: |
|
case 0: |
|
pszSound = "common/null.wav"; |
|
break; |
|
case 1: |
|
pszSound = "doors/doormove1.wav"; |
|
break; |
|
case 2: |
|
pszSound = "doors/doormove2.wav"; |
|
break; |
|
case 3: |
|
pszSound = "doors/doormove3.wav"; |
|
break; |
|
case 4: |
|
pszSound = "doors/doormove4.wav"; |
|
break; |
|
case 5: |
|
pszSound = "doors/doormove5.wav"; |
|
break; |
|
case 6: |
|
pszSound = "doors/doormove6.wav"; |
|
break; |
|
case 7: |
|
pszSound = "doors/doormove7.wav"; |
|
break; |
|
case 8: |
|
pszSound = "doors/doormove8.wav"; |
|
break; |
|
case 9: |
|
pszSound = "doors/doormove9.wav"; |
|
break; |
|
case 10: |
|
pszSound = "doors/doormove10.wav"; |
|
break; |
|
} |
|
} |
|
else if( type == EV_DMC_STOP_SOUND ) |
|
{ |
|
idx = ( index & 0xff ); |
|
|
|
// set the door's 'reached destination' stop sound |
|
switch( idx ) |
|
{ |
|
default: |
|
case 0: |
|
pszSound = "common/null.wav"; |
|
break; |
|
case 1: |
|
pszSound = "doors/doorstop1.wav"; |
|
break; |
|
case 2: |
|
pszSound = "doors/doorstop2.wav"; |
|
break; |
|
case 3: |
|
pszSound = "doors/doorstop3.wav"; |
|
break; |
|
case 4: |
|
pszSound = "doors/doorstop4.wav"; |
|
break; |
|
case 5: |
|
pszSound = "doors/doorstop5.wav"; |
|
break; |
|
case 6: |
|
pszSound = "doors/doorstop6.wav"; |
|
break; |
|
case 7: |
|
pszSound = "doors/doorstop7.wav"; |
|
break; |
|
case 8: |
|
pszSound = "doors/doorstop8.wav"; |
|
break; |
|
} |
|
} |
|
return pszSound; |
|
} |
|
|
|
void EV_DMC_DoorGoUp( event_args_t *args ) |
|
{ |
|
int idx = -1; |
|
int soundindex = args->iparam1; |
|
|
|
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex )); |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, args->origin, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex ), 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
void EV_DMC_DoorGoDown( event_args_t *args ) |
|
{ |
|
EV_DMC_DoorGoUp( args ); |
|
/* |
|
int idx = -1; |
|
int soundindex = args->iparam1; |
|
|
|
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex )); |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, args->origin, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex ), 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
*/ |
|
} |
|
|
|
void EV_DMC_DoorHitTop( event_args_t *args ) |
|
{ |
|
int idx = -1; |
|
int soundindex = args->iparam1; |
|
|
|
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex ) ); |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, args->origin, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_STOP_SOUND, soundindex ), 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
} |
|
|
|
void EV_DMC_DoorHitBottom( event_args_t *args ) |
|
{ |
|
EV_DMC_DoorHitTop( args ); |
|
/* |
|
int idx = -1; |
|
int soundindex = args->iparam1; |
|
|
|
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_MOVE_SOUND, soundindex ) ); |
|
gEngfuncs.pEventAPI->EV_PlaySound( idx, args->origin, CHAN_STATIC, EV_DMC_LookupDoorSound( EV_DMC_STOP_SOUND, soundindex ), 1.0, ATTN_NORM, 0, PITCH_NORM ); |
|
*/ |
|
}
|
|
|