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 explosion_s
30 {
31 struct explosion_s *prev, *next;
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 32
43 explosion_t cl_explosions[MAX_EXPLOSIONS];
44 explosion_t cl_explosions_headnode, *cl_free_expl;
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
75 #if defined(PARTICLESYSTEM)
76 void CL_ExplosionParticles (vec3_t org, float scale, int water);
77 #else
78 void CL_BlasterParticles (vec3_t org, vec3_t dir);
79 void CL_ExplosionParticles (vec3_t org);
80 #endif
81 void CL_BFGExplosionParticles (vec3_t org);
82 // RAFAEL
83 void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
84
85 struct sfx_s *cl_sfx_ric1;
86 struct sfx_s *cl_sfx_ric2;
87 struct sfx_s *cl_sfx_ric3;
88 struct sfx_s *cl_sfx_lashit;
89 struct sfx_s *cl_sfx_spark5;
90 struct sfx_s *cl_sfx_spark6;
91 struct sfx_s *cl_sfx_spark7;
92 struct sfx_s *cl_sfx_railg;
93 struct sfx_s *cl_sfx_rockexp;
94 struct sfx_s *cl_sfx_grenexp;
95 struct sfx_s *cl_sfx_watrexp;
96 // RAFAEL
97 struct sfx_s *cl_sfx_plasexp;
98 struct sfx_s *cl_sfx_footsteps[4];
99 /* Knightmare- Lazarus footstep sounds */
100 struct sfx_s *cl_sfx_metal_footsteps[4];
101 struct sfx_s *cl_sfx_dirt_footsteps[4];
102 struct sfx_s *cl_sfx_vent_footsteps[4];
103 struct sfx_s *cl_sfx_grate_footsteps[4];
104 struct sfx_s *cl_sfx_tile_footsteps[4];
105 struct sfx_s *cl_sfx_grass_footsteps[4];
106 struct sfx_s *cl_sfx_snow_footsteps[4];
107 struct sfx_s *cl_sfx_carpet_footsteps[4];
108 struct sfx_s *cl_sfx_force_footsteps[4];
109 struct sfx_s *cl_sfx_gravel_footsteps[4];
110 struct sfx_s *cl_sfx_ice_footsteps[4];
111 struct sfx_s *cl_sfx_sand_footsteps[4];
112 struct sfx_s *cl_sfx_wood_footsteps[4];
113 struct sfx_s *cl_sfx_slosh[4];
114 struct sfx_s *cl_sfx_wade[4];
115 struct sfx_s *cl_sfx_ladder[4];
116 /* end Knightmare */
117
118 struct model_s *cl_mod_explode;
119 struct model_s *cl_mod_smoke;
120 struct model_s *cl_mod_flash;
121 struct model_s *cl_mod_parasite_segment;
122 struct model_s *cl_mod_grapple_cable;
123 struct model_s *cl_mod_parasite_tip;
124 struct model_s *cl_mod_explo4;
125 struct model_s *cl_mod_bfg_explo;
126 struct model_s *cl_mod_powerscreen;
127 // RAFAEL
128 struct model_s *cl_mod_plasmaexplo;
129
130 //ROGUE
131 struct sfx_s *cl_sfx_lightning;
132 struct sfx_s *cl_sfx_disrexp;
133 struct model_s *cl_mod_lightning;
134 struct model_s *cl_mod_heatbeam;
135 struct model_s *cl_mod_monster_heatbeam;
136 struct model_s *cl_mod_explo4_big;
137
138 //ROGUE
139 /*
140 =================
141 CL_RegisterTEntSounds
142 =================
143 */
CL_RegisterTEntSounds(void)144 void CL_RegisterTEntSounds (void)
145 {
146 int i;
147 char name[MAX_QPATH];
148
149 cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
150 cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
151 cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
152 cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
153 cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
154 cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
155 cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
156 cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
157 cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
158 cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
159 cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
160
161 S_RegisterSound ("player/land1.wav");
162 S_RegisterSound ("player/fall2.wav");
163 S_RegisterSound ("player/fall1.wav");
164
165 for (i=0 ; i<4 ; i++) {
166 Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
167 cl_sfx_footsteps[i] = S_RegisterSound (name);
168 }
169
170 /* Knightmare- Lazarus footstep sounds */
171 for (i=0 ; i<4 ; i++) {
172 Com_sprintf (name, sizeof(name), "player/pl_metal%i.wav", i+1);
173 cl_sfx_metal_footsteps[i] = S_RegisterSound (name);
174 }
175 for (i=0 ; i<4 ; i++) {
176 Com_sprintf (name, sizeof(name), "player/pl_dirt%i.wav", i+1);
177 cl_sfx_dirt_footsteps[i] = S_RegisterSound (name);
178 }
179 for (i=0 ; i<4 ; i++) {
180 Com_sprintf (name, sizeof(name), "player/pl_duct%i.wav", i+1);
181 cl_sfx_vent_footsteps[i] = S_RegisterSound (name);
182 }
183 for (i=0 ; i<4 ; i++) {
184 Com_sprintf (name, sizeof(name), "player/pl_grate%i.wav", i+1);
185 cl_sfx_grate_footsteps[i] = S_RegisterSound (name);
186 }
187 for (i=0 ; i<4 ; i++) {
188 Com_sprintf (name, sizeof(name), "player/pl_tile%i.wav", i+1);
189 cl_sfx_tile_footsteps[i] = S_RegisterSound (name);
190 }
191 for (i=0 ; i<4 ; i++) {
192 Com_sprintf (name, sizeof(name), "player/pl_grass%i.wav", i+1);
193 cl_sfx_grass_footsteps[i] = S_RegisterSound (name);
194 }
195 for (i=0 ; i<4 ; i++) {
196 Com_sprintf (name, sizeof(name), "player/pl_snow%i.wav", i+1);
197 cl_sfx_snow_footsteps[i] = S_RegisterSound (name);
198 }
199 for (i=0 ; i<4 ; i++) {
200 Com_sprintf (name, sizeof(name), "player/pl_carpet%i.wav", i+1);
201 cl_sfx_carpet_footsteps[i] = S_RegisterSound (name);
202 }
203 for (i=0 ; i<4 ; i++) {
204 Com_sprintf (name, sizeof(name), "player/pl_force%i.wav", i+1);
205 cl_sfx_force_footsteps[i] = S_RegisterSound (name);
206 }
207 for (i=0 ; i<4 ; i++) {
208 Com_sprintf (name, sizeof(name), "player/pl_gravel%i.wav", i+1);
209 cl_sfx_gravel_footsteps[i] = S_RegisterSound (name);
210 }
211 for (i=0; i<4; i++) {
212 Com_sprintf (name, sizeof(name), "player/pl_ice%i.wav", i+1);
213 cl_sfx_ice_footsteps[i] = S_RegisterSound (name);
214 }
215 for (i=0; i<4; i++) {
216 Com_sprintf (name, sizeof(name), "player/pl_sand%i.wav", i+1);
217 cl_sfx_sand_footsteps[i] = S_RegisterSound (name);
218 }
219 for (i=0; i<4; i++) {
220 Com_sprintf (name, sizeof(name), "player/pl_wood%i.wav", i+1);
221 cl_sfx_wood_footsteps[i] = S_RegisterSound (name);
222 }
223 for (i=0; i<4; i++) {
224 Com_sprintf (name, sizeof(name), "player/pl_slosh%i.wav", i+1);
225 cl_sfx_slosh[i] = S_RegisterSound (name);
226 }
227 for (i=0; i<4; i++) {
228 Com_sprintf (name, sizeof(name), "player/pl_wade%i.wav", i+1);
229 cl_sfx_wade[i] = S_RegisterSound (name);
230 }
231 for (i=0; i<4; i++) {
232 Com_sprintf (name, sizeof(name), "player/pl_ladder%i.wav", i+1);
233 cl_sfx_ladder[i] = S_RegisterSound (name);
234 }
235 if (cl_footsteps_override->value)
236 ReadTextureSurfaceAssignments();
237 /* end Knightmare */
238
239
240 //PGM
241 cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
242 cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
243 //PGM
244 }
245
246 /*
247 =================
248 CL_RegisterTEntModels
249 =================
250 */
CL_RegisterTEntModels(void)251 void CL_RegisterTEntModels (void)
252 {
253 cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
254 cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
255 cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
256 cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
257 cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
258 cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
259 cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
260 cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
261 cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
262
263 re.RegisterModel ("models/objects/laser/tris.md2");
264 re.RegisterModel ("models/objects/grenade2/tris.md2");
265 re.RegisterModel ("models/weapons/v_machn/tris.md2");
266 re.RegisterModel ("models/weapons/v_handgr/tris.md2");
267 re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
268 re.RegisterModel ("models/objects/gibs/bone/tris.md2");
269 re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
270 re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
271
272 re.RegisterPic ("w_machinegun");
273 re.RegisterPic ("a_bullets");
274 re.RegisterPic ("i_health");
275 re.RegisterPic ("a_grenades");
276
277 //ROGUE
278 cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
279 cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
280 cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
281 cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
282 //ROGUE
283 }
284
285 /*
286 =================
287 CL_ClearTEnts
288 =================
289 */
CL_ClearTEnts(void)290 void CL_ClearTEnts (void)
291 {
292 int i;
293 memset (cl_beams, 0, sizeof(cl_beams));
294 memset (cl_explosions, 0, sizeof(cl_explosions));
295 memset (cl_lasers, 0, sizeof(cl_lasers));
296
297 // link explosions
298 cl_free_expl = cl_explosions;
299 cl_explosions_headnode.prev = &cl_explosions_headnode;
300 cl_explosions_headnode.next = &cl_explosions_headnode;
301 for ( i = 0; i < MAX_EXPLOSIONS - 1; i++ ) {
302 cl_explosions[i].next = &cl_explosions[i+1];
303 }
304
305 //ROGUE
306 memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
307 memset (cl_sustains, 0, sizeof(cl_sustains));
308 //ROGUE
309 }
310
311 /*
312 =================
313 CL_AllocExplosion
314 =================
315 */
CL_AllocExplosion(void)316 explosion_t *CL_AllocExplosion (void)
317 {
318 explosion_t *ex;
319
320 if ( cl_free_expl )
321 { // take a free explosion if possible
322 ex = cl_free_expl;
323 cl_free_expl = ex->next;
324 }
325 else
326 { // grab the oldest one otherwise
327 ex = cl_explosions_headnode.prev;
328 ex->prev->next = ex->next;
329 ex->next->prev = ex->prev;
330 }
331
332 memset ( ex, 0, sizeof (*ex) );
333 ex->start = cl.frame.servertime - 100;
334
335 // put the decal at the start of the list
336 ex->prev = &cl_explosions_headnode;
337 ex->next = cl_explosions_headnode.next;
338 ex->next->prev = ex;
339 ex->prev->next = ex;
340
341 return ex;
342 }
343
344 /*
345 =================
346 CL_FreeExplosion
347 =================
348 */
CL_FreeExplosion(explosion_t * ex)349 void CL_FreeExplosion ( explosion_t *ex )
350 {
351 // remove from linked active list
352 ex->prev->next = ex->next;
353 ex->next->prev = ex->prev;
354
355 // insert into linked free list
356 ex->next = cl_free_expl;
357 cl_free_expl = ex;
358 }
359
360 #if defined(PARTICLESYSTEM)
CL_R_Explode_SP(vec3_t origin,int water)361 void CL_R_Explode_SP (vec3_t origin, int water)
362 {
363 CL_Explosion_Particle (origin, 50, 25, water);
364 }
365
CL_G_Explode_SP(vec3_t origin,int water)366 void CL_G_Explode_SP (vec3_t origin, int water)
367 {
368 CL_Explosion_Particle (origin, 75, 0, water);
369 }
370 #endif
371 /*
372 =================
373 CL_SmokeAndFlash
374 =================
375 */
CL_SmokeAndFlash(vec3_t origin)376 void CL_SmokeAndFlash(vec3_t origin)
377 {
378 explosion_t *ex;
379
380 ex = CL_AllocExplosion ();
381 VectorCopy (origin, ex->ent.origin);
382 ex->type = ex_misc;
383 ex->frames = 4;
384 ex->ent.flags = RF_TRANSLUCENT|RF_NOSHADOW;
385 ex->ent.model = cl_mod_smoke;
386
387 ex = CL_AllocExplosion ();
388 VectorCopy (origin, ex->ent.origin);
389 ex->type = ex_flash;
390 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
391 ex->frames = 2;
392 ex->ent.model = cl_mod_flash;
393 }
394
395 /*
396 =================
397 CL_ParseParticles
398 =================
399 */
CL_ParseParticles(void)400 void CL_ParseParticles (void)
401 {
402 int color, count;
403 vec3_t pos, dir;
404
405 MSG_ReadPos (&net_message, pos);
406 MSG_ReadDir (&net_message, dir);
407
408 color = MSG_ReadByte (&net_message);
409
410 count = MSG_ReadByte (&net_message);
411
412 CL_ParticleEffect (pos, dir, color, count);
413 }
414
415 /*
416 =================
417 CL_ParseBeam
418 =================
419 */
CL_ParseBeam(struct model_s * model)420 int CL_ParseBeam (struct model_s *model)
421 {
422 int ent;
423 vec3_t start, end;
424 beam_t *b;
425 int i;
426
427 ent = MSG_ReadShort (&net_message);
428
429 MSG_ReadPos (&net_message, start);
430 MSG_ReadPos (&net_message, end);
431
432 // override any beam with the same entity
433 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
434 if (b->entity == ent)
435 {
436 b->entity = ent;
437 b->model = model;
438 b->endtime = cl.stime + 200;
439 VectorCopy (start, b->start);
440 VectorCopy (end, b->end);
441 VectorClear (b->offset);
442 return ent;
443 }
444
445 // find a free beam
446 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
447 {
448 if (!b->model || b->endtime < cl.stime)
449 {
450 b->entity = ent;
451 b->model = model;
452 b->endtime = cl.stime + 200;
453 VectorCopy (start, b->start);
454 VectorCopy (end, b->end);
455 VectorClear (b->offset);
456 return ent;
457 }
458 }
459 Com_Printf ("beam list overflow!\n");
460 return ent;
461 }
462
463 /*
464 =================
465 CL_ParseBeam2
466 =================
467 */
CL_ParseBeam2(struct model_s * model)468 int CL_ParseBeam2 (struct model_s *model)
469 {
470 int ent;
471 vec3_t start, end, offset;
472 beam_t *b;
473 int i;
474
475 ent = MSG_ReadShort (&net_message);
476
477 MSG_ReadPos (&net_message, start);
478 MSG_ReadPos (&net_message, end);
479 MSG_ReadPos (&net_message, offset);
480
481 // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
482
483 // override any beam with the same entity
484
485 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
486 if (b->entity == ent)
487 {
488 b->entity = ent;
489 b->model = model;
490 b->endtime = cl.stime + 200;
491 VectorCopy (start, b->start);
492 VectorCopy (end, b->end);
493 VectorCopy (offset, b->offset);
494 return ent;
495 }
496
497 // find a free beam
498 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
499 {
500 if (!b->model || b->endtime < cl.stime)
501 {
502 b->entity = ent;
503 b->model = model;
504 b->endtime = cl.stime + 200;
505 VectorCopy (start, b->start);
506 VectorCopy (end, b->end);
507 VectorCopy (offset, b->offset);
508 return ent;
509 }
510 }
511 Com_Printf ("beam list overflow!\n");
512 return ent;
513 }
514
515 // ROGUE
516 /*
517 =================
518 CL_ParsePlayerBeam
519 - adds to the cl_playerbeam array instead of the cl_beams array
520 =================
521 */
CL_ParsePlayerBeam(struct model_s * model)522 int CL_ParsePlayerBeam (struct model_s *model)
523 {
524 int ent;
525 vec3_t start, end, offset;
526 beam_t *b;
527 int i;
528
529 ent = MSG_ReadShort (&net_message);
530
531 MSG_ReadPos (&net_message, start);
532 MSG_ReadPos (&net_message, end);
533 // PMM - network optimization
534 if (model == cl_mod_heatbeam)
535 VectorSet(offset, 2, 7, -3);
536 else if (model == cl_mod_monster_heatbeam)
537 {
538 model = cl_mod_heatbeam;
539 VectorSet(offset, 0, 0, 0);
540 }
541 else
542 MSG_ReadPos (&net_message, offset);
543
544 // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
545
546 // override any beam with the same entity
547 // PMM - For player beams, we only want one per player (entity) so..
548 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
549 {
550 if (b->entity == ent)
551 {
552 b->entity = ent;
553 b->model = model;
554 b->endtime = cl.stime + 200;
555 VectorCopy (start, b->start);
556 VectorCopy (end, b->end);
557 VectorCopy (offset, b->offset);
558 return ent;
559 }
560 }
561
562 // find a free beam
563 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
564 {
565 if (!b->model || b->endtime < cl.stime)
566 {
567 b->entity = ent;
568 b->model = model;
569 b->endtime = cl.stime + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
570 VectorCopy (start, b->start);
571 VectorCopy (end, b->end);
572 VectorCopy (offset, b->offset);
573 return ent;
574 }
575 }
576 Com_Printf ("beam list overflow!\n");
577 return ent;
578 }
579 //rogue
580
581 /*
582 =================
583 CL_ParseLightning
584 =================
585 */
586 #if defined(PARTICLESYSTEM)
CL_ParseLightning(float size)587 int CL_ParseLightning (float size)
588 {
589
590 vec3_t start, end;
591 int srcEnt, dstEnt;
592
593 srcEnt = MSG_ReadShort (&net_message);
594 dstEnt = MSG_ReadShort (&net_message);
595
596 MSG_ReadPos (&net_message, start);
597 MSG_ReadPos (&net_message, end);
598
599 CL_LightningBeam(start, end, srcEnt, dstEnt, size);
600
601 return srcEnt;
602 }
603 #else
CL_ParseLightning(struct model_s * model)604 int CL_ParseLightning (struct model_s *model)
605 {
606 int srcEnt, destEnt;
607 vec3_t start, end;
608 beam_t *b;
609 int i;
610
611 srcEnt = MSG_ReadShort (&net_message);
612 destEnt = MSG_ReadShort (&net_message);
613
614 MSG_ReadPos (&net_message, start);
615 MSG_ReadPos (&net_message, end);
616
617 // override any beam with the same source AND destination entities
618 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
619 if (b->entity == srcEnt && b->dest_entity == destEnt)
620 {
621 // Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt);
622 b->entity = srcEnt;
623 b->dest_entity = destEnt;
624 b->model = model;
625 b->endtime = cl.stime + 200;
626 VectorCopy (start, b->start);
627 VectorCopy (end, b->end);
628 VectorClear (b->offset);
629 return srcEnt;
630 }
631
632 // find a free beam
633 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
634 {
635 if (!b->model || b->endtime < cl.stime)
636 {
637 // Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt);
638 b->entity = srcEnt;
639 b->dest_entity = destEnt;
640 b->model = model;
641 b->endtime = cl.stime + 200;
642 VectorCopy (start, b->start);
643 VectorCopy (end, b->end);
644 VectorClear (b->offset);
645 return srcEnt;
646 }
647 }
648 Com_Printf ("beam list overflow!\n");
649 return srcEnt;
650 }
651 #endif
652
653 /*
654 =================
655 CL_ParseLaser
656 =================
657 */
CL_ParseLaser(int colors)658 void CL_ParseLaser (int colors)
659 {
660 vec3_t start;
661 vec3_t end;
662 laser_t *l;
663 int i;
664
665 MSG_ReadPos (&net_message, start);
666 MSG_ReadPos (&net_message, end);
667
668 for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
669 {
670 if (l->endtime < cl.stime)
671 {
672 l->ent.flags = RF_TRANSLUCENT | RF_BEAM | RF_NOSHADOW;
673 VectorCopy (start, l->ent.origin);
674 VectorCopy (end, l->ent.oldorigin);
675 l->ent.alpha = 0.30;
676 l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
677 l->ent.model = NULL;
678 l->ent.frame = 4;
679 l->endtime = cl.stime + 100;
680 return;
681 }
682 }
683 }
684
685 //=============
686 //ROGUE
CL_ParseSteam(void)687 void CL_ParseSteam (void)
688 {
689 vec3_t pos, dir;
690 int id, i;
691 int r;
692 int cnt;
693 int color;
694 int magnitude;
695 cl_sustain_t *s, *free_sustain;
696
697 id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
698 if (id != -1) // sustains
699 {
700 // Com_Printf ("Sustain effect id %d\n", id);
701 free_sustain = NULL;
702 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
703 {
704 if (s->id == 0)
705 {
706 free_sustain = s;
707 break;
708 }
709 }
710 if (free_sustain)
711 {
712 s->id = id;
713 s->count = MSG_ReadByte (&net_message);
714 MSG_ReadPos (&net_message, s->org);
715 MSG_ReadDir (&net_message, s->dir);
716 r = MSG_ReadByte (&net_message);
717 s->color = r & 0xff;
718 s->magnitude = MSG_ReadShort (&net_message);
719 s->endtime = cl.stime + MSG_ReadLong (&net_message);
720 s->think = CL_ParticleSteamEffect2;
721 s->thinkinterval = 100;
722 s->nextthink = cl.stime;
723 }
724 else
725 {
726 // Com_Printf ("No free sustains!\n");
727 // FIXME - read the stuff anyway
728 cnt = MSG_ReadByte (&net_message);
729 MSG_ReadPos (&net_message, pos);
730 MSG_ReadDir (&net_message, dir);
731 r = MSG_ReadByte (&net_message);
732 magnitude = MSG_ReadShort (&net_message);
733 magnitude = MSG_ReadLong (&net_message); // really interval
734 }
735 }
736 else // instant
737 {
738 cnt = MSG_ReadByte (&net_message);
739 MSG_ReadPos (&net_message, pos);
740 MSG_ReadDir (&net_message, dir);
741 r = MSG_ReadByte (&net_message);
742 magnitude = MSG_ReadShort (&net_message);
743 color = r & 0xff;
744 #if defined(PARTICLESYSTEM)
745 CL_ParticleSteamEffect(pos, dir,
746 color8red(color),
747 color8green(color),
748 color8blue(color),
749 -20, -20, -20, cnt, magnitude);
750 #else
751 CL_ParticleSteamEffect(pos, dir, color, cnt, magnitude);
752 #endif
753 // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
754 }
755 }
756
CL_ParseWidow(void)757 void CL_ParseWidow (void)
758 {
759 vec3_t pos;
760 int id, i;
761 cl_sustain_t *s, *free_sustain;
762
763 id = MSG_ReadShort (&net_message);
764
765 free_sustain = NULL;
766 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
767 {
768 if (s->id == 0)
769 {
770 free_sustain = s;
771 break;
772 }
773 }
774 if (free_sustain)
775 {
776 s->id = id;
777 MSG_ReadPos (&net_message, s->org);
778 s->endtime = cl.stime + 2100;
779 s->think = CL_Widowbeamout;
780 s->thinkinterval = 1;
781 s->nextthink = cl.stime;
782 }
783 else // no free sustains
784 {
785 // FIXME - read the stuff anyway
786 MSG_ReadPos (&net_message, pos);
787 }
788 }
789
CL_ParseNuke(void)790 void CL_ParseNuke (void)
791 {
792 vec3_t pos;
793 int i;
794 cl_sustain_t *s, *free_sustain;
795
796 free_sustain = NULL;
797 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
798 {
799 if (s->id == 0)
800 {
801 free_sustain = s;
802 break;
803 }
804 }
805 if (free_sustain)
806 {
807 s->id = 21000;
808 MSG_ReadPos (&net_message, s->org);
809 s->endtime = cl.stime + 1000;
810 #if defined(PARTICLESYSTEM)
811 if (cl_nukeblast_enh->value) {
812 s->think = CL_Nukeblast_Opt;
813 }
814 else
815 #endif
816 s->think = CL_Nukeblast;
817 s->thinkinterval = 1;
818 s->nextthink = cl.stime;
819 }
820 else // no free sustains
821 {
822 // FIXME - read the stuff anyway
823 MSG_ReadPos (&net_message, pos);
824 }
825 }
826
827 //ROGUE
828 //=============
829
830 /*
831 =================
832 CL_FindTrailPlane
833
834 Disgusting hack
835 =================
836 */
837 #if !defined(PARTICLESYSTEM)
CL_FindTrailPlane(vec3_t start,vec3_t end,vec3_t dir)838 void CL_FindTrailPlane (vec3_t start, vec3_t end, vec3_t dir)
839 {
840
841 trace_t trace;
842 vec3_t vec, point;
843 float len;
844
845 VectorSubtract(end, start, vec);
846 len = VectorNormalize(vec);
847 VectorMA(start, len + 0.5, vec, point);
848
849 trace = CM_BoxTrace(start, point, vec3_origin, vec3_origin, 0, MASK_SOLID);
850 if (trace.allsolid || trace.fraction == 1.0){
851 VectorClear(dir);
852 return;
853 }
854
855 VectorCopy(trace.plane.normal, dir);
856 }
857
858 /*
859 =================
860 CL_FindExplosionPlane
861
862 Disgusting hack
863 =================
864 */
CL_FindExplosionPlane(vec3_t org,float radius,vec3_t dir)865 void CL_FindExplosionPlane (vec3_t org, float radius, vec3_t dir)
866 {
867
868 static vec3_t planes[6] = {{0, 0, 1},
869 {0, 1, 0},
870 {1, 0, 0},
871 {0, 0, -1},
872 {0, -1, 0},
873 {-1, 0, 0}};
874 trace_t trace;
875 vec3_t point;
876 float best = 1.0;
877 int i;
878
879 VectorClear(dir);
880
881 for (i = 0; i < 6; i++) {
882 VectorMA(org, radius, planes[i], point);
883
884 trace = CM_BoxTrace(org, point, vec3_origin, vec3_origin, 0, MASK_SOLID);
885 if (trace.allsolid || trace.fraction == 1.0)
886 continue;
887
888 if (trace.fraction < best){
889 best = trace.fraction;
890 VectorCopy(trace.plane.normal, dir);
891 }
892 }
893 }
894 #endif
895
896 /*
897 =================
898 CL_ParseTEnt
899 =================
900 */
901 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
902
CL_ParseTEnt(void)903 void CL_ParseTEnt (void)
904 {
905 int type;
906 vec3_t pos, pos2, dir;
907 explosion_t *ex;
908 int cnt;
909 int color;
910 int r;
911 int ent;
912 int magnitude;
913 #if defined(PARTICLESYSTEM)
914 int red,
915 green,
916 blue;
917 int decalsize = 0;
918 float smokesize;
919 vec3_t sparkdir;
920 #endif
921
922 type = MSG_ReadByte (&net_message);
923
924 switch (type)
925 {
926 case TE_BLOOD: // bullet hitting flesh
927 MSG_ReadPos (&net_message, pos);
928 MSG_ReadDir (&net_message, dir);
929 #if defined(PARTICLESYSTEM)
930 CL_BloodHit (pos, dir);
931 #else
932 CL_ParticleEffect (pos, dir, 0xe8, 60);
933 #endif
934 break;
935
936 case TE_GUNSHOT: // bullet hitting wall
937 case TE_SPARKS:
938 #if defined(PARTICLESYSTEM)
939 case TE_BULLET_SPARKS:
940 MSG_ReadPos (&net_message, pos);
941 MSG_ReadDir (&net_message, dir);
942 if (type == TE_GUNSHOT)
943 decalsize = 3;
944 else if (type == TE_SHOTGUN)
945 decalsize = 4;
946
947 if (type == TE_BULLET_SPARKS)
948 VectorScale(dir, 2, dir);
949
950 {
951 vec3_t color = {255, 125, 10};
952 CL_ParticleEffectSparks(pos, dir, color, (type == TE_GUNSHOT) ? 5 : 10);
953 }
954
955 if (type != TE_SPARKS)
956 {
957 if (cl_gunsmoke->value)
958 CL_ImpactSmokeEffect(pos, dir, 0.5);
959 CL_ParticleBulletDecal(pos, dir, decalsize);
960
961 // impact sound
962 cnt = rand()&15;
963 if (cnt == 1)
964 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
965 else if (cnt == 2)
966 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
967 else if (cnt == 3)
968 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
969 }
970 break;
971 #else
972 case TE_BULLET_SPARKS:
973 MSG_ReadPos (&net_message, pos);
974 MSG_ReadDir (&net_message, dir);
975 re.AddDecal(pos, dir, 0, 0, 0, 1.0, 0, 0, 0, 0,
976 4 + ((rand()%21*0.05) - 0.5),
977 DECAL_BULLET, 0, rand()%361);
978 if (type == TE_GUNSHOT)
979 CL_ParticleEffect (pos, dir, 0, 40);
980 else
981 CL_ParticleEffect (pos, dir, 0xe0, 6);
982 if (type != TE_SPARKS)
983 {
984 CL_SmokeAndFlash(pos);
985 // impact sound
986 cnt = rand()&15;
987 if (cnt == 1)
988 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
989 else if (cnt == 2)
990 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
991 else if (cnt == 3)
992 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
993 }
994 break;
995 #endif
996 case TE_SCREEN_SPARKS:
997 case TE_SHIELD_SPARKS:
998 MSG_ReadPos (&net_message, pos);
999 MSG_ReadDir (&net_message, dir);
1000 if (type == TE_SCREEN_SPARKS)
1001 CL_ParticleEffect (pos, dir, 0xd0, 40);
1002 else
1003 CL_ParticleEffect (pos, dir, 0xb0, 40);
1004 //FIXME : replace or remove this sound
1005 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1006 break;
1007
1008 case TE_SHOTGUN: // bullet hitting wall
1009 #if defined(PARTICLESYSTEM)
1010 MSG_ReadPos (&net_message, pos);
1011 MSG_ReadDir (&net_message, dir);
1012
1013 if (type == TE_GUNSHOT) {
1014 decalsize = 2.5;
1015 smokesize = 1;
1016 }
1017 else if (type == TE_BULLET_SPARKS) {
1018 decalsize = 3;
1019 smokesize = 1.25;
1020 }
1021 else if (type == TE_SHOTGUN) {
1022 decalsize = 3.5;
1023 smokesize = random()*0.75 + 0.25;
1024 }
1025
1026 if (!modType("dday") && !modType("action")) {
1027 decalsize *= 2;
1028 smokesize *= 1.5;
1029 }
1030
1031 if (type == TE_BULLET_SPARKS) {
1032 VectorScale(dir, 1.25 * smokesize, sparkdir);
1033 }
1034 else if (type != TE_SPARKS && type != TE_SHOTGUN) {
1035 VectorScale(dir, 1.1 * smokesize, sparkdir);
1036 // impact sound
1037 cnt = rand()&15;
1038 if (cnt == 1)
1039 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
1040 else if (cnt == 2)
1041 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
1042 else if (cnt == 3)
1043 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
1044 }
1045 else
1046 VectorCopy(dir, sparkdir);
1047
1048 //adding sparks
1049 {
1050 vec3_t color = { 255, 125, 10 };
1051 CL_ParticleEffectSparks (pos, sparkdir, color, (type == TE_GUNSHOT)? 5 : 10);
1052 }
1053
1054 if (type != TE_SPARKS) {
1055 VectorNormalize(dir);
1056 if (cl_gunsmoke->value)
1057 CL_ImpactSmokeEffect(pos, dir, smokesize);
1058
1059 CL_ParticleBulletDecal(pos, dir, decalsize);
1060 }
1061 break;
1062 #else
1063 MSG_ReadPos (&net_message, pos);
1064 MSG_ReadDir (&net_message, dir);
1065 re.AddDecal(pos, dir, 0, 0, 0, 1.0, 0, 0, 0, 0,
1066 6 + ((rand()%21*0.05) - 0.5),
1067 DECAL_BULLET, 0, rand()%361);
1068 CL_ParticleEffect (pos, dir, 0, 20);
1069 CL_SmokeAndFlash(pos);
1070 break;
1071 #endif
1072 case TE_SPLASH: // bullet hitting water
1073 cnt = MSG_ReadByte (&net_message);
1074 MSG_ReadPos (&net_message, pos);
1075 MSG_ReadDir (&net_message, dir);
1076 r = MSG_ReadByte (&net_message);
1077 if (r > 6)
1078 color = 0x00;
1079 else
1080 color = splash_color[r];
1081
1082 if (r == SPLASH_SPARKS)
1083 {
1084 CL_ParticleEffect (pos, dir, color, cnt);
1085 r = rand() & 3;
1086 if (r == 0)
1087 S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
1088 else if (r == 1)
1089 S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
1090 else
1091 S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
1092 }
1093 #if defined(PARTICLESYSTEM)
1094 else
1095 CL_ParticleWaterEffectSplash (pos, dir, color, cnt, r);
1096 #endif
1097 break;
1098
1099 case TE_LASER_SPARKS:
1100 cnt = MSG_ReadByte (&net_message);
1101 MSG_ReadPos (&net_message, pos);
1102 MSG_ReadDir (&net_message, dir);
1103 color = MSG_ReadByte (&net_message);
1104 CL_ParticleEffect2 (pos, dir, color, cnt);
1105 break;
1106
1107 // RAFAEL
1108 case TE_BLUEHYPERBLASTER:
1109 MSG_ReadPos (&net_message, pos);
1110 MSG_ReadPos (&net_message, dir);
1111 #if defined(PARTICLESYSTEM)
1112 CL_BlasterParticles (pos, dir, 40);
1113 #else
1114 CL_BlasterParticles (pos, dir);
1115 #endif
1116 break;
1117
1118 case TE_BLASTER: // blaster hitting wall
1119 MSG_ReadPos (&net_message, pos);
1120 MSG_ReadDir (&net_message, dir);
1121 #if defined(PARTICLESYSTEM)
1122 if (cl_blaster_color->value == 1) {
1123 /* give the bolt a red particle glow */
1124 CL_BlasterParticlesColor(pos, dir, 40, 235, 50, 50, 0, -90, -30);
1125 if (cl_gunsmoke->value)
1126 CL_WeapSmokeEffect(pos, dir, 235, 50, 50, 1.0, 0.4f);
1127 CL_ParticleBlasterColorDecal(pos, dir, 7.5, 235, 50, 50);
1128 } else if (cl_blaster_color->value == 2) {
1129 /* give the bolt a green particle glow */
1130 CL_BlasterParticlesColor(pos, dir, 40, 50, 235, 50, 0, -90, -30);
1131 if (cl_gunsmoke->value)
1132 CL_WeapSmokeEffect(pos, dir, 50, 235, 50, 1.0, 0.4f);
1133 CL_ParticleBlasterColorDecal(pos, dir, 7.5, 50, 235, 50);
1134 } else if (cl_blaster_color->value == 3) {
1135 /* give the bolt a blue particle glow */
1136 CL_BlasterParticlesColor(pos, dir, 40, 50, 50, 255, 0, -90, -30);
1137 if (cl_gunsmoke->value)
1138 CL_WeapSmokeEffect(pos, dir, 50, 50, 255, 1.0, 0.4f);
1139 CL_ParticleBlasterColorDecal(pos, dir, 7.5, 50, 50, 255);
1140 } else {
1141 CL_BlasterParticles(pos, dir, 40);
1142 if (cl_gunsmoke->value)
1143 CL_WeapSmokeEffect(pos, dir, 255, 150, 50, 1.0, 0.4f);
1144 CL_ParticleBlasterDecal(pos, dir, 7.5);
1145 }
1146
1147 for (r=0; r<3; r++)
1148 {
1149 dir[r]*=10;
1150 pos[r]+=dir[r];
1151 }
1152 #else
1153 re.AddDecal(pos, dir, 1, 0.5, 0, 1.0, 1, 0.5, 0, 1, 4 + ((rand()%21*0.05) - 0.5),
1154 DECAL_BLASTER, 0, rand()%361);
1155 CL_BlasterParticles (pos, dir);
1156
1157 ex = CL_AllocExplosion ();
1158 VectorCopy (pos, ex->ent.origin);
1159 ex->ent.angles[0] = acos(dir[2])/M_PI*180;
1160 // PMM - fixed to correct for pitch of 0
1161 if (dir[0])
1162 ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
1163 else if (dir[1] > 0)
1164 ex->ent.angles[1] = 90;
1165 else if (dir[1] < 0)
1166 ex->ent.angles[1] = 270;
1167 else
1168 ex->ent.angles[1] = 0;
1169
1170 ex->type = ex_misc;
1171 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW;
1172 ex->light = 150;
1173 ex->lightcolor[0] = 1;
1174 ex->lightcolor[1] = 1;
1175 ex->ent.model = cl_mod_explode;
1176 ex->frames = 4;
1177 #endif
1178 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1179 break;
1180
1181 case TE_RAILTRAIL: // railgun effect
1182 MSG_ReadPos (&net_message, pos);
1183 MSG_ReadPos (&net_message, pos2);
1184 #if defined(PARTICLESYSTEM)
1185 CL_RailTrail (pos, pos2);
1186 #else
1187 CL_FindTrailPlane(pos, pos2, dir);
1188 CL_RailTrail (pos, pos2);
1189 re.AddDecal(pos2, dir, 50, 50, 235,
1190 1, 1, 1, 1, 1,
1191 8, DECAL_RAIL, 0, rand()%361);
1192 #endif
1193 S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
1194 break;
1195
1196 case TE_EXPLOSION2:
1197 case TE_GRENADE_EXPLOSION:
1198 case TE_GRENADE_EXPLOSION_WATER:
1199 MSG_ReadPos (&net_message, pos);
1200 #if defined(PARTICLESYSTEM)
1201 #if 0
1202 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1203 CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1204 CL_ExplosionParticles(pos, 1.25, type == TE_GRENADE_EXPLOSION_WATER);
1205 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1206 CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1207 CL_ExplosionParticles_Old(pos);
1208 } else {
1209 ex = CL_AllocExplosion();
1210 VectorCopy(pos, ex->ent.origin);
1211 ex->type = ex_poly;
1212 ex->ent.flags = RF_FULLBRIGHT;
1213 ex->start = cl.frame.servertime - 100;
1214 ex->light = 350;
1215 ex->lightcolor[0] = 1.0;
1216 ex->lightcolor[1] = 0.5;
1217 ex->lightcolor[2] = 0.5;
1218 ex->ent.model = cl_mod_explo4;
1219 ex->ent.scale = cl_explosion_scale->value;
1220 ex->frames = 19;
1221 ex->baseframe = 30;
1222 ex->ent.angles[1] = rand() % 360;
1223 CL_Explosion_Decal (pos, 75);
1224 }
1225 #else
1226 if (!cl_explosion->value)
1227 {
1228 ex = CL_AllocExplosion ();
1229 VectorCopy (pos, ex->ent.origin);
1230 ex->type = ex_poly;
1231 ex->ent.flags = RF_FULLBRIGHT;
1232 ex->start = cl.frame.servertime - 100;
1233 ex->light = 350;
1234 ex->lightcolor[0] = 1.0;
1235 ex->lightcolor[1] = 0.5;
1236 ex->lightcolor[2] = 0.5;
1237 ex->ent.model = cl_mod_explo4;
1238 ex->ent.scale = cl_explosion_scale->value;
1239 ex->frames = 19;
1240 ex->baseframe = 30;
1241 ex->ent.angles[1] = rand() % 360;
1242
1243 CL_Explosion_Decal (pos, 75);
1244 }
1245 else
1246 CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1247 CL_ExplosionParticles (pos,1.25, type==TE_GRENADE_EXPLOSION_WATER);
1248 #endif
1249 #else
1250 CL_FindExplosionPlane(pos, 80, dir);
1251 re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1252 56 + ((rand()%21*0.05) - 0.5),
1253 DECAL_EXPLODE, 0, rand()%361);
1254 ex = CL_AllocExplosion ();
1255 VectorCopy (pos, ex->ent.origin);
1256 ex->type = ex_poly;
1257 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1258 ex->light = 350;
1259 ex->lightcolor[0] = 1.0;
1260 ex->lightcolor[1] = 0.5;
1261 ex->lightcolor[2] = 0.5;
1262 ex->ent.model = cl_mod_explo4;
1263 ex->frames = 19;
1264 ex->baseframe = 30;
1265 ex->ent.angles[1] = rand() % 360;
1266 CL_ExplosionParticles (pos);
1267 #endif
1268 if (type == TE_GRENADE_EXPLOSION_WATER)
1269 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1270 else
1271 S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
1272 break;
1273
1274 // RAFAEL
1275 case TE_PLASMA_EXPLOSION:
1276 MSG_ReadPos (&net_message, pos);
1277 #if defined(PARTICLESYSTEM)
1278 #if 0
1279 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1280 CL_R_Explode_SP(pos, 0);
1281 CL_ExplosionParticles(pos, 1, 0);
1282 CL_Explosion_Sparks (pos, 32);
1283 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1284 CL_R_Explode_SP(pos, 0);
1285 } else {
1286 ex = CL_AllocExplosion();
1287 VectorCopy(pos, ex->ent.origin);
1288 ex->type = ex_poly;
1289 ex->ent.flags = RF_FULLBRIGHT;
1290 ex->start = cl.frame.servertime - 100;
1291 ex->light = 350;
1292 ex->lightcolor[0] = 1.0;
1293 ex->lightcolor[1] = 0.5;
1294 ex->lightcolor[2] = 0.5;
1295 ex->ent.angles[1] = rand() % 360;
1296 ex->ent.model = cl_mod_explo4;
1297 ex->ent.scale = cl_explosion_scale->value;
1298 if (frand() < 0.5)
1299 ex->baseframe = 15;
1300 ex->frames = 15;
1301 CL_Explosion_Decal (pos, 50);
1302 }
1303 #else
1304 if (!cl_explosion->value)
1305 {
1306 ex = CL_AllocExplosion ();
1307 VectorCopy (pos, ex->ent.origin);
1308 ex->type = ex_poly;
1309 ex->ent.flags = RF_FULLBRIGHT;
1310 ex->start = cl.frame.servertime - 100;
1311 ex->light = 350;
1312 ex->lightcolor[0] = 1.0;
1313 ex->lightcolor[1] = 0.5;
1314 ex->lightcolor[2] = 0.5;
1315 ex->ent.angles[1] = rand() % 360;
1316 ex->ent.model = cl_mod_explo4;
1317 ex->ent.scale = cl_explosion_scale->value;
1318 if (frand() < 0.5)
1319 ex->baseframe = 15;
1320 ex->frames = 15;
1321
1322 CL_Explosion_Decal (pos, 50);
1323 }
1324 else
1325 CL_R_Explode_SP(pos, 0);
1326
1327 CL_ExplosionParticles (pos, 1, 0);
1328 #endif
1329 #else
1330 ex = CL_AllocExplosion ();
1331 VectorCopy (pos, ex->ent.origin);
1332 ex->type = ex_poly;
1333 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1334 ex->light = 350;
1335 ex->lightcolor[0] = 1.0;
1336 ex->lightcolor[1] = 0.5;
1337 ex->lightcolor[2] = 0.5;
1338 ex->ent.angles[1] = rand() % 360;
1339 ex->ent.model = cl_mod_explo4;
1340 if (frand() < 0.5)
1341 ex->baseframe = 15;
1342 ex->frames = 15;
1343 CL_ExplosionParticles (pos);
1344 #endif
1345 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1346 break;
1347
1348 case TE_EXPLOSION1:
1349 case TE_EXPLOSION1_BIG: // PMM
1350 #if defined(PARTICLESYSTEM)
1351 MSG_ReadPos (&net_message, pos);
1352 #if 0
1353 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1354 CL_Explosion_Particle(pos, 100, 0,0);
1355 CL_ExplosionParticles(pos, 3, 0);
1356 CL_Explosion_Sparks(pos, 96);
1357 {
1358 vec3_t color = {200, 100, 10};
1359 CL_ParticleEffectSparks(pos, dir, color, 8);
1360 }
1361 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1362 CL_Explosion_Particle(pos, 100, 0,0);
1363 CL_ExplosionParticles_Old(pos);
1364 } else {
1365 ex = CL_AllocExplosion();
1366 VectorCopy(pos, ex->ent.origin);
1367 ex->type = ex_poly;
1368 ex->ent.flags = RF_FULLBRIGHT;
1369 ex->start = cl.frame.servertime - 100;
1370 ex->light = 350;
1371 ex->lightcolor[0] = 1.0;
1372 ex->lightcolor[1] = 0.5;
1373 ex->lightcolor[2] = 0.5;
1374 ex->ent.angles[1] = rand() % 360;
1375 ex->ent.scale = cl_explosion_scale->value;
1376 ex->ent.model = cl_mod_explo4_big;
1377 if (frand() < 0.5)
1378 ex->baseframe = 15;
1379 ex->frames = 15;
1380
1381 CL_Explosion_Decal (pos, 100);
1382 CL_ExplosionParticles(pos, 3, 0);
1383 }
1384 #else
1385 if (!cl_explosion->value)
1386 {
1387
1388 ex = CL_AllocExplosion ();
1389 VectorCopy (pos, ex->ent.origin);
1390 ex->type = ex_poly;
1391 ex->ent.flags = RF_FULLBRIGHT;
1392 ex->start = cl.frame.servertime - 100;
1393 ex->light = 350;
1394 ex->lightcolor[0] = 1.0;
1395 ex->lightcolor[1] = 0.5;
1396 ex->lightcolor[2] = 0.5;
1397 ex->ent.angles[1] = rand() % 360;
1398 ex->ent.scale = cl_explosion_scale->value;
1399 ex->ent.model = cl_mod_explo4_big;
1400 if (frand() < 0.5)
1401 ex->baseframe = 15;
1402 ex->frames = 15;
1403
1404 CL_Explosion_Decal (pos, 100);
1405 CL_ExplosionParticles (pos, 3, 0);
1406 }
1407 else
1408 {
1409 if (modType("dday"))
1410 {
1411 CL_Explosion_Particle (pos, 250, 0, 0);
1412 CL_ExplosionParticles (pos, 5, 0);
1413 }
1414 else
1415 {
1416 CL_Explosion_Particle (pos, 100, 0, 0);
1417 CL_ExplosionParticles (pos, 2, 0);
1418 }
1419 }
1420 #endif
1421 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1422 break;
1423 #endif
1424 case TE_ROCKET_EXPLOSION:
1425 case TE_ROCKET_EXPLOSION_WATER:
1426 MSG_ReadPos(&net_message, pos);
1427 #if defined(PARTICLESYSTEM)
1428 #if 0
1429 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1430 CL_Explosion_Particle (pos, 50, 0, 0);
1431 CL_ExplosionParticles(pos, 1, type==TE_ROCKET_EXPLOSION_WATER);
1432 CL_Explosion_Sparks(pos, 21);
1433 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1434 CL_Explosion_Particle (pos, 50, 0, 0);
1435 CL_ExplosionParticles_Old(pos);
1436 } else {
1437 ex = CL_AllocExplosion();
1438 VectorCopy(pos, ex->ent.origin);
1439 ex->type = ex_poly;
1440 ex->ent.flags = RF_FULLBRIGHT;
1441 ex->start = cl.frame.servertime - 100;
1442 ex->light = 350;
1443 ex->lightcolor[0] = 1.0;
1444 ex->lightcolor[1] = 0.5;
1445 ex->lightcolor[2] = 0.5;
1446 ex->ent.angles[1] = rand() % 360;
1447 ex->ent.model = cl_mod_explo4;
1448 ex->ent.scale = cl_explosion_scale->value;
1449 if (frand() < 0.5)
1450 ex->baseframe = 15;
1451 ex->frames = 15;
1452 CL_Explosion_Decal (pos, 50);
1453
1454 }
1455 #else
1456 if (!cl_explosion->value)
1457 {
1458 ex = CL_AllocExplosion ();
1459 VectorCopy (pos, ex->ent.origin);
1460 ex->type = ex_poly;
1461 ex->ent.flags = RF_FULLBRIGHT;
1462 ex->start = cl.frame.servertime - 100;
1463 ex->light = 350;
1464 ex->lightcolor[0] = 1.0;
1465 ex->lightcolor[1] = 0.5;
1466 ex->lightcolor[2] = 0.5;
1467 ex->ent.angles[1] = rand() % 360;
1468 ex->ent.model = cl_mod_explo4;
1469 ex->ent.scale = cl_explosion_scale->value;
1470 if (frand() < 0.5)
1471 ex->baseframe = 15;
1472 ex->frames = 15;
1473
1474 CL_Explosion_Decal (pos, 50);
1475 }
1476 else
1477 CL_R_Explode_SP(pos, type==TE_ROCKET_EXPLOSION_WATER);
1478
1479 CL_ExplosionParticles (pos, 1, type==TE_ROCKET_EXPLOSION_WATER);
1480 #endif
1481 #else
1482 CL_FindExplosionPlane(pos, 70, dir);
1483 re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1484 56 + ((rand()%21*0.05) - 0.5),
1485 DECAL_EXPLODE, 0, rand()%361);
1486 ex = CL_AllocExplosion();
1487 VectorCopy(pos, ex->ent.origin);
1488 ex->type = ex_poly;
1489 ex->ent.flags = RF_FULLBRIGHT | RF_NOSHADOW;
1490 ex->light = 350;
1491 ex->lightcolor[0] = 1.0;
1492 ex->lightcolor[1] = 0.5;
1493 ex->lightcolor[2] = 0.5;
1494 ex->ent.angles[1] = rand() % 360;
1495 if (type != TE_EXPLOSION1_BIG) /* PMM */
1496 ex->ent.model = cl_mod_explo4; /* PMM */
1497 else
1498 ex->ent.model = cl_mod_explo4_big;
1499 if (frand() < 0.5)
1500 ex->baseframe = 15;
1501 ex->frames = 15;
1502 if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) /* PMM */
1503 CL_ExplosionParticles(pos); /* PMM */
1504 #endif
1505 if (type == TE_ROCKET_EXPLOSION_WATER)
1506 S_StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1507 else
1508 S_StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1509 break;
1510 case TE_EXPLOSION1_NP: // PMM
1511 MSG_ReadPos (&net_message, pos);
1512 #if defined(PARTICLESYSTEM)
1513 #if 0
1514 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1515 CL_R_Explode_SP(pos, 0);
1516 CL_ExplosionParticles (pos, 0.6666666, 0);
1517 CL_Explosion_Sparks(pos, 32); /* PMM */
1518 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1519 CL_R_Explode_SP(pos, type==TE_ROCKET_EXPLOSION_WATER);
1520 CL_ExplosionParticles_Old(pos);
1521 } else {
1522 ex = CL_AllocExplosion();
1523 VectorCopy(pos, ex->ent.origin);
1524 ex->type = ex_poly;
1525 ex->ent.flags = RF_FULLBRIGHT;
1526 ex->start = cl.frame.servertime - 100;
1527 ex->light = 350;
1528 ex->lightcolor[0] = 1.0;
1529 ex->lightcolor[1] = 0.5;
1530 ex->lightcolor[2] = 0.5;
1531 ex->ent.angles[1] = rand() % 360;
1532 ex->ent.model = cl_mod_explo4;
1533 ex->ent.scale = cl_explosion_scale->value;
1534 if (frand() < 0.5)
1535 ex->baseframe = 15;
1536 ex->frames = 15;
1537 CL_Explosion_Decal (pos, 65);
1538
1539 }
1540 #else
1541 if (!cl_explosion->value)
1542 {
1543 ex = CL_AllocExplosion ();
1544 VectorCopy (pos, ex->ent.origin);
1545 ex->type = ex_poly;
1546 ex->ent.flags = RF_FULLBRIGHT;
1547 ex->start = cl.frame.servertime - 100;
1548 ex->light = 350;
1549 ex->lightcolor[0] = 1.0;
1550 ex->lightcolor[1] = 0.5;
1551 ex->lightcolor[2] = 0.5;
1552 ex->ent.angles[1] = rand() % 360;
1553 ex->ent.model = cl_mod_explo4;
1554 ex->ent.scale = cl_explosion_scale->value;
1555 if (frand() < 0.5)
1556 ex->baseframe = 15;
1557 ex->frames = 15;
1558
1559 CL_Explosion_Decal (pos, 65);
1560 }
1561 else
1562 CL_Explosion_Particle (pos, 50, 0, 0);
1563
1564 CL_ExplosionParticles (pos, 0.6666666, 0);
1565 #endif
1566 #else
1567 CL_FindExplosionPlane(pos, 80, dir);
1568 re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1569 56 + ((rand()%21*0.05) - 0.5),
1570 DECAL_EXPLODE, 0, rand()%361);
1571 ex = CL_AllocExplosion ();
1572 VectorCopy (pos, ex->ent.origin);
1573 ex->type = ex_poly;
1574 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1575 ex->light = 350;
1576 ex->lightcolor[0] = 1.0;
1577 ex->lightcolor[1] = 0.5;
1578 ex->lightcolor[2] = 0.5;
1579 ex->ent.angles[1] = rand() % 360;
1580 if (type != TE_EXPLOSION1_BIG) // PMM
1581 ex->ent.model = cl_mod_explo4; // PMM
1582 else
1583 ex->ent.model = cl_mod_explo4_big;
1584 if (frand() < 0.5)
1585 ex->baseframe = 15;
1586 ex->frames = 15;
1587 if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
1588 CL_ExplosionParticles (pos); // PMM
1589 #endif
1590 if (type == TE_ROCKET_EXPLOSION_WATER)
1591 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1592 else
1593 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1594 break;
1595
1596 case TE_BFG_EXPLOSION:
1597 MSG_ReadPos (&net_message, pos);
1598 #if defined(PARTICLESYSTEM)
1599 #if 1
1600 CL_BFGExplosionParticles_2(pos);
1601 #else
1602 ex = CL_AllocExplosion ();
1603 VectorCopy (pos, ex->ent.origin);
1604 ex->type = ex_poly;
1605 ex->ent.flags = RF_FULLBRIGHT;
1606 ex->start = cl.frame.servertime - 100;
1607 ex->light = 350;
1608 ex->lightcolor[0] = 0.0;
1609 ex->lightcolor[1] = 1.0;
1610 ex->lightcolor[2] = 0.0;
1611 ex->ent.model = cl_mod_bfg_explo;
1612 ex->ent.flags |= RF_TRANSLUCENT | RF_TRANS_ADDITIVE;
1613 ex->ent.alpha = 0.9999;
1614 ex->frames = 4;
1615 ex->ent.scale = 1;
1616 #endif
1617 #else
1618 ex = CL_AllocExplosion ();
1619 VectorCopy (pos, ex->ent.origin);
1620 ex->type = ex_poly;
1621 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1622 ex->light = 350;
1623 ex->lightcolor[0] = 0.0;
1624 ex->lightcolor[1] = 1.0;
1625 ex->lightcolor[2] = 0.0;
1626 ex->ent.model = cl_mod_bfg_explo;
1627 ex->ent.flags |= RF_TRANSLUCENT|RF_NOSHADOW;
1628 ex->ent.alpha = 0.30;
1629 ex->frames = 4;
1630 #endif
1631 break;
1632
1633 case TE_BFG_BIGEXPLOSION:
1634 MSG_ReadPos (&net_message, pos);
1635 CL_BFGExplosionParticles (pos);
1636 #if defined(PARTICLESYSTEM)
1637 CL_Explosion_Decal (pos, 75);
1638 #else
1639 CL_FindExplosionPlane(pos, 96, dir);
1640 re.AddDecal(pos, dir, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1,
1641 60,
1642 DECAL_BFG, 0, rand()%361);
1643 #endif
1644 break;
1645
1646 case TE_BFG_LASER:
1647 CL_ParseLaser (0xd0d1d2d3);
1648 break;
1649
1650 case TE_BUBBLETRAIL:
1651 MSG_ReadPos (&net_message, pos);
1652 MSG_ReadPos (&net_message, pos2);
1653 CL_BubbleTrail (pos, pos2);
1654 break;
1655
1656 case TE_PARASITE_ATTACK:
1657 case TE_MEDIC_CABLE_ATTACK:
1658 ent = CL_ParseBeam (cl_mod_parasite_segment);
1659 break;
1660
1661 case TE_BOSSTPORT: // boss teleporting to station
1662 MSG_ReadPos (&net_message, pos);
1663 CL_BigTeleportParticles (pos);
1664 S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
1665 break;
1666
1667 case TE_GRAPPLE_CABLE:
1668 ent = CL_ParseBeam2 (cl_mod_grapple_cable);
1669 break;
1670
1671 // RAFAEL
1672 case TE_WELDING_SPARKS:
1673 cnt = MSG_ReadByte (&net_message);
1674 MSG_ReadPos (&net_message, pos);
1675 MSG_ReadDir (&net_message, dir);
1676 color = MSG_ReadByte (&net_message);
1677 #if defined(PARTICLESYSTEM)
1678 {
1679 vec3_t sparkcolor = {
1680 color8red(color),
1681 color8green(color),
1682 color8blue(color)
1683 };
1684
1685 CL_ParticleEffectSparks(pos, dir, sparkcolor, 40);
1686 }
1687 #else
1688 CL_ParticleEffect2 (pos, dir, color, cnt);
1689
1690 ex = CL_AllocExplosion ();
1691 VectorCopy (pos, ex->ent.origin);
1692 ex->type = ex_flash;
1693 // note to self
1694 // we need a better no draw flag
1695 ex->ent.flags = RF_BEAM|RF_NOSHADOW;
1696 ex->light = 100 + (rand()%75);
1697 ex->lightcolor[0] = 1.0;
1698 ex->lightcolor[1] = 1.0;
1699 ex->lightcolor[2] = 0.3;
1700 ex->ent.model = cl_mod_flash;
1701 ex->frames = 2;
1702 #endif
1703 break;
1704
1705 case TE_GREENBLOOD:
1706 MSG_ReadPos (&net_message, pos);
1707 MSG_ReadDir (&net_message, dir);
1708 #if defined(PARTICLESYSTEM)
1709 #if 0
1710 CL_GreenBloodHit(pos, dir);
1711 #else
1712 CL_ParticleEffect2 (pos, dir, 0xdf, 30);
1713 #endif
1714 #else
1715 CL_ParticleEffect2 (pos, dir, 0xdf, 30);
1716 #endif
1717 break;
1718
1719 // RAFAEL
1720 case TE_TUNNEL_SPARKS:
1721 cnt = MSG_ReadByte (&net_message);
1722 MSG_ReadPos (&net_message, pos);
1723 MSG_ReadDir (&net_message, dir);
1724 color = MSG_ReadByte (&net_message);
1725 CL_ParticleEffect3 (pos, dir, color, cnt);
1726 break;
1727
1728 //=============
1729 //PGM
1730 // PMM -following code integrated for flechette (different color)
1731 case TE_BLASTER2: // green blaster hitting wall
1732 case TE_FLECHETTE: // flechette
1733 MSG_ReadPos (&net_message, pos);
1734 MSG_ReadDir (&net_message, dir);
1735 #if defined(PARTICLESYSTEM)
1736 #if 1
1737 if (type == TE_BLASTER2) {
1738 CL_BlasterParticlesColor (pos, dir, 40, 50, 235, 50, -10, 0, -10);
1739 red=50;
1740 green=235;
1741 blue=50;
1742 }
1743 else if (type == TE_BLUEHYPERBLASTER) {
1744 CL_BlasterParticlesColor (pos, dir, 40, 50, 50, 235, -10, 0, -10);
1745 red=50;
1746 green=50;
1747 blue=235;
1748 }
1749 else {
1750 CL_BlasterParticlesColor (pos, dir, 40, 100, 100, 195, -10, 0, -10);
1751 red=100;
1752 green=100;
1753 blue=195;
1754 }
1755 CL_ParticleBlasterColorDecal(pos, dir, 7.5, red, green, blue);
1756 #else
1757 CL_BlasterParticlesColor(pos, dir, 40, 50, 50, 235, 0, -90, -30);
1758 #endif
1759 #else
1760 // PMM
1761 if (type == TE_BLASTER2)
1762 CL_BlasterParticles2 (pos, dir, 0xd0);
1763 else
1764 CL_BlasterParticles2 (pos, dir, 0x6f); // 75
1765 re.AddDecal(pos, dir, 1, 0.5, 0, 1, 1, 0.5, 0, 1, 4,
1766 DECAL_BLASTER, 0, 0);
1767 ex = CL_AllocExplosion ();
1768 VectorCopy (pos, ex->ent.origin);
1769 ex->ent.angles[0] = acos(dir[2])/M_PI*180;
1770 // PMM - fixed to correct for pitch of 0
1771 if (dir[0])
1772 ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
1773 else if (dir[1] > 0)
1774 ex->ent.angles[1] = 90;
1775 else if (dir[1] < 0)
1776 ex->ent.angles[1] = 270;
1777 else
1778 ex->ent.angles[1] = 0;
1779
1780 ex->type = ex_misc;
1781 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW;
1782
1783 // PMM
1784 if (type == TE_BLASTER2)
1785 ex->ent.skinnum = 1;
1786 else // flechette
1787 ex->ent.skinnum = 2;
1788
1789 ex->light = 150;
1790 // PMM
1791 if (type == TE_BLASTER2)
1792 ex->lightcolor[1] = 1;
1793 else // flechette
1794 {
1795 ex->lightcolor[0] = 0.19;
1796 ex->lightcolor[1] = 0.41;
1797 ex->lightcolor[2] = 0.75;
1798 }
1799 ex->ent.model = cl_mod_explode;
1800 ex->frames = 4;
1801 #endif
1802 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1803 break;
1804
1805
1806 case TE_LIGHTNING:
1807 #if defined(PARTICLESYSTEM)
1808 ent = CL_ParseLightning (10);
1809 #else
1810 ent = CL_ParseLightning (cl_mod_lightning);
1811 #endif
1812 S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
1813 break;
1814
1815 case TE_DEBUGTRAIL:
1816 MSG_ReadPos (&net_message, pos);
1817 MSG_ReadPos (&net_message, pos2);
1818 CL_DebugTrail (pos, pos2);
1819 break;
1820
1821 case TE_PLAIN_EXPLOSION:
1822 MSG_ReadPos (&net_message, pos);
1823 #if defined(PARTICLESYSTEM)
1824 #if 0
1825 if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1826 CL_Explosion_Particle(pos, 50, true, true);
1827 CL_ExplosionParticles(pos, 0.6666666, 0);
1828 CL_Explosion_Sparks(pos, 21);
1829 } else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1830 CL_Explosion_Particle(pos, 50, true, true);
1831 CL_ExplosionParticles_Old(pos);
1832 } else {
1833 ex = CL_AllocExplosion();
1834 VectorCopy(pos, ex->ent.origin);
1835 ex->type = ex_poly;
1836 ex->ent.flags = RF_FULLBRIGHT | RF_NOSHADOW;
1837 ex->start = cl.frame.servertime - 100;
1838 ex->light = 350;
1839 ex->lightcolor[0] = 1.0;
1840 ex->lightcolor[1] = 0.5;
1841 ex->lightcolor[2] = 0.5;
1842 ex->ent.angles[1] = rand() % 360;
1843 ex->ent.model = cl_mod_explo4;
1844 if (frand() < 0.5)
1845 ex->baseframe = 15;
1846 ex->frames = 15;
1847 }
1848 #else
1849 ex = CL_AllocExplosion ();
1850 VectorCopy (pos, ex->ent.origin);
1851 ex->type = ex_poly;
1852 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1853 ex->light = 350;
1854 ex->lightcolor[0] = 1.0;
1855 ex->lightcolor[1] = 0.5;
1856 ex->lightcolor[2] = 0.5;
1857 ex->ent.angles[1] = rand() % 360;
1858 ex->ent.model = cl_mod_explo4;
1859 if (frand() < 0.5)
1860 ex->baseframe = 15;
1861 ex->frames = 15;
1862 #endif
1863 #else
1864 CL_FindExplosionPlane(pos, 70, dir);
1865 re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1866 56 + ((rand()%21*0.05) - 0.5),
1867 DECAL_EXPLODE, 0, rand()%361);
1868 ex = CL_AllocExplosion ();
1869 VectorCopy (pos, ex->ent.origin);
1870 ex->type = ex_poly;
1871 ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1872 ex->light = 350;
1873 ex->lightcolor[0] = 1.0;
1874 ex->lightcolor[1] = 0.5;
1875 ex->lightcolor[2] = 0.5;
1876 ex->ent.angles[1] = rand() % 360;
1877 ex->ent.model = cl_mod_explo4;
1878 if (frand() < 0.5)
1879 ex->baseframe = 15;
1880 ex->frames = 15;
1881 #endif
1882 if (type == TE_ROCKET_EXPLOSION_WATER)
1883 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1884 else
1885 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1886 break;
1887
1888 case TE_FLASHLIGHT:
1889 MSG_ReadPos(&net_message, pos);
1890 ent = MSG_ReadShort(&net_message);
1891 CL_Flashlight(ent, pos);
1892 break;
1893
1894 case TE_FORCEWALL:
1895 MSG_ReadPos(&net_message, pos);
1896 MSG_ReadPos(&net_message, pos2);
1897 color = MSG_ReadByte (&net_message);
1898 CL_ForceWall(pos, pos2, color);
1899 break;
1900
1901 case TE_HEATBEAM:
1902 ent = CL_ParsePlayerBeam (cl_mod_heatbeam);
1903 break;
1904
1905 case TE_MONSTER_HEATBEAM:
1906 ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam);
1907 break;
1908
1909 case TE_HEATBEAM_SPARKS:
1910 cnt = 50;
1911 MSG_ReadPos (&net_message, pos);
1912 MSG_ReadDir (&net_message, dir);
1913 r = 8;
1914 magnitude = 60;
1915 color = r & 0xff;
1916 #if defined(PARTICLESYSTEM)
1917 CL_ParticleSteamEffect(pos, dir, 240, 240, 240, -20, -20, -20, cnt, magnitude);
1918 #else
1919 CL_ParticleSteamEffect(pos, dir, color, cnt, magnitude);
1920 #endif
1921 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1922 break;
1923
1924 case TE_HEATBEAM_STEAM:
1925 cnt = 20;
1926 MSG_ReadPos (&net_message, pos);
1927 MSG_ReadDir (&net_message, dir);
1928 magnitude = 60;
1929 color = 0xe0;
1930 #if defined(PARTICLESYSTEM)
1931 CL_ParticleSteamEffect(pos, dir, 255, 150, 50, 0, -90, -30, cnt, magnitude);
1932 CL_ParticleBlasterDecal(pos, dir, 7.5);
1933 #else
1934 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
1935 #endif
1936 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1937 break;
1938
1939 case TE_STEAM:
1940 CL_ParseSteam();
1941 break;
1942
1943 case TE_BUBBLETRAIL2:
1944 // cnt = MSG_ReadByte (&net_message);
1945 cnt = 8;
1946 MSG_ReadPos (&net_message, pos);
1947 MSG_ReadPos (&net_message, pos2);
1948 CL_BubbleTrail2 (pos, pos2, cnt);
1949 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1950 break;
1951
1952 case TE_MOREBLOOD:
1953 MSG_ReadPos (&net_message, pos);
1954 MSG_ReadDir (&net_message, dir);
1955 CL_ParticleEffect (pos, dir, 0xe8, 250);
1956 break;
1957
1958 case TE_CHAINFIST_SMOKE:
1959 dir[0]=0; dir[1]=0; dir[2]=1;
1960 MSG_ReadPos(&net_message, pos);
1961 #if defined(PARTICLESYSTEM)
1962 CL_ParticleSmokeEffect(pos, dir, 25, 1);
1963 #else
1964 CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
1965 #endif
1966 break;
1967
1968 case TE_ELECTRIC_SPARKS:
1969 MSG_ReadPos (&net_message, pos);
1970 MSG_ReadDir (&net_message, dir);
1971 // CL_ParticleEffect (pos, dir, 109, 40);
1972 #if defined(PARTICLESYSTEM)
1973 CL_ElectricParticles(pos, dir, 40);
1974 #else
1975 CL_ParticleEffect (pos, dir, 0x75, 40);
1976 #endif
1977 //FIXME : replace or remove this sound
1978 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1979 break;
1980
1981 case TE_TRACKER_EXPLOSION:
1982 MSG_ReadPos (&net_message, pos);
1983 CL_ColorFlash (pos, 0, 150, -1, -1, -1);
1984 #if 1
1985 CL_ColorExplosionParticles(pos, 0, 1);
1986 #else
1987 CL_Tracker_Explode (pos);
1988 #endif
1989 S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
1990 break;
1991
1992 case TE_TELEPORT_EFFECT:
1993 case TE_DBALL_GOAL:
1994 MSG_ReadPos (&net_message, pos);
1995 CL_TeleportParticles (pos);
1996 break;
1997
1998 case TE_WIDOWBEAMOUT:
1999 CL_ParseWidow ();
2000 break;
2001
2002 case TE_NUKEBLAST:
2003 CL_ParseNuke ();
2004 break;
2005
2006 case TE_WIDOWSPLASH:
2007 MSG_ReadPos (&net_message, pos);
2008 CL_WidowSplash (pos);
2009 break;
2010
2011 //NEW CUSTOM TEMP EVENTS
2012
2013 #if defined(PARTICLESYSTEM)
2014 case TE_LIGHTNINGFLARE: //-psychospaz
2015 {
2016 int num, entity;
2017
2018 entity = MSG_ReadShort (&net_message);
2019 num = MSG_ReadShort (&net_message);
2020 MSG_ReadPos (&net_message, pos);
2021
2022 //double up for opacity endurance
2023 CL_LightningFlare(pos, entity, 2*num);
2024 CL_LightningFlare(pos, entity, 2*num+1);
2025 }
2026 break;
2027 case TE_SMOKEPUFF:
2028 {
2029 float size;
2030
2031 MSG_ReadPos (&net_message, pos);
2032 MSG_ReadPos (&net_message, dir);
2033 size = MSG_ReadFloat(&net_message);
2034
2035 CL_ParticleSmokeEffect (pos, dir, size, 1);
2036 }
2037 break;
2038 case TE_IMPACTMARK:
2039 {
2040 float size;
2041 int flags;
2042
2043 MSG_ReadPos (&net_message, pos);
2044 MSG_ReadPos (&net_message, dir);
2045 size = MSG_ReadFloat(&net_message);
2046 flags = MSG_ReadLong (&net_message);
2047
2048 CL_ImpactMark (pos, dir, size, flags, particle_impact);
2049 }
2050 break;
2051 case TE_FOOTPRINT:
2052 {
2053 float size;
2054 vec3_t color, angle;
2055
2056 MSG_ReadPos (&net_message, pos);
2057 MSG_ReadPos (&net_message, dir);
2058 MSG_ReadPos (&net_message, color);
2059 size = MSG_ReadFloat(&net_message);
2060
2061 angle[0] = anglemod(dir[0] + 180);
2062 angle[1] = anglemod(dir[1]);
2063 angle[2] = anglemod(dir[2]);
2064
2065 CL_ParticleFootPrint (pos, angle, size, color);
2066 }
2067 break;
2068 case TE_FLAMEBURST:
2069 {
2070 float size;
2071
2072 MSG_ReadPos (&net_message, pos);
2073 size = MSG_ReadFloat(&net_message);
2074
2075 CL_FlameBurst (pos, size);
2076 }
2077 break;
2078 case TE_DISRUPTOR_EXPLOSION:
2079 {
2080 float size;
2081
2082 MSG_ReadPos (&net_message, pos);
2083 size = MSG_ReadFloat(&net_message);
2084
2085 CL_Disruptor_Explosion_Particle (pos, size);
2086
2087 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
2088 }
2089 break;
2090 case TE_DISINTEGRATE:
2091 {
2092 ent = MSG_ReadByte(&net_message);
2093 MSG_ReadPos (&net_message, pos);
2094 CL_Disintegrate (pos, ent);
2095 }
2096 break;
2097 #endif
2098 //PGM
2099 //==============
2100
2101 default:
2102 Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
2103 }
2104 }
2105
2106 /*
2107 =================
2108 CL_AddBeams
2109 =================
2110 */
2111 extern cvar_t *hand;
2112 /* Knightmare- backup of client angles */
2113 extern vec3_t old_viewangles;
CL_AddBeams(void)2114 void CL_AddBeams (void)
2115 {
2116 int i,j;
2117 beam_t *b;
2118 vec3_t dist, org;
2119 float d;
2120 entity_t ent;
2121 float yaw, pitch;
2122 float forward;
2123 float len, steps;
2124 float model_length;
2125
2126 /* Knightmare added */
2127 frame_t *oldframe;
2128 player_state_t *ps, *ops;
2129 qboolean firstperson, chasecam;
2130 int handmult;
2131 vec3_t thirdp_grapple_offset;
2132 vec3_t grapple_offset_dir;
2133
2134 /* Knightmare- chasecam grapple offset stuff */
2135 if (hand) {
2136 if (hand->value == 2)
2137 handmult = 1;
2138 else if (hand->value == 1)
2139 handmult = -1;
2140 else
2141 handmult = 1;
2142 } else
2143 handmult = 1;
2144 VectorSet(thirdp_grapple_offset, 6, 16, 16);
2145 /* end Knightmare */
2146
2147 // update beams
2148 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
2149 {
2150 if (!b->model || b->endtime < cl.stime)
2151 continue;
2152
2153 /* Knightmare- */
2154 firstperson = ((b->entity == cl.playernum + 1) && !cl_3dcam->value);
2155 chasecam = ((b->entity == cl.playernum + 1) && cl_3dcam->value);
2156
2157 // if coming from the player, update the start position
2158 if (firstperson) {// entity 0 is the world
2159 VectorCopy (cl.refdef.vieworg, b->start);
2160 b->start[2] -= 22; // adjust for view height
2161 } else if (chasecam) {
2162 vec3_t f, r, u;
2163
2164 ps = &cl.frame.playerstate;
2165 j = (cl.frame.serverframe - 1) & UPDATE_MASK;
2166 oldframe = &cl.frames[j];
2167 if (oldframe->serverframe != cl.frame.serverframe - 1 || !oldframe->valid)
2168 oldframe = &cl.frame;
2169 ops = &oldframe->playerstate;
2170
2171 AngleVectors(old_viewangles, f, r, u);
2172 VectorClear(grapple_offset_dir);
2173 for (j = 0; j < 3; j++) {
2174 grapple_offset_dir[j] += f[j] * thirdp_grapple_offset[1];
2175 grapple_offset_dir[j] += r[j] * thirdp_grapple_offset[0] * handmult;
2176 grapple_offset_dir[j] += u[j] * (-thirdp_grapple_offset[2]);
2177 }
2178
2179 for (j = 0; j < 3; j++)
2180 b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j]
2181 + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j])
2182 + grapple_offset_dir[j];
2183 }
2184 if (chasecam)
2185 VectorCopy(b->start, org);
2186 else
2187 VectorAdd (b->start, b->offset, org);
2188
2189 // calculate pitch and yaw
2190 VectorSubtract (b->end, org, dist);
2191
2192 if (dist[1] == 0 && dist[0] == 0)
2193 {
2194 yaw = 0;
2195 if (dist[2] > 0)
2196 pitch = 90;
2197 else
2198 pitch = 270;
2199 }
2200 else
2201 {
2202 // PMM - fixed to correct for pitch of 0
2203 if (dist[0])
2204 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
2205 else if (dist[1] > 0)
2206 yaw = 90;
2207 else
2208 yaw = 270;
2209 if (yaw < 0)
2210 yaw += 360;
2211
2212 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
2213 pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
2214 if (pitch < 0)
2215 pitch += 360.0;
2216 }
2217
2218 // add new entities for the beams
2219 d = VectorNormalize(dist);
2220
2221 memset (&ent, 0, sizeof(ent));
2222 if (b->model == cl_mod_lightning)
2223 {
2224 model_length = 35.0;
2225 d-= 20.0; // correction so it doesn't end in middle of tesla
2226 }
2227 else
2228 {
2229 model_length = 30.0;
2230 }
2231 steps = ceil(d/model_length);
2232 len = (d-model_length)/(steps-1);
2233
2234 // PMM - special case for lightning model .. if the real length is shorter than the model,
2235 // flip it around & draw it from the end to the start. This prevents the model from going
2236 // through the tesla mine (instead it goes through the target)
2237 if ((b->model == cl_mod_lightning) && (d <= model_length))
2238 {
2239 // Com_Printf ("special case\n");
2240 VectorCopy (b->end, ent.origin);
2241 // offset to push beam outside of tesla model (negative because dist is from end to start
2242 // for this beam)
2243 // for (j=0 ; j<3 ; j++)
2244 // ent.origin[j] -= dist[j]*10.0;
2245 ent.model = b->model;
2246 ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2247 ent.angles[0] = pitch;
2248 ent.angles[1] = yaw;
2249 ent.angles[2] = rand()%360;
2250 V_AddEntity (&ent);
2251 return;
2252 }
2253 while (d > 0)
2254 {
2255 VectorCopy (org, ent.origin);
2256 ent.model = b->model;
2257 if (b->model == cl_mod_lightning)
2258 {
2259 ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2260 ent.angles[0] = -pitch;
2261 ent.angles[1] = yaw + 180.0;
2262 ent.angles[2] = rand()%360;
2263 }
2264 else
2265 {
2266 ent.angles[0] = pitch;
2267 ent.angles[1] = yaw;
2268 ent.angles[2] = rand()%360;
2269 }
2270
2271 // Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
2272 ent.flags |= RF_NOSHADOW;
2273 V_AddEntity (&ent);
2274
2275 for (j=0 ; j<3 ; j++)
2276 org[j] += dist[j]*len;
2277 d -= model_length;
2278 }
2279 }
2280 }
2281
2282
2283 /*
2284 =================
2285 ROGUE - draw player locked beams
2286 CL_AddPlayerBeams
2287 =================
2288 */
CL_AddPlayerBeams(void)2289 void CL_AddPlayerBeams (void)
2290 {
2291 int i,j;
2292 beam_t *b;
2293 vec3_t dist, org;
2294 float d;
2295 entity_t ent;
2296 float yaw, pitch;
2297 float forward;
2298 float len, steps;
2299 int framenum = 0;
2300 float model_length;
2301
2302 float hand_multiplier;
2303 frame_t *oldframe;
2304 player_state_t *ps, *ops;
2305 /* Knightmare- */
2306 qboolean firstperson, chasecam;
2307 int newhandmult;
2308 vec3_t thirdp_pbeam_offset;
2309 vec3_t pbeam_offset_dir;
2310
2311 //PMM
2312 if (hand)
2313 {
2314 if (hand->value == 2)
2315 hand_multiplier = 0;
2316 else if (hand->value == 1)
2317 hand_multiplier = -1;
2318 else
2319 hand_multiplier = 1;
2320 }
2321 else
2322 {
2323 hand_multiplier = 1;
2324 }
2325 //PMM
2326 /* Knightmare- chasecam beam offset stuff */
2327 newhandmult = hand_multiplier;
2328 if (newhandmult == 0)
2329 newhandmult = 1;
2330
2331 VectorSet(thirdp_pbeam_offset, 6.5, 0, 12);
2332 /* end Knightmare */
2333
2334 // update beams
2335 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
2336 {
2337 vec3_t f,r,u;
2338
2339 if (!b->model || b->endtime < cl.stime)
2340 continue;
2341
2342 firstperson = ((b->entity == cl.playernum + 1) && !cl_3dcam->value);
2343 chasecam = ((b->entity == cl.playernum + 1) && cl_3dcam->value);
2344
2345 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
2346 {
2347
2348 // if coming from the player, update the start position
2349 if (firstperson || chasecam) // entity 0 is the world
2350 {
2351 // set up gun position
2352 // code straight out of CL_AddViewWeapon
2353 ps = &cl.frame.playerstate;
2354 j = (cl.frame.serverframe - 1) & UPDATE_MASK;
2355 oldframe = &cl.frames[j];
2356 if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
2357 oldframe = &cl.frame; // previous frame was dropped or involid
2358 ops = &oldframe->playerstate;
2359 /* Knightmare- lerp for chasecam mode */
2360 if (chasecam) { /* Knightmare- use player's original viewangles */
2361 AngleVectors(old_viewangles, f, r, u);
2362 VectorClear(pbeam_offset_dir);
2363 for (j = 0; j < 3; j++) {
2364 pbeam_offset_dir[j] += f[j] * thirdp_pbeam_offset[1];
2365 pbeam_offset_dir[j] += r[j] * thirdp_pbeam_offset[0] * newhandmult;
2366 pbeam_offset_dir[j] += u[j] * (-thirdp_pbeam_offset[2]);
2367 }
2368 for (j = 0; j < 3; j++)
2369 b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j]
2370 + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j])
2371 + pbeam_offset_dir[j];
2372 VectorMA(b->start, (newhandmult * b->offset[0]), r, org);
2373 VectorMA(org, b->offset[1], f, org);
2374 VectorMA(org, b->offset[2], u, org);
2375 } else {
2376 for (j=0 ; j<3 ; j++) {
2377 b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
2378 + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
2379 }
2380 VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
2381 VectorMA ( org, b->offset[1], cl.v_forward, org);
2382 VectorMA ( org, b->offset[2], cl.v_up, org);
2383 if ((hand) && (hand->value == 2)) {
2384 VectorMA (org, -1, cl.v_up, org);
2385 }
2386 // FIXME - take these out when final
2387 VectorCopy (cl.v_right, r);
2388 VectorCopy (cl.v_forward, f);
2389 VectorCopy (cl.v_up, u);
2390 }
2391
2392 }
2393 else
2394 VectorCopy (b->start, org);
2395 }
2396 else
2397 {
2398 // if coming from the player, update the start position
2399 if (firstperson) // entity 0 is the world
2400 {
2401 VectorCopy (cl.refdef.vieworg, b->start);
2402 b->start[2] -= 22; // adjust for view height
2403 }
2404 VectorAdd (b->start, b->offset, org);
2405 }
2406
2407 // calculate pitch and yaw
2408 VectorSubtract (b->end, org, dist);
2409
2410 //PMM
2411 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (firstperson || chasecam))
2412 {
2413 vec_t len;
2414
2415 len = VectorLength (dist);
2416 VectorScale (f, len, dist);
2417 if (chasecam)
2418 VectorMA(dist, (newhandmult * b->offset[0]), r, dist);
2419 else
2420 VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
2421 VectorMA (dist, b->offset[1], f, dist);
2422 VectorMA (dist, b->offset[2], u, dist);
2423 if (chasecam) {
2424 VectorMA(dist, -(newhandmult * thirdp_pbeam_offset[0]), r, dist);
2425 VectorMA(dist, thirdp_pbeam_offset[1], f, dist);
2426 VectorMA(dist, thirdp_pbeam_offset[2], u, dist);
2427 }
2428 if ((hand) && (hand->value == 2) && !chasecam) {
2429 VectorMA (org, -1, cl.v_up, org);
2430 }
2431 }
2432 //PMM
2433
2434 if (dist[1] == 0 && dist[0] == 0)
2435 {
2436 yaw = 0;
2437 if (dist[2] > 0)
2438 pitch = 90;
2439 else
2440 pitch = 270;
2441 }
2442 else
2443 {
2444 // PMM - fixed to correct for pitch of 0
2445 if (dist[0])
2446 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
2447 else if (dist[1] > 0)
2448 yaw = 90;
2449 else
2450 yaw = 270;
2451 if (yaw < 0)
2452 yaw += 360;
2453
2454 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
2455 pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
2456 if (pitch < 0)
2457 pitch += 360.0;
2458 }
2459
2460 if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) {
2461 if (!firstperson) {
2462 framenum = 2;
2463 ent.angles[0] = -pitch;
2464 ent.angles[1] = yaw + 180.0;
2465 ent.angles[2] = 0;
2466
2467 if (!chasecam) {
2468 AngleVectors(ent.angles, f, r, u);
2469
2470 // if it's a non-origin offset, it's a player, so use the hardcoded player offset
2471 if (!VectorCompare (b->offset, vec3_origin)) {
2472 VectorMA (org, -(b->offset[0])+1, r, org);
2473 VectorMA (org, -(b->offset[1]), f, org);
2474 VectorMA (org, -(b->offset[2])-10, u, org);
2475 }
2476 else {
2477 // if it's a monster, do the particle effect
2478 CL_MonsterPlasma_Shell(b->start);
2479 }
2480 }
2481 }
2482 else {
2483 framenum = 1;
2484 }
2485 }
2486
2487 // if it's the heatbeam, draw the particle effect
2488 if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (firstperson || chasecam))) {
2489 CL_Heatbeam (org, dist);
2490 }
2491
2492 // add new entities for the beams
2493 d = VectorNormalize(dist);
2494
2495 memset (&ent, 0, sizeof(ent));
2496 if (b->model == cl_mod_heatbeam) {
2497 model_length = 32.0;
2498 }
2499 else if (b->model == cl_mod_lightning) {
2500 model_length = 35.0;
2501 d-= 20.0; // correction so it doesn't end in middle of tesla
2502 }
2503 else {
2504 model_length = 30.0;
2505 }
2506 steps = ceil(d/model_length);
2507 len = (d-model_length)/(steps-1);
2508
2509 // PMM - special case for lightning model .. if the real length is shorter than the model,
2510 // flip it around & draw it from the end to the start. This prevents the model from going
2511 // through the tesla mine (instead it goes through the target)
2512 if ((b->model == cl_mod_lightning) && (d <= model_length))
2513 {
2514 VectorCopy (b->end, ent.origin);
2515 // offset to push beam outside of tesla model (negative because dist is from end to start
2516 // for this beam)
2517 ent.model = b->model;
2518 ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2519 ent.angles[0] = pitch;
2520 ent.angles[1] = yaw;
2521 ent.angles[2] = rand()%360;
2522 V_AddEntity (&ent);
2523 return;
2524 }
2525 while (d > 0)
2526 {
2527 VectorCopy (org, ent.origin);
2528 ent.model = b->model;
2529 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
2530 {
2531 ent.angles[0] = -pitch;
2532 ent.angles[1] = yaw + 180.0;
2533 ent.angles[2] = (cl.stime) % 360;
2534 ent.frame = framenum;
2535 }
2536 else if (b->model == cl_mod_lightning)
2537 {
2538 ent.flags = RF_FULLBRIGHT;
2539 ent.angles[0] = -pitch;
2540 ent.angles[1] = yaw + 180.0;
2541 ent.angles[2] = rand()%360;
2542 }
2543 else
2544 {
2545 ent.angles[0] = pitch;
2546 ent.angles[1] = yaw;
2547 ent.angles[2] = rand()%360;
2548 }
2549 ent.flags |= RF_NOSHADOW;
2550
2551 V_AddEntity (&ent);
2552
2553 for (j=0 ; j<3 ; j++)
2554 org[j] += dist[j]*len;
2555 d -= model_length;
2556 }
2557 }
2558 }
2559
2560 /*
2561 =================
2562 CL_AddExplosions
2563 =================
2564 */
CL_AddExplosions(void)2565 void CL_AddExplosions (void)
2566 {
2567 entity_t *ent;
2568 explosion_t *ex, *next, *hnode;
2569 float frac;
2570 int f;
2571
2572 memset (&ent, 0, sizeof(ent));
2573
2574 hnode = &cl_explosions_headnode;
2575 for (ex = hnode->next; ex != hnode; ex = next)
2576 {
2577 next = ex->next;
2578 ent = &ex->ent;
2579
2580 frac = (cl.stime - ex->start)/100.0;
2581 f = floor(frac);
2582
2583 switch (ex->type)
2584 {
2585 case ex_mflash:
2586 if (f >= ex->frames-1)
2587 ex->type = ex_free;
2588 break;
2589 case ex_misc:
2590 if (f >= ex->frames-1)
2591 {
2592 ex->type = ex_free;
2593 break;
2594 }
2595 ent->alpha = 1.0 - frac/(ex->frames-1);
2596 break;
2597 case ex_flash:
2598 if (f >= 1)
2599 {
2600 ex->type = ex_free;
2601 break;
2602 }
2603 ent->alpha = 1.0;
2604 break;
2605 case ex_poly:
2606 if (f >= ex->frames-1)
2607 {
2608 ex->type = ex_free;
2609 break;
2610 }
2611
2612 ent->alpha = (16.0 - (float)f)/16.0;
2613
2614 if (f < 10)
2615 {
2616 ent->skinnum = (f>>1);
2617 if (ent->skinnum < 0)
2618 ent->skinnum = 0;
2619 }
2620 else
2621 {
2622 ent->flags |= RF_TRANSLUCENT|RF_NOSHADOW;
2623 if (f < 13)
2624 ent->skinnum = 5;
2625 else
2626 ent->skinnum = 6;
2627 }
2628 break;
2629 case ex_poly2:
2630 if (f >= ex->frames-1)
2631 {
2632 ex->type = ex_free;
2633 break;
2634 }
2635
2636 ent->alpha = (5.0 - (float)f)/5.0;
2637 ent->skinnum = 0;
2638 ent->flags |= RF_TRANSLUCENT|RF_NOSHADOW;
2639 break;
2640 default:
2641 break;
2642 }
2643
2644 if (ex->type == ex_free)
2645 {
2646 CL_FreeExplosion (ex);
2647 continue;
2648 }
2649
2650 if (ex->light)
2651 {
2652 V_AddLight (ent->origin, ex->light*ent->alpha,
2653 ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
2654 }
2655
2656 VectorCopy (ent->origin, ent->oldorigin);
2657
2658 if (f < 0)
2659 f = 0;
2660 ent->frame = ex->baseframe + f + 1;
2661 ent->oldframe = ex->baseframe + f;
2662 ent->backlerp = 1.0 - cl.lerpfrac;
2663
2664 V_AddEntity (ent);
2665 }
2666 }
2667
2668
2669 /*
2670 =================
2671 CL_AddLasers
2672 =================
2673 */
CL_AddLasers(void)2674 void CL_AddLasers (void)
2675 {
2676 laser_t *l;
2677 int i;
2678
2679 for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
2680 {
2681 if (l->endtime >= cl.stime)
2682 V_AddEntity (&l->ent);
2683 }
2684 }
2685
2686 /* PMM - CL_Sustains */
CL_ProcessSustain(void)2687 void CL_ProcessSustain (void)
2688 {
2689 cl_sustain_t *s;
2690 int i;
2691
2692 for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
2693 {
2694 if (s->id) {
2695 if ((s->endtime >= cl.stime) && (cl.stime >= s->nextthink))
2696 {
2697 // Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
2698 s->think (s);
2699 }
2700 else if (s->endtime < cl.stime)
2701 s->id = 0;
2702 }
2703 }
2704 }
2705
2706 /*
2707 =================
2708 CL_AddTEnts
2709 =================
2710 */
CL_AddTEnts(void)2711 void CL_AddTEnts (void)
2712 {
2713 CL_AddBeams ();
2714 // PMM - draw plasma beams
2715 CL_AddPlayerBeams ();
2716 CL_AddExplosions ();
2717 CL_AddLasers ();
2718 // PMM - set up sustain
2719 CL_ProcessSustain();
2720 }
2721