1 /*
2 Copyright (C) 1997-2001 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 //
21 // cg_parteffects.c
22 //
23 
24 #include "cg_local.h"
25 
26 /*
27 ===============
28 CG_FindExplosionDir
29 
30 This is a "necessary hack" for explosion decal placement.
31 ===============
32 */
CG_FindExplosionDir(vec3_t origin,float radius,vec3_t endPos,vec3_t dir)33 static qBool CG_FindExplosionDir (vec3_t origin, float radius, vec3_t endPos, vec3_t dir)
34 {
35 	static vec3_t	planes[6] = {{0,0,1}, {0,1,0}, {1,0,0}, {0,0,-1}, {0,-1,0}, {-1,0,0}};
36 	trace_t			tr;
37 	vec3_t			tempDir;
38 	vec3_t			tempOrg;
39 	float			best;
40 	int				i;
41 
42 	best = 1.0f;
43 	Vec3Clear (endPos);
44 	Vec3Clear (dir);
45 	for (i=0 ; i<6 ; i++) {
46 		Vec3MA (origin, radius * 0.9f, planes[i], tempDir);
47 		Vec3MA (origin, radius * 0.1f, planes[(i+3)%6], tempOrg);
48 
49 		CG_PMTrace (&tr, tempOrg, NULL, NULL, tempDir, qFalse);
50 		if (tr.allSolid || tr.fraction == 1.0f)
51 			continue;
52 
53 		if (tr.fraction < best) {
54 			best = tr.fraction;
55 			Vec3Copy (tr.endPos, endPos);
56 			Vec3Copy (tr.plane.normal, dir);
57 		}
58 	}
59 
60 	if (best < 1.0f) {
61 		// FIXME: why does this "fix" decal normals on xdmt4? Something to do with the fragment planes...
62 		byte dirByte = DirToByte (dir);
63 		ByteToDir (dirByte, dir);
64 		return qTrue;
65 	}
66 
67 	return qFalse;
68 }
69 
70 /*
71 =============================================================================
72 
73 	PARTICLE EFFECTS
74 
75 =============================================================================
76 */
77 
78 /*
79 ===============
80 CG_BlasterBlueParticles
81 ===============
82 */
CG_BlasterBlueParticles(vec3_t org,vec3_t dir)83 void CG_BlasterBlueParticles (vec3_t org, vec3_t dir)
84 {
85 	int			i, count;
86 	int			rnum, rnum2;
87 	float		d;
88 
89 	// Glow mark
90 	rnum = (rand () % 5);
91 	rnum2 = (rand () % 5);
92 	CG_SpawnDecal (
93 		org[0],								org[1],								org[2],
94 		dir[0],								dir[1],								dir[2],
95 		palRed (0x70 + rnum),				palGreen (0x70 + rnum),				palBlue (0x70 + rnum),
96 		palRed (0x70 + rnum2),				palGreen (0x70 + rnum2),			palBlue (0x70 + rnum2),
97 		1,									0,
98 		7 + (frand() * 0.5f),
99 		DT_BLASTER_BLUEMARK,				DF_USE_BURNLIFE|DF_ALPHACOLOR,
100 		0,									qFalse,
101 		0,									frand () * 360);
102 
103 	// Burn mark
104 	rnum = (rand () % 5);
105 	CG_SpawnDecal (
106 		org[0],								org[1],								org[2],
107 		dir[0],								dir[1],								dir[2],
108 		(255-palRed(0x70+rnum))*0.5f+128,	(255-palGreen(0x70+rnum))*0.5f+128,	(255-palBlue(0x70+rnum))*0.5f+128,
109 		0,									0,									0,
110 		0.9f + (crand() * 0.1f),			0.9f + (crand() * 0.1f),
111 		5 + (frand() * 0.5f),
112 		DT_BLASTER_BURNMARK,				DF_ALPHACOLOR,
113 		0,									qFalse,
114 		0,									frand () * 360.0f);
115 
116 	// Smoke
117 	count = 6 + (cg_particleSmokeLinger->floatVal * 0.25f);
118 	for (i=0 ; i<count ; i++) {
119 		d = 3 + (frand () * 6);
120 		rnum = (rand () % 5);
121 
122 		CG_SpawnParticle (
123 			org[0] + (d*dir[0]) + (crand()*2),	org[1] + (d*dir[1]) + (crand()*2),	org[2] + (d*dir[2]) + (crand()*2),
124 			0,									0,									0,
125 			0,									0,									0,
126 			0,									0,									5 + (frand () * 25),
127 			palRed (0x70 + rnum),				palGreen (0x70 + rnum),				palBlue (0x70 + rnum),
128 			palRed (0x70 + rnum),				palGreen (0x70 + rnum),				palBlue (0x70 + rnum),
129 			0.9f + (frand() * 0.1f),			-1.0f / (0.8f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
130 			5 + crand (),						16 + (crand () * 8),
131 			pRandGlowSmoke (),					PF_ALPHACOLOR,
132 			NULL,								qFalse,
133 			PART_STYLE_QUAD,
134 			frand () * 360);
135 	}
136 
137 	// Dots
138 	count = 60;
139 	for (i=0 ; i<count ; i++) {
140 		d = 6 + (frand () * 12);
141 		rnum = (rand () % 5);
142 
143 		CG_SpawnParticle (
144 			org[0] + (d*dir[0]) + (crand()*4),	org[1] + (d*dir[1]) + (crand()*4),	org[2] + (d*dir[2]) + (crand()*4),
145 			0,									0,									0,
146 			(dir[0] * 25) + (crand () * 35),	(dir[1] * 25) + (crand () * 35),	(dir[2] * 25) + (crand () * 35),
147 			0,									0,									-(frand () * 10),
148 			palRed (0x70 + rnum),				palGreen (0x70 + rnum),				palBlue (0x70 + rnum),
149 			palRed (0x70 + rnum),				palGreen (0x70 + rnum),				palBlue (0x70 + rnum),
150 			0.9f + (frand () * 0.1f),			-1.0f / (1 + frand () * 0.3f),
151 			11 + (frand () * -10.75f),			0.1f + (frand () * 0.5f),
152 			PT_BLASTER_BLUE,					PF_SCALED|PF_GRAVITY|PF_ALPHACOLOR|PF_NOCLOSECULL,
153 			pBounceThink,						qTrue,
154 			PART_STYLE_QUAD,
155 			0);
156 	}
157 }
158 
159 
160 /*
161 ===============
162 CG_BlasterGoldParticles
163 ===============
164 */
CG_BlasterGoldParticles(vec3_t org,vec3_t dir)165 void CG_BlasterGoldParticles (vec3_t org, vec3_t dir)
166 {
167 	int			i, count;
168 	int			rnum, rnum2;
169 	float		d;
170 
171 	// Glow mark
172 	rnum = (rand () % 5);
173 	rnum2 = (rand () % 5);
174 	CG_SpawnDecal (
175 		org[0],								org[1],								org[2],
176 		dir[0],								dir[1],								dir[2],
177 		palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
178 		palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
179 		1,									0,
180 		7 + (frand() * 0.5f),
181 		DT_BLASTER_REDMARK,					DF_USE_BURNLIFE|DF_ALPHACOLOR,
182 		0,									qFalse,
183 		0,									frand () * 360);
184 
185 	// Burn mark
186 	rnum = (rand () % 5);
187 	CG_SpawnDecal (
188 		org[0],								org[1],								org[2],
189 		dir[0],								dir[1],								dir[2],
190 		(255-palRed(0xe0+rnum))*0.5f+128,	(255-palGreen(0xe0+rnum))*0.5f+128,	(255-palBlue(0xe0+rnum))*0.5f+128,
191 		0,									0,									0,
192 		0.9f + (crand() * 0.1f),			0.9f + (crand() * 0.1f),
193 		5 + (frand() * 0.5f),
194 		DT_BLASTER_BURNMARK,				DF_ALPHACOLOR,
195 		0,									qFalse,
196 		0,									frand () * 360);
197 
198 	// Smoke
199 	count = 6 + (cg_particleSmokeLinger->floatVal * 0.25f);
200 	for (i=0 ; i<count ; i++) {
201 		d = 3 + (frand () * 6);
202 		rnum = (rand () % 5);
203 		rnum2 = (rand () % 5);
204 
205 		CG_SpawnParticle (
206 			org[0] + (d*dir[0]) + (crand()*2),	org[1] + (d*dir[1]) + (crand()*2),	org[2] + (d*dir[2]) + (crand()*2),
207 			0,									0,									0,
208 			0,									0,									0,
209 			0,									0,									5 + (frand () * 25),
210 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
211 			palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
212 			0.9f + (frand() * 0.1f),			-1.0f / (0.8f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
213 			5 + crand (),						16 + (crand () * 8),
214 			pRandGlowSmoke (),					PF_ALPHACOLOR,
215 			NULL,								qFalse,
216 			PART_STYLE_QUAD,
217 			frand () * 360);
218 	}
219 
220 	// Dots
221 	count = 60.0f;
222 	for (i=0 ; i<count ; i++) {
223 		d = 6 + (frand () * 12);
224 		rnum = (rand () % 5);
225 
226 		CG_SpawnParticle (
227 			org[0] + (d*dir[0]) + (crand()*4),	org[1] + (d*dir[1]) + (crand()*4),	org[2] + (d*dir[2]) + (crand()*4),
228 			0,									0,									0,
229 			(dir[0] * 25) + (crand () * 35),	(dir[1] * 25) + (crand () * 35),	(dir[2] * 25) + (crand () * 35),
230 			0,									0,									-(frand () * 10),
231 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
232 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
233 			0.9f + (frand () * 0.1f),			-1.0f / (1 + frand () * 0.3f),
234 			11 + (frand () * -10.75f),			0.1f + (frand () * 0.5f),
235 			PT_BLASTER_RED,						PF_SCALED|PF_GRAVITY|PF_ALPHACOLOR|PF_NOCLOSECULL,
236 			pBounceThink,						qTrue,
237 			PART_STYLE_QUAD,
238 			0);
239 	}
240 }
241 
242 
243 /*
244 ===============
245 CG_BlasterGreenParticles
246 ===============
247 */
CG_BlasterGreenParticles(vec3_t org,vec3_t dir)248 void CG_BlasterGreenParticles (vec3_t org, vec3_t dir)
249 {
250 	int			i, count, rnum;
251 	float		d, randwhite;
252 
253 	// Glow mark
254 	CG_SpawnDecal (
255 		org[0],								org[1],								org[2],
256 		dir[0],								dir[1],								dir[2],
257 		(float)(rand()%41+135),				(float)180 + (rand()%76),			(float)(rand()%41+135),
258 		(float)(rand()%41+135),				(float)180 + (rand()%76),			(float)(rand()%41+135),
259 		1,									0,
260 		5 + (frand() * 0.5f),
261 		DT_BLASTER_GREENMARK,				DF_USE_BURNLIFE|DF_ALPHACOLOR,
262 		0,									qFalse,
263 		0,									frand () * 360);
264 
265 	// Burn mark
266 	rnum = (rand()%5);
267 	CG_SpawnDecal (
268 		org[0],								org[1],								org[2],
269 		dir[0],								dir[1],								dir[2],
270 		(255-palRed(0xd0+rnum))*0.5f+128,	(255-palGreen(0xd0+rnum))*0.5f+128,	(255-palBlue(0xd0+rnum))*0.5f+128,
271 		0,									0,									0,
272 		0.9f + (crand() * 0.1f),			0.9f + (crand() * 0.1f),
273 		4 + (frand() * 0.5f),
274 		DT_BLASTER_BURNMARK,				DF_ALPHACOLOR,
275 		0,									qFalse,
276 		0,									frand () * 360);
277 
278 	// Smoke
279 	count = 6 + (cg_particleSmokeLinger->floatVal * 0.25f);
280 	for (i=0 ; i<count ; i++) {
281 		d = 3 + (frand () * 6);
282 		randwhite = (rand()&1)?150 + (rand()%26) : 0.0f;
283 
284 		CG_SpawnParticle (
285 			org[0] + (d*dir[0]) + (crand()*2),	org[1] + (d*dir[1]) + (crand()*2),	org[2] + (d*dir[2]) + (crand()*2),
286 			0,									0,									0,
287 			0,									0,									0,
288 			0,									0,									5 + (frand () * 25),
289 			randwhite,							65 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
290 			randwhite,							65 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
291 			0.9f + (frand() * 0.1f),			-1.0f / (0.8f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
292 			5 + crand (),						16 + (crand () * 8),
293 			pRandGlowSmoke (),					PF_ALPHACOLOR,
294 			NULL,								qFalse,
295 			PART_STYLE_QUAD,
296 			frand () * 360);
297 	}
298 
299 	// Dots
300 	count = 60.0f;
301 	for (i=0 ; i<count ; i++) {
302 		d = 6 + (frand () * 12);
303 		randwhite = (rand()&1)?150 + (rand()%26) : 0.0f;
304 
305 		CG_SpawnParticle (
306 			org[0] + (d*dir[0]) + (crand()*4),	org[1] + (d*dir[1]) + (crand()*4),	org[2] + (d*dir[2]) + (crand()*4),
307 			0,									0,									0,
308 			(dir[0] * 25) + (crand () * 35),	(dir[1] * 25) + (crand () * 35),	(dir[2] * 25) + (crand () * 35),
309 			0,									0,									-(frand () * 10),
310 			randwhite,							65 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
311 			randwhite,							65 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
312 			0.9f + (frand() * 0.1f),			-0.4f / (0.3f + (frand () * 0.3f)),
313 			10 + (frand() * -9.75f),			0.1f + (frand() * 0.5f),
314 			PT_BLASTER_GREEN,					PF_SCALED|PF_GRAVITY|PF_ALPHACOLOR|PF_NOCLOSECULL,
315 			pBounceThink,						qTrue,
316 			PART_STYLE_QUAD,
317 			0);
318 	}
319 }
320 
321 
322 /*
323 ===============
324 CG_BlasterGreyParticles
325 ===============
326 */
CG_BlasterGreyParticles(vec3_t org,vec3_t dir)327 void CG_BlasterGreyParticles (vec3_t org, vec3_t dir)
328 {
329 	int		i, count;
330 	float	d;
331 
332 	// Smoke
333 	count = 6 + (cg_particleSmokeLinger->floatVal * 0.25f);
334 	for (i=0 ; i<count ; i++) {
335 		d = (float)(rand()%13 + 3);
336 
337 		CG_SpawnParticle (
338 			org[0] + d*dir[0],					org[1] + d*dir[1],					org[2] + d*dir[2],
339 			0,									0,									0,
340 			0,									0,									0,
341 			0,									0,									10 + (frand () * 20),
342 			130.0f + (rand()%6),				162.0f + (rand()%6),				178.0f + (rand()%6),
343 			130.0f + (rand()%6),				162.0f + (rand()%6),				178.0f + (rand()%6),
344 			0.9f + (frand() * 0.1f),			-1.0f / (0.8f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
345 			5 + crand (),						15 + (crand () * 8),
346 			pRandGlowSmoke (),					PF_ALPHACOLOR,
347 			NULL,								qFalse,
348 			PART_STYLE_QUAD,
349 			frand () * 360);
350 	}
351 
352 	// Dots
353 	count = 50.0f;
354 	for (i=0 ; i<count ; i++) {
355 		d = 1.5f + (rand()%13 + 3);
356 
357 		CG_SpawnParticle (
358 			org[0] + crand () * 4 + d*dir[0],	org[1] + crand () * 4 + d*dir[1],	org[2] + crand () * 4 + d*dir[2],
359 			0,									0,									0,
360 			dir[0] * 25 + crand () * 35,		dir[1] * 25 + crand () * 35,		dir[2] * 25 + crand () * 35,
361 			0,									0,									-10 + (frand () * 10),
362 			130.0f + (rand()%6),				162.0f + (rand()%6),				178.0f + (rand()%6),
363 			130.0f + (rand()%6),				162.0f + (rand()%6),				178.0f + (rand()%6),
364 			0.9f + (frand() * 0.1f),			-1.0f / (0.8f + (frand () * 0.3f)),
365 			10 + (frand() * -9.75f),			0.1f + (frand() * 0.5f),
366 			PT_FLARE,							PF_SCALED|PF_GRAVITY|PF_NOCLOSECULL,
367 			pBounceThink,						qTrue,
368 			PART_STYLE_QUAD,
369 			0);
370 	}
371 }
372 
373 
374 /*
375 ===============
376 CG_BleedEffect
377 ===============
378 */
CG_BleedEffect(vec3_t org,vec3_t dir,int count)379 void CG_BleedEffect (vec3_t org, vec3_t dir, int count)
380 {
381 	int			i, flags;
382 	float		d, gore, amount, fly;
383 	vec3_t		orgVec, dirVec;
384 
385 	gore = clamp (cg_particleGore->floatVal, 0.0f, 10.0f);
386 	fly = (gore * 0.1f) * 30;
387 
388 	// Splurt
389 	amount = ((gore + 5) / 10.0f) + 0.5f;
390 	for (i=0 ; i<amount ; i++) {
391 		dirVec[0] = crand () * 3;
392 		dirVec[1] = crand () * 3;
393 		dirVec[2] = crand () * 3;
394 
395 		CG_SpawnParticle (
396 			org[0] + (crand () * 3),			org[1] + (crand () * 3),			org[2] + (crand () * 3),
397 			0,									0,									0,
398 			dirVec[0],							dirVec[1],							dirVec[2],
399 			dirVec[0] * -0.25f,					dirVec[1] * -0.25f,					dirVec[2] * -0.25f,
400 			230 + (frand () * 5),				245 + (frand () * 10),				245 + (frand () * 10),
401 			0,									0,									0,
402 			1.0f,								-0.5f / (0.4f + (frand () * 0.3f)),
403 			9 + (crand () * 2),					14 + (crand () * 3),
404 			PT_BLDSPURT,						PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
405 			NULL,								qFalse,
406 			PART_STYLE_QUAD,
407 			frand () * 360);
408 	}
409 
410 	// Larger splurt
411 	for (i=0 ; i<amount ; i++) {
412 		dirVec[0] = crand () * 4;
413 		dirVec[1] = crand () * 4;
414 		dirVec[2] = crand () * 4;
415 
416 		CG_SpawnParticle (
417 			org[0] + (crand () * 3),			org[1] + (crand () * 3),			org[2] + (crand () * 3),
418 			0,									0,									0,
419 			dirVec[0],							dirVec[1],							dirVec[2],
420 			dirVec[0] * -0.25f,					dirVec[1] * -0.25f,					dirVec[2] * -0.25f,
421 			230 + (frand () * 5),				245 + (frand () * 10),				245 + (frand () * 10),
422 			0,									0,									0,
423 			1.0f,								-0.5f / (0.4f + (frand () * 0.3f)),
424 			10 + (crand () * 2),				14 + (crand () * 3),
425 			PT_BLDSPURT2,						PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
426 			NULL,								qFalse,
427 			PART_STYLE_QUAD,
428 			frand () * 360);
429 	}
430 
431 	// Drips
432 	amount = (count + gore) * 0.25f;
433 	flags = PF_ALPHACOLOR|PF_SCALED|PF_GRAVITY;
434 
435 	for (i=0 ; i<amount ; i++) {
436 		// Every other drip follows the last one
437 		if (i+1 & 1) {
438 			// Leader
439 			d = 1 + (frand () * 6);
440 
441 			Vec3Copy (org, orgVec);
442 			Vec3Copy (dir, dirVec);
443 			Vec3Scale (dirVec, d, dirVec);
444 
445 			orgVec[0] += crand () * 3;
446 			orgVec[1] += crand () * 3;
447 			orgVec[2] += crand () * 3;
448 
449 			dirVec[0] += crand () * (200 + fly);
450 			dirVec[1] += crand () * (200 + fly);
451 			dirVec[2] += crand () * (200 + fly);
452 
453 			flags |= PF_NODECAL;
454 		}
455 		else {
456 			// Follower
457 			Vec3Scale (dirVec, 0.75f + (crand () * 0.1f), dirVec);
458 
459 			flags &= ~PF_NODECAL;
460 		}
461 
462 		// Create the drip
463 		CG_SpawnParticle (
464 			orgVec[0] + (dir[0] * d),			orgVec[1] + (dir[1] * d),			orgVec[2] + (dir[2] * d),
465 			0,									0,									0,
466 			dirVec[0],							dirVec[1],							dirVec[2],
467 			0,									0,									-200,
468 			230 + (frand () * 5),				245 + (frand () * 10),				245 + (frand () * 10),
469 			0,									0,									0,
470 			1.0f,								-0.5f / (0.4f + (frand () * 0.9f)),
471 			0.25f + (frand () * 0.9f),			0.35f + (frand () * 0.5f),
472 			pRandBloodDrip (),					flags,
473 			pBloodDripThink,					qTrue,
474 			PART_STYLE_DIRECTION,
475 			PMAXBLDDRIPLEN*0.5f + (frand () * PMAXBLDDRIPLEN));
476 	}
477 }
478 
479 
480 /*
481 ===============
482 CG_BleedGreenEffect
483 ===============
484 */
CG_BleedGreenEffect(vec3_t org,vec3_t dir,int count)485 void CG_BleedGreenEffect (vec3_t org, vec3_t dir, int count)
486 {
487 	int			i, flags;
488 	float		d, gore, amount, fly;
489 	vec3_t		orgVec, dirVec;
490 
491 	gore = clamp ((cg_particleGore->floatVal + 1), 1, 11);
492 	amount = (count + gore) * 0.5f;
493 	fly = ((gore - 1) * 0.1f) * 30;
494 
495 	// Drip
496 	for (i=0 ; i<amount ; i++) {
497 		d = 1 + (frand () * 6);
498 
499 		Vec3Copy (org, orgVec);
500 		Vec3Copy (dir, dirVec);
501 		Vec3Scale (dirVec, d, dirVec);
502 
503 		orgVec[0] += crand () * 3;
504 		orgVec[1] += crand () * 3;
505 		orgVec[2] += crand () * 3;
506 
507 		dirVec[0] += crand () * (100 + fly);
508 		dirVec[1] += crand () * (100 + fly);
509 		dirVec[2] += crand () * (100 + fly);
510 
511 		flags = PF_SCALED|PF_GRAVITY|PF_GREENBLOOD;
512 		if (rand () % (int)(clamp (amount + 1, gore + 1, amount + 1) - gore))
513 			flags |= PF_NODECAL;
514 
515 		CG_SpawnParticle (
516 			orgVec[0] + (dir[0] * d),			orgVec[1] + (dir[1] * d),			orgVec[2] + (dir[2] * d),
517 			0,									0,									0,
518 			dirVec[0],							dirVec[1],							dirVec[2],
519 			0,									0,									-220,
520 			20.0f,								50.0f + (rand()%91),				20.0f,
521 			10.0f,								50.0f + (rand()%91),				10.0f,
522 			1.0f,								-0.5f / (0.4f + (frand () * 0.3f)),
523 			1.25f + (frand () * 0.2f),			1.35f + (frand () * 0.2f),
524 			pRandGrnBloodDrip (),				flags,
525 			pBloodDripThink,					qTrue,
526 			PART_STYLE_DIRECTION,
527 			PMAXBLDDRIPLEN);
528 	}
529 }
530 
531 
532 /*
533 ===============
534 CG_BubbleEffect
535 ===============
536 */
CG_BubbleEffect(vec3_t origin)537 void CG_BubbleEffect (vec3_t origin)
538 {
539 	float	rnum, rnum2;
540 
541 	// why bother spawn a particle that's just going to die anyways?
542 	if (!(cgi.CM_PointContents (origin, 0) & MASK_WATER))
543 		return;
544 
545 	rnum = 230 + (frand () * 25);
546 	rnum2 = 230 + (frand () * 25);
547 	CG_SpawnParticle (
548 		origin[0] + crand (),			origin[1] + crand (),			origin[2] + crand (),
549 		0,								0,								0,
550 		crand () * 4,					crand () * 4,					10 + (crand () * 4),
551 		0,								0,								0,
552 		rnum,							rnum,							rnum,
553 		rnum2,							rnum2,							rnum2,
554 		0.9f + (crand () * 0.1f),		-1.0f / (3 + (frand () * 0.2f)),
555 		0.1f + frand (),				0.1f + frand (),
556 		PT_WATERBUBBLE,					PF_SHADE|PF_LAVAONLY|PF_SLIMEONLY|PF_WATERONLY|PF_NOCLOSECULL,
557 		0,								qFalse,
558 		PART_STYLE_QUAD,
559 		0);
560 }
561 
562 
563 /*
564 ===============
565 CG_ExplosionBFGEffect
566 
567 Normally drawn at the feet of opponents when a bfg explodes
568 ===============
569 */
CG_ExplosionBFGEffect(vec3_t org)570 void CG_ExplosionBFGEffect (vec3_t org)
571 {
572 	int			i;
573 	float		randwhite;
574 	float		rnum, rnum2;
575 
576 	// Smoke
577 	for (i=0 ; i<8 ; i++) {
578 		rnum = 70 + (frand () * 40);
579 		rnum2 = 80 + (frand () * 40);
580 		CG_SpawnParticle (
581 			org[0] + (crand () * 4),		org[1] + (crand () * 4),		org[2] + (crand () * 4),
582 			0,								0,								0,
583 			crand () * 2,					crand () * 2,					crand () * 2,
584 			0,								0,								5 + (frand () * 6),
585 			rnum,							80 + rnum,						rnum,
586 			rnum2,							100+ rnum2,						rnum2,
587 			0.75f + (crand () * 0.1f),		-1.0f / (0.25f + (cg_particleSmokeLinger->floatVal * 0.1f) + (crand () * 0.1f)),
588 			35 + (crand () * 15),			140 + (crand () * 30),
589 			pRandGlowSmoke (),				0,
590 			pSmokeThink,					qTrue,
591 			PART_STYLE_QUAD,
592 			frand () * 361);
593 	}
594 
595 	// Dots
596 	for (i=0 ; i<256 ; i++) {
597 		randwhite = (rand()&1) ? 150 + (rand()%26) : 0.0f;
598 		CG_SpawnParticle (
599 			org[0] + (crand () * 20),		org[1] + (crand () * 20),			org[2] + (crand () * 20),
600 			0,								0,									0,
601 			crand () * 50,					crand () * 50,						crand () * 50,
602 			0,								0,									-40,
603 			randwhite,						75 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
604 			randwhite,						75 + (rand()%150) + randwhite,		(rand()%50) + randwhite,
605 			1.0f,							-0.8f / (0.8f + (frand () * 0.3f)),
606 			11 + (crand () * 10.5f),		0.6f + (crand () * 0.5f),
607 			PT_BFG_DOT,						PF_SCALED|PF_GRAVITY|PF_ALPHACOLOR|PF_NOCLOSECULL,
608 			pBounceThink,					qTrue,
609 			PART_STYLE_QUAD,
610 			0);
611 	}
612 }
613 
614 
615 /*
616 ===============
617 CG_FlareEffect
618 ===============
619 */
CG_FlareEffect(vec3_t origin,int type,float orient,float size,float sizevel,int color,int colorvel,float alpha,float alphavel)620 void __fastcall CG_FlareEffect (vec3_t origin, int type, float orient, float size, float sizevel, int color, int colorvel, float alpha, float alphavel)
621 {
622 	CG_SpawnParticle (
623 		origin[0],						origin[1],						origin[2],
624 		0,								0,								0,
625 		0,								0,								0,
626 		0,								0,								0,
627 		palRed (color),					palGreen (color),				palBlue (color),
628 		palRed (colorvel),				palGreen (colorvel),			palBlue (colorvel),
629 		alpha,							alphavel,
630 		size,							sizevel,
631 		type,							PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
632 		pFlareThink,					qTrue,
633 		PART_STYLE_QUAD,
634 		orient);
635 }
636 
637 
638 /*
639 ===============
640 CG_ItemRespawnEffect
641 ===============
642 */
CG_ItemRespawnEffect(vec3_t org)643 void CG_ItemRespawnEffect (vec3_t org)
644 {
645 	int			i;
646 
647 	for (i=0 ; i<64 ; i++) {
648 		CG_SpawnParticle (
649 			org[0] + (crand () * 9),		org[1] + (crand () * 9),		org[2] + (crand () * 9),
650 			0,								0,								0,
651 			crand () * 10,					crand () * 10,					crand () * 10,
652 			crand () * 10,					crand () * 10,					20 + (crand () * 10),
653 			135 + (frand () * 40),			180 + (frand () * 75),			135 + (frand () * 40),
654 			135 + (frand () * 40),			180 + (frand () * 75),			135 + (frand () * 40),
655 			1.0f,							-1.0f / (1.0f + (frand () * 0.3f)),
656 			4,								2,
657 			PT_ITEMRESPAWN,					PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
658 			0,								qFalse,
659 			PART_STYLE_QUAD,
660 			0);
661 	}
662 }
663 
664 
665 /*
666 ===============
667 CG_LogoutEffect
668 ===============
669 */
CG_LogoutEffect(vec3_t org,int type)670 void CG_LogoutEffect (vec3_t org, int type)
671 {
672 	int			i, rnum, rnum2;
673 	float		count = 300;
674 
675 	switch (type) {
676 	case MZ_LOGIN:
677 		// green
678 		for (i=0 ; i<count ; i++) {
679 			rnum = (rand() % 5);
680 			rnum2 = (rand() % 5);
681 			CG_SpawnParticle (
682 				org[0] - 16 + (frand () * 32),		org[1] - 16 + (frand () * 32),		org[2] - 24 + (frand () * 56),
683 				0,									0,									0,
684 				crand () * 20,						crand () * 20,						crand () * 20,
685 				0,									0,									-40,
686 				palRed (0xd0 + rnum),				palGreen (0xd0 + rnum),				palBlue (0xd0 + rnum),
687 				palRed (0xd0 + rnum2),				palGreen (0xd0 + rnum2),			palBlue (0xd0 + rnum2),
688 				1.0f,								-1.0f / (1.0f + (frand () * 0.3f)),
689 				3,									1,
690 				PT_GENERIC_GLOW,					PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
691 				0,									qFalse,
692 				PART_STYLE_QUAD,
693 				0);
694 		}
695 		break;
696 
697 	case MZ_LOGOUT:
698 		// red
699 		for (i=0 ; i<count ; i++) {
700 			rnum = (rand() % 5);
701 			rnum2 = (rand() % 5);
702 			CG_SpawnParticle (
703 				org[0] - 16 + (frand () * 32),		org[1] - 16 + (frand () * 32),		org[2] - 24 + (frand () * 56),
704 				0,									0,									0,
705 				crand () * 20,						crand () * 20,						crand () * 20,
706 				0,									0,									-40,
707 				palRed (0x40 + rnum),				palGreen (0x40 + rnum),				palBlue (0x40 + rnum),
708 				palRed (0x40 + rnum2),				palGreen (0x40 + rnum2),			palBlue (0x40 + rnum2),
709 				1.0f,								-1.0f / (1.0f + (frand () * 0.3f)),
710 				3,									1,
711 				PT_GENERIC_GLOW,					PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
712 				0,									qFalse,
713 				PART_STYLE_QUAD,
714 				0);
715 		}
716 		break;
717 
718 	default:
719 		// golden
720 		for (i=0 ; i<count ; i++) {
721 			rnum = (rand() % 5);
722 			rnum2 = (rand() % 5);
723 			CG_SpawnParticle (
724 				org[0] - 16 + (frand () * 32),		org[1] - 16 + (frand () * 32),		org[2] - 24 + (frand () * 56),
725 				0,									0,									0,
726 				crand () * 20,						crand () * 20,						crand () * 20,
727 				0,									0,									-40,
728 				palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
729 				palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
730 				1.0f,								-1.0f / (1.0f + (frand () * 0.3f)),
731 				3,									1,
732 				PT_GENERIC_GLOW,					PF_SCALED|PF_ALPHACOLOR|PF_NOCLOSECULL,
733 				0,									qFalse,
734 				PART_STYLE_QUAD,
735 				0);
736 		}
737 		break;
738 	}
739 }
740 
741 
742 /*
743 ===============
744 CG_ParticleEffect
745 
746 Wall impact puffs
747 ===============
748 */
CG_ParticleEffect(vec3_t org,vec3_t dir,int color,int count)749 void __fastcall CG_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
750 {
751 	int			i, rnum, rnum2;
752 	float		d;
753 
754 	if (cg.currGameMod == GAME_MOD_GLOOM) {
755 		switch (color) {
756 		// drone spit
757 		case 0xd0:
758 			CG_GloomDroneEffect (org, dir);
759 			return;
760 
761 		// slash
762 		case 0xe0:
763 			d = 5 + ((rand()%31*0.1f) - 1);
764 			CG_SpawnDecal (
765 				org[0],								org[1],								org[2],
766 				dir[0],								dir[1],								dir[2],
767 				255,								255,								255,
768 				0,									0,									0,
769 				0.9f + (crand () * 0.1f),			0.8f,
770 				d,
771 				dRandSlashMark (),					DF_ALPHACOLOR,
772 				0,									qFalse,
773 				0,									frand () * 360);
774 
775 			for (i=0 ; i<count ; i++) {
776 				d = (float)(rand()%17);
777 				rnum = (rand()%5);
778 				rnum2 = (rand()%5);
779 
780 				CG_SpawnParticle (
781 					org[0] + (crand () * 4) + d*dir[0],	org[1] + (crand () * 4) + d*dir[1],	org[2] + (crand () * 4) + d*dir[2],
782 					0,									0,									0,
783 					dir[0] * crand () * 3,				dir[1] * crand () * 3,				dir[2] * crand () * 3,
784 					(dir[0] * (crand() * 8)) + (crand () * 4),
785 					(dir[1] * (crand() * 8)) + (crand () * 4),
786 					(dir[2] * (crand() * 8)) + (crand () * 4) - (frand() * 60),
787 					palRed (color + rnum),				palGreen (color + rnum),			palBlue (color + rnum),
788 					palRed (color + rnum2),				palGreen (color + rnum2),			palBlue (color + rnum2),
789 					1.0f,								-1.0f / (0.5f + (frand () * 0.3f)),
790 					0.5f,								0.6f,
791 					PT_GENERIC_GLOW,					PF_SCALED|PF_ALPHACOLOR,
792 					0,									qFalse,
793 					PART_STYLE_QUAD,
794 					0);
795 			}
796 
797 			CG_SparkEffect (org, dir, color, color, count, 1, 1);
798 			return;
799 
800 		// exterm
801 		case 0x75:
802 			CG_BlasterBlueParticles (org, dir);
803 			return;
804 		}
805 	}
806 
807 	switch (color) {
808 	// blood
809 	case 0xe8:
810 		CG_BleedEffect (org, dir, count);
811 		return;
812 
813 	// bullet mark
814 	case 0x0:
815 		CG_RicochetEffect (org, dir, count);
816 		return;
817 
818 	// default
819 	default:
820 		for (i=0 ; i<count ; i++) {
821 			d = (float)(rand()%31);
822 			rnum = (rand()%5);
823 			rnum2 = (rand()%5);
824 
825 			CG_SpawnParticle (
826 				org[0] + ((rand()%7)-4) + d*dir[0],	org[1] + ((rand()%7)-4) + d*dir[1],	org[2] + ((rand()%7)-4) + d*dir[2],
827 				0,									0,									0,
828 				crand () * 20,						crand () * 20,						crand () * 20,
829 				0,									0,									-40,
830 				palRed (color + rnum),				palGreen (color + rnum),			palBlue (color + rnum),
831 				palRed (color + rnum2),				palGreen (color + rnum2),			palBlue (color + rnum2),
832 				1,									-1.0f / (0.5f + (frand () * 0.3f)),
833 				1,									1,
834 				PT_GENERIC,							PF_SCALED,
835 				0,									qFalse,
836 				PART_STYLE_QUAD,
837 				0);
838 		}
839 		return;
840 	}
841 }
842 
843 
844 /*
845 ===============
846 CG_ParticleEffect2
847 ===============
848 */
CG_ParticleEffect2(vec3_t org,vec3_t dir,int color,int count)849 void __fastcall CG_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
850 {
851 	if (color == 0xe2 && cg.currGameMod == GAME_MOD_GLOOM) {
852 		CG_GloomRepairEffect (org, dir, count);
853 	}
854 	else {
855 		int			i, rnum, rnum2;
856 		float		d;
857 
858 		for (i=0 ; i<count ; i++) {
859 			d = frand () * 7;
860 			rnum = (rand () % 5);
861 			rnum2 = (rand () % 5);
862 
863 			CG_SpawnParticle (
864 				org[0] + (crand () * 4) + d*dir[0],	org[1] + (crand () * 4) + d*dir[1],	org[2] + (crand () * 4) + d*dir[2],
865 				0,									0,									0,
866 				crand () * 20,						crand () * 20,						crand () * 20,
867 				0,									0,									-40,
868 				palRed (color + rnum),				palGreen (color + rnum),			palBlue (color + rnum),
869 				palRed (color + rnum2),				palGreen (color + rnum2),			palBlue (color + rnum2),
870 				1,									-1.0f / (0.5f + (frand () * 0.3f)),
871 				1,									1,
872 				PT_GENERIC,							PF_SCALED,
873 				0,									qFalse,
874 				PART_STYLE_QUAD,
875 				0);
876 		}
877 	}
878 }
879 
880 
881 /*
882 ===============
883 CG_ParticleEffect3
884 ===============
885 */
CG_ParticleEffect3(vec3_t org,vec3_t dir,int color,int count)886 void __fastcall CG_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
887 {
888 	int			i, rnum, rnum2;
889 	float		d;
890 
891 	for (i=0 ; i<count ; i++) {
892 		d = frand () * 7;
893 		rnum = (rand () % 5);
894 		rnum2 = (rand () % 5);
895 
896 		CG_SpawnParticle (
897 			org[0] + (crand () * 4) + d*dir[0],	org[1] + (crand () * 4) + d*dir[1],	org[2] + (crand () * 4) + d*dir[2],
898 			0,									0,									0,
899 			crand () * 20,						crand () * 20,						crand () * 20,
900 			0,									0,									40,
901 			palRed (color + rnum),				palGreen (color + rnum),			palBlue (color + rnum),
902 			palRed (color + rnum2),				palGreen (color + rnum2),			palBlue (color + rnum2),
903 			1.0f,								-1.0f / (0.5f + (frand () * 0.3f)),
904 			1,									1,
905 			PT_GENERIC,							PF_SCALED,
906 			0,									qFalse,
907 			PART_STYLE_QUAD,
908 			0);
909 	}
910 }
911 
912 
913 /*
914 ===============
915 CG_ParticleSmokeEffect
916 
917 like the steam effect, but unaffected by gravity
918 ===============
919 */
CG_ParticleSmokeEffect(vec3_t org,vec3_t dir,int color,int count,int magnitude)920 void __fastcall CG_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
921 {
922 	int			i, rnum, rnum2;
923 	float		d;
924 	vec3_t		r, u, pvel;
925 
926 	MakeNormalVectorsf (dir, r, u);
927 
928 	for (i=0 ; i<count ; i++) {
929 		Vec3Scale (dir, magnitude, pvel);
930 		d = crand() * magnitude / 3;
931 		Vec3MA (pvel, d, r, pvel);
932 		d = crand() * magnitude/ 3;
933 		Vec3MA (pvel, d, u, pvel);
934 
935 		rnum = (rand () % 5);
936 		rnum2 = (rand () % 5);
937 		CG_SpawnParticle (
938 			org[0] + magnitude*0.1f*crand(),org[1] + magnitude*0.1f*crand(),org[2] + magnitude*0.1f*crand(),
939 			0,								0,								0,
940 			pvel[0],						pvel[1],						pvel[2],
941 			0,								0,								0,
942 			palRed (color + rnum),			palGreen (color + rnum),		palBlue (color + rnum),
943 			palRed (color + rnum2),			palGreen (color + rnum2),		palBlue (color + rnum2),
944 			0.9f + (crand () * 0.1f),		-1.0f / (0.5f + (cg_particleSmokeLinger->floatVal * 0.5f) + (frand () * 0.3f)),
945 			5 + (frand () * 4),				10 + (frand () * 4),
946 			pRandSmoke (),					PF_SHADE,
947 			pSmokeThink,					qTrue,
948 			PART_STYLE_QUAD,
949 			frand () * 360);
950 	}
951 }
952 
953 
954 /*
955 ===============
956 CG_RicochetEffect
957 ===============
958 */
CG_RicochetEffect(vec3_t org,vec3_t dir,int count)959 void __fastcall CG_RicochetEffect (vec3_t org, vec3_t dir, int count)
960 {
961 	int		i, rnum, rnum2;
962 	float	d;
963 
964 	// Bullet mark
965 	CG_SpawnDecal (
966 		org[0],								org[1],								org[2],
967 		dir[0],								dir[1],								dir[2],
968 		255,								255,								255,
969 		0,									0,									0,
970 		0.9f + (crand () * 0.1f),			0.8f,
971 		4 + crand (),
972 		DT_BULLET,							DF_ALPHACOLOR,
973 		0,									qFalse,
974 		0,									frand () * 360);
975 
976 	// Dots
977 	for (i=0 ; i<count ; i++) {
978 		d = (float)(rand()%17);
979 		rnum = (rand()%3) + 2;
980 		rnum2 = (rand()%5);
981 
982 		CG_SpawnParticle (
983 			org[0] + ((rand()%7)-3) + d*dir[0],	org[1] + ((rand()%7)-3) + d*dir[1],	org[2] + ((rand()%7)-3) + d*dir[2],
984 			0,									0,									0,
985 			dir[0] * crand () * 3,				dir[1] * crand () * 3,				dir[2] * crand () * 3,
986 			(dir[0] * (crand() * 8)) + ((rand()%7)-3),
987 			(dir[1] * (crand() * 8)) + ((rand()%7)-3),
988 			(dir[2] * (crand() * 8)) + ((rand()%7)-3) - (40 * frand() * 1.5f),
989 			palRed (rnum),						palGreen (rnum),					palBlue (rnum),
990 			palRed (rnum2),						palGreen (rnum2),					palBlue (rnum2),
991 			1.0f,								-1.0f / (0.5f + (frand() * 0.2f)),
992 			0.5f,								0.6f,
993 			PT_GENERIC,							PF_SCALED|PF_NOCLOSECULL,
994 			0,									qFalse,
995 			PART_STYLE_QUAD,
996 			0);
997 	}
998 
999 	CG_SparkEffect (org, dir, 10, 10, count/2, 1, 1);
1000 }
1001 
1002 
1003 /*
1004 ===============
1005 CG_RocketFireParticles
1006 ===============
1007 */
CG_RocketFireParticles(vec3_t org,vec3_t dir)1008 void CG_RocketFireParticles (vec3_t org, vec3_t dir)
1009 {
1010 	float	rnum, rnum2;
1011 
1012 	// FIXME: need to use dir to tell smoke where to fly to
1013 	rnum = 60 + (frand () * 50);
1014 	rnum2 = 70 + (frand () * 50);
1015 
1016 	CG_SpawnParticle (
1017 		org[0] + (crand () * 4),		org[1] + (crand () * 4),		org[2] + (crand () * 4) + 16,
1018 		0,								0,								0,
1019 		crand () * 2,					crand () * 2,					crand () * 2,
1020 		crand () * 2,					crand () * 2,					crand () + (frand () * 4),
1021 		rnum,							rnum,							rnum,
1022 		rnum2,							rnum2,							rnum2,
1023 		0.4f,							-1.0f / (1.75f + (crand () * 0.25f)),
1024 		65 + (crand () * 10),			450 + (crand () * 10),
1025 		pRandSmoke (),					PF_SHADE,
1026 		pSmokeThink,					qTrue,
1027 		PART_STYLE_QUAD,
1028 		frand () * 360);
1029 }
1030 
1031 
1032 /*
1033 ===============
1034 CG_SparkEffect
1035 ===============
1036 */
CG_SparkEffect(vec3_t org,vec3_t dir,int color,int colorvel,int count,float smokeScale,float lifeScale)1037 void __fastcall CG_SparkEffect (vec3_t org, vec3_t dir, int color, int colorvel, int count, float smokeScale, float lifeScale)
1038 {
1039 	int			i;
1040 	float		d, d2;
1041 	float		rnum, rnum2;
1042 
1043 	// Sparks
1044 	for (i=0 ; i<count ; i++) {
1045 		d = 140 + (crand () * 40) * lifeScale;
1046 		d2 = 1 + crand ();
1047 		rnum = (float)(rand () % 5);
1048 		rnum2 = (float)(rand () % 5);
1049 
1050 		CG_SpawnParticle (
1051 			org[0] + (dir[0] * d2) + crand (),	org[1] + (dir[1] * d2) + crand (),	org[2] + (dir[2] * d2) + crand (),
1052 			0,									0,									0,
1053 			(dir[0] * d) + (crand () * 24),		(dir[1] * d) + (crand () * 24),		(dir[2] * d) + (crand () * 24),
1054 			0,									0,									0,
1055 			palRed ((int)(color + rnum)),		palGreen ((int)(color + rnum)),		palBlue ((int)(color + rnum)),
1056 			palRed ((int)(colorvel + rnum2)),	palGreen ((int)(colorvel + rnum2)),	palBlue ((int)(colorvel + rnum2)),
1057 			1,									-1.0f / (0.175f + (frand() * 0.05f)),
1058 			0.4f,								0.4f,
1059 			PT_SPARK,							PF_ALPHACOLOR,
1060 			pRicochetSparkThink,				qTrue,
1061 			PART_STYLE_DIRECTION,
1062 			16 + (crand () * 4));
1063 	}
1064 
1065 	// Smoke
1066 	for (i=1 ; i<4 ; i++) {
1067 		rnum = 60 + (frand () * 50);
1068 		rnum2 = 70 + (frand () * 50);
1069 		CG_SpawnParticle (
1070 			org[0] + (i*dir[0]*2.5f) + crand (),org[1] + (i*dir[1]*2.5f) + crand (),org[2] + (i*dir[2]*2.5f) + crand (),
1071 			0,									0,									0,
1072 			0,									0,									0,
1073 			0,									0,									i*3.5f,
1074 			rnum,								rnum,								rnum,
1075 			rnum2,								rnum2,								rnum2,
1076 			0.9f + (crand () * 0.1f),			-1.0f / (1.5f + (cg_particleSmokeLinger->floatVal * 0.05f) + (crand() * 0.2f)),
1077 			(4 + (frand () * 3)) * smokeScale,	(12 + (crand () * 3)) * smokeScale,
1078 			pRandSmoke (),						PF_SHADE|PF_NOCLOSECULL,
1079 			pFastSmokeThink,					qTrue,
1080 			PART_STYLE_QUAD,
1081 			frand () * 360);
1082 	}
1083 
1084 	// Burst smoke
1085 	for (i=1 ; i<7 ; i++) {
1086 		rnum = 60 + (frand () * 50);
1087 		rnum2 = 70 + (frand () * 50);
1088 		CG_SpawnParticle (
1089 			org[0]+(i*dir[0]*3.25f)+crand()*2,	org[1]+(i*dir[1]*3.25f)+crand()*2,	org[2]+(i*dir[2]*3.25f)+crand()*2,
1090 			0,									0,									0,
1091 			0,									0,									0,
1092 			0,									0,									5,
1093 			rnum,								rnum,								rnum,
1094 			rnum2,								rnum2,								rnum2,
1095 			0.9f + (crand () * 0.1f),			-1.0f / (1.25f + (cg_particleSmokeLinger->floatVal * 0.05f) + (crand() * 0.2f)),
1096 			(4 + (frand () * 3)) * smokeScale,	(12 + (crand () * 3)) * smokeScale,
1097 			pRandSmoke (),						PF_SHADE|PF_NOCLOSECULL,
1098 			pFastSmokeThink,					qTrue,
1099 			PART_STYLE_QUAD,
1100 			frand () * 360);
1101 	}
1102 }
1103 
1104 
1105 /*
1106 ===============
1107 CG_SplashEffect
1108 ===============
1109 */
CG_SplashParticles(vec3_t org,vec3_t dir,int color,int count,qBool glow)1110 void __fastcall CG_SplashParticles (vec3_t org, vec3_t dir, int color, int count, qBool glow)
1111 {
1112 	int		i, rnum, rnum2;
1113 	vec3_t	angle, dirVec;
1114 	float	d;
1115 
1116 	// Ripple
1117 	rnum = (rand () % 5);
1118 	rnum2 = (rand () % 5);
1119 
1120 	VecToAngleRolled (dir, frand () * 360, angle);
1121 	CG_SpawnParticle (
1122 		org[0] + dir[0],					org[1] + dir[0],					org[2] + dir[0],
1123 		angle[0],							angle[1],							angle[2],
1124 		0,									0,									0,
1125 		0,									0,									0,
1126 		palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1127 		palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1128 		0.5f + (crand () * 0.1f),			-1.0f / (1.9f + (frand () * 0.1f)),
1129 		7 + (crand () * 2),					24 + (crand () * 3),
1130 		PT_WATERRIPPLE,						PF_SCALED,
1131 		NULL,								qFalse,
1132 		PART_STYLE_ANGLED,
1133 		0);
1134 
1135 	// Ring
1136 	rnum = (rand () % 5);
1137 	rnum2 = (rand () % 5);
1138 
1139 	VecToAngleRolled (dir, frand () * 360, angle);
1140 	CG_SpawnParticle (
1141 		org[0] + dir[0],					org[1] + dir[0],					org[2] + dir[0],
1142 		angle[0],							angle[1],							angle[2],
1143 		0,									0,									0,
1144 		0,									0,									0,
1145 		palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1146 		palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1147 		0.9f + (crand () * 0.1f),			-1.0f / (0.5f + (frand () * 0.1f)),
1148 		2 + crand (),						15 + (crand () * 2),
1149 		PT_WATERRING,						PF_SCALED,
1150 		NULL,								qFalse,
1151 		PART_STYLE_ANGLED,
1152 		0);
1153 
1154 	// Impact
1155 	rnum = (rand () % 5);
1156 	rnum2 = (rand () % 5);
1157 
1158 	VecToAngleRolled (dir, frand () * 360, angle);
1159 	CG_SpawnParticle (
1160 		org[0] + dir[0],					org[1] + dir[0],					org[2] + dir[0],
1161 		angle[0],							angle[1],							angle[2],
1162 		0,									0,									0,
1163 		0,									0,									0,
1164 		palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1165 		palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1166 		0.5f + (crand () * 0.1f),			-1.0f / (0.2f + (frand () * 0.1f)),
1167 		5 + (crand () * 2),					25 + (crand () * 3),
1168 		PT_WATERIMPACT,						PF_SCALED,
1169 		NULL,								qFalse,
1170 		PART_STYLE_ANGLED,
1171 		0);
1172 
1173 	// Mist
1174 	for (i=0 ; i<2 ; i++) {
1175 		d = 1 + (frand () * 3);
1176 		rnum = (rand () % 5);
1177 		rnum2 = (rand () % 5);
1178 
1179 		CG_SpawnParticle (
1180 			org[0] + (dir[0] * d),				org[1] + (dir[1] * d),				org[2] + (dir[2] * d),
1181 			0,									0,									0,
1182 			d * dir[0],							d * dir[1],							d * dir[2],
1183 			0,									0,									100,
1184 			palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1185 			palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1186 			0.6f + (crand () * 0.1f),			-1.0f / (0.4f + (frand () * 0.1f)),
1187 			5 + (crand () * 5),					35 + (crand () * 5),
1188 			glow ? PT_WATERMIST_GLOW : PT_WATERMIST,
1189 			PF_SCALED|PF_GRAVITY|PF_NOCLOSECULL,
1190 			0,									qFalse,
1191 			PART_STYLE_QUAD,
1192 			frand () * 360);
1193 	}
1194 
1195 	// Point-away plume
1196 	d = 10 + crand ();
1197 	rnum = (rand () % 5);
1198 	rnum2 = (rand () % 5);
1199 	CG_SpawnParticle (
1200 		org[0] + (dir[0] * 7.5f),			org[1] + (dir[1] * 7.5f),			org[2] + (dir[2] * 7.5f),
1201 		dir[0],								dir[1],								dir[2],
1202 		0,									0,									0,
1203 		0,									0,									0,
1204 		palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1205 		palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1206 		1.0f,								-1.0f / (0.2f + (frand() * 0.2f)),
1207 		9,									9,
1208 		glow ? PT_WATERPLUME_GLOW : PT_WATERPLUME,		0,
1209 		NULL,								qFalse,
1210 		PART_STYLE_DIRECTION,
1211 		0);
1212 
1213 	// Flying droplets
1214 	for (i=0 ; i<count*2 ; i++) {
1215 		d = 34 + (frand () * 14);
1216 		rnum = (rand () % 5);
1217 		rnum2 = (rand () % 5);
1218 
1219 		dirVec[0] = dir[0] + crand ();
1220 		dirVec[1] = dir[1] + crand ();
1221 		dirVec[2] = dir[2] + crand ();
1222 
1223 		CG_SpawnParticle (
1224 			org[0] + dir[0],					org[1] + dir[1],					org[2] + dir[2],
1225 			0,									0,									0,
1226 			dirVec[0] * (frand () * 74),		dirVec[1] * (frand () * 74),		dirVec[2] * (frand () * 74),
1227 			0,									0,									50,
1228 			palRed (color + rnum) + 64,			palGreen (color + rnum) + 64,		palBlue (color + rnum) + 64,
1229 			palRed (color + rnum2) + 64,		palGreen (color + rnum2) + 64,		palBlue (color + rnum2) + 64,
1230 			0.7f + (frand () * 0.3f),			-1.0f / (0.5f + (frand () * 0.3f)),
1231 			1.5f + crand (),					0.15 + (crand () * 0.125f),
1232 			PT_WATERDROPLET,					PF_GRAVITY|PF_AIRONLY|PF_NOCLOSECULL,
1233 			pDropletThink,						qTrue,
1234 			PART_STYLE_QUAD,
1235 			frand () * 360);
1236 	}
1237 }
1238 
1239 byte		clrtbl[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
CG_SplashEffect(vec3_t org,vec3_t dir,int color,int count)1240 void __fastcall CG_SplashEffect (vec3_t org, vec3_t dir, int color, int count)
1241 {
1242 	// this function merely decides what route to take
1243 	switch (color) {
1244 	case SPLASH_UNKNOWN:
1245 		CG_RicochetEffect (org, dir, count);
1246 		break;
1247 	case SPLASH_SPARKS:
1248 		CG_SparkEffect (org, dir, 12, 12, count, 1, 4);
1249 		break;
1250 	case SPLASH_BLUE_WATER:
1251 		CG_SplashParticles (org, dir, 0x09, count, qFalse);
1252 		break;
1253 	case SPLASH_BROWN_WATER:
1254 		CG_ParticleEffect (org, dir, clrtbl[color], count);
1255 		break;
1256 	case SPLASH_SLIME: // also gloom drone spit
1257 		if (cg.currGameMod == GAME_MOD_GLOOM)
1258 			CG_GloomDroneEffect (org, dir);
1259 		else
1260 			CG_SplashParticles (org, dir, clrtbl[color], count, qTrue);
1261 		break;
1262 	case SPLASH_LAVA:
1263 		CG_SplashParticles (org, dir, clrtbl[color], count, qTrue);
1264 		break;
1265 	case SPLASH_BLOOD:
1266 		CG_BleedEffect (org, dir, count);
1267 		break;
1268 	}
1269 }
1270 
1271 /*
1272 =============================================================================
1273 
1274 	MISCELLANEOUS PARTICLE EFFECTS
1275 
1276 =============================================================================
1277 */
1278 
1279 /*
1280 ===============
1281 CG_BigTeleportParticles
1282 ===============
1283 */
CG_BigTeleportParticles(vec3_t org)1284 void CG_BigTeleportParticles (vec3_t org)
1285 {
1286 	int			i;
1287 	float		angle, dist;
1288 
1289 	for (i=0 ; i<4096 ; i++) {
1290 		angle = (M_PI * 2.0f) * (rand () & 1023) / 1023.0f;
1291 		dist = (float)(rand () & 31);
1292 
1293 		CG_SpawnParticle (
1294 			org[0] + (float)cos (angle) * dist,	org[1] + (float)sin (angle) * dist,	org[2] + 8 + (frand () * 90),
1295 			0,								0,								0,
1296 			(float)cos (angle) * (70+(rand()&63)),	(float)sin (angle) * (70+(rand()&63)),	-100.0f + (rand () & 31),
1297 			-(float)cos (angle) * 100,				-(float)sin (angle) * 100,				160.0f,
1298 			255,							255,							255,
1299 			230,							230,							230,
1300 			1.0f,							-0.3f / (0.2f + (frand () * 0.3f)),
1301 			10,								3,
1302 			PT_FLAREGLOW,					PF_SCALED|PF_NOCLOSECULL,
1303 			0,								qFalse,
1304 			PART_STYLE_QUAD,
1305 			0);
1306 	}
1307 }
1308 
1309 
1310 /*
1311 ===============
1312 CG_BlasterTip
1313 ===============
1314 */
CG_BlasterTip(vec3_t start,vec3_t end)1315 void CG_BlasterTip (vec3_t start, vec3_t end)
1316 {
1317 	int		rnum, rnum2;
1318 	vec3_t	move, vec;
1319 	float	len, dec;
1320 	int		i;
1321 
1322 	// Bubbles
1323 	CG_BubbleEffect (start);
1324 
1325 	// Smoke
1326 	dec = 1 + (cg_particleSmokeLinger->floatVal * 0.2f);
1327 	for (i=0 ; i<dec ; i++) {
1328 		rnum = (rand () % 5);
1329 		rnum2 = (rand () % 5);
1330 
1331 		CG_SpawnParticle (
1332 			start[0] + (crand()*2),				start[1] + (crand()*2),				start[2] + (crand()*2),
1333 			0,									0,									0,
1334 			0,									0,									0,
1335 			0,									0,									5 + (frand () * 25),
1336 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
1337 			palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
1338 			0.9f + (frand() * 0.1f),			-1.0f / (0.25f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
1339 			5 + crand (),						16 + (crand () * 8),
1340 			pRandGlowSmoke (),					PF_ALPHACOLOR,
1341 			NULL,								qFalse,
1342 			PART_STYLE_QUAD,
1343 			frand () * 360);
1344 	}
1345 
1346 	// Dot trail
1347 	Vec3Copy (start, move);
1348 	Vec3Subtract (start, end, vec);
1349 	len = VectorNormalizeFastf (vec);
1350 
1351 	dec = 2.5f;
1352 	Vec3Scale (vec, dec, vec);
1353 
1354 	for (; len>0 ; Vec3Add (move, vec, move)) {
1355 		len -= dec;
1356 
1357 		rnum = (rand () % 5);
1358 		rnum2 = (rand () % 5);
1359 
1360 		CG_SpawnParticle (
1361 			move[0] + crand (),					move[1] + crand (),					move[2] + crand (),
1362 			0,									0,									0,
1363 			crand () * 2,						crand () * 2,						crand () * 2,
1364 			crand () * 2,						crand () * 2,						crand () * 2,
1365 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
1366 			palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
1367 			1.0f,								-15,
1368 			4 + (frand () * 4),					1.5f + (frand () * 2.5f),
1369 			PT_BLASTER_RED,						PF_NOCLOSECULL,
1370 			0,									qFalse,
1371 			PART_STYLE_QUAD,
1372 			0);
1373 	}
1374 }
1375 
1376 
1377 /*
1378 ===============
1379 CG_ExplosionParticles
1380 
1381 FIXME: does scale actually scale the effect?
1382 ===============
1383 */
CG_ExplosionParticles(vec3_t org,float scale,qBool exploOnly,qBool inWater)1384 void CG_ExplosionParticles (vec3_t org, float scale, qBool exploOnly, qBool inWater)
1385 {
1386 	int			i, j;
1387 	float		rnum, rnum2;
1388 	float		waterOffset;
1389 	vec3_t		normal, angle, endPos;
1390 	float		distScale;
1391 
1392 	CG_ExploRattle (org, scale);
1393 
1394 	// Sparks
1395 	for (i=0 ; i<20 ; i++) {
1396 		CG_SpawnParticle (
1397 			org[0] + (crand () * 10 * scale),	org[1] + (crand () * 10 * scale),	org[2] + (crand () * 10 * scale),
1398 			0,									0,									0,
1399 			crand () * (140 * scale),			crand () * (140 * scale),			crand () * (140 * scale),
1400 			0,									0,									0,
1401 			235 + (frand () * 20),				225 + (frand () * 20),				205,
1402 			235 + (frand () * 20),				225 + (frand () * 20),				205,
1403 			0.9f,								-1.5f / (0.6f + (crand () * 0.15f)),
1404 			0.3f,								0.4f,
1405 			PT_SPARK,							0,
1406 			pSparkGrowThink,					qTrue,
1407 			PART_STYLE_DIRECTION,
1408 			(16 + (crand () * 4)) * scale);
1409 	}
1410 
1411 	if (inWater) {
1412 		waterOffset = 155;
1413 
1414 		// Bubbles
1415 		for (i=0 ; i<50*scale ; i++) {
1416 			rnum = 230 + (frand () * 25);
1417 			rnum2 = 230 + (frand () * 25);
1418 			CG_SpawnParticle (
1419 				org[0] + crand (),				org[1] + crand (),				org[2] + crand (),
1420 				0,								0,								0,
1421 				crand () * (164 * scale),		crand () * (164 * scale),		10 + (crand () * (164 * scale)),
1422 				0,								0,								0,
1423 				rnum,							rnum,							rnum,
1424 				rnum2,							rnum2,							rnum2,
1425 				0.9f + (crand () * 0.1f),		-1.0f / (1 + (frand () * 0.2f)),
1426 				0.1f + frand (),				0.1f + frand (),
1427 				PT_WATERBUBBLE,					PF_SHADE|PF_LAVAONLY|PF_SLIMEONLY|PF_WATERONLY,
1428 				0,								qFalse,
1429 				PART_STYLE_QUAD,
1430 				0);
1431 		}
1432 	}
1433 	else
1434 		waterOffset = 0;
1435 
1436 	// Explosion anim
1437 	CG_SpawnParticle (
1438 		org[0],								org[1],								org[2],
1439 		0,									0,									0,
1440 		0,									0,									0,
1441 		0,									0,									0,
1442 		255 - waterOffset,					255 - waterOffset,					255,
1443 		255 - waterOffset,					255 - waterOffset,					255,
1444 		1.0f,								-3 + (crand () * 0.1f) + (scale * 0.33f),
1445 		(40 + (crand () * 5)) * scale,		(130 + (crand () * 10)) * scale,
1446 		PT_EXPLO1,							PF_NOCLOSECULL,
1447 		pExploAnimThink,					qTrue,
1448 		PART_STYLE_QUAD,
1449 		crand () * 12);
1450 
1451 	// Explosion embers
1452 	for (i=0 ; i<2 ; i++) {
1453 		CG_SpawnParticle (
1454 			org[0] + (crand () * 3),			org[1] + (crand () * 3),			org[2] + (crand () * 3),
1455 			0,									0,									0,
1456 			0,									0,									0,
1457 			0,									0,									0,
1458 			255 - waterOffset,					255 - waterOffset,					255,
1459 			255 - waterOffset,					255 - waterOffset,					255,
1460 			1.0f,								-3.15f + (crand () * 0.1f) + (scale * 0.33f),
1461 			(2 + crand ()) * scale,				(155 + (crand () * 10)) * scale,
1462 			i?PT_EXPLOEMBERS1:PT_EXPLOEMBERS2,	PF_NOCLOSECULL,
1463 			0,									qFalse,
1464 			PART_STYLE_QUAD,
1465 			crand () * 360);
1466 	}
1467 
1468 	if (exploOnly)
1469 		return;
1470 
1471 	// Explosion flash
1472 	CG_SpawnParticle (
1473 		org[0],								org[1],								org[2],
1474 		0,									0,									0,
1475 		crand () * 20,						crand () * 20,						crand () * 20,
1476 		0,									0,									0,
1477 		255 - waterOffset,					255 - waterOffset,					255,
1478 		255 - waterOffset,					255 - waterOffset,					255,
1479 		1.0f,								-4.5f + (crand () * 0.1f) + (scale * 0.33f),
1480 		(2 + crand ()) * scale,				(130 + (crand () * 10)) * scale,
1481 		PT_EXPLOFLASH,						PF_NOCLOSECULL,
1482 		0,									qFalse,
1483 		PART_STYLE_QUAD,
1484 		crand () * 360);
1485 
1486 	// Smoke
1487 	j = scale + 2;
1488 	for (i=0 ; i<j ; i++) {
1489 		rnum = 70 + (frand () * 40);
1490 		rnum2 = 80 + (frand () * 40);
1491 		CG_SpawnParticle (
1492 			org[0] + (crand () * 4),		org[1] + (crand () * 4),		org[2] + (crand () * 4),
1493 			0,								0,								0,
1494 			crand () * 2,					crand () * 2,					crand () * 2,
1495 			0,								0,								3 + (frand () * 4),
1496 			rnum,							rnum,							rnum,
1497 			rnum2,							rnum2,							rnum2,
1498 			0.75f + (crand () * 0.1f),		-1.0f / (1.5f + (cg_particleSmokeLinger->floatVal * 0.4f) + (crand () * 0.2f)),
1499 			(40 + (crand () * 5)) * scale,	(100 + (crand () * 10)) * scale,
1500 			pRandSmoke (),					PF_SHADE,
1501 			pSmokeThink,					qTrue,
1502 			PART_STYLE_QUAD,
1503 			frand () * 361);
1504 	}
1505 
1506 	// Explosion mark
1507 	if (!CG_FindExplosionDir (org, 30 * scale, endPos, normal))
1508 		return;
1509 
1510 	// Directional smoke
1511 	j = scale + 3;
1512 	for (i=1 ; i<j ; i++) {
1513 		// Color randomization
1514 		rnum = 70 + (frand () * 40);
1515 		rnum2 = 80 + (frand () * 40);
1516 
1517 		distScale = (float)i/(float)j;
1518 
1519 		// Spawn particles
1520 		CG_SpawnParticle (
1521 			org[0] + (crand () * 4),		org[1] + (crand () * 4),		org[2] + (crand () * 4),
1522 			0,								0,								0,
1523 			normal[0] * 90 * distScale,		normal[1] * 90 * distScale,		normal[2] * 90 * distScale,
1524 			normal[0] * -32 * distScale,	normal[1] * -32 * distScale,	(normal[2] * -32 * distScale) + 5 + (frand () * 6),
1525 			rnum,							rnum,							rnum,
1526 			rnum2,							rnum2,							rnum2,
1527 			0.75f + (crand () * 0.1f),		-1.0f / (1.5f + (cg_particleSmokeLinger->floatVal * 0.1f) + (crand () * 0.2f)),
1528 			(30 + (crand () * 5)) * scale,	(100 + (crand () * 10)) * scale,
1529 			pRandSmoke (),					PF_SHADE,
1530 			pSmokeThink,					qTrue,
1531 			PART_STYLE_QUAD,
1532 			frand () * 361);
1533 	}
1534 
1535 	// Directional sparks
1536 	for (i=0 ; i<25 ; i++) {
1537 		CG_SpawnParticle (
1538 			org[0] + (crand () * 10 * scale),	org[1] + (crand () * 10 * scale),	org[2] + (crand () * 10 * scale),
1539 			0,									0,									0,
1540 			(normal[0] + (crand () * 0.4f)) * 175,
1541 			(normal[1] + (crand () * 0.4f)) * 175,
1542 			(normal[2] + (crand () * 0.4f)) * 175,
1543 			0,									0,									0,
1544 			235 + (frand () * 20),				225 + (frand () * 20),				205,
1545 			235 + (frand () * 20),				225 + (frand () * 20),				205,
1546 			0.9f,								-1.5f / (0.5f + (crand () * 0.15f)),
1547 			0.3f,								0.4f,
1548 			PT_SPARK,							0,
1549 			pSparkGrowThink,					qTrue,
1550 			PART_STYLE_DIRECTION,
1551 			(16 + (crand () * 4)) * scale);
1552 	}
1553 
1554 	// Burn mark
1555 	CG_SpawnDecal (
1556 		endPos[0],							endPos[1],							endPos[2],
1557 		normal[0],							normal[1],							normal[2],
1558 		255,								255,								255,
1559 		0,									0,									0,
1560 		0.9f + (crand () * 0.1f),			0.8f,
1561 		(35 + (frand () * 5)) * scale,
1562 		dRandExploMark (),					DF_ALPHACOLOR,
1563 		0,									qFalse,
1564 		0,									frand () * 360);
1565 
1566 	// Only do these for small effects
1567 	if (scale <= 2.0f) {
1568 		VecToAngleRolled (normal, 180, angle);
1569 		rnum = Vec3DistFast (org, endPos);
1570 		if (rnum < 50.0f) {
1571 			// Wave
1572 			CG_SpawnParticle (
1573 				endPos[0] + normal[0],				endPos[1] + normal[0],				endPos[2] + normal[0],
1574 				angle[0],							angle[1],							angle[2],
1575 				0,									0,									0,
1576 				0,									0,									0,
1577 				255 - waterOffset,					155 - waterOffset,					waterOffset,
1578 				255 - waterOffset,					155 - waterOffset,					waterOffset,
1579 				0.7f + (crand () * 0.1f),			-1.0f / (0.1f + (frand () * 0.05f)),
1580 				5 + (crand () * 2),					(60 + (crand () * 5)) * scale,
1581 				PT_EXPLOWAVE,						PF_SCALED,
1582 				NULL,								qFalse,
1583 				PART_STYLE_ANGLED,
1584 				0);
1585 		}
1586 
1587 		// Smoke
1588 		for (j=0 ; j<1.25f + (cg_particleSmokeLinger->floatVal * 0.05f) ; j++) {
1589 			rnum = 60 + (frand () * 50);
1590 			rnum2 = 70 + (frand () * 50);
1591 			CG_SpawnParticle (
1592 				endPos[0] + normal[0],				endPos[1] + normal[0],				endPos[2] + normal[0],
1593 				angle[0],							angle[1],							angle[2],
1594 				0,									0,									0,
1595 				0,									0,									0,
1596 				rnum,								rnum,								rnum,
1597 				rnum2,								rnum2,								rnum2,
1598 				0.6f + (crand () * 0.1f),			-1.0f / (1.65f + (cg_particleSmokeLinger->floatVal * 0.5f) + (crand () * 0.2f)),
1599 				(60 + (crand () * 5)) * scale,		(80 + (crand () * 10)) * scale,
1600 				pRandSmoke (),						PF_SHADE,
1601 				pSmokeThink,						qTrue,
1602 				PART_STYLE_ANGLED,
1603 				frand () * 361);
1604 		}
1605 	}
1606 }
1607 
1608 
1609 /*
1610 ===============
1611 CG_ExplosionBFGParticles
1612 ===============
1613 */
CG_ExplosionBFGParticles(vec3_t org)1614 void CG_ExplosionBFGParticles (vec3_t org)
1615 {
1616 	int			i;
1617 	cgDecal_t	*d;
1618 	float		mult;
1619 	float		rnum, rnum2;
1620 	vec3_t		endPos, dir;
1621 
1622 	// Smoke
1623 	for (i=0 ; i<8 ; i++) {
1624 		rnum = 70 + (frand () * 40);
1625 		rnum2 = 80 + (frand () * 40);
1626 		CG_SpawnParticle (
1627 			org[0] + (crand () * 4),		org[1] + (crand () * 4),		org[2] + (crand () * 4),
1628 			0,								0,								0,
1629 			crand () * 2,					crand () * 2,					crand () * 2,
1630 			0,								0,								5 + (frand () * 6),
1631 			rnum,							80 + rnum,						rnum,
1632 			rnum2,							100+ rnum2,						rnum2,
1633 			0.75f + (crand () * 0.1f),		-1.0f / (0.25f + (cg_particleSmokeLinger->floatVal * 0.1f) + (crand () * 0.1f)),
1634 			35 + (crand () * 15),			140 + (crand () * 30),
1635 			pRandGlowSmoke (),				0,
1636 			pSmokeThink,					qTrue,
1637 			PART_STYLE_QUAD,
1638 			frand () * 361);
1639 	}
1640 
1641 	// Dots
1642 	mult = (cg.currGameMod == GAME_MOD_GLOOM) ? 0.18f : 2.5f;
1643 	for (i=0 ; i<196 ; i++) {
1644 		rnum = (rand () % 2) ? 150 + (frand () * 25) : 0;
1645 		CG_SpawnParticle (
1646 			org[0] + (crand () * 16),		org[1] + (crand () * 16),			org[2] + (crand () * 16),
1647 			0,								0,									0,
1648 			(crand () * 192) * mult,		(crand () * 192) * mult,			(crand () * 192) * mult,
1649 			0,								0,									-40,
1650 			rnum,							rnum + 75 + (frand () * 150),		rnum + (frand () * 50),
1651 			rnum,							rnum + 75 + (frand () * 150),		rnum + (frand () * 50),
1652 			1.0f,							-0.8f / (0.8f + (frand () * 0.3f)),
1653 			11 + (crand () * 10.5f),		0.1f + (frand () * 0.5f),
1654 			PT_BFG_DOT,						PF_SCALED|PF_GRAVITY|PF_NOCLOSECULL,
1655 			pBounceThink,					qTrue,
1656 			PART_STYLE_QUAD,
1657 			0);
1658 	}
1659 
1660 	// Decal
1661 	if (!CG_FindExplosionDir (org, 40, endPos, dir))
1662 		return;
1663 
1664 	// Burn mark
1665 	d = CG_SpawnDecal (
1666 		endPos[0],							endPos[1],							endPos[2],
1667 		dir[0],								dir[1],								dir[2],
1668 		255,								255,								255,
1669 		0,									0,									0,
1670 		0.9f + (crand () * 0.1f),			0.8f,
1671 		40 + (crand () * 3) - 8,
1672 		DT_BFG_BURNMARK,					DF_ALPHACOLOR,
1673 		NULL,								qFalse,
1674 		0,									frand () * 360);
1675 
1676 	// Glow mark
1677 	d = CG_SpawnDecal (
1678 		endPos[0],							endPos[1],							endPos[2],
1679 		dir[0],								dir[1],								dir[2],
1680 		255,								255,								255,
1681 		0,									0,									0,
1682 		1.0f,								0,
1683 		40 + (crand () * 3) - 8,
1684 		DT_BFG_GLOWMARK,					DF_USE_BURNLIFE|DF_ALPHACOLOR,
1685 		NULL,								qFalse,
1686 		0,									frand () * 360);
1687 }
1688 
1689 
1690 /*
1691 ===============
1692 CG_ExplosionColorParticles
1693 ===============
1694 */
CG_ExplosionColorParticles(vec3_t org)1695 void CG_ExplosionColorParticles (vec3_t org)
1696 {
1697 	int			i;
1698 
1699 	for (i=0 ; i<128 ; i++) {
1700 		CG_SpawnParticle (
1701 			org[0] + (crand () * 16),		org[1] + (crand () * 16),			org[2] + (crand () * 16),
1702 			0,								0,									0,
1703 			crand () * 128,					crand () * 128,						crand () * 128,
1704 			0,								0,									-40,
1705 			0 + crand (),					0 + crand (),						0 + crand (),
1706 			0 + crand (),					0 + crand (),						0 + crand (),
1707 			1.0f,							-0.4f / (0.6f + (frand () * 0.2f)),
1708 			1.0f,							1.0f,
1709 			PT_GENERIC,						PF_SCALED|PF_NOCLOSECULL,
1710 			0,								qFalse,
1711 			PART_STYLE_QUAD,
1712 			0);
1713 	}
1714 }
1715 
1716 
1717 /*
1718 ===============
1719 CG_FlyEffect
1720 ===============
1721 */
CG_FlyParticles(vec3_t origin,int count)1722 void CG_FlyParticles (vec3_t origin, int count)
1723 {
1724 	int			i;
1725 	float		angle;
1726 	float		sr, sp, sy, cr, cp, cy;
1727 	vec3_t		forward;
1728 	float		dist = 64;
1729 	float		ltime;
1730 
1731 	if (count > NUMVERTEXNORMALS)
1732 		count = NUMVERTEXNORMALS;
1733 
1734 	ltime = (float)cg.realTime / 1000.0f;
1735 	for (i=0 ; i<count ; i+=2) {
1736 		angle = ltime * cg_randVels[i][0];
1737 		sy = (float)sin (angle);
1738 		cy = (float)cos (angle);
1739 		angle = ltime * cg_randVels[i][1];
1740 		sp = (float)sin (angle);
1741 		cp = (float)cos (angle);
1742 		angle = ltime * cg_randVels[i][2];
1743 		sr = (float)sin (angle);
1744 		cr = (float)cos (angle);
1745 
1746 		forward[0] = cp*cy;
1747 		forward[1] = cp*sy;
1748 		forward[2] = -sp;
1749 
1750 		dist = (float)sin (ltime + i) * 64;
1751 
1752 		CG_SpawnParticle (
1753 			origin[0] + (m_byteDirs[i][0] * dist) + (forward[0] * BEAMLENGTH),
1754 			origin[1] + (m_byteDirs[i][1] * dist) + (forward[1] * BEAMLENGTH),
1755 			origin[2] + (m_byteDirs[i][2] * dist) + (forward[2] * BEAMLENGTH),
1756 			0,								0,								0,
1757 			0,								0,								0,
1758 			0,								0,								0,
1759 			0,								0,								0,
1760 			0,								0,								0,
1761 			1,								-100,
1762 			1.5f,							1.5f,
1763 			PT_FLY,							PF_NOCLOSECULL,
1764 			0,								qFalse,
1765 			PART_STYLE_QUAD,
1766 			0);
1767 	}
1768 }
1769 
CG_FlyEffect(cgEntity_t * ent,vec3_t origin)1770 void CG_FlyEffect (cgEntity_t *ent, vec3_t origin)
1771 {
1772 	int		n;
1773 	float	count;
1774 	int		starttime;
1775 
1776 	if (ent->flyStopTime < cg.realTime) {
1777 		starttime = cg.realTime;
1778 		ent->flyStopTime = cg.realTime + 60000;
1779 	}
1780 	else
1781 		starttime = ent->flyStopTime - 60000;
1782 
1783 	n = cg.realTime - starttime;
1784 	if (n < 20000)
1785 		count = n * 162 / 20000.0f;
1786 	else {
1787 		n = ent->flyStopTime - cg.realTime;
1788 		if (n < 20000)
1789 			count = n * 162 / 20000.0f;
1790 		else
1791 			count = 162;
1792 	}
1793 
1794 	CG_FlyParticles (origin, count*2);
1795 }
1796 
1797 
1798 /*
1799 ===============
1800 CG_ForceWall
1801 ===============
1802 */
CG_ForceWall(vec3_t start,vec3_t end,int color)1803 void CG_ForceWall (vec3_t start, vec3_t end, int color)
1804 {
1805 	vec3_t		move, vec;
1806 	float		len, dec;
1807 
1808 	Vec3Copy (start, move);
1809 	Vec3Subtract (end, start, vec);
1810 	len = VectorNormalizeFastf (vec);
1811 
1812 	dec = 4;
1813 	Vec3Scale (vec, dec, vec);
1814 
1815 	for (; len>0 ; Vec3Add (move, vec, move)) {
1816 		len -= dec;
1817 
1818 		if (frand () > 0.3) {
1819 			CG_SpawnParticle (
1820 				move[0] + (crand () * 3),		move[1] + (crand () * 3),		move[2] + (crand () * 3),
1821 				0,								0,								0,
1822 				0,								0,								-40 - (crand () * 10),
1823 				0,								0,								0,
1824 				palRed (color),					palGreen (color),				palBlue (color),
1825 				palRed (color),					palGreen (color),				palBlue (color),
1826 				1.0f,							-1.0f / (3.0f + (frand () * 0.5f)),
1827 				1.0f,							1.0f,
1828 				PT_GENERIC,						PF_SCALED,
1829 				0,								qFalse,
1830 				PART_STYLE_QUAD,
1831 				0);
1832 		}
1833 	}
1834 }
1835 
1836 
1837 /*
1838 ===============
1839 CG_MonsterPlasma_Shell
1840 ===============
1841 */
CG_MonsterPlasma_Shell(vec3_t origin)1842 void CG_MonsterPlasma_Shell (vec3_t origin)
1843 {
1844 	vec3_t			dir, porg;
1845 	int				i, rnum, rnum2;
1846 
1847 	for (i=0 ; i<40 ; i++) {
1848 		Vec3Set (dir, crand (), crand (), crand ());
1849 		VectorNormalizeFastf (dir);
1850 		Vec3MA (origin, 10, dir, porg);
1851 
1852 		rnum = (rand () % 5);
1853 		rnum2 = (rand () % 5);
1854 		CG_SpawnParticle (
1855 			porg[0],						porg[1],						porg[2],
1856 			0,								0,								0,
1857 			0,								0,								0,
1858 			0,								0,								0,
1859 			palRed (0xe0 + rnum),			palGreen (0xe0 + rnum),			palBlue (0xe0 + rnum),
1860 			palRed (0xe0 + rnum2),			palGreen (0xe0 + rnum2),		palBlue (0xe0 + rnum2),
1861 			1.0,							PART_INSTANT,
1862 			1.0,							1.0,
1863 			PT_GENERIC,						PF_SCALED,
1864 			0,								qFalse,
1865 			PART_STYLE_QUAD,
1866 			0);
1867 	}
1868 }
1869 
1870 
1871 /*
1872 ===============
1873 CG_PhalanxTip
1874 ===============
1875 */
CG_PhalanxTip(vec3_t start,vec3_t end)1876 void CG_PhalanxTip (vec3_t start, vec3_t end)
1877 {
1878 	int		i, j, k;
1879 	int		rnum, rnum2;
1880 	vec3_t	move, vec, dir;
1881 	float	len, dec, vel;
1882 
1883 	// Bubbles
1884 	CG_BubbleEffect (start);
1885 
1886 	// Smoke
1887 	dec = 1 + (cg_particleSmokeLinger->floatVal * 0.2f);
1888 	for (i=0 ; i<dec ; i++) {
1889 		rnum = (rand () % 5);
1890 		rnum2 = (rand () % 5);
1891 
1892 		CG_SpawnParticle (
1893 			start[0] + (crand()*2),				start[1] + (crand()*2),				start[2] + (crand()*2),
1894 			0,									0,									0,
1895 			0,									0,									0,
1896 			0,									0,									5 + (frand () * 25),
1897 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
1898 			palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
1899 			0.9f + (frand() * 0.1f),			-1.0f / (0.25f + (cg_particleSmokeLinger->floatVal * 0.01f) + (frand() * 0.1f)),
1900 			5 + crand (),						16 + (crand () * 8),
1901 			pRandGlowSmoke (),					PF_ALPHACOLOR,
1902 			NULL,								qFalse,
1903 			PART_STYLE_QUAD,
1904 			frand () * 360);
1905 	}
1906 
1907 	// Trail
1908 	Vec3Copy (start, move);
1909 	Vec3Subtract (start, end, vec);
1910 	len = VectorNormalizeFastf (vec);
1911 
1912 	dec = 2.5f;
1913 	Vec3Scale (vec, dec, vec);
1914 
1915 	for (; len>0 ; Vec3Add (move, vec, move)) {
1916 		len -= dec;
1917 
1918 		rnum = (rand () % 5);
1919 		rnum2 = (rand () % 5);
1920 
1921 		CG_SpawnParticle (
1922 			move[0] + crand (),					move[1] + crand (),					move[2] + crand (),
1923 			0,									0,									0,
1924 			crand () * 2,						crand () * 2,						crand () * 2,
1925 			crand () * 2,						crand () * 2,						crand () * 2,
1926 			palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
1927 			palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
1928 			1.0,								-15,
1929 			5 + (frand () * 4),					3 + (frand () * 2.5f),
1930 			PT_PHALANXTIP,						0,
1931 			0,									qFalse,
1932 			PART_STYLE_QUAD,
1933 			0);
1934 	}
1935 
1936 	for (i=-2 ; i<=2 ; i+=4) {
1937 		for (j=-2 ; j<=2 ; j+=4) {
1938 			for (k=-2 ; k<=4 ; k+=4) {
1939 				Vec3Set (dir, (float)(j * 4), (float)(i * 4), (float)(k * 4));
1940 				VectorNormalizeFastf (dir);
1941 				vel = 10.0f + rand () % 11;
1942 
1943 				rnum = (rand () % 5);
1944 				rnum2 = (rand () % 5);
1945 				CG_SpawnParticle (
1946 					start[0] + i + ((rand () % 6) * crand ()),
1947 					start[1] + j + ((rand () % 6) * crand ()),
1948 					start[2] + k + ((rand () % 6) * crand ()),
1949 					0,									0,									0,
1950 					dir[0] * vel,						dir[1] * vel,						dir[2] * vel,
1951 					0,									0,									-40,
1952 					palRed (0xe0 + rnum),				palGreen (0xe0 + rnum),				palBlue (0xe0 + rnum),
1953 					palRed (0xe0 + rnum2),				palGreen (0xe0 + rnum2),			palBlue (0xe0 + rnum2),
1954 					0.9f,								-3.5f,
1955 					2 + (frand () * 0.5f),				0.5f + (frand () * 0.5f),
1956 					PT_GENERIC,							PF_NOCLOSECULL,
1957 					0,									qFalse,
1958 					PART_STYLE_QUAD,
1959 					0);
1960 			}
1961 		}
1962 	}
1963 }
1964 
1965 
1966 /*
1967 ===============
1968 CG_TeleportParticles
1969 ===============
1970 */
CG_TeleportParticles(vec3_t org)1971 void CG_TeleportParticles (vec3_t org)
1972 {
1973 	int		i;
1974 
1975 	for (i=0 ; i<300 ; i++) {
1976 		CG_SpawnParticle (
1977 			org[0] + (crand () * 32),		org[1] + (crand () * 32),		org[2] + (frand () * 85 - 25),
1978 			0,								0,								0,
1979 			crand () * 50,					crand () * 50,					crand () * 50,
1980 			crand () * 50,					crand () * 50,					50 + (crand () * 20),
1981 			220,							190,							150,
1982 			255,							255,							230,
1983 			0.9f + (frand () * 0.25f),		-0.3f / (0.1f + (frand () * 0.1f)),
1984 			10 + (frand () * 0.25f),		0.5f + (frand () * 0.25f),
1985 			PT_FLAREGLOW,					PF_SCALED|PF_GRAVITY|PF_NOCLOSECULL,
1986 			pBounceThink,					qTrue,
1987 			PART_STYLE_QUAD,
1988 			0);
1989 	}
1990 }
1991 
1992 
1993 /*
1994 ===============
1995 CG_TeleporterParticles
1996 ===============
1997 */
CG_TeleporterParticles(entityState_t * ent)1998 void CG_TeleporterParticles (entityState_t *ent)
1999 {
2000 	int		i;
2001 
2002 	for (i=0 ; i<2 ; i++) {
2003 		CG_SpawnParticle (
2004 			ent->origin[0] + (crand () * 16),	ent->origin[1] + (crand () * 16),	ent->origin[2] + (crand () * 8) - 3,
2005 			0,									0,									0,
2006 			crand () * 15,						crand () * 15,						80 + (frand () * 5),
2007 			0,									0,									-40,
2008 			210 + (crand () *  5),				180 + (crand () *  5),				120 + (crand () *  5),
2009 			255 + (crand () *  5),				210 + (crand () *  5),				140 + (crand () *  5),
2010 			1.0f,								-0.6f + (crand () * 0.1f),
2011 			2 + (frand () * 0.5f),				1 + (crand () * 0.5f),
2012 			PT_GENERIC_GLOW,					PF_SCALED|PF_NOCLOSECULL,
2013 			0,									qFalse,
2014 			PART_STYLE_QUAD,
2015 			0);
2016 	}
2017 }
2018 
2019 
2020 /*
2021 ===============
2022 CG_TrackerShell
2023 ===============
2024 */
CG_TrackerShell(vec3_t origin)2025 void CG_TrackerShell (vec3_t origin)
2026 {
2027 	vec3_t			dir, porg;
2028 	int				i;
2029 
2030 	for (i=0 ; i<300 ; i++) {
2031 		Vec3Set (dir, crand (), crand (), crand ());
2032 		VectorNormalizeFastf (dir);
2033 		Vec3MA (origin, 40, dir, porg);
2034 
2035 		CG_SpawnParticle (
2036 			porg[0],						porg[1],						porg[2],
2037 			0,								0,								0,
2038 			0,								0,								0,
2039 			0,								0,								0,
2040 			0,								0,								0,
2041 			0,								0,								0,
2042 			1.0,							PART_INSTANT,
2043 			1.0f,							1.0f,
2044 			PT_GENERIC,						PF_SCALED,
2045 			0,								qFalse,
2046 			PART_STYLE_QUAD,
2047 			0);
2048 	}
2049 }
2050 
2051 
2052 /*
2053 ===============
2054 CG_TrapParticles
2055 ===============
2056 */
CG_TrapParticles(refEntity_t * ent)2057 void CG_TrapParticles (refEntity_t *ent)
2058 {
2059 	vec3_t		move, vec, start, end, dir, org;
2060 	int			i, j, k, rnum, rnum2;
2061 	float		len, vel, dec;
2062 
2063 	ent->origin[2] -= 16;
2064 	Vec3Copy (ent->origin, start);
2065 	Vec3Copy (ent->origin, end);
2066 	end[2] += 10;
2067 
2068 	Vec3Copy (start, move);
2069 	Vec3Subtract (end, start, vec);
2070 	len = VectorNormalizeFastf (vec);
2071 
2072 	dec = 5;
2073 	Vec3Scale (vec, dec, vec);
2074 
2075 	for (; len>0 ; Vec3Add (move, vec, move)) {
2076 		len -= dec;
2077 
2078 		rnum = (rand () % 5);
2079 		rnum2 = (rand () % 5);
2080 		CG_SpawnParticle (
2081 			move[0] + (crand () * 2),		move[1] + (crand () * 1.5f),	move[2] + (crand () * 1.5f),
2082 			0,								0,								0,
2083 			crand () * 20,					crand () * 20,					crand () * 20,
2084 			0,								0,								40,
2085 			palRed (0xe0 + rnum),			palGreen (0xe0 + rnum),			palBlue (0xe0 + rnum),
2086 			palRed (0xe0 + rnum2),			palGreen (0xe0 + rnum2),		palBlue (0xe0 + rnum2),
2087 			1.0f,							-1.0f / (0.45f + (frand () * 0.2f)),
2088 			5.0f,							1.0f,
2089 			PT_GENERIC,						PF_SCALED,
2090 			0,								qFalse,
2091 			PART_STYLE_QUAD,
2092 			0);
2093 	}
2094 
2095 	ent->origin[2]+=14;
2096 	Vec3Copy (ent->origin, org);
2097 
2098 	for (i=-2 ; i<=2 ; i+=4)
2099 		for (j=-2 ; j<=2 ; j+=4)
2100 			for (k=-2 ; k<=4 ; k+=4) {
2101 				dir[0] = (float)(j * 8);
2102 				dir[1] = (float)(i * 8);
2103 				dir[2] = (float)(k * 8);
2104 
2105 				VectorNormalizeFastf (dir);
2106 				vel = 50 + (float)(rand () & 63);
2107 
2108 				rnum = (rand () % 5);
2109 				rnum2 = (rand () % 5);
2110 				CG_SpawnParticle (
2111 					org[0] + i + ((rand () & 23) * crand ()),
2112 					org[1] + j + ((rand () & 23) * crand ()),
2113 					org[2] + k + ((rand () & 23) * crand ()),
2114 					0,								0,								0,
2115 					dir[0] * vel,					dir[1] * vel,					dir[2] * vel,
2116 					0,								0,								-40,
2117 					palRed (0xe0 + rnum),			palGreen (0xe0 + rnum),			palBlue (0xe0 + rnum),
2118 					palRed (0xe0 + rnum2),			palGreen (0xe0 + rnum2),		palBlue (0xe0 + rnum2),
2119 					1.0f,							-1.0f / (0.3f + (frand () * 0.15f)),
2120 					2.0f,							1.0f,
2121 					PT_GENERIC,						PF_SCALED,
2122 					0,								qFalse,
2123 					PART_STYLE_QUAD,
2124 					0);
2125 			}
2126 }
2127 
2128 
2129 /*
2130 ===============
2131 CG_WidowSplash
2132 ===============
2133 */
CG_WidowSplash(vec3_t org)2134 void CG_WidowSplash (vec3_t org)
2135 {
2136 	int			clrtable[4] = {2*8, 13*8, 21*8, 18*8};
2137 	int			i, rnum, rnum2;
2138 	vec3_t		dir, porg, pvel;
2139 
2140 	for (i=0 ; i<256 ; i++) {
2141 		Vec3Set (dir, crand (), crand (), crand ());
2142 		VectorNormalizeFastf (dir);
2143 		Vec3MA (org, 45.0f, dir, porg);
2144 		Vec3MA (vec3Origin, 40.0f, dir, pvel);
2145 
2146 		rnum = (rand () % 4);
2147 		rnum2 = (rand () % 4);
2148 		CG_SpawnParticle (
2149 			porg[0],						porg[1],						porg[2],
2150 			0,								0,								0,
2151 			pvel[0],						pvel[1],						pvel[2],
2152 			0,								0,								0,
2153 			palRed (clrtable[rnum]),		palGreen (clrtable[rnum]),		palBlue (clrtable[rnum]),
2154 			palRed (clrtable[rnum2]),		palGreen (clrtable[rnum2]),		palBlue (clrtable[rnum2]),
2155 			1.0f,							-0.8f / (0.5f + (frand () * 0.3f)),
2156 			1.0f,							1.0f,
2157 			PT_GENERIC,						PF_SCALED,
2158 			0,								qFalse,
2159 			PART_STYLE_QUAD,
2160 			0);
2161 	}
2162 }
2163