File: client\cl_newfx.c
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // cl_newfx.c -- MORE entity effects parsing and management
21
22 #include "client.h"
23
24 extern cparticle_t *active_particles, *free_particles;
25 extern cparticle_t particles[MAX_PARTICLES];
26 extern int cl_numparticles;
27 extern cvar_t *vid_ref;
28
29 extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
30
31
32 /*
33 ======
34 vectoangles2 - this is duplicated in the game DLL, but I need it here.
35 ======
36 */
37 void vectoangles2 (vec3_t value1, vec3_t angles)
38 {
39 float forward;
40 float yaw, pitch;
41
42 if (value1[1] == 0 && value1[0] == 0)
43 {
44 yaw = 0;
45 if (value1[2] > 0)
46 pitch = 90;
47 else
48 pitch = 270;
49 }
50 else
51 {
52 // PMM - fixed to correct for pitch of 0
53 if (value1[0])
54 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
55 else if (value1[1] > 0)
56 yaw = 90;
57 else
58 yaw = 270;
59
60 if (yaw < 0)
61 yaw += 360;
62
63 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
64 pitch = (atan2(value1[2], forward) * 180 / M_PI);
65 if (pitch < 0)
66 pitch += 360;
67 }
68
69 angles[PITCH] = -pitch;
70 angles[YAW] = yaw;
71 angles[ROLL] = 0;
72 }
73
74 //=============
75 //=============
76 void CL_Flashlight (int ent, vec3_t pos)
77 {
78 cdlight_t *dl;
79
80 dl = CL_AllocDlight (ent);
81 VectorCopy (pos, dl->origin);
82 dl->radius = 400;
83 dl->minlight = 250;
84 dl->die = cl.time + 100;
85 dl->color[0] = 1;
86 dl->color[1] = 1;
87 dl->color[2] = 1;
88 }
89
90 /*
91 ======
92 CL_ColorFlash - flash of light
93 ======
94 */
95 void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
96 {
97 cdlight_t *dl;
98
99 if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
100 {
101 intensity = -intensity;
102 r = -r;
103 g = -g;
104 b = -b;
105 }
106
107 dl = CL_AllocDlight (ent);
108 VectorCopy (pos, dl->origin);
109 dl->radius = intensity;
110 dl->minlight = 250;
111 dl->die = cl.time + 100;
112 dl->color[0] = r;
113 dl->color[1] = g;
114 dl->color[2] = b;
115 }
116
117
118 /*
119 ======
120 CL_DebugTrail
121 ======
122 */
123 void CL_DebugTrail (vec3_t start, vec3_t end)
124 {
125 vec3_t move;
126 vec3_t vec;
127 float len;
128 // int j;
129 cparticle_t *p;
130 float dec;
131 vec3_t right, up;
132 // int i;
133 // float d, c, s;
134 // vec3_t dir;
135
136 VectorCopy (start, move);
137 VectorSubtract (end, start, vec);
138 len = VectorNormalize (vec);
139
140 MakeNormalVectors (vec, right, up);
141
142 // VectorScale(vec, RT2_SKIP, vec);
143
144 // dec = 1.0;
145 // dec = 0.75;
146 dec = 3;
147 VectorScale (vec, dec, vec);
148 VectorCopy (start, move);
149
150 while (len > 0)
151 {
152 len -= dec;
153
154 if (!free_particles)
155 return;
156 p = free_particles;
157 free_particles = p->next;
158 p->next = active_particles;
159 active_particles = p;
160
161 p->time = cl.time;
162 VectorClear (p->accel);
163 VectorClear (p->vel);
164 p->alpha = 1.0;
165 p->alphavel = -0.1;
166 // p->alphavel = 0;
167 p->color = 0x74 + (rand()&7);
168 VectorCopy (move, p->org);
169 /*
170 for (j=0 ; j<3 ; j++)
171 {
172 p->org[j] = move[j] + crand()*2;
173 p->vel[j] = crand()*3;
174 p->accel[j] = 0;
175 }
176 */
177 VectorAdd (move, vec, move);
178 }
179
180 }
181
182 /*
183 ===============
184 CL_SmokeTrail
185 ===============
186 */
187 void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
188 {
189 vec3_t move;
190 vec3_t vec;
191 float len;
192 int j;
193 cparticle_t *p;
194
195 VectorCopy (start, move);
196 VectorSubtract (end, start, vec);
197 len = VectorNormalize (vec);
198
199 VectorScale (vec, spacing, vec);
200
201 // FIXME: this is a really silly way to have a loop
202 while (len > 0)
203 {
204 len -= spacing;
205
206 if (!free_particles)
207 return;
208 p = free_particles;
209 free_particles = p->next;
210 p->next = active_particles;
211 active_particles = p;
212 VectorClear (p->accel);
213
214 p->time = cl.time;
215
216 p->alpha = 1.0;
217 p->alphavel = -1.0 / (1+frand()*0.5);
218 p->color = colorStart + (rand() % colorRun);
219 for (j=0 ; j<3 ; j++)
220 {
221 p->org[j] = move[j] + crand()*3;
222 p->accel[j] = 0;
223 }
224 p->vel[2] = 20 + crand()*5;
225
226 VectorAdd (move, vec, move);
227 }
228 }
229
230 void CL_ForceWall (vec3_t start, vec3_t end, int color)
231 {
232 vec3_t move;
233 vec3_t vec;
234 float len;
235 int j;
236 cparticle_t *p;
237
238 VectorCopy (start, move);
239 VectorSubtract (end, start, vec);
240 len = VectorNormalize (vec);
241
242 VectorScale (vec, 4, vec);
243
244 // FIXME: this is a really silly way to have a loop
245 while (len > 0)
246 {
247 len -= 4;
248
249 if (!free_particles)
250 return;
251
252 if (frand() > 0.3)
253 {
254 p = free_particles;
255 free_particles = p->next;
256 p->next = active_particles;
257 active_particles = p;
258 VectorClear (p->accel);
259
260 p->time = cl.time;
261
262 p->alpha = 1.0;
263 p->alphavel = -1.0 / (3.0+frand()*0.5);
264 p->color = color;
265 for (j=0 ; j<3 ; j++)
266 {
267 p->org[j] = move[j] + crand()*3;
268 p->accel[j] = 0;
269 }
270 p->vel[0] = 0;
271 p->vel[1] = 0;
272 p->vel[2] = -40 - (crand()*10);
273 }
274
275 VectorAdd (move, vec, move);
276 }
277 }
278
279 void CL_FlameEffects (centity_t *ent, vec3_t origin)
280 {
281 int n, count;
282 int j;
283 cparticle_t *p;
284
285 count = rand() & 0xF;
286
287 for(n=0;n<count;n++)
288 {
289 if (!free_particles)
290 return;
291
292 p = free_particles;
293 free_particles = p->next;
294 p->next = active_particles;
295 active_particles = p;
296
297 VectorClear (p->accel);
298 p->time = cl.time;
299
300 p->alpha = 1.0;
301 p->alphavel = -1.0 / (1+frand()*0.2);
302 p->color = 226 + (rand() % 4);
303 for (j=0 ; j<3 ; j++)
304 {
305 p->org[j] = origin[j] + crand()*5;
306 p->vel[j] = crand()*5;
307 }
308 p->vel[2] = crand() * -10;
309 p->accel[2] = -PARTICLE_GRAVITY;
310 }
311
312 count = rand() & 0x7;
313
314 for(n=0;n<count;n++)
315 {
316 if (!free_particles)
317 return;
318 p = free_particles;
319 free_particles = p->next;
320 p->next = active_particles;
321 active_particles = p;
322 VectorClear (p->accel);
323
324 p->time = cl.time;
325
326 p->alpha = 1.0;
327 p->alphavel = -1.0 / (1+frand()*0.5);
328 p->color = 0 + (rand() % 4);
329 for (j=0 ; j<3 ; j++)
330 {
331 p->org[j] = origin[j] + crand()*3;
332 }
333 p->vel[2] = 20 + crand()*5;
334 }
335
336 }
337
338
339 /*
340 ===============
341 CL_GenericParticleEffect
342 ===============
343 */
344 void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
345 {
346 int i, j;
347 cparticle_t *p;
348 float d;
349
350 for (i=0 ; i<count ; i++)
351 {
352 if (!free_particles)
353 return;
354 p = free_particles;
355 free_particles = p->next;
356 p->next = active_particles;
357 active_particles = p;
358
359 p->time = cl.time;
360 if (numcolors > 1)
361 p->color = color + (rand() & numcolors);
362 else
363 p->color = color;
364
365 d = rand() & dirspread;
366 for (j=0 ; j<3 ; j++)
367 {
368 p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
369 p->vel[j] = crand()*20;
370 }
371
372 p->accel[0] = p->accel[1] = 0;
373 p->accel[2] = -PARTICLE_GRAVITY;
374 // VectorCopy (accel, p->accel);
375 p->alpha = 1.0;
376
377 p->alphavel = -1.0 / (0.5 + frand()*alphavel);
378 // p->alphavel = alphavel;
379 }
380 }
381
382 /*
383 ===============
384 CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
385
386 ===============
387 */
388 void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
389 {
390 vec3_t move;
391 vec3_t vec;
392 float len;
393 int i, j;
394 cparticle_t *p;
395 float dec;
396
397 VectorCopy (start, move);
398 VectorSubtract (end, start, vec);
399 len = VectorNormalize (vec);
400
401 dec = dist;
402 VectorScale (vec, dec, vec);
403
404 for (i=0 ; i<len ; i+=dec)
405 {
406 if (!free_particles)
407 return;
408
409 p = free_particles;
410 free_particles = p->next;
411 p->next = active_particles;
412 active_particles = p;
413
414 VectorClear (p->accel);
415 p->time = cl.time;
416
417 p->alpha = 1.0;
418 p->alphavel = -1.0 / (1+frand()*0.1);
419 p->color = 4 + (rand()&7);
420 for (j=0 ; j<3 ; j++)
421 {
422 p->org[j] = move[j] + crand()*2;
423 p->vel[j] = crand()*10;
424 }
425 p->org[2] -= 4;
426 // p->vel[2] += 6;
427 p->vel[2] += 20;
428
429 VectorAdd (move, vec, move);
430 }
431 }
432
433 //#define CORKSCREW 1
434 //#define DOUBLE_SCREW 1
435 #define RINGS 1
436 //#define SPRAY 1
437
438 #ifdef CORKSCREW
439 void CL_Heatbeam (vec3_t start, vec3_t end)
440 {
441 vec3_t move;
442 vec3_t vec;
443 float len;
444 int j,k;
445 cparticle_t *p;
446 vec3_t right, up;
447 int i;
448 float d, c, s;
449 vec3_t dir;
450 float ltime;
451 float step = 5.0;
452
453 VectorCopy (start, move);
454 VectorSubtract (end, start, vec);
455 len = VectorNormalize (vec);
456
457 // MakeNormalVectors (vec, right, up);
458 VectorCopy (cl.v_right, right);
459 VectorCopy (cl.v_up, up);
460 VectorMA (move, -1, right, move);
461 VectorMA (move, -1, up, move);
462
463 VectorScale (vec, step, vec);
464 ltime = (float) cl.time/1000.0;
465
466 // for (i=0 ; i<len ; i++)
467 for (i=0 ; i<len ; i+=step)
468 {
469 d = i * 0.1 - fmod(ltime,16.0)*M_PI;
470 c = cos(d)/1.75;
471 s = sin(d)/1.75;
472 #ifdef DOUBLE_SCREW
473 for (k=-1; k<2; k+=2)
474 {
475 #else
476 k=1;
477 #endif
478 if (!free_particles)
479 return;
480
481 p = free_particles;
482 free_particles = p->next;
483 p->next = active_particles;
484 active_particles = p;
485
486 p->time = cl.time;
487 VectorClear (p->accel);
488
489 p->alpha = 0.5;
490 // p->alphavel = -1.0 / (1+frand()*0.2);
491 // only last one frame!
492 p->alphavel = INSTANT_PARTICLE;
493 // p->color = 0x74 + (rand()&7);
494 // p->color = 223 - (rand()&7);
495 p->color = 223;
496 // p->color = 240;
497
498 // trim it so it looks like it's starting at the origin
499 if (i < 10)
500 {
501 VectorScale (right, c*(i/10.0)*k, dir);
502 VectorMA (dir, s*(i/10.0)*k, up, dir);
503 }
504 else
505 {
506 VectorScale (right, c*k, dir);
507 VectorMA (dir, s*k, up, dir);
508 }
509
510 for (j=0 ; j<3 ; j++)
511 {
512 p->org[j] = move[j] + dir[j]*3;
513 // p->vel[j] = dir[j]*6;
514 p->vel[j] = 0;
515 }
516 #ifdef DOUBLE_SCREW
517 }
518 #endif
519 VectorAdd (move, vec, move);
520 }
521 } 522 #endif
523 #ifdef RINGS
524 //void CL_Heatbeam (vec3_t start, vec3_t end)
525 void CL_Heatbeam (vec3_t start, vec3_t forward)
526 {
527 vec3_t move;
528 vec3_t vec;
529 float len;
530 int j;
531 cparticle_t *p;
532 vec3_t right, up;
533 int i;
534 float c, s;
535 vec3_t dir;
536 float ltime;
537 float step = 32.0, rstep;
538 float start_pt;
539 float rot;
540 float variance;
541 vec3_t end;
542
543 VectorMA (start, 4096, forward, end);
544
545 VectorCopy (start, move);
546 VectorSubtract (end, start, vec);
547 len = VectorNormalize (vec);
548
549 // FIXME - pmm - these might end up using old values?
550 // MakeNormalVectors (vec, right, up);
551 VectorCopy (cl.v_right, right);
552 VectorCopy (cl.v_up, up);
553 if (vidref_val == VIDREF_GL)
554 { // GL mode
555 VectorMA (move, -0.5, right, move);
556 VectorMA (move, -0.5, up, move);
557 }
558 // otherwise assume SOFT
559
560 ltime = (float) cl.time/1000.0;
561 start_pt = fmod(ltime*96.0,step);
562 VectorMA (move, start_pt, vec, move);
563
564 VectorScale (vec, step, vec);
565
566 // Com_Printf ("%f\n", ltime);
567 rstep = M_PI/10.0;
568 for (i=start_pt ; i<len ; i+=step)
569 {
570 if (i>step*5) // don't bother after the 5th ring
571 break;
572
573 for (rot = 0; rot < M_PI*2; rot += rstep)
574 {
575
576 if (!free_particles)
577 return;
578
579 p = free_particles;
580 free_particles = p->next;
581 p->next = active_particles;
582 active_particles = p;
583
584 p->time = cl.time;
585 VectorClear (p->accel);
586 // rot+= fmod(ltime, 12.0)*M_PI;
587 // c = cos(rot)/2.0;
588 // s = sin(rot)/2.0;
589 // variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
590 variance = 0.5;
591 c = cos(rot)*variance;
592 s = sin(rot)*variance;
593
594 // trim it so it looks like it's starting at the origin
595 if (i < 10)
596 {
597 VectorScale (right, c*(i/10.0), dir);
598 VectorMA (dir, s*(i/10.0), up, dir);
599 }
600 else
601 {
602 VectorScale (right, c, dir);
603 VectorMA (dir, s, up, dir);
604 }
605
606 p->alpha = 0.5;
607 // p->alphavel = -1.0 / (1+frand()*0.2);
608 p->alphavel = -1000.0;
609 // p->color = 0x74 + (rand()&7);
610 p->color = 223 - (rand()&7);
611 for (j=0 ; j<3 ; j++)
612 {
613 p->org[j] = move[j] + dir[j]*3;
614 // p->vel[j] = dir[j]*6;
615 p->vel[j] = 0;
616 }
617 }
618 VectorAdd (move, vec, move);
619 }
620 }
621 #endif
622 #ifdef SPRAY
623 void CL_Heatbeam (vec3_t start, vec3_t end)
624 {
625 vec3_t move;
626 vec3_t vec;
627 float len;
628 int j;
629 cparticle_t *p;
630 vec3_t forward, right, up;
631 int i;
632 float d, c, s;
633 vec3_t dir;
634 float ltime;
635 float step = 32.0, rstep;
636 float start_pt;
637 float rot;
638
639 VectorCopy (start, move);
640 VectorSubtract (end, start, vec);
641 len = VectorNormalize (vec);
642
643 // MakeNormalVectors (vec, right, up);
644 VectorCopy (cl.v_forward, forward);
645 VectorCopy (cl.v_right, right);
646 VectorCopy (cl.v_up, up);
647 VectorMA (move, -0.5, right, move);
648 VectorMA (move, -0.5, up, move);
649
650 for (i=0; i<8; i++)
651 {
652 if (!free_particles)
653 return;
654
655 p = free_particles;
656 free_particles = p->next;
657 p->next = active_particles;
658 active_particles = p;
659
660 p->time = cl.time;
661 VectorClear (p->accel);
662
663 d = crand()*M_PI;
664 c = cos(d)*30;
665 s = sin(d)*30;
666
667 p->alpha = 1.0;
668 p->alphavel = -5.0 / (1+frand());
669 p->color = 223 - (rand()&7);
670
671 for (j=0 ; j<3 ; j++)
672 {
673 p->org[j] = move[j];
674 }
675 VectorScale (vec, 450, p->vel);
676 VectorMA (p->vel, c, right, p->vel);
677 VectorMA (p->vel, s, up, p->vel);
678 }
679 /*
680
681 ltime = (float) cl.time/1000.0;
682 start_pt = fmod(ltime*16.0,step);
683 VectorMA (move, start_pt, vec, move);
684
685 VectorScale (vec, step, vec);
686
687 // Com_Printf ("%f\n", ltime);
688 rstep = M_PI/12.0;
689 for (i=start_pt ; i<len ; i+=step)
690 {
691 if (i>step*5) // don't bother after the 5th ring
692 break;
693
694 for (rot = 0; rot < M_PI*2; rot += rstep)
695 {
696 if (!free_particles)
697 return;
698
699 p = free_particles;
700 free_particles = p->next;
701 p->next = active_particles;
702 active_particles = p;
703
704 p->time = cl.time;
705 VectorClear (p->accel);
706 // rot+= fmod(ltime, 12.0)*M_PI;
707 // c = cos(rot)/2.0;
708 // s = sin(rot)/2.0;
709 c = cos(rot)/1.5;
710 s = sin(rot)/1.5;
711
712 // trim it so it looks like it's starting at the origin
713 if (i < 10)
714 {
715 VectorScale (right, c*(i/10.0), dir);
716 VectorMA (dir, s*(i/10.0), up, dir);
717 }
718 else
719 {
720 VectorScale (right, c, dir);
721 VectorMA (dir, s, up, dir);
722 }
723
724 p->alpha = 0.5;
725 // p->alphavel = -1.0 / (1+frand()*0.2);
726 p->alphavel = -1000.0;
727 // p->color = 0x74 + (rand()&7);
728 p->color = 223 - (rand()&7);
729 for (j=0 ; j<3 ; j++)
730 {
731 p->org[j] = move[j] + dir[j]*3;
732 // p->vel[j] = dir[j]*6;
733 p->vel[j] = 0;
734 }
735 }
736 VectorAdd (move, vec, move);
737 }
738 */
739 } 740 #endif
741
742 /*
743 ===============
744 CL_ParticleSteamEffect
745
746 Puffs with velocity along direction, with some randomness thrown in
747 ===============
748 */
749 void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
750 {
751 int i, j;
752 cparticle_t *p;
753 float d;
754 vec3_t r, u;
755
756 // vectoangles2 (dir, angle_dir);
757 // AngleVectors (angle_dir, f, r, u);
758
759 MakeNormalVectors (dir, r, u);
760
761 for (i=0 ; i<count ; i++)
762 {
763 if (!free_particles)
764 return;
765 p = free_particles;
766 free_particles = p->next;
767 p->next = active_particles;
768 active_particles = p;
769
770 p->time = cl.time;
771 p->color = color + (rand()&7);
772
773 for (j=0 ; j<3 ; j++)
774 {
775 p->org[j] = org[j] + magnitude*0.1*crand();
776 // p->vel[j] = dir[j]*magnitude;
777 }
778 VectorScale (dir, magnitude, p->vel);
779 d = crand()*magnitude/3;
780 VectorMA (p->vel, d, r, p->vel);
781 d = crand()*magnitude/3;
782 VectorMA (p->vel, d, u, p->vel);
783
784 p->accel[0] = p->accel[1] = 0;
785 p->accel[2] = -PARTICLE_GRAVITY/2;
786 p->alpha = 1.0;
787
788 p->alphavel = -1.0 / (0.5 + frand()*0.3);
789 }
790 }
791
792 void CL_ParticleSteamEffect2 (cl_sustain_t *self)
793 //vec3_t org, vec3_t dir, int color, int count, int magnitude)
794 {
795 int i, j;
796 cparticle_t *p;
797 float d;
798 vec3_t r, u;
799 vec3_t dir;
800
801 // vectoangles2 (dir, angle_dir);
802 // AngleVectors (angle_dir, f, r, u);
803
804 VectorCopy (self->dir, dir);
805 MakeNormalVectors (dir, r, u);
806
807 for (i=0 ; i<self->count ; i++)
808 {
809 if (!free_particles)
810 return;
811 p = free_particles;
812 free_particles = p->next;
813 p->next = active_particles;
814 active_particles = p;
815
816 p->time = cl.time;
817 p->color = self->color + (rand()&7);
818
819 for (j=0 ; j<3 ; j++)
820 {
821 p->org[j] = self->org[j] + self->magnitude*0.1*crand();
822 // p->vel[j] = dir[j]*magnitude;
823 }
824 VectorScale (dir, self->magnitude, p->vel);
825 d = crand()*self->magnitude/3;
826 VectorMA (p->vel, d, r, p->vel);
827 d = crand()*self->magnitude/3;
828 VectorMA (p->vel, d, u, p->vel);
829
830 p->accel[0] = p->accel[1] = 0;
831 p->accel[2] = -PARTICLE_GRAVITY/2;
832 p->alpha = 1.0;
833
834 p->alphavel = -1.0 / (0.5 + frand()*0.3);
835 }
836 self->nextthink += self->thinkinterval;
837 }
838
839 /*
840 ===============
841 CL_TrackerTrail
842 ===============
843 */
844 void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
845 {
846 vec3_t move;
847 vec3_t vec;
848 vec3_t forward,right,up,angle_dir;
849 float len;
850 int j;
851 cparticle_t *p;
852 int dec;
853 float dist;
854
855 VectorCopy (start, move);
856 VectorSubtract (end, start, vec);
857 len = VectorNormalize (vec);
858
859 VectorCopy(vec, forward);
860 vectoangles2 (forward, angle_dir);
861 AngleVectors (angle_dir, forward, right, up);
862
863 dec = 3;
864 VectorScale (vec, 3, vec);
865
866 // FIXME: this is a really silly way to have a loop
867 while (len > 0)
868 {
869 len -= dec;
870
871 if (!free_particles)
872 return;
873 p = free_particles;
874 free_particles = p->next;
875 p->next = active_particles;
876 active_particles = p;
877 VectorClear (p->accel);
878
879 p->time = cl.time;
880
881 p->alpha = 1.0;
882 p->alphavel = -2.0;
883 p->color = particleColor;
884 dist = DotProduct(move, forward);
885 VectorMA(move, 8 * cos(dist), up, p->org);
886 for (j=0 ; j<3 ; j++)
887 {
888 // p->org[j] = move[j] + crand();
889 p->vel[j] = 0;
890 p->accel[j] = 0;
891 }
892 p->vel[2] = 5;
893
894 VectorAdd (move, vec, move);
895 }
896 }
897
898 void CL_Tracker_Shell(vec3_t origin)
899 {
900 vec3_t dir;
901 int i;
902 cparticle_t *p;
903
904 for(i=0;i<300;i++)
905 {
906 if (!free_particles)
907 return;
908 p = free_particles;
909 free_particles = p->next;
910 p->next = active_particles;
911 active_particles = p;
912 VectorClear (p->accel);
913
914 p->time = cl.time;
915
916 p->alpha = 1.0;
917 p->alphavel = INSTANT_PARTICLE;
918 p->color = 0;
919
920 dir[0] = crand();
921 dir[1] = crand();
922 dir[2] = crand();
923 VectorNormalize(dir);
924
925 VectorMA(origin, 40, dir, p->org);
926 }
927 }
928
929 void CL_MonsterPlasma_Shell(vec3_t origin)
930 {
931 vec3_t dir;
932 int i;
933 cparticle_t *p;
934
935 for(i=0;i<40;i++)
936 {
937 if (!free_particles)
938 return;
939 p = free_particles;
940 free_particles = p->next;
941 p->next = active_particles;
942 active_particles = p;
943 VectorClear (p->accel);
944
945 p->time = cl.time;
946
947 p->alpha = 1.0;
948 p->alphavel = INSTANT_PARTICLE;
949 p->color = 0xe0;
950
951 dir[0] = crand();
952 dir[1] = crand();
953 dir[2] = crand();
954 VectorNormalize(dir);
955
956 VectorMA(origin, 10, dir, p->org);
957 // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
958 }
959 }
960
961 void CL_Widowbeamout (cl_sustain_t *self)
962 {
963 vec3_t dir;
964 int i;
965 cparticle_t *p;
966 static int colortable[4] = {2*8,13*8,21*8,18*8};
967 float ratio;
968
969 ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
970
971 for(i=0;i<300;i++)
972 {
973 if (!free_particles)
974 return;
975 p = free_particles;
976 free_particles = p->next;
977 p->next = active_particles;
978 active_particles = p;
979 VectorClear (p->accel);
980
981 p->time = cl.time;
982
983 p->alpha = 1.0;
984 p->alphavel = INSTANT_PARTICLE;
985 p->color = colortable[rand()&3];
986
987 dir[0] = crand();
988 dir[1] = crand();
989 dir[2] = crand();
990 VectorNormalize(dir);
991
992 VectorMA(self->org, (45.0 * ratio), dir, p->org);
993 // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
994 }
995 }
996
997 void CL_Nukeblast (cl_sustain_t *self)
998 {
999 vec3_t dir;
1000 int i;
1001 cparticle_t *p;
1002 static int colortable[4] = {110, 112, 114, 116};
1003 float ratio;
1004
1005 ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
1006
1007 for(i=0;i<700;i++)
1008 {
1009 if (!free_particles)
1010 return;
1011 p = free_particles;
1012 free_particles = p->next;
1013 p->next = active_particles;
1014 active_particles = p;
1015 VectorClear (p->accel);
1016
1017 p->time = cl.time;
1018
1019 p->alpha = 1.0;
1020 p->alphavel = INSTANT_PARTICLE;
1021 p->color = colortable[rand()&3];
1022
1023 dir[0] = crand();
1024 dir[1] = crand();
1025 dir[2] = crand();
1026 VectorNormalize(dir);
1027
1028 VectorMA(self->org, (200.0 * ratio), dir, p->org);
1029 // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
1030 }
1031 }
1032
1033 void CL_WidowSplash (vec3_t org)
1034 {
1035 static int colortable[4] = {2*8,13*8,21*8,18*8};
1036 int i;
1037 cparticle_t *p;
1038 vec3_t dir;
1039
1040 for (i=0 ; i<256 ; i++)
1041 {
1042 if (!free_particles)
1043 return;
1044 p = free_particles;
1045 free_particles = p->next;
1046 p->next = active_particles;
1047 active_particles = p;
1048
1049 p->time = cl.time;
1050 p->color = colortable[rand()&3];
1051
1052 dir[0] = crand();
1053 dir[1] = crand();
1054 dir[2] = crand();
1055 VectorNormalize(dir);
1056 VectorMA(org, 45.0, dir, p->org);
1057 VectorMA(vec3_origin, 40.0, dir, p->vel);
1058
1059 p->accel[0] = p->accel[1] = 0;
1060 p->alpha = 1.0;
1061
1062 p->alphavel = -0.8 / (0.5 + frand()*0.3);
1063 }
1064
1065 }
1066
1067 void CL_Tracker_Explode(vec3_t origin)
1068 {
1069 vec3_t dir, backdir;
1070 int i;
1071 cparticle_t *p;
1072
1073 for(i=0;i<300;i++)
1074 {
1075 if (!free_particles)
1076 return;
1077 p = free_particles;
1078 free_particles = p->next;
1079 p->next = active_particles;
1080 active_particles = p;
1081 VectorClear (p->accel);
1082
1083 p->time = cl.time;
1084
1085 p->alpha = 1.0;
1086 p->alphavel = -1.0;
1087 p->color = 0;
1088
1089 dir[0] = crand();
1090 dir[1] = crand();
1091 dir[2] = crand();
1092 VectorNormalize(dir);
1093 VectorScale(dir, -1, backdir);
1094
1095 VectorMA(origin, 64, dir, p->org);
1096 VectorScale(backdir, 64, p->vel);
1097 }
1098
1099 }
1100
1101 /*
1102 ===============
1103 CL_TagTrail
1104
1105 ===============
1106 */
1107 void CL_TagTrail (vec3_t start, vec3_t end, float color)
1108 {
1109 vec3_t move;
1110 vec3_t vec;
1111 float len;
1112 int j;
1113 cparticle_t *p;
1114 int dec;
1115
1116 VectorCopy (start, move);
1117 VectorSubtract (end, start, vec);
1118 len = VectorNormalize (vec);
1119
1120 dec = 5;
1121 VectorScale (vec, 5, vec);
1122
1123 while (len >= 0)
1124 {
1125 len -= dec;
1126
1127 if (!free_particles)
1128 return;
1129 p = free_particles;
1130 free_particles = p->next;
1131 p->next = active_particles;
1132 active_particles = p;
1133 VectorClear (p->accel);
1134
1135 p->time = cl.time;
1136
1137 p->alpha = 1.0;
1138 p->alphavel = -1.0 / (0.8+frand()*0.2);
1139 p->color = color;
1140 for (j=0 ; j<3 ; j++)
1141 {
1142 p->org[j] = move[j] + crand()*16;
1143 p->vel[j] = crand()*5;
1144 p->accel[j] = 0;
1145 }
1146
1147 VectorAdd (move, vec, move);
1148 }
1149 }
1150
1151 /*
1152 ===============
1153 CL_ColorExplosionParticles
1154 ===============
1155 */
1156 void CL_ColorExplosionParticles (vec3_t org, int color, int run)
1157 {
1158 int i, j;
1159 cparticle_t *p;
1160
1161 for (i=0 ; i<128 ; i++)
1162 {
1163 if (!free_particles)
1164 return;
1165 p = free_particles;
1166 free_particles = p->next;
1167 p->next = active_particles;
1168 active_particles = p;
1169
1170 p->time = cl.time;
1171 p->color = color + (rand() % run);
1172
1173 for (j=0 ; j<3 ; j++)
1174 {
1175 p->org[j] = org[j] + ((rand()%32)-16);
1176 p->vel[j] = (rand()%256)-128;
1177 }
1178
1179 p->accel[0] = p->accel[1] = 0;
1180 p->accel[2] = -PARTICLE_GRAVITY;
1181 p->alpha = 1.0;
1182
1183 p->alphavel = -0.4 / (0.6 + frand()*0.2);
1184 }
1185 }
1186
1187 /*
1188 ===============
1189 CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
1190 ===============
1191 */
1192 void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
1193 {
1194 int i, j;
1195 cparticle_t *p;
1196 float d;
1197 vec3_t r, u;
1198
1199 MakeNormalVectors (dir, r, u);
1200
1201 for (i=0 ; i<count ; i++)
1202 {
1203 if (!free_particles)
1204 return;
1205 p = free_particles;
1206 free_particles = p->next;
1207 p->next = active_particles;
1208 active_particles = p;
1209
1210 p->time = cl.time;
1211 p->color = color + (rand()&7);
1212
1213 for (j=0 ; j<3 ; j++)
1214 {
1215 p->org[j] = org[j] + magnitude*0.1*crand();
1216 // p->vel[j] = dir[j]*magnitude;
1217 }
1218 VectorScale (dir, magnitude, p->vel);
1219 d = crand()*magnitude/3;
1220 VectorMA (p->vel, d, r, p->vel);
1221 d = crand()*magnitude/3;
1222 VectorMA (p->vel, d, u, p->vel);
1223
1224 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1225 p->alpha = 1.0;
1226
1227 p->alphavel = -1.0 / (0.5 + frand()*0.3);
1228 }
1229 }
1230
1231 /*
1232 ===============
1233 CL_BlasterParticles2
1234
1235 Wall impact puffs (Green)
1236 ===============
1237 */
1238 void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
1239 {
1240 int i, j;
1241 cparticle_t *p;
1242 float d;
1243 int count;
1244
1245 count = 40;
1246 for (i=0 ; i<count ; i++)
1247 {
1248 if (!free_particles)
1249 return;
1250 p = free_particles;
1251 free_particles = p->next;
1252 p->next = active_particles;
1253 active_particles = p;
1254
1255 p->time = cl.time;
1256 p->color = color + (rand()&7);
1257
1258 d = rand()&15;
1259 for (j=0 ; j<3 ; j++)
1260 {
1261 p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
1262 p->vel[j] = dir[j] * 30 + crand()*40;
1263 }
1264
1265 p->accel[0] = p->accel[1] = 0;
1266 p->accel[2] = -PARTICLE_GRAVITY;
1267 p->alpha = 1.0;
1268
1269 p->alphavel = -1.0 / (0.5 + frand()*0.3);
1270 }
1271 }
1272
1273 /*
1274 ===============
1275 CL_BlasterTrail2
1276
1277 Green!
1278 ===============
1279 */
1280 void CL_BlasterTrail2 (vec3_t start, vec3_t end)
1281 {
1282 vec3_t move;
1283 vec3_t vec;
1284 float len;
1285 int j;
1286 cparticle_t *p;
1287 int dec;
1288
1289 VectorCopy (start, move);
1290 VectorSubtract (end, start, vec);
1291 len = VectorNormalize (vec);
1292
1293 dec = 5;
1294 VectorScale (vec, 5, vec);
1295
1296 // FIXME: this is a really silly way to have a loop
1297 while (len > 0)
1298 {
1299 len -= dec;
1300
1301 if (!free_particles)
1302 return;
1303 p = free_particles;
1304 free_particles = p->next;
1305 p->next = active_particles;
1306 active_particles = p;
1307 VectorClear (p->accel);
1308
1309 p->time = cl.time;
1310
1311 p->alpha = 1.0;
1312 p->alphavel = -1.0 / (0.3+frand()*0.2);
1313 p->color = 0xd0;
1314 for (j=0 ; j<3 ; j++)
1315 {
1316 p->org[j] = move[j] + crand();
1317 p->vel[j] = crand()*5;
1318 p->accel[j] = 0;
1319 }
1320
1321 VectorAdd (move, vec, move);
1322 }
1323 }
1324