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