• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 #define	MAX_BEAMS	8
26 typedef struct
27 {
28 	int		entity;
29 	struct model_s	*model;
30 	float	endtime;
31 	vec3_t	start, end;
32 } beam_t;
33 
34 beam_t		cl_beams[MAX_BEAMS];
35 
36 #define	MAX_EXPLOSIONS	8
37 typedef struct
38 {
39 	vec3_t	origin;
40 	float	start;
41 	model_t	*model;
42 } explosion_t;
43 
44 explosion_t	cl_explosions[MAX_EXPLOSIONS];
45 
46 
47 sfx_t			*cl_sfx_wizhit;
48 sfx_t			*cl_sfx_knighthit;
49 sfx_t			*cl_sfx_tink1;
50 sfx_t			*cl_sfx_ric1;
51 sfx_t			*cl_sfx_ric2;
52 sfx_t			*cl_sfx_ric3;
53 sfx_t			*cl_sfx_r_exp3;
54 
55 /*
56 =================
57 CL_ParseTEnts
58 =================
59 */
CL_InitTEnts(void)60 void CL_InitTEnts (void)
61 {
62 	cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
63 	cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
64 	cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
65 	cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
66 	cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
67 	cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
68 	cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
69 }
70 
71 /*
72 =================
73 CL_ClearTEnts
74 =================
75 */
CL_ClearTEnts(void)76 void CL_ClearTEnts (void)
77 {
78 	memset (&cl_beams, 0, sizeof(cl_beams));
79 	memset (&cl_explosions, 0, sizeof(cl_explosions));
80 }
81 
82 /*
83 =================
84 CL_AllocExplosion
85 =================
86 */
CL_AllocExplosion(void)87 explosion_t *CL_AllocExplosion (void)
88 {
89 	int		i;
90 	float	time;
91 	int		index;
92 
93 	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
94 		if (!cl_explosions[i].model)
95 			return &cl_explosions[i];
96 // find the oldest explosion
97 	time = cl.time;
98 	index = 0;
99 
100 	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
101 		if (cl_explosions[i].start < time)
102 		{
103 			time = cl_explosions[i].start;
104 			index = i;
105 		}
106 	return &cl_explosions[index];
107 }
108 
109 /*
110 =================
111 CL_ParseBeam
112 =================
113 */
CL_ParseBeam(model_t * m)114 void CL_ParseBeam (model_t *m)
115 {
116 	int		ent;
117 	vec3_t	start, end;
118 	beam_t	*b;
119 	int		i;
120 
121 	ent = MSG_ReadShort ();
122 
123 	start[0] = MSG_ReadCoord ();
124 	start[1] = MSG_ReadCoord ();
125 	start[2] = MSG_ReadCoord ();
126 
127 	end[0] = MSG_ReadCoord ();
128 	end[1] = MSG_ReadCoord ();
129 	end[2] = MSG_ReadCoord ();
130 
131 // override any beam with the same entity
132 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
133 		if (b->entity == ent)
134 		{
135 			b->entity = ent;
136 			b->model = m;
137 			b->endtime = cl.time + 0.2;
138 			VectorCopy (start, b->start);
139 			VectorCopy (end, b->end);
140 			return;
141 		}
142 
143 // find a free beam
144 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
145 	{
146 		if (!b->model || b->endtime < cl.time)
147 		{
148 			b->entity = ent;
149 			b->model = m;
150 			b->endtime = cl.time + 0.2;
151 			VectorCopy (start, b->start);
152 			VectorCopy (end, b->end);
153 			return;
154 		}
155 	}
156 	Con_Printf ("beam list overflow!\n");
157 }
158 
159 /*
160 =================
161 CL_ParseTEnt
162 =================
163 */
CL_ParseTEnt(void)164 void CL_ParseTEnt (void)
165 {
166 	int		type;
167 	vec3_t	pos;
168 	dlight_t	*dl;
169 	int		rnd;
170 	explosion_t	*ex;
171 	int		cnt;
172 
173 	type = MSG_ReadByte ();
174 	switch (type)
175 	{
176 	case TE_WIZSPIKE:			// spike hitting wall
177 		pos[0] = MSG_ReadCoord ();
178 		pos[1] = MSG_ReadCoord ();
179 		pos[2] = MSG_ReadCoord ();
180 		R_RunParticleEffect (pos, vec3_origin, 20, 30);
181 		S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
182 		break;
183 
184 	case TE_KNIGHTSPIKE:			// spike hitting wall
185 		pos[0] = MSG_ReadCoord ();
186 		pos[1] = MSG_ReadCoord ();
187 		pos[2] = MSG_ReadCoord ();
188 		R_RunParticleEffect (pos, vec3_origin, 226, 20);
189 		S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
190 		break;
191 
192 	case TE_SPIKE:			// spike hitting wall
193 		pos[0] = MSG_ReadCoord ();
194 		pos[1] = MSG_ReadCoord ();
195 		pos[2] = MSG_ReadCoord ();
196 		R_RunParticleEffect (pos, vec3_origin, 0, 10);
197 
198 		if ( rand() % 5 )
199 			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
200 		else
201 		{
202 			rnd = rand() & 3;
203 			if (rnd == 1)
204 				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
205 			else if (rnd == 2)
206 				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
207 			else
208 				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
209 		}
210 		break;
211 	case TE_SUPERSPIKE:			// super spike hitting wall
212 		pos[0] = MSG_ReadCoord ();
213 		pos[1] = MSG_ReadCoord ();
214 		pos[2] = MSG_ReadCoord ();
215 		R_RunParticleEffect (pos, vec3_origin, 0, 20);
216 
217 		if ( rand() % 5 )
218 			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
219 		else
220 		{
221 			rnd = rand() & 3;
222 			if (rnd == 1)
223 				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
224 			else if (rnd == 2)
225 				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
226 			else
227 				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
228 		}
229 		break;
230 
231 	case TE_EXPLOSION:			// rocket explosion
232 	// particles
233 		pos[0] = MSG_ReadCoord ();
234 		pos[1] = MSG_ReadCoord ();
235 		pos[2] = MSG_ReadCoord ();
236 		R_ParticleExplosion (pos);
237 
238 	// light
239 		dl = CL_AllocDlight (0);
240 		VectorCopy (pos, dl->origin);
241 		dl->radius = 350;
242 		dl->die = cl.time + 0.5;
243 		dl->decay = 300;
244 		dl->color[0] = 0.2;
245 		dl->color[1] = 0.1;
246 		dl->color[2] = 0.05;
247 		dl->color[3] = 0.7;
248 
249 	// sound
250 		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
251 
252 	// sprite
253 		ex = CL_AllocExplosion ();
254 		VectorCopy (pos, ex->origin);
255 		ex->start = cl.time;
256 		ex->model = Mod_ForName ("progs/s_explod.spr", true);
257 		break;
258 
259 	case TE_TAREXPLOSION:			// tarbaby explosion
260 		pos[0] = MSG_ReadCoord ();
261 		pos[1] = MSG_ReadCoord ();
262 		pos[2] = MSG_ReadCoord ();
263 		R_BlobExplosion (pos);
264 
265 		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
266 		break;
267 
268 	case TE_LIGHTNING1:				// lightning bolts
269 		CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
270 		break;
271 
272 	case TE_LIGHTNING2:				// lightning bolts
273 		CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
274 		break;
275 
276 	case TE_LIGHTNING3:				// lightning bolts
277 		CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
278 		break;
279 
280 	case TE_LAVASPLASH:
281 		pos[0] = MSG_ReadCoord ();
282 		pos[1] = MSG_ReadCoord ();
283 		pos[2] = MSG_ReadCoord ();
284 		R_LavaSplash (pos);
285 		break;
286 
287 	case TE_TELEPORT:
288 		pos[0] = MSG_ReadCoord ();
289 		pos[1] = MSG_ReadCoord ();
290 		pos[2] = MSG_ReadCoord ();
291 		R_TeleportSplash (pos);
292 		break;
293 
294 	case TE_GUNSHOT:			// bullet hitting wall
295 		cnt = MSG_ReadByte ();
296 		pos[0] = MSG_ReadCoord ();
297 		pos[1] = MSG_ReadCoord ();
298 		pos[2] = MSG_ReadCoord ();
299 		R_RunParticleEffect (pos, vec3_origin, 0, 20*cnt);
300 		break;
301 
302 	case TE_BLOOD:				// bullets hitting body
303 		cnt = MSG_ReadByte ();
304 		pos[0] = MSG_ReadCoord ();
305 		pos[1] = MSG_ReadCoord ();
306 		pos[2] = MSG_ReadCoord ();
307 		R_RunParticleEffect (pos, vec3_origin, 73, 20*cnt);
308 		break;
309 
310 	case TE_LIGHTNINGBLOOD:		// lightning hitting body
311 		pos[0] = MSG_ReadCoord ();
312 		pos[1] = MSG_ReadCoord ();
313 		pos[2] = MSG_ReadCoord ();
314 		R_RunParticleEffect (pos, vec3_origin, 225, 50);
315 		break;
316 
317 	default:
318 		Sys_Error ("CL_ParseTEnt: bad type");
319 	}
320 }
321 
322 
323 /*
324 =================
325 CL_NewTempEntity
326 =================
327 */
CL_NewTempEntity(void)328 entity_t *CL_NewTempEntity (void)
329 {
330 	entity_t	*ent;
331 
332 	if (cl_numvisedicts == MAX_VISEDICTS)
333 		return NULL;
334 	ent = &cl_visedicts[cl_numvisedicts];
335 	cl_numvisedicts++;
336 	ent->keynum = 0;
337 
338 	memset (ent, 0, sizeof(*ent));
339 
340 	ent->colormap = vid.colormap;
341 	return ent;
342 }
343 
344 
345 /*
346 =================
347 CL_UpdateBeams
348 =================
349 */
CL_UpdateBeams(void)350 void CL_UpdateBeams (void)
351 {
352 	int			i;
353 	beam_t		*b;
354 	vec3_t		dist, org;
355 	float		d;
356 	entity_t	*ent;
357 	float		yaw, pitch;
358 	float		forward;
359 
360 // update lightning
361 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
362 	{
363 		if (!b->model || b->endtime < cl.time)
364 			continue;
365 
366 	// if coming from the player, update the start position
367 		if (b->entity == cl.playernum+1)	// entity 0 is the world
368 		{
369 			VectorCopy (cl.simorg, b->start);
370 //			b->start[2] -= 22;	// adjust for view height
371 		}
372 
373 	// calculate pitch and yaw
374 		VectorSubtract (b->end, b->start, dist);
375 
376 		if (dist[1] == 0 && dist[0] == 0)
377 		{
378 			yaw = 0;
379 			if (dist[2] > 0)
380 				pitch = 90;
381 			else
382 				pitch = 270;
383 		}
384 		else
385 		{
386 			yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
387 			if (yaw < 0)
388 				yaw += 360;
389 
390 			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
391 			pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
392 			if (pitch < 0)
393 				pitch += 360;
394 		}
395 
396 	// add new entities for the lightning
397 		VectorCopy (b->start, org);
398 		d = VectorNormalize(dist);
399 		while (d > 0)
400 		{
401 			ent = CL_NewTempEntity ();
402 			if (!ent)
403 				return;
404 			VectorCopy (org, ent->origin);
405 			ent->model = b->model;
406 			ent->angles[0] = pitch;
407 			ent->angles[1] = yaw;
408 			ent->angles[2] = rand()%360;
409 
410 			for (i=0 ; i<3 ; i++)
411 				org[i] += dist[i]*30;
412 			d -= 30;
413 		}
414 	}
415 
416 }
417 
418 /*
419 =================
420 CL_UpdateExplosions
421 =================
422 */
CL_UpdateExplosions(void)423 void CL_UpdateExplosions (void)
424 {
425 	int			i;
426 	int			f;
427 	explosion_t	*ex;
428 	entity_t	*ent;
429 
430 	for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
431 	{
432 		if (!ex->model)
433 			continue;
434 		f = 10*(cl.time - ex->start);
435 		if (f >= ex->model->numframes)
436 		{
437 			ex->model = NULL;
438 			continue;
439 		}
440 
441 		ent = CL_NewTempEntity ();
442 		if (!ent)
443 			return;
444 		VectorCopy (ex->origin, ent->origin);
445 		ent->model = ex->model;
446 		ent->frame = f;
447 	}
448 }
449 
450 /*
451 =================
452 CL_UpdateTEnts
453 =================
454 */
CL_UpdateTEnts(void)455 void CL_UpdateTEnts (void)
456 {
457 	CL_UpdateBeams ();
458 	CL_UpdateExplosions ();
459 }
460