]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_tent.c
bc9f87d7d81d38cacf197181f9897e188203bfd5
[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                 dl = CL_AllocDlight (0);
417                 VectorCopy (pos, dl->origin);
418                 dl->radius = 600;
419                 dl->die = cl.time + 0.5;
420                 dl->decay = 1200;
421                 dl->color[0] = 0.8;dl->color[1] = 0.4;dl->color[2] = 1.0;
422                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
423                 break;
424
425         case TE_LIGHTNING1:                             // lightning bolts
426                 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
427                 break;
428         
429         case TE_LIGHTNING2:                             // lightning bolts
430                 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
431                 break;
432         
433         case TE_LIGHTNING3:                             // lightning bolts
434                 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
435                 break;
436
437 // PGM 01/21/97 
438         case TE_BEAM:                           // grappling hook beam
439                 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
440                 break;
441 // PGM 01/21/97
442
443 // LordHavoc: ONLY for compatibility with the Nehahra movie... hack hack hack
444         case TE_LIGHTNING4NEH:
445                 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
446                 break;
447
448         case TE_LAVASPLASH:     
449                 pos[0] = MSG_ReadCoord ();
450                 pos[1] = MSG_ReadCoord ();
451                 pos[2] = MSG_ReadCoord ();
452                 R_LavaSplash (pos);
453                 break;
454         
455         case TE_TELEPORT:
456                 pos[0] = MSG_ReadCoord ();
457                 pos[1] = MSG_ReadCoord ();
458                 pos[2] = MSG_ReadCoord ();
459                 R_TeleportSplash (pos);
460                 break;
461                 
462         case TE_EXPLOSION2:                             // color mapped explosion
463                 pos[0] = MSG_ReadCoord ();
464                 pos[1] = MSG_ReadCoord ();
465                 pos[2] = MSG_ReadCoord ();
466                 colorStart = MSG_ReadByte ();
467                 colorLength = MSG_ReadByte ();
468 //              R_ParticleExplosion2 (pos, colorStart, colorLength);
469                 dl = CL_AllocDlight (0);
470                 VectorCopy (pos, dl->origin);
471                 dl->radius = 350;
472                 dl->die = cl.time + 0.5;
473                 dl->decay = 700;
474                 tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
475                 dl->color[0] = tempcolor[0];dl->color[1] = tempcolor[1];dl->color[2] = tempcolor[2];
476                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
477                 break;
478                 
479         default:
480                 Host_Error ("CL_ParseTEnt: bad type %d", type);
481         }
482 }
483
484
485 /*
486 =================
487 CL_NewTempEntity
488 =================
489 */
490 entity_t *CL_NewTempEntity (void)
491 {
492         entity_t        *ent;
493
494         if (cl_numvisedicts == MAX_VISEDICTS)
495                 return NULL;
496         if (num_temp_entities == MAX_TEMP_ENTITIES)
497                 return NULL;
498         ent = &cl_temp_entities[num_temp_entities];
499         memset (ent, 0, sizeof(*ent));
500         num_temp_entities++;
501         cl_visedicts[cl_numvisedicts] = ent;
502         cl_numvisedicts++;
503
504         ent->colormap = vid.colormap;
505         ent->scale = 1;
506         ent->alpha = 1;
507         ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
508         return ent;
509 }
510
511
512 /*
513 =================
514 CL_UpdateTEnts
515 =================
516 */
517 void CL_UpdateTEnts (void)
518 {
519         int                     i;
520         beam_t          *b;
521         vec3_t          dist, org;
522         float           d;
523         entity_t        *ent;
524         float           yaw, pitch;
525         float           forward;
526         dlight_t        *dl;
527
528         num_temp_entities = 0;
529
530 // update lightning
531         for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
532         {
533                 if (!b->model || b->endtime < cl.time)
534                         continue;
535
536         // if coming from the player, update the start position
537                 if (b->entity == cl.viewentity)
538                 {
539                         VectorCopy (cl_entities[cl.viewentity].origin, b->start);
540                 }
541
542         // calculate pitch and yaw
543                 VectorSubtract (b->end, b->start, dist);
544
545                 if (dist[1] == 0 && dist[0] == 0)
546                 {
547                         yaw = 0;
548                         if (dist[2] > 0)
549                                 pitch = 90;
550                         else
551                                 pitch = 270;
552                 }
553                 else
554                 {
555                         yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
556                         if (yaw < 0)
557                                 yaw += 360;
558         
559                         forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
560                         pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
561                         if (pitch < 0)
562                                 pitch += 360;
563                 }
564
565         // add new entities for the lightning
566                 VectorCopy (b->start, org);
567                 d = VectorNormalizeLength(dist);
568                 while (d > 0)
569                 {
570                         ent = CL_NewTempEntity ();
571                         if (!ent)
572                                 return;
573                         VectorCopy (org, ent->origin);
574                         ent->model = b->model;
575                         ent->effects = EF_FULLBRIGHT;
576                         ent->angles[0] = pitch;
577                         ent->angles[1] = yaw;
578                         ent->angles[2] = rand()%360;
579
580                         dl = CL_AllocDlight (0);
581                         VectorCopy (ent->origin,  dl->origin);
582                         dl->radius = 100 + (rand()&31);
583                         dl->die = cl.time + 0.001;
584                         dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 1;
585
586                         VectorMA(org, 30, dist, org);
587                         d -= 30;
588                 }
589         }
590         
591 }
592
593