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