1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- Quake III Arena source code is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- //
- // cg_weapons.c -- events and effects dealing with weapons
- #include "cg_local.h"
- /*
- ==========================
- CG_MachineGunEjectBrass
- ==========================
- */
- static void CG_MachineGunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[3];
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- velocity[0] = 0;
- velocity[1] = -50 + 40 * crandom();
- velocity[2] = 100 + 50 * crandom();
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - (rand()&15);
- AnglesToAxis( cent->lerpAngles, v );
- offset[0] = 8;
- offset[1] = -4;
- offset[2] = 24;
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.machinegunBrassModel;
- le->bounceFactor = 0.4 * waterScale;
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 2;
- le->angles.trDelta[1] = 1;
- le->angles.trDelta[2] = 0;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
- }
- /*
- ==========================
- CG_ShotgunEjectBrass
- ==========================
- */
- static void CG_ShotgunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int i;
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
- for ( i = 0; i < 2; i++ ) {
- float waterScale = 1.0f;
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- velocity[0] = 60 + 60 * crandom();
- if ( i == 0 ) {
- velocity[1] = 40 + 10 * crandom();
- } else {
- velocity[1] = -40 + 10 * crandom();
- }
- velocity[2] = 100 + 50 * crandom();
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
- AnglesToAxis( cent->lerpAngles, v );
- offset[0] = 8;
- offset[1] = 0;
- offset[2] = 24;
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.shotgunBrassModel;
- le->bounceFactor = 0.3f;
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
- }
- }
- #ifdef MISSIONPACK
- /*
- ==========================
- CG_NailgunEjectBrass
- ==========================
- */
- static void CG_NailgunEjectBrass( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- vec3_t v[3];
- vec3_t offset;
- vec3_t xoffset;
- vec3_t up;
- AnglesToAxis( cent->lerpAngles, v );
- offset[0] = 0;
- offset[1] = -12;
- offset[2] = 24;
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, origin );
- VectorSet( up, 0, 0, 64 );
- smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
- #endif
- /*
- ==========================
- CG_RailTrail
- ==========================
- */
- void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
- vec3_t axis[36], move, move2, next_move, vec, temp;
- float len;
- int i, j, skip;
-
- localEntity_t *le;
- refEntity_t *re;
-
- #define RADIUS 4
- #define ROTATION 1
- #define SPACING 5
-
- start[2] -= 4;
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
- PerpendicularVector(temp, vec);
- for (i = 0 ; i < 36; i++) {
- RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
- }
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + cg_railTrailTime.value;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_RAIL_CORE;
- re->customShader = cgs.media.railCoreShader;
-
- VectorCopy(start, re->origin);
- VectorCopy(end, re->oldorigin);
-
- re->shaderRGBA[0] = ci->color1[0] * 255;
- re->shaderRGBA[1] = ci->color1[1] * 255;
- re->shaderRGBA[2] = ci->color1[2] * 255;
- re->shaderRGBA[3] = 255;
- le->color[0] = ci->color1[0] * 0.75;
- le->color[1] = ci->color1[1] * 0.75;
- le->color[2] = ci->color1[2] * 0.75;
- le->color[3] = 1.0f;
- AxisClear( re->axis );
-
- VectorMA(move, 20, vec, move);
- VectorCopy(move, next_move);
- VectorScale (vec, SPACING, vec);
- if (cg_oldRail.integer != 0) {
- // nudge down a bit so it isn't exactly in center
- re->origin[2] -= 8;
- re->oldorigin[2] -= 8;
- return;
- }
- skip = -1;
-
- j = 18;
- for (i = 0; i < len; i += SPACING) {
- if (i != skip) {
- skip = i + SPACING;
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + (i>>1) + 600;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 1.1f;
- re->customShader = cgs.media.railRingsShader;
- re->shaderRGBA[0] = ci->color2[0] * 255;
- re->shaderRGBA[1] = ci->color2[1] * 255;
- re->shaderRGBA[2] = ci->color2[2] * 255;
- re->shaderRGBA[3] = 255;
- le->color[0] = ci->color2[0] * 0.75;
- le->color[1] = ci->color2[1] * 0.75;
- le->color[2] = ci->color2[2] * 0.75;
- le->color[3] = 1.0f;
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
- VectorCopy( move, move2);
- VectorMA(move2, RADIUS , axis[j], move2);
- VectorCopy(move2, le->pos.trBase);
- le->pos.trDelta[0] = axis[j][0]*6;
- le->pos.trDelta[1] = axis[j][1]*6;
- le->pos.trDelta[2] = axis[j][2]*6;
- }
- VectorAdd (move, vec, move);
- j = j + ROTATION < 36 ? j + ROTATION : (j + ROTATION) % 36;
- }
- }
- /*
- ==========================
- CG_RocketTrail
- ==========================
- */
- static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
- step = 50;
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
- ent->trailTime = cg.time;
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
- }
- #ifdef MISSIONPACK
- /*
- ==========================
- CG_NailTrail
- ==========================
- */
- static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
- step = 50;
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
- ent->trailTime = cg.time;
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.nailPuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
- }
- #endif
- /*
- ==========================
- CG_NailTrail
- ==========================
- */
- static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
- localEntity_t *le;
- refEntity_t *re;
- entityState_t *es;
- vec3_t velocity, xvelocity, origin;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int t, startTime, step;
- float waterScale = 1.0f;
- if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
- return;
- }
- step = 50;
- es = ¢->currentState;
- startTime = cent->trailTime;
- t = step * ( (startTime + step) / step );
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- velocity[0] = 60 - 120 * crandom();
- velocity[1] = 40 - 80 * crandom();
- velocity[2] = 100 - 200 * crandom();
- le->leType = LE_MOVE_SCALE_FADE;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_NONE;
- le->leMarkType = LEMT_NONE;
- le->startTime = cg.time;
- le->endTime = le->startTime + 600;
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
- AnglesToAxis( cent->lerpAngles, v );
- offset[0] = 2;
- offset[1] = 2;
- offset[2] = 2;
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( origin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
- AxisCopy( axisDefault, re->axis );
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 0.25f;
- re->customShader = cgs.media.railRingsShader;
- le->bounceFactor = 0.3f;
- re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
- re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
- re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
- re->shaderRGBA[3] = 63;
- le->color[0] = wi->flashDlightColor[0] * 0.2;
- le->color[1] = wi->flashDlightColor[1] * 0.2;
- le->color[2] = wi->flashDlightColor[2] * 0.2;
- le->color[3] = 0.25f;
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
- }
- /*
- ==========================
- CG_GrappleTrail
- ==========================
- */
- void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
- vec3_t origin;
- entityState_t *es;
- vec3_t forward, up;
- refEntity_t beam;
- es = &ent->currentState;
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- ent->trailTime = cg.time;
- memset( &beam, 0, sizeof( beam ) );
- //FIXME adjust for muzzle position
- VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
- beam.origin[2] += 26;
- AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
- VectorMA( beam.origin, -6, up, beam.origin );
- VectorCopy( origin, beam.oldorigin );
- if (Distance( beam.origin, beam.oldorigin ) < 64 )
- return; // Don't draw if close
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- AxisClear( beam.axis );
- beam.shaderRGBA[0] = 0xff;
- beam.shaderRGBA[1] = 0xff;
- beam.shaderRGBA[2] = 0xff;
- beam.shaderRGBA[3] = 0xff;
- trap_R_AddRefEntityToScene( &beam );
- }
- /*
- ==========================
- CG_GrenadeTrail
- ==========================
- */
- static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
- CG_RocketTrail( ent, wi );
- }
- /*
- =================
- CG_RegisterWeapon
- The server says this item is used on this level
- =================
- */
- void CG_RegisterWeapon( int weaponNum ) {
- weaponInfo_t *weaponInfo;
- gitem_t *item, *ammo;
- char path[MAX_QPATH];
- vec3_t mins, maxs;
- int i;
- 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 ) {
- weaponInfo->item = item;
- break;
- }
- }
- if ( !item->classname ) {
- CG_Error( "Couldn't find weapon %i", weaponNum );
- }
- CG_RegisterItemVisuals( item - bg_itemlist );
- // load cmodel before model so filecache works
- weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- // 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 );
- weaponInfo->ammoIcon = 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[0] ) {
- weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
- }
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_flash.md3" );
- weaponInfo->flashModel = trap_R_RegisterModel( path );
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_barrel.md3" );
- weaponInfo->barrelModel = trap_R_RegisterModel( path );
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_hand.md3" );
- weaponInfo->handsModel = trap_R_RegisterModel( path );
- if ( !weaponInfo->handsModel ) {
- weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
- }
- weaponInfo->loopFireSound = qfalse;
- switch ( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
- break;
- case WP_LIGHTNING:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
- cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
- cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
- cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
- cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
- cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
- break;
- case WP_GRAPPLING_HOOK:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileTrailFunc = CG_GrappleTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- break;
- #ifdef MISSIONPACK
- case WP_CHAINGUN:
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
- weaponInfo->loopFireSound = qtrue;
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
- #endif
- case WP_MACHINEGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
- case WP_SHOTGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
- break;
- case WP_ROCKET_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- weaponInfo->missileTrailFunc = CG_RocketTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
-
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
- break;
- #ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
- #endif
- case WP_GRENADE_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
- #ifdef MISSIONPACK
- case WP_NAILGUN:
- weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
- weaponInfo->missileTrailFunc = CG_NailTrail;
- // weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
- weaponInfo->trailRadius = 16;
- weaponInfo->wiTrailTime = 250;
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
- break;
- #endif
- case WP_PLASMAGUN:
- // weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
- weaponInfo->missileTrailFunc = CG_PlasmaTrail;
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
- cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- break;
- case WP_RAILGUN:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
- cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
- break;
- case WP_BFG:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
- cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- break;
- default:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- break;
- }
- }
- /*
- =================
- CG_RegisterItemVisuals
- The server says this item is used on this level
- =================
- */
- void CG_RegisterItemVisuals( int itemNum ) {
- itemInfo_t *itemInfo;
- gitem_t *item;
- if ( itemNum < 0 || itemNum >= bg_numItems ) {
- CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
- }
- itemInfo = &cg_items[ itemNum ];
- if ( itemInfo->registered ) {
- return;
- }
- item = &bg_itemlist[ itemNum ];
- memset( itemInfo, 0, sizeof( &itemInfo ) );
- itemInfo->registered = qtrue;
- itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
- itemInfo->icon = trap_R_RegisterShader( item->icon );
- if ( item->giType == IT_WEAPON ) {
- CG_RegisterWeapon( item->giTag );
- }
- //
- // powerups have an accompanying ring or sphere
- //
- if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
- item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
- if ( item->world_model[1] ) {
- itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
- }
- }
- }
- /*
- ========================================================================================
- VIEW WEAPON
- ========================================================================================
- */
- /*
- =================
- CG_MapTorsoToWeaponFrame
- =================
- */
- static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
- // change weapon
- if ( frame >= ci->animations[TORSO_DROP].firstFrame
- && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
- return frame - ci->animations[TORSO_DROP].firstFrame + 6;
- }
- // stand attack
- if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
- && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
- }
- // stand attack 2
- if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
- && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
- }
-
- return 0;
- }
- /*
- ==============
- CG_CalculateWeaponPosition
- ==============
- */
- 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)
- ===============
- */
- static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
- if (cent->currentState.weapon != WP_LIGHTNING) {
- return;
- }
- memset( &beam, 0, sizeof( beam ) );
- // CPMA "true" lightning
- if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
- vec3_t angle;
- int i;
- for (i = 0; i < 3; i++) {
- float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
- if (a > 180) {
- a -= 360;
- }
- if (a < -180) {
- a += 360;
- }
- angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
- if (angle[i] < 0) {
- angle[i] += 360;
- }
- if (angle[i] > 360) {
- angle[i] -= 360;
- }
- }
- AngleVectors(angle, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
- // VectorCopy(cg.refdef.vieworg, muzzlePoint );
- } else {
- // !CPMA
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
- }
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
- VectorMA( trace.endpos, -16, dir, beam.origin );
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
- }
- /*
- static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
- if ( cent->currentState.weapon != WP_LIGHTNING ) {
- return;
- }
- memset( &beam, 0, sizeof( beam ) );
- // find muzzle point for this frame
- VectorCopy( cent->lerpOrigin, muzzlePoint );
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
- VectorMA( trace.endpos, -16, dir, beam.origin );
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
- }
- */
- /*
- ===============
- CG_SpawnRailTrail
- Origin will be the exact tag point, which is slightly
- different than the muzzle point used for determining hits.
- ===============
- */
- static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
- clientInfo_t *ci;
- if ( cent->currentState.weapon != WP_RAILGUN ) {
- return;
- }
- if ( !cent->pe.railgunFlash ) {
- return;
- }
- cent->pe.railgunFlash = qtrue;
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RailTrail( ci, origin, cent->pe.railgunImpact );
- }
- /*
- ======================
- 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);
- #ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
- }
- #endif
- }
- return angle;
- }
- /*
- ========================
- CG_AddWeaponWithPowerups
- ========================
- */
- static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
- // add powerup effects
- if ( powerups & ( 1 << PW_INVIS ) ) {
- gun->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( gun );
- } else {
- trap_R_AddRefEntityToScene( gun );
- if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
- gun->customShader = cgs.media.battleWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- if ( powerups & ( 1 << PW_QUAD ) ) {
- gun->customShader = cgs.media.quadWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- }
- }
- /*
- =============
- 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, int team ) {
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t angles;
- weapon_t weaponNum;
- weaponInfo_t *weapon;
- centity_t *nonPredictedCent;
- // int col;
- 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_RAILGUN
- && 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;
- }
- }
- gun.hModel = weapon->weaponModel;
- if (!gun.hModel) {
- return;
- }
- if ( !ps ) {
- // add weapon ready sound
- cent->pe.lightningFiring = qfalse;
- if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
- // lightning gun and guantlet make a different sound when fire is held down
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
- cent->pe.lightningFiring = qtrue;
- } else if ( weapon->readySound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
- }
- CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
- CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
- // add the spinning barrel
- if ( weapon->barrelModel ) {
- memset( &barrel, 0, sizeof( barrel ) );
- VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = parent->shadowPlane;
- barrel.renderfx = parent->renderfx;
- barrel.hModel = weapon->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = CG_MachinegunSpinAngle( cent );
- AnglesToAxis( angles, barrel.axis );
- CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
- CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
- }
- // 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;
- }
- // add the flash
- if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
- && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
- {
- // continuous flash
- } else {
- // impulse flash
- if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
- 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] = crandom() * 10;
- AnglesToAxis( angles, flash.axis );
- // colorize the railgun blast
- if ( weaponNum == WP_RAILGUN ) {
- clientInfo_t *ci;
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- flash.shaderRGBA[0] = 255 * ci->color1[0];
- flash.shaderRGBA[1] = 255 * ci->color1[1];
- flash.shaderRGBA[2] = 255 * ci->color1[2];
- }
- CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
- trap_R_AddRefEntityToScene( &flash );
- if ( ps || cg.renderingThirdPerson ||
- cent->currentState.number != cg.predictedPlayerState.clientNum ) {
- // add lightning bolt
- CG_LightningBolt( nonPredictedCent, flash.origin );
- // add rail trail
- CG_SpawnRailTrail( cent, flash.origin );
- if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 300 + (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 ) {
- return;
- }
- if ( ps->pm_type == PM_INTERMISSION ) {
- return;
- }
- // no gun if in third person view or a camera is active
- //if ( cg.renderingThirdPerson || cg.cameraMode) {
- if ( cg.renderingThirdPerson ) {
- return;
- }
- // allow the gun to be completely removed
- if ( !cg_drawGun.integer ) {
- vec3_t origin;
- if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
- // special hack for lightning gun...
- VectorCopy( cg.refdef.vieworg, origin );
- VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
- CG_LightningBolt( &cg_entities[ps->clientNum], origin );
- }
- return;
- }
- // don't draw if testing a gun model
- if ( cg.testGun ) {
- return;
- }
- // drop gun lower at higher fov
- if ( cg_fov.integer > 90 ) {
- fovOffset = -0.2 * ( cg_fov.integer - 90 );
- } 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 | RF_MINLIGHT;
- // add everything onto the hand
- CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
- }
- /*
- ==============================================================================
- WEAPON SELECTION
- ==============================================================================
- */
- /*
- ===================
- CG_DrawWeaponSelect
- ===================
- */
- void CG_DrawWeaponSelect( void ) {
- int i;
- int bits;
- int count;
- int x, y, w;
- char *name;
- float *color;
- // don't display if dead
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
- color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
- if ( !color ) {
- return;
- }
- trap_R_SetColor( color );
- // 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 ];
- count = 0;
- for ( i = 1 ; i < 16 ; i++ ) {
- if ( bits & ( 1 << i ) ) {
- count++;
- }
- }
- x = 320 - count * 20;
- y = 380;
- for ( i = 1 ; i < 16 ; i++ ) {
- if ( !( bits & ( 1 << i ) ) ) {
- continue;
- }
- CG_RegisterWeapon( i );
- // draw weapon icon
- CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
- // draw selection marker
- if ( i == cg.weaponSelect ) {
- CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
- }
- // no ammo cross on top
- if ( !cg.snap->ps.ammo[ i ] ) {
- CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
- }
- x += 40;
- }
- // draw the selected name
- if ( cg_weapons[ cg.weaponSelect ].item ) {
- name = cg_weapons[ cg.weaponSelect ].item->pickup_name;
- if ( name ) {
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- CG_DrawBigStringColor(x, y - 22, name, 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;
- }
- /*
- ===============
- CG_NextWeapon_f
- ===============
- */
- void CG_NextWeapon_f( void ) {
- int i;
- int original;
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
- for ( i = 0 ; i < 16 ; i++ ) {
- cg.weaponSelect++;
- if ( cg.weaponSelect == 16 ) {
- cg.weaponSelect = 0;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == 16 ) {
- cg.weaponSelect = original;
- }
- }
- /*
- ===============
- CG_PrevWeapon_f
- ===============
- */
- void CG_PrevWeapon_f( void ) {
- int i;
- int original;
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
- for ( i = 0 ; i < 16 ; i++ ) {
- cg.weaponSelect--;
- if ( cg.weaponSelect == -1 ) {
- cg.weaponSelect = 15;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == 16 ) {
- cg.weaponSelect = original;
- }
- }
- /*
- ===============
- CG_Weapon_f
- ===============
- */
- void CG_Weapon_f( void ) {
- int num;
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
- num = atoi( CG_Argv( 1 ) );
- if ( num < 1 || num > 15 ) {
- return;
- }
- cg.weaponSelectTime = cg.time;
- if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
- return; // don't have the weapon
- }
- cg.weaponSelect = num;
- }
- /*
- ===================
- CG_OutOfAmmoChange
- The current weapon has just run out of ammo
- ===================
- */
- void CG_OutOfAmmoChange( void ) {
- int i;
- cg.weaponSelectTime = cg.time;
- for ( i = 15 ; i > 0 ; i-- ) {
- if ( CG_WeaponSelectable( i ) ) {
- cg.weaponSelect = i;
- break;
- }
- }
- }
- /*
- ===================================================================================================
- WEAPON EVENTS
- ===================================================================================================
- */
- /*
- ================
- CG_FireWeapon
- Caused by an EV_FIRE_WEAPON event
- ================
- */
- void CG_FireWeapon( centity_t *cent ) {
- entityState_t *ent;
- int c;
- weaponInfo_t *weap;
- ent = ¢->currentState;
- if ( ent->weapon == WP_NONE ) {
- 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_LIGHTNING ) {
- 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
- for ( c = 0 ; c < 4 ; c++ ) {
- if ( !weap->flashSound[c] ) {
- break;
- }
- }
- if ( c > 0 ) {
- c = rand() % c;
- if ( weap->flashSound[c] )
- {
- trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
- }
- }
- // do brass ejection
- if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
- weap->ejectBrassFunc( cent );
- }
- }
- /*
- =================
- CG_MissileHitWall
- Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
- =================
- */
- void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
- qhandle_t mod;
- qhandle_t mark;
- qhandle_t shader;
- sfxHandle_t sfx;
- float radius;
- float light;
- vec3_t lightColor;
- localEntity_t *le;
- int r;
- qboolean alphaFade;
- qboolean isSprite;
- int duration;
- vec3_t sprOrg;
- vec3_t sprVel;
- 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:
- #ifdef MISSIONPACK
- case WP_NAILGUN:
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_nghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_nghitmetal;
- } else {
- sfx = cgs.media.sfx_nghit;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
- #endif
- case WP_LIGHTNING:
- // no explosion at LG impact, it is added with the beam
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_lghit2;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_lghit1;
- } else {
- sfx = cgs.media.sfx_lghit3;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
- #ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_proxexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
- #endif
- case WP_GRENADE_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
- case WP_ROCKET_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.rocketExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- duration = 1000;
- lightColor[0] = 1;
- lightColor[1] = 0.75;
- lightColor[2] = 0.0;
- if (cg_oldRocket.integer == 0) {
- // explosion sprite animation
- VectorMA( origin, 24, dir, sprOrg );
- VectorScale( dir, 64, sprVel );
- CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
- }
- break;
- case WP_RAILGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.railExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 24;
- break;
- case WP_PLASMAGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.plasmaExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 16;
- break;
- case WP_BFG:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.bfgExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 32;
- isSprite = qtrue;
- break;
- case WP_SHOTGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- sfx = 0;
- radius = 4;
- break;
- #ifdef MISSIONPACK
- case WP_CHAINGUN:
- mod = cgs.media.bulletFlashModel;
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_chghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_chghitmetal;
- } else {
- sfx = cgs.media.sfx_chghit;
- }
- mark = cgs.media.bulletMarkShader;
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
- radius = 8;
- break;
- #endif
- case WP_MACHINEGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- r = rand() & 3;
- if ( r == 0 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 1 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
- radius = 8;
- 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, isSprite );
- le->light = light;
- VectorCopy( lightColor, le->lightColor );
- if ( weapon == WP_RAILGUN ) {
- // colorize with client color
- VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
- }
- }
- //
- // impact mark
- //
- alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
- if ( weapon == WP_RAILGUN ) {
- float *color;
- // colorize with client color
- color = cgs.clientinfo[clientNum].color2;
- CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
- } else {
- CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
- }
- }
- /*
- =================
- CG_MissileHitPlayer
- =================
- */
- void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
- CG_Bleed( origin, entityNum );
- // some weapons will make an explosion with the blood, while
- // others will just make the blood
- switch ( weapon ) {
- case WP_GRENADE_LAUNCHER:
- case WP_ROCKET_LAUNCHER:
- #ifdef MISSIONPACK
- case WP_NAILGUN:
- case WP_CHAINGUN:
- case WP_PROX_LAUNCHER:
- #endif
- CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
- break;
- default:
- break;
- }
- }
- /*
- ============================================================================
- SHOTGUN TRACING
- ============================================================================
- */
- /*
- ================
- CG_ShotgunPellet
- ================
- */
- static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
- trace_t tr;
- int sourceContentType, destContentType;
- CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( tr.endpos, 0 );
- // FIXME: should probably move this cruft into CG_BubbleTrail
- if ( sourceContentType == destContentType ) {
- if ( sourceContentType & CONTENTS_WATER ) {
- CG_BubbleTrail( start, tr.endpos, 32 );
- }
- } else if ( sourceContentType & CONTENTS_WATER ) {
- trace_t trace;
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- } else if ( destContentType & CONTENTS_WATER ) {
- trace_t trace;
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
- }
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
- if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
- CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
- } else {
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // SURF_NOIMPACT will not make a flame puff or a mark
- return;
- }
- if ( tr.surfaceFlags & SURF_METALSTEPS ) {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
- } else {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
- }
- }
- }
- /*
- ================
- CG_ShotgunPattern
- Perform the same traces the server did to locate the
- hit splashes
- ================
- */
- static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
- CG_ShotgunPellet( origin, end, otherEntNum );
- }
- }
- /*
- ==============
- CG_ShotgunFire
- ==============
- */
- void CG_ShotgunFire( entityState_t *es ) {
- vec3_t v;
- int contents;
- VectorSubtract( es->origin2, es->pos.trBase, v );
- VectorNormalize( v );
- VectorScale( v, 32, v );
- VectorAdd( es->pos.trBase, v, v );
- if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
- // ragepro can't alpha fade, so don't even bother with smoke
- vec3_t up;
- contents = trap_CM_PointContents( es->pos.trBase, 0 );
- if ( !( contents & CONTENTS_WATER ) ) {
- VectorSet( up, 0, 0, 8 );
- CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- }
- }
- CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
- }
- /*
- ============================================================================
- BULLETS
- ============================================================================
- */
- /*
- ===============
- CG_Tracer
- ===============
- */
- void CG_Tracer( vec3_t source, vec3_t dest ) {
- vec3_t forward, right;
- polyVert_t verts[4];
- vec3_t line;
- float len, begin, end;
- vec3_t start, finish;
- vec3_t midpoint;
- // tracer
- VectorSubtract( dest, source, forward );
- len = VectorNormalize( forward );
- // start at least a little ways from the muzzle
- if ( len < 100 ) {
- return;
- }
- begin = 50 + random() * (len - 60);
- end = begin + cg_tracerLength.value;
- if ( end > len ) {
- end = len;
- }
- VectorMA( source, begin, forward, start );
- VectorMA( source, end, forward, finish );
- line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
- line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
- VectorScale( cg.refdef.viewaxis[1], line[1], right );
- VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
- VectorNormalize( right );
- VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
- verts[0].st[0] = 0;
- verts[0].st[1] = 1;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
- VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
- verts[1].st[0] = 1;
- verts[1].st[1] = 0;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
- VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
- VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
- verts[3].st[0] = 0;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
- midpoint[0] = ( start[0] + finish[0] ) * 0.5;
- midpoint[1] = ( start[1] + finish[1] ) * 0.5;
- midpoint[2] = ( start[2] + finish[2] ) * 0.5;
- // add the tracer sound
- trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
- }
- /*
- ======================
- CG_CalcMuzzlePoint
- ======================
- */
- static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
- vec3_t forward;
- centity_t *cent;
- int anim;
- if ( entityNum == cg.snap->ps.clientNum ) {
- 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;
- }
- VectorCopy( cent->currentState.pos.trBase, muzzle );
- AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
- anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
- muzzle[2] += CROUCH_VIEWHEIGHT;
- } else {
- muzzle[2] += DEFAULT_VIEWHEIGHT;
- }
- VectorMA( muzzle, 14, forward, muzzle );
- return qtrue;
- }
- /*
- ======================
- CG_Bullet
- Renders bullet effects.
- ======================
- */
- void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
- trace_t trace;
- int sourceContentType, destContentType;
- vec3_t start;
- // if the shooter is currently valid, calc a source point and possibly
- // do trail effects
- if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
- if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( end, 0 );
- // do a complete bubble trail if necessary
- if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
- CG_BubbleTrail( start, end, 32 );
- }
- // bubble trail from water into air
- else if ( ( sourceContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- }
- // bubble trail from air into water
- else if ( ( destContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( trace.endpos, end, 32 );
- }
- // draw a tracer
- if ( random() < cg_tracerChance.value ) {
- CG_Tracer( start, end );
- }
- }
- }
- // impact splash and mark
- if ( flesh ) {
- CG_Bleed( end, fleshEntityNum );
- } else {
- CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
- }
- }
|