1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 #include "client.h"
24 #include "FxScheduler.h"
25 
26 //------------------------------------------------------
27 // CPrimitiveTemplate
28 //	Set up our minimal default values
29 //
30 // Input:
31 //	none
32 //
33 // Return:
34 //	none
35 //------------------------------------------------------
CPrimitiveTemplate()36 CPrimitiveTemplate::CPrimitiveTemplate()
37 {
38 	// We never start out as a copy or with a name
39 	mCopy = false;
40 	mName[0] = 0;
41 	mCullRange = 0; // no distance culling
42 
43 	mFlags = mSpawnFlags = 0;
44 	mElasticity.SetRange(0.1f, 0.1f);
45 
46 	mSoundVolume = -1;
47 	mSoundRadius = -1;
48 
49 	mMatImpactFX = MATIMPACTFX_NONE;
50 
51 	mLife.SetRange( 50.0f, 50.0f );
52 	mSpawnCount.SetRange( 1.0f, 1.0f );
53 	mRadius.SetRange( 10.0f, 10.0f );
54 	mHeight.SetRange( 10.0f, 10.0f );
55 	mWindModifier.SetRange( 1.0f, 1.0f );
56 
57 	VectorSet( mMin, 0.0f, 0.0f, 0.0f );
58 	VectorSet( mMax, 0.0f, 0.0f, 0.0f );
59 
60 	mRedStart.SetRange( 1.0f, 1.0f );
61 	mGreenStart.SetRange( 1.0f, 1.0f );
62 	mBlueStart.SetRange( 1.0f, 1.0f );
63 
64 	mRedEnd.SetRange( 1.0f, 1.0f );
65 	mGreenEnd.SetRange( 1.0f, 1.0f );
66 	mBlueEnd.SetRange( 1.0f, 1.0f );
67 
68 	mAlphaStart.SetRange( 1.0f, 1.0f );
69 	mAlphaEnd.SetRange( 1.0f, 1.0f );
70 
71 	mSizeStart.SetRange( 1.0f, 1.0f );
72 	mSizeEnd.SetRange( 1.0f, 1.0f );
73 
74 	mSize2Start.SetRange( 1.0f, 1.0f );
75 	mSize2End.SetRange( 1.0f, 1.0f );
76 
77 	mLengthStart.SetRange( 1.0f, 1.0f );
78 	mLengthEnd.SetRange( 1.0f, 1.0f );
79 
80 	mTexCoordS.SetRange( 1.0f, 1.0f );
81 	mTexCoordT.SetRange( 1.0f, 1.0f );
82 
83 	mVariance.SetRange( 1.0f, 1.0f );
84 	mDensity.SetRange( 10.0f, 10.0f );// default this high so it doesn't do bad things
85 }
86 
87 //-----------------------------------------------------------
operator =(const CPrimitiveTemplate & that)88 CPrimitiveTemplate &CPrimitiveTemplate::operator=(const CPrimitiveTemplate &that)
89 {
90 	// I'm assuming that doing a memcpy wouldn't work here
91 	// If you are looking at this and know a better way to do this, please tell me.
92 	strcpy( mName, that.mName );
93 
94 	mType				= that.mType;
95 
96 	mSpawnDelay			= that.mSpawnDelay;
97 	mSpawnCount			= that.mSpawnCount;
98 	mLife				= that.mLife;
99 	mCullRange			= that.mCullRange;
100 
101 	mMediaHandles		= that.mMediaHandles;
102 	mImpactFxHandles	= that.mImpactFxHandles;
103 	mDeathFxHandles		= that.mDeathFxHandles;
104 	mEmitterFxHandles	= that.mEmitterFxHandles;
105 	mPlayFxHandles		= that.mPlayFxHandles;
106 
107 	mFlags				= that.mFlags;
108 	mSpawnFlags			= that.mSpawnFlags;
109 
110 	VectorCopy( that.mMin, mMin );
111 	VectorCopy( that.mMax, mMax );
112 
113 	mOrigin1X			= that.mOrigin1X;
114 	mOrigin1Y			= that.mOrigin1Y;
115 	mOrigin1Z			= that.mOrigin1Z;
116 
117 	mOrigin2X			= that.mOrigin2X;
118 	mOrigin2Y			= that.mOrigin2Y;
119 	mOrigin2Z			= that.mOrigin2Z;
120 
121 	mRadius				= that.mRadius;
122 	mHeight				= that.mHeight;
123 	mWindModifier		= that.mWindModifier;
124 
125 	mRotation			= that.mRotation;
126 	mRotationDelta		= that.mRotationDelta;
127 
128 	mAngle1				= that.mAngle1;
129 	mAngle2				= that.mAngle2;
130 	mAngle3				= that.mAngle3;
131 
132 	mAngle1Delta		= that.mAngle1Delta;
133 	mAngle2Delta		= that.mAngle2Delta;
134 	mAngle3Delta		= that.mAngle3Delta;
135 
136 	mVelX				= that.mVelX;
137 	mVelY				= that.mVelY;
138 	mVelZ				= that.mVelZ;
139 
140 	mAccelX				= that.mAccelX;
141 	mAccelY				= that.mAccelY;
142 	mAccelZ				= that.mAccelZ;
143 
144 	mGravity			= that.mGravity;
145 
146 	mDensity			= that.mDensity;
147 	mVariance			= that.mVariance;
148 
149 	mRedStart			= that.mRedStart;
150 	mGreenStart			= that.mGreenStart;
151 	mBlueStart			= that.mBlueStart;
152 
153 	mRedEnd				= that.mRedEnd;
154 	mGreenEnd			= that.mGreenEnd;
155 	mBlueEnd			= that.mBlueEnd;
156 
157 	mRGBParm			= that.mRGBParm;
158 
159 	mAlphaStart			= that.mAlphaStart;
160 	mAlphaEnd			= that.mAlphaEnd;
161 	mAlphaParm			= that.mAlphaParm;
162 
163 	mSizeStart			= that.mSizeStart;
164 	mSizeEnd			= that.mSizeEnd;
165 	mSizeParm			= that.mSizeParm;
166 
167 	mSize2Start			= that.mSize2Start;
168 	mSize2End			= that.mSize2End;
169 	mSize2Parm			= that.mSize2Parm;
170 
171 	mLengthStart		= that.mLengthStart;
172 	mLengthEnd			= that.mLengthEnd;
173 	mLengthParm			= that.mLengthParm;
174 
175 	mTexCoordS			= that.mTexCoordS;
176 	mTexCoordT			= that.mTexCoordT;
177 
178 	mElasticity			= that.mElasticity;
179 
180 	mSoundRadius		= that.mSoundRadius;
181 	mSoundVolume		= that.mSoundVolume;
182 
183 	return *this;
184 }
185 
186 //------------------------------------------------------
187 // ParseFloat
188 //	Removes up to two values from a passed in string and
189 //	sets these values into the passed in min and max
190 //	fields.  if no max is present, min is copied into it.
191 //
192 // input:
193 //	string that contains up to two float values
194 //  min & max are used to return the parse values
195 //
196 // return:
197 //	success of parse operation.
198 //------------------------------------------------------
ParseFloat(const char * val,float * min,float * max)199 bool CPrimitiveTemplate::ParseFloat( const char *val, float *min, float *max )
200 {
201 	// We don't allow passing in a null for either of the fields
202 	if ( min == 0 || max == 0 )
203 	{ // failue
204 		return false;
205 	}
206 
207 	// attempt to read out the values
208 	int v = sscanf( val, "%f %f", min, max );
209 
210 	if ( v == 0 )
211 	{ // nothing was there, failure
212 		return false;
213 	}
214 	else if ( v == 1 )
215 	{ // only one field entered, this is ok, but we should copy min into max
216 		*max = *min;
217 	}
218 
219 	return true;
220 }
221 
222 
223 //------------------------------------------------------
224 // ParseVector
225 //	Removes up to six values from a passed in string and
226 //	sets these values into the passed in min and max vector
227 //	fields. if no max is present, min is copied into it.
228 //
229 // input:
230 //	string that contains up to six float values
231 //  min & max are used to return the parse values
232 //
233 // return:
234 //	success of parse operation.
235 //------------------------------------------------------
ParseVector(const char * val,vec3_t min,vec3_t max)236 bool CPrimitiveTemplate::ParseVector( const char *val, vec3_t min, vec3_t max )
237 {
238 	// we don't allow passing in a null
239 	if ( min == 0 || max == 0 )
240 	{
241 		return false;
242 	}
243 
244 	// attempt to read out our values
245 	int v = sscanf( val, "%f %f %f   %f %f %f", &min[0], &min[1], &min[2], &max[0], &max[1], &max[2] );
246 
247 	// Check for completeness
248 	if ( v < 3 || v == 4 || v == 5 )
249 	{ // not a complete value
250 		return false;
251 	}
252 	else if ( v == 3 )
253 	{ // only a min was entered, so copy the result into max
254 		VectorCopy( min, max );
255 	}
256 
257 	return true;
258 }
259 
260 //------------------------------------------------------
261 // ParseGroupFlags
262 //	Group flags are generic in nature, so we can easily
263 //	use a generic function to parse them in, then the
264 //	caller can shift them into the appropriate range.
265 //
266 // input:
267 //	string that contains the flag strings
268 //  *flags returns the set bit flags
269 //
270 // return:
271 //	success of parse operation.
272 //------------------------------------------------------
ParseGroupFlags(const char * val,int * flags)273 bool CPrimitiveTemplate::ParseGroupFlags( const char *val, int *flags )
274 {
275 	// Must pass in a non-null pointer
276 	if ( flags == 0 )
277 	{
278 		return false;
279 	}
280 
281 	char	flag[][32] = {"\0","\0","\0","0"};
282 	bool	ok = true;
283 
284 	// For a sub group, really you probably only have one or two flags set
285 	int v = sscanf( val, "%s %s %s %s", flag[0], flag[1], flag[2], flag[3] );
286 
287 	// Clear out the flags field, then convert the flag string to an actual value ( use generic flags )
288 	*flags = 0;
289 
290 	for ( int i = 0; i < 4; i++ )
291 	{
292 		if ( i + 1 > v )
293 		{
294 			return true;
295 		}
296 
297 		if ( !Q_stricmp( flag[i], "linear" ) )
298 			*flags |= FX_LINEAR;
299 		else if ( !Q_stricmp( flag[i], "nonlinear" ) )
300 			*flags |= FX_NONLINEAR;
301 		else if ( !Q_stricmp( flag[i], "wave" ) )
302 			*flags |= FX_WAVE;
303 		else if ( !Q_stricmp( flag[i], "random" ) )
304 			*flags |= FX_RAND;
305 		else if ( !Q_stricmp( flag[i], "clamp" ) )
306 			*flags |= FX_CLAMP;
307 
308 		else
309 		{ // we have badness going on, but continue on in case there are any valid fields in here
310 			ok = false;
311 		}
312 	}
313 
314 	return ok;
315 }
316 
317 //------------------------------------------------------
318 // ParseMin
319 //	Reads in a min bounding box field in vector format
320 //
321 // input:
322 //	string that contains three float values
323 //
324 // return:
325 //	success of parse operation.
326 //------------------------------------------------------
ParseMin(const char * val)327 bool CPrimitiveTemplate::ParseMin( const char *val )
328 {
329 	vec3_t min;
330 
331 	if ( ParseVector( val, min, min ) == true )
332 	{
333 		VectorCopy( min, mMin );
334 
335 		// We assume that if a min is being set that we are using physics and a bounding box
336 		mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS);
337 		return true;
338 	}
339 
340 	return false;
341 }
342 
343 //------------------------------------------------------
344 // ParseMax
345 //	Reads in a max bounding box field in vector format
346 //
347 // input:
348 //	string that contains three float values
349 //
350 // return:
351 //	success of parse operation.
352 //------------------------------------------------------
ParseMax(const char * val)353 bool CPrimitiveTemplate::ParseMax( const char *val )
354 {
355 	vec3_t max;
356 
357 	if ( ParseVector( val, max, max ) == true )
358 	{
359 		VectorCopy( max, mMax );
360 
361 		// We assume that if a max is being set that we are using physics and a bounding box
362 		mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS);
363 		return true;
364 	}
365 
366 	return false;
367 }
368 
369 //------------------------------------------------------
370 // ParseLife
371 //	Reads in a ranged life value
372 //
373 // input:
374 //	string that contains a float range ( two vals )
375 //
376 // return:
377 //	success of parse operation.
378 //------------------------------------------------------
ParseLife(const char * val)379 bool CPrimitiveTemplate::ParseLife( const char *val )
380 {
381 	float min, max;
382 
383 	if ( ParseFloat( val, &min, &max ) == true )
384 	{
385 		mLife.SetRange( min, max );
386 		return true;
387 	}
388 
389 	return false;
390 }
391 
392 //------------------------------------------------------
393 // ParseDelay
394 //	Reads in a ranged delay value
395 //
396 // input:
397 //	string that contains a float range ( two vals )
398 //
399 // return:
400 //	success of parse operation.
401 //------------------------------------------------------
ParseDelay(const char * val)402 bool CPrimitiveTemplate::ParseDelay( const char *val )
403 {
404 	float min, max;
405 
406 	if ( ParseFloat( val, &min, &max ) == true )
407 	{
408 		mSpawnDelay.SetRange( min, max );
409 		return true;
410 	}
411 
412 	return false;
413 }
414 
415 //------------------------------------------------------
416 // ParseCount
417 //	Reads in a ranged count value
418 //
419 // input:
420 //	string that contains a float range ( two vals )
421 //
422 // return:
423 //	success of parse operation.
424 //------------------------------------------------------
ParseCount(const char * val)425 bool CPrimitiveTemplate::ParseCount( const char *val )
426 {
427 	float min, max;
428 
429 	if ( ParseFloat( val, &min, &max ) == true )
430 	{
431 		mSpawnCount.SetRange( min, max );
432 		return true;
433 	}
434 
435 	return false;
436 }
437 
438 //------------------------------------------------------
439 // ParseElasticity
440 //	Reads in a ranged elasticity value
441 //
442 // input:
443 //	string that contains a float range ( two vals )
444 //
445 // return:
446 //	success of parse operation.
447 //------------------------------------------------------
ParseElasticity(const char * val)448 bool CPrimitiveTemplate::ParseElasticity( const char *val )
449 {
450 	float min, max;
451 
452 	if ( ParseFloat( val, &min, &max ) == true )
453 	{
454 		mElasticity.SetRange( min, max );
455 
456 		// We assume that if elasticity is set that we are using physics, but don't assume we are
457 		//	using a bounding box unless a min/max are explicitly set
458 		mFlags |= FX_APPLY_PHYSICS;
459 		return true;
460 	}
461 
462 	return false;
463 }
464 
465 //------------------------------------------------------
466 // ParseOrigin1
467 //	Reads in an origin field in vector format
468 //
469 // input:
470 //	string that contains three float values
471 //
472 // return:
473 //	success of parse operation.
474 //------------------------------------------------------
ParseOrigin1(const char * val)475 bool CPrimitiveTemplate::ParseOrigin1( const char *val )
476 {
477 	vec3_t min, max;
478 
479 	if ( ParseVector( val, min, max ) == true )
480 	{
481 		mOrigin1X.SetRange( min[0], max[0] );
482 		mOrigin1Y.SetRange( min[1], max[1] );
483 		mOrigin1Z.SetRange( min[2], max[2] );
484 		return true;
485 	}
486 
487 	return false;
488 }
489 
490 //------------------------------------------------------
491 // ParseOrigin2
492 //	Reads in an origin field in vector format
493 //
494 // input:
495 //	string that contains three float values
496 //
497 // return:
498 //	success of parse operation.
499 //------------------------------------------------------
ParseOrigin2(const char * val)500 bool CPrimitiveTemplate::ParseOrigin2( const char *val )
501 {
502 	vec3_t min, max;
503 
504 	if ( ParseVector( val, min, max ) == true )
505 	{
506 		mOrigin2X.SetRange( min[0], max[0] );
507 		mOrigin2Y.SetRange( min[1], max[1] );
508 		mOrigin2Z.SetRange( min[2], max[2] );
509 		return true;
510 	}
511 
512 	return false;
513 }
514 
515 //------------------------------------------------------
516 // ParseRadius
517 //	Reads in a ranged radius value
518 //
519 // input:
520 //	string that contains one or two floats
521 //
522 // return:
523 //	success of parse operation.
524 //------------------------------------------------------
ParseRadius(const char * val)525 bool CPrimitiveTemplate::ParseRadius( const char *val )
526 {
527 	float min, max;
528 
529 	if ( ParseFloat( val, &min, &max ) == true )
530 	{
531 		mRadius.SetRange( min, max );
532 		return true;
533 	}
534 
535 	return false;
536 }
537 
538 //------------------------------------------------------
539 // ParseHeight
540 //	Reads in a ranged height value
541 //
542 // input:
543 //	string that contains one or two floats
544 //
545 // return:
546 //	success of parse operation.
547 //------------------------------------------------------
ParseHeight(const char * val)548 bool CPrimitiveTemplate::ParseHeight( const char *val )
549 {
550 	float min, max;
551 
552 	if ( ParseFloat( val, &min, &max ) == true )
553 	{
554 		mHeight.SetRange( min, max );
555 		return true;
556 	}
557 
558 	return false;
559 }
560 
561 //------------------------------------------------------
562 // ParseWindModifier
563 //	Reads in a ranged wind modifier value
564 //
565 // input:
566 //	string that contains one or two floats
567 //
568 // return:
569 //	success of parse operation.
570 //------------------------------------------------------
ParseWindModifier(const char * val)571 bool CPrimitiveTemplate::ParseWindModifier( const char *val )
572 {
573 	float min, max;
574 
575 	if ( ParseFloat( val, &min, &max ) == true )
576 	{
577 		mWindModifier.SetRange( min, max );
578 		return true;
579 	}
580 
581 	return false;
582 }
583 
584 //------------------------------------------------------
585 // ParseRotation
586 //	Reads in a ranged rotation value
587 //
588 // input:
589 //	string that contains one or two floats
590 //
591 // return:
592 //	success of parse operation.
593 //------------------------------------------------------
ParseRotation(const char * val)594 bool CPrimitiveTemplate::ParseRotation( const char *val )
595 {
596 	float min, max;
597 
598 	if ( ParseFloat( val, &min, &max ) == qtrue )
599 	{
600 		mRotation.SetRange( min, max );
601 		return true;
602 	}
603 
604 	return false;
605 }
606 
607 //------------------------------------------------------
608 // ParseRotationDelta
609 //	Reads in a ranged rotationDelta value
610 //
611 // input:
612 //	string that contains one or two floats
613 //
614 // return:
615 //	success of parse operation.
616 //------------------------------------------------------
ParseRotationDelta(const char * val)617 bool CPrimitiveTemplate::ParseRotationDelta( const char *val )
618 {
619 	float min, max;
620 
621 	if ( ParseFloat( val, &min, &max ) == qtrue )
622 	{
623 		mRotationDelta.SetRange( min, max );
624 		return true;
625 	}
626 
627 	return false;
628 }
629 
630 //------------------------------------------------------
631 // ParseAngle
632 //	Reads in a ranged angle field in vector format
633 //
634 // input:
635 //	string that contains one or two vectors
636 //
637 // return:
638 //	success of parse operation.
639 //------------------------------------------------------
ParseAngle(const char * val)640 bool CPrimitiveTemplate::ParseAngle( const char *val )
641 {
642 	vec3_t min, max;
643 
644 	if ( ParseVector( val, min, max ) == true )
645 	{
646 		mAngle1.SetRange( min[0], max[0] );
647 		mAngle2.SetRange( min[1], max[1] );
648 		mAngle3.SetRange( min[2], max[2] );
649 		return true;
650 	}
651 
652 	return false;
653 }
654 
655 //------------------------------------------------------
656 // ParseAngleDelta
657 //	Reads in a ranged angleDelta field in vector format
658 //
659 // input:
660 //	string that contains one or two vectors
661 //
662 // return:
663 //	success of parse operation.
664 //------------------------------------------------------
ParseAngleDelta(const char * val)665 bool CPrimitiveTemplate::ParseAngleDelta( const char *val )
666 {
667 	vec3_t min, max;
668 
669 	if ( ParseVector( val, min, max ) == true )
670 	{
671 		mAngle1Delta.SetRange( min[0], max[0] );
672 		mAngle2Delta.SetRange( min[1], max[1] );
673 		mAngle3Delta.SetRange( min[2], max[2] );
674 		return true;
675 	}
676 
677 	return false;
678 }
679 
680 //------------------------------------------------------
681 // ParseVelocity
682 //	Reads in a ranged velocity field in vector format
683 //
684 // input:
685 //	string that contains one or two vectors
686 //
687 // return:
688 //	success of parse operation.
689 //------------------------------------------------------
ParseVelocity(const char * val)690 bool CPrimitiveTemplate::ParseVelocity( const char *val )
691 {
692 	vec3_t min, max;
693 
694 	if ( ParseVector( val, min, max ) == true )
695 	{
696 		mVelX.SetRange( min[0], max[0] );
697 		mVelY.SetRange( min[1], max[1] );
698 		mVelZ.SetRange( min[2], max[2] );
699 		return true;
700 	}
701 
702 	return false;
703 }
704 
705 //------------------------------------------------------
706 // ParseFlags
707 //	These are flags that are not specific to a group,
708 //	rather, they are specific to the whole primitive.
709 //
710 // input:
711 //	string that contains the flag strings
712 //
713 // return:
714 //	success of parse operation.
715 //------------------------------------------------------
ParseFlags(const char * val)716 bool CPrimitiveTemplate::ParseFlags( const char *val )
717 {
718 	char	flag[][32] = {"\0","\0","\0","\0","\0","\0","\0"};
719 	bool	ok = true;
720 
721 	// For a primitive, really you probably only have two or less flags set
722 	int v = sscanf( val, "%s %s %s %s %s %s %s", flag[0], flag[1], flag[2], flag[3], flag[4], flag[5], flag[6] );
723 
724 	for ( int i = 0; i < 7; i++ )
725 	{
726 		if ( i + 1 > v )
727 		{
728 			return true;
729 		}
730 
731 			 if ( !Q_stricmp( flag[i], "useModel" ))
732 			mFlags |= FX_ATTACHED_MODEL;
733 		else if ( !Q_stricmp( flag[i], "useBBox" ))
734 			mFlags |= FX_USE_BBOX;
735 		else if ( !Q_stricmp( flag[i], "usePhysics" ))
736 			mFlags |= FX_APPLY_PHYSICS;
737 		else if ( !Q_stricmp( flag[i], "expensivePhysics" ))
738 			mFlags |= FX_EXPENSIVE_PHYSICS;
739 		//rww - begin g2 stuff
740 		else if ( !Q_stricmp( flag[i], "ghoul2Collision" ))
741 			mFlags |= (FX_GHOUL2_TRACE|FX_APPLY_PHYSICS|FX_EXPENSIVE_PHYSICS);
742 		else if ( !Q_stricmp( flag[i], "ghoul2Decals" ))
743 			mFlags |= FX_GHOUL2_DECALS;
744 		//rww - end
745 		else if ( !Q_stricmp( flag[i], "impactKills" ))
746 			mFlags |= FX_KILL_ON_IMPACT;
747 		else if ( !Q_stricmp( flag[i], "impactFx" ))
748 			mFlags |= FX_IMPACT_RUNS_FX;
749 		else if ( !Q_stricmp( flag[i], "deathFx" ))
750 			mFlags |= FX_DEATH_RUNS_FX;
751 		else if ( !Q_stricmp( flag[i], "useAlpha" ))
752 			mFlags |= FX_USE_ALPHA;
753 		else if ( !Q_stricmp( flag[i], "emitFx" ))
754 			mFlags |= FX_EMIT_FX;
755 		else if ( !Q_stricmp( flag[i], "depthHack" ))
756 			mFlags |= FX_DEPTH_HACK;
757 		else if ( !Q_stricmp( flag[i], "relative" ))
758 			mFlags |= FX_RELATIVE;
759 		else if ( !Q_stricmp( flag[i], "setShaderTime" ))
760 			mFlags |= FX_SET_SHADER_TIME;
761 		else if ( !Q_stricmp( flag[i], "paperPhysics" ))
762 			mFlags |= FX_PAPER_PHYSICS; //warning! shared flag.  You use this with a cylinder and you can expect evilness to ensue
763 		else if ( !Q_stricmp( flag[i], "localizedFlash" ))
764 			mFlags |= FX_LOCALIZED_FLASH; //warning! shared flag.  You use this with a cylinder and you can expect evilness to ensue
765 		else if ( !Q_stricmp( flag[i], "playerView" ))
766 			mFlags |= FX_PLAYER_VIEW; //warning! shared flag.  You use this with a cylinder and you can expect evilness to ensue
767 		else
768 		{ // we have badness going on, but continue on in case there are any valid fields in here
769 			ok = false;
770 		}
771 	}
772 
773 	return ok;
774 }
775 
776 //------------------------------------------------------
777 // ParseSpawnFlags
778 //	These kinds of flags control how things spawn.  They
779 //	never get passed on to a primitive.
780 //
781 // input:
782 //	string that contains the flag strings
783 //
784 // return:
785 //	success of parse operation.
786 //------------------------------------------------------
ParseSpawnFlags(const char * val)787 bool CPrimitiveTemplate::ParseSpawnFlags( const char *val )
788 {
789 	char	flag[][32] = {"\0","\0","\0","\0","\0","\0","\0"};
790 	bool	ok = true;
791 
792 	// For a primitive, really you probably only have two or less flags set
793 	int v = sscanf( val, "%s %s %s %s %s %s %s", flag[0], flag[1], flag[2], flag[3], flag[4], flag[5], flag[6] );
794 
795 	for ( int i = 0; i < 7; i++ )
796 	{
797 		if ( i + 1 > v )
798 		{
799 			return true;
800 		}
801 
802 			 if ( !Q_stricmp( flag[i], "org2fromTrace" ) )
803 			mSpawnFlags |= FX_ORG2_FROM_TRACE;
804 		else if ( !Q_stricmp( flag[i], "traceImpactFx" ) )
805 			mSpawnFlags |= FX_TRACE_IMPACT_FX;
806 		else if ( !Q_stricmp( flag[i], "org2isOffset" ) )
807 			mSpawnFlags |= FX_ORG2_IS_OFFSET;
808 		else if ( !Q_stricmp( flag[i], "cheapOrgCalc" ) )
809 			mSpawnFlags |= FX_CHEAP_ORG_CALC;
810 		else if ( !Q_stricmp( flag[i], "cheapOrg2Calc" ) )
811 			mSpawnFlags |= FX_CHEAP_ORG2_CALC;
812 		else if ( !Q_stricmp( flag[i], "absoluteVel" ) )
813 			mSpawnFlags |= FX_VEL_IS_ABSOLUTE;
814 		else if ( !Q_stricmp( flag[i], "absoluteAccel" ) )
815 			mSpawnFlags |= FX_ACCEL_IS_ABSOLUTE;
816 		else if ( !Q_stricmp( flag[i], "orgOnSphere" ) ) // sphere/ellipsoid
817 			mSpawnFlags |= FX_ORG_ON_SPHERE;
818 		else if ( !Q_stricmp( flag[i], "orgOnCylinder" ) ) // cylinder/disk
819 			mSpawnFlags |= FX_ORG_ON_CYLINDER;
820 		else if ( !Q_stricmp( flag[i], "axisFromSphere" ) )
821 			mSpawnFlags |= FX_AXIS_FROM_SPHERE;
822 		else if ( !Q_stricmp( flag[i], "randrotaroundfwd" ) )
823 			mSpawnFlags |= FX_RAND_ROT_AROUND_FWD;
824 		else if ( !Q_stricmp( flag[i], "evenDistribution" ) )
825 			mSpawnFlags |= FX_EVEN_DISTRIBUTION;
826 		else if ( !Q_stricmp( flag[i], "rgbComponentInterpolation" ) )
827 			mSpawnFlags |= FX_RGB_COMPONENT_INTERP;
828 		else if ( !Q_stricmp( flag[i], "affectedByWind" ) )
829 			mSpawnFlags |= FX_AFFECTED_BY_WIND;
830 		else
831 		{ // we have badness going on, but continue on in case there are any valid fields in here
832 			ok = false;
833 		}
834 	}
835 
836 	return ok;
837 }
838 
839 
840 
ParseMaterialImpact(const char * val)841 bool CPrimitiveTemplate::ParseMaterialImpact(const char *val)
842 {
843 	if (!Q_stricmp(val, "shellsound"))
844 	{
845 		mMatImpactFX = MATIMPACTFX_SHELLSOUND;
846 	}
847 	else
848 	{
849 		mMatImpactFX = MATIMPACTFX_NONE;
850 		theFxHelper.Print( "CPrimitiveTemplate::ParseMaterialImpact -- unknown materialImpact type!\n" );
851 		return false;
852 	}
853 	return true;
854 }
855 
856 
857 //------------------------------------------------------
858 // ParseAcceleration
859 //	Reads in a ranged acceleration field in vector format
860 //
861 // input:
862 //	string that contains one or two vectors
863 //
864 // return:
865 //	success of parse operation.
866 //------------------------------------------------------
ParseAcceleration(const char * val)867 bool CPrimitiveTemplate::ParseAcceleration( const char *val )
868 {
869 	vec3_t min, max;
870 
871 	if ( ParseVector( val, min, max ) == true )
872 	{
873 		mAccelX.SetRange( min[0], max[0] );
874 		mAccelY.SetRange( min[1], max[1] );
875 		mAccelZ.SetRange( min[2], max[2] );
876 		return true;
877 	}
878 
879 	return false;
880 }
881 
882 //------------------------------------------------------
883 // ParseGravity
884 //	Reads in a ranged gravity value
885 //
886 // input:
887 //	string that contains one or two floats
888 //
889 // return:
890 //	success of parse operation.
891 //------------------------------------------------------
ParseGravity(const char * val)892 bool CPrimitiveTemplate::ParseGravity( const char *val )
893 {
894 	float min, max;
895 
896 	if ( ParseFloat( val, &min, &max ) == true )
897 	{
898 		mGravity.SetRange( min, max );
899 		return true;
900 	}
901 
902 	return false;
903 }
904 
905 //------------------------------------------------------
906 // ParseDensity
907 //	Reads in a ranged density value.  Density is only
908 //	for emitters that are calling effects...it basically
909 //	specifies how often the emitter should emit fx.
910 //
911 // input:
912 //	string that contains one or two floats
913 //
914 // return:
915 //	success of parse operation.
916 //------------------------------------------------------
ParseDensity(const char * val)917 bool CPrimitiveTemplate::ParseDensity( const char *val )
918 {
919 	float min, max;
920 
921 	if ( ParseFloat( val, &min, &max ) == true )
922 	{
923 		mDensity.SetRange( min, max );
924 		return true;
925 	}
926 
927 	return false;
928 }
929 
930 //------------------------------------------------------
931 // ParseVariance
932 //	Reads in a ranged variance value.  Variance is only
933 //	valid for emitters that are calling effects...
934 //	it basically determines the amount of slop in the
935 //	density calculations
936 //
937 // input:
938 //	string that contains one or two floats
939 //
940 // return:
941 //	success of parse operation.
942 //------------------------------------------------------
ParseVariance(const char * val)943 bool CPrimitiveTemplate::ParseVariance( const char *val )
944 {
945 	float min, max;
946 
947 	if ( ParseFloat( val, &min, &max ) == true )
948 	{
949 		mVariance.SetRange( min, max );
950 		return true;
951 	}
952 
953 	return false;
954 }
955 
956 //------------------------------------------------------
957 // ParseRGBStart
958 //	Reads in a ranged rgbStart field in vector format
959 //
960 // input:
961 //	string that contains one or two vectors
962 //
963 // return:
964 //	success of parse operation.
965 //------------------------------------------------------
ParseRGBStart(const char * val)966 bool CPrimitiveTemplate::ParseRGBStart( const char *val )
967 {
968 	vec3_t min, max;
969 
970 	if ( ParseVector( val, min, max ) == true )
971 	{
972 		mRedStart.SetRange( min[0], max[0] );
973 		mGreenStart.SetRange( min[1], max[1] );
974 		mBlueStart.SetRange( min[2], max[2] );
975 		return true;
976 	}
977 
978 	return false;
979 }
980 
981 //------------------------------------------------------
982 // ParseRGBEnd
983 //	Reads in a ranged rgbEnd field in vector format
984 //
985 // input:
986 //	string that contains one or two vectors
987 //
988 // return:
989 //	success of parse operation.
990 //------------------------------------------------------
ParseRGBEnd(const char * val)991 bool CPrimitiveTemplate::ParseRGBEnd( const char *val )
992 {
993 	vec3_t min, max;
994 
995 	if ( ParseVector( val, min, max ) == true )
996 	{
997 		mRedEnd.SetRange( min[0], max[0] );
998 		mGreenEnd.SetRange( min[1], max[1] );
999 		mBlueEnd.SetRange( min[2], max[2] );
1000 		return true;
1001 	}
1002 
1003 	return false;
1004 }
1005 
1006 //------------------------------------------------------
1007 // ParseRGBParm
1008 //	Reads in a ranged rgbParm field in float format
1009 //
1010 // input:
1011 //	string that contains one or two floats
1012 //
1013 // return:
1014 //	success of parse operation.
1015 //------------------------------------------------------
ParseRGBParm(const char * val)1016 bool CPrimitiveTemplate::ParseRGBParm( const char *val )
1017 {
1018 	float min, max;
1019 
1020 	if ( ParseFloat( val, &min, &max ) == true )
1021 	{
1022 		mRGBParm.SetRange( min, max );
1023 		return true;
1024 	}
1025 
1026 	return false;
1027 }
1028 
1029 //------------------------------------------------------
1030 // ParseRGBFlags
1031 //	Reads in a set of rgbFlags in string format
1032 //
1033 // input:
1034 //	string that contains the flag strings
1035 //
1036 // return:
1037 //	success of parse operation.
1038 //------------------------------------------------------
ParseRGBFlags(const char * val)1039 bool CPrimitiveTemplate::ParseRGBFlags( const char *val )
1040 {
1041 	int flags;
1042 
1043 	if ( ParseGroupFlags( val, &flags ) == true )
1044 	{
1045 		// Convert our generic flag values into type specific ones
1046 		mFlags |= ( flags << FX_RGB_SHIFT );
1047 		return true;
1048 	}
1049 
1050 	return false;
1051 }
1052 
1053 //------------------------------------------------------
1054 // ParseAlphaStart
1055 //	Reads in a ranged alphaStart field in float format
1056 //
1057 // input:
1058 //	string that contains one or two floats
1059 //
1060 // return:
1061 //	success of parse operation.
1062 //------------------------------------------------------
ParseAlphaStart(const char * val)1063 bool CPrimitiveTemplate::ParseAlphaStart( const char *val )
1064 {
1065 	float min, max;
1066 
1067 	if ( ParseFloat( val, &min, &max ) == true )
1068 	{
1069 		mAlphaStart.SetRange( min, max );
1070 		return true;
1071 	}
1072 
1073 	return false;
1074 }
1075 
1076 //------------------------------------------------------
1077 // ParseAlphaEnd
1078 //	Reads in a ranged alphaEnd field in float format
1079 //
1080 // input:
1081 //	string that contains one or two floats
1082 //
1083 // return:
1084 //	success of parse operation.
1085 //------------------------------------------------------
ParseAlphaEnd(const char * val)1086 bool CPrimitiveTemplate::ParseAlphaEnd( const char *val )
1087 {
1088 	float min, max;
1089 
1090 	if ( ParseFloat( val, &min, &max ) == true )
1091 	{
1092 		mAlphaEnd.SetRange( min, max );
1093 		return true;
1094 	}
1095 
1096 	return false;
1097 }
1098 
1099 //------------------------------------------------------
1100 // ParseAlphaParm
1101 //	Reads in a ranged alphaParm field in float format
1102 //
1103 // input:
1104 //	string that contains one or two floats
1105 //
1106 // return:
1107 //	success of parse operation.
1108 //------------------------------------------------------
ParseAlphaParm(const char * val)1109 bool CPrimitiveTemplate::ParseAlphaParm( const char *val )
1110 {
1111 	float min, max;
1112 
1113 	if ( ParseFloat( val, &min, &max ) == true )
1114 	{
1115 		mAlphaParm.SetRange( min, max );
1116 		return true;
1117 	}
1118 
1119 	return false;
1120 }
1121 
1122 //------------------------------------------------------
1123 // ParseAlphaFlags
1124 //	Reads in a set of alphaFlags in string format
1125 //
1126 // input:
1127 //	string that contains the flag strings
1128 //
1129 // return:
1130 //	success of parse operation.
1131 //------------------------------------------------------
ParseAlphaFlags(const char * val)1132 bool CPrimitiveTemplate::ParseAlphaFlags( const char *val )
1133 {
1134 	int flags;
1135 
1136 	if ( ParseGroupFlags( val, &flags ) == true )
1137 	{
1138 		// Convert our generic flag values into type specific ones
1139 		mFlags |= ( flags << FX_ALPHA_SHIFT );
1140 		return true;
1141 	}
1142 
1143 	return false;
1144 }
1145 
1146 //------------------------------------------------------
1147 // ParseSizeStart
1148 //	Reads in a ranged sizeStart field in float format
1149 //
1150 // input:
1151 //	string that contains one or two floats
1152 //
1153 // return:
1154 //	success of parse operation.
1155 //------------------------------------------------------
ParseSizeStart(const char * val)1156 bool CPrimitiveTemplate::ParseSizeStart( const char *val )
1157 {
1158 	float min, max;
1159 
1160 	if ( ParseFloat( val, &min, &max ) == true )
1161 	{
1162 		mSizeStart.SetRange( min, max );
1163 		return true;
1164 	}
1165 
1166 	return false;
1167 }
1168 
1169 //------------------------------------------------------
1170 // ParseSizeEnd
1171 //	Reads in a ranged sizeEnd field in float format
1172 //
1173 // input:
1174 //	string that contains one or two floats
1175 //
1176 // return:
1177 //	success of parse operation.
1178 //------------------------------------------------------
ParseSizeEnd(const char * val)1179 bool CPrimitiveTemplate::ParseSizeEnd( const char *val )
1180 {
1181 	float min, max;
1182 
1183 	if ( ParseFloat( val, &min, &max ) == true )
1184 	{
1185 		mSizeEnd.SetRange( min, max );
1186 		return true;
1187 	}
1188 
1189 	return false;
1190 }
1191 
1192 //------------------------------------------------------
1193 // ParseSizeParm
1194 //	Reads in a ranged sizeParm field in float format
1195 //
1196 // input:
1197 //	string that contains one or two floats
1198 //
1199 // return:
1200 //	success of parse operation.
1201 //------------------------------------------------------
ParseSizeParm(const char * val)1202 bool CPrimitiveTemplate::ParseSizeParm( const char *val )
1203 {
1204 	float min, max;
1205 
1206 	if ( ParseFloat( val, &min, &max ) == true )
1207 	{
1208 		mSizeParm.SetRange( min, max );
1209 		return true;
1210 	}
1211 
1212 	return false;
1213 }
1214 
1215 //------------------------------------------------------
1216 // ParseSizeFlags
1217 //	Reads in a set of sizeFlags in string format
1218 //
1219 // input:
1220 //	string that contains the flag strings
1221 //
1222 // return:
1223 //	success of parse operation.
1224 //------------------------------------------------------
ParseSizeFlags(const char * val)1225 bool CPrimitiveTemplate::ParseSizeFlags( const char *val )
1226 {
1227 	int flags;
1228 
1229 	if ( ParseGroupFlags( val, &flags ) == true )
1230 	{
1231 		// Convert our generic flag values into type specific ones
1232 		mFlags |= ( flags << FX_SIZE_SHIFT );
1233 		return true;
1234 	}
1235 
1236 	return false;
1237 }
1238 
1239 //------------------------------------------------------
1240 // ParseSize2Start
1241 //	Reads in a ranged Size2Start field in float format
1242 //
1243 // input:
1244 //	string that contains one or two floats
1245 //
1246 // return:
1247 //	success of parse operation.
1248 //------------------------------------------------------
ParseSize2Start(const char * val)1249 bool CPrimitiveTemplate::ParseSize2Start( const char *val )
1250 {
1251 	float min, max;
1252 
1253 	if ( ParseFloat( val, &min, &max ) == true )
1254 	{
1255 		mSize2Start.SetRange( min, max );
1256 		return true;
1257 	}
1258 
1259 	return false;
1260 }
1261 
1262 //------------------------------------------------------
1263 // ParseSize2End
1264 //	Reads in a ranged Size2End field in float format
1265 //
1266 // input:
1267 //	string that contains one or two floats
1268 //
1269 // return:
1270 //	success of parse operation.
1271 //------------------------------------------------------
ParseSize2End(const char * val)1272 bool CPrimitiveTemplate::ParseSize2End( const char *val )
1273 {
1274 	float min, max;
1275 
1276 	if ( ParseFloat( val, &min, &max ) == true )
1277 	{
1278 		mSize2End.SetRange( min, max );
1279 		return true;
1280 	}
1281 
1282 	return false;
1283 }
1284 
1285 //------------------------------------------------------
1286 // ParseSize2Parm
1287 //	Reads in a ranged Size2Parm field in float format
1288 //
1289 // input:
1290 //	string that contains one or two floats
1291 //
1292 // return:
1293 //	success of parse operation.
1294 //------------------------------------------------------
ParseSize2Parm(const char * val)1295 bool CPrimitiveTemplate::ParseSize2Parm( const char *val )
1296 {
1297 	float min, max;
1298 
1299 	if ( ParseFloat( val, &min, &max ) == true )
1300 	{
1301 		mSize2Parm.SetRange( min, max );
1302 		return true;
1303 	}
1304 
1305 	return false;
1306 }
1307 
1308 //------------------------------------------------------
1309 // ParseSize2Flags
1310 //	Reads in a set of Size2Flags in string format
1311 //
1312 // input:
1313 //	string that contains the flag strings
1314 //
1315 // return:
1316 //	success of parse operation.
1317 //------------------------------------------------------
ParseSize2Flags(const char * val)1318 bool CPrimitiveTemplate::ParseSize2Flags( const char *val )
1319 {
1320 	int flags;
1321 
1322 	if ( ParseGroupFlags( val, &flags ) == true )
1323 	{
1324 		// Convert our generic flag values into type specific ones
1325 		mFlags |= ( flags << FX_SIZE2_SHIFT );
1326 		return true;
1327 	}
1328 
1329 	return false;
1330 }
1331 
1332 //------------------------------------------------------
1333 // ParseLengthStart
1334 //	Reads in a ranged lengthStart field in float format
1335 //
1336 // input:
1337 //	string that contains one or two floats
1338 //
1339 // return:
1340 //	success of parse operation.
1341 //------------------------------------------------------
ParseLengthStart(const char * val)1342 bool CPrimitiveTemplate::ParseLengthStart( const char *val )
1343 {
1344 	float min, max;
1345 
1346 	if ( ParseFloat( val, &min, &max ) == true )
1347 	{
1348 		mLengthStart.SetRange( min, max );
1349 		return true;
1350 	}
1351 
1352 	return false;
1353 }
1354 
1355 //------------------------------------------------------
1356 // ParseLengthEnd
1357 //	Reads in a ranged lengthEnd field in float format
1358 //
1359 // input:
1360 //	string that contains one or two floats
1361 //
1362 // return:
1363 //	success of parse operation.
1364 //------------------------------------------------------
ParseLengthEnd(const char * val)1365 bool CPrimitiveTemplate::ParseLengthEnd( const char *val )
1366 {
1367 	float min, max;
1368 
1369 	if ( ParseFloat( val, &min, &max ) == true )
1370 	{
1371 		mLengthEnd.SetRange( min, max );
1372 		return true;
1373 	}
1374 
1375 	return false;
1376 }
1377 
1378 //------------------------------------------------------
1379 // ParseLengthParm
1380 //	Reads in a ranged lengthParm field in float format
1381 //
1382 // input:
1383 //	string that contains one or two floats
1384 //
1385 // return:
1386 //	success of parse operation.
1387 //------------------------------------------------------
ParseLengthParm(const char * val)1388 bool CPrimitiveTemplate::ParseLengthParm( const char *val )
1389 {
1390 	float min, max;
1391 
1392 	if ( ParseFloat( val, &min, &max ) == true )
1393 	{
1394 		mLengthParm.SetRange( min, max );
1395 		return true;
1396 	}
1397 
1398 	return false;
1399 }
1400 
1401 //------------------------------------------------------
1402 // ParseLengthFlags
1403 //	Reads in a set of lengthFlags in string format
1404 //
1405 // input:
1406 //	string that contains the flag strings
1407 //
1408 // return:
1409 //	success of parse operation.
1410 //------------------------------------------------------
ParseLengthFlags(const char * val)1411 bool CPrimitiveTemplate::ParseLengthFlags( const char *val )
1412 {
1413 	int flags;
1414 
1415 	if ( ParseGroupFlags( val, &flags ) == true )
1416 	{
1417 		// Convert our generic flag values into type specific ones
1418 		mFlags |= ( flags << FX_LENGTH_SHIFT );
1419 		return true;
1420 	}
1421 
1422 	return false;
1423 }
1424 
1425 //------------------------------------------------------
1426 // ParseShaders
1427 //	Reads in a group of shaders and registers them
1428 //
1429 // input:
1430 //	Parse group that contains the list of shaders to parse
1431 //
1432 // return:
1433 //	success of parse operation.
1434 //------------------------------------------------------
ParseShaders(CGPValue * grp)1435 bool CPrimitiveTemplate::ParseShaders( CGPValue *grp )
1436 {
1437 	const char	*val;
1438 	int			handle;
1439 
1440 	if ( grp->IsList() )
1441 	{
1442 		// If we are a list we have to do separate processing
1443 		CGPObject *list = grp->GetList();
1444 
1445 		while ( list )
1446 		{
1447 			// name is actually the value contained in the list
1448 			val = list->GetName();
1449 
1450 			handle = theFxHelper.RegisterShader( val );
1451 			mMediaHandles.AddHandle( handle );
1452 
1453 			list = (CGPValue *)list->GetNext();
1454 		}
1455 	}
1456 	else
1457 	{
1458 		// Let's get a value
1459 		val = grp->GetTopValue();
1460 
1461 		if ( val )
1462 		{
1463 			handle = theFxHelper.RegisterShader( val );
1464 			mMediaHandles.AddHandle( handle );
1465 		}
1466 		else
1467 		{
1468 			// empty "list"
1469 			theFxHelper.Print( "CPrimitiveTemplate::ParseShaders called with an empty list!\n" );
1470 			return false;
1471 		}
1472 	}
1473 
1474 	return true;
1475 }
1476 
1477 //------------------------------------------------------
1478 // ParseSounds
1479 //	Reads in a group of sounds and registers them
1480 //
1481 // input:
1482 //	Parse group that contains the list of sounds to parse
1483 //
1484 // return:
1485 //	success of parse operation.
1486 //------------------------------------------------------
ParseSounds(CGPValue * grp)1487 bool CPrimitiveTemplate::ParseSounds( CGPValue *grp )
1488 {
1489 	const char	*val;
1490 	int			handle;
1491 
1492 	if ( grp->IsList() )
1493 	{
1494 		// If we are a list we have to do separate processing
1495 		CGPObject *list = grp->GetList();
1496 
1497 		while ( list )
1498 		{
1499 			// name is actually the value contained in the list
1500 			val = list->GetName();
1501 
1502 			handle = theFxHelper.RegisterSound( val );
1503 			mMediaHandles.AddHandle( handle );
1504 
1505 			list = (CGPValue *)list->GetNext();
1506 		}
1507 	}
1508 	else
1509 	{
1510 		// Let's get a value
1511 		val = grp->GetTopValue();
1512 
1513 		if ( val )
1514 		{
1515 			handle = theFxHelper.RegisterSound( val );
1516 			mMediaHandles.AddHandle( handle );
1517 		}
1518 		else
1519 		{
1520 			// empty "list"
1521 			theFxHelper.Print( "CPrimitiveTemplate::ParseSounds called with an empty list!\n" );
1522 			return false;
1523 		}
1524 	}
1525 
1526 	return true;
1527 }
1528 
1529 //------------------------------------------------------
1530 // ParseModels
1531 //	Reads in a group of models and registers them
1532 //
1533 // input:
1534 //	Parse group that contains the list of models to parse
1535 //
1536 // return:
1537 //	success of parse operation.
1538 //------------------------------------------------------
ParseModels(CGPValue * grp)1539 bool CPrimitiveTemplate::ParseModels( CGPValue *grp )
1540 {
1541 	const char	*val;
1542 	int			handle;
1543 
1544 	if ( grp->IsList() )
1545 	{
1546 		// If we are a list we have to do separate processing
1547 		CGPObject *list = grp->GetList();
1548 
1549 		while ( list )
1550 		{
1551 			// name is actually the value contained in the list
1552 			val = list->GetName();
1553 
1554 			handle = theFxHelper.RegisterModel( val );
1555 			mMediaHandles.AddHandle( handle );
1556 
1557 			list = (CGPValue *)list->GetNext();
1558 		}
1559 	}
1560 	else
1561 	{
1562 		// Let's get a value
1563 		val = grp->GetTopValue();
1564 
1565 		if ( val )
1566 		{
1567 			handle = theFxHelper.RegisterModel( val );
1568 			mMediaHandles.AddHandle( handle );
1569 		}
1570 		else
1571 		{
1572 			// empty "list"
1573 			theFxHelper.Print( "CPrimitiveTemplate::ParseModels called with an empty list!\n" );
1574 			return false;
1575 		}
1576 	}
1577 
1578 	mFlags |= FX_ATTACHED_MODEL;
1579 
1580 	return true;
1581 }
1582 
1583 //------------------------------------------------------
1584 // ParseImpactFxStrings
1585 //	Reads in a group of fx file names and registers them
1586 //
1587 // input:
1588 //	Parse group that contains the list of fx to parse
1589 //
1590 // return:
1591 //	success of parse operation.
1592 //------------------------------------------------------
ParseImpactFxStrings(CGPValue * grp)1593 bool CPrimitiveTemplate::ParseImpactFxStrings( CGPValue *grp )
1594 {
1595 	const char	*val;
1596 	int			handle;
1597 
1598 	if ( grp->IsList() )
1599 	{
1600 		// If we are a list we have to do separate processing
1601 		CGPObject *list = grp->GetList();
1602 
1603 		while ( list )
1604 		{
1605 			// name is actually the value contained in the list
1606 			val = list->GetName();
1607 			handle = theFxScheduler.RegisterEffect( val );
1608 
1609 			if ( handle )
1610 			{
1611 				mImpactFxHandles.AddHandle( handle );
1612 			}
1613 			else
1614 			{
1615 				theFxHelper.Print( "FxTemplate: Impact effect file not found.\n" );
1616 				return false;
1617 			}
1618 
1619 			list = (CGPValue *)list->GetNext();
1620 		}
1621 	}
1622 	else
1623 	{
1624 		// Let's get a value
1625 		val = grp->GetTopValue();
1626 
1627 		if ( val )
1628 		{
1629 			handle = theFxScheduler.RegisterEffect( val );
1630 
1631 			if ( handle )
1632 			{
1633 				mImpactFxHandles.AddHandle( handle );
1634 			}
1635 			else
1636 			{
1637 				theFxHelper.Print( "FxTemplate: Impact effect file not found.\n" );
1638 				return false;
1639 			}
1640 		}
1641 		else
1642 		{
1643 			// empty "list"
1644 			theFxHelper.Print( "CPrimitiveTemplate::ParseImpactFxStrings called with an empty list!\n" );
1645 			return false;
1646 		}
1647 	}
1648 
1649 	mFlags |= FX_IMPACT_RUNS_FX | FX_APPLY_PHYSICS;
1650 
1651 	return true;
1652 }
1653 
1654 //------------------------------------------------------
1655 // ParseDeathFxStrings
1656 //	Reads in a group of fx file names and registers them
1657 //
1658 // input:
1659 //	Parse group that contains the list of fx to parse
1660 //
1661 // return:
1662 //	success of parse operation.
1663 //------------------------------------------------------
ParseDeathFxStrings(CGPValue * grp)1664 bool CPrimitiveTemplate::ParseDeathFxStrings( CGPValue *grp )
1665 {
1666 	const char	*val;
1667 	int			handle;
1668 
1669 	if ( grp->IsList() )
1670 	{
1671 		// If we are a list we have to do separate processing
1672 		CGPObject *list = grp->GetList();
1673 
1674 		while ( list )
1675 		{
1676 			// name is actually the value contained in the list
1677 			val = list->GetName();
1678 			handle = theFxScheduler.RegisterEffect( val );
1679 
1680 			if ( handle )
1681 			{
1682 				mDeathFxHandles.AddHandle( handle );
1683 			}
1684 			else
1685 			{
1686 				theFxHelper.Print( "FxTemplate: Death effect file not found.\n" );
1687 				return false;
1688 			}
1689 
1690 			list = (CGPValue *)list->GetNext();
1691 		}
1692 	}
1693 	else
1694 	{
1695 		// Let's get a value
1696 		val = grp->GetTopValue();
1697 
1698 		if ( val )
1699 		{
1700 			handle = theFxScheduler.RegisterEffect( val );
1701 
1702 			if ( handle )
1703 			{
1704 				mDeathFxHandles.AddHandle( handle );
1705 			}
1706 			else
1707 			{
1708 				theFxHelper.Print( "FxTemplate: Death effect file not found.\n" );
1709 				return false;
1710 			}
1711 		}
1712 		else
1713 		{
1714 			// empty "list"
1715 			theFxHelper.Print( "CPrimitiveTemplate::ParseDeathFxStrings called with an empty list!\n" );
1716 			return false;
1717 		}
1718 	}
1719 
1720 	mFlags |= FX_DEATH_RUNS_FX;
1721 
1722 	return true;
1723 }
1724 
1725 //------------------------------------------------------
1726 // ParseEmitterFxStrings
1727 //	Reads in a group of fx file names and registers them
1728 //
1729 // input:
1730 //	Parse group that contains the list of fx to parse
1731 //
1732 // return:
1733 //	success of parse operation.
1734 //------------------------------------------------------
ParseEmitterFxStrings(CGPValue * grp)1735 bool CPrimitiveTemplate::ParseEmitterFxStrings( CGPValue *grp )
1736 {
1737 	const char	*val;
1738 	int			handle;
1739 
1740 	if ( grp->IsList() )
1741 	{
1742 		// If we are a list we have to do separate processing
1743 		CGPObject *list = grp->GetList();
1744 
1745 		while ( list )
1746 		{
1747 			// name is actually the value contained in the list
1748 			val = list->GetName();
1749 			handle = theFxScheduler.RegisterEffect( val );
1750 
1751 			if ( handle )
1752 			{
1753 				mEmitterFxHandles.AddHandle( handle );
1754 			}
1755 			else
1756 			{
1757 				theFxHelper.Print( "FxTemplate: Emitter effect file not found.\n" );
1758 				return false;
1759 			}
1760 
1761 			list = (CGPValue *)list->GetNext();
1762 		}
1763 	}
1764 	else
1765 	{
1766 		// Let's get a value
1767 		val = grp->GetTopValue();
1768 
1769 		if ( val )
1770 		{
1771 			handle = theFxScheduler.RegisterEffect( val );
1772 
1773 			if ( handle )
1774 			{
1775 				mEmitterFxHandles.AddHandle( handle );
1776 			}
1777 			else
1778 			{
1779 				theFxHelper.Print( "FxTemplate: Emitter effect file not found.\n" );
1780 				return false;
1781 			}
1782 		}
1783 		else
1784 		{
1785 			// empty "list"
1786 			theFxHelper.Print( "CPrimitiveTemplate::ParseEmitterFxStrings called with an empty list!\n" );
1787 			return false;
1788 		}
1789 	}
1790 
1791 	mFlags |= FX_EMIT_FX;
1792 
1793 	return true;
1794 }
1795 
1796 //------------------------------------------------------
1797 // ParsePlayFxStrings
1798 //	Reads in a group of fx file names and registers them
1799 //
1800 // input:
1801 //	Parse group that contains the list of fx to parse
1802 //
1803 // return:
1804 //	success of parse operation.
1805 //------------------------------------------------------
ParsePlayFxStrings(CGPValue * grp)1806 bool CPrimitiveTemplate::ParsePlayFxStrings( CGPValue *grp )
1807 {
1808 	const char	*val;
1809 	int			handle;
1810 
1811 	if ( grp->IsList() )
1812 	{
1813 		// If we are a list we have to do separate processing
1814 		CGPObject *list = grp->GetList();
1815 
1816 		while ( list )
1817 		{
1818 			// name is actually the value contained in the list
1819 			val = list->GetName();
1820 			handle = theFxScheduler.RegisterEffect( val );
1821 
1822 			if ( handle )
1823 			{
1824 				mPlayFxHandles.AddHandle( handle );
1825 			}
1826 			else
1827 			{
1828 				theFxHelper.Print( "FxTemplate: Effect file not found.\n" );
1829 				return false;
1830 			}
1831 
1832 			list = (CGPValue *)list->GetNext();
1833 		}
1834 	}
1835 	else
1836 	{
1837 		// Let's get a value
1838 		val = grp->GetTopValue();
1839 
1840 		if ( val )
1841 		{
1842 			handle = theFxScheduler.RegisterEffect( val );
1843 
1844 			if ( handle )
1845 			{
1846 				mPlayFxHandles.AddHandle( handle );
1847 			}
1848 			else
1849 			{
1850 				theFxHelper.Print( "FxTemplate: Effect file not found.\n" );
1851 				return false;
1852 			}
1853 		}
1854 		else
1855 		{
1856 			// empty "list"
1857 			theFxHelper.Print( "CPrimitiveTemplate::ParsePlayFxStrings called with an empty list!\n" );
1858 			return false;
1859 		}
1860 	}
1861 
1862 	return true;
1863 }
1864 
1865 //------------------------------------------------------
1866 // ParseRGB
1867 //	Takes an RGB group and chomps out any pairs contained
1868 //	in it.
1869 //
1870 // input:
1871 //	the parse group to process
1872 //
1873 // return:
1874 //	success of parse operation.
1875 //------------------------------------------------------
ParseRGB(CGPGroup * grp)1876 bool CPrimitiveTemplate::ParseRGB( CGPGroup *grp )
1877 {
1878 	CGPValue	*pairs;
1879 	const char	*key;
1880 	const char	*val;
1881 
1882 	// Inside of the group, we should have a series of pairs
1883 	pairs = grp->GetPairs();
1884 
1885 	while( pairs )
1886 	{
1887 		// Let's get the key field
1888 		key = pairs->GetName();
1889 		val = pairs->GetTopValue();
1890 
1891 		// Huge Q_stricmp lists suxor
1892 			 if ( !Q_stricmp( key, "start" ) )
1893 			ParseRGBStart( val );
1894 		else if ( !Q_stricmp( key, "end" ) )
1895 			ParseRGBEnd( val );
1896 		else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) )
1897 			ParseRGBParm( val );
1898 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) )
1899 			ParseRGBFlags( val );
1900 		else
1901 			theFxHelper.Print( "Unknown key parsing an RGB group: %s\n", key );
1902 
1903 		pairs = (CGPValue *)pairs->GetNext();
1904 	}
1905 
1906 	return true;
1907 }
1908 
1909 //------------------------------------------------------
1910 // ParseAlpha
1911 //	Takes an alpha group and chomps out any pairs contained
1912 //	in it.
1913 //
1914 // input:
1915 //	the parse group to process
1916 //
1917 // return:
1918 //	success of parse operation.
1919 //------------------------------------------------------
ParseAlpha(CGPGroup * grp)1920 bool CPrimitiveTemplate::ParseAlpha( CGPGroup *grp )
1921 {
1922 	CGPValue	*pairs;
1923 	const char	*key;
1924 	const char	*val;
1925 
1926 	// Inside of the group, we should have a series of pairs
1927 	pairs = grp->GetPairs();
1928 
1929 	while( pairs )
1930 	{
1931 		// Let's get the key field
1932 		key = pairs->GetName();
1933 		val = pairs->GetTopValue();
1934 
1935 		// Huge Q_stricmp lists suxor
1936 			 if ( !Q_stricmp( key, "start" ) )
1937 			ParseAlphaStart( val );
1938 		else if ( !Q_stricmp( key, "end" ) )
1939 			ParseAlphaEnd( val );
1940 		else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) )
1941 			ParseAlphaParm( val );
1942 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) )
1943 			ParseAlphaFlags( val );
1944 		else
1945 			theFxHelper.Print( "Unknown key parsing an Alpha group: %s\n", key );
1946 
1947 		pairs = (CGPValue *)pairs->GetNext();
1948 	}
1949 
1950 	return true;
1951 }
1952 
1953 //------------------------------------------------------
1954 // ParseSize
1955 //	Takes a size group and chomps out any pairs contained
1956 //	in it.
1957 //
1958 // input:
1959 //	the parse group to process
1960 //
1961 // return:
1962 //	success of parse operation.
1963 //------------------------------------------------------
ParseSize(CGPGroup * grp)1964 bool CPrimitiveTemplate::ParseSize( CGPGroup *grp )
1965 {
1966 	CGPValue	*pairs;
1967 	const char	*key;
1968 	const char	*val;
1969 
1970 	// Inside of the group, we should have a series of pairs
1971 	pairs = grp->GetPairs();
1972 
1973 	while( pairs )
1974 	{
1975 		// Let's get the key field
1976 		key = pairs->GetName();
1977 		val = pairs->GetTopValue();
1978 
1979 		// Huge Q_stricmp lists suxor
1980 			 if ( !Q_stricmp( key, "start" ) )
1981 			ParseSizeStart( val );
1982 		else if ( !Q_stricmp( key, "end" ) )
1983 			ParseSizeEnd( val );
1984 		else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) )
1985 			ParseSizeParm( val );
1986 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) )
1987 			ParseSizeFlags( val );
1988 		else
1989 			theFxHelper.Print( "Unknown key parsing a Size group: %s\n", key );
1990 
1991 		pairs = (CGPValue *)pairs->GetNext();
1992 	}
1993 
1994 	return true;
1995 }
1996 
1997 //------------------------------------------------------
1998 // ParseSize2
1999 //	Takes a Size2 group and chomps out any pairs contained
2000 //	in it.
2001 //
2002 // input:
2003 //	the parse group to process
2004 //
2005 // return:
2006 //	success of parse operation.
2007 //------------------------------------------------------
ParseSize2(CGPGroup * grp)2008 bool CPrimitiveTemplate::ParseSize2( CGPGroup *grp )
2009 {
2010 	CGPValue	*pairs;
2011 	const char	*key;
2012 	const char	*val;
2013 
2014 	// Inside of the group, we should have a series of pairs
2015 	pairs = grp->GetPairs();
2016 
2017 	while( pairs )
2018 	{
2019 		// Let's get the key field
2020 		key = pairs->GetName();
2021 		val = pairs->GetTopValue();
2022 
2023 		// Huge Q_stricmp lists suxor
2024 			 if ( !Q_stricmp( key, "start" ) )
2025 			ParseSize2Start( val );
2026 		else if ( !Q_stricmp( key, "end" ) )
2027 			ParseSize2End( val );
2028 		else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) )
2029 			ParseSize2Parm( val );
2030 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) )
2031 			ParseSize2Flags( val );
2032 		else
2033 			theFxHelper.Print( "Unknown key parsing a Size2 group: %s\n", key );
2034 
2035 		pairs = (CGPValue *)pairs->GetNext();
2036 	}
2037 
2038 	return true;
2039 }
2040 
2041 //------------------------------------------------------
2042 // ParseLength
2043 //	Takes a length group and chomps out any pairs contained
2044 //	in it.
2045 //
2046 // input:
2047 //	the parse group to process
2048 //
2049 // return:
2050 //	success of parse operation.
2051 //------------------------------------------------------
ParseLength(CGPGroup * grp)2052 bool CPrimitiveTemplate::ParseLength( CGPGroup *grp )
2053 {
2054 	CGPValue	*pairs;
2055 	const char	*key;
2056 	const char	*val;
2057 
2058 	// Inside of the group, we should have a series of pairs
2059 	pairs = grp->GetPairs();
2060 
2061 	while( pairs )
2062 	{
2063 		// Let's get the key field
2064 		key = pairs->GetName();
2065 		val = pairs->GetTopValue();
2066 
2067 		// Huge Q_stricmp lists suxor
2068 			 if ( !Q_stricmp( key, "start" ))
2069 			ParseLengthStart( val );
2070 		else if ( !Q_stricmp( key, "end" ))
2071 			ParseLengthEnd( val );
2072 		else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ))
2073 			ParseLengthParm( val );
2074 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ))
2075 			ParseLengthFlags( val );
2076 		else
2077 			theFxHelper.Print( "Unknown key parsing a Length group: %s\n", key );
2078 
2079 		pairs = (CGPValue *)pairs->GetNext();
2080 	}
2081 
2082 	return true;
2083 }
2084 
2085 // Parse a primitive, apply defaults first, grab any base level
2086 //	key pairs, then process any sub groups we may contain.
2087 //------------------------------------------------------
ParsePrimitive(CGPGroup * grp)2088 bool CPrimitiveTemplate::ParsePrimitive( CGPGroup *grp )
2089 {
2090 	CGPGroup	*subGrp;
2091 	CGPValue	*pairs;
2092 	const char	*key;
2093 	const char	*val;
2094 
2095 	// Lets work with the pairs first
2096 	pairs = grp->GetPairs();
2097 
2098 	while( pairs )
2099 	{
2100 		// the fields
2101 		key = pairs->GetName();
2102 		val = pairs->GetTopValue();
2103 
2104 		// Huge Q_stricmp lists suxor
2105 			 if ( !Q_stricmp( key, "count" ) )
2106 			ParseCount( val );
2107 		else if ( !Q_stricmp( key, "shaders" ) || !Q_stricmp( key, "shader" ) )
2108 			ParseShaders( pairs );
2109 		else if ( !Q_stricmp( key, "models" ) || !Q_stricmp( key, "model" ) )
2110 			ParseModels( pairs );
2111 		else if ( !Q_stricmp( key, "sounds" ) || !Q_stricmp( key, "sound" ) )
2112 			ParseSounds( pairs );
2113 		else if ( !Q_stricmp( key, "impactfx" ) )
2114 			ParseImpactFxStrings( pairs );
2115 		else if ( !Q_stricmp( key, "deathfx" ) )
2116 			ParseDeathFxStrings( pairs );
2117 		else if ( !Q_stricmp( key, "emitfx" ) )
2118 			ParseEmitterFxStrings( pairs );
2119 		else if ( !Q_stricmp( key, "playfx" ) )
2120 			ParsePlayFxStrings( pairs );
2121 		else if ( !Q_stricmp( key, "life" ) )
2122 			ParseLife( val );
2123 		else if ( !Q_stricmp( key, "delay" ) )
2124 			ParseDelay( val );
2125 		else if ( !Q_stricmp( key, "cullrange" ) ) {
2126 //			mCullRange = atoi( val );
2127 //			mCullRange *= mCullRange; // square it now so we don't have to square every time we compare
2128 		}
2129 		else if ( !Q_stricmp( key, "bounce" ) || !Q_stricmp( key, "intensity" ) ) // me==bad for reusing this...but it shouldn't hurt anything)
2130 			ParseElasticity( val );
2131 		else if ( !Q_stricmp( key, "min" ) )
2132 			ParseMin( val );
2133 		else if ( !Q_stricmp( key, "max" ) )
2134 			ParseMax( val );
2135 		else if ( !Q_stricmp( key, "angle" ) || !Q_stricmp( key, "angles" ) )
2136 			ParseAngle( val );
2137 		else if ( !Q_stricmp( key, "angleDelta" ) )
2138 			ParseAngleDelta( val );
2139 		else if ( !Q_stricmp( key, "velocity" ) || !Q_stricmp( key, "vel" ) )
2140 			ParseVelocity( val );
2141 		else if ( !Q_stricmp( key, "acceleration" ) || !Q_stricmp( key, "accel" ) )
2142 			ParseAcceleration( val );
2143 		else if ( !Q_stricmp( key, "gravity" ) )
2144 			ParseGravity( val );
2145 		else if ( !Q_stricmp( key, "density" ) )
2146 			ParseDensity( val );
2147 		else if ( !Q_stricmp( key, "variance" ) )
2148 			ParseVariance( val );
2149 		else if ( !Q_stricmp( key, "origin" ) )
2150 			ParseOrigin1( val );
2151 		else if ( !Q_stricmp( key, "origin2" ) )
2152 			ParseOrigin2( val );
2153 		else if ( !Q_stricmp( key, "radius" ) ) // part of ellipse/cylinder calcs.
2154 			ParseRadius( val );
2155 		else if ( !Q_stricmp( key, "height" ) ) // part of ellipse/cylinder calcs.
2156 			ParseHeight( val );
2157 		else if ( !Q_stricmp( key, "wind" ) )
2158 			ParseWindModifier( val );
2159 		else if ( !Q_stricmp( key, "rotation" ) )
2160 			ParseRotation( val );
2161 		else if ( !Q_stricmp( key, "rotationDelta" ) )
2162 			ParseRotationDelta( val );
2163 		// these need to get passed on to the primitive
2164 		else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) )
2165 			ParseFlags( val );
2166 		// these are used to spawn things in cool ways, but don't ever get passed on to prims.
2167 		else if ( !Q_stricmp( key, "spawnFlags" ) || !Q_stricmp( key, "spawnFlag" ) )
2168 			ParseSpawnFlags( val );
2169 		else if ( !Q_stricmp( key, "name" ) ) {
2170 			if ( val ) // just stash the descriptive name of the primitive
2171 				strcpy( mName, val );
2172 		}
2173 		else if ( !Q_stricmp( key, "materialImpact" ) )
2174 			ParseMaterialImpact( val );
2175 		else
2176 			theFxHelper.Print( "Unknown key parsing an effect primitive: %s\n", key );
2177 
2178 		pairs = (CGPValue *)pairs->GetNext();
2179 	}
2180 
2181 	subGrp = grp->GetSubGroups();
2182 
2183 	// Lets chomp on the groups now
2184 	while ( subGrp )
2185 	{
2186 		key = subGrp->GetName();
2187 
2188 			 if ( !Q_stricmp( key, "rgb" ) )
2189 			ParseRGB( subGrp );
2190 		else if ( !Q_stricmp( key, "alpha" ) )
2191 			ParseAlpha( subGrp );
2192 		else if ( !Q_stricmp( key, "size" ) || !Q_stricmp( key, "width" ) )
2193 			ParseSize( subGrp );
2194 		else if ( !Q_stricmp( key, "size2" ) || !Q_stricmp( key, "width2" ) )
2195 			ParseSize2( subGrp );
2196 		else if ( !Q_stricmp( key, "length" ) || !Q_stricmp( key, "height" ) )
2197 			ParseLength( subGrp );
2198 		else
2199 			theFxHelper.Print( "Unknown group key parsing a particle: %s\n", key );
2200 
2201 		subGrp = (CGPGroup *)subGrp->GetNext();
2202 	}
2203 
2204 	return true;
2205 }
2206