1 /*
2 ** thingdef-properties.cpp
3 **
4 ** Actor definitions - properties and flags handling
5 **
6 **---------------------------------------------------------------------------
7 ** Copyright 2002-2007 Christoph Oelckers
8 ** Copyright 2004-2007 Randy Heit
9 ** All rights reserved.
10 **
11 ** Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions
13 ** are met:
14 **
15 ** 1. Redistributions of source code must retain the above copyright
16 **    notice, this list of conditions and the following disclaimer.
17 ** 2. Redistributions in binary form must reproduce the above copyright
18 **    notice, this list of conditions and the following disclaimer in the
19 **    documentation and/or other materials provided with the distribution.
20 ** 3. The name of the author may not be used to endorse or promote products
21 **    derived from this software without specific prior written permission.
22 ** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
23 **    covered by the terms of the GNU General Public License as published by
24 **    the Free Software Foundation; either version 2 of the License, or (at
25 **    your option) any later version.
26 **
27 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 **---------------------------------------------------------------------------
38 **
39 */
40 
41 #include "gi.h"
42 #include "actor.h"
43 #include "info.h"
44 #include "tarray.h"
45 #include "w_wad.h"
46 #include "templates.h"
47 #include "r_defs.h"
48 #include "a_pickups.h"
49 #include "s_sound.h"
50 #include "cmdlib.h"
51 #include "p_lnspec.h"
52 #include "a_action.h"
53 #include "decallib.h"
54 #include "m_random.h"
55 #include "i_system.h"
56 #include "p_local.h"
57 #include "p_effect.h"
58 #include "v_palette.h"
59 #include "doomerrors.h"
60 #include "a_hexenglobal.h"
61 #include "a_weaponpiece.h"
62 #include "p_conversation.h"
63 #include "v_text.h"
64 #include "thingdef.h"
65 #include "a_sharedglobal.h"
66 #include "r_data/r_translate.h"
67 #include "a_morph.h"
68 #include "colormatcher.h"
69 #include "teaminfo.h"
70 #include "v_video.h"
71 #include "r_data/colormaps.h"
72 
73 
74 //==========================================================================
75 //
76 // Gets a class pointer and performs an error check for correct type
77 //
78 //==========================================================================
FindClassTentative(const char * name,const char * ancestor)79 static const PClass *FindClassTentative(const char *name, const char *ancestor)
80 {
81 	// "" and "none" mean 'no class'
82 	if (name == NULL || *name == 0 || !stricmp(name, "none"))
83 	{
84 		return NULL;
85 	}
86 
87 	const PClass *anc = PClass::FindClass(ancestor);
88 	assert(anc != NULL);	// parent classes used here should always be natively defined
89 	const PClass *cls = const_cast<PClass*>(anc)->FindClassTentative(name);
90 	assert (cls != NULL);	// cls can not ne NULL here
91 	if (!cls->IsDescendantOf(anc))
92 	{
93 		I_Error("%s does not inherit from %s\n", name, ancestor);
94 	}
95 	return cls;
96 }
97 
98 //==========================================================================
99 //
100 // Sets or clears a flag, taking field width into account.
101 //
102 //==========================================================================
ModActorFlag(AActor * actor,FFlagDef * fd,bool set)103 void ModActorFlag(AActor *actor, FFlagDef *fd, bool set)
104 {
105 	// Little-Endian machines only need one case, because all field sizes
106 	// start at the same address. (Unless the machine has unaligned access
107 	// exceptions, in which case you'll need multiple cases for it too.)
108 #ifdef __BIG_ENDIAN__
109 	if (fd->fieldsize == 4)
110 #endif
111 	{
112 		DWORD *flagvar = (DWORD *)((char *)actor + fd->structoffset);
113 		if (set)
114 		{
115 			*flagvar |= fd->flagbit;
116 		}
117 		else
118 		{
119 			*flagvar &= ~fd->flagbit;
120 		}
121 	}
122 #ifdef __BIG_ENDIAN__
123 	else if (fd->fieldsize == 2)
124 	{
125 		WORD *flagvar = (WORD *)((char *)actor + fd->structoffset);
126 		if (set)
127 		{
128 			*flagvar |= fd->flagbit;
129 		}
130 		else
131 		{
132 			*flagvar &= ~fd->flagbit;
133 		}
134 	}
135 	else
136 	{
137 		assert(fd->fieldsize == 1);
138 		BYTE *flagvar = (BYTE *)((char *)actor + fd->structoffset);
139 		if (set)
140 		{
141 			*flagvar |= fd->flagbit;
142 		}
143 		else
144 		{
145 			*flagvar &= ~fd->flagbit;
146 		}
147 	}
148 #endif
149 }
150 
151 //==========================================================================
152 //
153 // Returns whether an actor flag is true or not.
154 //
155 //==========================================================================
156 
CheckActorFlag(const AActor * owner,FFlagDef * fd)157 INTBOOL CheckActorFlag(const AActor *owner, FFlagDef *fd)
158 {
159 	if (fd->structoffset == -1)
160 	{
161 		return CheckDeprecatedFlags(owner, owner->GetClass()->ActorInfo, fd->flagbit);
162 	}
163 	else
164 #ifdef __BIG_ENDIAN__
165 	if (fd->fieldsize == 4)
166 #endif
167 	{
168 		return fd->flagbit & *(DWORD *)(((char*)owner) + fd->structoffset);
169 	}
170 #ifdef __BIG_ENDIAN__
171 	else if (fd->fieldsize == 2)
172 	{
173 		return fd->flagbit & *(WORD *)(((char*)owner) + fd->structoffset);
174 	}
175 	else
176 	{
177 		assert(fd->fieldsize == 1);
178 		return fd->flagbit & *(BYTE *)(((char*)owner) + fd->structoffset);
179 	}
180 #endif
181 }
182 
CheckActorFlag(const AActor * owner,const char * flagname,bool printerror)183 INTBOOL CheckActorFlag(const AActor *owner, const char *flagname, bool printerror)
184 {
185 	const char *dot = strchr (flagname, '.');
186 	FFlagDef *fd;
187 	const PClass *cls = owner->GetClass();
188 
189 	if (dot != NULL)
190 	{
191 		FString part1(flagname, dot-flagname);
192 		fd = FindFlag (cls, part1, dot+1);
193 	}
194 	else
195 	{
196 		fd = FindFlag (cls, flagname, NULL);
197 	}
198 
199 	if (fd != NULL)
200 	{
201 		return CheckActorFlag(owner, fd);
202 	}
203 	else
204 	{
205 		if (printerror) Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars());
206 		return false;
207 	}
208 }
209 
210 //===========================================================================
211 //
212 // HandleDeprecatedFlags
213 //
214 // Handles the deprecated flags and sets the respective properties
215 // to appropriate values. This is solely intended for backwards
216 // compatibility so mixing this with code that is aware of the real
217 // properties is not recommended
218 //
219 //===========================================================================
HandleDeprecatedFlags(AActor * defaults,FActorInfo * info,bool set,int index)220 void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index)
221 {
222 	switch (index)
223 	{
224 	case DEPF_FIREDAMAGE:
225 		defaults->DamageType = set? NAME_Fire : NAME_None;
226 		break;
227 	case DEPF_ICEDAMAGE:
228 		defaults->DamageType = set? NAME_Ice : NAME_None;
229 		break;
230 	case DEPF_LOWGRAVITY:
231 		defaults->gravity = set? FRACUNIT/8 : FRACUNIT;
232 		break;
233 	case DEPF_SHORTMISSILERANGE:
234 		defaults->maxtargetrange = set? 896*FRACUNIT : 0;
235 		break;
236 	case DEPF_LONGMELEERANGE:
237 		defaults->meleethreshold = set? 196*FRACUNIT : 0;
238 		break;
239 	case DEPF_QUARTERGRAVITY:
240 		defaults->gravity = set? FRACUNIT/4 : FRACUNIT;
241 		break;
242 	case DEPF_FIRERESIST:
243 		info->SetDamageFactor(NAME_Fire, set? FRACUNIT/2 : FRACUNIT);
244 		break;
245 	// the bounce flags will set the compatibility bounce modes to remain compatible
246 	case DEPF_HERETICBOUNCE:
247 		defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
248 		if (set) defaults->BounceFlags |= BOUNCE_HereticCompat;
249 		break;
250 	case DEPF_HEXENBOUNCE:
251 		defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
252 		if (set) defaults->BounceFlags |= BOUNCE_HexenCompat;
253 		break;
254 	case DEPF_DOOMBOUNCE:
255 		defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
256 		if (set) defaults->BounceFlags |= BOUNCE_DoomCompat;
257 		break;
258 	case DEPF_PICKUPFLASH:
259 		if (set)
260 		{
261 			static_cast<AInventory*>(defaults)->PickupFlash = FindClassTentative("PickupFlash", "Actor");
262 		}
263 		else
264 		{
265 			static_cast<AInventory*>(defaults)->PickupFlash = NULL;
266 		}
267 		break;
268 	case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1.
269 		static_cast<AInventory*>(defaults)->InterHubAmount = set ? 0 : 1;
270 	default:
271 		break;	// silence GCC
272 	}
273 }
274 
275 //===========================================================================
276 //
277 // CheckDeprecatedFlags
278 //
279 // Checks properties related to deprecated flags, and returns true only
280 // if the relevant properties are configured exactly as they would have
281 // been by setting the flag in HandleDeprecatedFlags.
282 //
283 //===========================================================================
284 
CheckDeprecatedFlags(const AActor * actor,FActorInfo * info,int index)285 bool CheckDeprecatedFlags(const AActor *actor, FActorInfo *info, int index)
286 {
287 	// A deprecated flag is false if
288 	// a) it hasn't been added here
289 	// b) any property of the actor differs from what it would be after setting the flag using HandleDeprecatedFlags
290 
291 	// Deprecated flags are normally replaced by something more flexible, which means a multitude of related configurations
292 	// will report "false".
293 
294 	switch (index)
295 	{
296 	case DEPF_FIREDAMAGE:
297 		return actor->DamageType == NAME_Fire;
298 	case DEPF_ICEDAMAGE:
299 		return actor->DamageType == NAME_Ice;
300 	case DEPF_LOWGRAVITY:
301 		return actor->gravity == FRACUNIT/8;
302 	case DEPF_SHORTMISSILERANGE:
303 		return actor->maxtargetrange == 896*FRACUNIT;
304 	case DEPF_LONGMELEERANGE:
305 		return actor->meleethreshold == 196*FRACUNIT;
306 	case DEPF_QUARTERGRAVITY:
307 		return actor->gravity == FRACUNIT/4;
308 	case DEPF_FIRERESIST:
309 		if (info->DamageFactors)
310 		{
311 			fixed_t *df = info->DamageFactors->CheckKey(NAME_Fire);
312 			return df && (*df) == FRACUNIT / 2;
313 		}
314 		return false;
315 
316 	case DEPF_HERETICBOUNCE:
317 		return (actor->BounceFlags & (BOUNCE_TypeMask|BOUNCE_UseSeeSound)) == BOUNCE_HereticCompat;
318 
319 	case DEPF_HEXENBOUNCE:
320 		return (actor->BounceFlags & (BOUNCE_TypeMask|BOUNCE_UseSeeSound)) == BOUNCE_HexenCompat;
321 
322 	case DEPF_DOOMBOUNCE:
323 		return (actor->BounceFlags & (BOUNCE_TypeMask|BOUNCE_UseSeeSound)) == BOUNCE_DoomCompat;
324 
325 	case DEPF_PICKUPFLASH:
326 		return static_cast<const AInventory*>(actor)->PickupFlash == PClass::FindClass("PickupFlash");
327 		// A pure name lookup may or may not be more efficient, but I know no static identifier for PickupFlash.
328 
329 	case DEPF_INTERHUBSTRIP:
330 		return !(static_cast<const AInventory*>(actor)->InterHubAmount);
331 	}
332 
333 	return false; // Any entirely unknown flag is not set
334 }
335 
336 //==========================================================================
337 //
338 //
339 //
340 //==========================================================================
MatchString(const char * in,const char ** strings)341 int MatchString (const char *in, const char **strings)
342 {
343 	int i;
344 
345 	for (i = 0; *strings != NULL; i++)
346 	{
347 		if (!stricmp(in, *strings++))
348 		{
349 			return i;
350 		}
351 	}
352 	return -1;
353 }
354 
355 //==========================================================================
356 //
357 // Info Property handlers
358 //
359 //==========================================================================
360 
361 //==========================================================================
362 //
363 //==========================================================================
DEFINE_INFO_PROPERTY(game,S,Actor)364 DEFINE_INFO_PROPERTY(game, S, Actor)
365 {
366 	PROP_STRING_PARM(str, 0);
367 	if (!stricmp(str, "Doom"))
368 	{
369 		info->GameFilter |= GAME_Doom;
370 	}
371 	else if (!stricmp(str, "Heretic"))
372 	{
373 		info->GameFilter |= GAME_Heretic;
374 	}
375 	else if (!stricmp(str, "Hexen"))
376 	{
377 		info->GameFilter |= GAME_Hexen;
378 	}
379 	else if (!stricmp(str, "Raven"))
380 	{
381 		info->GameFilter |= GAME_Raven;
382 	}
383 	else if (!stricmp(str, "Strife"))
384 	{
385 		info->GameFilter |= GAME_Strife;
386 	}
387 	else if (!stricmp(str, "Chex"))
388 	{
389 		info->GameFilter |= GAME_Chex;
390 	}
391 	else if (!stricmp(str, "Any"))
392 	{
393 		info->GameFilter = GAME_Any;
394 	}
395 	else
396 	{
397 		I_Error ("Unknown game type %s", str);
398 	}
399 }
400 
401 //==========================================================================
402 //
403 //==========================================================================
DEFINE_INFO_PROPERTY(spawnid,I,Actor)404 DEFINE_INFO_PROPERTY(spawnid, I, Actor)
405 {
406 	PROP_INT_PARM(id, 0);
407 	if (id<0 || id>65535)
408 	{
409 		I_Error ("SpawnID must be in the range [0,65535]");
410 	}
411 	else info->SpawnID=(WORD)id;
412 }
413 
414 //==========================================================================
415 //
416 //==========================================================================
DEFINE_INFO_PROPERTY(conversationid,IiI,Actor)417 DEFINE_INFO_PROPERTY(conversationid, IiI, Actor)
418 {
419 	PROP_INT_PARM(convid, 0);
420 	PROP_INT_PARM(id1, 1);
421 	PROP_INT_PARM(id2, 2);
422 
423 	if (convid <= 0 || convid > 65535) return;	// 0 is not usable because the dialogue scripts use it as 'no object'.
424 	else info->ConversationID=(WORD)convid;
425 }
426 
427 //==========================================================================
428 //
429 // Property handlers
430 //
431 //==========================================================================
432 
433 //==========================================================================
434 //
435 //==========================================================================
436 DEFINE_PROPERTY(skip_super, 0, Actor)
437 {
438 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory)))
439 	{
440 		bag.ScriptPosition.Message(MSG_WARNING,
441 			"'skip_super' in definition of inventory item '%s' ignored.", info->Class->TypeName.GetChars() );
442 		return;
443 	}
444 	if (bag.StateSet)
445 	{
446 		bag.ScriptPosition.Message(MSG_WARNING,
447 			"'skip_super' must appear before any state definitions.");
448 		return;
449 	}
450 
451 	memcpy ((void *)defaults, (void *)GetDefault<AActor>(), sizeof(AActor));
452 	if (bag.DropItemList != NULL)
453 	{
454 		FreeDropItemChain (bag.DropItemList);
455 	}
456 	ResetBaggage (&bag, RUNTIME_CLASS(AActor));
457 }
458 
459 //==========================================================================
460 //
461 //==========================================================================
DEFINE_PROPERTY(tag,S,Actor)462 DEFINE_PROPERTY(tag, S, Actor)
463 {
464 	PROP_STRING_PARM(str, 0);
465 	defaults->SetTag(str);
466 }
467 
468 //==========================================================================
469 //
470 //==========================================================================
DEFINE_PROPERTY(health,I,Actor)471 DEFINE_PROPERTY(health, I, Actor)
472 {
473 	PROP_INT_PARM(id, 0);
474 	defaults->health=id;
475 }
476 
477 //==========================================================================
478 //
479 //==========================================================================
DEFINE_PROPERTY(gibhealth,I,Actor)480 DEFINE_PROPERTY(gibhealth, I, Actor)
481 {
482 	PROP_INT_PARM(id, 0);
483 	info->Class->Meta.SetMetaInt (AMETA_GibHealth, id);
484 }
485 
486 //==========================================================================
487 //
488 //==========================================================================
DEFINE_PROPERTY(woundhealth,I,Actor)489 DEFINE_PROPERTY(woundhealth, I, Actor)
490 {
491 	PROP_INT_PARM(id, 0);
492 	info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id);
493 }
494 
495 //==========================================================================
496 //
497 //==========================================================================
DEFINE_PROPERTY(reactiontime,I,Actor)498 DEFINE_PROPERTY(reactiontime, I, Actor)
499 {
500 	PROP_INT_PARM(id, 0);
501 	defaults->reactiontime=id;
502 }
503 
504 //==========================================================================
505 //
506 //==========================================================================
DEFINE_PROPERTY(painchance,ZI,Actor)507 DEFINE_PROPERTY(painchance, ZI, Actor)
508 {
509 	PROP_STRING_PARM(str, 0);
510 	PROP_INT_PARM(id, 1);
511 	if (str == NULL)
512 	{
513 		defaults->PainChance=id;
514 	}
515 	else
516 	{
517 		FName painType;
518 		if (!stricmp(str, "Normal")) painType = NAME_None;
519 		else painType=str;
520 
521 		info->SetPainChance(painType, id);
522 	}
523 }
524 
525 //==========================================================================
526 //
527 //==========================================================================
DEFINE_PROPERTY(painthreshold,I,Actor)528 DEFINE_PROPERTY(painthreshold, I, Actor)
529 {
530 	PROP_INT_PARM(id, 0);
531 
532 	defaults->PainThreshold = id;
533 }
534 
535 //==========================================================================
536 //
537 //==========================================================================
DEFINE_PROPERTY(damage,X,Actor)538 DEFINE_PROPERTY(damage, X, Actor)
539 {
540 	PROP_INT_PARM(id, 0);
541 
542 	// Damage can either be a single number, in which case it is subject
543 	// to the original damage calculation rules. Or, it can be an expression
544 	// and will be calculated as-is, ignoring the original rules. For
545 	// compatibility reasons, expressions must be enclosed within
546 	// parentheses.
547 
548 	defaults->Damage = id;
549 }
550 
551 //==========================================================================
552 //
553 //==========================================================================
DEFINE_PROPERTY(projectilekickback,I,Actor)554 DEFINE_PROPERTY(projectilekickback, I, Actor)
555 {
556 	PROP_INT_PARM(id, 0);
557 
558 	defaults->projectileKickback = id;
559 }
560 
561 //==========================================================================
562 //
563 //==========================================================================
DEFINE_PROPERTY(speed,F,Actor)564 DEFINE_PROPERTY(speed, F, Actor)
565 {
566 	PROP_FIXED_PARM(id, 0);
567 	defaults->Speed = id;
568 }
569 
570 //==========================================================================
571 //
572 //==========================================================================
DEFINE_PROPERTY(floatspeed,F,Actor)573 DEFINE_PROPERTY(floatspeed, F, Actor)
574 {
575 	PROP_FIXED_PARM(id, 0);
576 	defaults->FloatSpeed=id;
577 }
578 
579 //==========================================================================
580 //
581 //==========================================================================
DEFINE_PROPERTY(radius,F,Actor)582 DEFINE_PROPERTY(radius, F, Actor)
583 {
584 	PROP_FIXED_PARM(id, 0);
585 	defaults->radius=id;
586 }
587 
588 //==========================================================================
589 //
590 //==========================================================================
DEFINE_PROPERTY(height,F,Actor)591 DEFINE_PROPERTY(height, F, Actor)
592 {
593 	PROP_FIXED_PARM(id, 0);
594 	defaults->height=id;
595 }
596 
597 //==========================================================================
598 //
599 //==========================================================================
DEFINE_PROPERTY(projectilepassheight,F,Actor)600 DEFINE_PROPERTY(projectilepassheight, F, Actor)
601 {
602 	PROP_FIXED_PARM(id, 0);
603 	defaults->projectilepassheight=id;
604 }
605 
606 //==========================================================================
607 //
608 //==========================================================================
DEFINE_PROPERTY(mass,I,Actor)609 DEFINE_PROPERTY(mass, I, Actor)
610 {
611 	PROP_INT_PARM(id, 0);
612 	defaults->Mass=id;
613 }
614 
615 //==========================================================================
616 //
617 //==========================================================================
DEFINE_PROPERTY(xscale,F,Actor)618 DEFINE_PROPERTY(xscale, F, Actor)
619 {
620 	PROP_FIXED_PARM(id, 0);
621 	defaults->scaleX = id;
622 }
623 
624 //==========================================================================
625 //
626 //==========================================================================
DEFINE_PROPERTY(yscale,F,Actor)627 DEFINE_PROPERTY(yscale, F, Actor)
628 {
629 	PROP_FIXED_PARM(id, 0);
630 	defaults->scaleY = id;
631 }
632 
633 //==========================================================================
634 //
635 //==========================================================================
DEFINE_PROPERTY(scale,F,Actor)636 DEFINE_PROPERTY(scale, F, Actor)
637 {
638 	PROP_FIXED_PARM(id, 0);
639 	defaults->scaleX = defaults->scaleY = id;
640 }
641 
642 //==========================================================================
643 //
644 //==========================================================================
DEFINE_PROPERTY(floatbobphase,I,Actor)645 DEFINE_PROPERTY(floatbobphase, I, Actor)
646 {
647 	PROP_INT_PARM(id, 0);
648 	if (id < -1 || id >= 64) I_Error ("FloatBobPhase must be in range [-1,63]");
649 	defaults->FloatBobPhase = id;
650 }
651 
652 //==========================================================================
653 //
654 //==========================================================================
DEFINE_PROPERTY(args,Iiiii,Actor)655 DEFINE_PROPERTY(args, Iiiii, Actor)
656 {
657 	for (int i = 0; i < PROP_PARM_COUNT; i++)
658 	{
659 		PROP_INT_PARM(id, i);
660 		defaults->args[i] = id;
661 	}
662 	defaults->flags2|=MF2_ARGSDEFINED;
663 }
664 
665 //==========================================================================
666 //
667 //==========================================================================
DEFINE_PROPERTY(seesound,S,Actor)668 DEFINE_PROPERTY(seesound, S, Actor)
669 {
670 	PROP_STRING_PARM(str, 0);
671 	defaults->SeeSound = str;
672 }
673 
674 //==========================================================================
675 //
676 //==========================================================================
DEFINE_PROPERTY(attacksound,S,Actor)677 DEFINE_PROPERTY(attacksound, S, Actor)
678 {
679 	PROP_STRING_PARM(str, 0);
680 	defaults->AttackSound = str;
681 }
682 
683 //==========================================================================
684 //
685 //==========================================================================
DEFINE_PROPERTY(bouncesound,S,Actor)686 DEFINE_PROPERTY(bouncesound, S, Actor)
687 {
688 	PROP_STRING_PARM(str, 0);
689 	defaults->BounceSound = str;
690 }
691 
692 //==========================================================================
693 //
694 //==========================================================================
DEFINE_PROPERTY(wallbouncesound,S,Actor)695 DEFINE_PROPERTY(wallbouncesound, S, Actor)
696 {
697 	PROP_STRING_PARM(str, 0);
698 	defaults->WallBounceSound = str;
699 }
700 
701 //==========================================================================
702 //
703 //==========================================================================
DEFINE_PROPERTY(painsound,S,Actor)704 DEFINE_PROPERTY(painsound, S, Actor)
705 {
706 	PROP_STRING_PARM(str, 0);
707 	defaults->PainSound = str;
708 }
709 
710 //==========================================================================
711 //
712 //==========================================================================
DEFINE_PROPERTY(deathsound,S,Actor)713 DEFINE_PROPERTY(deathsound, S, Actor)
714 {
715 	PROP_STRING_PARM(str, 0);
716 	defaults->DeathSound = str;
717 }
718 
719 //==========================================================================
720 //
721 //==========================================================================
DEFINE_PROPERTY(activesound,S,Actor)722 DEFINE_PROPERTY(activesound, S, Actor)
723 {
724 	PROP_STRING_PARM(str, 0);
725 	defaults->ActiveSound = str;
726 }
727 
728 //==========================================================================
729 //
730 //==========================================================================
DEFINE_PROPERTY(howlsound,S,Actor)731 DEFINE_PROPERTY(howlsound, S, Actor)
732 {
733 	PROP_STRING_PARM(str, 0);
734 	info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str));
735 }
736 
737 //==========================================================================
738 //
739 //==========================================================================
DEFINE_PROPERTY(crushpainsound,S,Actor)740 DEFINE_PROPERTY(crushpainsound, S, Actor)
741 {
742 	PROP_STRING_PARM(str, 0);
743 	defaults->CrushPainSound = str;
744 }
745 
746 //==========================================================================
747 //
748 //==========================================================================
DEFINE_PROPERTY(dropitem,S_i_i,Actor)749 DEFINE_PROPERTY(dropitem, S_i_i, Actor)
750 {
751 	PROP_STRING_PARM(type, 0);
752 
753 	// create a linked list of dropitems
754 	if (!bag.DropItemSet)
755 	{
756 		bag.DropItemSet = true;
757 		bag.DropItemList = NULL;
758 	}
759 
760 	FDropItem *di = new FDropItem;
761 
762 	di->Name =type;
763 	di->probability=255;
764 	di->amount=-1;
765 
766 	if (PROP_PARM_COUNT > 1)
767 	{
768 		PROP_INT_PARM(prob, 1);
769 		di->probability = prob;
770 		if (PROP_PARM_COUNT > 2)
771 		{
772 			PROP_INT_PARM(amt, 2);
773 			di->amount = amt;
774 		}
775 	}
776 	di->Next = bag.DropItemList;
777 	bag.DropItemList = di;
778 }
779 
780 //==========================================================================
781 //
782 //==========================================================================
DEFINE_PROPERTY(renderstyle,S,Actor)783 DEFINE_PROPERTY(renderstyle, S, Actor)
784 {
785 	PROP_STRING_PARM(str, 0);
786 	static const char * renderstyles[]={
787 		"NONE", "NORMAL", "FUZZY", "SOULTRANS", "OPTFUZZY", "STENCIL",
788 		"TRANSLUCENT", "ADD", "SHADED", "SHADOW", "SUBTRACT", "ADDSTENCIL", "ADDSHADED", NULL };
789 
790 	static const int renderstyle_values[]={
791 		STYLE_None, STYLE_Normal, STYLE_Fuzzy, STYLE_SoulTrans, STYLE_OptFuzzy,
792 			STYLE_TranslucentStencil, STYLE_Translucent, STYLE_Add, STYLE_Shaded,
793 			STYLE_Shadow, STYLE_Subtract, STYLE_AddStencil, STYLE_AddShaded};
794 
795 	// make this work for old style decorations, too.
796 	if (!strnicmp(str, "style_", 6)) str+=6;
797 
798 	int style = MatchString(str, renderstyles);
799 	if (style < 0) I_Error("Unknown render style '%s'", str);
800 	defaults->RenderStyle = LegacyRenderStyles[renderstyle_values[style]];
801 }
802 
803 //==========================================================================
804 //
805 //==========================================================================
806 DEFINE_PROPERTY(defaultalpha, 0, Actor)
807 {
808 	defaults->alpha = gameinfo.gametype == GAME_Heretic ? HR_SHADOW : HX_SHADOW;
809 }
810 
811 //==========================================================================
812 //
813 //==========================================================================
DEFINE_PROPERTY(alpha,F,Actor)814 DEFINE_PROPERTY(alpha, F, Actor)
815 {
816 	PROP_FIXED_PARM(id, 0);
817 	defaults->alpha = id;
818 }
819 
820 //==========================================================================
821 //
822 //==========================================================================
DEFINE_PROPERTY(obituary,S,Actor)823 DEFINE_PROPERTY(obituary, S, Actor)
824 {
825 	PROP_STRING_PARM(str, 0);
826 	info->Class->Meta.SetMetaString (AMETA_Obituary, str);
827 }
828 
829 //==========================================================================
830 //
831 //==========================================================================
DEFINE_PROPERTY(hitobituary,S,Actor)832 DEFINE_PROPERTY(hitobituary, S, Actor)
833 {
834 	PROP_STRING_PARM(str, 0);
835 	info->Class->Meta.SetMetaString (AMETA_HitObituary, str);
836 }
837 
838 //==========================================================================
839 //
840 //==========================================================================
841 DEFINE_PROPERTY(donthurtshooter, 0, Actor)
842 {
843 	info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true);
844 }
845 
846 //==========================================================================
847 //
848 //==========================================================================
DEFINE_PROPERTY(explosionradius,I,Actor)849 DEFINE_PROPERTY(explosionradius, I, Actor)
850 {
851 	PROP_INT_PARM(id, 0);
852 	info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id);
853 }
854 
855 //==========================================================================
856 //
857 //==========================================================================
DEFINE_PROPERTY(explosiondamage,I,Actor)858 DEFINE_PROPERTY(explosiondamage, I, Actor)
859 {
860 	PROP_INT_PARM(id, 0);
861 	info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id);
862 }
863 
864 //==========================================================================
865 //
866 //==========================================================================
DEFINE_PROPERTY(deathheight,F,Actor)867 DEFINE_PROPERTY(deathheight, F, Actor)
868 {
869 	PROP_FIXED_PARM(h, 0);
870 	// AActor::Die() uses a height of 0 to mean "cut the height to 1/4",
871 	// so if a height of 0 is desired, store it as -1.
872 	info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h);
873 }
874 
875 //==========================================================================
876 //
877 //==========================================================================
DEFINE_PROPERTY(burnheight,F,Actor)878 DEFINE_PROPERTY(burnheight, F, Actor)
879 {
880 	PROP_FIXED_PARM(h, 0);
881 	// The note above for AMETA_DeathHeight also applies here.
882 	info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h);
883 }
884 
885 //==========================================================================
886 //
887 //==========================================================================
DEFINE_PROPERTY(maxtargetrange,F,Actor)888 DEFINE_PROPERTY(maxtargetrange, F, Actor)
889 {
890 	PROP_FIXED_PARM(id, 0);
891 	defaults->maxtargetrange = id;
892 }
893 
894 //==========================================================================
895 //
896 //==========================================================================
DEFINE_PROPERTY(meleethreshold,F,Actor)897 DEFINE_PROPERTY(meleethreshold, F, Actor)
898 {
899 	PROP_FIXED_PARM(id, 0);
900 	defaults->meleethreshold = id;
901 }
902 
903 //==========================================================================
904 //
905 //==========================================================================
DEFINE_PROPERTY(meleedamage,I,Actor)906 DEFINE_PROPERTY(meleedamage, I, Actor)
907 {
908 	PROP_INT_PARM(id, 0);
909 	info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id);
910 }
911 
912 //==========================================================================
913 //
914 //==========================================================================
DEFINE_PROPERTY(meleerange,F,Actor)915 DEFINE_PROPERTY(meleerange, F, Actor)
916 {
917 	PROP_FIXED_PARM(id, 0);
918 	defaults->meleerange = id;
919 }
920 
921 //==========================================================================
922 //
923 //==========================================================================
DEFINE_PROPERTY(meleesound,S,Actor)924 DEFINE_PROPERTY(meleesound, S, Actor)
925 {
926 	PROP_STRING_PARM(str, 0);
927 	info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str));
928 }
929 
930 //==========================================================================
931 //
932 //==========================================================================
DEFINE_PROPERTY(missiletype,S,Actor)933 DEFINE_PROPERTY(missiletype, S, Actor)
934 {
935 	PROP_STRING_PARM(str, 0);
936 	info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str));
937 }
938 
939 //==========================================================================
940 //
941 //==========================================================================
DEFINE_PROPERTY(missileheight,F,Actor)942 DEFINE_PROPERTY(missileheight, F, Actor)
943 {
944 	PROP_FIXED_PARM(id, 0);
945 	info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id);
946 }
947 
948 //==========================================================================
949 //
950 //==========================================================================
DEFINE_PROPERTY(pushfactor,F,Actor)951 DEFINE_PROPERTY(pushfactor, F, Actor)
952 {
953 	PROP_FIXED_PARM(id, 0);
954 	defaults->pushfactor = id;
955 }
956 
957 //==========================================================================
958 //
959 //==========================================================================
DEFINE_PROPERTY(translation,L,Actor)960 DEFINE_PROPERTY(translation, L, Actor)
961 {
962 	PROP_INT_PARM(type, 0);
963 
964 	if (type == 0)
965 	{
966 		PROP_INT_PARM(trans, 1);
967 		int max = 6;// (gameinfo.gametype == GAME_Strife || (info->GameFilter&GAME_Strife)) ? 6 : 2;
968 		if (trans < 0 || trans > max)
969 		{
970 			I_Error ("Translation must be in the range [0,%d]", max);
971 		}
972 		defaults->Translation = TRANSLATION(TRANSLATION_Standard, trans);
973 	}
974 	else
975 	{
976 		FRemapTable CurrentTranslation;
977 
978 		CurrentTranslation.MakeIdentity();
979 		for(int i = 1; i < PROP_PARM_COUNT; i++)
980 		{
981 			PROP_STRING_PARM(str, i);
982 			if (i== 1 && PROP_PARM_COUNT == 2 && !stricmp(str, "Ice"))
983 			{
984 				defaults->Translation = TRANSLATION(TRANSLATION_Standard, 7);
985 				return;
986 			}
987 			else
988 			{
989 				CurrentTranslation.AddToTranslation(str);
990 			}
991 		}
992 		defaults->Translation = CurrentTranslation.StoreTranslation ();
993 	}
994 }
995 
996 //==========================================================================
997 //
998 //==========================================================================
DEFINE_PROPERTY(stencilcolor,C,Actor)999 DEFINE_PROPERTY(stencilcolor, C, Actor)
1000 {
1001 	PROP_COLOR_PARM(color, 0);
1002 
1003 	defaults->fillcolor = color | (ColorMatcher.Pick (RPART(color), GPART(color), BPART(color)) << 24);
1004 }
1005 
1006 //==========================================================================
1007 //
1008 //==========================================================================
DEFINE_PROPERTY(bloodcolor,C,Actor)1009 DEFINE_PROPERTY(bloodcolor, C, Actor)
1010 {
1011 	PROP_COLOR_PARM(color, 0);
1012 
1013 	PalEntry pe = color;
1014 	pe.a = CreateBloodTranslation(pe);
1015 	info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe);
1016 }
1017 
1018 
1019 //==========================================================================
1020 //
1021 //==========================================================================
DEFINE_PROPERTY(bloodtype,Sss,Actor)1022 DEFINE_PROPERTY(bloodtype, Sss, Actor)
1023 {
1024 	PROP_STRING_PARM(str, 0)
1025 	PROP_STRING_PARM(str1, 1)
1026 	PROP_STRING_PARM(str2, 2)
1027 
1028 	FName blood = str;
1029 	// normal blood
1030 	info->Class->Meta.SetMetaInt (AMETA_BloodType, blood);
1031 
1032 	if (PROP_PARM_COUNT > 1)
1033 	{
1034 		blood = str1;
1035 	}
1036 	// blood splatter
1037 	info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood);
1038 
1039 	if (PROP_PARM_COUNT > 2)
1040 	{
1041 		blood = str2;
1042 	}
1043 	// axe blood
1044 	info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood);
1045 }
1046 
1047 //==========================================================================
1048 //
1049 //==========================================================================
DEFINE_PROPERTY(bouncetype,S,Actor)1050 DEFINE_PROPERTY(bouncetype, S, Actor)
1051 {
1052 	static const char *names[] = { "None", "Doom", "Heretic", "Hexen", "DoomCompat", "HereticCompat", "HexenCompat", "Grenade", "Classic", NULL };
1053 	static const ActorBounceFlag flags[] = { BOUNCE_None,
1054 		BOUNCE_Doom, BOUNCE_Heretic, BOUNCE_Hexen,
1055 		BOUNCE_DoomCompat, BOUNCE_HereticCompat, BOUNCE_HexenCompat,
1056 		BOUNCE_Grenade, BOUNCE_Classic, };
1057 	PROP_STRING_PARM(id, 0);
1058 	int match = MatchString(id, names);
1059 	if (match < 0)
1060 	{
1061 		I_Error("Unknown bouncetype %s", id);
1062 		match = 0;
1063 	}
1064 	defaults->BounceFlags &= ~(BOUNCE_TypeMask | BOUNCE_UseSeeSound);
1065 	defaults->BounceFlags |= flags[match];
1066 	if (defaults->BounceFlags & (BOUNCE_Actors | BOUNCE_AllActors))
1067 	{
1068 		// PASSMOBJ is irrelevant for normal missiles, but not for bouncers.
1069 		defaults->flags2 |= MF2_PASSMOBJ;
1070 	}
1071 }
1072 
1073 //==========================================================================
1074 //
1075 //==========================================================================
DEFINE_PROPERTY(bouncefactor,F,Actor)1076 DEFINE_PROPERTY(bouncefactor, F, Actor)
1077 {
1078 	PROP_FIXED_PARM(id, 0);
1079 	defaults->bouncefactor = clamp<fixed_t>(id, 0, FRACUNIT);
1080 }
1081 
1082 //==========================================================================
1083 //
1084 //==========================================================================
DEFINE_PROPERTY(wallbouncefactor,F,Actor)1085 DEFINE_PROPERTY(wallbouncefactor, F, Actor)
1086 {
1087 	PROP_FIXED_PARM(id, 0);
1088 	defaults->wallbouncefactor = clamp<fixed_t>(id, 0, FRACUNIT);
1089 }
1090 
1091 //==========================================================================
1092 //
1093 //==========================================================================
DEFINE_PROPERTY(bouncecount,I,Actor)1094 DEFINE_PROPERTY(bouncecount, I, Actor)
1095 {
1096 	PROP_INT_PARM(id, 0);
1097 	defaults->bouncecount = id;
1098 }
1099 
1100 //==========================================================================
1101 //
1102 //==========================================================================
DEFINE_PROPERTY(weaveindexXY,I,Actor)1103 DEFINE_PROPERTY(weaveindexXY, I, Actor)
1104 {
1105 	PROP_INT_PARM(id, 0);
1106 	defaults->WeaveIndexXY = id;
1107 }
1108 
1109 //==========================================================================
1110 //
1111 //==========================================================================
DEFINE_PROPERTY(weaveindexZ,I,Actor)1112 DEFINE_PROPERTY(weaveindexZ, I, Actor)
1113 {
1114 	PROP_INT_PARM(id, 0);
1115 	defaults->WeaveIndexZ = id;
1116 }
1117 
1118 //==========================================================================
1119 //
1120 //==========================================================================
DEFINE_PROPERTY(minmissilechance,I,Actor)1121 DEFINE_PROPERTY(minmissilechance, I, Actor)
1122 {
1123 	PROP_INT_PARM(id, 0);
1124 	defaults->MinMissileChance=id;
1125 }
1126 
1127 //==========================================================================
1128 //
1129 //==========================================================================
DEFINE_PROPERTY(damagetype,S,Actor)1130 DEFINE_PROPERTY(damagetype, S, Actor)
1131 {
1132 	PROP_STRING_PARM(str, 0);
1133 	if (!stricmp(str, "Normal")) defaults->DamageType = NAME_None;
1134 	else defaults->DamageType=str;
1135 }
1136 
1137 //==========================================================================
1138 
1139 //==========================================================================
DEFINE_PROPERTY(paintype,S,Actor)1140 DEFINE_PROPERTY(paintype, S, Actor)
1141 {
1142 	PROP_STRING_PARM(str, 0);
1143 	if (!stricmp(str, "Normal")) defaults->PainType = NAME_None;
1144 	else defaults->PainType=str;
1145 }
1146 
1147 //==========================================================================
1148 
1149 //==========================================================================
DEFINE_PROPERTY(deathtype,S,Actor)1150 DEFINE_PROPERTY(deathtype, S, Actor)
1151 {
1152 	PROP_STRING_PARM(str, 0);
1153 	if (!stricmp(str, "Normal")) defaults->DeathType = NAME_None;
1154 	else defaults->DeathType=str;
1155 }
1156 
1157 //==========================================================================
1158 //
1159 //==========================================================================
DEFINE_PROPERTY(damagefactor,ZF,Actor)1160 DEFINE_PROPERTY(damagefactor, ZF, Actor)
1161 {
1162 	PROP_STRING_PARM(str, 0);
1163 	PROP_FIXED_PARM(id, 1);
1164 
1165 	if (str == NULL)
1166 	{
1167 		defaults->DamageFactor = id;
1168 	}
1169 	else
1170 	{
1171 		FName dmgType;
1172 		if (!stricmp(str, "Normal")) dmgType = NAME_None;
1173 		else dmgType=str;
1174 
1175 		info->SetDamageFactor(dmgType, id);
1176 	}
1177 }
1178 
1179 //==========================================================================
1180 //
1181 //==========================================================================
DEFINE_PROPERTY(decal,S,Actor)1182 DEFINE_PROPERTY(decal, S, Actor)
1183 {
1184 	PROP_STRING_PARM(str, 0);
1185 	defaults->DecalGenerator = (FDecalBase *)intptr_t(int(FName(str)));
1186 }
1187 
1188 //==========================================================================
1189 //
1190 //==========================================================================
DEFINE_PROPERTY(maxstepheight,F,Actor)1191 DEFINE_PROPERTY(maxstepheight, F, Actor)
1192 {
1193 	PROP_FIXED_PARM(i, 0);
1194 	defaults->MaxStepHeight = i;
1195 }
1196 
1197 //==========================================================================
1198 //
1199 //==========================================================================
DEFINE_PROPERTY(maxdropoffheight,F,Actor)1200 DEFINE_PROPERTY(maxdropoffheight, F, Actor)
1201 {
1202 	PROP_FIXED_PARM(i, 0);
1203 	defaults->MaxDropOffHeight = i;
1204 }
1205 
1206 //==========================================================================
1207 //
1208 //==========================================================================
DEFINE_PROPERTY(poisondamage,Iii,Actor)1209 DEFINE_PROPERTY(poisondamage, Iii, Actor)
1210 {
1211 	PROP_INT_PARM(poisondamage, 0);
1212 	PROP_INT_PARM(poisonduration, 1);
1213 	PROP_INT_PARM(poisonperiod, 2);
1214 
1215 	defaults->PoisonDamage = poisondamage;
1216 	if (PROP_PARM_COUNT == 1)
1217 	{
1218 		defaults->PoisonDuration = INT_MIN;
1219 	}
1220 	else
1221 	{
1222 		defaults->PoisonDuration = poisonduration;
1223 
1224 		if (PROP_PARM_COUNT > 2)
1225 			defaults->PoisonPeriod = poisonperiod;
1226 		else
1227 			defaults->PoisonPeriod = 0;
1228 	}
1229 }
1230 
1231 //==========================================================================
1232 //
1233 //==========================================================================
DEFINE_PROPERTY(poisondamagetype,S,Actor)1234 DEFINE_PROPERTY(poisondamagetype, S, Actor)
1235 {
1236 	PROP_STRING_PARM(poisondamagetype, 0);
1237 
1238 	defaults->PoisonDamageType = poisondamagetype;
1239 }
1240 
1241 //==========================================================================
1242 //
1243 //==========================================================================
DEFINE_PROPERTY(fastspeed,F,Actor)1244 DEFINE_PROPERTY(fastspeed, F, Actor)
1245 {
1246 	PROP_FIXED_PARM(i, 0);
1247 	info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i);
1248 }
1249 
1250 //==========================================================================
1251 //
1252 //==========================================================================
DEFINE_PROPERTY(radiusdamagefactor,F,Actor)1253 DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
1254 {
1255 	PROP_FIXED_PARM(i, 0);
1256 	info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i);
1257 }
1258 
1259 //==========================================================================
1260 //
1261 //==========================================================================
DEFINE_PROPERTY(cameraheight,F,Actor)1262 DEFINE_PROPERTY(cameraheight, F, Actor)
1263 {
1264 	PROP_FIXED_PARM(i, 0);
1265 	info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i);
1266 }
1267 
1268 //==========================================================================
1269 //
1270 //==========================================================================
DEFINE_PROPERTY(vspeed,F,Actor)1271 DEFINE_PROPERTY(vspeed, F, Actor)
1272 {
1273 	PROP_FIXED_PARM(i, 0);
1274 	defaults->velz = i;
1275 }
1276 
1277 //==========================================================================
1278 //
1279 //==========================================================================
DEFINE_PROPERTY(gravity,F,Actor)1280 DEFINE_PROPERTY(gravity, F, Actor)
1281 {
1282 	PROP_FIXED_PARM(i, 0);
1283 
1284 	if (i < 0) I_Error ("Gravity must not be negative.");
1285 	defaults->gravity = i;
1286 }
1287 
1288 //==========================================================================
1289 //
1290 //==========================================================================
DEFINE_PROPERTY(friction,F,Actor)1291 DEFINE_PROPERTY(friction, F, Actor)
1292 {
1293 	PROP_FIXED_PARM(i, 0);
1294 
1295 	if (i < 0) I_Error ("Friction must not be negative.");
1296 	defaults->Friction = i;
1297 }
1298 
1299 //==========================================================================
1300 //
1301 //==========================================================================
DEFINE_PROPERTY(species,S,Actor)1302 DEFINE_PROPERTY(species, S, Actor)
1303 {
1304 	PROP_STRING_PARM(n, 0);
1305 	defaults->Species = n;
1306 }
1307 
1308 //==========================================================================
1309 //
1310 //==========================================================================
1311 DEFINE_PROPERTY(clearflags, 0, Actor)
1312 {
1313 	defaults->flags = 0;
1314 	defaults->flags2 &= MF2_ARGSDEFINED;	// this flag must not be cleared
1315 	defaults->flags3 = 0;
1316 	defaults->flags4 = 0;
1317 	defaults->flags5 = 0;
1318 	defaults->flags6 = 0;
1319 	defaults->flags7 = 0;
1320 }
1321 
1322 //==========================================================================
1323 //
1324 //==========================================================================
1325 DEFINE_PROPERTY(monster, 0, Actor)
1326 {
1327 	// sets the standard flags for a monster
1328 	defaults->flags|=MF_SHOOTABLE|MF_COUNTKILL|MF_SOLID;
1329 	defaults->flags2|=MF2_PUSHWALL|MF2_MCROSS|MF2_PASSMOBJ;
1330 	defaults->flags3|=MF3_ISMONSTER;
1331 	defaults->flags4|=MF4_CANUSEWALLS;
1332 }
1333 
1334 //==========================================================================
1335 //
1336 //==========================================================================
1337 DEFINE_PROPERTY(projectile, 0, Actor)
1338 {
1339 	// sets the standard flags for a projectile
1340 	defaults->flags|=MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE;
1341 	defaults->flags2|=MF2_IMPACT|MF2_PCROSS|MF2_NOTELEPORT;
1342 	if (gameinfo.gametype&GAME_Raven) defaults->flags5|=MF5_BLOODSPLATTER;
1343 }
1344 
1345 //==========================================================================
1346 //
1347 //==========================================================================
DEFINE_PROPERTY(activation,N,Actor)1348 DEFINE_PROPERTY(activation, N, Actor)
1349 {
1350 	// How the thing behaves when activated by death, USESPECIAL or BUMPSPECIAL
1351 	PROP_INT_PARM(val, 0);
1352 	defaults->activationtype = val;
1353 }
1354 
1355 //==========================================================================
1356 //
1357 //==========================================================================
DEFINE_PROPERTY(designatedteam,I,Actor)1358 DEFINE_PROPERTY(designatedteam, I, Actor)
1359 {
1360 	PROP_INT_PARM(val, 0);
1361 	if(val < 0 || (val >= (signed) Teams.Size() && val != TEAM_NONE))
1362 		I_Error("Invalid team designation.\n");
1363 	defaults->DesignatedTeam = val;
1364 }
1365 
1366 //==========================================================================
1367 // [BB]
1368 //==========================================================================
DEFINE_PROPERTY(visibletoteam,I,Actor)1369 DEFINE_PROPERTY(visibletoteam, I, Actor)
1370 {
1371 	PROP_INT_PARM(i, 0);
1372 	defaults->VisibleToTeam=i+1;
1373 }
1374 
1375 //==========================================================================
1376 // [BB]
1377 //==========================================================================
DEFINE_PROPERTY(visibletoplayerclass,Ssssssssssssssssssss,Actor)1378 DEFINE_PROPERTY(visibletoplayerclass, Ssssssssssssssssssss, Actor)
1379 {
1380 	info->VisibleToPlayerClass.Clear();
1381 	for(int i = 0;i < PROP_PARM_COUNT;++i)
1382 	{
1383 		PROP_STRING_PARM(n, i);
1384 		if (*n != 0)
1385 			info->VisibleToPlayerClass.Push(FindClassTentative(n, "PlayerPawn"));
1386 	}
1387 }
1388 
1389 //==========================================================================
1390 //
1391 //==========================================================================
DEFINE_PROPERTY(accuracy,I,Actor)1392 DEFINE_PROPERTY(accuracy, I, Actor)
1393 {
1394 	PROP_INT_PARM(i, 0);
1395 	defaults->accuracy = i;
1396 }
1397 
1398 //==========================================================================
1399 //
1400 //==========================================================================
DEFINE_PROPERTY(stamina,I,Actor)1401 DEFINE_PROPERTY(stamina, I, Actor)
1402 {
1403 	PROP_INT_PARM(i, 0);
1404 	defaults->stamina = i;
1405 }
1406 
1407 //==========================================================================
1408 //
1409 //==========================================================================
DEFINE_PROPERTY(telefogsourcetype,S,Actor)1410 DEFINE_PROPERTY(telefogsourcetype, S, Actor)
1411 {
1412 	PROP_STRING_PARM(str, 0);
1413 	defaults->TeleFogSourceType = FindClassTentative(str,"Actor");
1414 }
1415 
1416 //==========================================================================
1417 //
1418 //==========================================================================
DEFINE_PROPERTY(telefogdesttype,S,Actor)1419 DEFINE_PROPERTY(telefogdesttype, S, Actor)
1420 {
1421 	PROP_STRING_PARM(str, 0);
1422 	defaults->TeleFogDestType = FindClassTentative(str, "Actor");
1423 }
1424 
1425 //==========================================================================
1426 //
1427 //==========================================================================
DEFINE_PROPERTY(ripperlevel,I,Actor)1428 DEFINE_PROPERTY(ripperlevel, I, Actor)
1429 {
1430 	PROP_INT_PARM(id, 0);
1431 	if (id < 0)
1432 	{
1433 		I_Error ("RipperLevel must not be negative");
1434 	}
1435 	defaults->RipperLevel = id;
1436 }
1437 
1438 //==========================================================================
1439 //
1440 //==========================================================================
DEFINE_PROPERTY(riplevelmin,I,Actor)1441 DEFINE_PROPERTY(riplevelmin, I, Actor)
1442 {
1443 	PROP_INT_PARM(id, 0);
1444 	if (id < 0)
1445 	{
1446 		I_Error ("RipLevelMin must not be negative");
1447 	}
1448 	defaults->RipLevelMin = id;
1449 }
1450 
1451 //==========================================================================
1452 //
1453 //==========================================================================
DEFINE_PROPERTY(riplevelmax,I,Actor)1454 DEFINE_PROPERTY(riplevelmax, I, Actor)
1455 {
1456 	PROP_INT_PARM(id, 0);
1457 	if (id < 0)
1458 	{
1459 		I_Error ("RipLevelMax must not be negative");
1460 	}
1461 	defaults->RipLevelMax = id;
1462 }
1463 
1464 //==========================================================================
1465 //
1466 // Special inventory properties
1467 //
1468 //==========================================================================
1469 
1470 //==========================================================================
1471 //
1472 //==========================================================================
DEFINE_CLASS_PROPERTY(restrictedto,Ssssssssssssssssssss,Inventory)1473 DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
1474 {
1475 	info->RestrictedToPlayerClass.Clear();
1476 	for(int i = 0;i < PROP_PARM_COUNT;++i)
1477 	{
1478 		PROP_STRING_PARM(n, i);
1479 		if (*n != 0)
1480 			info->RestrictedToPlayerClass.Push(FindClassTentative(n, "PlayerPawn"));
1481 	}
1482 }
1483 
1484 //==========================================================================
1485 //
1486 //==========================================================================
DEFINE_CLASS_PROPERTY(forbiddento,Ssssssssssssssssssss,Inventory)1487 DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
1488 {
1489 	info->ForbiddenToPlayerClass.Clear();
1490 	for(int i = 0;i < PROP_PARM_COUNT;++i)
1491 	{
1492 		PROP_STRING_PARM(n, i);
1493 		if (*n != 0)
1494 			info->ForbiddenToPlayerClass.Push(FindClassTentative(n, "PlayerPawn"));
1495 	}
1496 }
1497 
1498 //==========================================================================
1499 //
1500 //==========================================================================
DEFINE_CLASS_PROPERTY(backpackamount,I,Ammo)1501 DEFINE_CLASS_PROPERTY(backpackamount, I, Ammo)
1502 {
1503 	PROP_INT_PARM(i, 0);
1504 	defaults->BackpackAmount = i;
1505 }
1506 
1507 //==========================================================================
1508 //
1509 //==========================================================================
DEFINE_CLASS_PROPERTY(backpackmaxamount,I,Ammo)1510 DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo)
1511 {
1512 	PROP_INT_PARM(i, 0);
1513 	defaults->BackpackMaxAmount = i;
1514 }
1515 
1516 //==========================================================================
1517 //
1518 //==========================================================================
DEFINE_CLASS_PROPERTY(dropamount,I,Ammo)1519 DEFINE_CLASS_PROPERTY(dropamount, I, Ammo)
1520 {
1521 	PROP_INT_PARM(i, 0);
1522 	info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i);
1523 }
1524 
1525 //==========================================================================
1526 //
1527 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor,maxsaveamount,I,BasicArmorBonus)1528 DEFINE_CLASS_PROPERTY_PREFIX(armor, maxsaveamount, I, BasicArmorBonus)
1529 {
1530 	PROP_INT_PARM(i, 0);
1531 	defaults->MaxSaveAmount = i;
1532 }
1533 
1534 //==========================================================================
1535 //
1536 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor,maxbonus,I,BasicArmorBonus)1537 DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonus, I, BasicArmorBonus)
1538 {
1539 	PROP_INT_PARM(i, 0);
1540 	defaults->BonusCount = i;
1541 }
1542 
1543 //==========================================================================
1544 //
1545 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor,maxbonusmax,I,BasicArmorBonus)1546 DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonusmax, I, BasicArmorBonus)
1547 {
1548 	PROP_INT_PARM(i, 0);
1549 	defaults->BonusMax = i;
1550 }
1551 
1552 //==========================================================================
1553 //
1554 //==========================================================================
DEFINE_CLASS_PROPERTY(saveamount,I,Armor)1555 DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
1556 {
1557 	PROP_INT_PARM(i, 0);
1558 
1559 	// Special case here because this property has to work for 2 unrelated classes
1560 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
1561 	{
1562 		((ABasicArmorPickup*)defaults)->SaveAmount=i;
1563 	}
1564 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
1565 	{
1566 		((ABasicArmorBonus*)defaults)->SaveAmount=i;
1567 	}
1568 	else
1569 	{
1570 		I_Error("\"Armor.SaveAmount\" requires an actor of type \"Armor\"");
1571 	}
1572 }
1573 
1574 //==========================================================================
1575 //
1576 //==========================================================================
DEFINE_CLASS_PROPERTY(savepercent,F,Armor)1577 DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
1578 {
1579 	PROP_FIXED_PARM(i, 0);
1580 
1581 	i = clamp(i, 0, 100*FRACUNIT)/100;
1582 	// Special case here because this property has to work for 2 unrelated classes
1583 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
1584 	{
1585 		((ABasicArmorPickup*)defaults)->SavePercent = i;
1586 	}
1587 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
1588 	{
1589 		((ABasicArmorBonus*)defaults)->SavePercent = i;
1590 	}
1591 	else
1592 	{
1593 		I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n");
1594 	}
1595 }
1596 
1597 //==========================================================================
1598 //
1599 //==========================================================================
DEFINE_CLASS_PROPERTY(maxabsorb,I,Armor)1600 DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor)
1601 {
1602 	PROP_INT_PARM(i, 0);
1603 
1604 	// Special case here because this property has to work for 2 unrelated classes
1605 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
1606 	{
1607 		((ABasicArmorPickup*)defaults)->MaxAbsorb = i;
1608 	}
1609 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
1610 	{
1611 		((ABasicArmorBonus*)defaults)->MaxAbsorb = i;
1612 	}
1613 	else
1614 	{
1615 		I_Error("\"Armor.MaxAbsorb\" requires an actor of type \"Armor\"\n");
1616 	}
1617 }
1618 
1619 //==========================================================================
1620 //
1621 //==========================================================================
DEFINE_CLASS_PROPERTY(maxfullabsorb,I,Armor)1622 DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor)
1623 {
1624 	PROP_INT_PARM(i, 0);
1625 
1626 	// Special case here because this property has to work for 2 unrelated classes
1627 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
1628 	{
1629 		((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i;
1630 	}
1631 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
1632 	{
1633 		((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i;
1634 	}
1635 	else
1636 	{
1637 		I_Error("\"Armor.MaxFullAbsorb\" requires an actor of type \"Armor\"\n");
1638 	}
1639 }
1640 
1641 //==========================================================================
1642 //
1643 //==========================================================================
DEFINE_CLASS_PROPERTY(amount,I,Inventory)1644 DEFINE_CLASS_PROPERTY(amount, I, Inventory)
1645 {
1646 	PROP_INT_PARM(i, 0);
1647 	defaults->Amount = i;
1648 }
1649 
1650 //==========================================================================
1651 //
1652 //==========================================================================
DEFINE_CLASS_PROPERTY(icon,S,Inventory)1653 DEFINE_CLASS_PROPERTY(icon, S, Inventory)
1654 {
1655 	PROP_STRING_PARM(i, 0);
1656 
1657 	if (i == NULL || i[0] == '\0')
1658 	{
1659 		defaults->Icon.SetNull();
1660 	}
1661 	else
1662 	{
1663 		defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
1664 		if (!defaults->Icon.isValid())
1665 		{
1666 			// Don't print warnings if the item is for another game or if this is a shareware IWAD.
1667 			// Strife's teaser doesn't contain all the icon graphics of the full game.
1668 			if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) &&
1669 				!(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
1670 			{
1671 				bag.ScriptPosition.Message(MSG_WARNING,
1672 					"Icon '%s' for '%s' not found\n", i, info->Class->TypeName.GetChars());
1673 			}
1674 		}
1675 	}
1676 }
1677 
1678 //==========================================================================
1679 //
1680 //==========================================================================
DEFINE_CLASS_PROPERTY(interhubamount,I,Inventory)1681 DEFINE_CLASS_PROPERTY(interhubamount, I, Inventory)
1682 {
1683 	PROP_INT_PARM(i, 0);
1684 	defaults->InterHubAmount = i;
1685 }
1686 
1687 //==========================================================================
1688 //
1689 //==========================================================================
DEFINE_CLASS_PROPERTY(maxamount,I,Inventory)1690 DEFINE_CLASS_PROPERTY(maxamount, I, Inventory)
1691 {
1692 	PROP_INT_PARM(i, 0);
1693 	defaults->MaxAmount = i;
1694 }
1695 
1696 //==========================================================================
1697 //
1698 //==========================================================================
1699 DEFINE_CLASS_PROPERTY(defmaxamount, 0, Inventory)
1700 {
1701 	defaults->MaxAmount = gameinfo.definventorymaxamount;
1702 }
1703 
1704 
1705 //==========================================================================
1706 //
1707 //==========================================================================
DEFINE_CLASS_PROPERTY(pickupflash,S,Inventory)1708 DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
1709 {
1710 	PROP_STRING_PARM(str, 0);
1711 	defaults->PickupFlash = FindClassTentative(str, "Actor");
1712 }
1713 
1714 //==========================================================================
1715 //
1716 //==========================================================================
DEFINE_CLASS_PROPERTY(pickupmessage,T,Inventory)1717 DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
1718 {
1719 	PROP_STRING_PARM(str, 0);
1720 	info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str);
1721 }
1722 
1723 //==========================================================================
1724 //
1725 //==========================================================================
DEFINE_CLASS_PROPERTY(pickupsound,S,Inventory)1726 DEFINE_CLASS_PROPERTY(pickupsound, S, Inventory)
1727 {
1728 	PROP_STRING_PARM(str, 0);
1729 	defaults->PickupSound = str;
1730 }
1731 
1732 //==========================================================================
1733 // Dummy for Skulltag compatibility...
1734 //==========================================================================
DEFINE_CLASS_PROPERTY(pickupannouncerentry,S,Inventory)1735 DEFINE_CLASS_PROPERTY(pickupannouncerentry, S, Inventory)
1736 {
1737 }
1738 
1739 //==========================================================================
1740 //
1741 //==========================================================================
DEFINE_CLASS_PROPERTY(respawntics,I,Inventory)1742 DEFINE_CLASS_PROPERTY(respawntics, I, Inventory)
1743 {
1744 	PROP_INT_PARM(i, 0);
1745 	defaults->RespawnTics = i;
1746 }
1747 
1748 //==========================================================================
1749 //
1750 //==========================================================================
DEFINE_CLASS_PROPERTY(usesound,S,Inventory)1751 DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
1752 {
1753 	PROP_STRING_PARM(str, 0);
1754 	defaults->UseSound = str;
1755 }
1756 
1757 //==========================================================================
1758 //
1759 //==========================================================================
DEFINE_CLASS_PROPERTY(givequest,I,Inventory)1760 DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
1761 {
1762 	PROP_INT_PARM(i, 0);
1763 	info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i);
1764 }
1765 
1766 //==========================================================================
1767 //
1768 //==========================================================================
DEFINE_CLASS_PROPERTY(lowmessage,IT,Health)1769 DEFINE_CLASS_PROPERTY(lowmessage, IT, Health)
1770 {
1771 	PROP_INT_PARM(i, 0);
1772 	PROP_STRING_PARM(str, 1);
1773 	info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i);
1774 	info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str);
1775 }
1776 
1777 //==========================================================================
1778 //
1779 //==========================================================================
DEFINE_CLASS_PROPERTY(autouse,I,HealthPickup)1780 DEFINE_CLASS_PROPERTY(autouse, I, HealthPickup)
1781 {
1782 	PROP_INT_PARM(i, 0);
1783 	defaults->autousemode = i;
1784 }
1785 
1786 //==========================================================================
1787 //
1788 //==========================================================================
DEFINE_CLASS_PROPERTY(number,I,PuzzleItem)1789 DEFINE_CLASS_PROPERTY(number, I, PuzzleItem)
1790 {
1791 	PROP_INT_PARM(i, 0);
1792 	defaults->PuzzleItemNumber = i;
1793 }
1794 
1795 //==========================================================================
1796 //
1797 //==========================================================================
DEFINE_CLASS_PROPERTY(failmessage,T,PuzzleItem)1798 DEFINE_CLASS_PROPERTY(failmessage, T, PuzzleItem)
1799 {
1800 	PROP_STRING_PARM(str, 0);
1801 	info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str);
1802 }
1803 
1804 //==========================================================================
1805 //
1806 //==========================================================================
DEFINE_CLASS_PROPERTY(ammogive,I,Weapon)1807 DEFINE_CLASS_PROPERTY(ammogive, I, Weapon)
1808 {
1809 	PROP_INT_PARM(i, 0);
1810 	defaults->AmmoGive1 = i;
1811 }
1812 
1813 //==========================================================================
1814 //
1815 //==========================================================================
DEFINE_CLASS_PROPERTY(ammogive1,I,Weapon)1816 DEFINE_CLASS_PROPERTY(ammogive1, I, Weapon)
1817 {
1818 	PROP_INT_PARM(i, 0);
1819 	defaults->AmmoGive1 = i;
1820 }
1821 
1822 //==========================================================================
1823 //
1824 //==========================================================================
DEFINE_CLASS_PROPERTY(ammogive2,I,Weapon)1825 DEFINE_CLASS_PROPERTY(ammogive2, I, Weapon)
1826 {
1827 	PROP_INT_PARM(i, 0);
1828 	defaults->AmmoGive2 = i;
1829 }
1830 
1831 //==========================================================================
1832 //
1833 //==========================================================================
DEFINE_CLASS_PROPERTY(ammotype,S,Weapon)1834 DEFINE_CLASS_PROPERTY(ammotype, S, Weapon)
1835 {
1836 	PROP_STRING_PARM(str, 0);
1837 	if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL;
1838 	else defaults->AmmoType1 = FindClassTentative(str, "Ammo");
1839 }
1840 
1841 //==========================================================================
1842 //
1843 //==========================================================================
DEFINE_CLASS_PROPERTY(ammotype1,S,Weapon)1844 DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon)
1845 {
1846 	PROP_STRING_PARM(str, 0);
1847 	if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL;
1848 	else defaults->AmmoType1 = FindClassTentative(str, "Ammo");
1849 }
1850 
1851 //==========================================================================
1852 //
1853 //==========================================================================
DEFINE_CLASS_PROPERTY(ammotype2,S,Weapon)1854 DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon)
1855 {
1856 	PROP_STRING_PARM(str, 0);
1857 	if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL;
1858 	else defaults->AmmoType2 = FindClassTentative(str, "Ammo");
1859 }
1860 
1861 //==========================================================================
1862 //
1863 //==========================================================================
DEFINE_CLASS_PROPERTY(ammouse,I,Weapon)1864 DEFINE_CLASS_PROPERTY(ammouse, I, Weapon)
1865 {
1866 	PROP_INT_PARM(i, 0);
1867 	defaults->AmmoUse1 = i;
1868 }
1869 
1870 //==========================================================================
1871 //
1872 //==========================================================================
DEFINE_CLASS_PROPERTY(ammouse1,I,Weapon)1873 DEFINE_CLASS_PROPERTY(ammouse1, I, Weapon)
1874 {
1875 	PROP_INT_PARM(i, 0);
1876 	defaults->AmmoUse1 = i;
1877 }
1878 
1879 //==========================================================================
1880 //
1881 //==========================================================================
DEFINE_CLASS_PROPERTY(ammouse2,I,Weapon)1882 DEFINE_CLASS_PROPERTY(ammouse2, I, Weapon)
1883 {
1884 	PROP_INT_PARM(i, 0);
1885 	defaults->AmmoUse2 = i;
1886 }
1887 
1888 //==========================================================================
1889 //
1890 //==========================================================================
DEFINE_CLASS_PROPERTY(kickback,I,Weapon)1891 DEFINE_CLASS_PROPERTY(kickback, I, Weapon)
1892 {
1893 	PROP_INT_PARM(i, 0);
1894 	defaults->Kickback = i;
1895 }
1896 
1897 //==========================================================================
1898 //
1899 //==========================================================================
1900 DEFINE_CLASS_PROPERTY(defaultkickback, 0, Weapon)
1901 {
1902 	defaults->Kickback = gameinfo.defKickback;
1903 }
1904 
1905 //==========================================================================
1906 //
1907 //==========================================================================
DEFINE_CLASS_PROPERTY(readysound,S,Weapon)1908 DEFINE_CLASS_PROPERTY(readysound, S, Weapon)
1909 {
1910 	PROP_STRING_PARM(str, 0);
1911 	defaults->ReadySound = str;
1912 }
1913 
1914 //==========================================================================
1915 //
1916 //==========================================================================
DEFINE_CLASS_PROPERTY(selectionorder,I,Weapon)1917 DEFINE_CLASS_PROPERTY(selectionorder, I, Weapon)
1918 {
1919 	PROP_INT_PARM(i, 0);
1920 	defaults->SelectionOrder = i;
1921 }
1922 
1923 //==========================================================================
1924 //
1925 //==========================================================================
DEFINE_CLASS_PROPERTY(minselectionammo1,I,Weapon)1926 DEFINE_CLASS_PROPERTY(minselectionammo1, I, Weapon)
1927 {
1928 	PROP_INT_PARM(i, 0);
1929 	defaults->MinSelAmmo1 = i;
1930 }
1931 
1932 //==========================================================================
1933 //
1934 //==========================================================================
DEFINE_CLASS_PROPERTY(minselectionammo2,I,Weapon)1935 DEFINE_CLASS_PROPERTY(minselectionammo2, I, Weapon)
1936 {
1937 	PROP_INT_PARM(i, 0);
1938 	defaults->MinSelAmmo2 = i;
1939 }
1940 
1941 //==========================================================================
1942 //
1943 //==========================================================================
DEFINE_CLASS_PROPERTY(sisterweapon,S,Weapon)1944 DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon)
1945 {
1946 	PROP_STRING_PARM(str, 0);
1947 	defaults->SisterWeaponType = FindClassTentative(str, "Weapon");
1948 }
1949 
1950 //==========================================================================
1951 //
1952 //==========================================================================
DEFINE_CLASS_PROPERTY(upsound,S,Weapon)1953 DEFINE_CLASS_PROPERTY(upsound, S, Weapon)
1954 {
1955 	PROP_STRING_PARM(str, 0);
1956 	defaults->UpSound = str;
1957 }
1958 
1959 //==========================================================================
1960 //
1961 //==========================================================================
DEFINE_CLASS_PROPERTY(yadjust,F,Weapon)1962 DEFINE_CLASS_PROPERTY(yadjust, F, Weapon)
1963 {
1964 	PROP_FIXED_PARM(i, 0);
1965 	defaults->YAdjust = i;
1966 }
1967 
1968 //==========================================================================
1969 //
1970 //==========================================================================
DEFINE_CLASS_PROPERTY(bobstyle,S,Weapon)1971 DEFINE_CLASS_PROPERTY(bobstyle, S, Weapon)
1972 {
1973 	static const char *names[] = { "Normal", "Inverse", "Alpha", "InverseAlpha", "Smooth", "InverseSmooth", NULL };
1974 	static const int styles[] = { AWeapon::BobNormal,
1975 		AWeapon::BobInverse, AWeapon::BobAlpha, AWeapon::BobInverseAlpha,
1976 		AWeapon::BobSmooth, AWeapon::BobInverseSmooth, };
1977 	PROP_STRING_PARM(id, 0);
1978 	int match = MatchString(id, names);
1979 	if (match < 0)
1980 	{
1981 		I_Error("Unknown bobstyle %s", id);
1982 		match = 0;
1983 	}
1984 	defaults->BobStyle = styles[match];
1985 }
1986 
1987 //==========================================================================
1988 //
1989 //==========================================================================
DEFINE_CLASS_PROPERTY(bobspeed,F,Weapon)1990 DEFINE_CLASS_PROPERTY(bobspeed, F, Weapon)
1991 {
1992 	PROP_FIXED_PARM(i, 0);
1993 	defaults->BobSpeed = i;
1994 }
1995 
1996 //==========================================================================
1997 //
1998 //==========================================================================
DEFINE_CLASS_PROPERTY(bobrangex,F,Weapon)1999 DEFINE_CLASS_PROPERTY(bobrangex, F, Weapon)
2000 {
2001 	PROP_FIXED_PARM(i, 0);
2002 	defaults->BobRangeX = i;
2003 }
2004 
2005 //==========================================================================
2006 //
2007 //==========================================================================
DEFINE_CLASS_PROPERTY(bobrangey,F,Weapon)2008 DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon)
2009 {
2010 	PROP_FIXED_PARM(i, 0);
2011 	defaults->BobRangeY = i;
2012 }
2013 
2014 //==========================================================================
2015 //
2016 //==========================================================================
DEFINE_CLASS_PROPERTY(slotnumber,I,Weapon)2017 DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
2018 {
2019 	PROP_INT_PARM(i, 0);
2020 	info->Class->Meta.SetMetaInt(AWMETA_SlotNumber, i);
2021 }
2022 
2023 //==========================================================================
2024 //
2025 //==========================================================================
DEFINE_CLASS_PROPERTY(slotpriority,F,Weapon)2026 DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
2027 {
2028 	PROP_FIXED_PARM(i, 0);
2029 	info->Class->Meta.SetMetaFixed(AWMETA_SlotPriority, i);
2030 }
2031 
2032 //==========================================================================
2033 //
2034 //==========================================================================
DEFINE_CLASS_PROPERTY(preferredskin,S,Weapon)2035 DEFINE_CLASS_PROPERTY(preferredskin, S, Weapon)
2036 {
2037 	PROP_STRING_PARM(str, 0);
2038 	// NoOp - only for Skulltag compatibility
2039 }
2040 
2041 //==========================================================================
2042 //
2043 //==========================================================================
DEFINE_CLASS_PROPERTY(number,I,WeaponPiece)2044 DEFINE_CLASS_PROPERTY(number, I, WeaponPiece)
2045 {
2046 	PROP_INT_PARM(i, 0);
2047 	defaults->PieceValue = 1 << (i-1);
2048 }
2049 
2050 //==========================================================================
2051 //
2052 //==========================================================================
DEFINE_CLASS_PROPERTY(weapon,S,WeaponPiece)2053 DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece)
2054 {
2055 	PROP_STRING_PARM(str, 0);
2056 	defaults->WeaponClass = FindClassTentative(str, "Weapon");
2057 }
2058 
2059 //==========================================================================
2060 //
2061 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,color,C_f,Inventory)2062 DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
2063 {
2064 	static const char *specialcolormapnames[] = {
2065 		"INVERSEMAP", "GOLDMAP", "REDMAP", "GREENMAP", "BLUEMAP", NULL };
2066 
2067 	int alpha;
2068 	PalEntry * pBlendColor;
2069 
2070 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2071 	{
2072 		pBlendColor = &((APowerup*)defaults)->BlendColor;
2073 	}
2074 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2075 	{
2076 		pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
2077 	}
2078 	else
2079 	{
2080 		I_Error("\"powerup.color\" requires an actor of type \"Powerup\"\n");
2081 		return;
2082 	}
2083 
2084 	PROP_INT_PARM(mode, 0);
2085 	PROP_INT_PARM(color, 1);
2086 
2087 	if (mode == 1)
2088 	{
2089 		PROP_STRING_PARM(name, 1);
2090 
2091 		// We must check the old special colormap names for compatibility
2092 		int v = MatchString(name, specialcolormapnames);
2093 		if (v >= 0)
2094 		{
2095 			*pBlendColor = MakeSpecialColormap(v);
2096 			return;
2097 		}
2098 		else if (!stricmp(name, "none") && info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2099 		{
2100 			*pBlendColor = MakeSpecialColormap(65535);
2101 			return;
2102 		}
2103 
2104 		color = V_GetColor(NULL, name);
2105 	}
2106 	if (PROP_PARM_COUNT > 2)
2107 	{
2108 		PROP_FLOAT_PARM(falpha, 2);
2109 		alpha=int(falpha*255);
2110 	}
2111 	else alpha = 255/3;
2112 
2113 	alpha=clamp<int>(alpha, 0, 255);
2114 	if (alpha != 0) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color;
2115 	else *pBlendColor = 0;
2116 }
2117 
2118 //==========================================================================
2119 //
2120 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,colormap,FFFfff,Inventory)2121 DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
2122 {
2123 	PalEntry * pBlendColor;
2124 
2125 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2126 	{
2127 		pBlendColor = &((APowerup*)defaults)->BlendColor;
2128 	}
2129 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2130 	{
2131 		pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
2132 	}
2133 	else
2134 	{
2135 		I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
2136 		return;
2137 	}
2138 
2139 	if (PROP_PARM_COUNT == 3)
2140 	{
2141 		PROP_FLOAT_PARM(r, 0);
2142 		PROP_FLOAT_PARM(g, 1);
2143 		PROP_FLOAT_PARM(b, 2);
2144 		*pBlendColor = MakeSpecialColormap(AddSpecialColormap(0, 0, 0, r, g, b));
2145 	}
2146 	else if (PROP_PARM_COUNT == 6)
2147 	{
2148 		PROP_FLOAT_PARM(r1, 0);
2149 		PROP_FLOAT_PARM(g1, 1);
2150 		PROP_FLOAT_PARM(b1, 2);
2151 		PROP_FLOAT_PARM(r2, 3);
2152 		PROP_FLOAT_PARM(g2, 4);
2153 		PROP_FLOAT_PARM(b2, 5);
2154 		*pBlendColor = MakeSpecialColormap(AddSpecialColormap(r1, g1, b1, r2, g2, b2));
2155 	}
2156 	else
2157 	{
2158 		I_Error("\"power.colormap\" must have either 3 or 6 parameters\n");
2159 	}
2160 }
2161 
2162 //==========================================================================
2163 //
2164 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,duration,I,Inventory)2165 DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
2166 {
2167 	int *pEffectTics;
2168 
2169 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2170 	{
2171 		pEffectTics = &((APowerup*)defaults)->EffectTics;
2172 	}
2173 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2174 	{
2175 		pEffectTics = &((APowerupGiver*)defaults)->EffectTics;
2176 	}
2177 	else
2178 	{
2179 		I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n");
2180 		return;
2181 	}
2182 
2183 	PROP_INT_PARM(i, 0);
2184 	*pEffectTics = (i >= 0) ? i : -i * TICRATE;
2185 }
2186 
2187 //==========================================================================
2188 //
2189 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,strength,F,Inventory)2190 DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory)
2191 {
2192 	fixed_t *pStrength;
2193 
2194 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2195 	{
2196 		pStrength = &((APowerup*)defaults)->Strength;
2197 	}
2198 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2199 	{
2200 		pStrength = &((APowerupGiver*)defaults)->Strength;
2201 	}
2202 	else
2203 	{
2204 		I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n");
2205 		return;
2206 	}
2207 	PROP_FIXED_PARM(f, 0);
2208 	*pStrength = f;
2209 }
2210 
2211 //==========================================================================
2212 //
2213 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,mode,S,Inventory)2214 DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
2215 {
2216 	PROP_STRING_PARM(str, 0);
2217 	FName *pMode;
2218 	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2219 	{
2220 		pMode = &((APowerup*)defaults)->Mode;
2221 	}
2222 	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
2223 	{
2224 		pMode = &((APowerupGiver*)defaults)->Mode;
2225 	}
2226 	else
2227 	{
2228 		I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n");
2229 		return;
2230 	}
2231 	*pMode = (FName)str;
2232 }
2233 
2234 //==========================================================================
2235 //
2236 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup,type,S,PowerupGiver)2237 DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
2238 {
2239 	PROP_STRING_PARM(str, 0);
2240 
2241 	// Yuck! What was I thinking when I decided to prepend "Power" to the name?
2242 	// Now it's too late to change it...
2243 	const PClass *cls = PClass::FindClass(str);
2244 	if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(APowerup)))
2245 	{
2246 		FString st;
2247 		st.Format("%s%s", strnicmp(str, "power", 5)? "Power" : "", str);
2248 		cls = FindClassTentative(st, "Powerup");
2249 	}
2250 
2251 	defaults->PowerupType = cls;
2252 }
2253 
2254 //==========================================================================
2255 //
2256 // [GRB] Special player properties
2257 //
2258 //==========================================================================
2259 
2260 //==========================================================================
2261 //
2262 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,displayname,S,PlayerPawn)2263 DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
2264 {
2265 	PROP_STRING_PARM(str, 0);
2266 	info->Class->Meta.SetMetaString (APMETA_DisplayName, str);
2267 }
2268 
2269 //==========================================================================
2270 //
2271 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,soundclass,S,PlayerPawn)2272 DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn)
2273 {
2274 	PROP_STRING_PARM(str, 0);
2275 
2276 	FString tmp = str;
2277 	tmp.ReplaceChars (' ', '_');
2278 	info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp);
2279 }
2280 
2281 //==========================================================================
2282 //
2283 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,face,S,PlayerPawn)2284 DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
2285 {
2286 	PROP_STRING_PARM(str, 0);
2287 	FString tmp = str;
2288 
2289 	tmp.ToUpper();
2290 	if (tmp.Len() != 3)
2291 	{
2292 		bag.ScriptPosition.Message(MSG_WARNING,
2293 			"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n",
2294 			tmp.GetChars(), info->Class->TypeName.GetChars ());
2295 	}
2296 
2297 	bool valid = (
2298 		(((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) &&
2299 		(((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) &&
2300 		(((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9')))
2301 		);
2302 	if (!valid)
2303 	{
2304 		bag.ScriptPosition.Message(MSG_WARNING,
2305 			"Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n",
2306 			tmp.GetChars(), info->Class->TypeName.GetChars ());
2307 	}
2308 
2309 	info->Class->Meta.SetMetaString (APMETA_Face, tmp);
2310 }
2311 
2312 //==========================================================================
2313 //
2314 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,colorrange,I_I,PlayerPawn)2315 DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn)
2316 {
2317 	PROP_INT_PARM(start, 0);
2318 	PROP_INT_PARM(end, 1);
2319 
2320 	if (start > end)
2321 		swapvalues (start, end);
2322 
2323 	info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8));
2324 }
2325 
2326 //==========================================================================
2327 //
2328 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,colorset,ISIIIiiiiiiiiiiiiiiiiiiiiiiii,PlayerPawn)2329 DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, PlayerPawn)
2330 {
2331 	PROP_INT_PARM(setnum, 0);
2332 	PROP_STRING_PARM(setname, 1);
2333 	PROP_INT_PARM(rangestart, 2);
2334 	PROP_INT_PARM(rangeend, 3);
2335 	PROP_INT_PARM(representative_color, 4);
2336 
2337 	FPlayerColorSet color;
2338 	color.Name = setname;
2339 	color.Lump = -1;
2340 	color.FirstColor = rangestart;
2341 	color.LastColor = rangeend;
2342 	color.RepresentativeColor = representative_color;
2343 	color.NumExtraRanges = 0;
2344 
2345 	if (PROP_PARM_COUNT > 5)
2346 	{
2347 		int count = PROP_PARM_COUNT - 5;
2348 		int start = 5;
2349 
2350 		while (count >= 4)
2351 		{
2352 			PROP_INT_PARM(range_start, start+0);
2353 			PROP_INT_PARM(range_end, start+1);
2354 			PROP_INT_PARM(first_color, start+2);
2355 			PROP_INT_PARM(last_color, start+3);
2356 			int extra = color.NumExtraRanges++;
2357 			assert (extra < (int)countof(color.Extra));
2358 
2359 			color.Extra[extra].RangeStart = range_start;
2360 			color.Extra[extra].RangeEnd = range_end;
2361 			color.Extra[extra].FirstColor = first_color;
2362 			color.Extra[extra].LastColor = last_color;
2363 			count -= 4;
2364 			start += 4;
2365 		}
2366 		if (count != 0)
2367 		{
2368 			bag.ScriptPosition.Message(MSG_WARNING, "Extra ranges require 4 parameters each.\n");
2369 		}
2370 	}
2371 
2372 	if (setnum < 0)
2373 	{
2374 		bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
2375 	}
2376 	else
2377 	{
2378 		info->SetColorSet(setnum, &color);
2379 	}
2380 }
2381 
2382 //==========================================================================
2383 //
2384 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,colorsetfile,ISSI,PlayerPawn)2385 DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
2386 {
2387 	PROP_INT_PARM(setnum, 0);
2388 	PROP_STRING_PARM(setname, 1);
2389 	PROP_STRING_PARM(rangefile, 2);
2390 	PROP_INT_PARM(representative_color, 3);
2391 
2392 	FPlayerColorSet color;
2393 	color.Name = setname;
2394 	color.Lump = Wads.CheckNumForName(rangefile);
2395 	color.RepresentativeColor = representative_color;
2396 	color.NumExtraRanges = 0;
2397 
2398 	if (setnum < 0)
2399 	{
2400 		bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
2401 	}
2402 	else if (color.Lump >= 0)
2403 	{
2404 		info->SetColorSet(setnum, &color);
2405 	}
2406 }
2407 
2408 //==========================================================================
2409 //
2410 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,clearcolorset,I,PlayerPawn)2411 DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
2412 {
2413 	PROP_INT_PARM(setnum, 0);
2414 
2415 	if (setnum < 0)
2416 	{
2417 		bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
2418 	}
2419 	else
2420 	{
2421 		info->SetColorSet(setnum, NULL);
2422 	}
2423 }
2424 
2425 //==========================================================================
2426 //
2427 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,attackzoffset,F,PlayerPawn)2428 DEFINE_CLASS_PROPERTY_PREFIX(player, attackzoffset, F, PlayerPawn)
2429 {
2430 	PROP_FIXED_PARM(z, 0);
2431 	defaults->AttackZOffset = z;
2432 }
2433 
2434 //==========================================================================
2435 //
2436 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,jumpz,F,PlayerPawn)2437 DEFINE_CLASS_PROPERTY_PREFIX(player, jumpz, F, PlayerPawn)
2438 {
2439 	PROP_FIXED_PARM(z, 0);
2440 	defaults->JumpZ = z;
2441 }
2442 
2443 //==========================================================================
2444 //
2445 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,GruntSpeed,F,PlayerPawn)2446 DEFINE_CLASS_PROPERTY_PREFIX(player, GruntSpeed, F, PlayerPawn)
2447 {
2448 	PROP_FIXED_PARM(z, 0);
2449 	defaults->GruntSpeed = z;
2450 }
2451 
2452 //==========================================================================
2453 //
2454 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,FallingScreamSpeed,FF,PlayerPawn)2455 DEFINE_CLASS_PROPERTY_PREFIX(player, FallingScreamSpeed, FF, PlayerPawn)
2456 {
2457 	PROP_FIXED_PARM(minz, 0);
2458 	PROP_FIXED_PARM(maxz, 1);
2459 	defaults->FallingScreamMinSpeed = minz;
2460 	defaults->FallingScreamMaxSpeed = maxz;
2461 }
2462 
2463 //==========================================================================
2464 //
2465 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,spawnclass,L,PlayerPawn)2466 DEFINE_CLASS_PROPERTY_PREFIX(player, spawnclass, L, PlayerPawn)
2467 {
2468 	PROP_INT_PARM(type, 0);
2469 
2470 	if (type == 0)
2471 	{
2472 		PROP_INT_PARM(val, 1);
2473 		if (val > 0) defaults->SpawnMask |= 1<<(val-1);
2474 	}
2475 	else
2476 	{
2477 		for(int i=1; i<PROP_PARM_COUNT; i++)
2478 		{
2479 			PROP_STRING_PARM(str, i);
2480 
2481 			if (!stricmp(str, "Any"))
2482 				defaults->SpawnMask = 0;
2483 			else if (!stricmp(str, "Fighter"))
2484 				defaults->SpawnMask |= 1;
2485 			else if (!stricmp(str, "Cleric"))
2486 				defaults->SpawnMask |= 2;
2487 			else if (!stricmp(str, "Mage"))
2488 				defaults->SpawnMask |= 4;
2489 
2490 		}
2491 	}
2492 }
2493 
2494 //==========================================================================
2495 //
2496 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,viewheight,F,PlayerPawn)2497 DEFINE_CLASS_PROPERTY_PREFIX(player, viewheight, F, PlayerPawn)
2498 {
2499 	PROP_FIXED_PARM(z, 0);
2500 	defaults->ViewHeight = z;
2501 }
2502 
2503 //==========================================================================
2504 //
2505 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,userange,F,PlayerPawn)2506 DEFINE_CLASS_PROPERTY_PREFIX(player, userange, F, PlayerPawn)
2507 {
2508 	PROP_FIXED_PARM(z, 0);
2509 	defaults->UseRange = z;
2510 }
2511 
2512 //==========================================================================
2513 //
2514 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,aircapacity,F,PlayerPawn)2515 DEFINE_CLASS_PROPERTY_PREFIX(player, aircapacity, F, PlayerPawn)
2516 {
2517 	PROP_FIXED_PARM(z, 0);
2518 	defaults->AirCapacity = z;
2519 }
2520 
2521 //==========================================================================
2522 //
2523 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,forwardmove,F_f,PlayerPawn)2524 DEFINE_CLASS_PROPERTY_PREFIX(player, forwardmove, F_f, PlayerPawn)
2525 {
2526 	PROP_FIXED_PARM(m, 0);
2527 	defaults->ForwardMove1 = defaults->ForwardMove2 = m;
2528 	if (PROP_PARM_COUNT > 1)
2529 	{
2530 		PROP_FIXED_PARM(m2, 1);
2531 		defaults->ForwardMove2 = m2;
2532 	}
2533 }
2534 
2535 //==========================================================================
2536 //
2537 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,sidemove,F_f,PlayerPawn)2538 DEFINE_CLASS_PROPERTY_PREFIX(player, sidemove, F_f, PlayerPawn)
2539 {
2540 	PROP_FIXED_PARM(m, 0);
2541 	defaults->SideMove1 = defaults->SideMove2 = m;
2542 	if (PROP_PARM_COUNT > 1)
2543 	{
2544 		PROP_FIXED_PARM(m2, 1);
2545 		defaults->SideMove2 = m2;
2546 	}
2547 }
2548 
2549 //==========================================================================
2550 //
2551 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,maxhealth,I,PlayerPawn)2552 DEFINE_CLASS_PROPERTY_PREFIX(player, maxhealth, I, PlayerPawn)
2553 {
2554 	PROP_INT_PARM(z, 0);
2555 	defaults->MaxHealth = z;
2556 }
2557 
2558 //==========================================================================
2559 //
2560 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,mugshotmaxhealth,I,PlayerPawn)2561 DEFINE_CLASS_PROPERTY_PREFIX(player, mugshotmaxhealth, I, PlayerPawn)
2562 {
2563 	PROP_INT_PARM(z, 0);
2564 	defaults->MugShotMaxHealth = z;
2565 }
2566 
2567 //==========================================================================
2568 //
2569 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,runhealth,I,PlayerPawn)2570 DEFINE_CLASS_PROPERTY_PREFIX(player, runhealth, I, PlayerPawn)
2571 {
2572 	PROP_INT_PARM(z, 0);
2573 	defaults->RunHealth = z;
2574 }
2575 
2576 //==========================================================================
2577 //
2578 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,morphweapon,S,PlayerPawn)2579 DEFINE_CLASS_PROPERTY_PREFIX(player, morphweapon, S, PlayerPawn)
2580 {
2581 	PROP_STRING_PARM(z, 0);
2582 	defaults->MorphWeapon = FName(z);
2583 }
2584 
2585 //==========================================================================
2586 //
2587 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,flechettetype,S,PlayerPawn)2588 DEFINE_CLASS_PROPERTY_PREFIX(player, flechettetype, S, PlayerPawn)
2589 {
2590 	PROP_STRING_PARM(str, 0);
2591 	defaults->FlechetteType = FindClassTentative(str, "ArtiPoisonBag");
2592 }
2593 
2594 //==========================================================================
2595 //
2596 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,scoreicon,S,PlayerPawn)2597 DEFINE_CLASS_PROPERTY_PREFIX(player, scoreicon, S, PlayerPawn)
2598 {
2599 	PROP_STRING_PARM(z, 0);
2600 	defaults->ScoreIcon = TexMan.CheckForTexture(z, FTexture::TEX_MiscPatch);
2601 	if (!defaults->ScoreIcon.isValid())
2602 	{
2603 		bag.ScriptPosition.Message(MSG_WARNING,
2604 			"Icon '%s' for '%s' not found\n", z, info->Class->TypeName.GetChars ());
2605 	}
2606 }
2607 
2608 //==========================================================================
2609 //
2610 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,crouchsprite,S,PlayerPawn)2611 DEFINE_CLASS_PROPERTY_PREFIX(player, crouchsprite, S, PlayerPawn)
2612 {
2613 	PROP_STRING_PARM(z, 0);
2614 	if (strlen(z) == 4)
2615 	{
2616 		defaults->crouchsprite = GetSpriteIndex (z);
2617 	}
2618 	else if (*z == 0)
2619 	{
2620 		defaults->crouchsprite = 0;
2621 	}
2622 	else
2623 	{
2624 		I_Error("Sprite name must have exactly 4 characters");
2625 	}
2626 }
2627 
2628 //==========================================================================
2629 //
2630 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,damagescreencolor,Cfs,PlayerPawn)2631 DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn)
2632 {
2633 	PROP_COLOR_PARM(c, 0);
2634 
2635 	PalEntry color = c;
2636 
2637 	if (PROP_PARM_COUNT < 3)		// Because colors count as 2 parms
2638 	{
2639 		color.a = 255;
2640 		defaults->DamageFade = color;
2641 	}
2642 	else if (PROP_PARM_COUNT < 4)
2643 	{
2644 		PROP_FLOAT_PARM(a, 2);
2645 
2646 		color.a = BYTE(255 * clamp(a, 0.f, 1.f));
2647 		defaults->DamageFade = color;
2648 	}
2649 	else
2650 	{
2651 		PROP_FLOAT_PARM(a, 2);
2652 		PROP_STRING_PARM(type, 3);
2653 
2654 		color.a = BYTE(255 * clamp(a, 0.f, 1.f));
2655 		info->SetPainFlash(type, color);
2656 	}
2657 }
2658 
2659 //==========================================================================
2660 //
2661 // [GRB] Store start items in drop item list
2662 //
2663 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,startitem,S_i,PlayerPawn)2664 DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
2665 {
2666 	PROP_STRING_PARM(str, 0);
2667 
2668 	// create a linked list of startitems
2669 	if (!bag.DropItemSet)
2670 	{
2671 		bag.DropItemSet = true;
2672 		bag.DropItemList = NULL;
2673 	}
2674 
2675 	FDropItem * di=new FDropItem;
2676 
2677 	di->Name = str;
2678 	di->probability = 255;
2679 	di->amount = 1;
2680 	if (PROP_PARM_COUNT > 1)
2681 	{
2682 		PROP_INT_PARM(amt, 1);
2683 		di->amount = amt;
2684 	}
2685 	di->Next = bag.DropItemList;
2686 	bag.DropItemList = di;
2687 }
2688 
2689 //==========================================================================
2690 //
2691 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,invulnerabilitymode,S,PlayerPawn)2692 DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
2693 {
2694 	PROP_STRING_PARM(str, 0);
2695 	info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str);
2696 }
2697 
2698 //==========================================================================
2699 //
2700 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,healradiustype,S,PlayerPawn)2701 DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
2702 {
2703 	PROP_STRING_PARM(str, 0);
2704 	info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str);
2705 }
2706 
2707 //==========================================================================
2708 //
2709 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,hexenarmor,FFFFF,PlayerPawn)2710 DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
2711 {
2712 	for (int i=0;i<5;i++)
2713 	{
2714 		PROP_FIXED_PARM(val, i);
2715 		info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val);
2716 	}
2717 }
2718 
2719 //==========================================================================
2720 //
2721 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,portrait,S,PlayerPawn)2722 DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
2723 {
2724 	PROP_STRING_PARM(val, 0);
2725 	info->Class->Meta.SetMetaString (APMETA_Portrait, val);
2726 }
2727 
2728 //==========================================================================
2729 //
2730 //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player,weaponslot,ISsssssssssssssssssssssssssssssssssssssssssss,PlayerPawn)2731 DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssssssssssssssssss, PlayerPawn)
2732 {
2733 	PROP_INT_PARM(slot, 0);
2734 
2735 	if (slot < 0 || slot > 9)
2736 	{
2737 		I_Error("Slot must be between 0 and 9.");
2738 	}
2739 	else
2740 	{
2741 		FString weapons;
2742 
2743 		for(int i = 1; i < PROP_PARM_COUNT; ++i)
2744 		{
2745 			PROP_STRING_PARM(str, i);
2746 			weapons << ' ' << str;
2747 		}
2748 		info->Class->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]);
2749 	}
2750 }
2751 
2752 //==========================================================================
2753 //
2754 //==========================================================================
DEFINE_CLASS_PROPERTY(playerclass,S,MorphProjectile)2755 DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile)
2756 {
2757 	PROP_STRING_PARM(str, 0);
2758 	defaults->PlayerClass = FName(str);
2759 }
2760 
2761 //==========================================================================
2762 //
2763 //==========================================================================
DEFINE_CLASS_PROPERTY(monsterclass,S,MorphProjectile)2764 DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile)
2765 {
2766 	PROP_STRING_PARM(str, 0);
2767 	defaults->MonsterClass = FName(str);
2768 }
2769 
2770 //==========================================================================
2771 //
2772 //==========================================================================
DEFINE_CLASS_PROPERTY(duration,I,MorphProjectile)2773 DEFINE_CLASS_PROPERTY(duration, I, MorphProjectile)
2774 {
2775 	PROP_INT_PARM(i, 0);
2776 	defaults->Duration = i >= 0 ? i : -i*TICRATE;
2777 }
2778 
2779 //==========================================================================
2780 //
2781 //==========================================================================
DEFINE_CLASS_PROPERTY(morphstyle,M,MorphProjectile)2782 DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile)
2783 {
2784 	PROP_INT_PARM(i, 0);
2785 	defaults->MorphStyle = i;
2786 }
2787 
2788 //==========================================================================
2789 //
2790 //==========================================================================
DEFINE_CLASS_PROPERTY(morphflash,S,MorphProjectile)2791 DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile)
2792 {
2793 	PROP_STRING_PARM(str, 0);
2794 	defaults->MorphFlash = FName(str);
2795 }
2796 
2797 //==========================================================================
2798 //
2799 //==========================================================================
DEFINE_CLASS_PROPERTY(unmorphflash,S,MorphProjectile)2800 DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
2801 {
2802 	PROP_STRING_PARM(str, 0);
2803 	defaults->UnMorphFlash = FName(str);
2804 }
2805 
2806 //==========================================================================
2807 //
2808 //==========================================================================
DEFINE_CLASS_PROPERTY(playerclass,S,PowerMorph)2809 DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph)
2810 {
2811 	PROP_STRING_PARM(str, 0);
2812 	defaults->PlayerClass = FName(str);
2813 }
2814 
2815 //==========================================================================
2816 //
2817 //==========================================================================
DEFINE_CLASS_PROPERTY(morphstyle,M,PowerMorph)2818 DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph)
2819 {
2820 	PROP_INT_PARM(i, 0);
2821 	defaults->MorphStyle = i;
2822 }
2823 
2824 //==========================================================================
2825 //
2826 //==========================================================================
DEFINE_CLASS_PROPERTY(morphflash,S,PowerMorph)2827 DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph)
2828 {
2829 	PROP_STRING_PARM(str, 0);
2830 	defaults->MorphFlash = FName(str);
2831 }
2832 
2833 //==========================================================================
2834 //
2835 //==========================================================================
DEFINE_CLASS_PROPERTY(unmorphflash,S,PowerMorph)2836 DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph)
2837 {
2838 	PROP_STRING_PARM(str, 0);
2839 	defaults->UnMorphFlash = FName(str);
2840 }
2841 
2842 
2843