diff options
Diffstat (limited to 'src/jake2/client/CL_tent.java')
-rw-r--r-- | src/jake2/client/CL_tent.java | 1720 |
1 files changed, 1720 insertions, 0 deletions
diff --git a/src/jake2/client/CL_tent.java b/src/jake2/client/CL_tent.java new file mode 100644 index 0000000..7430a45 --- /dev/null +++ b/src/jake2/client/CL_tent.java @@ -0,0 +1,1720 @@ +/* + * CL_tent.java + * Copyright (C) 2004 + * + * $Id: CL_tent.java,v 1.1 2004-07-07 19:58:40 hzi Exp $ + */ +/* +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. + +*/ +package jake2.client; + +import jake2.Globals; +import jake2.game.player_state_t; +import jake2.qcommon.Com; +import jake2.qcommon.MSG; +import jake2.render.model_t; + +/** + * CL_tent + */ +public class CL_tent extends Globals { + + static final int ex_free = 0; + static final int ex_explosion = 1; + static final int ex_misc = 2; + static final int ex_flash = 3; + static final int ex_mflash = 4; + static final int ex_poly = 5; + static final int ex_poly2 = 6; + + + static class explosion_t { + int type; + entity_t ent = new entity_t(); + + int frames; + float light; + float[] lightcolor = new float[3]; + float start; + int baseframe; + void clear() { + lightcolor[0] = lightcolor[1] = lightcolor[2] = + light = start = type = frames = baseframe = 0; + ent = new entity_t(); + } + } + + static final int MAX_EXPLOSIONS = 32; + static explosion_t[] cl_explosions = new explosion_t[MAX_EXPLOSIONS]; + static { + for (int i = 0; i < cl_explosions.length; i++) + cl_explosions[i] = new explosion_t(); + } + + static final int MAX_BEAMS = 32; + + static class beam_t { + int entity; + int dest_entity; + model_t model; + int endtime; + float[] offset = new float[3]; + float[] start = new float[3]; + float[] end = new float[3]; + void clear() { + offset[0] = offset[1] = offset[2] = + start[0] = start[1] = start[2] = + end[0] = end[1] = end[2] = + entity = dest_entity = endtime = 0; + model = null; + } + } + static beam_t[] cl_beams = new beam_t[MAX_BEAMS]; + // PMM - added this for player-linked beams. Currently only used by the plasma beam + static beam_t[] cl_playerbeams = new beam_t[MAX_BEAMS]; + static { + for (int i = 0; i < cl_beams.length; i++) + cl_beams[i] = new beam_t(); + for (int i = 0; i < cl_playerbeams.length; i++) + cl_playerbeams[i] = new beam_t(); + } + + static final int MAX_LASERS = 32; + + static class laser_t { + entity_t ent = new entity_t(); + int endtime; + void clear() { + endtime = 0; + ent = new entity_t(); + } + } + static laser_t[] cl_lasers = new laser_t[MAX_LASERS]; + static { + for (int i = 0; i < cl_lasers.length; i++) + cl_lasers[i] = new laser_t(); + } + +// ROGUE + static final int MAX_SUSTAINS = 32; + static cl_sustain_t[] cl_sustains = new cl_sustain_t[MAX_SUSTAINS]; + static { + for (int i = 0; i < cl_sustains.length; i++) + cl_sustains[i] = new cl_sustain_t(); + } +// ROGUE + + // all are references; + static sfx_t cl_sfx_ric1; + static sfx_t cl_sfx_ric2; + static sfx_t cl_sfx_ric3; + static sfx_t cl_sfx_lashit; + static sfx_t cl_sfx_spark5; + static sfx_t cl_sfx_spark6; + static sfx_t cl_sfx_spark7; + static sfx_t cl_sfx_railg; + static sfx_t cl_sfx_rockexp; + static sfx_t cl_sfx_grenexp; + static sfx_t cl_sfx_watrexp; + // RAFAEL + static sfx_t cl_sfx_plasexp; + static sfx_t cl_sfx_footsteps[] = new sfx_t[4]; + + static model_t cl_mod_explode; + static model_t cl_mod_smoke; + static model_t cl_mod_flash; + static model_t cl_mod_parasite_segment; + static model_t cl_mod_grapple_cable; + static model_t cl_mod_parasite_tip; + static model_t cl_mod_explo4; + static model_t cl_mod_bfg_explo; + static model_t cl_mod_powerscreen; + // RAFAEL + static model_t cl_mod_plasmaexplo; + + // ROGUE + static sfx_t cl_sfx_lightning; + static sfx_t cl_sfx_disrexp; + static model_t cl_mod_lightning; + static model_t cl_mod_heatbeam; + static model_t cl_mod_monster_heatbeam; + static model_t cl_mod_explo4_big; + +// ROGUE + /* + ================= + CL_RegisterTEntSounds + ================= + */ + static void RegisterTEntSounds() { + int i; + String name; + + // 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); + name = "player/step" + (i + 1) + ".wav"; + 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 + ================= + */ + static void RegisterTEntModels() { + cl_mod_explode = re.RegisterModel("models/objects/explode/tris.md2"); + cl_mod_smoke = re.RegisterModel("models/objects/smoke/tris.md2"); + cl_mod_flash = re.RegisterModel("models/objects/flash/tris.md2"); + cl_mod_parasite_segment = re.RegisterModel("models/monsters/parasite/segment/tris.md2"); + cl_mod_grapple_cable = re.RegisterModel("models/ctf/segment/tris.md2"); + cl_mod_parasite_tip = re.RegisterModel("models/monsters/parasite/tip/tris.md2"); + cl_mod_explo4 = re.RegisterModel("models/objects/r_explode/tris.md2"); + cl_mod_bfg_explo = re.RegisterModel("sprites/s_bfg2.sp2"); + cl_mod_powerscreen = re.RegisterModel("models/items/armor/effect/tris.md2"); + + re.RegisterModel("models/objects/laser/tris.md2"); + re.RegisterModel("models/objects/grenade2/tris.md2"); + re.RegisterModel("models/weapons/v_machn/tris.md2"); + re.RegisterModel("models/weapons/v_handgr/tris.md2"); + re.RegisterModel("models/weapons/v_shotg2/tris.md2"); + re.RegisterModel("models/objects/gibs/bone/tris.md2"); + re.RegisterModel("models/objects/gibs/sm_meat/tris.md2"); + re.RegisterModel("models/objects/gibs/bone2/tris.md2"); + // RAFAEL + // re.RegisterModel ("models/objects/blaser/tris.md2"); + + re.RegisterPic("w_machinegun"); + re.RegisterPic("a_bullets"); + re.RegisterPic("i_health"); + re.RegisterPic("a_grenades"); + + // ROGUE + cl_mod_explo4_big = re.RegisterModel("models/objects/r_explode2/tris.md2"); + cl_mod_lightning = re.RegisterModel("models/proj/lightning/tris.md2"); + cl_mod_heatbeam = re.RegisterModel("models/proj/beam/tris.md2"); + cl_mod_monster_heatbeam = re.RegisterModel("models/proj/widowbeam/tris.md2"); + // ROGUE + } + + /* + ================= + CL_ClearTEnts + ================= + */ + static void ClearTEnts() { + // memset (cl_beams, 0, sizeof(cl_beams)); + for (int i = 0; i < cl_beams.length; i++) + cl_beams[i].clear(); + // memset (cl_explosions, 0, sizeof(cl_explosions)); + for (int i = 0; i < cl_explosions.length; i++) + cl_explosions[i].clear(); + // memset (cl_lasers, 0, sizeof(cl_lasers)); + for (int i = 0; i < cl_lasers.length; i++) + cl_lasers[i].clear(); + // + // ROGUE + // memset (cl_playerbeams, 0, sizeof(cl_playerbeams)); + for (int i = 0; i < cl_playerbeams.length; i++) + cl_playerbeams[i].clear(); + // memset (cl_sustains, 0, sizeof(cl_sustains)); + for (int i = 0; i < cl_sustains.length; i++) + cl_sustains[i].clear(); + // ROGUE + } + + /* + ================= + CL_AllocExplosion + ================= + */ + static explosion_t AllocExplosion() { + 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])); + cl_explosions[i].clear(); + 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 = (int)cl_explosions[i].start; + index = i; + } + //memset (&cl_explosions[index], 0, sizeof (cl_explosions[index])); + cl_explosions[index].clear(); + return cl_explosions[index]; + } + + /* + ================= + CL_SmokeAndFlash + ================= + */ + static void SmokeAndFlash(float[] 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.frame.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.frame.servertime - 100; + ex.ent.model = cl_mod_flash; + } + + /* + ================= + CL_ParseParticles + ================= + */ + static void ParseParticles() { + int color, count; + float[] pos = new float[3]; + float[] dir = new float[3]; + + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + + color = MSG.ReadByte(net_message); + + count = MSG.ReadByte(net_message); + + CL.ParticleEffect(pos, dir, color, count); + } + + /* + ================= + CL_ParseBeam + ================= + */ + static int ParseBeam(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(net_message); + + MSG.ReadPos(net_message, start); + MSG.ReadPos(net_message, end); + + // override any beam with the same entity + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorClear(b[i].offset); + return ent; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorClear(b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } + + /* + ================= + CL_ParseBeam2 + ================= + */ + static int ParseBeam2(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + float[] offset = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(net_message); + + MSG.ReadPos(net_message, start); + MSG.ReadPos(net_message, end); + MSG.ReadPos(net_message, offset); + + // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); + + // override any beam with the same entity + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorCopy(offset, b[i].offset); + return ent; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorCopy(offset, b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } + + // ROGUE + /* + ================= + CL_ParsePlayerBeam + - adds to the cl_playerbeam array instead of the cl_beams array + ================= + */ + static int ParsePlayerBeam(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + float[] offset = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(net_message); + + MSG.ReadPos(net_message, start); + MSG.ReadPos(net_message, 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(net_message, offset); + + // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); + + // override any beam with the same entity + // PMM - For player beams, we only want one per player (entity) so.. + b = cl_playerbeams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorCopy(offset, b[i].offset); + return ent; + } + } + + // find a free beam + b = cl_playerbeams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorCopy(offset, b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } +// rogue + + /* + ================= + CL_ParseLightning + ================= + */ + static int ParseLightning(model_t model) { + int srcEnt, destEnt; + float[] start = new float[3]; + float[] end = new float[3]; + beam_t[] b; + int i; + + srcEnt = MSG.ReadShort(net_message); + destEnt = MSG.ReadShort(net_message); + + MSG.ReadPos(net_message, start); + MSG.ReadPos(net_message, end); + + // override any beam with the same source AND destination entities + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == srcEnt && b[i].dest_entity == destEnt) { + // Com_Printf("%d: OVERRIDE %d . %d\n", cl.time, srcEnt, destEnt); + b[i].entity = srcEnt; + b[i].dest_entity = destEnt; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorClear(b[i].offset); + return srcEnt; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < cl.time) { + // Com_Printf("%d: NORMAL %d . %d\n", cl.time, srcEnt, destEnt); + b[i].entity = srcEnt; + b[i].dest_entity = destEnt; + b[i].model = model; + b[i].endtime = cl.time + 200; + VectorCopy(start, b[i].start); + VectorCopy(end, b[i].end); + VectorClear(b[i].offset); + return srcEnt; + } + } + Com.Printf("beam list overflow!\n"); + return srcEnt; + } + + /* + ================= + CL_ParseLaser + ================= + */ + static void ParseLaser(int colors) { + float[] start = new float[3]; + float[] end = new float[3]; + laser_t[] l; + int i; + + MSG.ReadPos(net_message, start); + MSG.ReadPos(net_message, end); + + l = cl_lasers; + for (i = 0; i < MAX_LASERS; i++) { + if (l[i].endtime < cl.time) { + l[i].ent.flags = RF_TRANSLUCENT | RF_BEAM; + VectorCopy(start, l[i].ent.origin); + VectorCopy(end, l[i].ent.oldorigin); + l[i].ent.alpha = 0.30f; + l[i].ent.skinnum = (colors >> ((rand() % 4) * 8)) & 0xff; + l[i].ent.model = null; + l[i].ent.frame = 4; + l[i].endtime = cl.time + 100; + return; + } + } + } + +// ============= +// ROGUE + static void ParseSteam() { + float[] pos = new float[3]; + float[] dir = new float[3]; + int id, i; + int r; + int cnt; + int color; + int magnitude; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + id = MSG.ReadShort(net_message); // an id of -1 is an instant effect + if (id != -1) // sustains + { + // Com_Printf ("Sustain effect id %d\n", id); + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = id; + s[i].count = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, s[i].org); + MSG.ReadDir(net_message, s[i].dir); + r = MSG.ReadByte(net_message); + s[i].color = r & 0xff; + s[i].magnitude = MSG.ReadShort(net_message); + s[i].endtime = cl.time + MSG.ReadLong(net_message); + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL.ParticleSteamEffect2(self); + } + }; + s[i].thinkinterval = 100; + s[i].nextthink = cl.time; + } else { + // Com_Printf ("No free sustains!\n"); + // FIXME - read the stuff anyway + cnt = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + r = MSG.ReadByte(net_message); + magnitude = MSG.ReadShort(net_message); + magnitude = MSG.ReadLong(net_message); // really interval + } + } else // instant + { + cnt = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + r = MSG.ReadByte(net_message); + magnitude = MSG.ReadShort(net_message); + color = r & 0xff; + CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + } + } + + static void ParseWidow() { + float[] pos = new float[3]; + int id, i; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + id = MSG.ReadShort(net_message); + + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = id; + MSG.ReadPos(net_message, s[i].org); + s[i].endtime = cl.time + 2100; + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL.Widowbeamout(self); + } + }; + s[i].thinkinterval = 1; + s[i].nextthink = cl.time; + } else // no free sustains + { + // FIXME - read the stuff anyway + MSG.ReadPos(net_message, pos); + } + } + + static void ParseNuke() { + float[] pos = new float[3]; + int i; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = 21000; + MSG.ReadPos(net_message, s[i].org); + s[i].endtime = cl.time + 1000; + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL.Nukeblast(self); + } + }; + s[i].thinkinterval = 1; + s[i].nextthink = cl.time; + } else // no free sustains + { + // FIXME - read the stuff anyway + MSG.ReadPos(net_message, pos); + } + } + +// ROGUE +// ============= + + + /* + ================= + CL_ParseTEnt + ================= + */ + static int[] splash_color = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8}; + static void ParseTEnt() { + int type; + float[] pos = new float[3]; + float[] pos2 = new float[3]; + float[] dir = new float[3]; + explosion_t ex; + int cnt; + int color; + int r; + int ent; + int magnitude; + + type = MSG.ReadByte(net_message); + + switch (type) { + case TE_BLOOD : // bullet hitting flesh + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + CL.ParticleEffect(pos, dir, 0xe8, 60); + break; + + case TE_GUNSHOT : // bullet hitting wall + case TE_SPARKS : + case TE_BULLET_SPARKS : + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, 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(net_message, pos); + MSG.ReadDir(net_message, 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(net_message, pos); + MSG.ReadDir(net_message, dir); + CL.ParticleEffect(pos, dir, 0, 20); + CL.SmokeAndFlash(pos); + break; + + case TE_SPLASH : // bullet hitting water + cnt = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + r = MSG.ReadByte(net_message); + 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(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + color = MSG.ReadByte(net_message); + CL.ParticleEffect2(pos, dir, color, cnt); + break; + + // RAFAEL + case TE_BLUEHYPERBLASTER : + MSG.ReadPos(net_message, pos); + MSG.ReadPos(net_message, dir); + CL.BlasterParticles(pos, dir); + break; + + case TE_BLASTER : // blaster hitting wall + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + CL.BlasterParticles(pos, dir); + + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180); + // PMM - fixed to correct for pitch of 0 + if (dir[0] != 0.0f) + ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.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.frame.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(net_message, pos); + MSG.ReadPos(net_message, pos2); + CL.RailTrail(pos, pos2); + S.StartSound(pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0); + break; + + case TE_EXPLOSION2 : + case TE_GRENADE_EXPLOSION : + case TE_GRENADE_EXPLOSION_WATER : + MSG.ReadPos(net_message, pos); + + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = RF_FULLBRIGHT; + ex.start = cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.model = cl_mod_explo4; + ex.frames = 19; + ex.baseframe = 30; + ex.ent.angles[1] = rand() % 360; + 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; + + // RAFAEL + case TE_PLASMA_EXPLOSION : + MSG.ReadPos(net_message, pos); + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = RF_FULLBRIGHT; + ex.start = cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + 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_EXPLOSION1 : + case TE_EXPLOSION1_BIG : // PMM + case TE_ROCKET_EXPLOSION : + case TE_ROCKET_EXPLOSION_WATER : + case TE_EXPLOSION1_NP : // PMM + MSG.ReadPos(net_message, pos); + + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = RF_FULLBRIGHT; + ex.start = cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.angles[1] = rand() % 360; + if (type != TE_EXPLOSION1_BIG) // PMM + ex.ent.model = cl_mod_explo4; // PMM + else + ex.ent.model = cl_mod_explo4_big; + if (frand() < 0.5) + ex.baseframe = 15; + ex.frames = 15; + if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM + CL.ExplosionParticles(pos); // PMM + 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_BFG_EXPLOSION : + MSG.ReadPos(net_message, pos); + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = RF_FULLBRIGHT; + ex.start = cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 0.0f; + ex.lightcolor[1] = 1.0f; + ex.lightcolor[2] = 0.0f; + ex.ent.model = cl_mod_bfg_explo; + ex.ent.flags |= RF_TRANSLUCENT; + ex.ent.alpha = 0.30f; + ex.frames = 4; + break; + + case TE_BFG_BIGEXPLOSION : + MSG.ReadPos(net_message, pos); + CL.BFGExplosionParticles(pos); + break; + + case TE_BFG_LASER : + CL.ParseLaser(0xd0d1d2d3); + break; + + case TE_BUBBLETRAIL : + MSG.ReadPos(net_message, pos); + MSG.ReadPos(net_message, pos2); + CL.BubbleTrail(pos, pos2); + break; + + case TE_PARASITE_ATTACK : + case TE_MEDIC_CABLE_ATTACK : + ent = CL.ParseBeam(cl_mod_parasite_segment); + break; + + case TE_BOSSTPORT : // boss teleporting to station + MSG.ReadPos(net_message, pos); + CL.BigTeleportParticles(pos); + S.StartSound(pos, 0, 0, S.RegisterSound("misc/bigtele.wav"), 1, ATTN_NONE, 0); + break; + + case TE_GRAPPLE_CABLE : + ent = CL.ParseBeam2(cl_mod_grapple_cable); + break; + + // RAFAEL + case TE_WELDING_SPARKS : + cnt = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + color = MSG.ReadByte(net_message); + 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.frame.servertime - 0.1f; + ex.light = 100 + (rand() % 75); + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 1.0f; + ex.lightcolor[2] = 0.3f; + ex.ent.model = cl_mod_flash; + ex.frames = 2; + break; + + case TE_GREENBLOOD : + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + CL.ParticleEffect2(pos, dir, 0xdf, 30); + break; + + // RAFAEL + case TE_TUNNEL_SPARKS : + cnt = MSG.ReadByte(net_message); + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + color = MSG.ReadByte(net_message); + 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(net_message, pos); + MSG.ReadDir(net_message, 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] = (float) (Math.acos(dir[2]) / Math.PI * 180); + // PMM - fixed to correct for pitch of 0 + if (dir[0] != 0.0f) + ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.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.frame.servertime - 100; + ex.light = 150; + // PMM + if (type == TE_BLASTER2) + ex.lightcolor[1] = 1; + else // flechette + { + ex.lightcolor[0] = 0.19f; + ex.lightcolor[1] = 0.41f; + ex.lightcolor[2] = 0.75f; + } + 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 : + ent = CL.ParseLightning(cl_mod_lightning); + S.StartSound(null, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); + break; + + case TE_DEBUGTRAIL : + MSG.ReadPos(net_message, pos); + MSG.ReadPos(net_message, pos2); + CL.DebugTrail(pos, pos2); + break; + + case TE_PLAIN_EXPLOSION : + MSG.ReadPos(net_message, pos); + + ex = CL.AllocExplosion(); + VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = RF_FULLBRIGHT; + ex.start = cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.angles[1] = rand() % 360; + ex.ent.model = cl_mod_explo4; + if (frand() < 0.5) + ex.baseframe = 15; + ex.frames = 15; + 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_FLASHLIGHT : + MSG.ReadPos(net_message, pos); + ent = MSG.ReadShort(net_message); + CL.Flashlight(ent, pos); + break; + + case TE_FORCEWALL : + MSG.ReadPos(net_message, pos); + MSG.ReadPos(net_message, pos2); + color = MSG.ReadByte(net_message); + CL.ForceWall(pos, pos2, color); + break; + + case TE_HEATBEAM : + ent = CL.ParsePlayerBeam(cl_mod_heatbeam); + break; + + case TE_MONSTER_HEATBEAM : + ent = CL.ParsePlayerBeam(cl_mod_monster_heatbeam); + break; + + case TE_HEATBEAM_SPARKS : + // cnt = MSG.ReadByte (net_message); + cnt = 50; + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + // r = MSG.ReadByte (net_message); + // magnitude = MSG.ReadShort (net_message); + r = 8; + magnitude = 60; + color = r & 0xff; + CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_HEATBEAM_STEAM : + // cnt = MSG.ReadByte (net_message); + cnt = 20; + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + // r = MSG.ReadByte (net_message); + // magnitude = MSG.ReadShort (net_message); + // color = r & 0xff; + color = 0xe0; + magnitude = 60; + CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_STEAM : + CL.ParseSteam(); + break; + + case TE_BUBBLETRAIL2 : + // cnt = MSG.ReadByte (net_message); + cnt = 8; + MSG.ReadPos(net_message, pos); + MSG.ReadPos(net_message, pos2); + CL.BubbleTrail2(pos, pos2, cnt); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + break; + + case TE_MOREBLOOD : + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + CL.ParticleEffect(pos, dir, 0xe8, 250); + break; + + case TE_CHAINFIST_SMOKE : + dir[0] = 0; + dir[1] = 0; + dir[2] = 1; + MSG.ReadPos(net_message, pos); + CL.ParticleSmokeEffect(pos, dir, 0, 20, 20); + break; + + case TE_ELECTRIC_SPARKS : + MSG.ReadPos(net_message, pos); + MSG.ReadDir(net_message, dir); + // CL_ParticleEffect (pos, dir, 109, 40); + 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(net_message, pos); + CL.ColorFlash(pos, 0, 150, -1, -1, -1); + CL.ColorExplosionParticles(pos, 0, 1); + // CL_Tracker_Explode (pos); + S.StartSound(pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); + break; + + case TE_TELEPORT_EFFECT : + case TE_DBALL_GOAL : + MSG.ReadPos(net_message, pos); + CL.TeleportParticles(pos); + break; + + case TE_WIDOWBEAMOUT : + CL.ParseWidow(); + break; + + case TE_NUKEBLAST : + ParseNuke(); + break; + + case TE_WIDOWSPLASH : + MSG.ReadPos(net_message, pos); + CL.WidowSplash(pos); + break; + // PGM + // ============== + + default : + Com.Error(ERR_DROP, "CL_ParseTEnt: bad type"); + } + } + + /* + ================= + CL_AddBeams + ================= + */ + static void AddBeams() { + int i, j; + beam_t[] b; + float[] dist = new float[3]; + float[] org = new float[3]; + float d; + entity_t ent = new entity_t(); + float yaw, pitch; + float forward; + float len, steps; + float model_length; + + // update beams + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < cl.time) + continue; + + // if coming from the player, update the start position + if (b[i].entity == cl.playernum + 1) // entity 0 is the world + { + VectorCopy(cl.refdef.vieworg, b[i].start); + b[i].start[2] -= 22; // adjust for view height + } + VectorAdd(b[i].start, b[i].offset, org); + + // calculate pitch and yaw + VectorSubtract(b[i].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] != 0.0f) + yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]); + pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); + if (pitch < 0) + pitch += 360.0; + } + + // add new entities for the beams + d = VectorNormalize(dist); + + //memset (&ent, 0, sizeof(ent)); + ent = new entity_t(); + if (b[i].model == cl_mod_lightning) { + model_length = 35.0f; + d -= 20.0; // correction so it doesn't end in middle of tesla + } else { + model_length = 30.0f; + } + steps = (float)Math.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[i].model == cl_mod_lightning) && (d <= model_length)) { + // Com_Printf ("special case\n"); + VectorCopy(b[i].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[i].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[i].model; + if (b[i].model == cl_mod_lightning) { + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + 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[i].entity, b[i].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 + ================= + */ + static void AddPlayerBeams() { + int i, j; + beam_t[] b; + float[] dist = new float[3]; + float[] org = new float[3]; + float d; + entity_t ent = new entity_t(); + 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 (hand != null) { + if (hand.value == 2) + hand_multiplier = 0; + else if (hand.value == 1) + hand_multiplier = -1; + else + hand_multiplier = 1; + } else { + hand_multiplier = 1; + } + // PMM + + // update beams + b = cl_playerbeams; + for (i = 0; i < MAX_BEAMS; i++) { + float[] f = new float[3]; + float[] u = new float[3]; + float[] r = new float[3]; + if (b[i].model == null || b[i].endtime < cl.time) + continue; + + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { + + // if coming from the player, update the start position + if (b[i].entity == cl.playernum + 1) // entity 0 is the world + { + // set up gun position + // code straight out of CL_AddViewWeapon + ps = cl.frame.playerstate; + j = (cl.frame.serverframe - 1) & UPDATE_MASK; + oldframe = cl.frames[j]; + + if (oldframe.serverframe != cl.frame.serverframe - 1 || !oldframe.valid) + oldframe = cl.frame; // previous frame was dropped or involid + + ops = oldframe.playerstate; + for (j = 0; j < 3; j++) { + b[i].start[j] = + cl.refdef.vieworg[j] + + ops.gunoffset[j] + + cl.lerpfrac * (ps.gunoffset[j] - ops.gunoffset[j]); + } + VectorMA(b[i].start, (hand_multiplier * b[i].offset[0]), cl.v_right, org); + VectorMA(org, b[i].offset[1], cl.v_forward, org); + VectorMA(org, b[i].offset[2], cl.v_up, org); + if ((hand != null) && (hand.value == 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[i].start, org); + } else { + // if coming from the player, update the start position + if (b[i].entity == cl.playernum + 1) // entity 0 is the world + { + VectorCopy(cl.refdef.vieworg, b[i].start); + b[i].start[2] -= 22; // adjust for view height + } + VectorAdd(b[i].start, b[i].offset, org); + } + + // calculate pitch and yaw + VectorSubtract(b[i].end, org, dist); + + // PMM + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1)) { + + len = VectorLength(dist); + VectorScale(f, len, dist); + VectorMA(dist, (hand_multiplier * b[i].offset[0]), r, dist); + VectorMA(dist, b[i].offset[1], f, dist); + VectorMA(dist, b[i].offset[2], u, dist); + if ((hand != null) && (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] != 0.0f) + yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]); + pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); + if (pitch < 0) + pitch += 360.0; + } + + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { + if (b[i].entity != cl.playernum + 1) { + framenum = 2; + // Com_Printf ("Third person\n"); + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + ent.angles[2] = 0; + // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b[i].offset[0], b[i].offset[1], b[i].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[i].offset, vec3_origin) == 0) { + VectorMA(org, - (b[i].offset[0]) + 1, r, org); + VectorMA(org, - (b[i].offset[1]), f, org); + VectorMA(org, - (b[i].offset[2]) - 10, u, org); + } else { + // if it's a monster, do the particle effect + CL.MonsterPlasma_Shell(b[i].start); + } + } else { + framenum = 1; + } + } + + // if it's the heatbeam, draw the particle effect + if ((cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1))) { + CL.Heatbeam(org, dist); + } + + // add new entities for the beams + d = VectorNormalize(dist); + + //memset (&ent, 0, sizeof(ent)); + ent = new entity_t(); + if (b[i].model == cl_mod_heatbeam) { + model_length = 32.0f; + } else if (b[i].model == cl_mod_lightning) { + model_length = 35.0f; + d -= 20.0; // correction so it doesn't end in middle of tesla + } else { + model_length = 30.0f; + } + steps = (float)Math.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[i].model == cl_mod_lightning) && (d <= model_length)) { + // Com_Printf ("special case\n"); + VectorCopy(b[i].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[i].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[i].model; + if (cl_mod_heatbeam != null && (b[i].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.0f; + ent.angles[2] = (cl.time) % 360; + // ent.angles[2] = rand()%360; + ent.frame = framenum; + } else if (b[i].model == cl_mod_lightning) { + ent.flags = RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + 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[i].entity, b[i].dest_entity); + V.AddEntity(ent); + + for (j = 0; j < 3; j++) + org[j] += dist[j] * len; + d -= model_length; + } + } + } + + /* + ================= + CL_AddExplosions + ================= + */ + static void AddExplosions() { + entity_t ent; + int i; + explosion_t[] ex; + float frac; + int f; + + //memset (&ent, 0, sizeof(ent)); Pointer! + ent = null; + ex = cl_explosions; + for (i = 0; i < MAX_EXPLOSIONS; i++) { + if (ex[i].type == ex_free) + continue; + frac = (cl.time - ex[i].start) / 100.0f; + f = (int)Math.floor(frac); + + ent = ex[i].ent; + + switch (ex[i].type) { + case ex_mflash : + if (f >= ex[i].frames - 1) + ex[i].type = ex_free; + break; + case ex_misc : + if (f >= ex[i].frames - 1) { + ex[i].type = ex_free; + break; + } + ent.alpha = 1.0f - frac / (ex[i].frames - 1); + break; + case ex_flash : + if (f >= 1) { + ex[i].type = ex_free; + break; + } + ent.alpha = 1.0f; + break; + case ex_poly : + if (f >= ex[i].frames - 1) { + ex[i].type = ex_free; + break; + } + + ent.alpha = (16.0f - (float)f) / 16.0f; + + 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[i].frames - 1) { + ex[i].type = ex_free; + break; + } + + ent.alpha = (5.0f - (float)f) / 5.0f; + ent.skinnum = 0; + ent.flags |= RF_TRANSLUCENT; + break; + } + + if (ex[i].type == ex_free) + continue; + if (ex[i].light != 0.0f) { + V.AddLight( + ent.origin, + ex[i].light * ent.alpha, + ex[i].lightcolor[0], + ex[i].lightcolor[1], + ex[i].lightcolor[2]); + } + + VectorCopy(ent.origin, ent.oldorigin); + + if (f < 0) + f = 0; + ent.frame = ex[i].baseframe + f + 1; + ent.oldframe = ex[i].baseframe + f; + ent.backlerp = 1.0f - cl.lerpfrac; + + V.AddEntity(ent); + } + } + + /* + ================= + CL_AddLasers + ================= + */ + static void AddLasers() { + laser_t[] l; + int i; + + l = cl_lasers; + for (i = 0; i < MAX_LASERS; i++) { + if (l[i].endtime >= cl.time) + V.AddEntity(l[i].ent); + } + } + + /* PMM - CL_Sustains */ + static void ProcessSustain() { + cl_sustain_t[] s; + int i; + + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id != 0) + if ((s[i].endtime >= cl.time) && (cl.time >= s[i].nextthink)) { + s[i].think.think(s[i]); + } else if (s[i].endtime < cl.time) + s[i].id = 0; + } + } + + /* + ================= + CL_AddTEnts + ================= + */ + static void AddTEnts() { + CL.AddBeams(); + // PMM - draw plasma beams + CL.AddPlayerBeams(); + CL.AddExplosions(); + CL.AddLasers(); + // PMM - set up sustain + CL.ProcessSustain(); + } +} |