1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
24int			num_temp_entities;
25entity_t	cl_temp_entities[MAX_TEMP_ENTITIES];
26beam_t		cl_beams[MAX_BEAMS];
27
28sfx_t			*cl_sfx_wizhit;
29sfx_t			*cl_sfx_knighthit;
30sfx_t			*cl_sfx_tink1;
31sfx_t			*cl_sfx_ric1;
32sfx_t			*cl_sfx_ric2;
33sfx_t			*cl_sfx_ric3;
34sfx_t			*cl_sfx_r_exp3;
35#ifdef QUAKE2
36sfx_t			*cl_sfx_imp;
37sfx_t			*cl_sfx_rail;
38#endif
39
40/*
41=================
42CL_ParseTEnt
43=================
44*/
45void CL_InitTEnts (void)
46{
47	cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
48	cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
49	cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
50	cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
51	cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
52	cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
53	cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
54#ifdef QUAKE2
55	cl_sfx_imp = S_PrecacheSound ("shambler/sattck1.wav");
56	cl_sfx_rail = S_PrecacheSound ("weapons/lstart.wav");
57#endif
58}
59
60/*
61=================
62CL_ParseBeam
63=================
64*/
65void CL_ParseBeam (model_t *m)
66{
67	int		ent;
68	vec3_t	start, end;
69	beam_t	*b;
70	int		i;
71
72	ent = MSG_ReadShort ();
73
74	start[0] = MSG_ReadCoord ();
75	start[1] = MSG_ReadCoord ();
76	start[2] = MSG_ReadCoord ();
77
78	end[0] = MSG_ReadCoord ();
79	end[1] = MSG_ReadCoord ();
80	end[2] = MSG_ReadCoord ();
81
82// override any beam with the same entity
83	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
84		if (b->entity == ent)
85		{
86			b->entity = ent;
87			b->model = m;
88			b->endtime = cl.time + 0.2;
89			VectorCopy (start, b->start);
90			VectorCopy (end, b->end);
91			return;
92		}
93
94// find a free beam
95	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
96	{
97		if (!b->model || b->endtime < cl.time)
98		{
99			b->entity = ent;
100			b->model = m;
101			b->endtime = cl.time + 0.2;
102			VectorCopy (start, b->start);
103			VectorCopy (end, b->end);
104			return;
105		}
106	}
107	Con_Printf ("beam list overflow!\n");
108}
109
110/*
111=================
112CL_ParseTEnt
113=================
114*/
115void CL_ParseTEnt (void)
116{
117	int		type;
118	vec3_t	pos;
119#ifdef QUAKE2
120	vec3_t	endpos;
121#endif
122	dlight_t	*dl;
123	int		rnd;
124	int		colorStart, colorLength;
125
126	type = MSG_ReadByte ();
127	switch (type)
128	{
129	case TE_WIZSPIKE:			// spike hitting wall
130		pos[0] = MSG_ReadCoord ();
131		pos[1] = MSG_ReadCoord ();
132		pos[2] = MSG_ReadCoord ();
133		R_RunParticleEffect (pos, vec3_origin, 20, 30);
134		S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
135		break;
136
137	case TE_KNIGHTSPIKE:			// spike hitting wall
138		pos[0] = MSG_ReadCoord ();
139		pos[1] = MSG_ReadCoord ();
140		pos[2] = MSG_ReadCoord ();
141		R_RunParticleEffect (pos, vec3_origin, 226, 20);
142		S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
143		break;
144
145	case TE_SPIKE:			// spike hitting wall
146		pos[0] = MSG_ReadCoord ();
147		pos[1] = MSG_ReadCoord ();
148		pos[2] = MSG_ReadCoord ();
149#ifdef GLTEST
150		Test_Spawn (pos);
151#else
152		R_RunParticleEffect (pos, vec3_origin, 0, 10);
153#endif
154		if ( rand() % 5 )
155			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
156		else
157		{
158			rnd = rand() & 3;
159			if (rnd == 1)
160				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
161			else if (rnd == 2)
162				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
163			else
164				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
165		}
166		break;
167	case TE_SUPERSPIKE:			// super spike hitting wall
168		pos[0] = MSG_ReadCoord ();
169		pos[1] = MSG_ReadCoord ();
170		pos[2] = MSG_ReadCoord ();
171		R_RunParticleEffect (pos, vec3_origin, 0, 20);
172
173		if ( rand() % 5 )
174			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
175		else
176		{
177			rnd = rand() & 3;
178			if (rnd == 1)
179				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
180			else if (rnd == 2)
181				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
182			else
183				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
184		}
185		break;
186
187	case TE_GUNSHOT:			// bullet hitting wall
188		pos[0] = MSG_ReadCoord ();
189		pos[1] = MSG_ReadCoord ();
190		pos[2] = MSG_ReadCoord ();
191		R_RunParticleEffect (pos, vec3_origin, 0, 20);
192		break;
193
194	case TE_EXPLOSION:			// rocket explosion
195		pos[0] = MSG_ReadCoord ();
196		pos[1] = MSG_ReadCoord ();
197		pos[2] = MSG_ReadCoord ();
198		R_ParticleExplosion (pos);
199		dl = CL_AllocDlight (0);
200		VectorCopy (pos, dl->origin);
201		dl->radius = 350;
202		dl->die = cl.time + 0.5;
203		dl->decay = 300;
204		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
205		break;
206
207	case TE_TAREXPLOSION:			// tarbaby explosion
208		pos[0] = MSG_ReadCoord ();
209		pos[1] = MSG_ReadCoord ();
210		pos[2] = MSG_ReadCoord ();
211		R_BlobExplosion (pos);
212
213		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
214		break;
215
216	case TE_LIGHTNING1:				// lightning bolts
217		CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
218		break;
219
220	case TE_LIGHTNING2:				// lightning bolts
221		CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
222		break;
223
224	case TE_LIGHTNING3:				// lightning bolts
225		CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
226		break;
227
228// PGM 01/21/97
229	case TE_BEAM:				// grappling hook beam
230		CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
231		break;
232// PGM 01/21/97
233
234	case TE_LAVASPLASH:
235		pos[0] = MSG_ReadCoord ();
236		pos[1] = MSG_ReadCoord ();
237		pos[2] = MSG_ReadCoord ();
238		R_LavaSplash (pos);
239		break;
240
241	case TE_TELEPORT:
242		pos[0] = MSG_ReadCoord ();
243		pos[1] = MSG_ReadCoord ();
244		pos[2] = MSG_ReadCoord ();
245		R_TeleportSplash (pos);
246		break;
247
248	case TE_EXPLOSION2:				// color mapped explosion
249		pos[0] = MSG_ReadCoord ();
250		pos[1] = MSG_ReadCoord ();
251		pos[2] = MSG_ReadCoord ();
252		colorStart = MSG_ReadByte ();
253		colorLength = MSG_ReadByte ();
254		R_ParticleExplosion2 (pos, colorStart, colorLength);
255		dl = CL_AllocDlight (0);
256		VectorCopy (pos, dl->origin);
257		dl->radius = 350;
258		dl->die = cl.time + 0.5;
259		dl->decay = 300;
260		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
261		break;
262
263#ifdef QUAKE2
264	case TE_IMPLOSION:
265		pos[0] = MSG_ReadCoord ();
266		pos[1] = MSG_ReadCoord ();
267		pos[2] = MSG_ReadCoord ();
268		S_StartSound (-1, 0, cl_sfx_imp, pos, 1, 1);
269		break;
270
271	case TE_RAILTRAIL:
272		pos[0] = MSG_ReadCoord ();
273		pos[1] = MSG_ReadCoord ();
274		pos[2] = MSG_ReadCoord ();
275		endpos[0] = MSG_ReadCoord ();
276		endpos[1] = MSG_ReadCoord ();
277		endpos[2] = MSG_ReadCoord ();
278		S_StartSound (-1, 0, cl_sfx_rail, pos, 1, 1);
279		S_StartSound (-1, 1, cl_sfx_r_exp3, endpos, 1, 1);
280		R_RocketTrail (pos, endpos, 0+128);
281		R_ParticleExplosion (endpos);
282		dl = CL_AllocDlight (-1);
283		VectorCopy (endpos, dl->origin);
284		dl->radius = 350;
285		dl->die = cl.time + 0.5;
286		dl->decay = 300;
287		break;
288#endif
289
290	default:
291		Sys_Error ("CL_ParseTEnt: bad type");
292	}
293}
294
295
296/*
297=================
298CL_NewTempEntity
299=================
300*/
301entity_t *CL_NewTempEntity (void)
302{
303	entity_t	*ent;
304
305	if (cl_numvisedicts == MAX_VISEDICTS)
306		return NULL;
307	if (num_temp_entities == MAX_TEMP_ENTITIES)
308		return NULL;
309	ent = &cl_temp_entities[num_temp_entities];
310	memset (ent, 0, sizeof(*ent));
311	num_temp_entities++;
312	cl_visedicts[cl_numvisedicts] = ent;
313	cl_numvisedicts++;
314
315	ent->colormap = vid.colormap;
316	return ent;
317}
318
319
320/*
321=================
322CL_UpdateTEnts
323=================
324*/
325void CL_UpdateTEnts (void)
326{
327	int			i;
328	beam_t		*b;
329	vec3_t		dist, org;
330	float		d;
331	entity_t	*ent;
332	float		yaw, pitch;
333	float		forward;
334
335	num_temp_entities = 0;
336
337// update lightning
338	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
339	{
340		if (!b->model || b->endtime < cl.time)
341			continue;
342
343	// if coming from the player, update the start position
344		if (b->entity == cl.viewentity)
345		{
346			VectorCopy (cl_entities[cl.viewentity].origin, b->start);
347		}
348
349	// calculate pitch and yaw
350		VectorSubtract (b->end, b->start, dist);
351
352		if (dist[1] == 0 && dist[0] == 0)
353		{
354			yaw = 0;
355			if (dist[2] > 0)
356				pitch = 90;
357			else
358				pitch = 270;
359		}
360		else
361		{
362			yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
363			if (yaw < 0)
364				yaw += 360;
365
366			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
367			pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
368			if (pitch < 0)
369				pitch += 360;
370		}
371
372	// add new entities for the lightning
373		VectorCopy (b->start, org);
374		d = VectorNormalize(dist);
375		while (d > 0)
376		{
377			ent = CL_NewTempEntity ();
378			if (!ent)
379				return;
380			VectorCopy (org, ent->origin);
381			ent->model = b->model;
382			ent->angles[0] = pitch;
383			ent->angles[1] = yaw;
384			ent->angles[2] = rand()%360;
385
386			for (i=0 ; i<3 ; i++)
387				org[i] += dist[i]*30;
388			d -= 30;
389		}
390	}
391
392}
393
394
395