1 /*
2 * cl_effect.c -- Client side effects.
3 * $Id: cl_effect.c 5843 2017-04-07 14:55:31Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 1997-1998 Raven Software Corp.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 // HEADER FILES ------------------------------------------------------------
25
26 #include "quakedef.h"
27
28 // MACROS ------------------------------------------------------------------
29
30 // TYPES -------------------------------------------------------------------
31
32 #define MAX_EFFECT_ENTITIES 256
33
34 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
35
36 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
37
38 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
39
40 static int NewEffectEntity (void);
41 static void FreeEffectEntity (int idx);
42
43 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
44
45 // PUBLIC DATA DEFINITIONS -------------------------------------------------
46
47 // PRIVATE DATA DEFINITIONS ------------------------------------------------
48
49 static entity_t EffectEntities[MAX_EFFECT_ENTITIES];
50 static qboolean EntityUsed[MAX_EFFECT_ENTITIES];
51 static int EffectEntityCount;
52
53 // CODE --------------------------------------------------------------------
54
55
56 //==========================================================================
57 //
58 // CL_InitTEnts
59 //
60 //==========================================================================
61
CL_InitEffects(void)62 void CL_InitEffects (void)
63 {
64 }
65
CL_ClearEffects(void)66 void CL_ClearEffects (void)
67 {
68 memset(cl.Effects, 0, sizeof(cl.Effects));
69 memset(EntityUsed, 0, sizeof(EntityUsed));
70 EffectEntityCount = 0;
71 }
72
CL_FreeEffect(int idx)73 static void CL_FreeEffect (int idx)
74 {
75 int i;
76
77 switch (cl.Effects[idx].type)
78 {
79 case CE_RAIN:
80 break;
81
82 case CE_SNOW:
83 break;
84
85 case CE_FOUNTAIN:
86 break;
87
88 case CE_QUAKE:
89 break;
90
91 case CE_WHITE_SMOKE:
92 case CE_GREEN_SMOKE:
93 case CE_GREY_SMOKE:
94 case CE_RED_SMOKE:
95 case CE_SLOW_WHITE_SMOKE:
96 case CE_TELESMK1:
97 case CE_TELESMK2:
98 case CE_GHOST:
99 case CE_REDCLOUD:
100 case CE_ACID_MUZZFL:
101 case CE_FLAMESTREAM:
102 case CE_FLAMEWALL:
103 case CE_FLAMEWALL2:
104 case CE_ONFIRE:
105 FreeEffectEntity(cl.Effects[idx].ef.Smoke.entity_index);
106 break;
107
108 /* Just go through animation and then remove */
109 case CE_SM_WHITE_FLASH:
110 case CE_YELLOWRED_FLASH:
111 case CE_BLUESPARK:
112 case CE_YELLOWSPARK:
113 case CE_SM_CIRCLE_EXP:
114 case CE_BG_CIRCLE_EXP:
115 case CE_SM_EXPLOSION:
116 case CE_LG_EXPLOSION:
117 case CE_FLOOR_EXPLOSION:
118 case CE_FLOOR_EXPLOSION3:
119 case CE_BLUE_EXPLOSION:
120 case CE_REDSPARK:
121 case CE_GREENSPARK:
122 case CE_ICEHIT:
123 case CE_MEDUSA_HIT:
124 case CE_MEZZO_REFLECT:
125 case CE_FLOOR_EXPLOSION2:
126 case CE_XBOW_EXPLOSION:
127 case CE_NEW_EXPLOSION:
128 case CE_MAGIC_MISSILE_EXPLOSION:
129 case CE_BONE_EXPLOSION:
130 case CE_BLDRN_EXPL:
131 case CE_BRN_BOUNCE:
132 case CE_LSHOCK:
133 case CE_ACID_HIT:
134 case CE_ACID_SPLAT:
135 case CE_ACID_EXPL:
136 case CE_LBALL_EXPL:
137 case CE_FBOOM:
138 case CE_BOMB:
139 case CE_FIREWALL_SMALL:
140 case CE_FIREWALL_MEDIUM:
141 case CE_FIREWALL_LARGE:
142 FreeEffectEntity(cl.Effects[idx].ef.Smoke.entity_index);
143 break;
144
145 /* Go forward then backward through animation then remove */
146 case CE_WHITE_FLASH:
147 case CE_BLUE_FLASH:
148 case CE_SM_BLUE_FLASH:
149 case CE_RED_FLASH:
150 FreeEffectEntity(cl.Effects[idx].ef.Flash.entity_index);
151 break;
152
153 case CE_RIDER_DEATH:
154 break;
155
156 case CE_GRAVITYWELL:
157 break;
158
159 case CE_TELEPORTERPUFFS:
160 for (i = 0 ; i < 8 ; ++i)
161 FreeEffectEntity(cl.Effects[idx].ef.Teleporter.entity_index[i]);
162 break;
163
164 case CE_TELEPORTERBODY:
165 FreeEffectEntity(cl.Effects[idx].ef.Teleporter.entity_index[0]);
166 break;
167
168 case CE_BONESHARD:
169 case CE_BONESHRAPNEL:
170 FreeEffectEntity(cl.Effects[idx].ef.Missile.entity_index);
171 break;
172
173 case CE_CHUNK:
174 // Con_Printf("Freeing a chunk here\n");
175 for (i = 0 ; i < cl.Effects[idx].ef.Chunk.numChunks ; i++)
176 {
177 if (cl.Effects[idx].ef.Chunk.entity_index[i] != -1)
178 FreeEffectEntity(cl.Effects[idx].ef.Chunk.entity_index[i]);
179 }
180 break;
181 }
182
183 memset(&cl.Effects[idx], 0, sizeof(struct EffectT));
184 }
185
186 //==========================================================================
187 //
188 // CL_ParseEffect
189 //
190 //==========================================================================
191
192 // All changes need to be in SV_SendEffect(), SV_ParseEffect(),
193 // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect()
CL_ParseEffect(void)194 void CL_ParseEffect (void)
195 {
196 int i, idx;
197 qboolean ImmediateFree;
198 entity_t *ent;
199 int dir;
200 float angleval, sinval, cosval;
201 float skinnum;
202 float final;
203
204 ImmediateFree = false;
205
206 idx = MSG_ReadByte();
207 if (cl.Effects[idx].type)
208 CL_FreeEffect(idx);
209
210 memset(&cl.Effects[idx], 0, sizeof(struct EffectT));
211
212 cl.Effects[idx].type = MSG_ReadByte();
213
214 switch (cl.Effects[idx].type)
215 {
216 case CE_RAIN:
217 cl.Effects[idx].ef.Rain.min_org[0] = MSG_ReadCoord();
218 cl.Effects[idx].ef.Rain.min_org[1] = MSG_ReadCoord();
219 cl.Effects[idx].ef.Rain.min_org[2] = MSG_ReadCoord();
220 cl.Effects[idx].ef.Rain.max_org[0] = MSG_ReadCoord();
221 cl.Effects[idx].ef.Rain.max_org[1] = MSG_ReadCoord();
222 cl.Effects[idx].ef.Rain.max_org[2] = MSG_ReadCoord();
223 cl.Effects[idx].ef.Rain.e_size[0] = MSG_ReadCoord();
224 cl.Effects[idx].ef.Rain.e_size[1] = MSG_ReadCoord();
225 cl.Effects[idx].ef.Rain.e_size[2] = MSG_ReadCoord();
226 cl.Effects[idx].ef.Rain.dir[0] = MSG_ReadCoord();
227 cl.Effects[idx].ef.Rain.dir[1] = MSG_ReadCoord();
228 cl.Effects[idx].ef.Rain.dir[2] = MSG_ReadCoord();
229 cl.Effects[idx].ef.Rain.color = MSG_ReadShort();
230 cl.Effects[idx].ef.Rain.count = MSG_ReadShort();
231 cl.Effects[idx].ef.Rain.wait = MSG_ReadFloat();
232 break;
233
234 case CE_SNOW:
235 cl.Effects[idx].ef.Rain.min_org[0] = MSG_ReadCoord();
236 cl.Effects[idx].ef.Rain.min_org[1] = MSG_ReadCoord();
237 cl.Effects[idx].ef.Rain.min_org[2] = MSG_ReadCoord();
238 cl.Effects[idx].ef.Rain.max_org[0] = MSG_ReadCoord();
239 cl.Effects[idx].ef.Rain.max_org[1] = MSG_ReadCoord();
240 cl.Effects[idx].ef.Rain.max_org[2] = MSG_ReadCoord();
241 cl.Effects[idx].ef.Rain.flags = MSG_ReadByte();
242 cl.Effects[idx].ef.Rain.dir[0] = MSG_ReadCoord();
243 cl.Effects[idx].ef.Rain.dir[1] = MSG_ReadCoord();
244 cl.Effects[idx].ef.Rain.dir[2] = MSG_ReadCoord();
245 cl.Effects[idx].ef.Rain.count = MSG_ReadByte();
246 //cl.Effects[idx].ef.Rain.veer = MSG_ReadShort();
247 break;
248
249 case CE_FOUNTAIN:
250 cl.Effects[idx].ef.Fountain.pos[0] = MSG_ReadCoord ();
251 cl.Effects[idx].ef.Fountain.pos[1] = MSG_ReadCoord ();
252 cl.Effects[idx].ef.Fountain.pos[2] = MSG_ReadCoord ();
253 cl.Effects[idx].ef.Fountain.angle[0] = MSG_ReadAngle ();
254 cl.Effects[idx].ef.Fountain.angle[1] = MSG_ReadAngle ();
255 cl.Effects[idx].ef.Fountain.angle[2] = MSG_ReadAngle ();
256 cl.Effects[idx].ef.Fountain.movedir[0] = MSG_ReadCoord ();
257 cl.Effects[idx].ef.Fountain.movedir[1] = MSG_ReadCoord ();
258 cl.Effects[idx].ef.Fountain.movedir[2] = MSG_ReadCoord ();
259 cl.Effects[idx].ef.Fountain.color = MSG_ReadShort ();
260 cl.Effects[idx].ef.Fountain.cnt = MSG_ReadByte ();
261 AngleVectors (cl.Effects[idx].ef.Fountain.angle,
262 cl.Effects[idx].ef.Fountain.vforward,
263 cl.Effects[idx].ef.Fountain.vright,
264 cl.Effects[idx].ef.Fountain.vup);
265 break;
266
267 case CE_QUAKE:
268 cl.Effects[idx].ef.Quake.origin[0] = MSG_ReadCoord ();
269 cl.Effects[idx].ef.Quake.origin[1] = MSG_ReadCoord ();
270 cl.Effects[idx].ef.Quake.origin[2] = MSG_ReadCoord ();
271 cl.Effects[idx].ef.Quake.radius = MSG_ReadFloat ();
272 break;
273
274 case CE_WHITE_SMOKE:
275 case CE_GREEN_SMOKE:
276 case CE_GREY_SMOKE:
277 case CE_RED_SMOKE:
278 case CE_SLOW_WHITE_SMOKE:
279 case CE_TELESMK1:
280 case CE_TELESMK2:
281 case CE_GHOST:
282 case CE_REDCLOUD:
283 case CE_ACID_MUZZFL:
284 case CE_FLAMESTREAM:
285 case CE_FLAMEWALL:
286 case CE_FLAMEWALL2:
287 case CE_ONFIRE:
288 cl.Effects[idx].ef.Smoke.origin[0] = MSG_ReadCoord ();
289 cl.Effects[idx].ef.Smoke.origin[1] = MSG_ReadCoord ();
290 cl.Effects[idx].ef.Smoke.origin[2] = MSG_ReadCoord ();
291
292 cl.Effects[idx].ef.Smoke.velocity[0] = MSG_ReadFloat ();
293 cl.Effects[idx].ef.Smoke.velocity[1] = MSG_ReadFloat ();
294 cl.Effects[idx].ef.Smoke.velocity[2] = MSG_ReadFloat ();
295
296 cl.Effects[idx].ef.Smoke.framelength = MSG_ReadFloat ();
297 /* smoke frame is a mission pack thing only. */
298 if (cl_protocol > PROTOCOL_RAVEN_111)
299 cl.Effects[idx].ef.Smoke.frame = MSG_ReadFloat ();
300
301 if ((cl.Effects[idx].ef.Smoke.entity_index = NewEffectEntity()) != -1)
302 {
303 ent = &EffectEntities[cl.Effects[idx].ef.Smoke.entity_index];
304 VectorCopy(cl.Effects[idx].ef.Smoke.origin, ent->origin);
305
306 if ((cl.Effects[idx].type == CE_WHITE_SMOKE) ||
307 (cl.Effects[idx].type == CE_SLOW_WHITE_SMOKE))
308 ent->model = Mod_ForName("models/whtsmk1.spr", true);
309 else if (cl.Effects[idx].type == CE_GREEN_SMOKE)
310 ent->model = Mod_ForName("models/grnsmk1.spr", true);
311 else if (cl.Effects[idx].type == CE_GREY_SMOKE)
312 ent->model = Mod_ForName("models/grysmk1.spr", true);
313 else if (cl.Effects[idx].type == CE_RED_SMOKE)
314 ent->model = Mod_ForName("models/redsmk1.spr", true);
315 else if (cl.Effects[idx].type == CE_TELESMK1)
316 ent->model = Mod_ForName("models/telesmk1.spr", true);
317 else if (cl.Effects[idx].type == CE_TELESMK2)
318 ent->model = Mod_ForName("models/telesmk2.spr", true);
319 else if (cl.Effects[idx].type == CE_REDCLOUD)
320 ent->model = Mod_ForName("models/rcloud.spr", true);
321 else if (cl.Effects[idx].type == CE_FLAMESTREAM)
322 ent->model = Mod_ForName("models/flamestr.spr", true);
323 else if (cl.Effects[idx].type == CE_ACID_MUZZFL)
324 {
325 ent->model = Mod_ForName("models/muzzle1.spr", true);
326 ent->drawflags = DRF_TRANSLUCENT | MLS_ABSLIGHT;
327 ent->abslight = 51;
328 }
329 else if (cl.Effects[idx].type == CE_FLAMEWALL)
330 ent->model = Mod_ForName("models/firewal1.spr", true);
331 else if (cl.Effects[idx].type == CE_FLAMEWALL2)
332 ent->model = Mod_ForName("models/firewal2.spr", true);
333 else if (cl.Effects[idx].type == CE_ONFIRE)
334 {
335 float rdm = rand() & 3;
336
337 if (rdm < 1)
338 ent->model = Mod_ForName("models/firewal1.spr", true);
339 else if (rdm < 2)
340 ent->model = Mod_ForName("models/firewal2.spr", true);
341 else
342 ent->model = Mod_ForName("models/firewal3.spr", true);
343
344 ent->drawflags = DRF_TRANSLUCENT;
345 ent->abslight = 255;
346 ent->frame = cl.Effects[idx].ef.Smoke.frame;
347 }
348
349 if (cl.Effects[idx].type != CE_REDCLOUD &&
350 cl.Effects[idx].type != CE_ACID_MUZZFL &&
351 cl.Effects[idx].type != CE_FLAMEWALL)
352 ent->drawflags = DRF_TRANSLUCENT;
353
354 if (cl.Effects[idx].type == CE_FLAMESTREAM)
355 {
356 ent->drawflags = DRF_TRANSLUCENT | MLS_ABSLIGHT;
357 ent->abslight = 255;
358 ent->frame = cl.Effects[idx].ef.Smoke.frame;
359 }
360
361 if (cl.Effects[idx].type == CE_GHOST)
362 {
363 ent->model = Mod_ForName("models/ghost.spr", true);
364 ent->drawflags = DRF_TRANSLUCENT | MLS_ABSLIGHT;
365 ent->abslight = 127;
366 }
367 }
368 else
369 ImmediateFree = true;
370 break;
371
372 case CE_SM_WHITE_FLASH:
373 case CE_YELLOWRED_FLASH:
374 case CE_BLUESPARK:
375 case CE_YELLOWSPARK:
376 case CE_SM_CIRCLE_EXP:
377 case CE_BG_CIRCLE_EXP:
378 case CE_SM_EXPLOSION:
379 case CE_LG_EXPLOSION:
380 case CE_FLOOR_EXPLOSION:
381 case CE_FLOOR_EXPLOSION3:
382 case CE_BLUE_EXPLOSION:
383 case CE_REDSPARK:
384 case CE_GREENSPARK:
385 case CE_ICEHIT:
386 case CE_MEDUSA_HIT:
387 case CE_MEZZO_REFLECT:
388 case CE_FLOOR_EXPLOSION2:
389 case CE_XBOW_EXPLOSION:
390 case CE_NEW_EXPLOSION:
391 case CE_MAGIC_MISSILE_EXPLOSION:
392 case CE_BONE_EXPLOSION:
393 case CE_BLDRN_EXPL:
394 case CE_BRN_BOUNCE:
395 case CE_LSHOCK:
396 case CE_ACID_HIT:
397 case CE_ACID_SPLAT:
398 case CE_ACID_EXPL:
399 case CE_LBALL_EXPL:
400 case CE_FBOOM:
401 case CE_BOMB:
402 case CE_FIREWALL_SMALL:
403 case CE_FIREWALL_MEDIUM:
404 case CE_FIREWALL_LARGE:
405 cl.Effects[idx].ef.Smoke.origin[0] = MSG_ReadCoord ();
406 cl.Effects[idx].ef.Smoke.origin[1] = MSG_ReadCoord ();
407 cl.Effects[idx].ef.Smoke.origin[2] = MSG_ReadCoord ();
408 if ((cl.Effects[idx].ef.Smoke.entity_index = NewEffectEntity()) != -1)
409 {
410 ent = &EffectEntities[cl.Effects[idx].ef.Smoke.entity_index];
411 VectorCopy(cl.Effects[idx].ef.Smoke.origin, ent->origin);
412
413 if (cl.Effects[idx].type == CE_BLUESPARK)
414 ent->model = Mod_ForName("models/bspark.spr", true);
415 else if (cl.Effects[idx].type == CE_YELLOWSPARK)
416 ent->model = Mod_ForName("models/spark.spr", true);
417 else if (cl.Effects[idx].type == CE_SM_CIRCLE_EXP)
418 ent->model = Mod_ForName("models/fcircle.spr", true);
419 else if (cl.Effects[idx].type == CE_BG_CIRCLE_EXP)
420 ent->model = Mod_ForName("models/xplod29.spr", true);
421 else if (cl.Effects[idx].type == CE_SM_WHITE_FLASH)
422 ent->model = Mod_ForName("models/sm_white.spr", true);
423 else if (cl.Effects[idx].type == CE_YELLOWRED_FLASH)
424 {
425 ent->model = Mod_ForName("models/yr_flsh.spr", true);
426 ent->drawflags = DRF_TRANSLUCENT;
427 }
428 else if (cl.Effects[idx].type == CE_SM_EXPLOSION)
429 ent->model = Mod_ForName("models/sm_expld.spr", true);
430 else if (cl.Effects[idx].type == CE_LG_EXPLOSION)
431 ent->model = Mod_ForName("models/bg_expld.spr", true);
432 else if (cl.Effects[idx].type == CE_FLOOR_EXPLOSION)
433 ent->model = Mod_ForName("models/fl_expld.spr", true);
434 else if (cl.Effects[idx].type == CE_FLOOR_EXPLOSION3)
435 ent->model = Mod_ForName("models/biggy.spr", true);
436 else if (cl.Effects[idx].type == CE_BLUE_EXPLOSION)
437 ent->model = Mod_ForName("models/xpspblue.spr", true);
438 else if (cl.Effects[idx].type == CE_REDSPARK)
439 ent->model = Mod_ForName("models/rspark.spr", true);
440 else if (cl.Effects[idx].type == CE_GREENSPARK)
441 ent->model = Mod_ForName("models/gspark.spr", true);
442 else if (cl.Effects[idx].type == CE_ICEHIT)
443 ent->model = Mod_ForName("models/icehit.spr", true);
444 else if (cl.Effects[idx].type == CE_MEDUSA_HIT)
445 ent->model = Mod_ForName("models/medhit.spr", true);
446 else if (cl.Effects[idx].type == CE_MEZZO_REFLECT)
447 ent->model = Mod_ForName("models/mezzoref.spr", true);
448 else if (cl.Effects[idx].type == CE_FLOOR_EXPLOSION2)
449 ent->model = Mod_ForName("models/flrexpl2.spr", true);
450 else if (cl.Effects[idx].type == CE_XBOW_EXPLOSION)
451 ent->model = Mod_ForName("models/xbowexpl.spr", true);
452 else if (cl.Effects[idx].type == CE_NEW_EXPLOSION)
453 ent->model = Mod_ForName("models/gen_expl.spr", true);
454 else if (cl.Effects[idx].type == CE_MAGIC_MISSILE_EXPLOSION)
455 ent->model = Mod_ForName("models/mm_expld.spr", true);
456 else if (cl.Effects[idx].type == CE_BONE_EXPLOSION)
457 ent->model = Mod_ForName("models/bonexpld.spr", true);
458 else if (cl.Effects[idx].type == CE_BLDRN_EXPL)
459 ent->model = Mod_ForName("models/xplsn_1.spr", true);
460 else if (cl.Effects[idx].type == CE_ACID_HIT)
461 ent->model = Mod_ForName("models/axplsn_2.spr", true);
462 else if (cl.Effects[idx].type == CE_ACID_SPLAT)
463 ent->model = Mod_ForName("models/axplsn_1.spr", true);
464 else if (cl.Effects[idx].type == CE_ACID_EXPL)
465 {
466 ent->model = Mod_ForName("models/axplsn_5.spr", true);
467 ent->drawflags = MLS_ABSLIGHT;
468 ent->abslight = 255;
469 }
470 else if (cl.Effects[idx].type == CE_FBOOM)
471 ent->model = Mod_ForName("models/fboom.spr", true);
472 else if (cl.Effects[idx].type == CE_BOMB)
473 ent->model = Mod_ForName("models/pow.spr", true);
474 else if (cl.Effects[idx].type == CE_LBALL_EXPL)
475 ent->model = Mod_ForName("models/Bluexp3.spr", true);
476 else if (cl.Effects[idx].type == CE_FIREWALL_SMALL)
477 ent->model = Mod_ForName("models/firewal1.spr", true);
478 else if (cl.Effects[idx].type == CE_FIREWALL_MEDIUM)
479 ent->model = Mod_ForName("models/firewal5.spr", true);
480 else if (cl.Effects[idx].type == CE_FIREWALL_LARGE)
481 ent->model = Mod_ForName("models/firewal4.spr", true);
482 else if (cl.Effects[idx].type == CE_BRN_BOUNCE)
483 ent->model = Mod_ForName("models/spark.spr", true);
484 else if (cl.Effects[idx].type == CE_LSHOCK)
485 {
486 ent->model = Mod_ForName("models/vorpshok.mdl", true);
487 ent->drawflags = MLS_TORCH;
488 ent->angles[2] = 90;
489 ent->scale = 255;
490 }
491 }
492 else
493 {
494 ImmediateFree = true;
495 }
496 break;
497
498 case CE_WHITE_FLASH:
499 case CE_BLUE_FLASH:
500 case CE_SM_BLUE_FLASH:
501 case CE_RED_FLASH:
502 cl.Effects[idx].ef.Flash.origin[0] = MSG_ReadCoord ();
503 cl.Effects[idx].ef.Flash.origin[1] = MSG_ReadCoord ();
504 cl.Effects[idx].ef.Flash.origin[2] = MSG_ReadCoord ();
505 cl.Effects[idx].ef.Flash.reverse = 0;
506 if ((cl.Effects[idx].ef.Flash.entity_index = NewEffectEntity()) != -1)
507 {
508 ent = &EffectEntities[cl.Effects[idx].ef.Flash.entity_index];
509 VectorCopy(cl.Effects[idx].ef.Flash.origin, ent->origin);
510
511 if (cl.Effects[idx].type == CE_WHITE_FLASH)
512 ent->model = Mod_ForName("models/gryspt.spr", true);
513 else if (cl.Effects[idx].type == CE_BLUE_FLASH)
514 ent->model = Mod_ForName("models/bluflash.spr", true);
515 else if (cl.Effects[idx].type == CE_SM_BLUE_FLASH)
516 ent->model = Mod_ForName("models/sm_blue.spr", true);
517 else if (cl.Effects[idx].type == CE_RED_FLASH)
518 ent->model = Mod_ForName("models/redspt.spr", true);
519
520 ent->drawflags = DRF_TRANSLUCENT;
521 }
522 else
523 {
524 ImmediateFree = true;
525 }
526 break;
527
528 case CE_RIDER_DEATH:
529 cl.Effects[idx].ef.RD.origin[0] = MSG_ReadCoord ();
530 cl.Effects[idx].ef.RD.origin[1] = MSG_ReadCoord ();
531 cl.Effects[idx].ef.RD.origin[2] = MSG_ReadCoord ();
532 break;
533
534 case CE_GRAVITYWELL:
535 cl.Effects[idx].ef.RD.origin[0] = MSG_ReadCoord ();
536 cl.Effects[idx].ef.RD.origin[1] = MSG_ReadCoord ();
537 cl.Effects[idx].ef.RD.origin[2] = MSG_ReadCoord ();
538 cl.Effects[idx].ef.RD.color = MSG_ReadShort ();
539 cl.Effects[idx].ef.RD.lifetime = MSG_ReadFloat ();
540 break;
541
542 case CE_TELEPORTERPUFFS:
543 cl.Effects[idx].ef.Teleporter.origin[0] = MSG_ReadCoord ();
544 cl.Effects[idx].ef.Teleporter.origin[1] = MSG_ReadCoord ();
545 cl.Effects[idx].ef.Teleporter.origin[2] = MSG_ReadCoord ();
546
547 cl.Effects[idx].ef.Teleporter.framelength = .05;
548 dir = 0;
549 for (i = 0 ; i < 8 ; ++i)
550 {
551 if ((cl.Effects[idx].ef.Teleporter.entity_index[i] = NewEffectEntity()) != -1)
552 {
553 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[i]];
554 VectorCopy(cl.Effects[idx].ef.Teleporter.origin, ent->origin);
555
556 angleval = dir * M_PI*2 / 360;
557
558 sinval = sin(angleval);
559 cosval = cos(angleval);
560
561 cl.Effects[idx].ef.Teleporter.velocity[i][0] = 10*cosval;
562 cl.Effects[idx].ef.Teleporter.velocity[i][1] = 10*sinval;
563 cl.Effects[idx].ef.Teleporter.velocity[i][2] = 0;
564 dir += 45;
565
566 ent->model = Mod_ForName("models/telesmk2.spr", true);
567 ent->drawflags = DRF_TRANSLUCENT;
568 }
569 }
570 break;
571
572 case CE_TELEPORTERBODY:
573 cl.Effects[idx].ef.Teleporter.origin[0] = MSG_ReadCoord ();
574 cl.Effects[idx].ef.Teleporter.origin[1] = MSG_ReadCoord ();
575 cl.Effects[idx].ef.Teleporter.origin[2] = MSG_ReadCoord ();
576
577 cl.Effects[idx].ef.Teleporter.velocity[0][0] = MSG_ReadFloat ();
578 cl.Effects[idx].ef.Teleporter.velocity[0][1] = MSG_ReadFloat ();
579 cl.Effects[idx].ef.Teleporter.velocity[0][2] = MSG_ReadFloat ();
580
581 skinnum = MSG_ReadFloat ();
582
583 cl.Effects[idx].ef.Teleporter.framelength = .05;
584 dir = 0;
585 if ((cl.Effects[idx].ef.Teleporter.entity_index[0] = NewEffectEntity()) != -1)
586 {
587 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[0]];
588 VectorCopy(cl.Effects[idx].ef.Teleporter.origin, ent->origin);
589
590 ent->model = Mod_ForName("models/teleport.mdl", true);
591 ent->drawflags = SCALE_TYPE_XYONLY | DRF_TRANSLUCENT;
592 ent->scale = 100;
593 ent->skinnum = skinnum;
594 }
595 break;
596
597 case CE_BONESHARD:
598 case CE_BONESHRAPNEL:
599 cl.Effects[idx].ef.Missile.origin[0] = MSG_ReadCoord ();
600 cl.Effects[idx].ef.Missile.origin[1] = MSG_ReadCoord ();
601 cl.Effects[idx].ef.Missile.origin[2] = MSG_ReadCoord ();
602
603 cl.Effects[idx].ef.Missile.velocity[0] = MSG_ReadFloat ();
604 cl.Effects[idx].ef.Missile.velocity[1] = MSG_ReadFloat ();
605 cl.Effects[idx].ef.Missile.velocity[2] = MSG_ReadFloat ();
606
607 cl.Effects[idx].ef.Missile.angle[0] = MSG_ReadFloat ();
608 cl.Effects[idx].ef.Missile.angle[1] = MSG_ReadFloat ();
609 cl.Effects[idx].ef.Missile.angle[2] = MSG_ReadFloat ();
610
611 cl.Effects[idx].ef.Missile.avelocity[0] = MSG_ReadFloat ();
612 cl.Effects[idx].ef.Missile.avelocity[1] = MSG_ReadFloat ();
613 cl.Effects[idx].ef.Missile.avelocity[2] = MSG_ReadFloat ();
614
615 if ((cl.Effects[idx].ef.Missile.entity_index = NewEffectEntity()) != -1)
616 {
617 ent = &EffectEntities[cl.Effects[idx].ef.Missile.entity_index];
618 VectorCopy(cl.Effects[idx].ef.Missile.origin, ent->origin);
619 if (cl.Effects[idx].type == CE_BONESHARD)
620 ent->model = Mod_ForName("models/boneshot.mdl", true);
621 else if (cl.Effects[idx].type == CE_BONESHRAPNEL)
622 ent->model = Mod_ForName("models/boneshrd.mdl", true);
623 }
624 else
625 ImmediateFree = true;
626 break;
627
628 case CE_CHUNK:
629 cl.Effects[idx].ef.Chunk.origin[0] = MSG_ReadCoord ();
630 cl.Effects[idx].ef.Chunk.origin[1] = MSG_ReadCoord ();
631 cl.Effects[idx].ef.Chunk.origin[2] = MSG_ReadCoord ();
632
633 cl.Effects[idx].ef.Chunk.type = MSG_ReadByte ();
634
635 cl.Effects[idx].ef.Chunk.srcVel[0] = MSG_ReadCoord ();
636 cl.Effects[idx].ef.Chunk.srcVel[1] = MSG_ReadCoord ();
637 cl.Effects[idx].ef.Chunk.srcVel[2] = MSG_ReadCoord ();
638
639 cl.Effects[idx].ef.Chunk.numChunks = MSG_ReadByte ();
640
641 cl.Effects[idx].ef.Chunk.time_amount = 4.0;
642
643 cl.Effects[idx].ef.Chunk.aveScale =
644 30 + 100 * (cl.Effects[idx].ef.Chunk.numChunks / 40.0);
645
646 if (cl.Effects[idx].ef.Chunk.numChunks > 16)
647 cl.Effects[idx].ef.Chunk.numChunks = 16;
648
649 for (i = 0 ; i < cl.Effects[idx].ef.Chunk.numChunks ; i++)
650 {
651 if ((cl.Effects[idx].ef.Chunk.entity_index[i] = NewEffectEntity()) != -1)
652 {
653 ent = &EffectEntities[cl.Effects[idx].ef.Chunk.entity_index[i]];
654 VectorCopy(cl.Effects[idx].ef.Chunk.origin, ent->origin);
655
656 VectorCopy(cl.Effects[idx].ef.Chunk.srcVel,
657 cl.Effects[idx].ef.Chunk.velocity[i]);
658 VectorScale(cl.Effects[idx].ef.Chunk.velocity[i],
659 .80 + ((rand() % 4) / 10.0),
660 cl.Effects[idx].ef.Chunk.velocity[i]);
661 /* temp modify them... */
662 cl.Effects[idx].ef.Chunk.velocity[i][0] += (rand() % 140) - 70;
663 cl.Effects[idx].ef.Chunk.velocity[i][1] += (rand() % 140) - 70;
664 cl.Effects[idx].ef.Chunk.velocity[i][2] += (rand() % 140) - 70;
665
666 /* are these in degrees or radians? */
667 ent->angles[0] = rand() % 360;
668 ent->angles[1] = rand() % 360;
669 ent->angles[2] = rand() % 360;
670
671 ent->scale = cl.Effects[idx].ef.Chunk.aveScale + (rand() % 40);
672
673 /* make this overcomplicated */
674 final = (rand() % 100) * .01;
675 if ((cl.Effects[idx].ef.Chunk.type == THINGTYPE_GLASS) ||
676 (cl.Effects[idx].ef.Chunk.type == THINGTYPE_REDGLASS) ||
677 (cl.Effects[idx].ef.Chunk.type == THINGTYPE_CLEARGLASS) ||
678 (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WEBS))
679 {
680 if (final < 0.20)
681 ent->model = Mod_ForName ("models/shard1.mdl", true);
682 else if (final < 0.40)
683 ent->model = Mod_ForName ("models/shard2.mdl", true);
684 else if (final < 0.60)
685 ent->model = Mod_ForName ("models/shard3.mdl", true);
686 else if (final < 0.80)
687 ent->model = Mod_ForName ("models/shard4.mdl", true);
688 else
689 ent->model = Mod_ForName ("models/shard5.mdl", true);
690
691 if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_CLEARGLASS)
692 {
693 ent->skinnum = 1;
694 ent->drawflags |= DRF_TRANSLUCENT;
695 }
696 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_REDGLASS)
697 {
698 ent->skinnum = 2;
699 }
700 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WEBS)
701 {
702 ent->skinnum = 3;
703 ent->drawflags |= DRF_TRANSLUCENT;
704 }
705 }
706 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WOOD)
707 {
708 if (final < 0.25)
709 ent->model = Mod_ForName ("models/splnter1.mdl", true);
710 else if (final < 0.50)
711 ent->model = Mod_ForName ("models/splnter2.mdl", true);
712 else if (final < 0.75)
713 ent->model = Mod_ForName ("models/splnter3.mdl", true);
714 else
715 ent->model = Mod_ForName ("models/splnter4.mdl", true);
716 }
717 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_METAL)
718 {
719 if (final < 0.25)
720 ent->model = Mod_ForName ("models/metlchk1.mdl", true);
721 else if (final < 0.50)
722 ent->model = Mod_ForName ("models/metlchk2.mdl", true);
723 else if (final < 0.75)
724 ent->model = Mod_ForName ("models/metlchk3.mdl", true);
725 else
726 ent->model = Mod_ForName ("models/metlchk4.mdl", true);
727 }
728 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_FLESH)
729 {
730 if (final < 0.33)
731 ent->model = Mod_ForName ("models/flesh1.mdl", true);
732 else if (final < 0.66)
733 ent->model = Mod_ForName ("models/flesh2.mdl", true);
734 else
735 ent->model = Mod_ForName ("models/flesh3.mdl", true);
736 }
737 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_BROWNSTONE)
738 {
739 if (final < 0.25)
740 ent->model = Mod_ForName ("models/schunk1.mdl", true);
741 else if (final < 0.50)
742 ent->model = Mod_ForName ("models/schunk2.mdl", true);
743 else if (final < 0.75)
744 ent->model = Mod_ForName ("models/schunk3.mdl", true);
745 else
746 ent->model = Mod_ForName ("models/schunk4.mdl", true);
747 ent->skinnum = 1;
748 }
749 else if ((cl.Effects[idx].ef.Chunk.type == THINGTYPE_CLAY) ||
750 (cl.Effects[idx].ef.Chunk.type == THINGTYPE_BONE))
751 {
752 if (final < 0.25)
753 ent->model = Mod_ForName ("models/clshard1.mdl", true);
754 else if (final < 0.50)
755 ent->model = Mod_ForName ("models/clshard2.mdl", true);
756 else if (final < 0.75)
757 ent->model = Mod_ForName ("models/clshard3.mdl", true);
758 else
759 ent->model = Mod_ForName ("models/clshard4.mdl", true);
760 if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_BONE)
761 {
762 ent->skinnum = 1; /* bone skin is second */
763 }
764 }
765 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_LEAVES)
766 {
767 if (final < 0.33)
768 ent->model = Mod_ForName ("models/leafchk1.mdl", true);
769 else if (final < 0.66)
770 ent->model = Mod_ForName ("models/leafchk2.mdl", true);
771 else
772 ent->model = Mod_ForName ("models/leafchk3.mdl", true);
773 }
774 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_HAY)
775 {
776 if (final < 0.33)
777 ent->model = Mod_ForName ("models/hay1.mdl", true);
778 else if (final < 0.66)
779 ent->model = Mod_ForName ("models/hay2.mdl", true);
780 else
781 ent->model = Mod_ForName ("models/hay3.mdl", true);
782 }
783 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_CLOTH)
784 {
785 if (final < 0.33)
786 ent->model = Mod_ForName ("models/clthchk1.mdl", true);
787 else if (final < 0.66)
788 ent->model = Mod_ForName ("models/clthchk2.mdl", true);
789 else
790 ent->model = Mod_ForName ("models/clthchk3.mdl", true);
791 }
792 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WOOD_LEAF)
793 {
794 if (final < 0.14)
795 ent->model = Mod_ForName ("models/splnter1.mdl", true);
796 else if (final < 0.28)
797 ent->model = Mod_ForName ("models/leafchk1.mdl", true);
798 else if (final < 0.42)
799 ent->model = Mod_ForName ("models/splnter2.mdl", true);
800 else if (final < 0.56)
801 ent->model = Mod_ForName ("models/leafchk2.mdl", true);
802 else if (final < 0.70)
803 ent->model = Mod_ForName ("models/splnter3.mdl", true);
804 else if (final < 0.84)
805 ent->model = Mod_ForName ("models/leafchk3.mdl", true);
806 else
807 ent->model = Mod_ForName ("models/splnter4.mdl", true);
808 }
809 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WOOD_METAL)
810 {
811 if (final < 0.125)
812 ent->model = Mod_ForName ("models/splnter1.mdl", true);
813 else if (final < 0.25)
814 ent->model = Mod_ForName ("models/metlchk1.mdl", true);
815 else if (final < 0.375)
816 ent->model = Mod_ForName ("models/splnter2.mdl", true);
817 else if (final < 0.50)
818 ent->model = Mod_ForName ("models/metlchk2.mdl", true);
819 else if (final < 0.625)
820 ent->model = Mod_ForName ("models/splnter3.mdl", true);
821 else if (final < 0.75)
822 ent->model = Mod_ForName ("models/metlchk3.mdl", true);
823 else if (final < 0.875)
824 ent->model = Mod_ForName ("models/splnter4.mdl", true);
825 else
826 ent->model = Mod_ForName ("models/metlchk4.mdl", true);
827 }
828 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_WOOD_STONE)
829 {
830 if (final < 0.125)
831 ent->model = Mod_ForName ("models/splnter1.mdl", true);
832 else if (final < 0.25)
833 ent->model = Mod_ForName ("models/schunk1.mdl", true);
834 else if (final < 0.375)
835 ent->model = Mod_ForName ("models/splnter2.mdl", true);
836 else if (final < 0.50)
837 ent->model = Mod_ForName ("models/schunk2.mdl", true);
838 else if (final < 0.625)
839 ent->model = Mod_ForName ("models/splnter3.mdl", true);
840 else if (final < 0.75)
841 ent->model = Mod_ForName ("models/schunk3.mdl", true);
842 else if (final < 0.875)
843 ent->model = Mod_ForName ("models/splnter4.mdl", true);
844 else
845 ent->model = Mod_ForName ("models/schunk4.mdl", true);
846 }
847 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_METAL_STONE)
848 {
849 if (final < 0.125)
850 ent->model = Mod_ForName ("models/metlchk1.mdl", true);
851 else if (final < 0.25)
852 ent->model = Mod_ForName ("models/schunk1.mdl", true);
853 else if (final < 0.375)
854 ent->model = Mod_ForName ("models/metlchk2.mdl", true);
855 else if (final < 0.50)
856 ent->model = Mod_ForName ("models/schunk2.mdl", true);
857 else if (final < 0.625)
858 ent->model = Mod_ForName ("models/metlchk3.mdl", true);
859 else if (final < 0.75)
860 ent->model = Mod_ForName ("models/schunk3.mdl", true);
861 else if (final < 0.875)
862 ent->model = Mod_ForName ("models/metlchk4.mdl", true);
863 else
864 ent->model = Mod_ForName ("models/schunk4.mdl", true);
865 }
866 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_METAL_CLOTH)
867 {
868 if (final < 0.14)
869 ent->model = Mod_ForName ("models/metlchk1.mdl", true);
870 else if (final < 0.28)
871 ent->model = Mod_ForName ("models/clthchk1.mdl", true);
872 else if (final < 0.42)
873 ent->model = Mod_ForName ("models/metlchk2.mdl", true);
874 else if (final < 0.56)
875 ent->model = Mod_ForName ("models/clthchk2.mdl", true);
876 else if (final < 0.70)
877 ent->model = Mod_ForName ("models/metlchk3.mdl", true);
878 else if (final < 0.84)
879 ent->model = Mod_ForName ("models/clthchk3.mdl", true);
880 else
881 ent->model = Mod_ForName ("models/metlchk4.mdl", true);
882 }
883 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_ICE)
884 {
885 ent->model = Mod_ForName("models/shard.mdl", true);
886 ent->skinnum = 0;
887 ent->frame = rand() % 2;
888 ent->drawflags |= DRF_TRANSLUCENT|MLS_ABSLIGHT;
889 ent->abslight = 127;
890 }
891 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_METEOR)
892 {
893 ent->model = Mod_ForName("models/tempmetr.mdl", true);
894 ent->skinnum = 0;
895 }
896 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_ACID)
897 { /* no spinning if possible... */
898 ent->model = Mod_ForName("models/sucwp2p.mdl", true);
899 ent->skinnum = 0;
900 }
901 else if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_GREENFLESH)
902 { /* spider guts */
903 if (final < 0.33)
904 ent->model = Mod_ForName ("models/sflesh1.mdl", true);
905 else if (final < 0.66)
906 ent->model = Mod_ForName ("models/sflesh2.mdl", true);
907 else
908 ent->model = Mod_ForName ("models/sflesh3.mdl", true);
909
910 ent->skinnum = 0;
911 }
912 else// if (cl.Effects[idx].ef.Chunk.type == THINGTYPE_GREYSTONE)
913 {
914 if (final < 0.25)
915 ent->model = Mod_ForName ("models/schunk1.mdl", true);
916 else if (final < 0.50)
917 ent->model = Mod_ForName ("models/schunk2.mdl", true);
918 else if (final < 0.75)
919 ent->model = Mod_ForName ("models/schunk3.mdl", true);
920 else
921 ent->model = Mod_ForName ("models/schunk4.mdl", true);
922 ent->skinnum = 0;
923 }
924 }
925 }
926
927 for (i = 0 ; i < 3 ; i++)
928 {
929 cl.Effects[idx].ef.Chunk.avel[i][0] = (rand() % 850) - 425;
930 cl.Effects[idx].ef.Chunk.avel[i][1] = (rand() % 850) - 425;
931 cl.Effects[idx].ef.Chunk.avel[i][2] = (rand() % 850) - 425;
932 }
933
934 break;
935
936 default:
937 Host_Error ("%s: bad type", __thisfunc__);
938 }
939
940 if (ImmediateFree)
941 {
942 cl.Effects[idx].type = CE_NONE;
943 }
944 }
945
CL_EndEffect(void)946 void CL_EndEffect (void)
947 {
948 int idx;
949
950 idx = MSG_ReadByte();
951
952 CL_FreeEffect(idx);
953 }
954
CL_LinkEntity(entity_t * ent)955 static void CL_LinkEntity (entity_t *ent)
956 {
957 if (cl_numvisedicts < MAX_VISEDICTS)
958 {
959 cl_visedicts[cl_numvisedicts++] = ent;
960 }
961 }
962
CL_UpdateEffects(void)963 void CL_UpdateEffects (void)
964 {
965 int i;
966 int idx, cur_frame;
967 vec3_t mymin, mymax;
968 float frametime;
969 // edict_t test;
970 // trace_t trace;
971 vec3_t org, org2, alldir, snow_org;
972 int x_dir, y_dir;
973 entity_t *ent;
974 float distance, smoketime;
975
976 if (cls.state == ca_disconnected)
977 return;
978
979 frametime = cl.time - cl.oldtime;
980 if (!frametime)
981 return;
982 // Con_Printf("Here at %f\n",cl.time);
983
984 for (idx = 0 ; idx < MAX_EFFECTS ; idx++)
985 {
986 if (!cl.Effects[idx].type)
987 continue;
988
989 switch (cl.Effects[idx].type)
990 {
991 case CE_RAIN:
992 org[0] = cl.Effects[idx].ef.Rain.min_org[0];
993 org[1] = cl.Effects[idx].ef.Rain.min_org[1];
994 org[2] = cl.Effects[idx].ef.Rain.max_org[2];
995
996 org2[0] = cl.Effects[idx].ef.Rain.e_size[0];
997 org2[1] = cl.Effects[idx].ef.Rain.e_size[1];
998 org2[2] = cl.Effects[idx].ef.Rain.e_size[2];
999
1000 x_dir = cl.Effects[idx].ef.Rain.dir[0];
1001 y_dir = cl.Effects[idx].ef.Rain.dir[1];
1002
1003 cl.Effects[idx].ef.Rain.next_time += frametime;
1004 if (cl.Effects[idx].ef.Rain.next_time >= cl.Effects[idx].ef.Rain.wait)
1005 {
1006 R_RainEffect(org, org2, x_dir, y_dir, cl.Effects[idx].ef.Rain.color,
1007 cl.Effects[idx].ef.Rain.count);
1008 cl.Effects[idx].ef.Rain.next_time = 0;
1009 }
1010 break;
1011
1012 case CE_SNOW:
1013 VectorCopy(cl.Effects[idx].ef.Rain.min_org, org);
1014 VectorCopy(cl.Effects[idx].ef.Rain.max_org, org2);
1015 VectorCopy(cl.Effects[idx].ef.Rain.dir, alldir);
1016
1017 VectorAdd(org, org2, snow_org);
1018
1019 snow_org[0] *= 0.5;
1020 snow_org[1] *= 0.5;
1021 snow_org[2] *= 0.5;
1022
1023 snow_org[2] = r_origin[2];
1024
1025 VectorSubtract(snow_org, r_origin, snow_org);
1026
1027 distance = VectorNormalize(snow_org);
1028
1029 cl.Effects[idx].ef.Rain.next_time += frametime;
1030 /* jfm: fixme, check distance to player first */
1031 if (cl.Effects[idx].ef.Rain.next_time >= 0.10 && distance < 1024)
1032 {
1033 R_SnowEffect(org, org2, cl.Effects[idx].ef.Rain.flags, alldir,
1034 cl.Effects[idx].ef.Rain.count);
1035
1036 cl.Effects[idx].ef.Rain.next_time = 0;
1037 }
1038 break;
1039
1040 case CE_FOUNTAIN:
1041 mymin[0] = (-3 * cl.Effects[idx].ef.Fountain.vright[0] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1042 (-3 * cl.Effects[idx].ef.Fountain.vforward[0] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1043 (2 * cl.Effects[idx].ef.Fountain.vup[0] * cl.Effects[idx].ef.Fountain.movedir[2]);
1044 mymin[1] = (-3 * cl.Effects[idx].ef.Fountain.vright[1] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1045 (-3 * cl.Effects[idx].ef.Fountain.vforward[1] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1046 (2 * cl.Effects[idx].ef.Fountain.vup[1] * cl.Effects[idx].ef.Fountain.movedir[2]);
1047 mymin[2] = (-3 * cl.Effects[idx].ef.Fountain.vright[2] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1048 (-3 * cl.Effects[idx].ef.Fountain.vforward[2] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1049 (2 * cl.Effects[idx].ef.Fountain.vup[2] * cl.Effects[idx].ef.Fountain.movedir[2]);
1050 mymin[0] *= 15;
1051 mymin[1] *= 15;
1052 mymin[2] *= 15;
1053
1054 mymax[0] = (3 * cl.Effects[idx].ef.Fountain.vright[0] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1055 (3 * cl.Effects[idx].ef.Fountain.vforward[0] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1056 (10 * cl.Effects[idx].ef.Fountain.vup[0] * cl.Effects[idx].ef.Fountain.movedir[2]);
1057 mymax[1] = (3 * cl.Effects[idx].ef.Fountain.vright[1] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1058 (3 * cl.Effects[idx].ef.Fountain.vforward[1] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1059 (10 * cl.Effects[idx].ef.Fountain.vup[1] * cl.Effects[idx].ef.Fountain.movedir[2]);
1060 mymax[2] = (3 * cl.Effects[idx].ef.Fountain.vright[2] * cl.Effects[idx].ef.Fountain.movedir[0]) +
1061 (3 * cl.Effects[idx].ef.Fountain.vforward[2] * cl.Effects[idx].ef.Fountain.movedir[1]) +
1062 (10 * cl.Effects[idx].ef.Fountain.vup[2] * cl.Effects[idx].ef.Fountain.movedir[2]);
1063 mymax[0] *= 15;
1064 mymax[1] *= 15;
1065 mymax[2] *= 15;
1066
1067 R_RunParticleEffect2 (cl.Effects[idx].ef.Fountain.pos, mymin, mymax,
1068 cl.Effects[idx].ef.Fountain.color, pt_fastgrav,
1069 cl.Effects[idx].ef.Fountain.cnt);
1070
1071 /*
1072 memset(&test, 0, sizeof(test));
1073 trace = SV_Move (cl.Effects[idx].ef.Fountain.pos, mymin, mymax, mymin,
1074 false, &test);
1075 Con_Printf("Fraction is %f\n", trace.fraction);
1076 */
1077 break;
1078
1079 case CE_QUAKE:
1080 R_RunQuakeEffect (cl.Effects[idx].ef.Quake.origin,
1081 cl.Effects[idx].ef.Quake.radius);
1082 break;
1083
1084 case CE_WHITE_SMOKE:
1085 case CE_GREEN_SMOKE:
1086 case CE_GREY_SMOKE:
1087 case CE_RED_SMOKE:
1088 case CE_SLOW_WHITE_SMOKE:
1089 case CE_TELESMK1:
1090 case CE_TELESMK2:
1091 case CE_GHOST:
1092 case CE_REDCLOUD:
1093 case CE_FLAMESTREAM:
1094 case CE_ACID_MUZZFL:
1095 case CE_FLAMEWALL:
1096 case CE_FLAMEWALL2:
1097 case CE_ONFIRE:
1098 cl.Effects[idx].ef.Smoke.time_amount += frametime;
1099 ent = &EffectEntities[cl.Effects[idx].ef.Smoke.entity_index];
1100
1101 smoketime = cl.Effects[idx].ef.Smoke.framelength;
1102 if (!smoketime)
1103 smoketime = HX_FRAME_TIME;
1104
1105 ent->origin[0] += (frametime/smoketime) * cl.Effects[idx].ef.Smoke.velocity[0];
1106 ent->origin[1] += (frametime/smoketime) * cl.Effects[idx].ef.Smoke.velocity[1];
1107 ent->origin[2] += (frametime/smoketime) * cl.Effects[idx].ef.Smoke.velocity[2];
1108
1109 while (cl.Effects[idx].ef.Smoke.time_amount >= smoketime)
1110 {
1111 ent->frame++;
1112 cl.Effects[idx].ef.Smoke.time_amount -= smoketime;
1113 }
1114
1115 if (ent->frame >= ent->model->numframes)
1116 {
1117 CL_FreeEffect(idx);
1118 }
1119 else
1120 {
1121 CL_LinkEntity(ent);
1122 }
1123
1124 break;
1125
1126 /* Just go through animation and then remove */
1127 case CE_SM_WHITE_FLASH:
1128 case CE_YELLOWRED_FLASH:
1129 case CE_BLUESPARK:
1130 case CE_YELLOWSPARK:
1131 case CE_SM_CIRCLE_EXP:
1132 case CE_BG_CIRCLE_EXP:
1133 case CE_SM_EXPLOSION:
1134 case CE_LG_EXPLOSION:
1135 case CE_FLOOR_EXPLOSION:
1136 case CE_FLOOR_EXPLOSION3:
1137 case CE_BLUE_EXPLOSION:
1138 case CE_REDSPARK:
1139 case CE_GREENSPARK:
1140 case CE_ICEHIT:
1141 case CE_MEDUSA_HIT:
1142 case CE_MEZZO_REFLECT:
1143 case CE_FLOOR_EXPLOSION2:
1144 case CE_XBOW_EXPLOSION:
1145 case CE_NEW_EXPLOSION:
1146 case CE_MAGIC_MISSILE_EXPLOSION:
1147 case CE_BONE_EXPLOSION:
1148 case CE_BLDRN_EXPL:
1149 case CE_BRN_BOUNCE:
1150 case CE_ACID_HIT:
1151 case CE_ACID_SPLAT:
1152 case CE_ACID_EXPL:
1153 case CE_LBALL_EXPL:
1154 case CE_FBOOM:
1155 case CE_BOMB:
1156 case CE_FIREWALL_SMALL:
1157 case CE_FIREWALL_MEDIUM:
1158 case CE_FIREWALL_LARGE:
1159 cl.Effects[idx].ef.Smoke.time_amount += frametime;
1160 ent = &EffectEntities[cl.Effects[idx].ef.Smoke.entity_index];
1161
1162 if (cl.Effects[idx].type != CE_BG_CIRCLE_EXP)
1163 {
1164 while (cl.Effects[idx].ef.Smoke.time_amount >= HX_FRAME_TIME)
1165 {
1166 ent->frame++;
1167 cl.Effects[idx].ef.Smoke.time_amount -= HX_FRAME_TIME;
1168 }
1169 }
1170 else
1171 {
1172 while (cl.Effects[idx].ef.Smoke.time_amount >= HX_FRAME_TIME * 2)
1173 {
1174 ent->frame++;
1175 cl.Effects[idx].ef.Smoke.time_amount -= HX_FRAME_TIME * 2;
1176 }
1177 }
1178 if (ent->frame >= ent->model->numframes)
1179 {
1180 CL_FreeEffect(idx);
1181 }
1182 else
1183 {
1184 CL_LinkEntity(ent);
1185 }
1186 break;
1187
1188 case CE_LSHOCK:
1189 ent = &EffectEntities[cl.Effects[idx].ef.Smoke.entity_index];
1190 if (ent->skinnum == 0)
1191 ent->skinnum = 1;
1192 else if (ent->skinnum == 1)
1193 ent->skinnum = 0;
1194 ent->scale -= 10;
1195 if (ent->scale <= 10)
1196 {
1197 CL_FreeEffect(idx);
1198 }
1199 else
1200 {
1201 CL_LinkEntity(ent);
1202 }
1203 break;
1204
1205 /* Go forward then backward through animation then remove */
1206 case CE_WHITE_FLASH:
1207 case CE_BLUE_FLASH:
1208 case CE_SM_BLUE_FLASH:
1209 case CE_RED_FLASH:
1210 cl.Effects[idx].ef.Flash.time_amount += frametime;
1211 ent = &EffectEntities[cl.Effects[idx].ef.Flash.entity_index];
1212
1213 while (cl.Effects[idx].ef.Flash.time_amount >= HX_FRAME_TIME)
1214 {
1215 if (!cl.Effects[idx].ef.Flash.reverse)
1216 {
1217 if (ent->frame >= ent->model->numframes-1)
1218 {
1219 /* Ran through forward animation */
1220 cl.Effects[idx].ef.Flash.reverse = 1;
1221 ent->frame--;
1222 }
1223 else
1224 ent->frame++;
1225 }
1226 else
1227 {
1228 ent->frame--;
1229 }
1230
1231 cl.Effects[idx].ef.Flash.time_amount -= HX_FRAME_TIME;
1232 }
1233
1234 if ((ent->frame <= 0) && (cl.Effects[idx].ef.Flash.reverse))
1235 {
1236 CL_FreeEffect(idx);
1237 }
1238 else
1239 {
1240 CL_LinkEntity(ent);
1241 }
1242 break;
1243
1244 case CE_RIDER_DEATH:
1245 cl.Effects[idx].ef.RD.time_amount += frametime;
1246 if (cl.Effects[idx].ef.RD.time_amount >= 1)
1247 {
1248 cl.Effects[idx].ef.RD.stage++;
1249 cl.Effects[idx].ef.RD.time_amount -= 1;
1250 }
1251
1252 VectorCopy(cl.Effects[idx].ef.RD.origin, org);
1253 org[0] += sin(cl.Effects[idx].ef.RD.time_amount * 2 * M_PI) * 30;
1254 org[1] += cos(cl.Effects[idx].ef.RD.time_amount * 2 * M_PI) * 30;
1255
1256 if (cl.Effects[idx].ef.RD.stage <= 6)
1257 {
1258 // RiderParticle(cl.Effects[idx].ef.RD.stage + 1, cl.Effects[idx].ef.RD.origin);
1259 RiderParticle(cl.Effects[idx].ef.RD.stage + 1, org);
1260 }
1261 else
1262 {
1263 /* To set the rider's origin point for the particles */
1264 RiderParticle(0, org);
1265 if (cl.Effects[idx].ef.RD.stage == 7)
1266 {
1267 cl.cshifts[CSHIFT_BONUS].destcolor[0] = 255;
1268 cl.cshifts[CSHIFT_BONUS].destcolor[1] = 255;
1269 cl.cshifts[CSHIFT_BONUS].destcolor[2] = 255;
1270 cl.cshifts[CSHIFT_BONUS].percent = 256;
1271 }
1272 else if (cl.Effects[idx].ef.RD.stage > 13)
1273 {
1274 // cl.Effects[idx].ef.RD.stage = 0;
1275 CL_FreeEffect(idx);
1276 }
1277 }
1278 break;
1279
1280 case CE_GRAVITYWELL:
1281 cl.Effects[idx].ef.RD.time_amount += frametime*2;
1282 if (cl.Effects[idx].ef.RD.time_amount >= 1)
1283 cl.Effects[idx].ef.RD.time_amount -= 1;
1284
1285 VectorCopy(cl.Effects[idx].ef.RD.origin, org);
1286 org[0] += sin(cl.Effects[idx].ef.RD.time_amount * 2 * M_PI) * 30;
1287 org[1] += cos(cl.Effects[idx].ef.RD.time_amount * 2 * M_PI) * 30;
1288
1289 if (cl.Effects[idx].ef.RD.lifetime < cl.time)
1290 {
1291 CL_FreeEffect(idx);
1292 }
1293 else
1294 {
1295 GravityWellParticle(rand() % 8, org, cl.Effects[idx].ef.RD.color);
1296 }
1297
1298 break;
1299
1300 case CE_TELEPORTERPUFFS:
1301 cl.Effects[idx].ef.Teleporter.time_amount += frametime;
1302 smoketime = cl.Effects[idx].ef.Teleporter.framelength;
1303
1304 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[0]];
1305 while (cl.Effects[idx].ef.Teleporter.time_amount >= HX_FRAME_TIME)
1306 {
1307 ent->frame++;
1308 cl.Effects[idx].ef.Teleporter.time_amount -= HX_FRAME_TIME;
1309 }
1310 cur_frame = ent->frame;
1311
1312 if (cur_frame >= ent->model->numframes)
1313 {
1314 CL_FreeEffect(idx);
1315 break;
1316 }
1317
1318 for (i = 0 ; i < 8 ; ++i)
1319 {
1320 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[i]];
1321
1322 ent->origin[0] += (frametime/smoketime) * cl.Effects[idx].ef.Teleporter.velocity[i][0];
1323 ent->origin[1] += (frametime/smoketime) * cl.Effects[idx].ef.Teleporter.velocity[i][1];
1324 ent->origin[2] += (frametime/smoketime) * cl.Effects[idx].ef.Teleporter.velocity[i][2];
1325 ent->frame = cur_frame;
1326
1327 CL_LinkEntity(ent);
1328 }
1329 break;
1330
1331 case CE_TELEPORTERBODY:
1332 cl.Effects[idx].ef.Teleporter.time_amount += frametime;
1333 smoketime = cl.Effects[idx].ef.Teleporter.framelength;
1334
1335 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[0]];
1336 while (cl.Effects[idx].ef.Teleporter.time_amount >= HX_FRAME_TIME)
1337 {
1338 ent->scale -= 15;
1339 cl.Effects[idx].ef.Teleporter.time_amount -= HX_FRAME_TIME;
1340 }
1341
1342 ent = &EffectEntities[cl.Effects[idx].ef.Teleporter.entity_index[0]];
1343 ent->angles[1] += 45;
1344
1345 if (ent->scale <= 10)
1346 {
1347 CL_FreeEffect(idx);
1348 }
1349 else
1350 {
1351 CL_LinkEntity(ent);
1352 }
1353 break;
1354
1355 case CE_BONESHARD:
1356 case CE_BONESHRAPNEL:
1357 cl.Effects[idx].ef.Missile.time_amount += frametime;
1358 ent = &EffectEntities[cl.Effects[idx].ef.Missile.entity_index];
1359
1360 // ent->angles[0] = cl.Effects[idx].ef.Missile.angle[0];
1361 // ent->angles[1] = cl.Effects[idx].ef.Missile.angle[1];
1362 // ent->angles[2] = cl.Effects[idx].ef.Missile.angle[2];
1363
1364 ent->angles[0] += frametime * cl.Effects[idx].ef.Missile.avelocity[0];
1365 ent->angles[1] += frametime * cl.Effects[idx].ef.Missile.avelocity[1];
1366 ent->angles[2] += frametime * cl.Effects[idx].ef.Missile.avelocity[2];
1367
1368 ent->origin[0] += frametime * cl.Effects[idx].ef.Missile.velocity[0];
1369 ent->origin[1] += frametime * cl.Effects[idx].ef.Missile.velocity[1];
1370 ent->origin[2] += frametime * cl.Effects[idx].ef.Missile.velocity[2];
1371
1372 CL_LinkEntity(ent);
1373 break;
1374
1375 case CE_CHUNK:
1376 cl.Effects[idx].ef.Chunk.time_amount -= frametime;
1377 if (cl.Effects[idx].ef.Chunk.time_amount < 0)
1378 {
1379 CL_FreeEffect(idx);
1380 }
1381 else
1382 {
1383 for (i = 0 ; i < cl.Effects[idx].ef.Chunk.numChunks ; i++)
1384 {
1385 vec3_t oldorg;
1386 mleaf_t *l;
1387 int moving = 1;
1388
1389 ent = &EffectEntities[cl.Effects[idx].ef.Chunk.entity_index[i]];
1390
1391 VectorCopy(ent->origin, oldorg);
1392
1393 ent->origin[0] += frametime * cl.Effects[idx].ef.Chunk.velocity[i][0];
1394 ent->origin[1] += frametime * cl.Effects[idx].ef.Chunk.velocity[i][1];
1395 ent->origin[2] += frametime * cl.Effects[idx].ef.Chunk.velocity[i][2];
1396
1397 l = Mod_PointInLeaf (ent->origin, cl.worldmodel);
1398 if (l->contents != CONTENTS_EMPTY) //|| in_solid == true
1399 { /* bouncing prolly won't work... */
1400 VectorCopy(oldorg, ent->origin);
1401
1402 cl.Effects[idx].ef.Chunk.velocity[i][0] = 0;
1403 cl.Effects[idx].ef.Chunk.velocity[i][1] = 0;
1404 cl.Effects[idx].ef.Chunk.velocity[i][2] = 0;
1405
1406 moving = 0;
1407 }
1408 else
1409 {
1410 ent->angles[0] += frametime * cl.Effects[idx].ef.Chunk.avel[i%3][0];
1411 ent->angles[1] += frametime * cl.Effects[idx].ef.Chunk.avel[i%3][1];
1412 ent->angles[2] += frametime * cl.Effects[idx].ef.Chunk.avel[i%3][2];
1413 }
1414
1415 if (cl.Effects[idx].ef.Chunk.time_amount < frametime * 3)
1416 { /* chunk leaves in 3 frames */
1417 ent->scale *= .7;
1418 }
1419
1420 CL_LinkEntity(ent);
1421
1422 cl.Effects[idx].ef.Chunk.velocity[i][2] -= frametime * 500; /* apply gravity */
1423
1424 switch (cl.Effects[idx].ef.Chunk.type)
1425 {
1426 case THINGTYPE_GREYSTONE:
1427 break;
1428 case THINGTYPE_WOOD:
1429 break;
1430 case THINGTYPE_METAL:
1431 break;
1432 case THINGTYPE_FLESH:
1433 if (moving)
1434 R_RocketTrail (oldorg, ent->origin, 17);
1435 break;
1436 case THINGTYPE_FIRE:
1437 break;
1438 case THINGTYPE_CLAY:
1439 case THINGTYPE_BONE:
1440 break;
1441 case THINGTYPE_LEAVES:
1442 break;
1443 case THINGTYPE_HAY:
1444 break;
1445 case THINGTYPE_BROWNSTONE:
1446 break;
1447 case THINGTYPE_CLOTH:
1448 break;
1449 case THINGTYPE_WOOD_LEAF:
1450 break;
1451 case THINGTYPE_WOOD_METAL:
1452 break;
1453 case THINGTYPE_WOOD_STONE:
1454 break;
1455 case THINGTYPE_METAL_STONE:
1456 break;
1457 case THINGTYPE_METAL_CLOTH:
1458 break;
1459 case THINGTYPE_WEBS:
1460 break;
1461 case THINGTYPE_GLASS:
1462 break;
1463 case THINGTYPE_ICE:
1464 if (moving)
1465 R_RocketTrail (oldorg, ent->origin, rt_ice);
1466 break;
1467 case THINGTYPE_CLEARGLASS:
1468 break;
1469 case THINGTYPE_REDGLASS:
1470 break;
1471 case THINGTYPE_ACID:
1472 if (moving)
1473 R_RocketTrail (oldorg, ent->origin, rt_acidball);
1474 break;
1475 case THINGTYPE_METEOR:
1476 R_RocketTrail (oldorg, ent->origin, 1);
1477 break;
1478 case THINGTYPE_GREENFLESH:
1479 if (moving)
1480 R_RocketTrail (oldorg, ent->origin, rt_acidball);
1481 break;
1482 }
1483 }
1484 }
1485 break;
1486 }
1487 }
1488 }
1489
1490 //==========================================================================
1491 //
1492 // NewEffectEntity
1493 //
1494 //==========================================================================
1495
NewEffectEntity(void)1496 static int NewEffectEntity (void)
1497 {
1498 entity_t *ent;
1499 int counter;
1500
1501 if (cl_numvisedicts == MAX_VISEDICTS)
1502 return -1;
1503
1504 if (EffectEntityCount == MAX_EFFECT_ENTITIES)
1505 return -1;
1506
1507 for (counter = 0 ; counter < MAX_EFFECT_ENTITIES ; counter++)
1508 {
1509 if (!EntityUsed[counter])
1510 break;
1511 }
1512
1513 EntityUsed[counter] = true;
1514 EffectEntityCount++;
1515 ent = &EffectEntities[counter];
1516 memset(ent, 0, sizeof(*ent));
1517 ent->colormap = vid.colormap;
1518
1519 return counter;
1520 }
1521
FreeEffectEntity(int idx)1522 static void FreeEffectEntity (int idx)
1523 {
1524 EntityUsed[idx] = false;
1525 EffectEntityCount--;
1526 }
1527
1528