misc. cleanup, bubble trails fixed, improved lightmap compatibility.
[xonotic/darkplaces.git] / cl_tent.c
1 /*
2 Copyright (C) 1996-1997 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 "quakedef.h"
23
24 int                     num_temp_entities;
25 entity_t        cl_temp_entities[MAX_TEMP_ENTITIES];
26 beam_t          cl_beams[MAX_BEAMS];
27
28 sfx_t                   *cl_sfx_wizhit;
29 sfx_t                   *cl_sfx_knighthit;
30 sfx_t                   *cl_sfx_tink1;
31 sfx_t                   *cl_sfx_ric1;
32 sfx_t                   *cl_sfx_ric2;
33 sfx_t                   *cl_sfx_ric3;
34 sfx_t                   *cl_sfx_r_exp3;
35
36 /*
37 =================
38 CL_ParseTEnt
39 =================
40 */
41 void CL_InitTEnts (void)
42 {
43         cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
44         cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
45         cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
46         cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
47         cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
48         cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
49         cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
50 }
51
52 /*
53 =================
54 CL_ParseBeam
55 =================
56 */
57 void CL_ParseBeam (model_t *m)
58 {
59         int             ent;
60         vec3_t  start, end;
61         beam_t  *b;
62         int             i;
63         
64         ent = MSG_ReadShort ();
65         
66         start[0] = MSG_ReadCoord ();
67         start[1] = MSG_ReadCoord ();
68         start[2] = MSG_ReadCoord ();
69         
70         end[0] = MSG_ReadCoord ();
71         end[1] = MSG_ReadCoord ();
72         end[2] = MSG_ReadCoord ();
73
74 // override any beam with the same entity
75         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
76                 if (b->entity == ent)
77                 {
78                         b->entity = ent;
79                         b->model = m;
80                         b->endtime = cl.time + 0.2;
81                         VectorCopy (start, b->start);
82                         VectorCopy (end, b->end);
83                         return;
84                 }
85
86 // find a free beam
87         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
88         {
89                 if (!b->model || b->endtime < cl.time)
90                 {
91                         b->entity = ent;
92                         b->model = m;
93                         b->endtime = cl.time + 0.2;
94                         VectorCopy (start, b->start);
95                         VectorCopy (end, b->end);
96                         return;
97                 }
98         }
99         Con_Printf ("beam list overflow!\n");   
100 }
101
102 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
103 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
104 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
105
106 /*
107 =================
108 CL_ParseTEnt
109 =================
110 */
111 void CL_ParseTEnt (void)
112 {
113         int             type;
114         vec3_t  pos;
115         vec3_t  dir;
116         vec3_t  pos2;
117         dlight_t        *dl;
118         int             rnd;
119         int             colorStart, colorLength, count;
120         float   velspeed;
121         byte *tempcolor;
122
123         type = MSG_ReadByte ();
124         switch (type)
125         {
126         case TE_WIZSPIKE:                       // spike hitting wall
127                 pos[0] = MSG_ReadCoord ();
128                 pos[1] = MSG_ReadCoord ();
129                 pos[2] = MSG_ReadCoord ();
130                 R_RunParticleEffect (pos, vec3_origin, 20, 30);
131                 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
132                 break;
133                 
134         case TE_KNIGHTSPIKE:                    // spike hitting wall
135                 pos[0] = MSG_ReadCoord ();
136                 pos[1] = MSG_ReadCoord ();
137                 pos[2] = MSG_ReadCoord ();
138                 R_RunParticleEffect (pos, vec3_origin, 226, 20);
139                 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
140                 break;
141                 
142         case TE_SPIKE:                  // spike hitting wall
143                 pos[0] = MSG_ReadCoord ();
144                 pos[1] = MSG_ReadCoord ();
145                 pos[2] = MSG_ReadCoord ();
146                 // LordHavoc: changed to spark shower
147                 R_SparkShower(pos, vec3_origin, 15, 0);
148                 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
149                 if ( rand() % 5 )
150                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
151                 else
152                 {
153                         rnd = rand() & 3;
154                         if (rnd == 1)
155                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
156                         else if (rnd == 2)
157                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
158                         else
159                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
160                 }
161                 break;
162         case TE_SPIKEQUAD:                      // quad spike hitting wall
163                 pos[0] = MSG_ReadCoord ();
164                 pos[1] = MSG_ReadCoord ();
165                 pos[2] = MSG_ReadCoord ();
166                 // LordHavoc: changed to spark shower
167                 R_SparkShower(pos, vec3_origin, 15, 0);
168                 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
169                 dl = CL_AllocDlight (0);
170                 VectorCopy (pos, dl->origin);
171                 dl->radius = 200;
172                 dl->die = cl.time + 0.2;
173                 dl->decay = 1000;
174                 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
175                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
176                 if ( rand() % 5 )
177                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
178                 else
179                 {
180                         rnd = rand() & 3;
181                         if (rnd == 1)
182                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
183                         else if (rnd == 2)
184                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
185                         else
186                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
187                 }
188                 break;
189         case TE_SUPERSPIKE:                     // super spike hitting wall
190                 pos[0] = MSG_ReadCoord ();
191                 pos[1] = MSG_ReadCoord ();
192                 pos[2] = MSG_ReadCoord ();
193                 // LordHavoc: changed to dust shower
194                 R_SparkShower(pos, vec3_origin, 30, 0);
195                 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
196                 if ( rand() % 5 )
197                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
198                 else
199                 {
200                         rnd = rand() & 3;
201                         if (rnd == 1)
202                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
203                         else if (rnd == 2)
204                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
205                         else
206                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
207                 }
208                 break;
209         case TE_SUPERSPIKEQUAD:                 // quad super spike hitting wall
210                 pos[0] = MSG_ReadCoord ();
211                 pos[1] = MSG_ReadCoord ();
212                 pos[2] = MSG_ReadCoord ();
213                 // LordHavoc: changed to dust shower
214                 R_SparkShower(pos, vec3_origin, 30, 0);
215                 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
216                 dl = CL_AllocDlight (0);
217                 VectorCopy (pos, dl->origin);
218                 dl->radius = 200;
219                 dl->die = cl.time + 0.2;
220                 dl->decay = 1000;
221                 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
222                 if ( rand() % 5 )
223                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
224                 else
225                 {
226                         rnd = rand() & 3;
227                         if (rnd == 1)
228                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
229                         else if (rnd == 2)
230                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
231                         else
232                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
233                 }
234                 break;
235                 // LordHavoc: added for improved blood splatters
236         case TE_BLOOD:  // blood puff
237                 pos[0] = MSG_ReadCoord ();
238                 pos[1] = MSG_ReadCoord ();
239                 pos[2] = MSG_ReadCoord ();
240                 dir[0] = MSG_ReadChar ();
241                 dir[1] = MSG_ReadChar ();
242                 dir[2] = MSG_ReadChar ();
243                 count = MSG_ReadByte (); // amount of particles
244                 R_SparkShower(pos, dir, count, 1);
245                 break;
246         case TE_SPARK:  // spark shower
247                 pos[0] = MSG_ReadCoord ();
248                 pos[1] = MSG_ReadCoord ();
249                 pos[2] = MSG_ReadCoord ();
250                 dir[0] = MSG_ReadChar ();
251                 dir[1] = MSG_ReadChar ();
252                 dir[2] = MSG_ReadChar ();
253                 count = MSG_ReadByte (); // amount of particles
254                 R_SparkShower(pos, dir, count, 0);
255                 break;
256                 // LordHavoc: added for improved gore
257         case TE_BLOODSHOWER:    // vaporized body
258                 pos[0] = MSG_ReadCoord (); // mins
259                 pos[1] = MSG_ReadCoord ();
260                 pos[2] = MSG_ReadCoord ();
261                 dir[0] = MSG_ReadCoord (); // maxs
262                 dir[1] = MSG_ReadCoord ();
263                 dir[2] = MSG_ReadCoord ();
264                 velspeed = MSG_ReadCoord (); // speed
265                 count = MSG_ReadShort (); // number of particles
266                 R_BloodShower(pos, dir, velspeed, count);
267                 break;
268         case TE_PARTICLECUBE:   // general purpose particle effect
269                 pos[0] = MSG_ReadCoord (); // mins
270                 pos[1] = MSG_ReadCoord ();
271                 pos[2] = MSG_ReadCoord ();
272                 pos2[0] = MSG_ReadCoord (); // maxs
273                 pos2[1] = MSG_ReadCoord ();
274                 pos2[2] = MSG_ReadCoord ();
275                 dir[0] = MSG_ReadCoord (); // dir
276                 dir[1] = MSG_ReadCoord ();
277                 dir[2] = MSG_ReadCoord ();
278                 count = MSG_ReadShort (); // number of particles
279                 colorStart = MSG_ReadByte (); // color
280                 colorLength = MSG_ReadByte (); // gravity (1 or 0)
281                 velspeed = MSG_ReadCoord (); // randomvel
282                 R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
283                 break;
284
285         case TE_PARTICLERAIN:   // general purpose particle effect
286                 pos[0] = MSG_ReadCoord (); // mins
287                 pos[1] = MSG_ReadCoord ();
288                 pos[2] = MSG_ReadCoord ();
289                 pos2[0] = MSG_ReadCoord (); // maxs
290                 pos2[1] = MSG_ReadCoord ();
291                 pos2[2] = MSG_ReadCoord ();
292                 dir[0] = MSG_ReadCoord (); // dir
293                 dir[1] = MSG_ReadCoord ();
294                 dir[2] = MSG_ReadCoord ();
295                 count = MSG_ReadShort (); // number of particles
296                 colorStart = MSG_ReadByte (); // color
297                 R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
298                 break;
299
300         case TE_PARTICLESNOW:   // general purpose particle effect
301                 pos[0] = MSG_ReadCoord (); // mins
302                 pos[1] = MSG_ReadCoord ();
303                 pos[2] = MSG_ReadCoord ();
304                 pos2[0] = MSG_ReadCoord (); // maxs
305                 pos2[1] = MSG_ReadCoord ();
306                 pos2[2] = MSG_ReadCoord ();
307                 dir[0] = MSG_ReadCoord (); // dir
308                 dir[1] = MSG_ReadCoord ();
309                 dir[2] = MSG_ReadCoord ();
310                 count = MSG_ReadShort (); // number of particles
311                 colorStart = MSG_ReadByte (); // color
312                 R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
313                 break;
314
315         case TE_GUNSHOT:                        // bullet hitting wall
316                 pos[0] = MSG_ReadCoord ();
317                 pos[1] = MSG_ReadCoord ();
318                 pos[2] = MSG_ReadCoord ();
319                 // LordHavoc: changed to dust shower
320                 R_SparkShower(pos, vec3_origin, 15, 0);
321                 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
322                 break;
323
324         case TE_GUNSHOTQUAD:                    // quad bullet hitting wall
325                 pos[0] = MSG_ReadCoord ();
326                 pos[1] = MSG_ReadCoord ();
327                 pos[2] = MSG_ReadCoord ();
328                 R_SparkShower(pos, vec3_origin, 15, 0);
329                 dl = CL_AllocDlight (0);
330                 VectorCopy (pos, dl->origin);
331                 dl->radius = 200;
332                 dl->die = cl.time + 0.2;
333                 dl->decay = 1000;
334                 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
335                 break;
336
337         case TE_EXPLOSION:                      // rocket explosion
338                 pos[0] = MSG_ReadCoord ();
339                 pos[1] = MSG_ReadCoord ();
340                 pos[2] = MSG_ReadCoord ();
341                 R_ParticleExplosion (pos, false);
342                 dl = CL_AllocDlight (0);
343                 VectorCopy (pos, dl->origin);
344                 dl->radius = 350;
345                 dl->die = cl.time + 0.5;
346                 dl->decay = 700;
347                 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
348                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
349                 break;
350
351         case TE_EXPLOSIONQUAD:                  // quad rocket explosion
352                 pos[0] = MSG_ReadCoord ();
353                 pos[1] = MSG_ReadCoord ();
354                 pos[2] = MSG_ReadCoord ();
355                 R_ParticleExplosion (pos, false);
356                 dl = CL_AllocDlight (0);
357                 VectorCopy (pos, dl->origin);
358                 dl->radius = 600;
359                 dl->die = cl.time + 0.5;
360                 dl->decay = 1200;
361                 dl->color[0] = 0.5;dl->color[1] = 0.4;dl->color[2] = 1.0;
362                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
363                 break;
364
365                 /*
366         case TE_SMOKEEXPLOSION:                 // rocket explosion with a cloud of smoke
367                 pos[0] = MSG_ReadCoord ();
368                 pos[1] = MSG_ReadCoord ();
369                 pos[2] = MSG_ReadCoord ();
370                 R_ParticleExplosion (pos, true);
371                 dl = CL_AllocDlight (0);
372                 VectorCopy (pos, dl->origin);
373                 dl->radius = 350;
374                 dl->die = cl.time + 0.5;
375                 dl->decay = 300;
376                 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
377                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
378                 break;
379                 */
380
381         case TE_EXPLOSION3:                             // Nehahra movie colored lighting explosion
382                 pos[0] = MSG_ReadCoord ();
383                 pos[1] = MSG_ReadCoord ();
384                 pos[2] = MSG_ReadCoord ();
385                 R_ParticleExplosion (pos, false);
386                 dl = CL_AllocDlight (0);
387                 VectorCopy (pos, dl->origin);
388                 dl->radius = 350;
389                 dl->die = cl.time + 0.5;
390                 dl->decay = 700;
391                 dl->color[0] = MSG_ReadCoord();dl->color[1] = MSG_ReadCoord();dl->color[2] = MSG_ReadCoord();
392                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
393                 break;
394
395         case TE_EXPLOSIONRGB:                   // colored lighting explosion
396                 pos[0] = MSG_ReadCoord ();
397                 pos[1] = MSG_ReadCoord ();
398                 pos[2] = MSG_ReadCoord ();
399                 R_ParticleExplosion (pos, false);
400                 dl = CL_AllocDlight (0);
401                 VectorCopy (pos, dl->origin);
402                 dl->radius = 350;
403                 dl->die = cl.time + 0.5;
404                 dl->decay = 700;
405                 dl->color[0] = MSG_ReadByte() * (1.0 / 255.0);dl->color[1] = MSG_ReadByte() * (1.0 / 255.0);dl->color[2] = MSG_ReadByte() * (1.0 / 255.0);
406                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
407                 break;
408
409         case TE_TAREXPLOSION:                   // tarbaby explosion
410                 pos[0] = MSG_ReadCoord ();
411                 pos[1] = MSG_ReadCoord ();
412                 pos[2] = MSG_ReadCoord ();
413                 R_BlobExplosion (pos);
414
415                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
416                 break;
417
418         case TE_LIGHTNING1:                             // lightning bolts
419                 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
420                 break;
421         
422         case TE_LIGHTNING2:                             // lightning bolts
423                 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
424                 break;
425         
426         case TE_LIGHTNING3:                             // lightning bolts
427                 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
428                 break;
429
430 // PGM 01/21/97 
431         case TE_BEAM:                           // grappling hook beam
432                 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
433                 break;
434 // PGM 01/21/97
435
436 // LordHavoc: ONLY for compatibility with the Nehahra movie... hack hack hack
437         case TE_LIGHTNING4NEH:
438                 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
439                 break;
440
441         case TE_LAVASPLASH:     
442                 pos[0] = MSG_ReadCoord ();
443                 pos[1] = MSG_ReadCoord ();
444                 pos[2] = MSG_ReadCoord ();
445                 R_LavaSplash (pos);
446                 break;
447         
448         case TE_TELEPORT:
449                 pos[0] = MSG_ReadCoord ();
450                 pos[1] = MSG_ReadCoord ();
451                 pos[2] = MSG_ReadCoord ();
452                 R_TeleportSplash (pos);
453                 break;
454                 
455         case TE_EXPLOSION2:                             // color mapped explosion
456                 pos[0] = MSG_ReadCoord ();
457                 pos[1] = MSG_ReadCoord ();
458                 pos[2] = MSG_ReadCoord ();
459                 colorStart = MSG_ReadByte ();
460                 colorLength = MSG_ReadByte ();
461                 R_ParticleExplosion2 (pos, colorStart, colorLength);
462                 dl = CL_AllocDlight (0);
463                 VectorCopy (pos, dl->origin);
464                 dl->radius = 350;
465                 dl->die = cl.time + 0.5;
466                 dl->decay = 700;
467                 tempcolor = (byte *)&d_8to24table[colorStart+(colorLength >> 1)];
468                 dl->color[0] = tempcolor[0];dl->color[1] = tempcolor[1];dl->color[2] = tempcolor[2];
469                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
470                 break;
471                 
472         default:
473                 Host_Error ("CL_ParseTEnt: bad type %d", type);
474         }
475 }
476
477
478 /*
479 =================
480 CL_NewTempEntity
481 =================
482 */
483 entity_t *CL_NewTempEntity (void)
484 {
485         entity_t        *ent;
486
487         if (cl_numvisedicts == MAX_VISEDICTS)
488                 return NULL;
489         if (num_temp_entities == MAX_TEMP_ENTITIES)
490                 return NULL;
491         ent = &cl_temp_entities[num_temp_entities];
492         memset (ent, 0, sizeof(*ent));
493         num_temp_entities++;
494         cl_visedicts[cl_numvisedicts] = ent;
495         cl_numvisedicts++;
496
497         ent->colormap = vid.colormap;
498         ent->scale = 1;
499         ent->alpha = 1;
500         ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
501         return ent;
502 }
503
504
505 /*
506 =================
507 CL_UpdateTEnts
508 =================
509 */
510 void CL_UpdateTEnts (void)
511 {
512         int                     i;
513         beam_t          *b;
514         vec3_t          dist, org;
515         float           d;
516         entity_t        *ent;
517         float           yaw, pitch;
518         float           forward;
519         dlight_t        *dl;
520
521         num_temp_entities = 0;
522
523 // update lightning
524         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
525         {
526                 if (!b->model || b->endtime < cl.time)
527                         continue;
528
529         // if coming from the player, update the start position
530                 if (b->entity == cl.viewentity)
531                 {
532                         VectorCopy (cl_entities[cl.viewentity].origin, b->start);
533                 }
534
535         // calculate pitch and yaw
536                 VectorSubtract (b->end, b->start, dist);
537
538                 if (dist[1] == 0 && dist[0] == 0)
539                 {
540                         yaw = 0;
541                         if (dist[2] > 0)
542                                 pitch = 90;
543                         else
544                                 pitch = 270;
545                 }
546                 else
547                 {
548                         yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
549                         if (yaw < 0)
550                                 yaw += 360;
551         
552                         forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
553                         pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
554                         if (pitch < 0)
555                                 pitch += 360;
556                 }
557
558         // add new entities for the lightning
559                 VectorCopy (b->start, org);
560                 d = VectorNormalizeLength(dist);
561                 while (d > 0)
562                 {
563                         ent = CL_NewTempEntity ();
564                         if (!ent)
565                                 return;
566                         VectorCopy (org, ent->origin);
567                         ent->model = b->model;
568                         ent->effects = EF_FULLBRIGHT;
569                         ent->angles[0] = pitch;
570                         ent->angles[1] = yaw;
571                         ent->angles[2] = rand()%360;
572
573                         dl = CL_AllocDlight (0);
574                         VectorCopy (ent->origin,  dl->origin);
575                         dl->radius = 100 + (rand()&31);
576                         dl->die = cl.time + 0.001;
577                         dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 1;
578
579                         VectorMA(org, 30, dist, org);
580                         d -= 30;
581                 }
582         }
583         
584 }
585
586