File: client\cl_tent.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 // cl_tent.c -- client side temporary entities
   21 
   22 #include "client.h"
   23 
   24 typedef enum
   25 {
   26         ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
   27 } exptype_t;
   28 
   29 typedef struct
   30 {
   31         exptype_t       type;
   32         entity_t        ent;
   33 
   34         int                     frames;
   35         float           light;
   36         vec3_t          lightcolor;
   37         float           start;
   38         int                     baseframe;
   39 } explosion_t;
   40 
   41 
   42 
   43 #define MAX_EXPLOSIONS  32
   44 explosion_t     cl_explosions[MAX_EXPLOSIONS];
   45 
   46 
   47 #define MAX_BEAMS       32
   48 typedef struct
   49 {
   50         int             entity;
   51         int             dest_entity;
   52         struct model_s  *model;
   53         int             endtime;
   54         vec3_t  offset;
   55         vec3_t  start, end;
   56 } beam_t;
   57 beam_t          cl_beams[MAX_BEAMS];
   58 //PMM - added this for player-linked beams.  Currently only used by the plasma beam
   59 beam_t          cl_playerbeams[MAX_BEAMS];
   60 
   61 
   62 #define MAX_LASERS      32
   63 typedef struct
   64 {
   65         entity_t        ent;
   66         int                     endtime;
   67 } laser_t;
   68 laser_t         cl_lasers[MAX_LASERS];
   69 
   70 //ROGUE
   71 cl_sustain_t    cl_sustains[MAX_SUSTAINS];
   72 //ROGUE
   73 
   74 //PGM
   75 extern void CL_TeleportParticles (vec3_t org);
   76 //PGM
   77 
   78 void CL_BlasterParticles (vec3_t org, vec3_t dir);
   79 void CL_ExplosionParticles (vec3_t org);
   80 void CL_BFGExplosionParticles (vec3_t org);
   81 // RAFAEL
   82 void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
   83 
   84 struct sfx_s    *cl_sfx_ric1;
   85 struct sfx_s    *cl_sfx_ric2;
   86 struct sfx_s    *cl_sfx_ric3;
   87 struct sfx_s    *cl_sfx_lashit;
   88 struct sfx_s    *cl_sfx_spark5;
   89 struct sfx_s    *cl_sfx_spark6;
   90 struct sfx_s    *cl_sfx_spark7;
   91 struct sfx_s    *cl_sfx_railg;
   92 struct sfx_s    *cl_sfx_rockexp;
   93 struct sfx_s    *cl_sfx_grenexp;
   94 struct sfx_s    *cl_sfx_watrexp;
   95 // RAFAEL
   96 struct sfx_s    *cl_sfx_plasexp;
   97 struct sfx_s    *cl_sfx_footsteps[4];
   98 
   99 struct model_s  *cl_mod_explode;
  100 struct model_s  *cl_mod_smoke;
  101 struct model_s  *cl_mod_flash;
  102 struct model_s  *cl_mod_parasite_segment;
  103 struct model_s  *cl_mod_grapple_cable;
  104 struct model_s  *cl_mod_parasite_tip;
  105 struct model_s  *cl_mod_explo4;
  106 struct model_s  *cl_mod_bfg_explo;
  107 struct model_s  *cl_mod_powerscreen;
  108 // RAFAEL
  109 struct model_s  *cl_mod_plasmaexplo;
  110 
  111 //ROGUE
  112 struct sfx_s    *cl_sfx_lightning;
  113 struct sfx_s    *cl_sfx_disrexp;
  114 struct model_s  *cl_mod_lightning;
  115 struct model_s  *cl_mod_heatbeam;
  116 struct model_s  *cl_mod_monster_heatbeam;
  117 struct model_s  *cl_mod_explo4_big;
  118 
  119 //ROGUE
  120 /*
  121 =================
  122 CL_RegisterTEntSounds
  123 =================
  124 */
  125 void CL_RegisterTEntSounds (void)
  126 {
  127         int             i;
  128         char    name[MAX_QPATH];
  129 
  130         // PMM - version stuff
  131 //      Com_Printf ("%s\n", ROGUE_VERSION_STRING);
  132         // PMM
  133         cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
  134         cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
  135         cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
  136         cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
  137         cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
  138         cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
  139         cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
  140         cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
  141         cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
  142         cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
  143         cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
  144         // RAFAEL
  145         // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
  146         S_RegisterSound ("player/land1.wav");
  147 
  148         S_RegisterSound ("player/fall2.wav");
  149         S_RegisterSound ("player/fall1.wav");
  150 
  151         for (i=0 ; i<4 ; i++)
  152         {
  153                 Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
  154                 cl_sfx_footsteps[i] = S_RegisterSound (name);
  155         }
  156 
  157 //PGM
  158         cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
  159         cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
  160         // version stuff
  161 //      sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
  162 //      if (name[0] == 'w')
  163 //              name[0] = 'W';
  164 //PGM
  165 }       
  166 
  167 /*
  168 =================
  169 CL_RegisterTEntModels
  170 =================
  171 */
  172 void CL_RegisterTEntModels (void)
  173 {
  174         cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
  175         cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
  176         cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
  177         cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
  178         cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
  179         cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
  180         cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
  181         cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
  182         cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
  183 
  184 re.RegisterModel ("models/objects/laser/tris.md2");
  185 re.RegisterModel ("models/objects/grenade2/tris.md2");
  186 re.RegisterModel ("models/weapons/v_machn/tris.md2");
  187 re.RegisterModel ("models/weapons/v_handgr/tris.md2");
  188 re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
  189 re.RegisterModel ("models/objects/gibs/bone/tris.md2");
  190 re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
  191 re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
  192 // RAFAEL
  193 // re.RegisterModel ("models/objects/blaser/tris.md2");
  194 
  195 re.RegisterPic ("w_machinegun");
  196 re.RegisterPic ("a_bullets");
  197 re.RegisterPic ("i_health");
  198 re.RegisterPic ("a_grenades");
  199 
  200 //ROGUE
  201         cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
  202         cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
  203         cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
  204         cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
  205 //ROGUE
  206 }       
  207 
  208 /*
  209 =================
  210 CL_ClearTEnts
  211 =================
  212 */
  213 void CL_ClearTEnts (void)
  214 {
  215         memset (cl_beams, 0, sizeof(cl_beams));
  216         memset (cl_explosions, 0, sizeof(cl_explosions));
  217         memset (cl_lasers, 0, sizeof(cl_lasers));
  218 
  219 //ROGUE
  220         memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
  221         memset (cl_sustains, 0, sizeof(cl_sustains));
  222 //ROGUE
  223 }
  224 
  225 /*
  226 =================
  227 CL_AllocExplosion
  228 =================
  229 */
  230 explosion_t *CL_AllocExplosion (void)
  231 {
  232         int             i;
  233         int             time;
  234         int             index;
  235         
  236         for (i=0 ; i<MAX_EXPLOSIONS ; i++)
  237         {
  238                 if (cl_explosions[i].type == ex_free)
  239                 {
  240                         memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
  241                         return &cl_explosions[i];
  242                 }
  243         }
  244 // find the oldest explosion
  245         time = cl.time;
  246         index = 0;
  247 
  248         for (i=0 ; i<MAX_EXPLOSIONS ; i++)
  249                 if (cl_explosions[i].start < time)
  250                 {
  251                         time = cl_explosions[i].start;
  252                         index = i;
  253                 }
  254         memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
  255         return &cl_explosions[index];
  256 }
  257 
  258 /*
  259 =================
  260 CL_SmokeAndFlash
  261 =================
  262 */
  263 void CL_SmokeAndFlash(vec3_t origin)
  264 {
  265         explosion_t     *ex;
  266 
  267         ex = CL_AllocExplosion ();
  268         VectorCopy (origin, ex->ent.origin);
  269         ex->type = ex_misc;
  270         ex->frames = 4;
  271         ex->ent.flags = RF_TRANSLUCENT;
  272         ex->start = cl.frame.servertime - 100;
  273         ex->ent.model = cl_mod_smoke;
  274 
  275         ex = CL_AllocExplosion ();
  276         VectorCopy (origin, ex->ent.origin);
  277         ex->type = ex_flash;
  278         ex->ent.flags = RF_FULLBRIGHT;
  279         ex->frames = 2;
  280         ex->start = cl.frame.servertime - 100;
  281         ex->ent.model = cl_mod_flash;
  282 }
  283 
  284 /*
  285 =================
  286 CL_ParseParticles
  287 =================
  288 */
  289 void CL_ParseParticles (void)
  290 {
  291         int             color, count;
  292         vec3_t  pos, dir;
  293 
  294         MSG_ReadPos (&net_message, pos);
  295         MSG_ReadDir (&net_message, dir);
  296 
  297         color = MSG_ReadByte (&net_message);
  298 
  299         count = MSG_ReadByte (&net_message);
  300 
  301         CL_ParticleEffect (pos, dir, color, count);
  302 }
  303 
  304 /*
  305 =================
  306 CL_ParseBeam
  307 =================
  308 */
  309 int CL_ParseBeam (struct model_s *model)
  310 {
  311         int             ent;
  312         vec3_t  start, end;
  313         beam_t  *b;
  314         int             i;
  315         
  316         ent = MSG_ReadShort (&net_message);
  317         
  318         MSG_ReadPos (&net_message, start);
  319         MSG_ReadPos (&net_message, end);
  320 
  321 // override any beam with the same entity
  322         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  323                 if (b->entity == ent)
  324                 {
  325                         b->entity = ent;
  326                         b->model = model;
  327                         b->endtime = cl.time + 200;
  328                         VectorCopy (start, b->start);
  329                         VectorCopy (end, b->end);
  330                         VectorClear (b->offset);
  331                         return ent;
  332                 }
  333 
  334 // find a free beam
  335         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  336         {
  337                 if (!b->model || b->endtime < cl.time)
  338                 {
  339                         b->entity = ent;
  340                         b->model = model;
  341                         b->endtime = cl.time + 200;
  342                         VectorCopy (start, b->start);
  343                         VectorCopy (end, b->end);
  344                         VectorClear (b->offset);
  345                         return ent;
  346                 }
  347         }
  348         Com_Printf ("beam list overflow!\n");   
  349         return ent;
  350 }
  351 
  352 /*
  353 =================
  354 CL_ParseBeam2
  355 =================
  356 */
  357 int CL_ParseBeam2 (struct model_s *model)
  358 {
  359         int             ent;
  360         vec3_t  start, end, offset;
  361         beam_t  *b;
  362         int             i;
  363         
  364         ent = MSG_ReadShort (&net_message);
  365         
  366         MSG_ReadPos (&net_message, start);
  367         MSG_ReadPos (&net_message, end);
  368         MSG_ReadPos (&net_message, offset);
  369 
  370 //      Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
  371 
  372 // override any beam with the same entity
  373 
  374         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  375                 if (b->entity == ent)
  376                 {
  377                         b->entity = ent;
  378                         b->model = model;
  379                         b->endtime = cl.time + 200;
  380                         VectorCopy (start, b->start);
  381                         VectorCopy (end, b->end);
  382                         VectorCopy (offset, b->offset);
  383                         return ent;
  384                 }
  385 
  386 // find a free beam
  387         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  388         {
  389                 if (!b->model || b->endtime < cl.time)
  390                 {
  391                         b->entity = ent;
  392                         b->model = model;
  393                         b->endtime = cl.time + 200;     
  394                         VectorCopy (start, b->start);
  395                         VectorCopy (end, b->end);
  396                         VectorCopy (offset, b->offset);
  397                         return ent;
  398                 }
  399         }
  400         Com_Printf ("beam list overflow!\n");   
  401         return ent;
  402 }
  403 
  404 // ROGUE
  405 /*
  406 =================
  407 CL_ParsePlayerBeam
  408   - adds to the cl_playerbeam array instead of the cl_beams array
  409 =================
  410 */
  411 int CL_ParsePlayerBeam (struct model_s *model)
  412 {
  413         int             ent;
  414         vec3_t  start, end, offset;
  415         beam_t  *b;
  416         int             i;
  417         
  418         ent = MSG_ReadShort (&net_message);
  419         
  420         MSG_ReadPos (&net_message, start);
  421         MSG_ReadPos (&net_message, end);
  422         // PMM - network optimization
  423         if (model == cl_mod_heatbeam)
  424                 VectorSet(offset, 2, 7, -3);
  425         else if (model == cl_mod_monster_heatbeam)
  426         {
  427                 model = cl_mod_heatbeam;
  428                 VectorSet(offset, 0, 0, 0);
  429         }
  430         else
  431                 MSG_ReadPos (&net_message, offset);
  432 
  433 //      Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
  434 
  435 // override any beam with the same entity
  436 // PMM - For player beams, we only want one per player (entity) so..
  437         for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
  438         {
  439                 if (b->entity == ent)
  440                 {
  441                         b->entity = ent;
  442                         b->model = model;
  443                         b->endtime = cl.time + 200;
  444                         VectorCopy (start, b->start);
  445                         VectorCopy (end, b->end);
  446                         VectorCopy (offset, b->offset);
  447                         return ent;
  448                 }
  449         }
  450 
  451 // find a free beam
  452         for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
  453         {
  454                 if (!b->model || b->endtime < cl.time)
  455                 {
  456                         b->entity = ent;
  457                         b->model = model;
  458                         b->endtime = cl.time + 100;             // PMM - this needs to be 100 to prevent multiple heatbeams
  459                         VectorCopy (start, b->start);
  460                         VectorCopy (end, b->end);
  461                         VectorCopy (offset, b->offset);
  462                         return ent;
  463                 }
  464         }
  465         Com_Printf ("beam list overflow!\n");   
  466         return ent;
  467 }
  468 //rogue
  469 
  470 /*
  471 =================
  472 CL_ParseLightning
  473 =================
  474 */
  475 int CL_ParseLightning (struct model_s *model)
  476 {
  477         int             srcEnt, destEnt;
  478         vec3_t  start, end;
  479         beam_t  *b;
  480         int             i;
  481         
  482         srcEnt = MSG_ReadShort (&net_message);
  483         destEnt = MSG_ReadShort (&net_message);
  484 
  485         MSG_ReadPos (&net_message, start);
  486         MSG_ReadPos (&net_message, end);
  487 
  488 // override any beam with the same source AND destination entities
  489         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  490                 if (b->entity == srcEnt && b->dest_entity == destEnt)
  491                 {
  492 //                      Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
  493                         b->entity = srcEnt;
  494                         b->dest_entity = destEnt;
  495                         b->model = model;
  496                         b->endtime = cl.time + 200;
  497                         VectorCopy (start, b->start);
  498                         VectorCopy (end, b->end);
  499                         VectorClear (b->offset);
  500                         return srcEnt;
  501                 }
  502 
  503 // find a free beam
  504         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
  505         {
  506                 if (!b->model || b->endtime < cl.time)
  507                 {
  508 //                      Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
  509                         b->entity = srcEnt;
  510                         b->dest_entity = destEnt;
  511                         b->model = model;
  512                         b->endtime = cl.time + 200;
  513                         VectorCopy (start, b->start);
  514                         VectorCopy (end, b->end);
  515                         VectorClear (b->offset);
  516                         return srcEnt;
  517                 }
  518         }
  519         Com_Printf ("beam list overflow!\n");   
  520         return srcEnt;
  521 }
  522 
  523 /*
  524 =================
  525 CL_ParseLaser
  526 =================
  527 */
  528 void CL_ParseLaser (int colors)
  529 {
  530         vec3_t  start;
  531         vec3_t  end;
  532         laser_t *l;
  533         int             i;
  534 
  535         MSG_ReadPos (&net_message, start);
  536         MSG_ReadPos (&net_message, end);
  537 
  538         for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
  539         {
  540                 if (l->endtime < cl.time)
  541                 {
  542                         l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
  543                         VectorCopy (start, l->ent.origin);
  544                         VectorCopy (end, l->ent.oldorigin);
  545                         l->ent.alpha = 0.30;
  546                         l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
  547                         l->ent.model = NULL;
  548                         l->ent.frame = 4;
  549                         l->endtime = cl.time + 100;
  550                         return;
  551                 }
  552         }
  553 }
  554 
  555 //=============
  556 //ROGUE
  557 void CL_ParseSteam (void)
  558 {
  559         vec3_t  pos, dir;
  560         int             id, i;
  561         int             r;
  562         int             cnt;
  563         int             color;
  564         int             magnitude;
  565         cl_sustain_t    *s, *free_sustain;
  566 
  567         id = MSG_ReadShort (&net_message);              // an id of -1 is an instant effect
  568         if (id != -1) // sustains
  569         {
  570 //                      Com_Printf ("Sustain effect id %d\n", id);
  571                 free_sustain = NULL;
  572                 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
  573                 {
  574                         if (s->id == 0)
  575                         {
  576                                 free_sustain = s;
  577                                 break;
  578                         }
  579                 }
  580                 if (free_sustain)
  581                 {
  582                         s->id = id;
  583                         s->count = MSG_ReadByte (&net_message);
  584                         MSG_ReadPos (&net_message, s->org);
  585                         MSG_ReadDir (&net_message, s->dir);
  586                         r = MSG_ReadByte (&net_message);
  587                         s->color = r & 0xff;
  588                         s->magnitude = MSG_ReadShort (&net_message);
  589                         s->endtime = cl.time + MSG_ReadLong (&net_message);
  590                         s->think = CL_ParticleSteamEffect2;
  591                         s->thinkinterval = 100;
  592                         s->nextthink = cl.time;
  593                 }
  594                 else
  595                 {
  596 //                              Com_Printf ("No free sustains!\n");
  597                         // FIXME - read the stuff anyway
  598                         cnt = MSG_ReadByte (&net_message);
  599                         MSG_ReadPos (&net_message, pos);
  600                         MSG_ReadDir (&net_message, dir);
  601                         r = MSG_ReadByte (&net_message);
  602                         magnitude = MSG_ReadShort (&net_message);
  603                         magnitude = MSG_ReadLong (&net_message); // really interval
  604                 }
  605         }
  606         else // instant
  607         {
  608                 cnt = MSG_ReadByte (&net_message);
  609                 MSG_ReadPos (&net_message, pos);
  610                 MSG_ReadDir (&net_message, dir);
  611                 r = MSG_ReadByte (&net_message);
  612                 magnitude = MSG_ReadShort (&net_message);
  613                 color = r & 0xff;
  614                 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
  615 //              S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
  616         }
  617 }
  618 
  619 void CL_ParseWidow (void)
  620 {
  621         vec3_t  pos;
  622         int             id, i;
  623         cl_sustain_t    *s, *free_sustain;
  624 
  625         id = MSG_ReadShort (&net_message);
  626 
  627         free_sustain = NULL;
  628         for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
  629         {
  630                 if (s->id == 0)
  631                 {
  632                         free_sustain = s;
  633                         break;
  634                 }
  635         }
  636         if (free_sustain)
  637         {
  638                 s->id = id;
  639                 MSG_ReadPos (&net_message, s->org);
  640                 s->endtime = cl.time + 2100;
  641                 s->think = CL_Widowbeamout;
  642                 s->thinkinterval = 1;
  643                 s->nextthink = cl.time;
  644         }
  645         else // no free sustains
  646         {
  647                 // FIXME - read the stuff anyway
  648                 MSG_ReadPos (&net_message, pos);
  649         }
  650 }
  651 
  652 void CL_ParseNuke (void)
  653 {
  654         vec3_t  pos;
  655         int             i;
  656         cl_sustain_t    *s, *free_sustain;
  657 
  658         free_sustain = NULL;
  659         for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
  660         {
  661                 if (s->id == 0)
  662                 {
  663                         free_sustain = s;
  664                         break;
  665                 }
  666         }
  667         if (free_sustain)
  668         {
  669                 s->id = 21000;
  670                 MSG_ReadPos (&net_message, s->org);
  671                 s->endtime = cl.time + 1000;
  672                 s->think = CL_Nukeblast;
  673                 s->thinkinterval = 1;
  674                 s->nextthink = cl.time;
  675         }
  676         else // no free sustains
  677         {
  678                 // FIXME - read the stuff anyway
  679                 MSG_ReadPos (&net_message, pos);
  680         }
  681 }
  682 
  683 //ROGUE
  684 //=============
  685 
  686 
  687 /*
  688 =================
  689 CL_ParseTEnt
  690 =================
  691 */
  692 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
  693 
  694 void CL_ParseTEnt (void)
  695 {
  696         int             type;
  697         vec3_t  pos, pos2, dir;
  698         explosion_t     *ex;
  699         int             cnt;
  700         int             color;
  701         int             r;
  702         int             ent;
  703         int             magnitude;
  704 
  705         type = MSG_ReadByte (&net_message);
  706 
  707         switch (type)
  708         {
  709         case TE_BLOOD:                  // bullet hitting flesh
  710                 MSG_ReadPos (&net_message, pos);
  711                 MSG_ReadDir (&net_message, dir);
  712                 CL_ParticleEffect (pos, dir, 0xe8, 60);
  713                 break;
  714 
  715         case TE_GUNSHOT:                        // bullet hitting wall
  716         case TE_SPARKS:
  717         case TE_BULLET_SPARKS:
  718                 MSG_ReadPos (&net_message, pos);
  719                 MSG_ReadDir (&net_message, dir);
  720                 if (type == TE_GUNSHOT)
  721                         CL_ParticleEffect (pos, dir, 0, 40);
  722                 else
  723                         CL_ParticleEffect (pos, dir, 0xe0, 6);
  724 
  725                 if (type != TE_SPARKS)
  726                 {
  727                         CL_SmokeAndFlash(pos);
  728                         
  729                         // impact sound
  730                         cnt = rand()&15;
  731                         if (cnt == 1)
  732                                 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
  733                         else if (cnt == 2)
  734                                 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
  735                         else if (cnt == 3)
  736                                 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
  737                 }
  738 
  739                 break;
  740                 
  741         case TE_SCREEN_SPARKS:
  742         case TE_SHIELD_SPARKS:
  743                 MSG_ReadPos (&net_message, pos);
  744                 MSG_ReadDir (&net_message, dir);
  745                 if (type == TE_SCREEN_SPARKS)
  746                         CL_ParticleEffect (pos, dir, 0xd0, 40);
  747                 else
  748                         CL_ParticleEffect (pos, dir, 0xb0, 40);
  749                 //FIXME : replace or remove this sound
  750                 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
  751                 break;
  752                 
  753         case TE_SHOTGUN:                        // bullet hitting wall
  754                 MSG_ReadPos (&net_message, pos);
  755                 MSG_ReadDir (&net_message, dir);
  756                 CL_ParticleEffect (pos, dir, 0, 20);
  757                 CL_SmokeAndFlash(pos);
  758                 break;
  759 
  760         case TE_SPLASH:                 // bullet hitting water
  761                 cnt = MSG_ReadByte (&net_message);
  762                 MSG_ReadPos (&net_message, pos);
  763                 MSG_ReadDir (&net_message, dir);
  764                 r = MSG_ReadByte (&net_message);
  765                 if (r > 6)
  766                         color = 0x00;
  767                 else
  768                         color = splash_color[r];
  769                 CL_ParticleEffect (pos, dir, color, cnt);
  770 
  771                 if (r == SPLASH_SPARKS)
  772                 {
  773                         r = rand() & 3;
  774                         if (r == 0)
  775                                 S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
  776                         else if (r == 1)
  777                                 S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
  778                         else
  779                                 S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
  780                 }
  781                 break;
  782 
  783         case TE_LASER_SPARKS:
  784                 cnt = MSG_ReadByte (&net_message);
  785                 MSG_ReadPos (&net_message, pos);
  786                 MSG_ReadDir (&net_message, dir);
  787                 color = MSG_ReadByte (&net_message);
  788                 CL_ParticleEffect2 (pos, dir, color, cnt);
  789                 break;
  790 
  791         // RAFAEL
  792         case TE_BLUEHYPERBLASTER:
  793                 MSG_ReadPos (&net_message, pos);
  794                 MSG_ReadPos (&net_message, dir);
  795                 CL_BlasterParticles (pos, dir);
  796                 break;
  797 
  798         case TE_BLASTER:                        // blaster hitting wall
  799                 MSG_ReadPos (&net_message, pos);
  800                 MSG_ReadDir (&net_message, dir);
  801                 CL_BlasterParticles (pos, dir);
  802 
  803                 ex = CL_AllocExplosion ();
  804                 VectorCopy (pos, ex->ent.origin);
  805                 ex->ent.angles[0] = acos(dir[2])/M_PI*180;
  806         // PMM - fixed to correct for pitch of 0
  807                 if (dir[0])
  808                         ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
  809                 else if (dir[1] > 0)
  810                         ex->ent.angles[1] = 90;
  811                 else if (dir[1] < 0)
  812                         ex->ent.angles[1] = 270;
  813                 else
  814                         ex->ent.angles[1] = 0;
  815 
  816                 ex->type = ex_misc;
  817                 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
  818                 ex->start = cl.frame.servertime - 100;
  819                 ex->light = 150;
  820                 ex->lightcolor[0] = 1;
  821                 ex->lightcolor[1] = 1;
  822                 ex->ent.model = cl_mod_explode;
  823                 ex->frames = 4;
  824                 S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
  825                 break;
  826                 
  827         case TE_RAILTRAIL:                      // railgun effect
  828                 MSG_ReadPos (&net_message, pos);
  829                 MSG_ReadPos (&net_message, pos2);
  830                 CL_RailTrail (pos, pos2);
  831                 S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
  832                 break;
  833 
  834         case TE_EXPLOSION2:
  835         case TE_GRENADE_EXPLOSION:
  836         case TE_GRENADE_EXPLOSION_WATER:
  837                 MSG_ReadPos (&net_message, pos);
  838 
  839                 ex = CL_AllocExplosion ();
  840                 VectorCopy (pos, ex->ent.origin);
  841                 ex->type = ex_poly;
  842                 ex->ent.flags = RF_FULLBRIGHT;
  843                 ex->start = cl.frame.servertime - 100;
  844                 ex->light = 350;
  845                 ex->lightcolor[0] = 1.0;
  846                 ex->lightcolor[1] = 0.5;
  847                 ex->lightcolor[2] = 0.5;
  848                 ex->ent.model = cl_mod_explo4;
  849                 ex->frames = 19;
  850                 ex->baseframe = 30;
  851                 ex->ent.angles[1] = rand() % 360;
  852                 CL_ExplosionParticles (pos);
  853                 if (type == TE_GRENADE_EXPLOSION_WATER)
  854                         S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
  855                 else
  856                         S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
  857                 break;
  858 
  859         // RAFAEL
  860         case TE_PLASMA_EXPLOSION:
  861                 MSG_ReadPos (&net_message, pos);
  862                 ex = CL_AllocExplosion ();
  863                 VectorCopy (pos, ex->ent.origin);
  864                 ex->type = ex_poly;
  865                 ex->ent.flags = RF_FULLBRIGHT;
  866                 ex->start = cl.frame.servertime - 100;
  867                 ex->light = 350;
  868                 ex->lightcolor[0] = 1.0; 
  869                 ex->lightcolor[1] = 0.5;
  870                 ex->lightcolor[2] = 0.5;
  871                 ex->ent.angles[1] = rand() % 360;
  872                 ex->ent.model = cl_mod_explo4;
  873                 if (frand() < 0.5)
  874                         ex->baseframe = 15;
  875                 ex->frames = 15;
  876                 CL_ExplosionParticles (pos);
  877                 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
  878                 break;
  879         
  880         case TE_EXPLOSION1:
  881         case TE_EXPLOSION1_BIG:                                         // PMM
  882         case TE_ROCKET_EXPLOSION:
  883         case TE_ROCKET_EXPLOSION_WATER:
  884         case TE_EXPLOSION1_NP:                                          // PMM
  885                 MSG_ReadPos (&net_message, pos);
  886 
  887                 ex = CL_AllocExplosion ();
  888                 VectorCopy (pos, ex->ent.origin);
  889                 ex->type = ex_poly;
  890                 ex->ent.flags = RF_FULLBRIGHT;
  891                 ex->start = cl.frame.servertime - 100;
  892                 ex->light = 350;
  893                 ex->lightcolor[0] = 1.0;
  894                 ex->lightcolor[1] = 0.5;
  895                 ex->lightcolor[2] = 0.5;
  896                 ex->ent.angles[1] = rand() % 360;
  897                 if (type != TE_EXPLOSION1_BIG)                          // PMM
  898                         ex->ent.model = cl_mod_explo4;                  // PMM
  899                 else
  900                         ex->ent.model = cl_mod_explo4_big;
  901                 if (frand() < 0.5)
  902                         ex->baseframe = 15;
  903                 ex->frames = 15;
  904                 if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))          // PMM
  905                         CL_ExplosionParticles (pos);                                                                    // PMM
  906                 if (type == TE_ROCKET_EXPLOSION_WATER)
  907                         S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
  908                 else
  909                         S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
  910                 break;
  911 
  912         case TE_BFG_EXPLOSION:
  913                 MSG_ReadPos (&net_message, pos);
  914                 ex = CL_AllocExplosion ();
  915                 VectorCopy (pos, ex->ent.origin);
  916                 ex->type = ex_poly;
  917                 ex->ent.flags = RF_FULLBRIGHT;
  918                 ex->start = cl.frame.servertime - 100;
  919                 ex->light = 350;
  920                 ex->lightcolor[0] = 0.0;
  921                 ex->lightcolor[1] = 1.0;
  922                 ex->lightcolor[2] = 0.0;
  923                 ex->ent.model = cl_mod_bfg_explo;
  924                 ex->ent.flags |= RF_TRANSLUCENT;
  925                 ex->ent.alpha = 0.30;
  926                 ex->frames = 4;
  927                 break;
  928 
  929         case TE_BFG_BIGEXPLOSION:
  930                 MSG_ReadPos (&net_message, pos);
  931                 CL_BFGExplosionParticles (pos);
  932                 break;
  933 
  934         case TE_BFG_LASER:
  935                 CL_ParseLaser (0xd0d1d2d3);
  936                 break;
  937 
  938         case TE_BUBBLETRAIL:
  939                 MSG_ReadPos (&net_message, pos);
  940                 MSG_ReadPos (&net_message, pos2);
  941                 CL_BubbleTrail (pos, pos2);
  942                 break;
  943 
  944         case TE_PARASITE_ATTACK:
  945         case TE_MEDIC_CABLE_ATTACK:
  946                 ent = CL_ParseBeam (cl_mod_parasite_segment);
  947                 break;
  948 
  949         case TE_BOSSTPORT:                      // boss teleporting to station
  950                 MSG_ReadPos (&net_message, pos);
  951                 CL_BigTeleportParticles (pos);
  952                 S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
  953                 break;
  954 
  955         case TE_GRAPPLE_CABLE:
  956                 ent = CL_ParseBeam2 (cl_mod_grapple_cable);
  957                 break;
  958 
  959         // RAFAEL
  960         case TE_WELDING_SPARKS:
  961                 cnt = MSG_ReadByte (&net_message);
  962                 MSG_ReadPos (&net_message, pos);
  963                 MSG_ReadDir (&net_message, dir);
  964                 color = MSG_ReadByte (&net_message);
  965                 CL_ParticleEffect2 (pos, dir, color, cnt);
  966 
  967                 ex = CL_AllocExplosion ();
  968                 VectorCopy (pos, ex->ent.origin);
  969                 ex->type = ex_flash;
  970                 // note to self
  971                 // we need a better no draw flag
  972                 ex->ent.flags = RF_BEAM;
  973                 ex->start = cl.frame.servertime - 0.1;
  974                 ex->light = 100 + (rand()%75);
  975                 ex->lightcolor[0] = 1.0;
  976                 ex->lightcolor[1] = 1.0;
  977                 ex->lightcolor[2] = 0.3;
  978                 ex->ent.model = cl_mod_flash;
  979                 ex->frames = 2;
  980                 break;
  981 
  982         case TE_GREENBLOOD:
  983                 MSG_ReadPos (&net_message, pos);
  984                 MSG_ReadDir (&net_message, dir);
  985                 CL_ParticleEffect2 (pos, dir, 0xdf, 30);
  986                 break;
  987 
  988         // RAFAEL
  989         case TE_TUNNEL_SPARKS:
  990                 cnt = MSG_ReadByte (&net_message);
  991                 MSG_ReadPos (&net_message, pos);
  992                 MSG_ReadDir (&net_message, dir);
  993                 color = MSG_ReadByte (&net_message);
  994                 CL_ParticleEffect3 (pos, dir, color, cnt);
  995                 break;
  996 
  997 //=============
  998 //PGM
  999                 // PMM -following code integrated for flechette (different color)
 1000         case TE_BLASTER2:                       // green blaster hitting wall
 1001         case TE_FLECHETTE:                      // flechette
 1002                 MSG_ReadPos (&net_message, pos);
 1003                 MSG_ReadDir (&net_message, dir);
 1004                 
 1005                 // PMM
 1006                 if (type == TE_BLASTER2)
 1007                         CL_BlasterParticles2 (pos, dir, 0xd0);
 1008                 else
 1009                         CL_BlasterParticles2 (pos, dir, 0x6f); // 75
 1010 
 1011                 ex = CL_AllocExplosion ();
 1012                 VectorCopy (pos, ex->ent.origin);
 1013                 ex->ent.angles[0] = acos(dir[2])/M_PI*180;
 1014         // PMM - fixed to correct for pitch of 0
 1015                 if (dir[0])
 1016                         ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
 1017                 else if (dir[1] > 0)
 1018                         ex->ent.angles[1] = 90;
 1019                 else if (dir[1] < 0)
 1020                         ex->ent.angles[1] = 270;
 1021                 else
 1022                         ex->ent.angles[1] = 0;
 1023 
 1024                 ex->type = ex_misc;
 1025                 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
 1026 
 1027                 // PMM
 1028                 if (type == TE_BLASTER2)
 1029                         ex->ent.skinnum = 1;
 1030                 else // flechette
 1031                         ex->ent.skinnum = 2;
 1032 
 1033                 ex->start = cl.frame.servertime - 100;
 1034                 ex->light = 150;
 1035                 // PMM
 1036                 if (type == TE_BLASTER2)
 1037                         ex->lightcolor[1] = 1;
 1038                 else // flechette
 1039                 {
 1040                         ex->lightcolor[0] = 0.19;
 1041                         ex->lightcolor[1] = 0.41;
 1042                         ex->lightcolor[2] = 0.75;
 1043                 }
 1044                 ex->ent.model = cl_mod_explode;
 1045                 ex->frames = 4;
 1046                 S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
 1047                 break;
 1048 
 1049 
 1050         case TE_LIGHTNING:
 1051                 ent = CL_ParseLightning (cl_mod_lightning);
 1052                 S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
 1053                 break;
 1054 
 1055         case TE_DEBUGTRAIL:
 1056                 MSG_ReadPos (&net_message, pos);
 1057                 MSG_ReadPos (&net_message, pos2);
 1058                 CL_DebugTrail (pos, pos2);
 1059                 break;
 1060 
 1061         case TE_PLAIN_EXPLOSION:
 1062                 MSG_ReadPos (&net_message, pos);
 1063 
 1064                 ex = CL_AllocExplosion ();
 1065                 VectorCopy (pos, ex->ent.origin);
 1066                 ex->type = ex_poly;
 1067                 ex->ent.flags = RF_FULLBRIGHT;
 1068                 ex->start = cl.frame.servertime - 100;
 1069                 ex->light = 350;
 1070                 ex->lightcolor[0] = 1.0;
 1071                 ex->lightcolor[1] = 0.5;
 1072                 ex->lightcolor[2] = 0.5;
 1073                 ex->ent.angles[1] = rand() % 360;
 1074                 ex->ent.model = cl_mod_explo4;
 1075                 if (frand() < 0.5)
 1076                         ex->baseframe = 15;
 1077                 ex->frames = 15;
 1078                 if (type == TE_ROCKET_EXPLOSION_WATER)
 1079                         S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
 1080                 else
 1081                         S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
 1082                 break;
 1083 
 1084         case TE_FLASHLIGHT:
 1085                 MSG_ReadPos(&net_message, pos);
 1086                 ent = MSG_ReadShort(&net_message);
 1087                 CL_Flashlight(ent, pos);
 1088                 break;
 1089 
 1090         case TE_FORCEWALL:
 1091                 MSG_ReadPos(&net_message, pos);
 1092                 MSG_ReadPos(&net_message, pos2);
 1093                 color = MSG_ReadByte (&net_message);
 1094                 CL_ForceWall(pos, pos2, color);
 1095                 break;
 1096 
 1097         case TE_HEATBEAM:
 1098                 ent = CL_ParsePlayerBeam (cl_mod_heatbeam);
 1099                 break;
 1100 
 1101         case TE_MONSTER_HEATBEAM:
 1102                 ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam);
 1103                 break;
 1104 
 1105         case TE_HEATBEAM_SPARKS:
 1106 //              cnt = MSG_ReadByte (&net_message);
 1107                 cnt = 50;
 1108                 MSG_ReadPos (&net_message, pos);
 1109                 MSG_ReadDir (&net_message, dir);
 1110 //              r = MSG_ReadByte (&net_message);
 1111 //              magnitude = MSG_ReadShort (&net_message);
 1112                 r = 8;
 1113                 magnitude = 60;
 1114                 color = r & 0xff;
 1115                 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
 1116                 S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
 1117                 break;
 1118         
 1119         case TE_HEATBEAM_STEAM:
 1120 //              cnt = MSG_ReadByte (&net_message);
 1121                 cnt = 20;
 1122                 MSG_ReadPos (&net_message, pos);
 1123                 MSG_ReadDir (&net_message, dir);
 1124 //              r = MSG_ReadByte (&net_message);
 1125 //              magnitude = MSG_ReadShort (&net_message);
 1126 //              color = r & 0xff;
 1127                 color = 0xe0;
 1128                 magnitude = 60;
 1129                 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
 1130                 S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
 1131                 break;
 1132 
 1133         case TE_STEAM:
 1134                 CL_ParseSteam();
 1135                 break;
 1136 
 1137         case TE_BUBBLETRAIL2:
 1138 //              cnt = MSG_ReadByte (&net_message);
 1139                 cnt = 8;
 1140                 MSG_ReadPos (&net_message, pos);
 1141                 MSG_ReadPos (&net_message, pos2);
 1142                 CL_BubbleTrail2 (pos, pos2, cnt);
 1143                 S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
 1144                 break;
 1145 
 1146         case TE_MOREBLOOD:
 1147                 MSG_ReadPos (&net_message, pos);
 1148                 MSG_ReadDir (&net_message, dir);
 1149                 CL_ParticleEffect (pos, dir, 0xe8, 250);
 1150                 break;
 1151 
 1152         case TE_CHAINFIST_SMOKE:
 1153                 dir[0]=0; dir[1]=0; dir[2]=1;
 1154                 MSG_ReadPos(&net_message, pos);
 1155                 CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
 1156                 break;
 1157 
 1158         case TE_ELECTRIC_SPARKS:
 1159                 MSG_ReadPos (&net_message, pos);
 1160                 MSG_ReadDir (&net_message, dir);
 1161 //              CL_ParticleEffect (pos, dir, 109, 40);
 1162                 CL_ParticleEffect (pos, dir, 0x75, 40);
 1163                 //FIXME : replace or remove this sound
 1164                 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
 1165                 break;
 1166 
 1167         case TE_TRACKER_EXPLOSION:
 1168                 MSG_ReadPos (&net_message, pos);
 1169                 CL_ColorFlash (pos, 0, 150, -1, -1, -1);
 1170                 CL_ColorExplosionParticles (pos, 0, 1);
 1171 //              CL_Tracker_Explode (pos);
 1172                 S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
 1173                 break;
 1174 
 1175         case TE_TELEPORT_EFFECT:
 1176         case TE_DBALL_GOAL:
 1177                 MSG_ReadPos (&net_message, pos);
 1178                 CL_TeleportParticles (pos);
 1179                 break;
 1180 
 1181         case TE_WIDOWBEAMOUT:
 1182                 CL_ParseWidow ();
 1183                 break;
 1184 
 1185         case TE_NUKEBLAST:
 1186                 CL_ParseNuke ();
 1187                 break;
 1188 
 1189         case TE_WIDOWSPLASH:
 1190                 MSG_ReadPos (&net_message, pos);
 1191                 CL_WidowSplash (pos);
 1192                 break;
 1193 //PGM
 1194 //==============
 1195 
 1196         default:
 1197                 Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
 1198         }
 1199 }
 1200 
 1201 /*
 1202 =================
 1203 CL_AddBeams
 1204 =================
 1205 */
 1206 void CL_AddBeams (void)
 1207 {
 1208         int                     i,j;
 1209         beam_t          *b;
 1210         vec3_t          dist, org;
 1211         float           d;
 1212         entity_t        ent;
 1213         float           yaw, pitch;
 1214         float           forward;
 1215         float           len, steps;
 1216         float           model_length;
 1217         
 1218 // update beams
 1219         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
 1220         {
 1221                 if (!b->model || b->endtime < cl.time)
 1222                         continue;
 1223 
 1224                 // if coming from the player, update the start position
 1225                 if (b->entity == cl.playernum+1)        // entity 0 is the world
 1226                 {
 1227                         VectorCopy (cl.refdef.vieworg, b->start);
 1228                         b->start[2] -= 22;      // adjust for view height
 1229                 }
 1230                 VectorAdd (b->start, b->offset, org);
 1231 
 1232         // calculate pitch and yaw
 1233                 VectorSubtract (b->end, org, dist);
 1234 
 1235                 if (dist[1] == 0 && dist[0] == 0)
 1236                 {
 1237                         yaw = 0;
 1238                         if (dist[2] > 0)
 1239                                 pitch = 90;
 1240                         else
 1241                                 pitch = 270;
 1242                 }
 1243                 else
 1244                 {
 1245         // PMM - fixed to correct for pitch of 0
 1246                         if (dist[0])
 1247                                 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
 1248                         else if (dist[1] > 0)
 1249                                 yaw = 90;
 1250                         else
 1251                                 yaw = 270;
 1252                         if (yaw < 0)
 1253                                 yaw += 360;
 1254         
 1255                         forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
 1256                         pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
 1257                         if (pitch < 0)
 1258                                 pitch += 360.0;
 1259                 }
 1260 
 1261         // add new entities for the beams
 1262                 d = VectorNormalize(dist);
 1263 
 1264                 memset (&ent, 0, sizeof(ent));
 1265                 if (b->model == cl_mod_lightning)
 1266                 {
 1267                         model_length = 35.0;
 1268                         d-= 20.0;  // correction so it doesn't end in middle of tesla
 1269                 }
 1270                 else
 1271                 {
 1272                         model_length = 30.0;
 1273                 }
 1274                 steps = ceil(d/model_length);
 1275                 len = (d-model_length)/(steps-1);
 1276 
 1277                 // PMM - special case for lightning model .. if the real length is shorter than the model,
 1278                 // flip it around & draw it from the end to the start.  This prevents the model from going
 1279                 // through the tesla mine (instead it goes through the target)
 1280                 if ((b->model == cl_mod_lightning) && (d <= model_length))
 1281                 {
 1282 //                      Com_Printf ("special case\n");
 1283                         VectorCopy (b->end, ent.origin);
 1284                         // offset to push beam outside of tesla model (negative because dist is from end to start
 1285                         // for this beam)
 1286 //                      for (j=0 ; j<3 ; j++)
 1287 //                              ent.origin[j] -= dist[j]*10.0;
 1288                         ent.model = b->model;
 1289                         ent.flags = RF_FULLBRIGHT;
 1290                         ent.angles[0] = pitch;
 1291                         ent.angles[1] = yaw;
 1292                         ent.angles[2] = rand()%360;
 1293                         V_AddEntity (&ent);                     
 1294                         return;
 1295                 }
 1296                 while (d > 0)
 1297                 {
 1298                         VectorCopy (org, ent.origin);
 1299                         ent.model = b->model;
 1300                         if (b->model == cl_mod_lightning)
 1301                         {
 1302                                 ent.flags = RF_FULLBRIGHT;
 1303                                 ent.angles[0] = -pitch;
 1304                                 ent.angles[1] = yaw + 180.0;
 1305                                 ent.angles[2] = rand()%360;
 1306                         }
 1307                         else
 1308                         {
 1309                                 ent.angles[0] = pitch;
 1310                                 ent.angles[1] = yaw;
 1311                                 ent.angles[2] = rand()%360;
 1312                         }
 1313                         
 1314 //                      Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
 1315                         V_AddEntity (&ent);
 1316 
 1317                         for (j=0 ; j<3 ; j++)
 1318                                 org[j] += dist[j]*len;
 1319                         d -= model_length;
 1320                 }
 1321         }
 1322 }
 1323 
 1324 
 1325 /*
 1326 //                              Com_Printf ("Endpoint:  %f %f %f\n", b->end[0], b->end[1], b->end[2]);
 1327 //                              Com_Printf ("Pred View Angles:  %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
 1328 //                              Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
 1329 //                              VectorCopy (cl.predicted_origin, b->start);
 1330 //                              b->start[2] += 22;      // adjust for view height
 1331 //                              if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
 1332 //                                      b->start[2] = cl.refdef.vieworg[2];
 1333 //                              }
 1334 
 1335 //                              Com_Printf ("Time:  %d %d %f\n", cl.time, cls.realtime, cls.frametime);
 1336 */
 1337 
 1338 extern cvar_t *hand;
 1339 
 1340 /*
 1341 =================
 1342 ROGUE - draw player locked beams
 1343 CL_AddPlayerBeams
 1344 =================
 1345 */
 1346 void CL_AddPlayerBeams (void)
 1347 {
 1348         int                     i,j;
 1349         beam_t          *b;
 1350         vec3_t          dist, org;
 1351         float           d;
 1352         entity_t        ent;
 1353         float           yaw, pitch;
 1354         float           forward;
 1355         float           len, steps;
 1356         int                     framenum;
 1357         float           model_length;
 1358         
 1359         float           hand_multiplier;
 1360         frame_t         *oldframe;
 1361         player_state_t  *ps, *ops;
 1362 
 1363 //PMM
 1364         if (hand)
 1365         {
 1366                 if (hand->value == 2)
 1367                         hand_multiplier = 0;
 1368                 else if (hand->value == 1)
 1369                         hand_multiplier = -1;
 1370                 else
 1371                         hand_multiplier = 1;
 1372         }
 1373         else 
 1374         {
 1375                 hand_multiplier = 1;
 1376         }
 1377 //PMM
 1378 
 1379 // update beams
 1380         for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
 1381         {
 1382                 vec3_t          f,r,u;
 1383                 if (!b->model || b->endtime < cl.time)
 1384                         continue;
 1385 
 1386                 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
 1387                 {
 1388 
 1389                         // if coming from the player, update the start position
 1390                         if (b->entity == cl.playernum+1)        // entity 0 is the world
 1391                         {       
 1392                                 // set up gun position
 1393                                 // code straight out of CL_AddViewWeapon
 1394                                 ps = &cl.frame.playerstate;
 1395                                 j = (cl.frame.serverframe - 1) & UPDATE_MASK;
 1396                                 oldframe = &cl.frames[j];
 1397                                 if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
 1398                                         oldframe = &cl.frame;           // previous frame was dropped or involid
 1399                                 ops = &oldframe->playerstate;
 1400                                 for (j=0 ; j<3 ; j++)
 1401                                 {
 1402                                         b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
 1403                                                 + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
 1404                                 }
 1405                                 VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
 1406                                 VectorMA (     org, b->offset[1], cl.v_forward, org);
 1407                                 VectorMA (     org, b->offset[2], cl.v_up, org);
 1408                                 if ((hand) && (hand->value == 2)) {
 1409                                         VectorMA (org, -1, cl.v_up, org);
 1410                                 }
 1411                                 // FIXME - take these out when final
 1412                                 VectorCopy (cl.v_right, r);
 1413                                 VectorCopy (cl.v_forward, f);
 1414                                 VectorCopy (cl.v_up, u);
 1415 
 1416                         }
 1417                         else
 1418                                 VectorCopy (b->start, org);
 1419                 }
 1420                 else
 1421                 {
 1422                         // if coming from the player, update the start position
 1423                         if (b->entity == cl.playernum+1)        // entity 0 is the world
 1424                         {
 1425                                 VectorCopy (cl.refdef.vieworg, b->start);
 1426                                 b->start[2] -= 22;      // adjust for view height
 1427                         }
 1428                         VectorAdd (b->start, b->offset, org);
 1429                 }
 1430 
 1431         // calculate pitch and yaw
 1432                 VectorSubtract (b->end, org, dist);
 1433 
 1434 //PMM
 1435                 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
 1436                 {
 1437                         vec_t len;
 1438 
 1439                         len = VectorLength (dist);
 1440                         VectorScale (f, len, dist);
 1441                         VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
 1442                         VectorMA (dist, b->offset[1], f, dist);
 1443                         VectorMA (dist, b->offset[2], u, dist);
 1444                         if ((hand) && (hand->value == 2)) {
 1445                                 VectorMA (org, -1, cl.v_up, org);
 1446                         }
 1447                 }
 1448 //PMM
 1449 
 1450                 if (dist[1] == 0 && dist[0] == 0)
 1451                 {
 1452                         yaw = 0;
 1453                         if (dist[2] > 0)
 1454                                 pitch = 90;
 1455                         else
 1456                                 pitch = 270;
 1457                 }
 1458                 else
 1459                 {
 1460         // PMM - fixed to correct for pitch of 0
 1461                         if (dist[0])
 1462                                 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
 1463                         else if (dist[1] > 0)
 1464                                 yaw = 90;
 1465                         else
 1466                                 yaw = 270;
 1467                         if (yaw < 0)
 1468                                 yaw += 360;
 1469         
 1470                         forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
 1471                         pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
 1472                         if (pitch < 0)
 1473                                 pitch += 360.0;
 1474                 }
 1475                 
 1476                 if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
 1477                 {
 1478                         if (b->entity != cl.playernum+1)
 1479                         {
 1480                                 framenum = 2;
 1481 //                              Com_Printf ("Third person\n");
 1482                                 ent.angles[0] = -pitch;
 1483                                 ent.angles[1] = yaw + 180.0;
 1484                                 ent.angles[2] = 0;
 1485 //                              Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
 1486                                 AngleVectors(ent.angles, f, r, u);
 1487                                         
 1488                                 // if it's a non-origin offset, it's a player, so use the hardcoded player offset
 1489                                 if (!VectorCompare (b->offset, vec3_origin))
 1490                                 {
 1491                                         VectorMA (org, -(b->offset[0])+1, r, org);
 1492                                         VectorMA (org, -(b->offset[1]), f, org);
 1493                                         VectorMA (org, -(b->offset[2])-10, u, org);
 1494                                 }
 1495                                 else
 1496                                 {
 1497                                         // if it's a monster, do the particle effect
 1498                                         CL_MonsterPlasma_Shell(b->start);
 1499                                 }
 1500                         }
 1501                         else
 1502                         {
 1503                                 framenum = 1;
 1504                         }
 1505                 }
 1506 
 1507                 // if it's the heatbeam, draw the particle effect
 1508                 if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
 1509                 {
 1510                         CL_Heatbeam (org, dist);
 1511                 }
 1512 
 1513         // add new entities for the beams
 1514                 d = VectorNormalize(dist);
 1515 
 1516                 memset (&ent, 0, sizeof(ent));
 1517                 if (b->model == cl_mod_heatbeam)
 1518                 {
 1519                         model_length = 32.0;
 1520                 }
 1521                 else if (b->model == cl_mod_lightning)
 1522                 {
 1523                         model_length = 35.0;
 1524                         d-= 20.0;  // correction so it doesn't end in middle of tesla
 1525                 }
 1526                 else
 1527                 {
 1528                         model_length = 30.0;
 1529                 }
 1530                 steps = ceil(d/model_length);
 1531                 len = (d-model_length)/(steps-1);
 1532 
 1533                 // PMM - special case for lightning model .. if the real length is shorter than the model,
 1534                 // flip it around & draw it from the end to the start.  This prevents the model from going
 1535                 // through the tesla mine (instead it goes through the target)
 1536                 if ((b->model == cl_mod_lightning) && (d <= model_length))
 1537                 {
 1538 //                      Com_Printf ("special case\n");
 1539                         VectorCopy (b->end, ent.origin);
 1540                         // offset to push beam outside of tesla model (negative because dist is from end to start
 1541                         // for this beam)
 1542 //                      for (j=0 ; j<3 ; j++)
 1543 //                              ent.origin[j] -= dist[j]*10.0;
 1544                         ent.model = b->model;
 1545                         ent.flags = RF_FULLBRIGHT;
 1546                         ent.angles[0] = pitch;
 1547                         ent.angles[1] = yaw;
 1548                         ent.angles[2] = rand()%360;
 1549                         V_AddEntity (&ent);                     
 1550                         return;
 1551                 }
 1552                 while (d > 0)
 1553                 {
 1554                         VectorCopy (org, ent.origin);
 1555                         ent.model = b->model;
 1556                         if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
 1557                         {
 1558 //                              ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
 1559 //                              ent.alpha = 0.3;
 1560                                 ent.flags = RF_FULLBRIGHT;
 1561                                 ent.angles[0] = -pitch;
 1562                                 ent.angles[1] = yaw + 180.0;
 1563                                 ent.angles[2] = (cl.time) % 360;
 1564 //                              ent.angles[2] = rand()%360;
 1565                                 ent.frame = framenum;
 1566                         }
 1567                         else if (b->model == cl_mod_lightning)
 1568                         {
 1569                                 ent.flags = RF_FULLBRIGHT;
 1570                                 ent.angles[0] = -pitch;
 1571                                 ent.angles[1] = yaw + 180.0;
 1572                                 ent.angles[2] = rand()%360;
 1573                         }
 1574                         else
 1575                         {
 1576                                 ent.angles[0] = pitch;
 1577                                 ent.angles[1] = yaw;
 1578                                 ent.angles[2] = rand()%360;
 1579                         }
 1580                         
 1581 //                      Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
 1582                         V_AddEntity (&ent);
 1583 
 1584                         for (j=0 ; j<3 ; j++)
 1585                                 org[j] += dist[j]*len;
 1586                         d -= model_length;
 1587                 }
 1588         }
 1589 }
 1590 
 1591 /*
 1592 =================
 1593 CL_AddExplosions
 1594 =================
 1595 */
 1596 void CL_AddExplosions (void)
 1597 {
 1598         entity_t        *ent;
 1599         int                     i;
 1600         explosion_t     *ex;
 1601         float           frac;
 1602         int                     f;
 1603 
 1604         memset (&ent, 0, sizeof(ent));
 1605 
 1606         for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
 1607         {
 1608                 if (ex->type == ex_free)
 1609                         continue;
 1610                 frac = (cl.time - ex->start)/100.0;
 1611                 f = floor(frac);
 1612 
 1613                 ent = &ex->ent;
 1614 
 1615                 switch (ex->type)
 1616                 {
 1617                 case ex_mflash:
 1618                         if (f >= ex->frames-1)
 1619                                 ex->type = ex_free;
 1620                         break;
 1621                 case ex_misc:
 1622                         if (f >= ex->frames-1)
 1623                         {
 1624                                 ex->type = ex_free;
 1625                                 break;
 1626                         }
 1627                         ent->alpha = 1.0 - frac/(ex->frames-1);
 1628                         break;
 1629                 case ex_flash:
 1630                         if (f >= 1)
 1631                         {
 1632                                 ex->type = ex_free;
 1633                                 break;
 1634                         }
 1635                         ent->alpha = 1.0;
 1636                         break;
 1637                 case ex_poly:
 1638                         if (f >= ex->frames-1)
 1639                         {
 1640                                 ex->type = ex_free;
 1641                                 break;
 1642                         }
 1643 
 1644                         ent->alpha = (16.0 - (float)f)/16.0;
 1645 
 1646                         if (f < 10)
 1647                         {
 1648                                 ent->skinnum = (f>>1);
 1649                                 if (ent->skinnum < 0)
 1650                                         ent->skinnum = 0;
 1651                         }
 1652                         else
 1653                         {
 1654                                 ent->flags |= RF_TRANSLUCENT;
 1655                                 if (f < 13)
 1656                                         ent->skinnum = 5;
 1657                                 else
 1658                                         ent->skinnum = 6;
 1659                         }
 1660                         break;
 1661                 case ex_poly2:
 1662                         if (f >= ex->frames-1)
 1663                         {
 1664                                 ex->type = ex_free;
 1665                                 break;
 1666                         }
 1667 
 1668                         ent->alpha = (5.0 - (float)f)/5.0;
 1669                         ent->skinnum = 0;
 1670                         ent->flags |= RF_TRANSLUCENT;
 1671                         break;
 1672                 }
 1673 
 1674                 if (ex->type == ex_free)
 1675                         continue;
 1676                 if (ex->light)
 1677                 {
 1678                         V_AddLight (ent->origin, ex->light*ent->alpha,
 1679                                 ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
 1680                 }
 1681 
 1682                 VectorCopy (ent->origin, ent->oldorigin);
 1683 
 1684                 if (f < 0)
 1685                         f = 0;
 1686                 ent->frame = ex->baseframe + f + 1;
 1687                 ent->oldframe = ex->baseframe + f;
 1688                 ent->backlerp = 1.0 - cl.lerpfrac;
 1689 
 1690                 V_AddEntity (ent);
 1691         }
 1692 }
 1693 
 1694 
 1695 /*
 1696 =================
 1697 CL_AddLasers
 1698 =================
 1699 */
 1700 void CL_AddLasers (void)
 1701 {
 1702         laser_t         *l;
 1703         int                     i;
 1704 
 1705         for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
 1706         {
 1707                 if (l->endtime >= cl.time)
 1708                         V_AddEntity (&l->ent);
 1709         }
 1710 }
 1711 
 1712 /* PMM - CL_Sustains */
 1713 void CL_ProcessSustain ()
 1714 {
 1715         cl_sustain_t    *s;
 1716         int                             i;
 1717 
 1718         for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
 1719         {
 1720                 if (s->id)
 1721                         if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
 1722                         {
 1723 //                              Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
 1724                                 s->think (s);
 1725                         }
 1726                         else if (s->endtime < cl.time)
 1727                                 s->id = 0;
 1728         }
 1729 }
 1730 
 1731 /*
 1732 =================
 1733 CL_AddTEnts
 1734 =================
 1735 */
 1736 void CL_AddTEnts (void)
 1737 {
 1738         CL_AddBeams ();
 1739         // PMM - draw plasma beams
 1740         CL_AddPlayerBeams ();
 1741         CL_AddExplosions ();
 1742         CL_AddLasers ();
 1743         // PMM - set up sustain
 1744         CL_ProcessSustain();
 1745 }
 1746