// 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_StasisWeaponHitWall( 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; } }