diff options
Diffstat (limited to 'source/cl_tent.c')
-rw-r--r-- | source/cl_tent.c | 1763 |
1 files changed, 1763 insertions, 0 deletions
diff --git a/source/cl_tent.c b/source/cl_tent.c new file mode 100644 index 0000000..1bef312 --- /dev/null +++ b/source/cl_tent.c @@ -0,0 +1,1763 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program 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. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_tent.c -- client side temporary entities + +#include "cl_local.h" + +typedef enum +{ + ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2, ex_light +} exptype_t; + +typedef struct +{ + exptype_t type; + entity_t ent; + + int frames; + float light; + vec3_t lightcolor; + float start; + int baseframe; +} explosion_t; + + + +#define MAX_EXPLOSIONS 32 +explosion_t cl_explosions[MAX_EXPLOSIONS]; + + +#define MAX_BEAMS 32 +typedef struct +{ + int entity; + int dest_entity; + qhandle_t model; + int endtime; + vec3_t offset; + vec3_t start, end; +} beam_t; +beam_t cl_beams[MAX_BEAMS]; +//PMM - added this for player-linked beams. Currently only used by the plasma beam +beam_t cl_playerbeams[MAX_BEAMS]; + +//ROGUE +cl_sustain_t cl_sustains[MAX_SUSTAINS]; +//ROGUE + +//PGM +extern void CL_TeleportParticles (vec3_t org); +//PGM + +void CL_BlasterParticles (vec3_t org, vec3_t dir); +void CL_ExplosionParticles (vec3_t org); +void CL_BFGExplosionParticles (vec3_t org); +// RAFAEL +void CL_BlueBlasterParticles (vec3_t org, vec3_t dir); + +qhandle_t cl_sfx_ric1; +qhandle_t cl_sfx_ric2; +qhandle_t cl_sfx_ric3; +qhandle_t cl_sfx_lashit; +qhandle_t cl_sfx_spark5; +qhandle_t cl_sfx_spark6; +qhandle_t cl_sfx_spark7; +qhandle_t cl_sfx_railg; +qhandle_t cl_sfx_rockexp; +qhandle_t cl_sfx_grenexp; +qhandle_t cl_sfx_watrexp; +// RAFAEL +qhandle_t cl_sfx_plasexp; +qhandle_t cl_sfx_footsteps[4]; + +qhandle_t cl_mod_explode; +qhandle_t cl_mod_smoke; +qhandle_t cl_mod_flash; +qhandle_t cl_mod_parasite_segment; +qhandle_t cl_mod_grapple_cable; +qhandle_t cl_mod_parasite_tip; +qhandle_t cl_mod_explo4; +qhandle_t cl_mod_bfg_explo; +qhandle_t cl_mod_powerscreen; +// RAFAEL +qhandle_t cl_mod_plasmaexplo; + +//ROGUE +qhandle_t cl_sfx_lightning; +qhandle_t cl_sfx_disrexp; +qhandle_t cl_mod_lightning; +qhandle_t cl_mod_heatbeam; +qhandle_t cl_mod_monster_heatbeam; +qhandle_t cl_mod_explo4_big; + + +#define MAX_LASERS 32 + +laser_t cl_lasers[MAX_LASERS]; + +/* +================= +CL_AllocLaser +================= +*/ +laser_t *CL_AllocLaser( void ) { + laser_t *l; + int i; + + for( i=0, l=cl_lasers ; i<MAX_LASERS ; i++, l++ ) { + if( cl.time - l->startTime >= l->lifeTime ) { + memset( l, 0, sizeof( *l ) ); + l->startTime = cl.time; + return l; + } + } + + return NULL; +} + +/* +================= +CL_AddLasers +================= +*/ +void CL_AddLasers( void ) { + laser_t *l; + entity_t ent; + int i; + color_t color; + int time; + float f; + + memset( &ent, 0, sizeof( ent ) ); + + for( i = 0, l = cl_lasers; i < MAX_LASERS; i++, l++ ) { + time = l->lifeTime - ( cl.time - l->startTime ); + if( time < 0 ) { + continue; + } + + ent.alpha = l->color[3] / 255.0f; + + if( l->fadeType != LASER_FADE_NOT ) { + f = (float)time / (float)l->lifeTime; + + ent.alpha *= f; + if( l->fadeType == LASER_FADE_RGBA ) { + *(int *)color = *(int *)l->color; + color[0] *= f; + color[1] *= f; + color[2] *= f; + ent.skinnum = *(int *)color; + } + } else { + ent.skinnum = *(int *)l->color; + } + + ent.flags = RF_TRANSLUCENT|RF_BEAM; + VectorCopy( l->start, ent.origin ); + VectorCopy( l->end, ent.oldorigin ); + ent.frame = l->width; + ent.lightstyle = !l->indexed; + + V_AddEntity( &ent ); + } +} + +//ROGUE +/* +================= +CL_RegisterTEntSounds +================= +*/ +void CL_RegisterTEntSounds (void) +{ + int i; + char name[MAX_QPATH]; + + // PMM - version stuff +// Com_Printf ("%s\n", ROGUE_VERSION_STRING); + // PMM + cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav"); + cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav"); + cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav"); + cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav"); + cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav"); + cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav"); + cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav"); + cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav"); + cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav"); + cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav"); + cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav"); + // RAFAEL + // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav"); + S_RegisterSound ("player/land1.wav"); + + S_RegisterSound ("player/fall2.wav"); + S_RegisterSound ("player/fall1.wav"); + + for (i=0 ; i<4 ; i++) + { + Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1); + cl_sfx_footsteps[i] = S_RegisterSound (name); + } + +//PGM + cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav"); + cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav"); + // version stuff +// sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID); +// if (name[0] == 'w') +// name[0] = 'W'; +//PGM +} + +/* +================= +CL_RegisterTEntModels +================= +*/ +void CL_RegisterTEntModels (void) +{ + cl_mod_explode = ref.RegisterModel ("models/objects/explode/tris.md2"); + cl_mod_smoke = ref.RegisterModel ("models/objects/smoke/tris.md2"); + cl_mod_flash = ref.RegisterModel ("models/objects/flash/tris.md2"); + cl_mod_parasite_segment = ref.RegisterModel ("models/monsters/parasite/segment/tris.md2"); + cl_mod_grapple_cable = ref.RegisterModel ("models/ctf/segment/tris.md2"); + cl_mod_parasite_tip = ref.RegisterModel ("models/monsters/parasite/tip/tris.md2"); + cl_mod_explo4 = ref.RegisterModel ("models/objects/r_explode/tris.md2"); + cl_mod_bfg_explo = ref.RegisterModel ("sprites/s_bfg2.sp2"); + cl_mod_powerscreen = ref.RegisterModel ("models/items/armor/effect/tris.md2"); + + ref.RegisterModel ("models/objects/laser/tris.md2"); + ref.RegisterModel ("models/objects/grenade2/tris.md2"); + ref.RegisterModel ("models/weapons/v_machn/tris.md2"); + ref.RegisterModel ("models/weapons/v_handgr/tris.md2"); + ref.RegisterModel ("models/weapons/v_shotg2/tris.md2"); + ref.RegisterModel ("models/objects/gibs/bone/tris.md2"); + ref.RegisterModel ("models/objects/gibs/sm_meat/tris.md2"); + ref.RegisterModel ("models/objects/gibs/bone2/tris.md2"); + // RAFAEL + // ref.RegisterModel ("models/objects/blaser/tris.md2"); + + ref.RegisterPic ("w_machinegun"); + ref.RegisterPic ("a_bullets"); + ref.RegisterPic ("i_health"); + ref.RegisterPic ("a_grenades"); + +//ROGUE + cl_mod_explo4_big = ref.RegisterModel ("models/objects/r_explode2/tris.md2"); + cl_mod_lightning = ref.RegisterModel ("models/proj/lightning/tris.md2"); + cl_mod_heatbeam = ref.RegisterModel ("models/proj/beam/tris.md2"); + cl_mod_monster_heatbeam = ref.RegisterModel ("models/proj/widowbeam/tris.md2"); +//ROGUE +} + +/* +================= +CL_ClearTEnts +================= +*/ +void CL_ClearTEnts (void) +{ + memset (cl_beams, 0, sizeof(cl_beams)); + memset (cl_explosions, 0, sizeof(cl_explosions)); + memset (cl_lasers, 0, sizeof(cl_lasers)); + +//ROGUE + memset (cl_playerbeams, 0, sizeof(cl_playerbeams)); + memset (cl_sustains, 0, sizeof(cl_sustains)); +//ROGUE +} + +/* +================= +CL_AllocExplosion +================= +*/ +explosion_t *CL_AllocExplosion (void) +{ + int i; + int time; + int index; + + for (i=0 ; i<MAX_EXPLOSIONS ; i++) + { + if (cl_explosions[i].type == ex_free) + { + memset (&cl_explosions[i], 0, sizeof (cl_explosions[i])); + return &cl_explosions[i]; + } + } +// find the oldest explosion + time = cl.time; + index = 0; + + for (i=0 ; i<MAX_EXPLOSIONS ; i++) + if (cl_explosions[i].start < time) + { + time = cl_explosions[i].start; + index = i; + } + memset (&cl_explosions[index], 0, sizeof (cl_explosions[index])); + return &cl_explosions[index]; +} + +/* +================= +CL_SmokeAndFlash +================= +*/ +void CL_SmokeAndFlash(vec3_t origin) +{ + explosion_t *ex; + + ex = CL_AllocExplosion (); + VectorCopy (origin, ex->ent.origin); + ex->type = ex_misc; + ex->frames = 4; + ex->ent.flags = RF_TRANSLUCENT; + ex->start = cl.serverTime - 100; + ex->ent.model = cl_mod_smoke; + + ex = CL_AllocExplosion (); + VectorCopy (origin, ex->ent.origin); + ex->type = ex_flash; + ex->ent.flags = RF_FULLBRIGHT; + ex->frames = 2; + ex->start = cl.serverTime - 100; + ex->ent.model = cl_mod_flash; +} + +/* +================= +CL_ParseBeam +================= +*/ +static void CL_ParseBeam (qhandle_t model) +{ + int ent; + vec3_t start, end; + beam_t *b; + int i; + + ent = MSG_ReadShort (); + + MSG_ReadPos (start); + MSG_ReadPos (end); + +// override any beam with the same entity + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->entity == ent) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorClear (b->offset); + return; + } + +// find a free beam + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorClear (b->offset); + return; + } + } + +} + +/* +================= +CL_ParseBeam2 +================= +*/ +static void CL_ParseBeam2 (qhandle_t model) +{ + int ent; + vec3_t start, end, offset; + beam_t *b; + int i; + + ent = MSG_ReadShort (); + + MSG_ReadPos (start); + MSG_ReadPos (end); + MSG_ReadPos (offset); + +// override any beam with the same entity + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->entity == ent) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorCopy (offset, b->offset); + return; + } + +// find a free beam + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorCopy (offset, b->offset); + return; + } + } +} + +// ROGUE +/* +================= +CL_ParsePlayerBeam + - adds to the cl_playerbeam array instead of the cl_beams array +================= +*/ +static void CL_ParsePlayerBeam (qhandle_t model) +{ + int ent; + vec3_t start, end, offset; + beam_t *b; + int i; + + ent = MSG_ReadShort (); + + MSG_ReadPos (start); + MSG_ReadPos (end); + // PMM - network optimization + if (model == cl_mod_heatbeam) + VectorSet(offset, 2, 7, -3); + else if (model == cl_mod_monster_heatbeam) + { + model = cl_mod_heatbeam; + VectorSet(offset, 0, 0, 0); + } + else + MSG_ReadPos (offset); + +// override any beam with the same entity +// PMM - For player beams, we only want one per player (entity) so.. + for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) + { + if (b->entity == ent) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorCopy (offset, b->offset); + return; + } + } + +// find a free beam + for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = ent; + b->model = model; + b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorCopy (offset, b->offset); + return; + } + } + +} +//rogue + +/* +================= +CL_ParseLightning +================= +*/ +static void CL_ParseLightning (qhandle_t model) +{ + int srcEnt, destEnt; + vec3_t start, end; + beam_t *b; + int i; + + srcEnt = MSG_ReadShort (); + destEnt = MSG_ReadShort (); + + MSG_ReadPos (start); + MSG_ReadPos (end); + + S_StartSound (NULL, srcEnt, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); + +// override any beam with the same source AND destination entities + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->entity == srcEnt && b->dest_entity == destEnt) + { + b->entity = srcEnt; + b->dest_entity = destEnt; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorClear (b->offset); + return; + } + +// find a free beam + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = srcEnt; + b->dest_entity = destEnt; + b->model = model; + b->endtime = cl.time + 200; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + VectorClear (b->offset); + return; + } + } +} + +/* +================= +CL_ParseLaser +================= +*/ +void CL_ParseLaser( int colors ) { + vec3_t start; + vec3_t end; + laser_t *l; + + MSG_ReadPos( start ); + MSG_ReadPos( end ); + + if( !( l = CL_AllocLaser() ) ) { + return; + } + + VectorCopy( start, l->start ); + VectorCopy( end, l->end ); + l->fadeType = LASER_FADE_NOT; + l->lifeTime = 100; + l->indexed = qtrue; + l->color[0] = ( colors >> ( ( rand() % 4 ) * 8 ) ) & 0xff; + l->color[1] = 0; + l->color[2] = 0; + l->color[3] = 77; + l->width = 4; +} + +//============= +//ROGUE +void CL_ParseSteam (void) +{ + vec3_t pos, dir; + int id, i; + int r; + int cnt; + int color; + int magnitude; + cl_sustain_t *s, *free_sustain; + int time; + + id = MSG_ReadShort (); // an id of -1 is an instant effect + cnt = MSG_ReadByte (); + MSG_ReadPos (pos); + MSG_ReadDir (dir); + r = MSG_ReadByte (); + magnitude = MSG_ReadShort (); + + if( id == -1 ) { + color = r & 0xff; + CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude); + return; + } + + + time = MSG_ReadLong (); // really interval + + // sustains + + free_sustain = NULL; + for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) + { + if (s->id == 0) + { + free_sustain = s; + break; + } + } + if (free_sustain) + { + s->id = id; + s->count = cnt; + VectorCopy( pos, s->org ); + VectorCopy( dir, s->dir ); + s->color = r & 0xff; + s->magnitude = magnitude; + s->endtime = cl.time + time; + s->think = CL_ParticleSteamEffect2; + s->thinkinterval = 100; + s->nextthink = cl.time; + } + + + +} + +void CL_ParseWidow (void) +{ + vec3_t pos; + int id, i; + cl_sustain_t *s, *free_sustain; + + id = MSG_ReadShort (); + + free_sustain = NULL; + for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) + { + if (s->id == 0) + { + free_sustain = s; + break; + } + } + if (free_sustain) + { + s->id = id; + MSG_ReadPos (s->org); + s->endtime = cl.time + 2100; + s->think = CL_Widowbeamout; + s->thinkinterval = 1; + s->nextthink = cl.time; + } + else // no free sustains + { + // FIXME - read the stuff anyway + MSG_ReadPos (pos); + } +} + +void CL_ParseNuke (void) +{ + vec3_t pos; + int i; + cl_sustain_t *s, *free_sustain; + + free_sustain = NULL; + for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) + { + if (s->id == 0) + { + free_sustain = s; + break; + } + } + if (free_sustain) + { + s->id = 21000; + MSG_ReadPos (s->org); + s->endtime = cl.time + 1000; + s->think = CL_Nukeblast; + s->thinkinterval = 1; + s->nextthink = cl.time; + } + else // no free sustains + { + // FIXME - read the stuff anyway + MSG_ReadPos (pos); + } +} + +//ROGUE +//============= + +static explosion_t *CL_RocketExplosion( vec3_t pos, qhandle_t hModel ) { + explosion_t *ex; + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 0.5; + ex->lightcolor[2] = 0.5; + ex->ent.angles[1] = rand() % 360; + ex->ent.model = hModel; + if (frand() < 0.5) + ex->baseframe = 15; + ex->frames = 15; + + return ex; +} + +/* +================= +CL_ParseTEnt +================= +*/ +static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8}; + +void CL_ParseTEnt (void) +{ + int type; + vec3_t pos, pos2, dir; + explosion_t *ex; + int cnt; + int color; + int r; + int ent; + + type = MSG_ReadByte (); + + switch (type) + { + case TE_BLOOD: // bullet hitting flesh + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleEffect (pos, dir, 0xe8, 60); + break; + + case TE_GUNSHOT: // bullet hitting wall + case TE_SPARKS: + case TE_BULLET_SPARKS: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + if (type == TE_GUNSHOT) + CL_ParticleEffect (pos, dir, 0, 40); + else + CL_ParticleEffect (pos, dir, 0xe0, 6); + + if (type != TE_SPARKS) + { + CL_SmokeAndFlash(pos); + + // impact sound + cnt = rand()&15; + if (cnt == 1) + S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0); + else if (cnt == 2) + S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0); + else if (cnt == 3) + S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0); + } + + break; + + case TE_SCREEN_SPARKS: + case TE_SHIELD_SPARKS: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + if (type == TE_SCREEN_SPARKS) + CL_ParticleEffect (pos, dir, 0xd0, 40); + else + CL_ParticleEffect (pos, dir, 0xb0, 40); + //FIXME : replace or remove this sound + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_SHOTGUN: // bullet hitting wall + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleEffect (pos, dir, 0, 20); + CL_SmokeAndFlash(pos); + break; + + case TE_SPLASH: // bullet hitting water + cnt = MSG_ReadByte (); + MSG_ReadPos (pos); + MSG_ReadDir (dir); + r = MSG_ReadByte (); + if (r > 6) + color = 0x00; + else + color = splash_color[r]; + CL_ParticleEffect (pos, dir, color, cnt); + + if (r == SPLASH_SPARKS) + { + r = rand() & 3; + if (r == 0) + S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0); + else if (r == 1) + S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0); + else + S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0); + } + break; + + case TE_LASER_SPARKS: + cnt = MSG_ReadByte (); + MSG_ReadPos (pos); + MSG_ReadDir (dir); + color = MSG_ReadByte (); + CL_ParticleEffect2 (pos, dir, color, cnt); + break; + + // RAFAEL + case TE_BLUEHYPERBLASTER: + MSG_ReadPos (pos); + MSG_ReadPos (dir); + CL_BlasterParticles (pos, dir); + break; + + case TE_BLASTER: // blaster hitting wall + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_BlasterParticles( pos, dir ); + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->ent.angles[0] = acos(dir[2])/M_PI*180; + // PMM - fixed to correct for pitch of 0 + if (dir[0]) + ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180; + else if (dir[1] > 0) + ex->ent.angles[1] = 90; + else if (dir[1] < 0) + ex->ent.angles[1] = 270; + else + ex->ent.angles[1] = 0; + + ex->type = ex_misc; + ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; + ex->start = cl.serverTime - 100; + ex->light = 150; + ex->lightcolor[0] = 1; + ex->lightcolor[1] = 1; + ex->ent.model = cl_mod_explode; + ex->frames = 4; + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_RAILTRAIL: // railgun effect + MSG_ReadPos (pos); + MSG_ReadPos (pos2); + CL_RailTrail (pos, pos2); + S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0); + break; + + case TE_GRENADE_EXPLOSION: + case TE_GRENADE_EXPLOSION_WATER: + MSG_ReadPos( pos ); + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 0.5; + ex->lightcolor[2] = 0.5; + ex->ent.model = cl_mod_explo4; + ex->frames = 19; + ex->baseframe = 30; + ex->ent.angles[1] = rand() % 360; + + if( cl_disable_explosions->integer & NOEXP_GRENADE ) { + ex->type = ex_light; + } + + if( !( cl_disable_particles->integer & NOPART_GRENADE_EXPLOSION ) ) { + CL_ExplosionParticles( pos ); + } + if (type == TE_GRENADE_EXPLOSION_WATER) + S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); + else + S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0); + break; + + case TE_EXPLOSION2: + MSG_ReadPos( pos ); + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 0.5; + ex->lightcolor[2] = 0.5; + ex->ent.model = cl_mod_explo4; + ex->frames = 19; + ex->baseframe = 30; + ex->ent.angles[1] = rand() % 360; + + CL_ExplosionParticles( pos ); + S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0); + break; + + + // RAFAEL + case TE_PLASMA_EXPLOSION: + MSG_ReadPos (pos); + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 0.5; + ex->lightcolor[2] = 0.5; + ex->ent.angles[1] = rand() % 360; + ex->ent.model = cl_mod_explo4; + if (frand() < 0.5) + ex->baseframe = 15; + ex->frames = 15; + CL_ExplosionParticles (pos); + S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); + break; + + case TE_ROCKET_EXPLOSION: + case TE_ROCKET_EXPLOSION_WATER: + MSG_ReadPos( pos ); + + ex = CL_RocketExplosion( pos, cl_mod_explo4 ); + if( cl_disable_explosions->integer & NOEXP_ROCKET ) { + ex->type = ex_light; + } + if( !( cl_disable_particles->integer & NOPART_ROCKET_EXPLOSION ) ) { + CL_ExplosionParticles( pos ); + } + + if( type == TE_ROCKET_EXPLOSION_WATER ) + S_StartSound( pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0 ); + else + S_StartSound( pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0 ); + break; + + case TE_EXPLOSION1: + MSG_ReadPos( pos ); + CL_RocketExplosion( pos, cl_mod_explo4 ); + CL_ExplosionParticles( pos ); + S_StartSound( pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0 ); + break; + + case TE_EXPLOSION1_NP: // PMM + MSG_ReadPos( pos ); + CL_RocketExplosion( pos, cl_mod_explo4 ); + S_StartSound( pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0 ); + break; + + case TE_EXPLOSION1_BIG: // PMM + MSG_ReadPos( pos ); + CL_RocketExplosion( pos, cl_mod_explo4_big ); + S_StartSound( pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0 ); + break; + + case TE_BFG_EXPLOSION: + MSG_ReadPos (pos); + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 0.0; + ex->lightcolor[1] = 1.0; + ex->lightcolor[2] = 0.0; + ex->ent.model = cl_mod_bfg_explo; + ex->ent.flags |= RF_TRANSLUCENT; + ex->ent.alpha = 0.30; + ex->frames = 4; + break; + + case TE_BFG_BIGEXPLOSION: + MSG_ReadPos (pos); + CL_BFGExplosionParticles (pos); + break; + + case TE_BFG_LASER: + CL_ParseLaser (0xd0d1d2d3); + break; + + case TE_BUBBLETRAIL: + MSG_ReadPos (pos); + MSG_ReadPos (pos2); + CL_BubbleTrail (pos, pos2); + break; + + case TE_PARASITE_ATTACK: + case TE_MEDIC_CABLE_ATTACK: + CL_ParseBeam (cl_mod_parasite_segment); + break; + + case TE_BOSSTPORT: // boss teleporting to station + MSG_ReadPos (pos); + CL_BigTeleportParticles (pos); + S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0); + break; + + case TE_GRAPPLE_CABLE: + CL_ParseBeam2 (cl_mod_grapple_cable); + break; + + // RAFAEL + case TE_WELDING_SPARKS: + cnt = MSG_ReadByte (); + MSG_ReadPos (pos); + MSG_ReadDir (dir); + color = MSG_ReadByte (); + CL_ParticleEffect2 (pos, dir, color, cnt); + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_flash; + // note to self + // we need a better no draw flag + ex->ent.flags = RF_BEAM; + ex->start = cl.serverTime - 0.1; + ex->light = 100 + (rand()%75); + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 1.0; + ex->lightcolor[2] = 0.3; + ex->ent.model = cl_mod_flash; + ex->frames = 2; + break; + + case TE_GREENBLOOD: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleEffect2 (pos, dir, 0xdf, 30); + break; + + // RAFAEL + case TE_TUNNEL_SPARKS: + cnt = MSG_ReadByte (); + MSG_ReadPos (pos); + MSG_ReadDir (dir); + color = MSG_ReadByte (); + CL_ParticleEffect3 (pos, dir, color, cnt); + break; + +//============= +//PGM + // PMM -following code integrated for flechette (different color) + case TE_BLASTER2: // green blaster hitting wall + case TE_FLECHETTE: // flechette + MSG_ReadPos (pos); + MSG_ReadDir (dir); + + // PMM + if (type == TE_BLASTER2) + CL_BlasterParticles2 (pos, dir, 0xd0); + else + CL_BlasterParticles2 (pos, dir, 0x6f); // 75 + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->ent.angles[0] = acos(dir[2])/M_PI*180; + // PMM - fixed to correct for pitch of 0 + if (dir[0]) + ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180; + else if (dir[1] > 0) + ex->ent.angles[1] = 90; + else if (dir[1] < 0) + ex->ent.angles[1] = 270; + else + ex->ent.angles[1] = 0; + + ex->type = ex_misc; + ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; + + // PMM + if (type == TE_BLASTER2) + ex->ent.skinnum = 1; + else // flechette + ex->ent.skinnum = 2; + + ex->start = cl.serverTime - 100; + ex->light = 150; + // PMM + if (type == TE_BLASTER2) + ex->lightcolor[1] = 1; + else // flechette + { + ex->lightcolor[0] = 0.19; + ex->lightcolor[1] = 0.41; + ex->lightcolor[2] = 0.75; + } + ex->ent.model = cl_mod_explode; + ex->frames = 4; + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + + case TE_LIGHTNING: + CL_ParseLightning (cl_mod_lightning); + break; + + case TE_DEBUGTRAIL: + MSG_ReadPos (pos); + MSG_ReadPos (pos2); + CL_DebugTrail (pos, pos2); + break; + + case TE_PLAIN_EXPLOSION: + MSG_ReadPos (pos); + + ex = CL_AllocExplosion (); + VectorCopy (pos, ex->ent.origin); + ex->type = ex_poly; + ex->ent.flags = RF_FULLBRIGHT; + ex->start = cl.serverTime - 100; + ex->light = 350; + ex->lightcolor[0] = 1.0; + ex->lightcolor[1] = 0.5; + ex->lightcolor[2] = 0.5; + ex->ent.angles[1] = rand() % 360; + ex->ent.model = cl_mod_explo4; + if (frand() < 0.5) + ex->baseframe = 15; + ex->frames = 15; + S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); + break; + + case TE_FLASHLIGHT: + MSG_ReadPos(pos); + ent = MSG_ReadShort(); + CL_Flashlight(ent, pos); + break; + + case TE_FORCEWALL: + MSG_ReadPos(pos); + MSG_ReadPos(pos2); + color = MSG_ReadByte (); + CL_ForceWall(pos, pos2, color); + break; + + case TE_HEATBEAM: + CL_ParsePlayerBeam (cl_mod_heatbeam); + break; + + case TE_MONSTER_HEATBEAM: + CL_ParsePlayerBeam (cl_mod_monster_heatbeam); + break; + + case TE_HEATBEAM_SPARKS: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleSteamEffect (pos, dir, 0x8, 50, 60); + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_HEATBEAM_STEAM: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleSteamEffect (pos, dir, 0xE0, 20, 60); + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_STEAM: + CL_ParseSteam(); + break; + + case TE_BUBBLETRAIL2: + MSG_ReadPos (pos); + MSG_ReadPos (pos2); + CL_BubbleTrail2 (pos, pos2, 8); + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_MOREBLOOD: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleEffect (pos, dir, 0xe8, 250); + break; + + case TE_CHAINFIST_SMOKE: + MSG_ReadPos(pos); + VectorSet( dir, 0, 0, 1 ); + CL_ParticleSmokeEffect (pos, dir, 0, 20, 20); + break; + + case TE_ELECTRIC_SPARKS: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + CL_ParticleEffect (pos, dir, 0x75, 40); + //FIXME : replace or remove this sound + S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_TRACKER_EXPLOSION: + MSG_ReadPos (pos); + CL_ColorFlash (pos, 0, 150, -1, -1, -1); + CL_ColorExplosionParticles (pos, 0, 1); + S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); + break; + + case TE_TELEPORT_EFFECT: + case TE_DBALL_GOAL: + MSG_ReadPos (pos); + CL_TeleportParticles (pos); + break; + + case TE_WIDOWBEAMOUT: + CL_ParseWidow (); + break; + + case TE_NUKEBLAST: + CL_ParseNuke (); + break; + + case TE_WIDOWSPLASH: + MSG_ReadPos (pos); + CL_WidowSplash (pos); + break; +//PGM +//============== + + default: + Com_Error (ERR_DROP, "CL_ParseTEnt: bad type"); + } +} + +/* +================= +CL_AddBeams +================= +*/ +void CL_AddBeams (void) +{ + int i,j; + beam_t *b; + vec3_t dist, org; + float d; + entity_t ent; + float yaw, pitch; + float forward; + float len, steps; + float model_length; + +// update beams + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + continue; + + // if coming from the player, update the start position + if (b->entity == cl.frame.clientNum+1) // entity 0 is the world + { + VectorCopy (cl.refdef.vieworg, b->start); + b->start[2] -= 22; // adjust for view height + } + VectorAdd (b->start, b->offset, org); + + // calculate pitch and yaw + VectorSubtract (b->end, org, dist); + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + // PMM - fixed to correct for pitch of 0 + if (dist[0]) + yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (atan2(dist[2], forward) * -180.0 / M_PI); + if (pitch < 0) + pitch += 360.0; + } + + // add new entities for the beams + d = VectorNormalize(dist); + + memset (&ent, 0, sizeof(ent)); + if (b->model == cl_mod_lightning) + { + model_length = 35.0; + d-= 20.0; // correction so it doesn't end in middle of tesla + } + else + { + model_length = 30.0; + } + steps = ceil(d/model_length); + len = (d-model_length)/(steps-1); + + // PMM - special case for lightning model .. if the real length is shorter than the model, + // flip it around & draw it from the end to the start. This prevents the model from going + // through the tesla mine (instead it goes through the target) + if ((b->model == cl_mod_lightning) && (d <= model_length)) + { +// Com_Printf ("special case\n"); + VectorCopy (b->end, ent.origin); + // offset to push beam outside of tesla model (negative because dist is from end to start + // for this beam) +// for (j=0 ; j<3 ; j++) +// ent.origin[j] -= dist[j]*10.0; + ent.model = b->model; + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = rand()%360; + V_AddEntity (&ent); + return; + } + while (d > 0) + { + VectorCopy (org, ent.origin); + ent.model = b->model; + if (b->model == cl_mod_lightning) + { + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0; + ent.angles[2] = rand()%360; + } + else + { + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = rand()%360; + } + +// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); + V_AddEntity (&ent); + + for (j=0 ; j<3 ; j++) + org[j] += dist[j]*len; + d -= model_length; + } + } +} + +extern cvar_t *hand; + +/* +================= +ROGUE - draw player locked beams +CL_AddPlayerBeams +================= +*/ +void CL_AddPlayerBeams (void) +{ + int i,j; + beam_t *b; + vec3_t dist, org; + float d; + entity_t ent; + float yaw, pitch; + float forward; + float len, steps; + int framenum = 0; + float model_length; + + float hand_multiplier; +// frame_t *oldframe; + player_state_t *ps, *ops; + +//PMM + if (info_hand->integer == 2) + hand_multiplier = 0; + else if (info_hand->integer == 1) + hand_multiplier = -1; + else + hand_multiplier = 1; +//PMM + +// update beams + for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) + { + vec3_t f,r,u; + if (!b->model || b->endtime < cl.time) + continue; + + if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) + { + + // if coming from the player, update the start position + if (b->entity == cl.frame.clientNum+1) // entity 0 is the world + { + // set up gun position + ps = &cl.frame.ps; + ops = &cl.oldframe.ps; + + if( !cl.oldframe.valid || cl.oldframe.number != cl.frame.number - 1 ) + ops = ps; // previous frame was dropped or invalid + + for (j=0 ; j<3 ; j++) + { + b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j] + + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]); + } + VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org); + VectorMA ( org, b->offset[1], cl.v_forward, org); + VectorMA ( org, b->offset[2], cl.v_up, org); + if (info_hand->integer == 2) { + VectorMA (org, -1, cl.v_up, org); + } + // FIXME - take these out when final + VectorCopy (cl.v_right, r); + VectorCopy (cl.v_forward, f); + VectorCopy (cl.v_up, u); + + } + else + VectorCopy (b->start, org); + } + else + { + // if coming from the player, update the start position + if (b->entity == cl.frame.clientNum+1) // entity 0 is the world + { + VectorCopy (cl.refdef.vieworg, b->start); + b->start[2] -= 22; // adjust for view height + } + VectorAdd (b->start, b->offset, org); + } + + // calculate pitch and yaw + VectorSubtract (b->end, org, dist); + +//PMM + if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.frame.clientNum+1)) + { + vec_t len; + + len = VectorLength (dist); + VectorScale (f, len, dist); + VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist); + VectorMA (dist, b->offset[1], f, dist); + VectorMA (dist, b->offset[2], u, dist); + if (info_hand->value == 2) { + VectorMA (org, -1, cl.v_up, org); + } + } +//PMM + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + // PMM - fixed to correct for pitch of 0 + if (dist[0]) + yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (atan2(dist[2], forward) * -180.0 / M_PI); + if (pitch < 0) + pitch += 360.0; + } + + if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) + { + if (b->entity != cl.frame.clientNum+1) + { + framenum = 2; +// Com_Printf ("Third person\n"); + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0; + ent.angles[2] = 0; +// Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]); + AngleVectors(ent.angles, f, r, u); + + // if it's a non-origin offset, it's a player, so use the hardcoded player offset + if (!VectorCompare (b->offset, vec3_origin)) + { + VectorMA (org, -(b->offset[0])+1, r, org); + VectorMA (org, -(b->offset[1]), f, org); + VectorMA (org, -(b->offset[2])-10, u, org); + } + else + { + // if it's a monster, do the particle effect + CL_MonsterPlasma_Shell(b->start); + } + } + else + { + framenum = 1; + } + } + + // if it's the heatbeam, draw the particle effect + if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.frame.clientNum+1))) + { + CL_Heatbeam (org, dist); + } + + // add new entities for the beams + d = VectorNormalize(dist); + + memset (&ent, 0, sizeof(ent)); + if (b->model == cl_mod_heatbeam) + { + model_length = 32.0; + } + else if (b->model == cl_mod_lightning) + { + model_length = 35.0; + d-= 20.0; // correction so it doesn't end in middle of tesla + } + else + { + model_length = 30.0; + } + steps = ceil(d/model_length); + len = (d-model_length)/(steps-1); + + // PMM - special case for lightning model .. if the real length is shorter than the model, + // flip it around & draw it from the end to the start. This prevents the model from going + // through the tesla mine (instead it goes through the target) + if ((b->model == cl_mod_lightning) && (d <= model_length)) + { +// Com_Printf ("special case\n"); + VectorCopy (b->end, ent.origin); + // offset to push beam outside of tesla model (negative because dist is from end to start + // for this beam) +// for (j=0 ; j<3 ; j++) +// ent.origin[j] -= dist[j]*10.0; + ent.model = b->model; + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = rand()%360; + V_AddEntity (&ent); + return; + } + while (d > 0) + { + VectorCopy (org, ent.origin); + ent.model = b->model; + if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) + { +// ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; +// ent.alpha = 0.3; + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0; + ent.angles[2] = (cl.time) % 360; +// ent.angles[2] = rand()%360; + ent.frame = framenum; + } + else if (b->model == cl_mod_lightning) + { + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0; + ent.angles[2] = rand()%360; + } + else + { + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = rand()%360; + } + +// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); + V_AddEntity (&ent); + + for (j=0 ; j<3 ; j++) + org[j] += dist[j]*len; + d -= model_length; + } + } +} + +/* +================= +CL_AddExplosions +================= +*/ +void CL_AddExplosions (void) +{ + entity_t *ent; + int i; + explosion_t *ex; + float frac; + int f; + + memset (&ent, 0, sizeof(ent)); + + for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++) + { + if (ex->type == ex_free) + continue; + frac = (cl.time - ex->start)/100.0; + f = floor(frac); + + ent = &ex->ent; + + switch (ex->type) { + case ex_mflash: + if (f >= ex->frames-1) + ex->type = ex_free; + break; + case ex_misc: + case ex_light: + if (f >= ex->frames-1) { + ex->type = ex_free; + break; + } + ent->alpha = 1.0 - frac/(ex->frames-1); + break; + case ex_flash: + if (f >= 1) { + ex->type = ex_free; + break; + } + ent->alpha = 1.0; + break; + case ex_poly: + if (f >= ex->frames-1) { + ex->type = ex_free; + break; + } + + ent->alpha = (16.0 - (float)f)/16.0; + + if (f < 10) { + ent->skinnum = (f>>1); + if (ent->skinnum < 0) + ent->skinnum = 0; + } else { + ent->flags |= RF_TRANSLUCENT; + if (f < 13) + ent->skinnum = 5; + else + ent->skinnum = 6; + } + break; + case ex_poly2: + if (f >= ex->frames-1) { + ex->type = ex_free; + break; + } + + ent->alpha = (5.0 - (float)f)/5.0; + ent->skinnum = 0; + ent->flags |= RF_TRANSLUCENT; + break; + default: + break; + } + + if (ex->type == ex_free) + continue; + if (ex->light) { + V_AddLight (ent->origin, ex->light*ent->alpha, + ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]); + } + + if( ex->type != ex_light ) { + VectorCopy (ent->origin, ent->oldorigin); + + if (f < 0) + f = 0; + ent->frame = ex->baseframe + f + 1; + ent->oldframe = ex->baseframe + f; + ent->backlerp = 1.0 - cl.lerpfrac; + + V_AddEntity (ent); + } + } +} + + + + +/* PMM - CL_Sustains */ +void CL_ProcessSustain (void) +{ + cl_sustain_t *s; + int i; + + for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++) + { + if (s->id) + { + if ((s->endtime >= cl.time) && (cl.time >= s->nextthink)) + { +// Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval); + s->think (s); + } + else if (s->endtime < cl.time) + s->id = 0; + } + } +} + +/* +================= +CL_AddTEnts +================= +*/ +void CL_AddTEnts (void) +{ + CL_AddBeams (); + // PMM - draw plasma beams + CL_AddPlayerBeams (); + CL_AddExplosions (); + CL_AddLasers (); + // PMM - set up sustain + CL_ProcessSustain(); +} + + + |