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