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