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