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