halflife-thewastes-sdk/cl_dll/ev_thewastes.cpp

2253 lines
63 KiB
C++
Raw Normal View History

/***
*
* 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.
*
****/
#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_thewastes.h"
#include "r_efx.h"
#include "event_api.h"
#include "event_args.h"
#include "in_defs.h"
#include "tw_common.h"
#include <string.h>
static int tracerCount[ 32 ];
#define DISABLE_PENETRATION 0 // Disables client side wall penetration
#ifndef M_PI
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
extern "C" char PM_FindTextureType( char *name );
void V_PunchAxis( int axis, float punch );
void VectorAngles( const float *forward, float *angles );
extern cvar_t *cl_lw;
// Used for gun recoil
extern cl_enginefunc_t gEngfuncs;
// Thermal vision on the client
extern int ev_thermal;
extern "C"
{
// Events
void EV_BerettaShoot (struct event_args_s *args);
void EV_ColtShoot (struct event_args_s *args);
void EV_DeagleShoot (struct event_args_s *args);
void EV_RugerShoot (struct event_args_s *args);
void EV_HandcannonShoot(struct event_args_s *args);
void EV_SawedOffShoot (struct event_args_s *args);
void EV_MossbergShoot (struct event_args_s *args);
void EV_WinchesterShoot(struct event_args_s *args);
void EV_Smg9Shoot (struct event_args_s *args);
void EV_FnFalShoot (struct event_args_s *args);
void EV_TommyGunShoot (struct event_args_s *args);
void EV_JackHammerShoot(struct event_args_s *args);
void EV_G11Shoot (struct event_args_s *args);
void EV_BoltRifleShoot (struct event_args_s *args);
void EV_StenShoot (struct event_args_s *args);
void EV_MolotovCocktail(struct event_args_s *args);
void EV_FragGrenade (struct event_args_s *args);
void EV_Pipebomb (struct event_args_s *args);
void EV_CombatKnife (struct event_args_s *args);
void EV_BaseballBat (struct event_args_s *args);
void EV_SledgeHammer (struct event_args_s *args);
void EV_Katana (struct event_args_s *args);
void EV_Spear (struct event_args_s *args);
void EV_CattleProd (struct event_args_s *args);
void EV_AkimboBerettas (struct event_args_s *args);
void EV_AkimboColts (struct event_args_s *args);
void EV_AkimboDeagles (struct event_args_s *args);
void EV_AkimboSawedOffs(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
void VectorAngles2( const float *forward, float *angles )
{
float tmp, yaw, pitch;
if (forward[1] == 0 && forward[0] == 0)
{
yaw = 0;
if (forward[2] > 0)
pitch = 90;
else
pitch = 270;
}
else
{
yaw = (atan2(forward[1], forward[0]) * 180 / M_PI);
if (yaw < 0)
yaw += 360;
tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]);
pitch = (atan2(forward[2], tmp) * 180 / M_PI);
if (pitch < 0)
pitch += 360;
}
angles[0] = pitch;
angles[1] = yaw;
angles[2] = 0;
}
int EV_HLDM_SpawnSmoke(int iBulletType)
{
// we use cl_efx_frequency to decide
// if we want to spawn a tent
switch(iBulletType)
{
case BULLET_9MMP:
case BULLET_10MM:
case BULLET_50AE:
case BULLET_454CASULL:
case BULLET_SLUG:
case BULLET_556MM:
if(gEngfuncs.pfnRandomFloat(0,1) > CVAR_GET_FLOAT("cl_efx_frequency")*2)
return 0;
case BULLET_9MM:
case BULLET_45ACP:
case BULLET_762MM:
case BULLET_47MM:
if(gEngfuncs.pfnRandomFloat(0,1) > CVAR_GET_FLOAT("cl_efx_frequency"))
return 0;
case BULLET_20GAUGE:
case BULLET_12GAUGE:
case BULLET_10GAUGE:
if(gEngfuncs.pfnRandomFloat(0,1) > CVAR_GET_FLOAT("cl_efx_frequency")/2)
return 0;
}
return 1;
}
TEMPENTITY *EV_HLDM_GunshotSmoke(pmtrace_t *pTrace,float *vecSrc,int iBulletType,color24 Color)
{
int iSpriteIdx;
vec3_t vecDir;
float scale;
// Game told us not to make smoke
if(!EV_HLDM_SpawnSmoke(iBulletType))
return NULL;
iSpriteIdx = gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/smoke1.spr");
// TODO: Find a way to prevent bullets from going
// Into the wall if you hit the wall directly?
VectorSubtract(pTrace->endpos,vecSrc,vecDir);
VectorNormalize(vecDir); // Set actual sprite speed below
switch(iBulletType)
{
// small caliber
case BULLET_9MMP:
case BULLET_10MM:
case BULLET_9MM:
VectorScale(vecDir,2,vecDir);
scale = 0.25f;
break;
// medium caliber
case BULLET_50AE:
case BULLET_454CASULL:
case BULLET_45ACP:
VectorScale(vecDir,3,vecDir);
scale = 0.5f;
break;
// large caliber
case BULLET_SLUG:
case BULLET_556MM:
case BULLET_762MM:
case BULLET_47MM:
VectorScale(vecDir,4,vecDir);
scale = 1.0f;
break;
// buckshot
case BULLET_20GAUGE:
case BULLET_12GAUGE:
case BULLET_10GAUGE:
VectorScale(vecDir,1,vecDir);
scale = 1.25f;
break;
// insane values so we know we need
// to assign a bullet type to the list!
default:
VectorScale(vecDir,-5,vecDir);
scale = 20;
break;
}
// create the puff
TEMPENTITY *pTent = gEngfuncs.pEfxAPI->R_TempSprite(pTrace->endpos + pTrace->plane.normal*4,
vecDir,
scale,
iSpriteIdx,
kRenderTransAlpha,
0,
25,
5,
FTENT_SPRANIMATE);
// state settings
if(pTent != NULL)
{
pTent->entity.curstate.rendercolor = Color;
pTent->entity.curstate.framerate = 10;
pTent->entity.curstate.renderamt = 128;
return pTent;
}
return NULL;
}
void EV_HLDM_SetColor(color24 &color,byte r,byte g,byte b)
{
color.r = r;
color.g = g;
color.b = b;
}
void EV_HLDM_GunshotLight( float *origin, float radius, byte r, byte g, byte b, float lifetime )
{
// TODO: IMPLEMENT AT LATER STAGE
/* dlight_t *dl;
dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 );
if( dl == NULL )
return;
VectorCopy( origin, dl->origin );
dl->radius = radius;
dl->color.r = r;
dl->color.g = g;
dl->color.b = b;
dl->die = gHUD.m_flTime + lifetime;
lifetime -= 0.05f;
dl->decay = 1/(lifetime/dl->radius);*/
}
void EV_HLDM_GunshotEfx( pmtrace_t *pTrace, int iBulletType, float *vecSrc, float *vecEnd)
{
int iRand = gEngfuncs.pfnRandomLong(0,0x7FFF);
int bRicochet = (iRand < (0x7fff/2));
int bGenericDecal = 0;
physent_t *pe;
static char decalname[32];
// we create texture based smoke instead of just cute little sparks
color24 SmokeColor;
const char *szTextureName = gEngfuncs.pEventAPI->EV_TraceTexture(pTrace->ent,vecSrc,vecEnd); // get texture info
char cTextureType = 0;
int iRenderSmoke = 1; // Do we want to show a smokepuff ?
int bShowLight = 1;
static unsigned int lightcount;
EV_HLDM_SetColor(SmokeColor,255,255,255); // default color
if( szTextureName != NULL )
cTextureType = PM_FindTextureType((char*)szTextureName);
switch(cTextureType)
{
case CHAR_TEX_COMPUTER:
case CHAR_TEX_GLASS:
if(bRicochet)
{
switch(iRand % 3)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_glass1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_glass2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_glass3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
iRenderSmoke = 0; // No smoke puff
bShowLight = 0;
bGenericDecal = 1;
break;
case CHAR_TEX_WOOD:
if(bRicochet)
{
switch(iRand % 5)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_wood1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_wood2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_wood3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_wood4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_wood5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holewood");
EV_HLDM_SetColor(SmokeColor,187,141,43);
break;
case CHAR_TEX_CONCRETE:
if(bRicochet)
{
switch(iRand % 3)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_con1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_con2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_con3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holeconcrete");
break;
case CHAR_TEX_RUST:
if(bRicochet)
{
switch(iRand % 2)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_metalwall1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_metalwall2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holerust");
break;
case CHAR_TEX_VENT:
case CHAR_TEX_METAL:
if(bRicochet)
{
switch(iRand % 2)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_metalwall1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_metalwall2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holemetal");
break;
case CHAR_TEX_GRATE:
case CHAR_TEX_BARREL:
if(bRicochet)
{
switch(iRand % 4)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_barrel1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_barrel2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_barrel3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_barrel4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
sprintf(decalname, "{dent%i", gEngfuncs.pfnRandomLong( 0, 5 ) + 1 );
break;
case CHAR_TEX_TIN:
if(bRicochet)
{
switch(iRand % 3)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_tinroof1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_tinroof2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_tinroof3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
sprintf(decalname, "{dent%i", gEngfuncs.pfnRandomLong( 0, 5 ) + 1 );
break;
case CHAR_TEX_TILE:
if(bRicochet)
{
switch(iRand % 2)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_drywall1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_drywall2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holetile");
break;
case CHAR_TEX_DRYWALL:
if(bRicochet)
{
switch(iRand % 2)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_drywall1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric_drywall2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
strcpy(decalname, "{holedry");
EV_HLDM_SetColor(SmokeColor,255,255,200);
break;
case CHAR_TEX_SAND:
strcpy(decalname, "{holesand");
EV_HLDM_SetColor(SmokeColor,255,255,192);
break;
case CHAR_TEX_FLESH:
EV_HLDM_SetColor(SmokeColor,200,25,25);
bGenericDecal = 1;
break;
case CHAR_TEX_DIRT:
EV_HLDM_SetColor(SmokeColor,115,53,25);
bGenericDecal = 1;
break;
case CHAR_TEX_SNOW:
EV_HLDM_SetColor(SmokeColor,255,255,255);
bGenericDecal = 1;
break;
case CHAR_TEX_SLOSH:
iRenderSmoke = 0;
default:
if(bRicochet)
{
switch( iRand % 5)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "debris/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
bGenericDecal = 1;
break;
}
pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent );
// Override some object decals
if ( pe->classnumber == 1 )
sprintf( decalname, "{break%i", gEngfuncs.pfnRandomLong( 0, 2 ) + 1 );
else if ( pe->rendermode != kRenderNormal )
{
sprintf( decalname, "{bproof1" );
}
else if(iBulletType >= BULLET_20GAUGE && iBulletType <= BULLET_12GAUGE)
{
// Buckshot
sprintf(decalname,"{bigshot%i",gEngfuncs.pfnRandomLong( 0, 4 )+ 1 );
bShowLight = 0;
}
else if(bGenericDecal)
sprintf( decalname, "{shot%i", gEngfuncs.pfnRandomLong( 0, 7 ) + 1 );
if( bShowLight && CVAR_GET_FLOAT( "cl_efx_frequency" ) > 0 )
{
// Only do every 3 bullets
if( lightcount++ % 3 == 1 )
EV_HLDM_GunshotLight( pTrace->endpos, gEngfuncs.pfnRandomFloat( 30.0f, 40.0f ), 255, 255, 255, 0.75f );
}
if(iRenderSmoke)
EV_HLDM_GunshotSmoke(pTrace,vecSrc,iBulletType,SmokeColor);
// 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 );
}
}
}
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 )
// {
// default:
EV_CreateTracer( vecTracerSrc, end );
// break;
// }
}
return tracer;
}
void EV_HLDM_BulletDecal(int iBulletType,pmtrace_t *pTr,float *vecSrc,float *vecEnd)
{
// do damage, paint decals
physent_t *pe;
pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTr->ent );
if ( pe && pe->solid == SOLID_BSP )
{
// smoke and decal
EV_HLDM_GunshotEfx( pTr, iBulletType, vecSrc, vecEnd );
}
}
/*
================
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 flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY,int penetration_type )
{
int i;
pmtrace_t tr;
int tracer;
int iShot;
#if !(DISABLE_PENETRATION)
// penetration values
int wall_thickness = 0;
float falloff_rate = 0;
int wall_limit = MAX_WALLCOUNT;
switch(penetration_type)
{
case P_BERETTA:
wall_thickness = MAX_THICKNESS_BERETTA;
falloff_rate = FALLOFF_BERETTA;
break;
case P_COLT:
wall_thickness = MAX_THICKNESS_COLT;
falloff_rate = FALLOFF_COLT;
break;
case P_RUGER:
wall_thickness = MAX_THICKNESS_RUGER;
falloff_rate = FALLOFF_RUGER;
break;
case P_DEAGLE:
wall_thickness = MAX_THICKNESS_DEAGLE;
falloff_rate = FALLOFF_DEAGLE;
break;
case P_HANDCANNON:
wall_thickness = MAX_THICKNESS_HANDCANNON;
falloff_rate = FALLOFF_HANDCANNON;
break;
case P_WINCHESTER:
wall_thickness = MAX_THICKNESS_WINCHESTER;
falloff_rate = FALLOFF_WINCHESTER;
break;
case P_SMG9:
wall_thickness = MAX_THICKNESS_SMG9;
falloff_rate = FALLOFF_SMG9;
break;
case P_FNFAL:
wall_thickness = MAX_THICKNESS_FNFAL;
falloff_rate = FALLOFF_FNFAL;
break;
case P_TOMMYGUN:
wall_thickness = MAX_THICKNESS_TOMMYGUN;
falloff_rate = FALLOFF_TOMMYGUN;
break;
case P_G11:
wall_thickness = MAX_THICKNESS_G11;
falloff_rate = FALLOFF_G11;
break;
case P_BOLTRIFLE:
wall_thickness = MAX_THICKNESS_BOLTRIFLE;
falloff_rate = FALLOFF_BOLTRIFLE;
break;
case P_STEN:
wall_thickness = MAX_THICKNESS_STEN;
falloff_rate = FALLOFF_STEN;
break;
}
#endif
#if !(DISABLE_PENETRATION)
do
{
#endif
for ( iShot = 1; iShot <= cShots; iShot++ )
{
vec3_t vecDir, vecEnd;
float x, y, z;
//We randomize for the Shotguns
if(iBulletType >= BULLET_20GAUGE && iBulletType <= BULLET_12GAUGE)
{
do {
x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5);
y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5);
z = x*x+y*y;
} while (z > 1);
for ( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ];
vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ];
}
}//But other guns already have their spread randomized in the synched spread.
else
{
for ( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * 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 );
if( tr.fraction != 1.0 )
{
EV_HLDM_BulletDecal(iBulletType,&tr,vecSrc,(float*)&vecEnd);
#if !(DISABLE_PENETRATION)
// If we want an exit hole, show it.
if(wall_thickness)
{
// wall thickness
vec3_t wall_begin = tr.endpos;
vec3_t wall_end;
pmtrace_t new_tr;
gEngfuncs.pEventAPI->EV_PlayerTrace(tr.endpos+vecDir*wall_thickness,vecEnd,PM_STUDIO_BOX,-1,&new_tr);
// We cannot continue
if(new_tr.allsolid)
wall_thickness = 0;
else
{
// Get exit hole
gEngfuncs.pEventAPI->EV_PlayerTrace(new_tr.endpos,tr.endpos,PM_STUDIO_BOX,-1,&tr);
if(!tr.allsolid)
{
// get length of wall, and detract from overall bullet effectiveness
// only subtract for hard targets, not players.
if(tr.ent != NULL && !EV_IsPlayer(tr.ent))
{
VectorSubtract(tr.endpos,wall_begin,wall_end);
wall_thickness -= (int)(Length(wall_end) * falloff_rate);
}
if(wall_thickness <= 0)
wall_thickness = 0;
else
EV_HLDM_BulletDecal(iBulletType,&tr,vecSrc,(float*)&vecEnd);
// Trace ahead to get next wall.
vecSrc = tr.endpos;
}
else
wall_thickness = 0; // cant go any further.
}
}
#endif
}
gEngfuncs.pEventAPI->EV_PopPMStates();
}
#if !(DISABLE_PENETRATION)
}while(wall_thickness && wall_limit--);
#endif
}
// globals used by most Pistol events
// Some Ruger specific code is here too.
int EV_PistolShoot( event_args_t *args , char *fire_sound,int iBulletType, char *loshell, char *hishell)
{
int idx = args->entindex;
int empty = args->bparam1;
int aimmode = args->bparam2;
vec3_t up, right, forward;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
vec3_t vecSrc, vecAiming;
if ( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
if(iBulletType == BULLET_454CASULL)
{
if(!aimmode)
gEngfuncs.pEventAPI->EV_WeaponAnimation( RUGER_SHOOT, 2 );
else
gEngfuncs.pEventAPI->EV_WeaponAnimation( RUGER_AIM_SHOOT, 2 );
}
else
{
if(!aimmode)
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? SPISTOL_SHOOT_LAST : SPISTOL_SHOOT, 2 );
else
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? SPISTOL_AIM_SHOOT_LAST : SPISTOL_AIM_SHOOT , 2 );
}
V_PunchAxis( 0, -2.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON,fire_sound, gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
int penetration_type;
switch(iBulletType)
{
case BULLET_9MMP:
penetration_type = P_BERETTA;
break;
case BULLET_10MM:
penetration_type = P_COLT;
break;
case BULLET_454CASULL:
penetration_type = P_RUGER;
break;
case BULLET_50AE:
penetration_type = P_DEAGLE;
break;
default:
penetration_type = 0;
break;
}
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if( iBulletType != BULLET_454CASULL )
{
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( loshell );
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( hishell );
EV_GetDefaultShellInfo( 0, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
EV_EjectBrass( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
}
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, iBulletType, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2, penetration_type );
return 1;
}
void EV_PistolWhip(event_args_t *args)
{
int idx = args->entindex;
int clip_empty = args->iparam1;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
VectorCopy( args->origin, origin );
//Play Swing sound
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip3.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 2:
default:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip2.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
}
if ( EV_IsLocal( idx ) )
{
switch( gEngfuncs.pfnRandomLong(0,1) )
{
case 0:
gEngfuncs.pEventAPI->EV_WeaponAnimation ( clip_empty ? SPISTOL_WHIP1_EMPTY : SPISTOL_WHIP1, 1 ); break;
case 1:
gEngfuncs.pEventAPI->EV_WeaponAnimation ( clip_empty ? SPISTOL_WHIP2_EMPTY : SPISTOL_WHIP2, 1 ); break;
}
}
}
/*************
Beretta
*************/
void EV_BerettaShoot(event_args_t *args)
{
if(args->iparam2)
EV_PistolShoot(args,"weapons/beretta_fire.wav",BULLET_9MMP,"models/shells/shell_9x18mm_lo.mdl","models/shells/shell_9x18mm_hi.mdl");
else
EV_PistolWhip(args);
}
/*************
Enforcer
*************/
void EV_ColtShoot(event_args_t *args)
{
if(args->iparam2)
EV_PistolShoot(args,"weapons/colt_fire.wav",BULLET_10MM,"models/shells/shell_10mm_lo.mdl","models/shells/shell_10mm_hi.mdl");
else
EV_PistolWhip(args);
}
/*************
Desert Eagle
*************/
void EV_DeagleShoot(event_args_t *args)
{
if(args->iparam2)
{
EV_PistolShoot(args,"weapons/deagle_fire.wav",BULLET_50AE,"models/shells/shell_50AE_lo.mdl","models/shells/shell_50AE_hi.mdl");
// Pop up the view angle - (dont pop up if aiming)
if(EV_IsPlayer(args->entindex) && EV_IsLocal(args->entindex) && !args->bparam2)
RECOIL_VIEW(5.5,0);
}
else
EV_PistolWhip(args);
}
/*************
Ruger
*************/
void EV_RugerShoot(event_args_t *args)
{
if(EV_PistolShoot(args,"weapons/ruger_fire.wav",BULLET_454CASULL,"models/shells/shell_454_lo.mdl","models/shells/shell_454_hi.mdl"))
{
// Not as extreme as Desert Eagle, but still there :D
if(EV_IsPlayer(args->entindex) && EV_IsLocal(args->entindex) && !args->bparam2 && !args->iparam2)
RECOIL_VIEW(5,0);
}
}
/*************
5.56mm Handcannon
*************/
void EV_HandcannonShoot(event_args_t *args)
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int empty;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
empty = args->bparam1;
AngleVectors( angles, forward, right, up );
// Play sound only
if(args->iparam1)
{
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_AUTO,args->bparam2 ? "weapons/handcannon_laser_on.wav" : "weapons/handcannon_laser_off.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
return;
}
if ( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? HC_SHOOT_LAST : HC_SHOOT, 2 );
if(!args->bparam2)
{
RECOIL_VIEW(13.5,0);
}
else
// Huge kickback noticed if your using a laser
V_PunchAxis( 0, -10.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON,"weapons/handcannon_fire.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_556MM, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2,P_HANDCANNON );
}
/*************
Sawed Off
*************/
void EV_SawedOffShoot(event_args_t *args)
{
int idx = args->entindex;
int barrels = args->iparam1;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t up, right, forward;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
if( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( (barrels == 2) ? SAWED_SHOOT_L : SAWED_SHOOT_R, 2 );
if(barrels == 1)
V_PunchAxis( 0, -5.0 );
else
V_PunchAxis( 0, -11.5 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, (barrels == 1) ? "weapons/sawedoff_fire1.wav" : "weapons/sawedoff_fire2.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
int shotCount = (barrels == 1) ? 14 : 26;
// Remember to change the randomization code at the bottom :)
EV_HLDM_FireBullets( idx, forward, right, up, shotCount, vecSrc, vecAiming, 2048, BULLET_20GAUGE, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2,0 );
}
/*************
Mossberg
*************/
void EV_MossbergBlast(event_args_t *args)
{
int idx = args->entindex;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t up, right, forward;
VectorCopy ( args->origin, origin );
VectorCopy ( args->angles, angles );
VectorCopy ( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
// Shoot gun as normal
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
if(EV_IsLocal(idx))
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( args->bparam2 ? MOSSBERG_SHOOT : MOSSBERG_SHOOT2, 2 );
V_PunchAxis( 0, -4.5 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, args->bparam2 ? "weapons/mossberg_fire1.wav" : "weapons/mossberg_fire2.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
int shotCount = args->iparam1;
// Remember to change the randomization code at the bottom :)
EV_HLDM_FireBullets( idx, forward, right, up, shotCount, vecSrc, vecAiming, 2048, BULLET_12GAUGE, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2,0 );
}
void EV_MossbergWhip(event_args_t *args)
{
int idx = args->entindex;
int clip_empty = args->iparam1;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
VectorCopy( args->origin, origin );
//Play Swing sound
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip3.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 2:
default:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip2.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
}
if ( EV_IsLocal( idx ) )
gEngfuncs.pEventAPI->EV_WeaponAnimation ( MOSSBERG_WHIP, 1 );
}
void EV_MossbergShoot(event_args_t *args)
{
if(args->iparam2)
EV_MossbergBlast(args);
else
EV_MossbergWhip(args);
}
/*************
Winchester
*************/
void EV_WinchesterShoot(event_args_t *args)
{
int idx = args->entindex;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t up, right, forward;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
int animation = args->iparam1;
vec3_t vecSrc, vecAiming;
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( animation ? WINNY_SHOOT : WINNY_SHOOT2, 2 );
V_PunchAxis( 0, -2.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON,animation ? "weapons/winchester_fire1.wav" : "weapons/winchester_fire2.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_SLUG, ev_thermal ? 1 : 0, ev_thermal ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2, P_WINCHESTER);
}
/*************
Smg9
*************/
void EV_Smg9Shoot(struct event_args_s *args)
{
float dirx = args->fparam1;
float diry = args->fparam2;
float accuracy = args->angles[0];
float recoil;
int idx = args->entindex;
int empty = args->iparam2;
int secondary = args->iparam1;
int lowrecoil = args->bparam1;
int burstpredict = args->bparam2;
if(secondary)
{
if(lowrecoil)
recoil = gEngfuncs.pfnRandomFloat(1.4,2.4);
else
recoil = gEngfuncs.pfnRandomFloat(3.4,4.4);
}
else
{
if(lowrecoil)
recoil = gEngfuncs.pfnRandomFloat(0.4,1.4);
else
recoil = gEngfuncs.pfnRandomFloat(1.4,2.0);
}
// muck up bullet locations a bit in burst fire
if(burstpredict)
{
dirx *= gEngfuncs.pfnRandomFloat(-accuracy,accuracy);
diry *= gEngfuncs.pfnRandomFloat(accuracy/4,accuracy);
}
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
// Shell ejection
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_9x22mm_lo.mdl");
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_9x22mm_hi.mdl");
if(!secondary)
EV_GetDefaultShellInfo( 2, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
else
// Eject upwards as normal
EV_GetDefaultShellInfo( 0, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 0 );
EV_EjectBrass(ShellOrigin,ShellVelocity,angles[ YAW ],shell,TE_BOUNCE_SHELL);
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(secondary ? SMG9_SECONDARY_SHOOT : SMG9_SHOOT,2);
RECOIL_VIEW(recoil,0);
}
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomFloat(0,1) == 0) ? "weapons/smg9_fire1.wav" : "weapons/smg9_fire2.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_9MM,ev_thermal ? 1 : 0,ev_thermal ? &tracerCount[idx-1] : 0,dirx,diry,P_SMG9);
}
/*************
FN FAL
*************/
void EV_FnFalShoot(event_args_t *args)
{
int idx = args->entindex;
int aimfire = args->bparam2;
int lowrecoil = args->bparam1;
int semiauto = args->iparam2;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
// Shell ejection
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_762mm_lo.mdl");
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_762mm_hi.mdl");
if(!aimfire)
EV_GetDefaultShellInfo( 2, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
else
EV_GetDefaultShellInfo( 2, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 0 );
EV_EjectBrass(ShellOrigin,ShellVelocity,angles[ YAW ],shell,TE_BOUNCE_SHELL);
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(aimfire ? FNFAL_AIM_SHOOT : FNFAL_SHOOT,2);
if(aimfire)
{
if( semiauto )
V_PunchAxis(0,-3.4);
else
{
if( lowrecoil )
{
RECOIL_VIEW( gEngfuncs.pfnRandomFloat( 0.50, 1.50 ), 0 );
}
else
{
RECOIL_VIEW( gEngfuncs.pfnRandomFloat( 1.25, 2.25 ), 0 );
}
}
}
else
{
if(lowrecoil)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(1.25,2.25),0);
}
else
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(2.75,4.5),0);
}
}
}
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomLong(0,1) == 0) ? "weapons/fnfal_fire1.wav" : "weapons/fnfal_fire2.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_762MM,ev_thermal ? 1 : 2,&tracerCount[idx-1],args->fparam1,args->fparam2,P_FNFAL);
}
/*************
Tommy Gun
*************/
void EV_TommyGunShoot(event_args_t *args)
{
int idx = args->entindex;
int lessrecoil = args->bparam1;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
// Shell ejection
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_45cal_lo.mdl");
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_45cal_hi.mdl");
EV_GetDefaultShellInfo( 2, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
EV_EjectBrass(ShellOrigin,ShellVelocity,angles[ YAW ],shell,TE_BOUNCE_SHELL);
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(TOMMYGUN_SHOOT,2);
if(lessrecoil)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(1.25,2.0),0);
}
else
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(2.0,3.5),0);
}
}
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomLong(0,1) == 0) ? "weapons/tommygun_fire1.wav" : "weapons/tommygun_fire2.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_45ACP,ev_thermal ? 1 : 3,&tracerCount[idx-1],args->fparam1,args->fparam2,P_TOMMYGUN);
}
/*************
Jackhammer
*************/
void EV_JackHammerShoot(event_args_t *args)
{
int idx = args->entindex;
int ducking = args->iparam2;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t up, right, forward;
VectorCopy ( args->origin, origin );
VectorCopy ( args->angles, angles );
VectorCopy ( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
if(EV_IsLocal(idx))
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( JACKHAMMER_SHOOT, 2 );
if(ducking)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(3.0,4.0),0);
}
else
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(5.0,6.5),0);
}
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, gEngfuncs.pfnRandomLong(0,1) ? "weapons/jackhammer_fire1.wav" : "weapons/jackhammer_fire2.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
int shotCount = args->iparam1;
// Remember to change the randomization code at the bottom :)
EV_HLDM_FireBullets( idx, forward, right, up, shotCount, vecSrc, vecAiming, 2048, BULLET_10GAUGE, ev_thermal ? 1 : 0, ev_thermal ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2,0 );
}
/*************
H&K G11
*************/
void EV_G11Shoot(event_args_t *args)
{
int idx = args->entindex;
int burstfire = args->iparam1;
float bursthop = args->fparam2;
int burstcount = args->iparam2; // How many bullets to fire
int zoom_sound = args->bparam1; // just do a cute zoom sound ?
int lessrecoil = args->bparam2;
// We do this as an event so other people can hear it
if(zoom_sound)
{
gEngfuncs.pEventAPI->EV_PlaySound(idx,args->origin,CHAN_AUTO,args->bparam2 ? "weapons/g11_zoom2.wav" : "weapons/g11_zoom1.wav", gEngfuncs.pfnRandomFloat(0.7,0.8), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
return;
}
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(burstfire ? G11_BURST : G11_SHOOT,2);
if(burstfire)
{
if(lessrecoil)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(2.0,3.0),0);
}
else
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(3.0,4.5),0);
}
}
else
{
if(lessrecoil)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(0.5,1.0),0);
}
else
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(1.0,1.5),0);
}
}
}
if(burstfire)
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON, "weapons/g11_burst.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
else
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomLong(0,1) == 0) ? "weapons/g11_ffire1.wav" : "weapons/g11_ffire2.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
if(burstfire)
{
float spreadX = args->fparam1;
float spreadY = args->fparam2;
for(int i = 0;i < burstcount;i++)
{
spreadX += gEngfuncs.pfnRandomFloat(-0.015,0.015);
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_47MM,ev_thermal ? 1 : 3,&tracerCount[idx-1],spreadX,spreadY,P_G11);
spreadY += bursthop;
spreadX = args->fparam1;
}
}
else
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_47MM,ev_thermal ? 1 : 10,&tracerCount[idx-1],args->fparam1,args->fparam2,P_G11);
}
/*************
Bolt Rifle
*************/
void EV_BoltRifleShoot(event_args_t *args)
{
int idx = args->entindex;
int whip_only = args->bparam1;
int empty = args->iparam1;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
// BoltRifle whip
if(whip_only)
{
//Play Swing sound
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip3.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
case 2:
default:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_AUTO, "weapons/whip2.wav", 1, ATTN_NORM, 0, PITCH_NORM); break;
}
if ( EV_IsLocal( idx ) )
gEngfuncs.pEventAPI->EV_WeaponAnimation ( BOLTRIFLE_STRIKE, 1 );
return;
}
if(EV_IsLocal(idx))
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(empty ? BOLTRIFLE_SHOOT_LAST : BOLTRIFLE_SHOOT,2);
RECOIL_VIEW(5.0,gEngfuncs.pfnRandomFloat(-1.5,1.5));
}
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/boltrifle_fire1.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_762MM,ev_thermal ? 1 : 0,ev_thermal ? &tracerCount[idx-1] : 0,args->fparam1,args->fparam2,P_BOLTRIFLE);
}
/*************
Sten
*************/
void EV_StenShoot(event_args_t *args)
{
int idx = args->entindex;
int silenced = args->bparam1;
int overheat = args->bparam2;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc;
vec3_t up, right, forward;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,angles);
VectorCopy(args->velocity,velocity);
AngleVectors(angles,forward,right,up);
if(overheat)
{
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/sten_overheat.wav",1.0,ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
return;
}
// Shell ejection
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_9x22mm_lo.mdl");
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shells/shell_9x22mm_hi.mdl");
EV_GetDefaultShellInfo( 2, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
EV_EjectBrass(ShellOrigin,ShellVelocity,angles[ YAW ],shell,TE_BOUNCE_SHELL);
if(EV_IsLocal(idx))
{
if(!silenced)
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation(silenced ? STEN_SHOOT_SILENCED : STEN_SHOOT,2);
if(!silenced)
{
RECOIL_VIEW(gEngfuncs.pfnRandomFloat(1.4,2.4),0);
}
else
{
V_PunchAxis( 0, -1.0 );
}
}
if(silenced)
{
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomFloat(0,1) == 0) ? "weapons/sten_sfire1.wav" : "weapons/sten_sfire2.wav",gEngfuncs.pfnRandomFloat(0.6, 0.75),ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
}
else
{
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,(gEngfuncs.pfnRandomFloat(0,1) == 0) ? "weapons/sten_nfire1.wav" : "weapons/sten_nfire2.wav",gEngfuncs.pfnRandomFloat(0.6, 0.75),ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
}
EV_GetGunPosition( args, vecSrc, origin );
EV_HLDM_FireBullets(idx,forward,right,up,1,vecSrc,forward,8192,BULLET_9MMP,ev_thermal ? 1 : 0,ev_thermal ? &tracerCount[idx-1] : 0,args->fparam1,args->fparam2,P_STEN);
}
/*************
Molotov Cocktail
*************/
void EV_MolotovCocktail(event_args_t *args)
{
int flameidx = gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/fire.spr");
int idx = args->entindex;
int i;
float lifetime = args->fparam1;
float radius = args->fparam2;
vec3_t origin,origin_down,normal,flame_origin,dl_normal;
dlight_t *dl;
pmtrace_t tr;
physent_t *pe;
TEMPENTITY *pExplosion;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,normal);
// If we're underwater, dont bother running the event
if(gEngfuncs.PM_PointContents(origin,NULL) == CONTENTS_WATER)
return;
VectorScale(normal,-1024,origin_down);
VectorAdd(origin,origin_down,origin_down);
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false,true);
gEngfuncs.pEventAPI->EV_PushPMStates();
gEngfuncs.pEventAPI->EV_SetSolidPlayers(idx - 1);
gEngfuncs.pEventAPI->EV_SetTraceHull(2);
gEngfuncs.pEventAPI->EV_PlayerTrace(origin,origin_down,PM_WORLD_ONLY,-1,&tr);
pe = gEngfuncs.pEventAPI->EV_GetPhysent(tr.ent);
// Add scorch mark
if(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("{scorch1")),
gEngfuncs.pEventAPI->EV_IndexFromTrace(&tr),0,tr.endpos,0);
}
pExplosion = gEngfuncs.pEfxAPI->R_TempSprite(origin + normal * 8,
Vector(0,0,8),
4,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/explode1.spr"),
kRenderTransAdd,
0,
25,
2,
FTENT_SPRANIMATE);
// Create dynamiclight
dl = gEngfuncs.pEfxAPI->CL_AllocDlight(0);
if(dl != NULL)
{
VectorCopy(args->origin,dl->origin);
// Pull out of the wall so the light shows up
VectorScale(normal,6,dl_normal);
VectorAdd(dl_normal,dl->origin,dl->origin);
dl->radius = radius;
// Color
dl->color.r = 255;
dl->color.g = 220;
dl->color.b = 0;
dl->die = gHUD.m_flTime + lifetime;
dl->decay = 1/(lifetime/dl->radius); // Make it so it completely decays
}
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_AUTO,"debris/glass1.wav",1.0,ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_AUTO,"debris/glass2.wav",1.0,ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 2:
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_AUTO,"debris/glass3.wav",1.0,ATTN_NORM,0,98 + gEngfuncs.pfnRandomLong(0,3)); break;
}
// Main flame
VectorCopy(origin,flame_origin);
gEngfuncs.pEventAPI->EV_PopPMStates();
// Cinders
for(i = 0;i <= CVAR_GET_FLOAT("cl_efx_frequency");i++)
{
vec3_t cinder_origin = flame_origin + normal*10;
// randomize cinder_origin a bit
cinder_origin[0] += gEngfuncs.pfnRandomFloat(-9.0f,9.0f);
cinder_origin[1] += gEngfuncs.pfnRandomFloat(-9.0f,9.0f);
cinder_origin[2] += gEngfuncs.pfnRandomFloat(-9.0f,9.0f);
TEMPENTITY *pTent = gEngfuncs.pEfxAPI->CL_TempEntAllocNoModel(cinder_origin);
if(pTent != NULL)
{
pTent->flags |= FTENT_NOMODEL|FTENT_GRAVITY|FTENT_COLLIDEWORLD|FTENT_COLLIDEKILL|FTENT_PERSIST|FTENT_CLIENTCUSTOM;
pTent->die += lifetime;
}
}
}
/*************
Frag Grenade
*************/
// copied from util.cpp to here
float EV_WaterLevel(float *position, float minz, float maxz )
{
vec3_t midUp = position;
midUp.z = minz;
if (gEngfuncs.PM_PointContents(midUp,NULL) != CONTENTS_WATER)
return minz;
midUp.z = maxz;
if (gEngfuncs.PM_PointContents(midUp,NULL) == CONTENTS_WATER)
return maxz;
float diff = maxz - minz;
while (diff > 1.0)
{
midUp.z = minz + diff/2.0;
if (gEngfuncs.PM_PointContents(midUp,NULL) == CONTENTS_WATER)
{
minz = midUp.z;
}
else
{
maxz = midUp.z;
}
diff = maxz - minz;
}
return midUp.z;
}
void EV_FragGrenade_ShrapnelCallback(struct tempent_s *ent,float frametime,float currenttime)
{
if(gHUD.m_flTime >= ent->entity.baseline.fuser1)
{
ent->entity.baseline.fuser1 = gHUD.m_flTime + 0.25f;
// Emit a smoke tent
TEMPENTITY *pTent = gEngfuncs.pEfxAPI->R_TempSprite(ent->entity.origin,
Vector(0,0,5),
1,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/smoke1.spr"),
kRenderTransAlpha,
0,
25,
5,
FTENT_SPRANIMATE);
// state settings
if(pTent != NULL)
{
pTent->entity.curstate.framerate = 30;
pTent->entity.curstate.renderamt = 128;
}
}
}
void EV_FragGrenade(event_args_t *args)
{
int idx = args->entindex;
int inwater = args->iparam1;
vec3_t origin,normal;
vec3_t origin_down;
vec3_t sh_forward,sh_right,sh_up,sh_velocity;
pmtrace_t tr;
physent_t *pe;
TEMPENTITY *pExplosion;
TEMPENTITY *pShrapnel;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,normal);
VectorScale(normal,-32,origin_down);
VectorAdd(origin,origin_down,origin_down);
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false,true);
gEngfuncs.pEventAPI->EV_PushPMStates();
gEngfuncs.pEventAPI->EV_SetSolidPlayers(idx - 1);
gEngfuncs.pEventAPI->EV_SetTraceHull(2);
gEngfuncs.pEventAPI->EV_PlayerTrace(origin + normal*16,origin_down,PM_WORLD_ONLY,-1,&tr);
gEngfuncs.pEventAPI->EV_PopPMStates();
pe = gEngfuncs.pEventAPI->EV_GetPhysent(tr.ent);
// Add scorch mark
if(!inwater && 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("{scorch1")),
gEngfuncs.pEventAPI->EV_IndexFromTrace(&tr),0,tr.endpos,0);
}
// create the explosion sprite
if(!inwater)
{
pExplosion = gEngfuncs.pEfxAPI->R_TempSprite(origin + normal * 8,
Vector(0,0,8),
4,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/explode1.spr"),
kRenderTransAdd,
0,
25,
2,
FTENT_SPRANIMATE);
}
else
{
vec3_t mins = origin - Vector(64,64,64);
vec3_t maxs = origin + Vector(64,64,64);
vec3_t mid = (mins + maxs) * 0.5f;
float flHeight = EV_WaterLevel(mid,mid.z,mid.z + 1024);
flHeight = flHeight - mins.z;
// Water bubbles!
gEngfuncs.pEfxAPI->R_Bubbles(mins,
maxs,
flHeight,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/bubble.spr"),
CVAR_GET_FLOAT("cl_efx_frequency") * 75,
8);
}
// Explosion
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode3.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode4.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode5.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
}
// Debris sound
if(!inwater)
{
if(gEngfuncs.pfnRandomLong(0,1))
{
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/debris1.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/debris2.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/debris3.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
}
}
}
// Shrapnel !
if(!inwater)
{
AngleVectors(normal,sh_forward,sh_right,sh_up);
for(int i = 0;i < CVAR_GET_FLOAT("cl_efx_frequency") * 4;i++)
{
// Randomize velocity
sh_velocity = sh_forward * gEngfuncs.pfnRandomFloat(-800.0f,800.0f) + sh_right * gEngfuncs.pfnRandomFloat(-800.0f,800.0f) + sh_up * gEngfuncs.pfnRandomFloat(200.0f,400.0f);
pShrapnel = gEngfuncs.pEfxAPI->R_TempModel(origin + normal * 10,
sh_velocity,
normal,
5,
gEngfuncs.pEventAPI->EV_FindModelIndex("models/shrapnel.mdl"),
0);
if(pShrapnel != NULL)
{
pShrapnel->flags |= FTENT_CLIENTCUSTOM;
pShrapnel->callback = EV_FragGrenade_ShrapnelCallback;
// Next smoke emit
pShrapnel->entity.baseline.fuser1 = gHUD.m_flTime + 0.25f;
}
}
}
}
/*************
Pipebomb
*************/
void EV_Pipebomb(event_args_t *args)
{
int idx = args->entindex;
int inwater = args->iparam1;
vec3_t origin,normal;
vec3_t origin_down;
pmtrace_t tr;
physent_t *pe;
TEMPENTITY *pExplosion;
VectorCopy(args->origin,origin);
VectorCopy(args->angles,normal);
VectorScale(normal,-32,origin_down);
VectorAdd(origin,origin_down,origin_down);
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false,true);
gEngfuncs.pEventAPI->EV_PushPMStates();
gEngfuncs.pEventAPI->EV_SetSolidPlayers(idx - 1);
gEngfuncs.pEventAPI->EV_SetTraceHull(2);
gEngfuncs.pEventAPI->EV_PlayerTrace(origin + normal*16,origin_down,PM_WORLD_ONLY,-1,&tr);
gEngfuncs.pEventAPI->EV_PopPMStates();
pe = gEngfuncs.pEventAPI->EV_GetPhysent(tr.ent);
// Add scorch mark
if(!inwater && 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("{scorch1")),
gEngfuncs.pEventAPI->EV_IndexFromTrace(&tr),0,tr.endpos,0);
}
// Explosion
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode3.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode4.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound(idx, origin, CHAN_AUTO, "weapons/explode5.wav", 1.0, ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong(0,3)); break;
}
// create the explosion sprite
if(!inwater)
{
pExplosion = gEngfuncs.pEfxAPI->R_TempSprite(origin + normal * 8,
Vector(0,0,8),
4.75f,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/explode1.spr"),
kRenderTransAdd,
0,
25,
2,
FTENT_SPRANIMATE);
}
else
{
vec3_t mins = origin - Vector(64,64,64);
vec3_t maxs = origin + Vector(64,64,64);
vec3_t mid = (mins + maxs) * 0.5f;
float flHeight = EV_WaterLevel(mid,mid.z,mid.z + 1024);
flHeight = flHeight - mins.z;
// Water bubbles!
gEngfuncs.pEfxAPI->R_Bubbles(mins,
maxs,
flHeight,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/bubble.spr"),
CVAR_GET_FLOAT("cl_efx_frequency") * 75,
8);
}
}
/*************
Combat Knife
*************/
void EV_CombatKnife(event_args_t *args)
{
int idx,primary_attack;
vec3_t origin;
vec3_t vecSrc,vecDest;
idx = args->entindex;
primary_attack = args->iparam1;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/combatknife_slash1.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
if(primary_attack)
gEngfuncs.pEventAPI->EV_WeaponAnimation(COMBATKNIFE_ATTACK1MISS,1);
else
{
switch(gEngfuncs.pfnRandomLong(0,1))
{
case 0:
gEngfuncs.pEventAPI->EV_WeaponAnimation(COMBATKNIFE_ATTACK2,1); break;
case 1:
gEngfuncs.pEventAPI->EV_WeaponAnimation(COMBATKNIFE_ATTACK3,1); break;
}
}
}
}
/*************
Baseball Bat
*************/
void EV_BaseballBat(event_args_t *args)
{
int idx;
vec3_t origin;
vec3_t vecSrc,vecDest;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/baseballbat_slash1.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
switch(gEngfuncs.pfnRandomLong(0,2))
{
case 0: gEngfuncs.pEventAPI->EV_WeaponAnimation(BAT_ATTACK1,1); break;
case 1: gEngfuncs.pEventAPI->EV_WeaponAnimation(BAT_ATTACK2,1); break;
case 2: gEngfuncs.pEventAPI->EV_WeaponAnimation(BAT_ATTACK3,1); break;
}
}
}
/*************
Sledge Hammer
*************/
void EV_SledgeHammer(event_args_t *args)
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/sledgehammer_slash1.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
switch(gEngfuncs.pfnRandomLong(0,1))
{
case 0: gEngfuncs.pEventAPI->EV_WeaponAnimation(SLEDGE_ATTACK1,1); break;
case 1: gEngfuncs.pEventAPI->EV_WeaponAnimation(SLEDGE_ATTACK2,1); break;
}
}
}
/*************
Katana
*************/
void EV_Katana(event_args_t *args)
{
int idx,primary_attack;
vec3_t origin;
idx = args->entindex;
primary_attack = args->iparam1;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/katana_slash1.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
if(primary_attack)
{
gEngfuncs.pEventAPI->EV_WeaponAnimation(KATANA_ST1_ATTACK1,1);
}
else
{
switch(gEngfuncs.pfnRandomLong(0,1))
{
case 0: gEngfuncs.pEventAPI->EV_WeaponAnimation(KATANA_ST2_ATTACK1,1); break;
case 1: gEngfuncs.pEventAPI->EV_WeaponAnimation(KATANA_ST2_ATTACK2,1); break;
}
}
}
}
/*************
Spear
*************/
void EV_Spear(event_args_t *args)
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/spear_slash1.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
switch(gEngfuncs.pfnRandomLong(0,1))
{
case 0: gEngfuncs.pEventAPI->EV_WeaponAnimation(SPEAR_ATTACK1,1); break;
case 1: gEngfuncs.pEventAPI->EV_WeaponAnimation(SPEAR_ATTACK2,1); break;
}
}
}
extern cvar_t *sensitivity;
/*************
Cattle Prod
*************/
void EV_CattleProd(event_args_t *args)
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound(idx,origin,CHAN_WEAPON,"weapons/prod_hit.wav",1,ATTN_NORM,0,PITCH_NORM);
if(EV_IsLocal(idx))
{
switch(gEngfuncs.pfnRandomLong(0,1))
{
case 0: gEngfuncs.pEventAPI->EV_WeaponAnimation(PROD_ATTACK1,1); break;
case 1: gEngfuncs.pEventAPI->EV_WeaponAnimation(PROD_ATTACK2,1); break;
}
}
}
/*************
Akimbo Weapons
*************/
void EV_AkimboWeapon(event_args_t *args, char *sound, char *loshell, char *hishell, int bullettype, int ptype )
{
int idx;
vec3_t origin, angles, up, right, forward, velocity;
vec3_t vecSrc, vecAiming;
int curhand;
int ammo_left;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
idx = args->entindex;
curhand = args->iparam1;
ammo_left = args->iparam2;
// Play firing sound
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, sound, 1, ATTN_NORM, 0, PITCH_NORM );
// Shell ejection
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
if(!CVAR_GET_FLOAT("cl_shellcase_quality"))
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ( loshell );
else
shell = gEngfuncs.pEventAPI->EV_FindModelIndex ( hishell );
if( curhand == AH_RIGHT )
EV_GetDefaultShellInfo( 0, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, 5 );
else
EV_GetDefaultShellInfo( 0, args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 10, -4, -5 );
EV_EjectBrass( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
if( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
if( curhand == AH_LEFT )
{
if( ammo_left <= 1 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( AKIMBO_LSHOOTLAST, 1 );
else
gEngfuncs.pEventAPI->EV_WeaponAnimation( AKIMBO_LSHOOT, 1 );
}
else
{
if( ammo_left <= 1 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( AKIMBO_RSHOOTLAST_LEMPTY, 1 );
else
gEngfuncs.pEventAPI->EV_WeaponAnimation( AKIMBO_RSHOOT, 1 );
}
}
// TODO: change penetration type and bullet type to match different guns!
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, bullettype, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2, ptype );
}
void EV_AkimboBerettas( event_args_t *args )
{
int idx = args->entindex;
EV_AkimboWeapon( args,
"weapons/beretta_fire.wav",
"models/shells/shell_9x18mm_lo.mdl",
"models/shells/shell_9x18mm_hi.mdl",
BULLET_9MMP,
P_BERETTA );
if( EV_IsLocal( idx ) )
V_PunchAxis( 0, -2.0 );
}
void EV_AkimboColts( event_args_t *args )
{
int idx = args->entindex;
EV_AkimboWeapon( args,
"weapons/colt_fire.wav",
"models/shells/shell_10mm_lo.mdl",
"models/shells/shell_10mm_hi.mdl",
BULLET_10MM,
P_COLT );
if( EV_IsLocal( idx ) )
V_PunchAxis( 0, -2.0 );
}
void EV_AkimboDeagles( event_args_t *args )
{
int idx = args->entindex;
EV_AkimboWeapon( args,
"weapons/deagle_fire.wav",
"models/shells/shell_50AE_lo.mdl",
"models/shells/shell_50AE_hi.mdl",
BULLET_50AE,
P_DEAGLE );
if( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -2.0 );
RECOIL_VIEW(5.5,0);
}
}
void EV_AkimboSawedOffs( event_args_t *args )
{
int idx = args->entindex;
int curhand = args->iparam1;
int bothshoot = args->bparam1; // Both guns were fired :O
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t up, right, forward;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
if( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
if( bothshoot )
gEngfuncs.pEventAPI->EV_WeaponAnimation( AKIMBOSS_BSHOOT, 2 );
else
gEngfuncs.pEventAPI->EV_WeaponAnimation( (curhand == AH_LEFT) ? AKIMBOSS_LSHOOT : AKIMBOSS_RSHOOT, 2 );
if( bothshoot )
V_PunchAxis( 0, -11.5 );
else
V_PunchAxis( 0, -5.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, ( !bothshoot ) ? "weapons/sawedoff_fire1.wav" : "weapons/sawedoff_fire2.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
int shotCount = (bothshoot) ? 26 : 14;
// Remember to change the randomization code at the bottom :)
EV_HLDM_FireBullets( idx, forward, right, up, shotCount, vecSrc, vecAiming, 2048, BULLET_20GAUGE, (ev_thermal) ? 1 : 0, (ev_thermal) ? &tracerCount[idx-1] : 0, args->fparam1, args->fparam2, 0 );
}