1 /*
2 Copyright (C) 1997-2001 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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client.h"
27
28 cl_sustain_t cl_sustains[MAX_SUSTAINS];
29
30 struct sfx_s *cl_sfx_ric1;
31 struct sfx_s *cl_sfx_ric2;
32 struct sfx_s *cl_sfx_ric3;
33 // [no file] struct sfx_s *cl_sfx_lashit;
34 struct sfx_s *cl_sfx_spark5;
35 struct sfx_s *cl_sfx_spark6;
36 struct sfx_s *cl_sfx_spark7;
37 struct sfx_s *cl_sfx_railg;
38 struct sfx_s *cl_sfx_rockexp;
39 struct sfx_s *cl_sfx_watrexp;
40 struct sfx_s *cl_sfx_footsteps[4];
41 struct sfx_s *cl_sfx_metal_footsteps[4];
42
43 /*
44 =================
45 CL_RegisterTEntSounds
46 =================
47 */
CL_RegisterTEntSounds(void)48 void CL_RegisterTEntSounds (void)
49 {
50 int i;
51 char name[MAX_QPATH];
52
53 cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
54 cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
55 cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
56 // [no file] cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
57 cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
58 cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
59
60 S_RegisterSound ("player/land1.wav");
61 S_RegisterSound ("player/fall2.wav");
62 S_RegisterSound ("player/fall1.wav");
63
64 for (i=0 ; i<4 ; i++)
65 {
66 Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
67 cl_sfx_footsteps[i] = S_RegisterSound (name);
68 }
69 for (i=0 ; i<4 ; i++)
70 {
71 Com_sprintf (name, sizeof(name), "player/step_metal%i.wav", i+1);
72 cl_sfx_metal_footsteps[i] = S_RegisterSound (name);
73 }
74 }
75
76 /*
77 =================
78 CL_ClearTEnts
79 =================
80 */
CL_ClearTEnts(void)81 void CL_ClearTEnts (void)
82 {
83 memset (cl_sustains, 0, sizeof(cl_sustains));
84 }
85
86 /*
87 =================
88 CL_ParseParticles
89 =================
90 */
CL_ParseParticles(void)91 void CL_ParseParticles (void)
92 {
93 int color, count;
94 vec3_t pos, dir;
95
96 MSG_ReadPos (&net_message, pos);
97 MSG_ReadDir (&net_message, dir);
98
99 color = MSG_ReadByte (&net_message);
100
101 count = MSG_ReadByte (&net_message);
102
103 CL_ParticleEffect (pos, dir, color, count);
104 }
105
106 //=============
107 //ROGUE
CL_ParseSteam(void)108 void CL_ParseSteam (void)
109 {
110 vec3_t pos, dir;
111 int i;
112 int r;
113 int cnt;
114 cl_sustain_t *s, *free_sustain;
115
116 free_sustain = NULL;
117 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
118 {
119 if (s->id == 0)
120 {
121 free_sustain = s;
122 break;
123 }
124 }
125 if (free_sustain)
126 {
127 s->id = 25; //unused for now
128 s->count = MSG_ReadByte (&net_message);
129 if (!s->count)
130 s->count = 32;
131
132 MSG_ReadPos (&net_message, s->org);
133 MSG_ReadDir (&net_message, s->dir);
134 r = MSG_ReadByte (&net_message);
135 if(!r)
136 r = 15; //light gray
137 else {
138 switch(r) {
139 case 1:
140 r = 0xd2; //lime green
141 break;
142 case 2:
143 r = 0x74; //blue
144 break;
145 case 3:
146 r = 0xe8; //red
147 break;
148 default:
149 r = 15; //light gray
150 break;
151 }
152 }
153 s->color = r;
154 s->magnitude = 30;
155 s->endtime = cl.time + 10000000;
156 s->think = CL_ParticleSteamEffect;
157 s->thinkinterval = 512/s->count; //~ 60 fps
158 s->nextthink = cl.time;
159 }
160 else
161 {
162 // read the stuff anyway
163 cnt = MSG_ReadByte (&net_message);
164 MSG_ReadPos (&net_message, pos);
165 MSG_ReadDir (&net_message, dir);
166 r = MSG_ReadByte (&net_message);
167 }
168 }
169
CL_ParseFire(void)170 void CL_ParseFire (void)
171 {
172 vec3_t pos, dir;
173 int id, i;
174 int r;
175 int cnt;
176 int magnitude;
177 cl_sustain_t *s, *free_sustain;
178
179 // id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
180 id = 25;
181 if (id != -1) // sustains
182 {
183 // Com_Printf ("Sustain effect id %d\n", id);
184 free_sustain = NULL;
185 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
186 {
187 if (s->id == 0)
188 {
189 free_sustain = s;
190 break;
191 }
192 }
193 if (free_sustain)
194 {
195 s->id = id;
196 s->count = MSG_ReadByte (&net_message);
197 s->count = 10;//just for testing here
198 MSG_ReadPos (&net_message, s->org);
199 MSG_ReadDir (&net_message, s->dir);
200 r = MSG_ReadByte (&net_message);
201 s->color = r & 0xff;
202 s->magnitude = 150;//MSG_ReadShort (&net_message);
203 s->endtime = cl.time + 10000000;//MSG_ReadLong (&net_message);
204 s->think = CL_ParticleFireEffect2;
205 s->thinkinterval = 16; //~ 60 fps
206 s->nextthink = cl.time;
207 }
208 else
209 {
210 // Com_Printf ("No free sustains!\n");
211 // FIXME - read the stuff anyway
212 cnt = MSG_ReadByte (&net_message);
213 MSG_ReadPos (&net_message, pos);
214 MSG_ReadDir (&net_message, dir);
215 r = MSG_ReadByte (&net_message);
216 magnitude = MSG_ReadShort (&net_message);
217 magnitude = MSG_ReadLong (&net_message); // really interval
218 }
219 }
220
221 }
222
CL_ParseSmoke(void)223 void CL_ParseSmoke (void)
224 {
225 vec3_t pos, dir;
226 int id, i;
227 int r;
228 int cnt;
229 int magnitude;
230 cl_sustain_t *s, *free_sustain;
231
232 // id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
233 id = 25;
234 if (id != -1) // sustains
235 {
236 // Com_Printf ("Sustain effect id %d\n", id);
237 free_sustain = NULL;
238 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
239 {
240 if (s->id == 0)
241 {
242 free_sustain = s;
243 break;
244 }
245 }
246 if (free_sustain)
247 {
248 s->id = id;
249 s->count = MSG_ReadByte (&net_message);
250 MSG_ReadPos (&net_message, s->org);
251 MSG_ReadDir (&net_message, s->dir);
252 r = MSG_ReadByte (&net_message);
253 s->color = r & 0xff;
254 s->magnitude = 400;//MSG_ReadShort (&net_message);
255 s->endtime = cl.time + 10000000;//MSG_ReadLong (&net_message);
256 s->think = CL_ParticleSmokeEffect2;
257 s->thinkinterval = 16; //~ 60 fps
258 s->nextthink = cl.time;
259 }
260 else
261 {
262 // Com_Printf ("No free sustains!\n");
263 // FIXME - read the stuff anyway
264 cnt = MSG_ReadByte (&net_message);
265 MSG_ReadPos (&net_message, pos);
266 MSG_ReadDir (&net_message, dir);
267 r = MSG_ReadByte (&net_message);
268 magnitude = MSG_ReadShort (&net_message);
269 magnitude = MSG_ReadLong (&net_message); // really interval
270 }
271 }
272
273 }
274
275 //ROGUE
276 //=============
277
278
279 /*
280 =================
281 CL_ParseTEnt
282 =================
283 */
284 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
285 extern void R_ApplyForceToRagdolls(vec3_t origin, float force);
CL_ParseTEnt(void)286 void CL_ParseTEnt (void)
287 {
288 int type;
289 vec3_t pos, pos2, dir;
290 int cnt;
291 int color;
292 int r;
293 trace_t trace;
294 static vec3_t mins = { -8, -8, -8 };
295 static vec3_t maxs = { 8, 8, 8 };
296
297 type = MSG_ReadByte (&net_message);
298
299 switch (type)
300 {
301 case TE_BLOOD: // bullet hitting flesh
302 MSG_ReadPos (&net_message, pos);
303 MSG_ReadDir (&net_message, dir);
304 CL_ParticleEffect (pos, dir, 450, 60);// doing the blood here - color is red
305 break;
306 case TE_GREENBLOOD:
307 MSG_ReadPos (&net_message, pos);
308 MSG_ReadDir (&net_message, dir);
309 CL_ParticleEffect (pos, dir, 550, 60);// doing the blood here - color is green
310 break;
311 case TE_GUNSHOT:
312 case TE_SPARKS:
313 case TE_BULLET_SPARKS:
314 MSG_ReadPos (&net_message, pos);
315 MSG_ReadDir (&net_message, dir);
316
317 if (type == TE_GUNSHOT) {
318 CL_ParticleEffect (pos, dir, 425, 10);
319 trace = CL_Trace ( pos, mins, maxs, pos, -1, MASK_SOLID, true, NULL);
320 if(trace.contents) {
321 CL_BulletMarks(pos, dir);
322 R_ApplyForceToRagdolls(pos, 40);
323 }
324 }
325 else
326 CL_ParticleEffect (pos, dir, 425, 2); // bullets, color is 0xe0
327
328 CL_BulletSparks( pos, dir);
329
330 if (type != TE_SPARKS)
331 {
332 // impact sound
333 cnt = rand()&15;
334 if (cnt == 1)
335 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
336 else if (cnt == 2)
337 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
338 else if (cnt == 3)
339 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
340 }
341
342 break;
343
344 case TE_SCREEN_SPARKS:
345 MSG_ReadPos (&net_message, pos);
346 MSG_ReadDir (&net_message, dir);
347 if (type == TE_SCREEN_SPARKS) {
348 trace = CL_Trace ( pos, mins, maxs, pos, -1, MASK_SOLID, true, NULL);
349 if(trace.contents) {
350 CL_BeamgunMark(pos, dir, 0.8, false);
351 R_ApplyForceToRagdolls(pos, 40);
352 }
353 CL_LaserSparks (pos, dir, 0xd0, 20);
354 }
355 else
356 CL_ParticleEffect (pos, dir, 0xb0, 40);
357 // [no file] S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
358 break;
359
360 case TE_LASERBEAM: // martian laser effect
361 MSG_ReadPos (&net_message, pos);
362 MSG_ReadPos (&net_message, pos2);
363 CL_LaserBeam (pos, pos2);
364 break;
365
366 case TE_SPLASH: // bullet hitting water
367 cnt = MSG_ReadByte (&net_message);
368 MSG_ReadPos (&net_message, pos);
369 MSG_ReadDir (&net_message, dir);
370 r = MSG_ReadByte (&net_message);
371 if (r > 6)
372 color = 0x00;
373 else
374 color = splash_color[r];
375
376 CL_SplashEffect (pos, dir, color, cnt);
377
378 if (r == SPLASH_SPARKS)
379 {
380 r = rand() & 3;
381 if (r == 0)
382 S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
383 else if (r == 1)
384 S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
385 else
386 S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
387 }
388 break;
389
390 case TE_LASER_SPARKS:
391 cnt = MSG_ReadByte (&net_message);
392 MSG_ReadPos (&net_message, pos);
393 MSG_ReadDir (&net_message, dir);
394 color = MSG_ReadByte (&net_message);
395 CL_ParticleEffect2 (pos, dir, color, cnt);
396 break;
397
398 case TE_BLASTER: // blaster hitting wall
399 MSG_ReadPos (&net_message, pos);
400 MSG_ReadDir (&net_message, dir);
401 CL_BlasterParticles (pos, dir);
402 R_ApplyForceToRagdolls(pos, 100);
403 break;
404
405 case TE_RAILTRAIL: // beam effect
406 MSG_ReadPos (&net_message, pos);
407 MSG_ReadPos (&net_message, pos2);
408 CL_DisruptorBeam (pos, pos2);
409 trace = CL_Trace ( pos, mins, maxs, pos2, -1, MASK_SOLID, true, NULL);
410 if(trace.contents) {
411 CL_BeamgunMark(pos2, trace.plane.normal, 0.4, true);
412 R_ApplyForceToRagdolls(pos2, 100);
413 }
414 S_StartSound (pos, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
415 CL_PlasmaFlashParticle(pos, cl.refdef.viewangles, false);
416 break;
417
418 case TE_EXPLOSION2: //using this for a "dust" explosion, ie big, big footsteps effect
419 MSG_ReadPos (&net_message, pos);
420
421 CL_DustParticles (pos);
422 break;
423
424 case TE_EXPLOSION1:
425 case TE_ROCKET_EXPLOSION:
426 case TE_ROCKET_EXPLOSION_WATER:
427 MSG_ReadPos (&net_message, pos);
428
429 //remember to add explosion stain
430
431 CL_ExplosionParticles (pos);
432 if (type == TE_ROCKET_EXPLOSION_WATER)
433 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
434 else
435 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
436 R_ApplyForceToRagdolls(pos, 100);
437
438 break;
439
440 case TE_BFG_BIGEXPLOSION:
441 MSG_ReadPos (&net_message, pos);
442 CL_BFGExplosionParticles (pos);
443 R_ApplyForceToRagdolls(pos, 200);
444 break;
445
446 case TE_BUBBLETRAIL:
447 MSG_ReadPos (&net_message, pos);
448 MSG_ReadPos (&net_message, pos2);
449 CL_BubbleTrail (pos, pos2);
450 break;
451
452 case TE_REDLASER:
453 MSG_ReadPos (&net_message, pos);
454 MSG_ReadPos (&net_message, pos2);
455 CL_RedBlasterBeam (pos, pos2);
456 break;
457
458 case TE_BOSSTPORT: // boss teleporting to station
459 MSG_ReadPos (&net_message, pos);
460 CL_BigTeleportParticles (pos);
461 S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
462 break;
463
464 case TE_LIGHTNING:
465 MSG_ReadPos (&net_message, pos);
466 MSG_ReadPos (&net_message, pos2);
467 CL_NewLightning (pos, pos2);
468 break;
469
470 case TE_VAPORBEAM:
471 MSG_ReadPos (&net_message, pos);
472 MSG_ReadPos (&net_message, pos2);
473 CL_VaporizerBeam (pos, pos2);
474 trace = CL_Trace ( pos, mins, maxs, pos2, -1, MASK_SOLID, true, NULL);
475 if(trace.contents)
476 CL_VaporizerMarks(pos2, trace.plane.normal);
477 break;
478
479 case TE_STEAM:
480 CL_ParseSteam();
481 break;
482 case TE_FIRE:
483 CL_ParseFire();
484 break;
485 case TE_SMOKE:
486 CL_ParseSmoke();
487 break;
488
489 case TE_SAYICON:
490 MSG_ReadPos(&net_message, pos);
491 CL_SayIcon(pos);
492 break;
493
494 case TE_TELEPORT_EFFECT:
495 MSG_ReadPos (&net_message, pos);
496 CL_TeleportParticles (pos);
497 break;
498
499 case TE_LEADERBLASTER:
500 MSG_ReadPos (&net_message, pos);
501 MSG_ReadPos (&net_message, pos2);
502 CL_RedBlasterBeam (pos, pos2);
503 S_StartSound (pos, 0, 0, S_RegisterSound ("weapons/biglaser.wav"), 1, ATTN_NONE, 0);
504 break;
505
506 case TE_CHAINGUNSMOKE:
507 MSG_ReadPos (&net_message, pos);
508 CL_MuzzleParticles (pos);
509 CL_MuzzleFlashParticle(pos, cl.refdef.viewangles, false);
510 break;
511
512 case TE_BLUE_MUZZLEFLASH:
513 MSG_ReadPos (&net_message, pos);
514 CL_BlueMuzzleParticles (pos);
515 break;
516 case TE_SMART_MUZZLEFLASH:
517 MSG_ReadPos (&net_message, pos);
518 CL_SmartMuzzle (pos);
519 break;
520
521 case TE_VOLTAGE:
522 MSG_ReadPos (&net_message, pos);
523 MSG_ReadDir (&net_message, dir);
524 CL_Voltage (pos);
525 R_ApplyForceToRagdolls(pos, -50);
526 break;
527
528 case TE_DEATHFIELD:
529 MSG_ReadPos (&net_message, pos);
530 CL_Deathfield (pos, 0);
531 break;
532 case TE_DEATHFIELD2:
533 MSG_ReadPos (&net_message, pos);
534 MSG_ReadDir (&net_message, dir);
535 CL_Deathfield (pos, 1);
536 break;
537
538 case TE_BLASTERBEAM: // blaster beam effect
539 MSG_ReadPos (&net_message, pos);
540 MSG_ReadPos (&net_message, pos2);
541 CL_BlasterBeam (pos, pos2);
542 trace = CL_Trace ( pos, mins, maxs, pos2, -1, MASK_SOLID, true, NULL);
543 if(trace.contents) {
544 CL_BlasterMark(pos2, trace.plane.normal);
545 R_ApplyForceToRagdolls(pos2, 100);
546 }
547 break;
548
549 default: // Do we really want to drop an error for this?
550 //Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
551 Com_Printf("CL_ParseTEnt: bad type\n");
552 }
553 }
554
555 extern cvar_t *hand;
556
557 /* PMM - CL_Sustains */
CL_ProcessSustain()558 void CL_ProcessSustain ()
559 {
560 cl_sustain_t *s;
561 int i;
562
563 for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
564 {
565 if (s->id && CM_inPVS (cl.refdef.vieworg, s->org))
566 {
567 if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
568 {
569 s->think (s);
570 }
571 else if (s->endtime < cl.time)
572 s->id = 0;
573 }
574 }
575 }
576
577 /*
578 =================
579 CL_AddTEnts
580 =================
581 */
CL_AddTEnts(void)582 void CL_AddTEnts (void)
583 {
584 CL_ProcessSustain();
585 }
586