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 #include "neh.h"
24
25 extern void R_Smoke (vec3_t org, int color);
26 int num_temp_entities;
27 entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
28 beam_t cl_beams[MAX_BEAMS];
29
30 sfx_t *cl_sfx_wizhit;
31 sfx_t *cl_sfx_knighthit;
32 sfx_t *cl_sfx_tink1;
33 sfx_t *cl_sfx_ric1;
34 sfx_t *cl_sfx_ric2;
35 sfx_t *cl_sfx_ric3;
36 sfx_t *cl_sfx_r_exp3;
37
38 /*
39 =================
40 CL_ParseTEnt
41 =================
42 */
CL_InitTEnts(void)43 void CL_InitTEnts (void)
44 {
45 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
46 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
47 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
48 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
49 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
50 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
51 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
52 #ifdef QUAKE2
53 cl_sfx_imp = S_PrecacheSound ("shambler/sattck1.wav");
54 cl_sfx_rail = S_PrecacheSound ("weapons/lstart.wav");
55 #endif
56 }
57
58 /*
59 =================
60 CL_ParseBeam
61 =================
62 */
CL_ParseBeam(model_t * m)63 void CL_ParseBeam (model_t *m)
64 {
65 int ent;
66 vec3_t start, end;
67 beam_t *b;
68 int i;
69
70 ent = MSG_ReadShort ();
71
72 start[0] = MSG_ReadCoord ();
73 start[1] = MSG_ReadCoord ();
74 start[2] = MSG_ReadCoord ();
75
76 end[0] = MSG_ReadCoord ();
77 end[1] = MSG_ReadCoord ();
78 end[2] = MSG_ReadCoord ();
79
80 // override any beam with the same entity
81 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
82 if (b->entity == ent)
83 {
84 b->entity = ent;
85 b->model = m;
86 b->endtime = cl.time + 0.2;
87 VectorCopy (start, b->start);
88 VectorCopy (end, b->end);
89 return;
90 }
91
92 // find a free beam
93 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
94 {
95 if (!b->model || b->endtime < cl.time)
96 {
97 b->entity = ent;
98 b->model = m;
99 b->endtime = cl.time + 0.2;
100 VectorCopy (start, b->start);
101 VectorCopy (end, b->end);
102 return;
103 }
104 }
105 Con_Printf ("beam list overflow (max = %d)\n", MAX_BEAMS);
106 }
107
108 /*
109 =================
110 CL_ParseTEnt
111 =================
112 */
CL_ParseTEnt(void)113 void CL_ParseTEnt (void)
114 {
115 int type;
116 vec3_t pos;
117 vec3_t endpos;
118
119 dlight_t *dl;
120 int rnd;
121 int colorStart, colorLength;
122
123 type = MSG_ReadByte ();
124 switch (type)
125 {
126 case TE_WIZSPIKE: // spike hitting wall
127 pos[0] = MSG_ReadCoord ();
128 pos[1] = MSG_ReadCoord ();
129 pos[2] = MSG_ReadCoord ();
130 R_RunParticleEffect (pos, vec3_origin, 20, 30);
131 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
132 break;
133
134 case TE_KNIGHTSPIKE: // spike hitting wall
135 pos[0] = MSG_ReadCoord ();
136 pos[1] = MSG_ReadCoord ();
137 pos[2] = MSG_ReadCoord ();
138 R_RunParticleEffect (pos, vec3_origin, 226, 20);
139 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
140 break;
141
142 case TE_SPIKE: // spike hitting wall
143 pos[0] = MSG_ReadCoord ();
144 pos[1] = MSG_ReadCoord ();
145 pos[2] = MSG_ReadCoord ();
146
147 // LordHavoc's "Dust" effect
148 R_SparkShower(pos, vec3_origin, 15, 0);
149 // R_RunParticleEffect (pos, vec3_origin, 0, 10);
150
151 if ( rand() % 5 )
152 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
153 else
154 {
155 rnd = rand() & 3;
156 if (rnd == 1)
157 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
158 else if (rnd == 2)
159 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
160 else
161 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
162 }
163 break;
164 case TE_SUPERSPIKE: // super spike hitting wall
165 pos[0] = MSG_ReadCoord ();
166 pos[1] = MSG_ReadCoord ();
167 pos[2] = MSG_ReadCoord ();
168
169 // LordHavoc's "dust" effect
170 R_SparkShower(pos, vec3_origin, 30, 0);
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
192 // LordHavoc's "dust" effect
193 R_SparkShower(pos, vec3_origin, 15, 0);
194 // R_RunParticleEffect (pos, vec3_origin, 0, 20);
195 break;
196
197 case TE_EXPLOSION: // rocket explosion
198 pos[0] = MSG_ReadCoord ();
199 pos[1] = MSG_ReadCoord ();
200 pos[2] = MSG_ReadCoord ();
201 R_ParticleExplosion (pos, gl_rsmoke.value);
202 dl = CL_AllocDlight (0);
203 VectorCopy (pos, dl->origin);
204 dl->radius = 350;
205 dl->die = cl.time + 0.5;
206 dl->decay = 300;
207 dl->color[0] = 0.4; dl->color[1] = 0.2; dl->color[2] = 0.1;
208 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
209 break;
210
211 case TE_TAREXPLOSION: // tarbaby explosion
212 pos[0] = MSG_ReadCoord ();
213 pos[1] = MSG_ReadCoord ();
214 pos[2] = MSG_ReadCoord ();
215 R_BlobExplosion (pos);
216
217 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
218 break;
219
220 case TE_LIGHTNING1: // lightning bolts
221 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
222 break;
223
224 case TE_LIGHTNING2: // lightning bolts
225 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
226 break;
227
228 case TE_LIGHTNING3: // lightning bolts
229 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
230 break;
231
232 case TE_LIGHTNING4: // lightning bolts
233 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
234 break;
235
236 // PGM 01/21/97
237 case TE_BEAM: // grappling hook beam
238 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
239 break;
240 // PGM 01/21/97
241
242 case TE_LAVASPLASH:
243 pos[0] = MSG_ReadCoord ();
244 pos[1] = MSG_ReadCoord ();
245 pos[2] = MSG_ReadCoord ();
246 R_LavaSplash (pos);
247 break;
248
249 case TE_TELEPORT:
250 pos[0] = MSG_ReadCoord ();
251 pos[1] = MSG_ReadCoord ();
252 pos[2] = MSG_ReadCoord ();
253 R_TeleportSplash (pos);
254 break;
255
256 case TE_EXPLOSION2: // color mapped explosion
257 pos[0] = MSG_ReadCoord ();
258 pos[1] = MSG_ReadCoord ();
259 pos[2] = MSG_ReadCoord ();
260 colorStart = MSG_ReadByte ();
261 colorLength = MSG_ReadByte ();
262 R_ParticleExplosion2 (pos, colorStart, colorLength);
263 dl = CL_AllocDlight (0);
264 VectorCopy (pos, dl->origin);
265 dl->radius = 350;
266 dl->die = cl.time + 0.5;
267 dl->decay = 300;
268 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
269 break;
270
271 case TE_SMOKE: // rocket explosion
272 pos[0] = MSG_ReadCoord ();
273 pos[1] = MSG_ReadCoord ();
274 pos[2] = MSG_ReadCoord ();
275 R_Smoke(pos, MSG_ReadByte());
276 case TE_EXPLOSION3: // rocket explosion
277 pos[0] = MSG_ReadCoord ();
278 pos[1] = MSG_ReadCoord ();
279 pos[2] = MSG_ReadCoord ();
280 dl = CL_AllocDlight (0);
281 VectorCopy (pos, dl->origin);
282 dl->radius = 350;
283 dl->die = cl.time + 0.5;
284 dl->decay = 300;
285 dl->color[0] = MSG_ReadCoord();
286 dl->color[1] = MSG_ReadCoord();
287 dl->color[2] = MSG_ReadCoord();
288 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
289 break;
290
291 default:
292 Sys_Error ("CL_ParseTEnt: bad type %d", type);
293 }
294 }
295
296
297 /*
298 =================
299 CL_NewTempEntity
300 =================
301 */
CL_NewTempEntity(void)302 entity_t *CL_NewTempEntity (void)
303 {
304 entity_t *ent;
305 static float lastmsg1 = 0, lastmsg2 = 0;
306
307 if (cl_numvisedicts == MAX_VISEDICTS)
308 {
309 if (IsTimeout (&lastmsg1, 2))
310 Con_DPrintf ("CL_NewTempEntity: too many visedicts (max = %d)\n", MAX_VISEDICTS);
311
312 return NULL;
313 }
314 if (num_temp_entities == MAX_TEMP_ENTITIES)
315 {
316 if (IsTimeout (&lastmsg2, 2))
317 Con_DPrintf ("CL_NewTempEntity: too many temp_entities (max = %d)\n", MAX_TEMP_ENTITIES);
318
319 return NULL;
320 }
321 ent = &cl_temp_entities[num_temp_entities];
322 memset (ent, 0, sizeof(*ent));
323 num_temp_entities++;
324 cl_visedicts[cl_numvisedicts] = ent;
325 cl_numvisedicts++;
326
327 ent->colormap = vid.colormap;
328 return ent;
329 }
330
331
332 /*
333 =================
334 CL_UpdateTEnts
335 =================
336 */
CL_UpdateTEnts(void)337 void CL_UpdateTEnts (void)
338 {
339 int i, j;
340 beam_t *b;
341 vec3_t dist, org;
342 float d;
343 entity_t *ent;
344 float yaw, pitch;
345 float forward;
346
347 if (SV_IsPaused ())
348 return; // No beams when game paused
349
350 num_temp_entities = 0;
351
352 // update lightning
353 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
354 {
355 if (!b->model || b->endtime < cl.time)
356 continue;
357
358 // if coming from the player, update the start position
359 if (b->entity == cl.viewentity)
360 {
361 VectorCopy (cl_entities[cl.viewentity].origin, b->start);
362 }
363
364 // calculate pitch and yaw
365 VectorSubtract (b->end, b->start, dist);
366
367 if (dist[1] == 0 && dist[0] == 0)
368 {
369 yaw = 0;
370 if (dist[2] > 0)
371 pitch = 90;
372 else
373 pitch = 270;
374 }
375 else
376 {
377 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
378 if (yaw < 0)
379 yaw += 360;
380
381 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
382 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
383 if (pitch < 0)
384 pitch += 360;
385 }
386
387 // add new entities for the lightning
388 VectorCopy (b->start, org);
389 d = VectorNormalize(dist);
390 while (d > 0)
391 {
392 ent = CL_NewTempEntity ();
393 if (!ent)
394 return;
395 VectorCopy (org, ent->origin);
396 ent->fullbright = 1;
397 ent->model = b->model;
398 ent->angles[0] = pitch;
399 ent->angles[1] = yaw;
400 ent->angles[2] = rand()%360;
401
402 for (j=0 ; j<3 ; j++)
403 org[j] += dist[j]*30;
404 d -= 30;
405 }
406 }
407
408 }
409
410
411