Home | History | Annotate | Download | only in client
      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 */
     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 */
     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 */
     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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    455 void CL_UpdateTEnts (void)
    456 {
    457 	CL_UpdateBeams ();
    458 	CL_UpdateExplosions ();
    459 }
    460