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