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