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