mirror of
https://github.com/UberGames/RPG-X2.git
synced 2024-11-25 13:51:03 +00:00
2503 lines
71 KiB
C
2503 lines
71 KiB
C
// Copyright (C) 1999-2000 Id Software, Inc.
|
|
//
|
|
// cg_weapons.c -- events and effects dealing with weapons
|
|
#include "cg_local.h"
|
|
#include "fx_local.h"
|
|
|
|
//RPG-X : TiM - Weapons Arrays
|
|
static int RAweapons[8] = { WP_PADD,
|
|
WP_TRICORDER,
|
|
WP_COMPRESSION_RIFLE,
|
|
WP_TR116,
|
|
WP_VOYAGER_HYPO,
|
|
WP_DERMAL_REGEN,
|
|
WP_MEDKIT,
|
|
WP_COFFEE
|
|
};
|
|
|
|
static char *RAweapFileName[8] = { "padd",
|
|
"tricorder",
|
|
"prifle",
|
|
"tr116",
|
|
"hypospray",
|
|
"dermal_regen",
|
|
"medkit",
|
|
"coffeecup"
|
|
};
|
|
|
|
|
|
/*
|
|
=================
|
|
CG_RegisterWeapon
|
|
|
|
The server says this item is used on this level
|
|
=================
|
|
*/
|
|
|
|
// kef -- sad? yep.
|
|
typedef struct wpnBarrelInfo_s
|
|
{
|
|
weapon_t giTag;
|
|
int numBarrels;
|
|
int flashTime;
|
|
} wpnBarrelInfo_t;
|
|
|
|
wpnBarrelInfo_t wpnBarrelData[] =
|
|
{
|
|
{WP_NULL_HAND, 0, 0},
|
|
|
|
{WP_TRICORDER, 0, 0},
|
|
{WP_PADD, 0, 0},
|
|
{WP_COFFEE, 0, 0},
|
|
|
|
{WP_PHASER, 0, 0},
|
|
{WP_COMPRESSION_RIFLE, 0, 120},
|
|
{WP_TR116, 1, 60},
|
|
|
|
{WP_GRENADE_LAUNCHER, 2, 150},
|
|
{WP_QUANTUM_BURST, 1, 200},
|
|
{WP_DISRUPTOR, 1, 130},
|
|
|
|
{WP_MEDKIT, 0, 0},
|
|
{WP_VOYAGER_HYPO, 0, 0},
|
|
{WP_DERMAL_REGEN, 0, 0},
|
|
|
|
{WP_TOOLKIT, 0, 0},
|
|
{WP_HYPERSPANNER, 0, 0},
|
|
|
|
// make sure this is the last entry in this array, please
|
|
{WP_NONE, 0, 0},
|
|
};
|
|
|
|
//wpnBarrelInfo_t wpnBarrelData[] =
|
|
//{
|
|
// {WP_PHASER, 0, 0},
|
|
// {WP_COMPRESSION_RIFLE, 0, 100},
|
|
// {WP_NULL_HAND, 0, 0},
|
|
// {WP_COFFEE, 0, 0},
|
|
// {WP_DISRUPTOR, 1, 80},
|
|
// {WP_GRENADE_LAUNCHER, 2, 140},
|
|
// {WP_TR116, 1, 120},
|
|
// {WP_QUANTUM_BURST, 1, 200},
|
|
// {WP_DERMAL_REGEN, 0, 0},
|
|
// {WP_VOYAGER_HYPO, 0, 0},
|
|
// {WP_TOOLKIT, 0, 0},
|
|
// {WP_MEDKIT, 0, 0},
|
|
// {WP_TRICORDER, 0, 0},
|
|
// {WP_PADD, 0, 0},
|
|
// {WP_NEUTRINO_PROBE, 0, 0},
|
|
// {WP_TR116, 0, 90},
|
|
//
|
|
// // make sure this is the last entry in this array, please
|
|
// {WP_NONE, 0},
|
|
//};
|
|
|
|
void CG_RegisterWeapon( int weaponNum ) {
|
|
weaponInfo_t *weaponInfo;
|
|
gitem_t *item, *ammo;
|
|
char path[MAX_QPATH];
|
|
vec3_t mins, maxs;
|
|
int i;
|
|
int numBarrels = 0;
|
|
wpnBarrelInfo_t *barrelInfo = NULL;
|
|
|
|
|
|
weaponInfo = &cg_weapons[weaponNum];
|
|
|
|
if ( weaponNum == 0 ) {
|
|
return;
|
|
}
|
|
|
|
if ( weaponInfo->registered ) {
|
|
return;
|
|
}
|
|
|
|
memset( weaponInfo, 0, sizeof( *weaponInfo ) );
|
|
weaponInfo->registered = qtrue;
|
|
|
|
for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
|
|
if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
|
|
/*if ( weaponNum == WP_DISRUPTOR ) {
|
|
Com_Printf( S_COLOR_RED "Registering %s with pickup name of %s\n", bg_itemlist[10].classname, bg_itemlist[10].pickup_name );
|
|
}*/
|
|
weaponInfo->item = item;
|
|
break;
|
|
}
|
|
}
|
|
if ( !item->classname ) {
|
|
CG_Error( "Couldn't find weapon %i", weaponNum );
|
|
}
|
|
CG_RegisterItemVisuals( item - bg_itemlist );
|
|
|
|
weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model );
|
|
|
|
// kef -- load in-view model
|
|
weaponInfo->viewModel = trap_R_RegisterModel(item->view_model);
|
|
|
|
// calc midpoint for rotation
|
|
trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
|
|
for ( i = 0 ; i < 3 ; i++ ) {
|
|
weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
|
|
}
|
|
|
|
weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
|
|
|
|
for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
|
|
if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
|
|
break;
|
|
}
|
|
}
|
|
// if ( ammo->classname && ammo->world_model ) {
|
|
// weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model );
|
|
// }
|
|
|
|
strcpy( path, item->view_model );
|
|
COM_StripExtension( path, path );
|
|
strcat( path, "_flash.md3" );
|
|
weaponInfo->flashModel = trap_R_RegisterModel( path );
|
|
|
|
for (barrelInfo = wpnBarrelData; barrelInfo->giTag != WP_NONE; barrelInfo++)
|
|
{
|
|
if (barrelInfo->giTag == weaponNum)
|
|
{
|
|
numBarrels = barrelInfo->numBarrels;
|
|
break;
|
|
}
|
|
}
|
|
for (i=0; i< numBarrels; i++) {
|
|
Q_strncpyz( path, item->view_model, MAX_QPATH );
|
|
COM_StripExtension( path, path );
|
|
if (i)
|
|
{
|
|
strcat( path, va("_barrel%d.md3", i+1));
|
|
}
|
|
else
|
|
strcat( path, "_barrel.md3" );
|
|
weaponInfo->barrelModel[i] = trap_R_RegisterModel( path );
|
|
}
|
|
|
|
strcpy( path, item->view_model );
|
|
COM_StripExtension( path, path );
|
|
strcat( path, "_hand.md3" );
|
|
weaponInfo->handsModel = trap_R_RegisterModel( path );
|
|
|
|
if ( !weaponInfo->handsModel ) {
|
|
weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_hand.md3" );
|
|
}
|
|
|
|
switch ( weaponNum ) {
|
|
case WP_PHASER:
|
|
MAKERGB( weaponInfo->flashDlightColor, 0, 0, 0 );
|
|
|
|
weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "phaser/phaserfiring.wav" );
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "phaser/altphaserfiring.wav" );
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "phaser/phaserstart.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "phaser/altphaserstart.wav" );
|
|
weaponInfo->stopSound = trap_S_RegisterSound(SOUND_DIR "phaser/phaserstop.wav");
|
|
weaponInfo->altStopSound = trap_S_RegisterSound(SOUND_DIR "phaser/altphaserstop.wav");
|
|
|
|
cgs.media.phaserShader = trap_R_RegisterShader( "gfx/misc/phaser_stx" );
|
|
cgs.media.phaserEmptyShader = trap_R_RegisterShader( "gfx/misc/phaserempty" );
|
|
|
|
cgs.media.phaserAltShader = trap_R_RegisterShader("gfx/effects/whitelaser"); // "gfx/misc/phaser_alt" );
|
|
|
|
cgs.media.phaserAltEmptyShader = trap_R_RegisterShader( "gfx/misc/phaser_altempty" );
|
|
cgs.media.phaserMuzzleEmptyShader= trap_R_RegisterShader( "models/weapons2/phaser/muzzle_empty" );
|
|
|
|
break;
|
|
|
|
case WP_DERMAL_REGEN:
|
|
weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "dermal_regen/dm_1.wav" );
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "dermal_regen/dm_2.wav" );
|
|
break;
|
|
|
|
case WP_DISRUPTOR:
|
|
//weaponInfo->missileTrailFunc = FX_StasisProjectileThink;
|
|
weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/alien_disruptor/disruptor_bolt.md3" );
|
|
weaponInfo->missileDlight = 70;
|
|
MAKERGB( weaponInfo->missileDlightColor, 0.0, 1.0, 0.0 );
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.0, 1.0, 0.0 );
|
|
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/fire.wav" );
|
|
weaponInfo->mainHitSound = trap_S_RegisterSound(SOUND_DIR "stasis/hit_wall.wav");
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/disruptorstart.wav" );
|
|
weaponInfo->stopSound = trap_S_RegisterSound(SOUND_DIR "alien_disruptor/disruptorstop.wav");
|
|
weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/disruptorfiring.wav" );
|
|
|
|
cgs.media.disruptorBolt = trap_R_RegisterShader( "gfx/misc/disruptor_bolt" );
|
|
cgs.media.disruptorStreak = trap_R_RegisterShader( "gfx/misc/disruptor_streak" );
|
|
//cgs.media.altIMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2alt" );
|
|
//cgs.media.dnBoltShader = trap_R_RegisterShader( "gfx/misc/dnBolt" );
|
|
|
|
cgs.media.greenParticleShader = trap_R_RegisterShader( "gfx/misc/greenparticle" );
|
|
cgs.media.greenParticleStreakShader = trap_R_RegisterShader( "gfx/misc/greenparticle_anamorphic" );
|
|
|
|
cgs.media.disruptorBeam = trap_R_RegisterShader( "gfx/misc/disruptor" );
|
|
|
|
break;
|
|
|
|
case WP_GRENADE_LAUNCHER:
|
|
weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile.md3" );
|
|
if(rpg_ctribgrenade.integer == 1)//RPG-X: - RedTechie Possible Hack! FIX | TiM: Heh, you're a possible hack :)
|
|
{
|
|
weaponInfo->alt_missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile2a.md3" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "glauncher/alt_fire.wav" );
|
|
weaponInfo->altHitSound = trap_S_RegisterSound( "sound/weapons/glauncher/beepa.wav" );
|
|
cgs.media.grenadeAltStickSound = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_stick.wav");
|
|
|
|
}
|
|
else
|
|
{
|
|
weaponInfo->alt_missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile2.md3" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "glauncher/alt_fire.wav" );
|
|
weaponInfo->altHitSound = trap_S_RegisterSound( SOUND_DIR "glauncher/beep.wav" );
|
|
cgs.media.grenadeAltStickSound = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_stick.wav");
|
|
}
|
|
|
|
weaponInfo->missileTrailFunc = FX_GrenadeThink;
|
|
//TiM : No flash anymore
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.0, 0.0, 0.0 );
|
|
//MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 );
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "glauncher/fire.wav" );
|
|
cgs.media.grenadeBounceSound1 = trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav");
|
|
cgs.media.grenadeBounceSound2 = trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav");
|
|
cgs.media.grenadeExplodeSound = trap_S_RegisterSound(SOUND_DIR "glauncher/explode.wav");
|
|
cgs.media.grenadeAltExplodeSnd = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_explode.wav" );
|
|
|
|
cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" );
|
|
cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );
|
|
cgs.media.whiteLaserShader = trap_R_RegisterShader( "gfx/effects/whitelaser" );
|
|
cgs.media.borgEyeFlareShader = trap_R_RegisterShader( "gfx/misc/borgeyeflare" );
|
|
break;
|
|
|
|
case WP_COFFEE:
|
|
//MAKERGB( weaponInfo->flashDlightColor, 1, 0.6, 0.6 );
|
|
|
|
/*weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "scavenger/fire.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "scavenger/alt_fire.wav" );
|
|
weaponInfo->mainHitSound = trap_S_RegisterSound(SOUND_DIR "scavenger/hit_wall.wav");
|
|
weaponInfo->altHitSound = trap_S_RegisterSound(SOUND_DIR "scavenger/alt_explode.wav");
|
|
weaponInfo->missileTrailFunc = FX_ScavengerProjectileThink;
|
|
weaponInfo->alt_missileTrailFunc = FX_ScavengerAltFireThink;
|
|
// weaponInfo->wiTrailTime = 100;
|
|
// weaponInfo->trailRadius = 8;
|
|
cgs.media.tetrionFlareShader = trap_R_RegisterShader( "gfx/misc/tet1" );
|
|
cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" );
|
|
cgs.media.redFlareShader = trap_R_RegisterShader( "gfx/misc/red_flare" );
|
|
|
|
cgs.media.scavengerAltShader = trap_R_RegisterShader( "gfx/misc/scavaltfire" );
|
|
cgs.media.scavExplosionFastShader = trap_R_RegisterShader( "scavExplosionFast" );
|
|
cgs.media.scavExplosionSlowShader = trap_R_RegisterShader( "scavExplosionSlow" );
|
|
cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );*/
|
|
break;
|
|
|
|
case WP_QUANTUM_BURST:
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 ); //Bluish
|
|
|
|
weaponInfo->missileTrailFunc = FX_QuantumThink;
|
|
weaponInfo->alt_missileTrailFunc = FX_QuantumAltThink;
|
|
|
|
weaponInfo->missileDlight = 75;
|
|
weaponInfo->alt_missileDlight = 100;
|
|
MAKERGB( weaponInfo->missileDlightColor, 1.0, 1.0, 0.5); //yellowish
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "quantum/fire.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "quantum/alt_fire.wav" );
|
|
|
|
weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "quantum/hit_wall.wav" );;
|
|
weaponInfo->altHitSound = trap_S_RegisterSound( SOUND_DIR "quantum/alt_hit_wall.wav" );;
|
|
|
|
cgs.media.whiteRingShader = trap_R_RegisterShader( "gfx/misc/whitering" );
|
|
cgs.media.orangeRingShader = trap_R_RegisterShader( "gfx/misc/orangering" );
|
|
cgs.media.quantumExplosionShader = trap_R_RegisterShader( "quantumExplosion" );
|
|
cgs.media.quantumFlashShader = trap_R_RegisterShader( "yellowflash" );
|
|
//cgs.media.bigBoomShader = trap_R_RegisterShader( "gfx/misc/bigboom" );
|
|
cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" );
|
|
cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );
|
|
cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" );
|
|
cgs.media.quantumRingShader = trap_R_RegisterShader( "gfx/misc/detpack3" );
|
|
cgs.media.quantumBoom = trap_S_RegisterSound ( SOUND_DIR "explosions/explode5.wav" );
|
|
break;
|
|
|
|
case WP_NULL_HAND:
|
|
/*MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 );
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "IMOD/fire.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "IMOD/alt_fire.wav" );
|
|
|
|
cgs.media.IMODShader = trap_R_RegisterShader( "gfx/misc/IMOD" );
|
|
cgs.media.IMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2" );
|
|
cgs.media.altIMODShader = trap_R_RegisterShader( "gfx/misc/IMODalt" );
|
|
cgs.media.altIMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2alt" );
|
|
cgs.media.imodExplosionShader = trap_R_RegisterShader( "imodExplosion" );*/
|
|
break;
|
|
|
|
case WP_COMPRESSION_RIFLE:
|
|
if(!grp_berp.integer) {
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.59, 0.24, 0.25 );
|
|
MAKERGB( weaponInfo->missileDlightColor, 0.59, 0.24, 0.25 );
|
|
} else {
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.16, 0.32, 0.5 );
|
|
MAKERGB( weaponInfo->missileDlightColor, 0.16, 0.32, 0.5 );
|
|
}
|
|
|
|
weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_bolt.md3" );
|
|
weaponInfo->missileDlight = 90;
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "prifle/fire.wav" );
|
|
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "prifle/phaserriflestart.wav" );
|
|
weaponInfo->altStopSound = trap_S_RegisterSound(SOUND_DIR "prifle/phaserriflestop.wav");
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "prifle/phaserriflefiring.wav" );
|
|
|
|
weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "prifle/impact.wav" );;
|
|
|
|
cgs.media.prifleImpactShader = trap_R_RegisterShader( "gfx/effects/prifle_hit" );
|
|
cgs.media.compressionAltBeamShader = trap_R_RegisterShader( "gfx/effects/prifle_altbeam" );
|
|
cgs.media.compressionAltBlastShader = trap_R_RegisterShader( "gfx/effects/prifle_altblast" );
|
|
cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );
|
|
cgs.media.prifleBolt = trap_R_RegisterShader( "gfx/misc/priflebolt" );
|
|
|
|
cgs.media.liteRedParticleStreakShader = trap_R_RegisterShader( "gfx/misc/literedparticle_anamorphic" );
|
|
cgs.media.liteRedParticleShader = trap_R_RegisterShader( "gfx/misc/literedparticle" );
|
|
|
|
cgs.media.flashlightModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_flashlight.md3" ); //RPG-X : TiM - flashlight model
|
|
|
|
cgs.media.prifleBeam = trap_R_RegisterShader( "gfx/misc/phaser_rifle" );
|
|
|
|
break;
|
|
|
|
/* case WP_TR116:
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.16, 0.16, 1 );
|
|
weaponInfo->flashSound = trap_S_RegisterSound( "sound/weapons/hitonhead.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/weapons/guncharge.wav" );
|
|
cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" );
|
|
cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );
|
|
weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "prifle/impact.wav" );
|
|
break;*/
|
|
/*
|
|
case WP_TR116: //OLD CODE (replaced for TR116)
|
|
MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 );
|
|
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "tetrion/fire.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "tetrion/alt_fire.wav" );
|
|
cgs.media.tetrionRicochetSound1 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet1.wav");
|
|
cgs.media.tetrionRicochetSound2 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet2.wav");
|
|
cgs.media.tetrionRicochetSound3 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet3.wav");
|
|
|
|
weaponInfo->missileTrailFunc = FX_TetrionProjectileThink;
|
|
weaponInfo->alt_missileTrailFunc = FX_TetrionProjectileThink;
|
|
|
|
cgs.media.greenBurstShader = trap_R_RegisterShader( "gfx/misc/greenburst" );
|
|
cgs.media.greenTrailShader = trap_R_RegisterShader( "gfx/misc/greentrail" );
|
|
cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" );
|
|
cgs.media.tetrionFlareShader = trap_R_RegisterShader( "gfx/misc/tet1" );
|
|
cgs.media.borgFlareShader = trap_R_RegisterShader( "gfx/misc/borgflare" );
|
|
cgs.media.bulletmarksShader = trap_R_RegisterShader( "textures/decals/bulletmark4" );
|
|
break;
|
|
*/
|
|
case WP_VOYAGER_HYPO:
|
|
weaponInfo->flashSound = weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/items/jetpuffmed.wav" );
|
|
break;
|
|
|
|
case WP_TRICORDER:
|
|
weaponInfo->firingSound= trap_S_RegisterSound( "sound/items/tricorderscan.wav" ); //altFlashSnd
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( "sound/ambience/voyager/medictricorder.wav" ); //flashSound
|
|
|
|
//weaponInfo->isAnimSndBased = qtrue;
|
|
break;
|
|
|
|
case WP_PADD:
|
|
weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "padd/padd_1.wav" ); //flashSound
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "padd/padd_2.wav" ); //altFlashSnd
|
|
|
|
weaponInfo->isAnimSndBased = qtrue;
|
|
break;
|
|
|
|
case WP_HYPERSPANNER:
|
|
weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "hyperspanner/spanner_1.wav" );
|
|
weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "hyperspanner/spanner_2.wav" );
|
|
break;
|
|
|
|
case WP_TR116:
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "hitonhead.wav" );
|
|
weaponInfo->altFlashSnd = weaponInfo->flashSound;
|
|
//weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/weapons/guncharge.wav" );
|
|
break;
|
|
|
|
//Toolkit
|
|
case WP_TOOLKIT:
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "toolkit/toolkit_1.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "toolkit/toolkit_2.wav" );
|
|
break;
|
|
|
|
//Medkit
|
|
case WP_MEDKIT:
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "medkit/medkit_1.wav" );
|
|
weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "medkit/medkit_2.wav" );
|
|
break;
|
|
|
|
default:
|
|
MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
|
|
weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "prifle/fire.wav" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CG_RegisterItemVisuals
|
|
|
|
The server says this item is used on this level
|
|
=================
|
|
*/
|
|
void CG_RegisterItemVisuals( int itemNum ) {
|
|
itemInfo_t *itemInfo;
|
|
gitem_t *item;
|
|
|
|
itemInfo = &cg_items[ itemNum ];
|
|
if ( itemInfo->registered ) {
|
|
return;
|
|
}
|
|
|
|
item = &bg_itemlist[ itemNum ];
|
|
|
|
memset( itemInfo, 0, sizeof( &itemInfo ) );
|
|
itemInfo->registered = qtrue;
|
|
|
|
itemInfo->model = trap_R_RegisterModel( item->world_model );
|
|
|
|
itemInfo->icon = trap_R_RegisterShader( item->icon );
|
|
|
|
if ( item->giType == IT_WEAPON ) {
|
|
CG_RegisterWeapon( item->giTag );
|
|
}
|
|
|
|
// since the seeker uses the scavenger rifes sounds, we must precache the scavenger rifle stuff if we hit the item seeker
|
|
/* if ( item->giTag == PW_FLASHLIGHT)
|
|
{
|
|
CG_RegisterWeapon( WP_COFFEE );
|
|
}*/
|
|
|
|
// hang onto the handles for holdable items in case they're useable (e.g. detpack)
|
|
/* if (IT_HOLDABLE == item->giType)
|
|
{
|
|
// sanity check
|
|
if ( (item->giTag < HI_NUM_HOLDABLE) && (item->giTag > 0) ) // use "> 0" cuz first slot should be empty
|
|
{
|
|
if (item->world_model[1])
|
|
{
|
|
cgs.useableModels[item->giTag] = trap_R_RegisterModel( item->useablemodel );
|
|
}
|
|
else
|
|
{
|
|
cgs.useableModels[item->giTag] = itemInfo->model];
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================================
|
|
|
|
VIEW WEAPON
|
|
|
|
========================================================================================
|
|
*/
|
|
|
|
/*
|
|
=================
|
|
CG_MapTorsoToWeaponFrame
|
|
|
|
=================
|
|
*/
|
|
static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
|
|
animation_t *anim;
|
|
|
|
// change weapon
|
|
anim = &cg_animsList[ci->animIndex].animations[TORSO_DROPWEAP1];
|
|
if ( frame >= anim->firstFrame
|
|
&& frame < anim->firstFrame + 9 ) {
|
|
return frame - anim->firstFrame + 6;
|
|
}
|
|
|
|
// stand attack
|
|
anim = &cg_animsList[ci->animIndex].animations[BOTH_ATTACK3];
|
|
if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) {
|
|
return 1 + frame - anim->firstFrame;
|
|
}
|
|
|
|
// stand attack 2
|
|
anim = &cg_animsList[ci->animIndex].animations[BOTH_ATTACK2];
|
|
if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) {
|
|
return 1 + frame - anim->firstFrame;
|
|
}
|
|
|
|
anim = &cg_animsList[ci->animIndex].animations[TORSO_WEAPONREADY1];
|
|
if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) {
|
|
return 1 + frame - anim->firstFrame;
|
|
}
|
|
|
|
// change weapon
|
|
//USED TO BE TORSO_RAISE
|
|
/* if ( frame >= ci->animations[TORSO_DROPWEAP1].firstFrame
|
|
&& frame < ci->animations[TORSO_DROPWEAP1].firstFrame + 9 ) {
|
|
return frame - ci->animations[TORSO_DROPWEAP1].firstFrame + 6;
|
|
}
|
|
|
|
// stand attack
|
|
if ( frame >= ci->animations[BOTH_ATTACK3].firstFrame
|
|
&& frame < ci->animations[BOTH_ATTACK3].firstFrame + 6 ) {
|
|
return 1 + frame - ci->animations[BOTH_ATTACK3].firstFrame;
|
|
}
|
|
|
|
// stand attack 2
|
|
if ( frame >= ci->animations[BOTH_ATTACK2].firstFrame
|
|
&& frame < ci->animations[BOTH_ATTACK2].firstFrame + 6 ) {
|
|
return 1 + frame - ci->animations[BOTH_ATTACK2].firstFrame;
|
|
}*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
CG_CalculateWeaponPosition
|
|
==============
|
|
*/
|
|
//BOOKMARK
|
|
static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
|
|
float scale;
|
|
int delta;
|
|
float fracsin;
|
|
|
|
VectorCopy( cg.refdef.vieworg, origin );
|
|
VectorCopy( cg.refdefViewAngles, angles );
|
|
|
|
// on odd legs, invert some angles
|
|
if ( cg.bobcycle & 1 ) {
|
|
scale = -cg.xyspeed;
|
|
} else {
|
|
scale = cg.xyspeed;
|
|
}
|
|
|
|
// gun angles from bobbing
|
|
angles[ROLL] += scale * cg.bobfracsin * 0.005;
|
|
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
|
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
|
|
|
|
// drop the weapon when landing
|
|
delta = cg.time - cg.landTime;
|
|
if ( delta < LAND_DEFLECT_TIME ) {
|
|
origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
|
|
} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
|
|
origin[2] += cg.landChange*0.25 *
|
|
(LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
|
|
}
|
|
|
|
#if 0
|
|
// drop the weapon when stair climbing
|
|
delta = cg.time - cg.stepTime;
|
|
if ( delta < STEP_TIME/2 ) {
|
|
origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
|
|
} else if ( delta < STEP_TIME ) {
|
|
origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
|
|
}
|
|
#endif
|
|
|
|
// idle drift
|
|
scale = cg.xyspeed + 40;
|
|
fracsin = sin( cg.time * 0.001 );
|
|
angles[ROLL] += scale * fracsin * 0.01;
|
|
angles[YAW] += scale * fracsin * 0.01;
|
|
angles[PITCH] += scale * fracsin * 0.01;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CG_LightningBolt
|
|
|
|
Origin will be the exact tag point, which is slightly
|
|
different than the muzzle point used for determining hits.
|
|
The cent should be the non-predicted cent if it is from the player,
|
|
so the endpoint will reflect the simulated strike (lagging the predicted
|
|
angle)
|
|
===============
|
|
*/
|
|
|
|
#define RANGE_BEAM (2048.0)
|
|
#define BEAM_VARIATION 6
|
|
|
|
void CG_LightningBolt( centity_t *cent, vec3_t origin )
|
|
{
|
|
trace_t trace;
|
|
// gentity_t *traceEnt;
|
|
vec3_t startpos, endpos, forward;
|
|
qboolean spark = qfalse, impact = qtrue;
|
|
|
|
if ( cg.snap->ps.pm_type == PM_INTERMISSION )
|
|
{
|
|
return; // Don't draw a phaser during an intermission you crezzy mon!
|
|
}
|
|
|
|
//Must be a durational weapon
|
|
if ( cent->currentState.clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson && !(cent->currentState.eFlags & EF_ITEMPLACEHOLDER ) ) //fuck decoys
|
|
{
|
|
// different checks for first person view
|
|
if ( cg.snap->ps.weapon == WP_HYPERSPANNER ||
|
|
cg.snap->ps.weapon == WP_PHASER ||
|
|
cg.snap->ps.weapon == WP_DERMAL_REGEN ||
|
|
(cg.snap->ps.eFlags & EF_ALT_FIRING && cg.snap->ps.weapon == WP_COMPRESSION_RIFLE )
|
|
|| (!(cg.snap->ps.eFlags & EF_ALT_FIRING) && cg.snap->ps.weapon == WP_DISRUPTOR )
|
|
)
|
|
{ /*continue*/ }
|
|
else
|
|
return;
|
|
} else {
|
|
if ( cent->currentState.weapon == WP_HYPERSPANNER ||
|
|
cent->currentState.weapon == WP_PHASER ||
|
|
cent->currentState.weapon == WP_DERMAL_REGEN ||
|
|
(cent->currentState.eFlags & EF_ALT_FIRING && (cent->currentState.weapon == WP_COMPRESSION_RIFLE) ) ||
|
|
(!(cent->currentState.eFlags & EF_ALT_FIRING) && cent->currentState.weapon == WP_DISRUPTOR)
|
|
)
|
|
{ /*continue*/ }
|
|
else
|
|
return;
|
|
}
|
|
|
|
// Find the impact point of the beam
|
|
if ( cent->currentState.clientNum == cg.snap->ps.clientNum
|
|
&& !cg.renderingThirdPerson ) {
|
|
// take origin from view
|
|
/*
|
|
VectorCopy( cg.refdef.vieworg, origin );
|
|
VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
|
|
VectorMA( origin, 8, cg.refdef.viewaxis[0], origin );
|
|
VectorMA( origin, -2, cg.refdef.viewaxis[1], origin );
|
|
*/
|
|
VectorCopy( cg.refdef.viewaxis[0], forward );
|
|
VectorCopy( cg.refdef.vieworg, startpos);
|
|
}
|
|
else
|
|
{
|
|
// take origin from entity
|
|
if ( cent->currentState.clientNum == cg.snap->ps.clientNum )
|
|
AngleVectors( cg.predictedPlayerState.viewangles, forward, NULL, NULL );
|
|
else
|
|
AngleVectors( cent->lerpAngles, forward, NULL, NULL );
|
|
VectorCopy( origin, startpos);
|
|
|
|
// Check first from the center to the muzzle.
|
|
CG_Trace(&trace, cent->lerpOrigin, vec3_origin, vec3_origin, origin, cent->currentState.number, MASK_SHOT);
|
|
if (trace.fraction < 1.0)
|
|
{ // We hit something here... Stomp the muzzle back to the eye...
|
|
VectorCopy(cent->lerpOrigin, startpos);
|
|
if ( cg.snap->ps.eFlags & EF_FULL_ROTATE && Q_fabs( cg.snap->ps.viewangles[PITCH] ) > 89.0f )
|
|
startpos[2] -= 20;
|
|
else
|
|
startpos[2] += cg.snap->ps.viewheight;
|
|
}
|
|
}
|
|
|
|
VectorMA( startpos, RANGE_BEAM, forward, endpos );
|
|
|
|
// Add a subtle variation to the beam weapon's endpoint
|
|
/*for (i = 0; i < 3; i ++ )
|
|
{
|
|
endpos[i] += crandom() * BEAM_VARIATION;
|
|
}*/
|
|
|
|
CG_Trace( &trace, startpos, vec3_origin, vec3_origin, endpos, cent->currentState.number, MASK_SHOT );
|
|
|
|
// traceEnt = &g_entities[ trace.entityNum ];
|
|
|
|
// Make sparking be a bit less frame-rate dependent..also never add sparking when we hit a surface with a NOIMPACT flag
|
|
if (!(trace.surfaceFlags & SURF_NOIMPACT))
|
|
{
|
|
spark = qtrue;
|
|
}
|
|
|
|
// Don't draw certain kinds of impacts when it hits a player and such..or when we hit a surface with a NOIMPACT flag
|
|
if ( cg_entities[trace.entityNum].currentState.eType == ET_PLAYER || (trace.surfaceFlags & SURF_NOIMPACT) )
|
|
{
|
|
impact = qfalse;
|
|
}
|
|
|
|
// Add in the effect
|
|
switch ( cent->currentState.weapon )
|
|
{
|
|
case WP_PHASER:
|
|
if (cg.snap->ps.rechargeTime == 0)
|
|
{
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
FX_PhaserAltFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty );
|
|
else
|
|
FX_PhaserFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty );
|
|
}
|
|
break;
|
|
case WP_COMPRESSION_RIFLE:
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
{
|
|
FX_PrifleBeamFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty );
|
|
}
|
|
break;
|
|
case WP_HYPERSPANNER:
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
FX_ProbeBeam( origin, forward, cent->currentState.clientNum, qtrue );
|
|
else
|
|
FX_ProbeBeam( origin, forward, cent->currentState.clientNum, qfalse );
|
|
break;
|
|
|
|
case WP_DERMAL_REGEN:
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
FX_RegenBeam( origin, forward, cent->currentState.clientNum, qtrue );
|
|
else
|
|
FX_RegenBeam( origin, forward, cent->currentState.clientNum, qfalse );
|
|
break;
|
|
|
|
case WP_DISRUPTOR:
|
|
if ( cent->currentState.eFlags & EF_FIRING && !(cent->currentState.eFlags & EF_ALT_FIRING) )
|
|
FX_DisruptorBeamFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty );
|
|
|
|
/* case WP_DERMAL_REGEN:
|
|
if (!(cent->currentState.eFlags & EF_ALT_FIRING))
|
|
{
|
|
vec3_t org;
|
|
|
|
// Move the beam back a bit to help cover up the poly edges on the fire beam
|
|
VectorMA( origin, -4, forward, org );
|
|
FX_DreadnoughtFire( org, trace.endpos, trace.plane.normal, spark, impact );
|
|
}
|
|
break;*/
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
======================
|
|
CG_MachinegunSpinAngle
|
|
======================
|
|
*/
|
|
#define SPIN_SPEED 0.9
|
|
#define COAST_TIME 1000
|
|
static float CG_MachinegunSpinAngle( centity_t *cent ) {
|
|
int delta;
|
|
float angle;
|
|
float speed;
|
|
|
|
delta = cg.time - cent->pe.barrelTime;
|
|
if ( cent->pe.barrelSpinning ) {
|
|
angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
|
|
} else {
|
|
if ( delta > COAST_TIME ) {
|
|
delta = COAST_TIME;
|
|
}
|
|
|
|
speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
|
|
angle = cent->pe.barrelAngle + delta * speed;
|
|
}
|
|
|
|
if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
|
|
cent->pe.barrelTime = cg.time;
|
|
cent->pe.barrelAngle = AngleMod( angle );
|
|
cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
CG_AddWeaponWithPowerups
|
|
========================
|
|
*/
|
|
|
|
static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups, beamData_t* beamData, int cloakTime, int decloakTime ) //
|
|
{
|
|
// add powerup effects
|
|
if ( powerups & ( 1 << PW_INVIS ) || ( !(powerups & ( 1 << PW_INVIS )) && decloakTime > 0 ) ) {
|
|
|
|
//TiM - modified so it persists during the first bit of cloaking / last of decloaking
|
|
if ( ( cloakTime <= 0 && decloakTime <= 0 ) || ( decloakTime > 0 && cg.time < ( decloakTime + Q_FLASH_TIME * 0.5 ) )
|
|
|| ( cloakTime > 0 && cg.time > ( cloakTime + Q_FLASH_TIME * 0.5 ) ) )
|
|
{
|
|
if ( /*cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN*/ cgs.clientinfo[cg.snap->ps.clientNum].isAdmin )
|
|
{//admins can see cloaked people
|
|
//gun->customShader = cgs.media.teleportEffectShader;
|
|
//TiM - Make it look cooler - Half invis
|
|
gun->renderfx |= RF_FORCE_ENT_ALPHA;
|
|
gun->shaderRGBA[3] = (unsigned char)(0.4f * 255.0f);
|
|
trap_R_AddRefEntityToScene( gun );
|
|
}
|
|
}
|
|
else
|
|
trap_R_AddRefEntityToScene( gun );
|
|
|
|
//gun->customShader = cgs.media.invisShader;
|
|
//trap_R_AddRefEntityToScene( gun );
|
|
}
|
|
else if ( powerups & ( 1 << PW_BEAM_OUT ) || powerups & ( 1 << PW_QUAD ) )
|
|
{
|
|
int btime;
|
|
btime = cg.time - beamData->beamTimeParam;
|
|
|
|
if ( btime <= PLAYER_BEAM_FADE ) {
|
|
if ( powerups & ( 1 << PW_BEAM_OUT ) ) {
|
|
gun->shaderRGBA[3] = 255;
|
|
}
|
|
else {
|
|
gun->shaderRGBA[3] = 0;
|
|
}
|
|
}
|
|
else if ( btime >= ( PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME ) ) {
|
|
if ( powerups & ( 1 << PW_BEAM_OUT ) ) {
|
|
gun->shaderRGBA[3] = 0;
|
|
}
|
|
else {
|
|
gun->shaderRGBA[3] = 255;
|
|
}
|
|
}
|
|
|
|
if (btime > PLAYER_BEAM_FADE && btime < (PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME) )
|
|
{
|
|
gun->renderfx |= RF_FORCE_ENT_ALPHA;
|
|
gun->shaderRGBA[3] = (int)(255 * beamData->beamAlpha);
|
|
}
|
|
|
|
if ( gun->shaderRGBA[3] > 0 ) {
|
|
trap_R_AddRefEntityToScene( gun );
|
|
gun->renderfx &= ~RF_FORCE_ENT_ALPHA;
|
|
gun->shaderRGBA[3] = 255;
|
|
}
|
|
|
|
//Just a precaution. Loop it once, then the player should be invisible
|
|
if ( btime < 4100 ) {
|
|
gun->customShader = cgs.media.transportShader;
|
|
gun->shaderTime = beamData->beamTimeParam * 0.001;
|
|
trap_R_AddRefEntityToScene( gun );
|
|
}
|
|
} else if(powerups & (1 << PW_BORG_ADAPT)) {
|
|
gun->renderfx |= RF_FORCE_ENT_ALPHA;
|
|
gun->shaderRGBA[3] = 255;
|
|
trap_R_AddRefEntityToScene(gun);
|
|
gun->customShader = cgs.media.borgFullBodyShieldShader;
|
|
trap_R_AddRefEntityToScene(gun);
|
|
return;
|
|
}
|
|
else {
|
|
trap_R_AddRefEntityToScene( gun );
|
|
|
|
if(gun->renderfx & RF_FORCE_ENT_ALPHA) {
|
|
gun->renderfx &= ~RF_FORCE_ENT_ALPHA;
|
|
}
|
|
|
|
/* if ( powerups & ( 1 << PW_BOLTON ) ) {
|
|
gun->customShader = cgs.media.battleWeaponShader;
|
|
trap_R_AddRefEntityToScene( gun );
|
|
}*/
|
|
|
|
/* if ( powerups & ( 1 << PW_QUAD ) ) {
|
|
gun->customShader = cgs.media.quadWeaponShader;
|
|
trap_R_AddRefEntityToScene( gun );
|
|
}*/
|
|
/*if (powerups & (1 << PW_OUCH))
|
|
{
|
|
gun->customShader = cgs.media.holoOuchShader;
|
|
// set rgb to 1 of 16 values from 0 to 255. don't use random so that the three
|
|
//parts of the player model as well as the gun will all look the same
|
|
gun->shaderRGBA[0] =
|
|
gun->shaderRGBA[1] =
|
|
gun->shaderRGBA[2] = ((cg.time % 17)*0.0625)*255;//irandom(0,255);
|
|
trap_R_AddRefEntityToScene(gun);
|
|
}*/
|
|
}
|
|
}
|
|
|
|
/*void CG_CoffeeSteamFirstPerson ( refEntity_t* parent, weaponInfo_t *weapon ) {
|
|
refEntity_t steam;
|
|
vec3_t angle = { 0.0, 0.0, 6.0 };
|
|
|
|
CG_PositionEntityOnTag( &steam, parent, weapon->viewModel, "tag_steam1" );
|
|
|
|
if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o
|
|
return;
|
|
}
|
|
|
|
//CG_Steam( steam.origin, angle);
|
|
//Disables the OpenGL Hack where the viewmodel is drawn over EVERYTHING ELSE INCLUDING THE STEAM
|
|
parent->renderfx &= ~RF_DEPTHHACK;
|
|
|
|
if (cg.time % 10 == 0 ) {
|
|
FX_AddSprite( steam.origin,
|
|
angle, qfalse,
|
|
( random() * 3 + 1), (10), //random() * 4 + 2 //12
|
|
0.6 + random() * 0.4, 0.0,
|
|
random() * 120, //180
|
|
0.0,
|
|
1300, //300 //random() * 200 + 1200, //300 //
|
|
cgs.media.steamShader );
|
|
}
|
|
localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale,
|
|
float startalpha, float endalpha, float roll, float elasticity,
|
|
float killTime, qhandle_t shader)*/
|
|
|
|
//if (
|
|
/*}
|
|
|
|
void CG_CoffeeSteamThirdPerson ( refEntity_t* parent, weaponInfo_t *weapon) {
|
|
refEntity_t steam;
|
|
localEntity_t *le = NULL;
|
|
|
|
vec3_t angle = { 0.0, 0.0, 6.0 };
|
|
|
|
CG_PositionEntityOnTag( &steam, parent, weapon->weaponModel, "tag_steam");
|
|
|
|
if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o
|
|
return;
|
|
}
|
|
|
|
if (cg.time % 10 == 0 ) {
|
|
le = FX_AddSprite( steam.origin,
|
|
angle, qfalse,
|
|
( random() * 1.2 + 0.5), ( 5 ), //random() * 4 + 2 //12
|
|
0.6 + random() * 0.4, 0.0,
|
|
random() * 120, //180
|
|
0.0,
|
|
1300, //300 //random() * 200 + 1200, //300 //
|
|
cgs.media.steamShader );
|
|
}
|
|
localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale,
|
|
float startalpha, float endalpha, float roll, float elasticity,
|
|
float killTime, qhandle_t shader)*/
|
|
|
|
//if (
|
|
//}*/
|
|
|
|
void CG_CoffeeSteam( refEntity_t* parent, weaponInfo_t *weapon, qboolean thirdperson ) {
|
|
refEntity_t steam;
|
|
localEntity_t *le;
|
|
|
|
vec3_t angle = { 0.0, 0.0, 10.0 };
|
|
|
|
//FIXME: I probably should name the tag the same thing in both models... O_o
|
|
if ( !thirdperson ) {
|
|
CG_PositionEntityOnTag( &steam, parent, weapon->viewModel, "tag_steam1" );
|
|
}
|
|
else {
|
|
CG_PositionEntityOnTag( &steam, parent, weapon->weaponModel, "tag_steam");
|
|
}
|
|
|
|
if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o
|
|
return;
|
|
}
|
|
|
|
//CG_Steam( steam.origin, angle);
|
|
//Disables the OpenGL Hack where the viewmodel is drawn over EVERYTHING ELSE INCLUDING THE STEAM
|
|
parent->renderfx &= ~RF_DEPTHHACK;
|
|
|
|
if (cg.time % 10 == 0 ) { //release a sprite every .01 of a second
|
|
le = FX_AddSprite( steam.origin,
|
|
angle, qfalse,
|
|
( thirdperson ? random() * 1.2 + 0.5 : random() * 1 + 1), ( thirdperson ? 7 : 10), //random() * 4 + 2 //12
|
|
0.05 + random() * 0.1, 0.0,
|
|
random() * 120, //180
|
|
0.0,
|
|
1500, //300 //random() * 200 + 1200, //300 //
|
|
cgs.media.steamShader );
|
|
}
|
|
/*localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale,
|
|
float startalpha, float endalpha, float roll, float elasticity,
|
|
float killTime, qhandle_t shader)*/
|
|
//Without this, the steam gets drawn behind the cup... which looks weird
|
|
//le->refEntity.renderfx |= RF_DEPTHHACK;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
getClassColor
|
|
|
|
RPG-X : TiM - used to determine what color skins the weapons should have applied to them
|
|
My way of having to not have to enter in so many conditionals over and over
|
|
=============
|
|
*/
|
|
|
|
//char *getClassColor ( void )
|
|
//{
|
|
// /*if (( cg.snap->ps.persistant[PERS_CLASS] == PC_SECURITY )
|
|
// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_ENGINEER))
|
|
// {
|
|
// return "default";
|
|
// }
|
|
//
|
|
// if (( cg.snap->ps.persistant[PERS_CLASS] == PC_SCIENCE )
|
|
// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_MEDICAL )
|
|
// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_ALPHAOMEGA22 ))
|
|
// {
|
|
// return "teal";
|
|
// }
|
|
//
|
|
// if ((cg.snap->ps.persistant[PERS_CLASS] == PC_COMMAND)
|
|
// || (cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN))
|
|
// {
|
|
// return "red";
|
|
// }
|
|
// if ( cg.snap->ps.persistant[PERS_CLASS] == PC_NOCLASS ) {
|
|
// return "NULL";
|
|
// }*/
|
|
//
|
|
// //lolz... this time, let's base it off of current model
|
|
// //rather than class
|
|
// cgs.clientinfo[0].
|
|
//
|
|
// return "default";
|
|
//}
|
|
|
|
|
|
/*
|
|
=============
|
|
CG_AddPlayerWeapon
|
|
|
|
Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
|
|
The main player will have this called for BOTH cases, so effects like light and
|
|
sound should only be done on the world model case.
|
|
=============
|
|
*/
|
|
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) {
|
|
refEntity_t gun;
|
|
refEntity_t barrel;
|
|
refEntity_t flash;
|
|
vec3_t angles;
|
|
weapon_t weaponNum;
|
|
weaponInfo_t *weapon;
|
|
centity_t *nonPredictedCent;
|
|
int i = 0, numBarrels = 0;
|
|
wpnBarrelInfo_t *barrelInfo = NULL;
|
|
|
|
char filename[MAX_QPATH];
|
|
char* skinColor;
|
|
|
|
weaponNum = cent->currentState.weapon;
|
|
|
|
CG_RegisterWeapon( weaponNum );
|
|
weapon = &cg_weapons[weaponNum];
|
|
|
|
// add the weapon
|
|
memset( &gun, 0, sizeof( gun ) );
|
|
VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
|
|
gun.shadowPlane = parent->shadowPlane;
|
|
gun.renderfx = parent->renderfx;
|
|
|
|
// set custom shading for railgun refire rate
|
|
/*if ( ps ) {
|
|
if ( cg.predictedPlayerState.weapon == WP_NULL_HAND
|
|
&& cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
|
|
float f;
|
|
|
|
f = (float)cg.predictedPlayerState.weaponTime / 1500;
|
|
gun.shaderRGBA[1] = 0;
|
|
gun.shaderRGBA[0] =
|
|
gun.shaderRGBA[2] = 255 * ( 1.0 - f );
|
|
} else {
|
|
gun.shaderRGBA[0] = 255;
|
|
gun.shaderRGBA[1] = 255;
|
|
gun.shaderRGBA[2] = 255;
|
|
gun.shaderRGBA[3] = 255;
|
|
}
|
|
}*/
|
|
|
|
if (ps)
|
|
{
|
|
qhandle_t skin;
|
|
|
|
gun.hModel = weapon->viewModel;
|
|
|
|
skinColor = cgs.clientinfo[cg.snap->ps.clientNum].skinName;
|
|
|
|
//if ( skinColor != "NULL" ) { //RPG-X : TiM - Will change the color of the band on the viewmodel's arm, depending what class
|
|
if(!Q_stricmpn(skinColor, "NULL", 4)) {
|
|
for ( i = 0; i < 8; i++ ) {
|
|
if ( cg.predictedPlayerState.weapon == (RAweapons[i]) ) {
|
|
Com_sprintf( filename, sizeof( filename ),"models/weapons2/%s/model_%s.skin", RAweapFileName[i], skinColor ); //Formulate the skin route
|
|
|
|
skin = trap_R_RegisterSkin ( filename );
|
|
|
|
if ( !skin )
|
|
break;
|
|
|
|
gun.customSkin = skin; //and 'plonk' it on the model :)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
gun.hModel = weapon->weaponModel;
|
|
}
|
|
|
|
if (!gun.hModel) {
|
|
return;
|
|
}
|
|
|
|
if ( !ps ) {
|
|
// add weapon stop sound
|
|
if ( !( cent->currentState.eFlags & EF_FIRING ) && !( cent->currentState.eFlags & EF_ALT_FIRING ) && cent->pe.lightningFiring &&
|
|
cg.predictedPlayerState.ammo[cg.predictedPlayerState.weapon] )
|
|
{
|
|
if (weapon->stopSound)
|
|
{
|
|
trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_WEAPON, weapon->stopSound );
|
|
}
|
|
else if (weapon->altStopSound )
|
|
{
|
|
trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_WEAPON, weapon->altStopSound );
|
|
}
|
|
}
|
|
cent->pe.lightningFiring = qfalse;
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
{
|
|
// hark, I smell hackery afoot
|
|
if ((weaponNum == WP_PHASER) && !(cg.predictedPlayerState.ammo[WP_PHASER]))
|
|
{
|
|
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.phaserEmptySound );
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
else if ( weapon->altFiringSound && !weapon->isAnimSndBased )
|
|
{
|
|
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->altFiringSound );
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
|
|
if ( weaponNum == WP_TOOLKIT || weaponNum == WP_MEDKIT ) {
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
}
|
|
else if ( cent->currentState.eFlags & EF_FIRING )
|
|
{
|
|
if ((weaponNum == WP_PHASER) && !(cg.predictedPlayerState.ammo[WP_PHASER]))
|
|
{
|
|
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.phaserEmptySound );
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
else if ( weapon->firingSound && !weapon->isAnimSndBased )
|
|
{
|
|
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
|
|
//TiM: Haxxor. I want the medkit + toolkit sounds to play only once when u hold them down
|
|
if ( weaponNum == WP_TOOLKIT || weaponNum == WP_MEDKIT ) {
|
|
cent->pe.lightningFiring = qtrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
|
|
//RPG-X : TiM - A little variety here :) Toolkit gets attached to player model's left hand, medkit on waist :)
|
|
//Hack: I dunno why, but unless I specified thirdperson (ie (!ps) ), the viewmodel went crazy. :P
|
|
if (!ps) {
|
|
if (( weaponNum == WP_TOOLKIT ) ) { //Toolkit //cg.predictedPlayerState.weapon
|
|
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_lhand");
|
|
}
|
|
else if (( weaponNum == WP_MEDKIT ) ) { //Medkit
|
|
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_torso");
|
|
}
|
|
/*else {
|
|
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
|
|
}*/
|
|
//TiM: also in the hopes of keeping the weapon scale constant in contrast to the player model
|
|
gun.nonNormalizedAxes = qfalse;
|
|
}
|
|
|
|
if ( weaponNum == WP_COFFEE ) {
|
|
if ( !ps ) {
|
|
if ( !(!cg.renderingThirdPerson && cent->currentState.clientNum == cg.predictedPlayerState.clientNum) )
|
|
CG_CoffeeSteam( &gun, weapon, qtrue );
|
|
}
|
|
//else {
|
|
// CG_CoffeeSteam( &gun, weapon, qfalse );
|
|
//}
|
|
}
|
|
|
|
CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups, ¢->beamData, cent->cloakTime, cent->decloakTime );
|
|
|
|
// add the spinning barrel
|
|
//
|
|
//
|
|
for (barrelInfo = wpnBarrelData; barrelInfo->giTag != WP_NONE; barrelInfo++)
|
|
{
|
|
if (barrelInfo->giTag == weaponNum)
|
|
{
|
|
numBarrels = barrelInfo->numBarrels;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// don't add barrels to world model...only viewmodels
|
|
if (ps)
|
|
{
|
|
for (i = 0; i < numBarrels; i++)
|
|
{
|
|
memset( &barrel, 0, sizeof( barrel ) );
|
|
VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
|
|
barrel.shadowPlane = parent->shadowPlane;
|
|
barrel.renderfx = parent->renderfx;
|
|
|
|
barrel.hModel = weapon->barrelModel[i];
|
|
angles[YAW] = 0;
|
|
angles[PITCH] = 0;
|
|
if ( weaponNum == WP_TR116) {
|
|
angles[ROLL] = CG_MachinegunSpinAngle( cent );
|
|
} else {
|
|
angles[ROLL] = 0;//CG_MachinegunSpinAngle( cent );
|
|
}
|
|
AnglesToAxis( angles, barrel.axis );
|
|
|
|
if (!i) {
|
|
CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" );
|
|
} else {
|
|
CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, va("tag_barrel%d",i+1) );
|
|
}
|
|
|
|
CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups, ¢->beamData, cent->cloakTime, cent->decloakTime );
|
|
}
|
|
}
|
|
|
|
// make sure we aren't looking at cg.predictedPlayerEntity for LG
|
|
nonPredictedCent = &cg_entities[cent->currentState.clientNum];
|
|
|
|
// if the index of the nonPredictedCent is not the same as the clientNum
|
|
// then this is a fake player (like on teh single player podiums), so
|
|
// go ahead and use the cent
|
|
if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
|
|
nonPredictedCent = cent;
|
|
}
|
|
|
|
//Com_Printf("eType: %i, eventParm: %i, weaponNum: %i\n", cent->currentState.eType, cent->currentState.eventParm, weaponNum);
|
|
if ( weaponNum == WP_COMPRESSION_RIFLE
|
|
&&
|
|
cent->currentState.powerups & ( 1 << PW_FLASHLIGHT )
|
|
&&
|
|
cent->beamData.beamTimeParam == 0
|
|
&&
|
|
( !(cent->currentState.powerups & ( 1 << PW_INVIS ))
|
|
|| cent->currentState.clientNum == cg.predictedPlayerState.clientNum )
|
|
)
|
|
{ //FIXME: TiM - need to know if flashlight is on or off at the time :S
|
|
refEntity_t flashlight;
|
|
|
|
memset( &flashlight, 0, sizeof( flashlight ) );
|
|
VectorCopy( parent->lightingOrigin, flashlight.lightingOrigin );
|
|
flashlight.shadowPlane = parent->shadowPlane;
|
|
flashlight.renderfx = parent->renderfx;
|
|
|
|
flashlight.hModel = cgs.media.flashlightModel;
|
|
if (!flashlight.hModel) {
|
|
return;
|
|
}
|
|
|
|
angles[YAW] = 0;
|
|
angles[PITCH] = 0;
|
|
angles[ROLL] = 0;
|
|
|
|
AnglesToAxis( angles, flashlight.axis );
|
|
|
|
if (ps)
|
|
{ // Rendering inside the head...
|
|
CG_PositionRotatedEntityOnTag( &flashlight, &gun, weapon->viewModel, "tag_flashlight");
|
|
}
|
|
else
|
|
{ // Rendering outside the head...
|
|
CG_PositionRotatedEntityOnTag( &flashlight, &gun, weapon->weaponModel, "tag_flashlight");
|
|
}
|
|
trap_R_AddRefEntityToScene( &flashlight );
|
|
}
|
|
|
|
// add the flash
|
|
if ( ( weaponNum == WP_PHASER ||
|
|
weaponNum == WP_DERMAL_REGEN)
|
|
&& ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
|
|
{
|
|
// continuous flash
|
|
}
|
|
else
|
|
{
|
|
// impulse flash
|
|
//if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME) {
|
|
if ( cg.time - cent->muzzleFlashTime > wpnBarrelData[weaponNum-1].flashTime )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
memset( &flash, 0, sizeof( flash ) );
|
|
VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
|
|
flash.shadowPlane = parent->shadowPlane;
|
|
flash.renderfx = parent->renderfx;
|
|
|
|
flash.hModel = weapon->flashModel;
|
|
if (!flash.hModel) {
|
|
return;
|
|
}
|
|
|
|
angles[YAW] = 0;
|
|
angles[PITCH] = 0;
|
|
angles[ROLL] = 0; //angles[ROLL] = crandom() * 10; //RPG-X - TiM: This stops the lensflare on the muzzle from jiggling around
|
|
|
|
AnglesToAxis( angles, flash.axis );
|
|
|
|
//TiM - Instead of briefly showing the flash, show it scaling down
|
|
if (weaponNum != WP_PHASER &&
|
|
weaponNum != WP_HYPERSPANNER &&
|
|
weaponNum != WP_DERMAL_REGEN &&
|
|
!(weaponNum == WP_COMPRESSION_RIFLE && (cent->currentState.eFlags & EF_ALT_FIRING) ) &&
|
|
!(weaponNum == WP_DISRUPTOR && !(cent->currentState.eFlags & EF_ALT_FIRING) )
|
|
)
|
|
{
|
|
float scale;
|
|
scale = (1.0f - ( (float)(cg.time - cent->muzzleFlashTime) / (float)wpnBarrelData[weaponNum-1].flashTime )) * 2.0f;
|
|
|
|
flash.nonNormalizedAxes = qtrue;
|
|
VectorScale( flash.axis[0], scale, flash.axis[0] );
|
|
VectorScale( flash.axis[1], scale, flash.axis[1] );
|
|
VectorScale( flash.axis[2], scale, flash.axis[2] );
|
|
}
|
|
|
|
//TiM - quick hack
|
|
//jiggle the scale of the phaser rifle on alt fire around
|
|
if ( (weaponNum == WP_COMPRESSION_RIFLE && (cent->currentState.eFlags & EF_ALT_FIRING))
|
|
||
|
|
( weaponNum == WP_DISRUPTOR && !(cent->currentState.eFlags & EF_ALT_FIRING)) )
|
|
{
|
|
float min, max;
|
|
|
|
if ( weaponNum == WP_COMPRESSION_RIFLE )
|
|
{
|
|
min = 1.3f;
|
|
max = 1.6f;
|
|
}
|
|
else
|
|
{
|
|
min = 0.8f;
|
|
max = 0.9f;
|
|
}
|
|
|
|
VectorScale( flash.axis[0], flrandom(min, max), flash.axis[0] );
|
|
VectorScale( flash.axis[1], flrandom(min, max), flash.axis[1] );
|
|
VectorScale( flash.axis[2], flrandom(min, max), flash.axis[2] );
|
|
}
|
|
|
|
if (cent->pe.empty)
|
|
{ // Make muzzle flash wussy when empty.
|
|
flash.customShader = cgs.media.phaserMuzzleEmptyShader;
|
|
}
|
|
|
|
if (ps)
|
|
{ // Rendering inside the head...
|
|
CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->viewModel, "tag_flash" );
|
|
}
|
|
else
|
|
{ // Rendering outside the head...
|
|
CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" );
|
|
}
|
|
|
|
if ( !(cent->currentState.powerups & ( 1 << PW_INVIS ))
|
|
|| cent->currentState.clientNum == cg.predictedPlayerState.clientNum )
|
|
{
|
|
trap_R_AddRefEntityToScene( &flash );
|
|
}
|
|
|
|
if ( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum || cg_firstPersonBody.integer )
|
|
{
|
|
// add phaser/dreadnought
|
|
// grrr nonPredictedCent doesn't have the proper empty setting
|
|
nonPredictedCent->pe.empty = cent->pe.empty;
|
|
CG_LightningBolt( nonPredictedCent, flash.origin );
|
|
|
|
// make a dlight for the flash
|
|
if ( (weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2]) && !(cent->currentState.powerups & ( 1 << PW_INVIS ) ) ) {
|
|
trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), weapon->flashDlightColor[0],
|
|
weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
CG_AddViewWeapon
|
|
|
|
Add the weapon, and flash for the player's view
|
|
==============
|
|
*/
|
|
void CG_AddViewWeapon( playerState_t *ps ) {
|
|
refEntity_t hand;
|
|
centity_t *cent;
|
|
clientInfo_t *ci;
|
|
float fovOffset;
|
|
vec3_t angles;
|
|
weaponInfo_t *weapon;
|
|
|
|
if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (ps->eFlags&EF_ELIMINATED)*/ ) {
|
|
return;
|
|
}
|
|
|
|
if ( ps->pm_type == PM_INTERMISSION ) {
|
|
return;
|
|
}
|
|
|
|
// no gun if in third person view
|
|
if ( cg.renderingThirdPerson || cg_firstPersonBody.integer ) {
|
|
return;
|
|
}
|
|
|
|
// allow the gun to be completely removed
|
|
//TiM: Added alt fire for alt-fire beam weapons
|
|
if ( !cg_drawGun.integer || cg.zoomed ) {
|
|
vec3_t origin;
|
|
|
|
if ( cg.predictedPlayerState.eFlags & EF_FIRING || cg.predictedPlayerState.eFlags & EF_ALT_FIRING )
|
|
{
|
|
// special hack for phaser/dreadnought...
|
|
VectorCopy( cg.refdef.vieworg, origin );
|
|
VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
|
|
CG_LightningBolt( &cg_entities[ps->clientNum], origin );
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( (cg.zoomed) && (ps->weapon == WP_COMPRESSION_RIFLE) ) { //RPG-X : TiM - People were saying that being able to see the gunsight on the rifle thru the gunsight in zoom mode was weird :P
|
|
return;
|
|
}
|
|
|
|
// don't draw if testing a gun model
|
|
if ( cg.testGun ) {
|
|
return;
|
|
}
|
|
|
|
// drop gun lower at higher fov
|
|
if ( cg_fov.integer > 80 ) {
|
|
fovOffset = -0.2 * ( cg_fov.integer - 80 );
|
|
} else {
|
|
fovOffset = 0;
|
|
}
|
|
|
|
cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
|
|
CG_RegisterWeapon( ps->weapon );
|
|
weapon = &cg_weapons[ ps->weapon ];
|
|
|
|
memset (&hand, 0, sizeof(hand));
|
|
|
|
// set up gun position
|
|
CG_CalculateWeaponPosition( hand.origin, angles );
|
|
|
|
VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
|
|
VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
|
|
VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
|
|
|
|
AnglesToAxis( angles, hand.axis );
|
|
|
|
// map torso animations to weapon animations
|
|
if ( cg_gun_frame.integer ) {
|
|
// development tool
|
|
hand.frame = hand.oldframe = cg_gun_frame.integer;
|
|
hand.backlerp = 0;
|
|
} else {
|
|
// get clientinfo for animation map
|
|
ci = &cgs.clientinfo[ cent->currentState.clientNum ];
|
|
hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
|
|
hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
|
|
hand.backlerp = cent->pe.torso.backlerp;
|
|
}
|
|
|
|
hand.hModel = weapon->handsModel;
|
|
hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON;
|
|
|
|
// add everything onto the hand
|
|
CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity );
|
|
}
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
WEAPON SELECTION
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
void static CG_RegisterWeaponIcon( int weaponNum ) {
|
|
weaponInfo_t *weaponInfo;
|
|
gitem_t *item;
|
|
|
|
weaponInfo = &cg_weapons[weaponNum];
|
|
|
|
if ( weaponNum == 0 ) {
|
|
return;
|
|
}
|
|
|
|
if ( weaponInfo->registered ) {
|
|
return;
|
|
}
|
|
|
|
for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
|
|
if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
|
|
weaponInfo->item = item;
|
|
break;
|
|
}
|
|
}
|
|
if ( !item->classname ) {
|
|
CG_Error( "Couldn't find weapon %i", weaponNum );
|
|
}
|
|
|
|
weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CG_DrawWeaponIcon
|
|
RPG-X | Phenix | 08/06/2005
|
|
RPG-X | TiM | 5/1/2006
|
|
===========================
|
|
*/
|
|
void CG_DrawWeaponIcon ( int x, int y, int weapon )
|
|
{
|
|
/*vec4_t color;
|
|
|
|
color[3] = alpha;
|
|
if ( !color[3] ) {
|
|
return;
|
|
}*/
|
|
|
|
CG_RegisterWeaponIcon( weapon ); //short version
|
|
|
|
// draw selection marker
|
|
|
|
if ( weapon == cg.weaponSelect )
|
|
{
|
|
trap_R_SetColor( colorTable[CT_LTPURPLE1] );
|
|
}
|
|
else
|
|
{
|
|
trap_R_SetColor(colorTable[CT_DKPURPLE1]);
|
|
}
|
|
|
|
CG_DrawPic( x-4,y-4,38, 38, cgs.media.weaponbox);
|
|
|
|
// draw weapon icon
|
|
trap_R_SetColor(colorTable[CT_WHITE]);
|
|
CG_DrawPic( x, y, 32, 32, cg_weapons[weapon].weaponIcon );
|
|
|
|
// draw selection marker
|
|
/*if ( weapon == cg.weaponSelect ) {
|
|
CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );*/
|
|
//}
|
|
trap_R_SetColor( NULL );
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_DrawWeaponSelect
|
|
===================
|
|
*/
|
|
|
|
static int weaponRows[6][3] = { { WP_NULL_HAND, 0, 0 },
|
|
{ WP_TRICORDER, WP_PADD, WP_COFFEE },
|
|
{ WP_PHASER, WP_COMPRESSION_RIFLE, WP_TR116 },
|
|
{ WP_GRENADE_LAUNCHER, WP_QUANTUM_BURST, WP_DISRUPTOR },
|
|
{ WP_MEDKIT, WP_VOYAGER_HYPO, WP_DERMAL_REGEN },
|
|
{ WP_TOOLKIT, WP_HYPERSPANNER, 0 } };
|
|
|
|
void CG_DrawWeaponSelect( void ) {
|
|
int i, rowCount, cellCount;
|
|
int bits;
|
|
//int count;
|
|
int x, y, w, defaultX, defaultY;
|
|
char *name;
|
|
float *color;
|
|
qboolean WeapOnThisRow = qfalse;
|
|
//vec4_t color;
|
|
|
|
// don't display if dead
|
|
if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 1 || cg.predictedPlayerState.eFlags & EF_DEAD ) { //RPG-X: RedTechie - No weapons at health 1 (you die at health 1 now)
|
|
return;
|
|
}
|
|
|
|
color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
|
|
if ( !color ) {
|
|
return;
|
|
}
|
|
|
|
// showing weapon select clears pickup item display, but not the blend blob
|
|
cg.itemPickupTime = 0;
|
|
|
|
// count the number of weapons owned
|
|
bits = cg.snap->ps.stats[ STAT_WEAPONS ];
|
|
|
|
//NEW HUD FOR RPG-X
|
|
defaultX = 18;
|
|
defaultY = 52;
|
|
x = defaultX;
|
|
|
|
y = (BIGCHAR_HEIGHT * 2) + 20;
|
|
|
|
for ( i = 0, rowCount = 0, cellCount = 0; i < MAX_WEAPONS; i++, cellCount++ ) {
|
|
if ( cellCount == 3 ) { //we've hit the end of the row
|
|
rowCount++; //go to the next row
|
|
cellCount = 0; //reset cell clock
|
|
|
|
if ( WeapOnThisRow ) {
|
|
//**** Draw the end caps *****
|
|
//VectorCopy( colorTable[CT_LTPURPLE2], color );
|
|
trap_R_SetColor(colorTable[CT_LTPURPLE2]);
|
|
// Left end cap
|
|
CG_DrawPic( 2, y - 5, 16, 50, cgs.media.weaponcap1); //6
|
|
// Right End Cap
|
|
CG_DrawPic( x - 20 + 16, y - 5, 16, 50, cgs.media.weaponcap2); //2 - 6, 16 - 18
|
|
trap_R_SetColor(NULL);
|
|
|
|
y += defaultY;
|
|
x = defaultX;
|
|
|
|
WeapOnThisRow = qfalse;
|
|
}
|
|
|
|
if ( rowCount >= 6 ) { //if we exceed our rows, that's bad O_o
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( weaponRows[rowCount][cellCount] == 0 ) {
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
if (bits & ( 1 << weaponRows[rowCount][cellCount] ) ) {
|
|
CG_DrawWeaponIcon( x, y, weaponRows[rowCount][cellCount] );
|
|
x += 40;
|
|
|
|
if ( !WeapOnThisRow ) {
|
|
WeapOnThisRow = qtrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// END HUD
|
|
|
|
// draw the selected names
|
|
if ( cg_weapons[ cg.weaponSelect ].item ) {
|
|
name = cg_weapons[ cg.weaponSelect ].item->pickup_name;
|
|
if ( name ) {
|
|
w= UI_ProportionalStringWidth(name,UI_SMALLFONT);
|
|
UI_DrawProportionalString(x, y, name, UI_SMALLFONT,color);
|
|
|
|
}
|
|
}
|
|
|
|
trap_R_SetColor( NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CG_WeaponSelectable
|
|
===============
|
|
*/
|
|
static qboolean CG_WeaponSelectable( int i ) {
|
|
if ( !cg.snap->ps.ammo[i] ) {
|
|
return qfalse;
|
|
}
|
|
if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
extern int altAmmoUsage[];
|
|
/*
|
|
{
|
|
0, //WP_NONE,
|
|
2, //WP_PHASER,
|
|
10, //WP_COMPRESSION_RIFLE,
|
|
3, //WP_NULL_HAND,
|
|
5, //WP_COFFEE,
|
|
1, //WP_DISRUPTOR,
|
|
1, //WP_GRENADE_LAUNCHER,
|
|
2, //WP_TR116,
|
|
2, //WP_QUANTUM_BURST,
|
|
5 //WP_DERMAL_REGEN,
|
|
20, //WP_VOYAGER_HYPO,
|
|
##, //WP_TOOLKIT,
|
|
##, //WP_MEDKIT,
|
|
|
|
};
|
|
*/
|
|
|
|
/*
|
|
===============
|
|
CG_WeaponAltSelectable
|
|
===============
|
|
*/
|
|
static qboolean CG_WeaponAltSelectable( int i ) {
|
|
if ( cg.snap->ps.ammo[i] < altAmmoUsage[cg.snap->ps.weapon]) {
|
|
return qfalse;
|
|
}
|
|
if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CG_NextWeapon_f
|
|
===============
|
|
*/
|
|
void CG_NextWeapon_f( void ) {
|
|
int i; //, topWeapon
|
|
int original;
|
|
// int newWeapons[16];
|
|
// int bits;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
|
|
cg.weaponSelectTime = cg.time;
|
|
original = cg.weaponSelect;
|
|
|
|
|
|
//RPG-X | Phenix | 08/06/2005
|
|
//Removed to be replaced to scroll through our list
|
|
//TiM | 4/1/2006
|
|
//Put back in since I optimized the way weapons are handled
|
|
for ( i = 0 ; i < 16 ; i++ ) {
|
|
cg.weaponSelect++;
|
|
if ( cg.weaponSelect == 16 ) {
|
|
cg.weaponSelect = 0;
|
|
}
|
|
if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
|
|
break;
|
|
}
|
|
}
|
|
if ( i == 16 ) {
|
|
cg.weaponSelect = original;
|
|
}
|
|
|
|
//TiM: Just for the record. Phenix. Enumerated value lists. Look them up. Use them!
|
|
//Reading this code was really tricky when it didn't have to be >.<
|
|
//ie 1 = WP_PHASER etc
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_PrevWeapon_f
|
|
===============
|
|
*/
|
|
void CG_PrevWeapon_f( void ) {
|
|
int i; //, topWeapon
|
|
int original;
|
|
// int newWeapons[16];
|
|
// int bits;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
|
|
cg.weaponSelectTime = cg.time;
|
|
original = cg.weaponSelect;
|
|
|
|
//RPG-X | Phenix | 08/06/2005
|
|
//Removed to be replaced to scroll through our list
|
|
//TiM | 4/1/2006
|
|
//Put back in since I optimized the way weapons are handled
|
|
for ( i = 0 ; i < 16 ; i++ ) {
|
|
cg.weaponSelect--;
|
|
if ( cg.weaponSelect == -1 ) {
|
|
cg.weaponSelect = 15;
|
|
}
|
|
if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
|
|
break;
|
|
}
|
|
}
|
|
if ( i == 16 ) {
|
|
cg.weaponSelect = original;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_Weapon_f
|
|
===============
|
|
*/
|
|
/*TiM : Here for reference
|
|
static int weaponRows[6][3] = { WP_NULL_HAND, 0, 0,
|
|
WP_TRICORDER, WP_PADD, WP_COFFEE,
|
|
WP_PHASER, WP_COMPRESSION_RIFLE, WP_TR116,
|
|
WP_GRENADE_LAUNCHER, WP_QUANTUM_BURST, WP_DISRUPTOR,
|
|
WP_MEDKIT, WP_VOYAGER_HYPO, WP_DERMAL_REGEN,
|
|
WP_TOOLKIT, WP_NEUTRINO_PROBE, 0 };*/
|
|
|
|
void CG_Weapon_f( void ) {
|
|
int num;
|
|
//int newWeapons[16];
|
|
int i;
|
|
int bits;
|
|
int weaponsOnRow;
|
|
int weaponGot[6];
|
|
int onRow;
|
|
int onCol;
|
|
int rowsUsed;
|
|
int currentWeaponCol;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
|
|
num = atoi( CG_Argv( 1 ) );
|
|
bits = cg.snap->ps.stats[ STAT_WEAPONS ];
|
|
|
|
//TiM - 0 = Null hand weapon now
|
|
//if ( num < 1 || num > 15 ) {
|
|
if ( num < 0 || num > 15 ) {
|
|
return;
|
|
}
|
|
|
|
cg.weaponSelectTime = cg.time;
|
|
|
|
//Hacky Override: 0 = Null hand no matter what.
|
|
if (num == 0 ) {
|
|
if ( bits & ( 1 << WP_NULL_HAND ) ) {
|
|
cg.weaponSelect = WP_NULL_HAND;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//TiM : The code below went into an infinite loop if a high number was
|
|
//set as an arg to this command.
|
|
//Lemme just insert a check to make sure the code NEVER accepts args higher
|
|
//than the size of our weapons array. I'll put it underneath the weaponSelectTime
|
|
//statement, so the user will still see a response to their input.
|
|
else if ( num > 5 ) {
|
|
return;
|
|
}
|
|
|
|
/* RPG-X | Phenix | 02/02/2006
|
|
*
|
|
* Code to group weapons together by keyboard */
|
|
|
|
//Init weaponGot values
|
|
/*for (i = 0; i < 6; i++)
|
|
weaponGot[i] = -1;*/
|
|
memset( weaponGot, -1, sizeof( weaponGot ) );
|
|
|
|
onCol = 0;
|
|
weaponsOnRow = 0;
|
|
rowsUsed = 0;
|
|
currentWeaponCol = -1;
|
|
|
|
//Loop though every weapon in weaponRows (starting on row 2 - WHY TIM WHY!)
|
|
//TiM: ... because :)
|
|
for ( i = 0, onRow = 1; i < 15; i++ )
|
|
{
|
|
if (onCol == 3)
|
|
{
|
|
onCol = 0;
|
|
weaponsOnRow = 0;
|
|
onRow++;
|
|
|
|
if (onRow > 5) //Something has gone wrong!
|
|
break;
|
|
}
|
|
|
|
if ( weaponRows[onRow][onCol] > 0)
|
|
{ //Double check this is a weapon
|
|
if (( bits & ( 1 << weaponRows[onRow][onCol] ) ) && (weaponsOnRow == 0))
|
|
{ //If we have this weapon And it is the first weapon on this row we have
|
|
weaponGot[rowsUsed] = onRow;
|
|
weaponsOnRow++;
|
|
rowsUsed++;
|
|
}
|
|
|
|
if ((cg.predictedPlayerState.weapon == weaponRows[onRow][onCol]) && (rowsUsed == num))
|
|
{ //If this is the selected weapon record what column it is on
|
|
currentWeaponCol = onCol;
|
|
}
|
|
}
|
|
|
|
onCol++;
|
|
}
|
|
|
|
//If they selected a row that doesn't exist
|
|
if (weaponGot[num - 1] == -1)
|
|
return; //(dont need to worry about num being zero because of tims hack ^^)
|
|
|
|
do
|
|
{ //Loop though this row until we come accross a weapon which the player has got and is not "null" (0)
|
|
currentWeaponCol++;
|
|
|
|
if (currentWeaponCol == 3)
|
|
{
|
|
currentWeaponCol = 0;
|
|
}
|
|
} while ((weaponRows[ weaponGot[num - 1] ][currentWeaponCol] == 0) || !( bits & ( 1 << weaponRows[weaponGot[num - 1]][currentWeaponCol] )));
|
|
|
|
cg.weaponSelect = weaponRows[weaponGot[num - 1]][currentWeaponCol];
|
|
|
|
//TiM - based on the number we pressed, and whichever
|
|
//weapons we have in sequential order, select the one that corresponds.
|
|
|
|
//Start at number 2, skipping null hand. He owns us all
|
|
/*for ( i = WP_TRICORDER, weaponCount = 0; i < MAX_WEAPONS; i++ ) {
|
|
//if we have that weapon
|
|
if ( bits & ( 1 << i ) ) {
|
|
weaponCount++;
|
|
|
|
if ( weaponCount == num ) {
|
|
cg.weaponSelect = i;
|
|
return;
|
|
}
|
|
}
|
|
}*/
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_OutOfAmmoChange
|
|
|
|
The current weapon has just run out of ammo
|
|
===================
|
|
*/
|
|
void CG_OutOfAmmoChange( qboolean altfire ) {
|
|
int i;
|
|
|
|
cg.weaponSelectTime = cg.time;
|
|
|
|
for ( i = 15 ; i > 0 ; i-- )
|
|
{
|
|
if (altfire)
|
|
{
|
|
if ( CG_WeaponAltSelectable( i ) )
|
|
{
|
|
cg.weaponSelect = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( CG_WeaponSelectable( i ) )
|
|
{
|
|
cg.weaponSelect = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===================================================================================================
|
|
|
|
WEAPON EVENTS
|
|
|
|
===================================================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
CG_FireWeapon
|
|
|
|
Caused by an EV_FIRE_WEAPON event
|
|
================
|
|
*/
|
|
int tris_state = 0;
|
|
void CG_FireWeapon( centity_t *cent, qboolean alt_fire ) {
|
|
entityState_t *ent;
|
|
weaponInfo_t *weap;
|
|
int rpg_effectsgun;
|
|
int rpg_tripmines;
|
|
const char *info;
|
|
//const char *info2;
|
|
|
|
ent = ¢->currentState;
|
|
if ( ent->weapon == WP_NONE || ent->weapon == WP_NULL_HAND ) {
|
|
return;
|
|
}
|
|
if ( ent->weapon >= WP_NUM_WEAPONS ) {
|
|
CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
|
|
return;
|
|
}
|
|
weap = &cg_weapons[ ent->weapon ];
|
|
|
|
// mark the entity as muzzle flashing, so when it is added it will
|
|
// append the flash to the weapon model
|
|
cent->muzzleFlashTime = cg.time;
|
|
|
|
// lightning gun only does this this on initial press
|
|
if ( ent->weapon == WP_PHASER /*||
|
|
ent->weapon == WP_DERMAL_REGEN*/
|
|
|| ent->weapon == WP_TOOLKIT
|
|
|| ent->weapon == WP_MEDKIT
|
|
|| (!(cent->currentState.eFlags & EF_ALT_FIRING) && ent->weapon == WP_DISRUPTOR )
|
|
|| (cent->currentState.eFlags & EF_ALT_FIRING && ent->weapon == WP_COMPRESSION_RIFLE )
|
|
)
|
|
{
|
|
if ( cent->pe.lightningFiring ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// play quad sound if needed
|
|
/* if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
|
|
trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
|
|
}*/
|
|
|
|
// play a sound
|
|
info = CG_ConfigString( CS_SERVERINFO );
|
|
rpg_tripmines = atoi( Info_ValueForKey( info, "rpg_invisibletripmines" ) );
|
|
rpg_effectsgun = atoi( Info_ValueForKey( info, "rpg_effectsgun" ) );
|
|
if (alt_fire)
|
|
{
|
|
//RPG-X: RedTechie - Wrong place for show tris
|
|
/*if( ent->weapon == WP_TR116 )
|
|
{
|
|
if(tris_state == 1)
|
|
tris_state = 0;
|
|
else
|
|
tris_state = 1;
|
|
|
|
trap_Cvar_Set("r_showtris", va("%i",tris_state));
|
|
}*/
|
|
if ( weap->altFlashSnd )
|
|
{
|
|
//TiM : Hark, I smell hackery again
|
|
//admin alt hypos no fire coz it grinds my teeth
|
|
if ( cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cgs.clientinfo[cent->currentState.clientNum].pClass == PC_ADMIN*/
|
|
&&
|
|
cent->currentState.weapon == WP_VOYAGER_HYPO ) {
|
|
return;
|
|
}
|
|
|
|
if(ent->weapon == WP_GRENADE_LAUNCHER){
|
|
if(rpg_tripmines != 1){
|
|
trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSnd );
|
|
}
|
|
}else{
|
|
trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSnd );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( weap->flashSound )
|
|
{
|
|
if(ent->weapon == WP_GRENADE_LAUNCHER){
|
|
if((rpg_effectsgun == 1) || (rpg_tripmines == 1)){
|
|
return;
|
|
}else{
|
|
trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound );
|
|
}
|
|
}else{
|
|
trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
CG_FireSeeker
|
|
|
|
Caused by an EV_FIRE_WEAPON event
|
|
================
|
|
*/
|
|
void CG_FireSeeker( centity_t *cent )
|
|
{
|
|
entityState_t *ent;
|
|
weaponInfo_t *weap;
|
|
|
|
ent = ¢->currentState;
|
|
weap = &cg_weapons[ WP_COFFEE ];
|
|
|
|
trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CG_MissileHitWall
|
|
|
|
Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
|
|
=================
|
|
*/
|
|
void CG_MissileHitWall( centity_t *cent, int weapon, vec3_t origin, vec3_t dir )
|
|
{
|
|
qhandle_t mod;
|
|
qhandle_t mark;
|
|
qhandle_t shader;
|
|
sfxHandle_t sfx;
|
|
float radius;
|
|
float light;
|
|
vec3_t lightColor;
|
|
localEntity_t *le;
|
|
qboolean isSprite;
|
|
int duration;
|
|
qboolean alphaFade;
|
|
// weaponInfo_t *weaponInfo = &cg_weapons[weapon];
|
|
|
|
mark = 0;
|
|
radius = 32;
|
|
sfx = 0;
|
|
mod = 0;
|
|
shader = 0;
|
|
light = 0;
|
|
lightColor[0] = 1;
|
|
lightColor[1] = 1;
|
|
lightColor[2] = 0;
|
|
|
|
// set defaults
|
|
isSprite = qfalse;
|
|
duration = 600;
|
|
|
|
switch ( weapon ) {
|
|
default:
|
|
case WP_PHASER:
|
|
// no explosion at LG impact, it is added with the beam
|
|
mark = cgs.media.holeMarkShader;
|
|
radius = 12;
|
|
break;
|
|
case WP_DERMAL_REGEN:
|
|
// no explosion at LG impact, it is added with the beam
|
|
mark = cgs.media.holeMarkShader;
|
|
radius = 12;
|
|
break;
|
|
case WP_GRENADE_LAUNCHER:
|
|
FX_GrenadeExplode( origin, dir );
|
|
return;
|
|
break;
|
|
case WP_DISRUPTOR:
|
|
FX_DisruptorWeaponHitWall( origin, dir, 2 ); //cent->currentState.time2
|
|
return;
|
|
break;
|
|
case WP_NULL_HAND:
|
|
/*mod = cgs.media.ringFlashModel;
|
|
shader = cgs.media.imodExplosionShader;
|
|
mark = cgs.media.energyMarkShader;
|
|
radius = 24;*/
|
|
break;
|
|
case WP_COMPRESSION_RIFLE:
|
|
//mod = cgs.media.ringFlashModel;
|
|
//shader = cgs.media.imodExplosionShader;
|
|
//mark = cgs.media.energyMarkShader;
|
|
//radius = 24;
|
|
FX_CompressionExplosion( cent->lerpOrigin, origin, dir, qfalse );
|
|
return;
|
|
break;
|
|
case WP_TR116:
|
|
//FX_TetrionAltHitWall( origin, dir );
|
|
return;
|
|
break;
|
|
/* case WP_COFFEE:
|
|
if (cent->currentState.eFlags & EF_ALT_FIRING)
|
|
{
|
|
FX_ScavengerAltExplode( origin, dir );
|
|
}
|
|
else
|
|
{
|
|
FX_ScavengerWeaponHitWall( origin, dir, qfalse );
|
|
}
|
|
return;
|
|
break;*/
|
|
/* case WP_MEDKIT:
|
|
if ( !( cent->currentState.eFlags & EF_ALT_FIRING ))
|
|
{
|
|
FX_BorgWeaponHitWall( origin, dir );
|
|
}
|
|
return;
|
|
break;*/
|
|
|
|
case WP_QUANTUM_BURST:
|
|
if ( cent->currentState.eFlags & EF_ALT_FIRING )
|
|
{
|
|
FX_QuantumAltHitWall( origin, dir );
|
|
}
|
|
else
|
|
{
|
|
FX_QuantumHitWall( origin, dir );
|
|
}
|
|
return;
|
|
break;
|
|
}
|
|
|
|
if ( sfx ) {
|
|
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
|
|
}
|
|
|
|
//
|
|
// create the explosion
|
|
//
|
|
if ( mod ) {
|
|
le = CG_MakeExplosion( origin, dir,
|
|
mod, shader,
|
|
duration, 1, isSprite );
|
|
le->light = light;
|
|
VectorCopy( lightColor, le->lightColor );
|
|
}
|
|
|
|
//
|
|
// impact mark
|
|
//
|
|
alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
|
|
CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CG_MissileHitPlayer
|
|
=================
|
|
*/
|
|
void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir)
|
|
{
|
|
if (cent)
|
|
{ // Showing blood is a no-no.
|
|
|
|
// CG_Bleed( origin, cent->currentState.otherEntityNum );
|
|
}
|
|
|
|
CG_MissileHitWall( cent, weapon, origin, dir );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CG_BounceEffect
|
|
|
|
Caused by an EV_BOUNCE | EV_BOUNCE_HALF event
|
|
=================
|
|
*/
|
|
|
|
// big fixme. none of these sounds should be registered at runtime
|
|
void CG_BounceEffect( centity_t *cent, int weapon, vec3_t origin, vec3_t normal )
|
|
{
|
|
int rpg_tripmines;
|
|
const char *info;
|
|
|
|
switch( weapon )
|
|
{
|
|
case WP_GRENADE_LAUNCHER:
|
|
info = CG_ConfigString( CS_SERVERINFO );
|
|
rpg_tripmines = atoi( Info_ValueForKey( info, "rpg_invisibletripmines" ) );
|
|
if(rpg_tripmines != 1){
|
|
if ( rand() & 1 ) {
|
|
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav") );
|
|
} else {
|
|
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav") );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WP_TR116:
|
|
//trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound ( va(SOUND_DIR "tetrion/ricochet%d.wav", irandom(1, 3)) ) );
|
|
//FX_TetrionRicochet( origin, normal );
|
|
break;
|
|
|
|
default:
|
|
if ( rand() & 1 ) {
|
|
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav") );
|
|
} else {
|
|
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav") );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
============================================================================
|
|
|
|
BULLETS
|
|
|
|
============================================================================
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
======================
|
|
CG_CalcMuzzlePoint
|
|
======================
|
|
*/
|
|
|
|
extern qboolean PM_PlayerCrouching ( int legsAnim );
|
|
|
|
qboolean CG_CalcMuzzlePoint( centity_t *cent, vec3_t muzzle, qboolean isDecoy ) {
|
|
vec3_t forward;
|
|
//centity_t *cent;
|
|
int anim;
|
|
|
|
/*if ( entityNum == cg.snap->ps.clientNum && !isDecoy ) {
|
|
VectorCopy( cg.snap->ps.origin, muzzle );
|
|
muzzle[2] += cg.snap->ps.viewheight;
|
|
AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
|
|
VectorMA( muzzle, 14, forward, muzzle );
|
|
return qtrue;
|
|
}*/
|
|
|
|
//cent = &cg_entities[entityNum];
|
|
if ( !cent->currentValid ) {
|
|
return qfalse;
|
|
}
|
|
|
|
//if ( !isDecoy )
|
|
VectorCopy( cent->currentState.pos.trBase, muzzle );
|
|
//else
|
|
// VectorCopy( cent->currentState.origin, muzzle );
|
|
|
|
AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
|
|
anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
|
|
if ( PM_PlayerCrouching( cent->currentState.legsAnim ) ) {
|
|
muzzle[2] += CROUCH_VIEWHEIGHT;
|
|
} else {
|
|
muzzle[2] += DEFAULT_VIEWHEIGHT;
|
|
}
|
|
|
|
VectorMA( muzzle, 14, forward, muzzle );
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
CG_SurfaceExplosion
|
|
|
|
Adds an explosion to a surface
|
|
================
|
|
*/
|
|
|
|
#define NUM_SPARKS 12
|
|
#define NUM_PUFFS 1
|
|
#define NUM_EXPLOSIONS 4
|
|
|
|
void CG_SurfaceExplosion( vec3_t origin, vec3_t normal, float radius, float shake_speed, qboolean smoke )
|
|
{
|
|
localEntity_t *le;
|
|
vec3_t direction, new_org;
|
|
vec3_t sprayvel, velocity = { 0, 0, 0 };
|
|
vec3_t temp_org, temp_vel;
|
|
float scale, dscale;
|
|
int i, numSparks;
|
|
|
|
//Sparks
|
|
|
|
numSparks = 32 + (random() * 16.0f);
|
|
|
|
//VectorSet( normal, 0, 0, 1 );
|
|
|
|
for ( i = 0; i < numSparks; i++ )
|
|
{
|
|
scale = 0.25f + (random() * 2.0f);
|
|
dscale = -scale*0.5;
|
|
|
|
FXE_Spray( normal, 500, 150, 1.0f, sprayvel);
|
|
|
|
FX_AddTrail( origin,
|
|
sprayvel,
|
|
qtrue,
|
|
32.0f,
|
|
-64.0f,
|
|
scale,
|
|
-scale,
|
|
1.0f,
|
|
0.0f,
|
|
0.25f,
|
|
4000.0f,
|
|
cgs.media.sparkShader);
|
|
}
|
|
|
|
//Smoke
|
|
|
|
//Move this out a little from the impact surface
|
|
VectorMA( origin, 4, normal, new_org );
|
|
VectorSet( velocity, 0.0f, 0.0f, 16.0f );
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
VectorSet( temp_org, new_org[0] + (crandom() * 16.0f), new_org[1] + (crandom() * 16.0f), new_org[2] + (random() * 4.0f) );
|
|
VectorSet( temp_vel, velocity[0] + (crandom() * 8.0f), velocity[1] + (crandom() * 8.0f), velocity[2] + (crandom() * 8.0f) );
|
|
|
|
FX_AddSprite( temp_org,
|
|
temp_vel,
|
|
qfalse,
|
|
radius /**96.0f*/ + (random() * 12.0f),
|
|
16.0f,
|
|
1.0f,
|
|
0.0f,
|
|
20.0f + (crandom() * 90.0f),
|
|
0.5f,
|
|
2000.0f,
|
|
cgs.media.smokeShader);
|
|
}
|
|
|
|
//Core of the explosion
|
|
|
|
//Orient the explosions to face the camera
|
|
VectorSubtract( cg.refdef.vieworg, origin, direction );
|
|
VectorNormalize( direction );
|
|
|
|
//Tag the last one with a light
|
|
le = CG_MakeExplosion2( origin, direction, cgs.media.explosionModel, 5, cgs.media.surfaceExplosionShader,
|
|
500, qfalse, radius * 0.02f + (random() * 0.3f), LEF_NONE);
|
|
le->light = 150;
|
|
VectorSet( le->lightColor, 0.9f, 0.8f, 0.5f );
|
|
|
|
for ( i = 0; i < NUM_EXPLOSIONS-1; i ++)
|
|
{
|
|
VectorSet( new_org, (origin[0] + (32 + (crandom() * 8))*crandom()), (origin[1] + (32 + (crandom() * 8))*crandom()), (origin[2] + (32 + (crandom() * 8))*crandom()) );
|
|
le = CG_MakeExplosion2( new_org, direction, cgs.media.explosionModel, 5, cgs.media.surfaceExplosionShader,
|
|
300 + (rand() & 99), qfalse, radius * 0.05f + (crandom() *0.3f), LEF_NONE);
|
|
}
|
|
|
|
//Shake the camera
|
|
CG_ExplosionEffects( origin, shake_speed, 350 );
|
|
|
|
}
|
|
|
|
void CG_PlayShooterSound(centity_t *cent) {
|
|
weaponInfo_t *weap;
|
|
|
|
weap = &cg_weapons[cent->currentState.eventParm];
|
|
|
|
switch(cent->currentState.eventParm) {
|
|
case WP_COMPRESSION_RIFLE:
|
|
case WP_GRENADE_LAUNCHER:
|
|
case WP_QUANTUM_BURST:
|
|
trap_S_StartSound(cent->currentState.origin, cent->currentState.number, CHAN_VOICE, weap->flashSound);
|
|
break;
|
|
case WP_DISRUPTOR:
|
|
trap_S_StartSound(cent->currentState.origin, cent->currentState.number, CHAN_VOICE, weap->altFlashSnd);
|
|
break;
|
|
}
|
|
}
|