1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: vc_decorate.cpp 4327 2010-07-24 19:30:53Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "vc_local.h"
29 #include "sv_local.h"
30 
31 // MACROS ------------------------------------------------------------------
32 
33 // TYPES -------------------------------------------------------------------
34 
35 enum
36 {
37 	PROPS_HASH_SIZE		= 256,
38 	FLAGS_HASH_SIZE		= 256,
39 };
40 
41 enum
42 {
43 	OLDDEC_Decoration,
44 	OLDDEC_Breakable,
45 	OLDDEC_Projectile,
46 	OLDDEC_Pickup,
47 };
48 
49 enum
50 {
51 	BOUNCE_None,
52 	BOUNCE_Doom,
53 	BOUNCE_Heretic,
54 	BOUNCE_Hexen
55 };
56 
57 enum
58 {
59 	PROP_Int,
60 	PROP_IntConst,
61 	PROP_IntUnsupported,
62 	PROP_BitIndex,
63 	PROP_Float,
64 	PROP_Speed,
65 	PROP_Tics,
66 	PROP_TicsSecs,
67 	PROP_Percent,
68 	PROP_FloatClamped,
69 	PROP_FloatClamped2,
70 	PROP_FloatOpt2,
71 	PROP_Name,
72 	PROP_NameLower,
73 	PROP_Str,
74 	PROP_StrUnsupported,
75 	PROP_Class,
76 	PROP_Power_Class,
77 	PROP_BoolConst,
78 	PROP_State,
79 	PROP_Game,
80 	PROP_SpawnId,
81 	PROP_ConversationId,
82 	PROP_PainChance,
83 	PROP_DamageFactor,
84 	PROP_MissileDamage,
85 	PROP_VSpeed,
86 	PROP_RenderStyle,
87 	PROP_Translation,
88 	PROP_BloodColour,
89 	PROP_BloodType,
90 	PROP_StencilColour,
91 	PROP_Monster,
92 	PROP_Projectile,
93 	PROP_BounceType,
94 	PROP_ClearFlags,
95 	PROP_DropItem,
96 	PROP_States,
97 	PROP_SkipSuper,
98 	PROP_Args,
99 	PROP_LowMessage,
100 	PROP_PowerupColour,
101 	PROP_ColourRange,
102 	PROP_DamageScreenColour,
103 	PROP_HexenArmor,
104 	PROP_StartItem,
105 	PROP_MorphStyle,
106 };
107 
108 enum
109 {
110 	FLAG_Bool,
111 	FLAG_Unsupported,
112 	FLAG_Byte,
113 	FLAG_Float,
114 	FLAG_Name,
115 	FLAG_Class,
116 	FLAG_NoClip,
117 };
118 
119 struct VClassFixup
120 {
121 	int			Offset;
122 	VStr		Name;
123 	VClass*		ReqParent;
124 	VClass*		Class;
125 };
126 
127 struct VPropDef
128 {
129 	vuint8		Type;
130 	int			HashNext;
131 	VName		Name;
132 	VField*		Field;
133 	VField*		Field2;
134 	VName		PropName;
135 	union
136 	{
137 		int		IConst;
138 		float	FMin;
139 	};
140 	float		FMax;
141 	VStr		CPrefix;
142 
143 	void SetField(VClass*, const char*);
144 	void SetField2(VClass*, const char*);
145 };
146 
147 struct VFlagDef
148 {
149 	vuint8		Type;
150 	int			HashNext;
151 	VName		Name;
152 	VField*		Field;
153 	VField*		Field2;
154 	union
155 	{
156 		vuint8	BTrue;
157 		float	FTrue;
158 	};
159 	VName		NTrue;
160 	union
161 	{
162 		vuint8	BFalse;
163 		float	FFalse;
164 	};
165 	VName		NFalse;
166 
167 	void SetField(VClass*, const char*);
168 	void SetField2(VClass*, const char*);
169 };
170 
171 struct VFlagList
172 {
173 	VClass*				Class;
174 
175 	TArray<VPropDef>	Props;
176 	int					PropsHash[PROPS_HASH_SIZE];
177 
178 	TArray<VFlagDef>	Flags;
179 	int					FlagsHash[FLAGS_HASH_SIZE];
180 
181 	VPropDef& NewProp(vuint8, VXmlNode*);
182 	VFlagDef& NewFlag(vuint8, VXmlNode*);
183 };
184 
185 //==========================================================================
186 //
187 //	VDecorateInvocation
188 //
189 //==========================================================================
190 
191 class VDecorateInvocation : public VExpression
192 {
193 public:
194 	VName			Name;
195 	int				NumArgs;
196 	VExpression*	Args[VMethod::MAX_PARAMS + 1];
197 
198 	VDecorateInvocation(VName, const TLocation&, int, VExpression**);
199 	~VDecorateInvocation();
200 	VExpression* DoResolve(VEmitContext&);
201 	void Emit(VEmitContext&);
202 };
203 
204 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
205 
206 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
207 
208 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
209 
210 static VExpression* ParseExpressionPriority13(VScriptParser* sc);
211 
212 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
213 
214 // PUBLIC DATA DEFINITIONS -------------------------------------------------
215 
216 TArray<VLineSpecInfo>	LineSpecialInfos;
217 
218 // PRIVATE DATA DEFINITIONS ------------------------------------------------
219 
220 static VPackage*		DecPkg;
221 
222 static VClass*			ActorClass;
223 static VClass*			FakeInventoryClass;
224 static VClass*			InventoryClass;
225 static VClass*			AmmoClass;
226 static VClass*			BasicArmorPickupClass;
227 static VClass*			BasicArmorBonusClass;
228 static VClass*			HealthClass;
229 static VClass*			PowerupGiverClass;
230 static VClass*			PuzzleItemClass;
231 static VClass*			WeaponClass;
232 static VClass*			WeaponPieceClass;
233 static VClass*			PlayerPawnClass;
234 static VClass*			MorphProjectileClass;
235 
236 static VMethod*			FuncA_Scream;
237 static VMethod*			FuncA_NoBlocking;
238 static VMethod*			FuncA_ScreamAndUnblock;
239 static VMethod*			FuncA_ActiveSound;
240 static VMethod*			FuncA_ActiveAndUnblock;
241 static VMethod*			FuncA_ExplodeParms;
242 static VMethod*			FuncA_FreezeDeath;
243 static VMethod*			FuncA_FreezeDeathChunks;
244 
245 static TArray<VFlagList>	FlagList;
246 
247 // CODE --------------------------------------------------------------------
248 
249 //==========================================================================
250 //
251 //	ParseDecorateDef
252 //
253 //==========================================================================
254 
ParseDecorateDef(VXmlDocument & Doc)255 static void ParseDecorateDef(VXmlDocument& Doc)
256 {
257 	guard(ParseDecorateDef);
258 	for (VXmlNode* N = Doc.Root.FindChild("class"); N; N = N->FindNext())
259 	{
260 		VStr ClassName = N->GetAttribute("name");
261 		VFlagList& Lst = FlagList.Alloc();
262 		Lst.Class = VClass::FindClass(*ClassName);
263 		for (int i = 0; i < PROPS_HASH_SIZE; i++)
264 		{
265 			Lst.PropsHash[i] = -1;
266 		}
267 		for (int i = 0; i < FLAGS_HASH_SIZE; i++)
268 		{
269 			Lst.FlagsHash[i] = -1;
270 		}
271 		for (VXmlNode* PN = N->FirstChild; PN; PN = PN->NextSibling)
272 		{
273 			if (PN->Name == "prop_int")
274 			{
275 				VPropDef& P = Lst.NewProp(PROP_Int, PN);
276 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
277 			}
278 			else if (PN->Name == "prop_int_const")
279 			{
280 				VPropDef& P = Lst.NewProp(PROP_IntConst, PN);
281 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
282 				P.IConst = atoi(*PN->GetAttribute("value"));
283 			}
284 			else if (PN->Name == "prop_int_unsupported")
285 			{
286 				VPropDef& P = Lst.NewProp(PROP_IntUnsupported, PN);
287 			}
288 			else if (PN->Name == "prop_bit_index")
289 			{
290 				VPropDef& P = Lst.NewProp(PROP_BitIndex, PN);
291 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
292 			}
293 			else if (PN->Name == "prop_float")
294 			{
295 				VPropDef& P = Lst.NewProp(PROP_Float, PN);
296 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
297 			}
298 			else if (PN->Name == "prop_speed")
299 			{
300 				VPropDef& P = Lst.NewProp(PROP_Speed, PN);
301 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
302 			}
303 			else if (PN->Name == "prop_tics")
304 			{
305 				VPropDef& P = Lst.NewProp(PROP_Tics, PN);
306 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
307 			}
308 			else if (PN->Name == "prop_tics_secs")
309 			{
310 				VPropDef& P = Lst.NewProp(PROP_TicsSecs, PN);
311 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
312 			}
313 			else if (PN->Name == "prop_percent")
314 			{
315 				VPropDef& P = Lst.NewProp(PROP_Percent, PN);
316 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
317 			}
318 			else if (PN->Name == "prop_float_clamped")
319 			{
320 				VPropDef& P = Lst.NewProp(PROP_FloatClamped, PN);
321 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
322 				P.FMin = atof(*PN->GetAttribute("min"));
323 				P.FMax = atof(*PN->GetAttribute("max"));
324 			}
325 			else if (PN->Name == "prop_float_clamped_2")
326 			{
327 				VPropDef& P = Lst.NewProp(PROP_FloatClamped2, PN);
328 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
329 				P.SetField2(Lst.Class, *PN->GetAttribute("property2"));
330 				P.FMin = atof(*PN->GetAttribute("min"));
331 				P.FMax = atof(*PN->GetAttribute("max"));
332 			}
333 			else if (PN->Name == "prop_float_optional_2")
334 			{
335 				VPropDef& P = Lst.NewProp(PROP_FloatOpt2, PN);
336 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
337 				P.SetField2(Lst.Class, *PN->GetAttribute("property2"));
338 			}
339 			else if (PN->Name == "prop_name")
340 			{
341 				VPropDef& P = Lst.NewProp(PROP_Name, PN);
342 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
343 			}
344 			else if (PN->Name == "prop_name_lower")
345 			{
346 				VPropDef& P = Lst.NewProp(PROP_NameLower, PN);
347 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
348 			}
349 			else if (PN->Name == "prop_string")
350 			{
351 				VPropDef& P = Lst.NewProp(PROP_Str, PN);
352 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
353 			}
354 			else if (PN->Name == "prop_string_unsupported")
355 			{
356 				VPropDef& P = Lst.NewProp(PROP_StrUnsupported, PN);
357 			}
358 			else if (PN->Name == "prop_class")
359 			{
360 				VPropDef& P = Lst.NewProp(PROP_Class, PN);
361 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
362 				if (PN->HasAttribute("prefix"))
363 				{
364 					P.CPrefix = PN->GetAttribute("prefix");
365 				}
366 			}
367 			else if (PN->Name == "prop_power_class")
368 			{
369 				VPropDef& P = Lst.NewProp(PROP_Power_Class, PN);
370 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
371 				if (PN->HasAttribute("prefix"))
372 				{
373 					P.CPrefix = PN->GetAttribute("prefix");
374 				}
375 			}
376 			else if (PN->Name == "prop_bool_const")
377 			{
378 				VPropDef& P = Lst.NewProp(PROP_BoolConst, PN);
379 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
380 				P.IConst = !PN->GetAttribute("value").ICmp("true");
381 			}
382 			else if (PN->Name == "prop_state")
383 			{
384 				VPropDef& P = Lst.NewProp(PROP_State, PN);
385 				P.PropName = *PN->GetAttribute("property");
386 			}
387 			else if (PN->Name == "prop_game")
388 			{
389 				VPropDef& P = Lst.NewProp(PROP_Game, PN);
390 			}
391 			else if (PN->Name == "prop_spawn_id")
392 			{
393 				VPropDef& P = Lst.NewProp(PROP_SpawnId, PN);
394 			}
395 			else if (PN->Name == "prop_conversation_id")
396 			{
397 				VPropDef& P = Lst.NewProp(PROP_ConversationId, PN);
398 				P.SetField(Lst.Class, "ConversationID");
399 			}
400 			else if (PN->Name == "prop_pain_chance")
401 			{
402 				VPropDef& P = Lst.NewProp(PROP_PainChance, PN);
403 				P.SetField(Lst.Class, "PainChance");
404 			}
405 			else if (PN->Name == "prop_damage_factor")
406 			{
407 				VPropDef& P = Lst.NewProp(PROP_DamageFactor, PN);
408 			}
409 			else if (PN->Name == "prop_missile_damage")
410 			{
411 				VPropDef& P = Lst.NewProp(PROP_MissileDamage, PN);
412 				P.SetField(Lst.Class, "MissileDamage");
413 			}
414 			else if (PN->Name == "prop_vspeed")
415 			{
416 				VPropDef& P = Lst.NewProp(PROP_VSpeed, PN);
417 				P.SetField(Lst.Class, "Velocity");
418 			}
419 			else if (PN->Name == "prop_render_style")
420 			{
421 				VPropDef& P = Lst.NewProp(PROP_RenderStyle, PN);
422 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
423 			}
424 			else if (PN->Name == "prop_translation")
425 			{
426 				VPropDef& P = Lst.NewProp(PROP_Translation, PN);
427 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
428 			}
429 			else if (PN->Name == "prop_blood_colour")
430 			{
431 				VPropDef& P = Lst.NewProp(PROP_BloodColour, PN);
432 				P.SetField(Lst.Class, "BloodColour");
433 				P.SetField2(Lst.Class, "BloodTranslation");
434 			}
435 			else if (PN->Name == "prop_blood_type")
436 			{
437 				VPropDef& P = Lst.NewProp(PROP_BloodType, PN);
438 				P.SetField(Lst.Class, "BloodType");
439 				P.SetField2(Lst.Class, "BloodSplatterType");
440 			}
441 			else if (PN->Name == "prop_stencil_colour")
442 			{
443 				VPropDef& P = Lst.NewProp(PROP_StencilColour, PN);
444 			}
445 			else if (PN->Name == "prop_monster")
446 			{
447 				VPropDef& P = Lst.NewProp(PROP_Monster, PN);
448 			}
449 			else if (PN->Name == "prop_projectile")
450 			{
451 				VPropDef& P = Lst.NewProp(PROP_Projectile, PN);
452 			}
453 			else if (PN->Name == "prop_bouncetype")
454 			{
455 				VPropDef& P = Lst.NewProp(PROP_BounceType, PN);
456 			}
457 			else if (PN->Name == "prop_clear_flags")
458 			{
459 				VPropDef& P = Lst.NewProp(PROP_ClearFlags, PN);
460 			}
461 			else if (PN->Name == "prop_drop_item")
462 			{
463 				VPropDef& P = Lst.NewProp(PROP_DropItem, PN);
464 			}
465 			else if (PN->Name == "prop_states")
466 			{
467 				VPropDef& P = Lst.NewProp(PROP_States, PN);
468 			}
469 			else if (PN->Name == "prop_skip_super")
470 			{
471 				VPropDef& P = Lst.NewProp(PROP_SkipSuper, PN);
472 			}
473 			else if (PN->Name == "prop_args")
474 			{
475 				VPropDef& P = Lst.NewProp(PROP_Args, PN);
476 				P.SetField(Lst.Class, "Args");
477 				P.SetField2(Lst.Class, "bArgsDefined");
478 			}
479 			else if (PN->Name == "prop_low_message")
480 			{
481 				VPropDef& P = Lst.NewProp(PROP_LowMessage, PN);
482 				P.SetField(Lst.Class, "LowHealth");
483 				P.SetField2(Lst.Class, "LowHealthMessage");
484 			}
485 			else if (PN->Name == "prop_powerup_colour")
486 			{
487 				VPropDef& P = Lst.NewProp(PROP_PowerupColour, PN);
488 				P.SetField(Lst.Class, "BlendColour");
489 			}
490 			else if (PN->Name == "prop_colour_range")
491 			{
492 				VPropDef& P = Lst.NewProp(PROP_ColourRange, PN);
493 				P.SetField(Lst.Class, "TranslStart");
494 				P.SetField2(Lst.Class, "TranslEnd");
495 			}
496 			else if (PN->Name == "prop_damage_screen_colour")
497 			{
498 				VPropDef& P = Lst.NewProp(PROP_DamageScreenColour, PN);
499 				P.SetField(Lst.Class, "DamageScreenColour");
500 			}
501 			else if (PN->Name == "prop_hexen_armor")
502 			{
503 				VPropDef& P = Lst.NewProp(PROP_HexenArmor, PN);
504 				P.SetField(Lst.Class, "HexenArmor");
505 			}
506 			else if (PN->Name == "prop_start_item")
507 			{
508 				VPropDef& P = Lst.NewProp(PROP_StartItem, PN);
509 				P.SetField(Lst.Class, "DropItemList");
510 			}
511 			else if (PN->Name == "prop_morph_style")
512 			{
513 				VPropDef& P = Lst.NewProp(PROP_MorphStyle, PN);
514 				P.SetField(Lst.Class, *PN->GetAttribute("property"));
515 			}
516 			else if (PN->Name == "flag")
517 			{
518 				VFlagDef& F = Lst.NewFlag(FLAG_Bool, PN);
519 				F.SetField(Lst.Class, *PN->GetAttribute("property"));
520 			}
521 			else if (PN->Name == "flag_unsupported")
522 			{
523 				VFlagDef& F = Lst.NewFlag(FLAG_Unsupported, PN);
524 			}
525 			else if (PN->Name == "flag_byte")
526 			{
527 				VFlagDef& F = Lst.NewFlag(FLAG_Byte, PN);
528 				F.SetField(Lst.Class, *PN->GetAttribute("property"));
529 				F.BTrue = atoi(*PN->GetAttribute("true_value"));
530 				F.BFalse = atoi(*PN->GetAttribute("false_value"));
531 			}
532 			else if (PN->Name == "flag_float")
533 			{
534 				VFlagDef& F = Lst.NewFlag(FLAG_Float, PN);
535 				F.SetField(Lst.Class, *PN->GetAttribute("property"));
536 				F.FTrue = atof(*PN->GetAttribute("true_value"));
537 				F.FFalse = atof(*PN->GetAttribute("false_value"));
538 			}
539 			else if (PN->Name == "flag_name")
540 			{
541 				VFlagDef& F = Lst.NewFlag(FLAG_Name, PN);
542 				F.SetField(Lst.Class, *PN->GetAttribute("property"));
543 				F.NTrue = *PN->GetAttribute("true_value");
544 				F.NFalse = *PN->GetAttribute("false_value");
545 			}
546 			else if (PN->Name == "flag_class")
547 			{
548 				VFlagDef& F = Lst.NewFlag(FLAG_Class, PN);
549 				F.SetField(Lst.Class, *PN->GetAttribute("property"));
550 				F.NTrue = *PN->GetAttribute("true_value");
551 				F.NFalse = *PN->GetAttribute("false_value");
552 			}
553 			else if (PN->Name == "flag_noclip")
554 			{
555 				VFlagDef& F = Lst.NewFlag(FLAG_NoClip, PN);
556 				F.SetField(Lst.Class, "bColideWithThings");
557 				F.SetField2(Lst.Class, "bColideWithWorld");
558 			}
559 			else
560 			{
561 				Sys_Error("Unknown XML node %s", *PN->Name);
562 			}
563 		}
564 	}
565 	unguard;
566 }
567 
568 //==========================================================================
569 //
570 //	VPropDef::SetField
571 //
572 //==========================================================================
573 
SetField(VClass * Class,const char * FieldName)574 void VPropDef::SetField(VClass* Class, const char* FieldName)
575 {
576 	guard(VPropDef::SetField);
577 	Field = Class->FindFieldChecked(FieldName);
578 	unguard;
579 }
580 
581 //==========================================================================
582 //
583 //	VPropDef::SetField2
584 //
585 //==========================================================================
586 
SetField2(VClass * Class,const char * FieldName)587 void VPropDef::SetField2(VClass* Class, const char* FieldName)
588 {
589 	guard(VPropDef::SetField2);
590 	Field2 = Class->FindFieldChecked(FieldName);
591 	unguard;
592 }
593 
594 //==========================================================================
595 //
596 //	VFlagDef::SetField
597 //
598 //==========================================================================
599 
SetField(VClass * Class,const char * FieldName)600 void VFlagDef::SetField(VClass* Class, const char* FieldName)
601 {
602 	guard(VFlagDef::SetField);
603 	Field = Class->FindFieldChecked(FieldName);
604 	unguard;
605 }
606 
607 //==========================================================================
608 //
609 //	VFlagDef::SetField2
610 //
611 //==========================================================================
612 
SetField2(VClass * Class,const char * FieldName)613 void VFlagDef::SetField2(VClass* Class, const char* FieldName)
614 {
615 	guard(VFlagDef::SetField2);
616 	Field2 = Class->FindFieldChecked(FieldName);
617 	unguard;
618 }
619 
620 //==========================================================================
621 //
622 //	VFlagList::NewProp
623 //
624 //==========================================================================
625 
NewProp(vuint8 Type,VXmlNode * PN)626 VPropDef& VFlagList::NewProp(vuint8 Type, VXmlNode* PN)
627 {
628 	guard(VFlagList::NewProp);
629 	VPropDef& P = Props.Alloc();
630 	P.Type = Type;
631 	P.Name = *PN->GetAttribute("name").ToLower();
632 	int HashIndex = GetTypeHash(P.Name) & (PROPS_HASH_SIZE - 1);
633 	P.HashNext = PropsHash[HashIndex];
634 	PropsHash[HashIndex] = Props.Num() - 1;
635 	return P;
636 	unguard;
637 }
638 
639 //==========================================================================
640 //
641 //	VFlagList::NewFlag
642 //
643 //==========================================================================
644 
NewFlag(vuint8 Type,VXmlNode * PN)645 VFlagDef& VFlagList::NewFlag(vuint8 Type, VXmlNode* PN)
646 {
647 	guard(VFlagList::NewFlag);
648 	VFlagDef& F = Flags.Alloc();
649 	F.Type = Type;
650 	F.Name = *PN->GetAttribute("name").ToLower();
651 	int HashIndex = GetTypeHash(F.Name) & (FLAGS_HASH_SIZE - 1);
652 	F.HashNext = FlagsHash[HashIndex];
653 	FlagsHash[HashIndex] = Flags.Num() - 1;
654 	return F;
655 	unguard;
656 }
657 
658 //==========================================================================
659 //
660 //	VDecorateSingleName::VDecorateSingleName
661 //
662 //==========================================================================
663 
VDecorateSingleName(const VStr & AName,const TLocation & ALoc)664 VDecorateSingleName::VDecorateSingleName(const VStr& AName,
665 	const TLocation& ALoc)
666 : VExpression(ALoc)
667 , Name(AName)
668 {
669 }
670 
671 //==========================================================================
672 //
673 //	VDecorateSingleName::DoResolve
674 //
675 //==========================================================================
676 
DoResolve(VEmitContext & ec)677 VExpression* VDecorateSingleName::DoResolve(VEmitContext& ec)
678 {
679 	guard(VDecorateSingleName::DoResolve);
680 	VName CheckName = va("decorate_%s", *Name.ToLower());
681 	if (ec.SelfClass)
682 	{
683 		VConstant* Const = ec.SelfClass->FindConstant(CheckName);
684 		if (Const)
685 		{
686 			VExpression* e = new VConstantValue(Const, Loc);
687 			delete this;
688 			return e->Resolve(ec);
689 		}
690 
691 		VProperty* Prop = ec.SelfClass->FindProperty(CheckName);
692 		if (Prop)
693 		{
694 			if (!Prop->GetFunc)
695 			{
696 				ParseError(Loc, "Property %s cannot be read", *Name);
697 				delete this;
698 				return NULL;
699 			}
700 			VExpression* e = new VInvocation(NULL, Prop->GetFunc, NULL,
701 				false, false, Loc, 0, NULL);
702 			delete this;
703 			return e->Resolve(ec);
704 		}
705 	}
706 
707 	CheckName = *Name.ToLower();
708 	//	Look only for constants defined in DECORATE scripts.
709 	VConstant* Const = ec.Package->FindConstant(CheckName);
710 	if (Const)
711 	{
712 		VExpression* e = new VConstantValue(Const, Loc);
713 		delete this;
714 		return e->Resolve(ec);
715 	}
716 
717 	ParseError(Loc, "Illegal expression identifier %s", *Name);
718 	delete this;
719 	return NULL;
720 	unguard;
721 }
722 
723 //==========================================================================
724 //
725 //	VDecorateSingleName::Emit
726 //
727 //==========================================================================
728 
Emit(VEmitContext &)729 void VDecorateSingleName::Emit(VEmitContext&)
730 {
731 	ParseError(Loc, "Should not happen");
732 }
733 
734 //==========================================================================
735 //
736 //	VDecorateSingleName::IsDecorateSingleName
737 //
738 //==========================================================================
739 
IsDecorateSingleName() const740 bool VDecorateSingleName::IsDecorateSingleName() const
741 {
742 	return true;
743 }
744 
745 //==========================================================================
746 //
747 //	VDecorateInvocation::VDecorateInvocation
748 //
749 //==========================================================================
750 
VDecorateInvocation(VName AName,const TLocation & ALoc,int ANumArgs,VExpression ** AArgs)751 VDecorateInvocation::VDecorateInvocation(VName AName, const TLocation& ALoc, int ANumArgs,
752 	VExpression** AArgs)
753 : VExpression(ALoc)
754 , Name(AName)
755 , NumArgs(ANumArgs)
756 {
757 	for (int i = 0; i < NumArgs; i++)
758 		Args[i] = AArgs[i];
759 }
760 
761 //==========================================================================
762 //
763 //	VDecorateInvocation::~VDecorateInvocation
764 //
765 //==========================================================================
766 
~VDecorateInvocation()767 VDecorateInvocation::~VDecorateInvocation()
768 {
769 	for (int i = 0; i < NumArgs; i++)
770 		if (Args[i])
771 		{
772 			delete Args[i];
773 			Args[i] = NULL;
774 		}
775 }
776 
777 //==========================================================================
778 //
779 //	VDecorateInvocation::DoResolve
780 //
781 //==========================================================================
782 
DoResolve(VEmitContext & ec)783 VExpression* VDecorateInvocation::DoResolve(VEmitContext& ec)
784 {
785 	guard(VDecorateInvocation::DoResolve);
786 	if (ec.SelfClass)
787 	{
788 		//	First try with decorate_ prefix, then without.
789 		VMethod* M = ec.SelfClass->FindMethod(va("decorate_%s", *Name));
790 		if (!M)
791 		{
792 			M = ec.SelfClass->FindMethod(Name);
793 		}
794 		if (M)
795 		{
796 			if (M->Flags & FUNC_Iterator)
797 			{
798 				ParseError(Loc, "Iterator methods can only be used in foreach statements");
799 				delete this;
800 				return NULL;
801 			}
802 			VExpression* e = new VInvocation(NULL, M, NULL,
803 				false, false, Loc, NumArgs, Args);
804 			NumArgs = 0;
805 			delete this;
806 			return e->Resolve(ec);
807 		}
808 	}
809 
810 	ParseError(Loc, "Unknown method %s", *Name);
811 	delete this;
812 	return NULL;
813 	unguard;
814 }
815 
816 //==========================================================================
817 //
818 //	VDecorateInvocation::Emit
819 //
820 //==========================================================================
821 
Emit(VEmitContext &)822 void VDecorateInvocation::Emit(VEmitContext&)
823 {
824 	ParseError(Loc, "Should not happen");
825 }
826 
827 //==========================================================================
828 //
829 //	GetClassFieldFloat
830 //
831 //==========================================================================
832 
GetClassFieldFloat(VClass * Class,VName FieldName)833 static float GetClassFieldFloat(VClass* Class, VName FieldName)
834 {
835 	guard(GetClassFieldFloat);
836 	VField* F = Class->FindFieldChecked(FieldName);
837 	return F->GetFloat((VObject*)Class->Defaults);
838 	unguard;
839 }
840 
841 //==========================================================================
842 //
843 //	GetClassFieldVec
844 //
845 //==========================================================================
846 
GetClassFieldVec(VClass * Class,VName FieldName)847 static TVec GetClassFieldVec(VClass* Class, VName FieldName)
848 {
849 	guard(GetClassFieldVec);
850 	VField* F = Class->FindFieldChecked(FieldName);
851 	return F->GetVec((VObject*)Class->Defaults);
852 	unguard;
853 }
854 
855 //==========================================================================
856 //
857 //	GetClassDropItems
858 //
859 //==========================================================================
860 
GetClassDropItems(VClass * Class)861 static TArray<VDropItemInfo>& GetClassDropItems(VClass* Class)
862 {
863 	guard(GetClassDropItems);
864 	VField* F = Class->FindFieldChecked("DropItemList");
865 	return *(TArray<VDropItemInfo>*)F->GetFieldPtr((VObject*)Class->Defaults);
866 	unguard;
867 }
868 
869 //==========================================================================
870 //
871 //	GetClassDamageFactors
872 //
873 //==========================================================================
874 
GetClassDamageFactors(VClass * Class)875 static TArray<VDamageFactor>& GetClassDamageFactors(VClass* Class)
876 {
877 	guard(GetClassDamageFactors);
878 	VField* F = Class->FindFieldChecked("DamageFactors");
879 	return *(TArray<VDamageFactor>*)F->GetFieldPtr((VObject*)Class->Defaults);
880 	unguard;
881 }
882 
883 //==========================================================================
884 //
885 //	GetClassPainChances
886 //
887 //==========================================================================
888 
GetClassPainChances(VClass * Class)889 static TArray<VPainChanceInfo>& GetClassPainChances(VClass* Class)
890 {
891 	guard(GetClassPainChances);
892 	VField* F = Class->FindFieldChecked("PainChances");
893 	return *(TArray<VPainChanceInfo>*)F->GetFieldPtr((VObject*)Class->Defaults);
894 	unguard;
895 }
896 
897 //==========================================================================
898 //
899 //	SetClassFieldInt
900 //
901 //==========================================================================
902 
SetClassFieldInt(VClass * Class,VName FieldName,int Value,int Idx=0)903 static void SetClassFieldInt(VClass* Class, VName FieldName, int Value,
904 	int Idx = 0)
905 {
906 	guard(SetClassFieldInt);
907 	VField* F = Class->FindFieldChecked(FieldName);
908 	F->SetInt((VObject*)Class->Defaults, Value, Idx);
909 	unguard;
910 }
911 
912 //==========================================================================
913 //
914 //	SetClassFieldByte
915 //
916 //==========================================================================
917 
SetClassFieldByte(VClass * Class,VName FieldName,vuint8 Value)918 static void SetClassFieldByte(VClass* Class, VName FieldName, vuint8 Value)
919 {
920 	guard(SetClassFieldByte);
921 	VField* F = Class->FindFieldChecked(FieldName);
922 	F->SetByte((VObject*)Class->Defaults, Value);
923 	unguard;
924 }
925 
926 //==========================================================================
927 //
928 //	SetClassFieldFloat
929 //
930 //==========================================================================
931 
SetClassFieldFloat(VClass * Class,VName FieldName,float Value,int Idx=0)932 static void SetClassFieldFloat(VClass* Class, VName FieldName, float Value,
933 	int Idx = 0)
934 {
935 	guard(SetClassFieldFloat);
936 	VField* F = Class->FindFieldChecked(FieldName);
937 	F->SetFloat((VObject*)Class->Defaults, Value, Idx);
938 	unguard;
939 }
940 
941 //==========================================================================
942 //
943 //	SetClassFieldBool
944 //
945 //==========================================================================
946 
SetClassFieldBool(VClass * Class,VName FieldName,int Value)947 static void SetClassFieldBool(VClass* Class, VName FieldName, int Value)
948 {
949 	guard(SetClassFieldBool);
950 	VField* F = Class->FindFieldChecked(FieldName);
951 	F->SetBool((VObject*)Class->Defaults, Value);
952 	unguard;
953 }
954 
955 //==========================================================================
956 //
957 //	SetClassFieldName
958 //
959 //==========================================================================
960 
SetClassFieldName(VClass * Class,VName FieldName,VName Value)961 static void SetClassFieldName(VClass* Class, VName FieldName, VName Value)
962 {
963 	guard(SetClassFieldName);
964 	VField* F = Class->FindFieldChecked(FieldName);
965 	F->SetName((VObject*)Class->Defaults, Value);
966 	unguard;
967 }
968 
969 //==========================================================================
970 //
971 //	SetClassFieldStr
972 //
973 //==========================================================================
974 
SetClassFieldStr(VClass * Class,VName FieldName,const VStr & Value)975 static void SetClassFieldStr(VClass* Class, VName FieldName,
976 	const VStr& Value)
977 {
978 	guard(SetClassFieldStr);
979 	VField* F = Class->FindFieldChecked(FieldName);
980 	F->SetStr((VObject*)Class->Defaults, Value);
981 	unguard;
982 }
983 
984 //==========================================================================
985 //
986 //	SetClassFieldVec
987 //
988 //==========================================================================
989 
SetClassFieldVec(VClass * Class,VName FieldName,const TVec & Value)990 static void SetClassFieldVec(VClass* Class, VName FieldName,
991 	const TVec& Value)
992 {
993 	guard(SetClassFieldVec);
994 	VField* F = Class->FindFieldChecked(FieldName);
995 	F->SetVec((VObject*)Class->Defaults, Value);
996 	unguard;
997 }
998 
999 //==========================================================================
1000 //
1001 //	SetFieldByte
1002 //
1003 //==========================================================================
1004 
SetFieldByte(VObject * Obj,VName FieldName,vuint8 Value)1005 static void SetFieldByte(VObject* Obj, VName FieldName, vuint8 Value)
1006 {
1007 	guard(SetFieldByte);
1008 	VField* F = Obj->GetClass()->FindFieldChecked(FieldName);
1009 	F->SetByte(Obj, Value);
1010 	unguard;
1011 }
1012 
1013 //==========================================================================
1014 //
1015 //	SetFieldFloat
1016 //
1017 //==========================================================================
1018 
SetFieldFloat(VObject * Obj,VName FieldName,float Value,int Idx=0)1019 static void SetFieldFloat(VObject* Obj, VName FieldName, float Value,
1020 	int Idx = 0)
1021 {
1022 	guard(SetFieldFloat);
1023 	VField* F = Obj->GetClass()->FindFieldChecked(FieldName);
1024 	F->SetFloat(Obj, Value, Idx);
1025 	unguard;
1026 }
1027 
1028 //==========================================================================
1029 //
1030 //	SetFieldBool
1031 //
1032 //==========================================================================
1033 
SetFieldBool(VObject * Obj,VName FieldName,int Value)1034 static void SetFieldBool(VObject* Obj, VName FieldName, int Value)
1035 {
1036 	guard(SetFieldBool);
1037 	VField* F = Obj->GetClass()->FindFieldChecked(FieldName);
1038 	F->SetBool(Obj, Value);
1039 	unguard;
1040 }
1041 
1042 //==========================================================================
1043 //
1044 //	SetFieldName
1045 //
1046 //==========================================================================
1047 
SetFieldName(VObject * Obj,VName FieldName,VName Value)1048 static void SetFieldName(VObject* Obj, VName FieldName, VName Value)
1049 {
1050 	guard(SetFieldName);
1051 	VField* F = Obj->GetClass()->FindFieldChecked(FieldName);
1052 	F->SetName(Obj, Value);
1053 	unguard;
1054 }
1055 
1056 //==========================================================================
1057 //
1058 //	SetFieldClass
1059 //
1060 //==========================================================================
1061 
SetFieldClass(VObject * Obj,VName FieldName,VClass * Value)1062 static void SetFieldClass(VObject* Obj, VName FieldName, VClass* Value)
1063 {
1064 	guard(SetFieldClass);
1065 	VField* F = Obj->GetClass()->FindFieldChecked(FieldName);
1066 	F->SetClass(Obj, Value);
1067 	unguard;
1068 }
1069 
1070 //==========================================================================
1071 //
1072 //	AddClassFixup
1073 //
1074 //==========================================================================
1075 
AddClassFixup(VClass * Class,VName FieldName,const VStr & ClassName,TArray<VClassFixup> & ClassFixups)1076 static void AddClassFixup(VClass* Class, VName FieldName,
1077 	const VStr& ClassName, TArray<VClassFixup>& ClassFixups)
1078 {
1079 	guard(AddClassFixup);
1080 	VField* F = Class->FindFieldChecked(FieldName);
1081 	VClassFixup& CF = ClassFixups.Alloc();
1082 	CF.Offset = F->Ofs;
1083 	CF.Name = ClassName;
1084 	CF.ReqParent = F->Type.Class;
1085 	CF.Class = Class;
1086 	unguard;
1087 }
1088 
1089 //==========================================================================
1090 //
1091 //	AddClassFixup
1092 //
1093 //==========================================================================
1094 
AddClassFixup(VClass * Class,VField * Field,const VStr & ClassName,TArray<VClassFixup> & ClassFixups)1095 static void AddClassFixup(VClass* Class, VField* Field,
1096 	const VStr& ClassName, TArray<VClassFixup>& ClassFixups)
1097 {
1098 	guard(AddClassFixup);
1099 	VClassFixup& CF = ClassFixups.Alloc();
1100 	CF.Offset = Field->Ofs;
1101 	CF.Name = ClassName;
1102 	CF.ReqParent = Field->Type.Class;
1103 	CF.Class = Class;
1104 	unguard;
1105 }
1106 
1107 //==========================================================================
1108 //
1109 //	SkipBlock
1110 //
1111 //==========================================================================
1112 
SkipBlock(VScriptParser * sc,int Level)1113 static void SkipBlock(VScriptParser* sc, int Level)
1114 {
1115 	while (!sc->AtEnd() && Level > 0)
1116 	{
1117 		if (sc->Check("{"))
1118 		{
1119 			Level++;
1120 		}
1121 		else if (sc->Check("}"))
1122 		{
1123 			Level--;
1124 		}
1125 		else
1126 		{
1127 			sc->GetString();
1128 		}
1129 	}
1130 }
1131 
1132 //==========================================================================
1133 //
1134 //	ParseMethodCall
1135 //
1136 //==========================================================================
1137 
ParseMethodCall(VScriptParser * sc,VName Name,TLocation Loc)1138 static VExpression* ParseMethodCall(VScriptParser* sc, VName Name,
1139 	TLocation Loc)
1140 {
1141 	guard(ParseMethodCall);
1142 	VExpression* Args[VMethod::MAX_PARAMS + 1];
1143 	int NumArgs = 0;
1144 	if (!sc->Check(")"))
1145 	{
1146 		do
1147 		{
1148 			Args[NumArgs] = ParseExpressionPriority13(sc);
1149 			if (NumArgs == VMethod::MAX_PARAMS)
1150 				ParseError(sc->GetLoc(), "Too many arguments");
1151 			else
1152 				NumArgs++;
1153 		} while (sc->Check(","));
1154 		sc->Expect(")");
1155 	}
1156 	return new VDecorateInvocation(Name, Loc, NumArgs, Args);
1157 	unguard;
1158 }
1159 
1160 //==========================================================================
1161 //
1162 //	ParseExpressionPriority0
1163 //
1164 //==========================================================================
1165 
ParseExpressionPriority0(VScriptParser * sc)1166 static VExpression* ParseExpressionPriority0(VScriptParser* sc)
1167 {
1168 	guard(ParseExpressionPriority0);
1169 	TLocation l = sc->GetLoc();
1170 	//  Check for quoted strings first,
1171 	//  since these could also have numbers...
1172 	if (sc->CheckQuotedString())
1173 	{
1174 		int Val = DecPkg->FindString(*sc->String);
1175 		return new VStringLiteral(Val, l);
1176 	}
1177 
1178 	if (sc->CheckNumber())
1179 	{
1180 		vint32 Val = sc->Number;
1181 		return new VIntLiteral(Val, l);
1182 	}
1183 
1184 	if (sc->CheckFloat())
1185 	{
1186 		float Val = sc->Float;
1187 		return new VFloatLiteral(Val, l);
1188 	}
1189 
1190 	if (sc->Check("false"))
1191 	{
1192 		return new VIntLiteral(0, l);
1193 	}
1194 
1195 	if (sc->Check("true"))
1196 	{
1197 		return new VIntLiteral(1, l);
1198 	}
1199 
1200 	if (sc->Check("("))
1201 	{
1202 		VExpression* op = ParseExpressionPriority13(sc);
1203 		if (!op)
1204 		{
1205 			ParseError(l, "Expression expected");
1206 		}
1207 		sc->Expect(")");
1208 		return op;
1209 	}
1210 
1211 	if (sc->CheckIdentifier())
1212 	{
1213 		VStr Name = sc->String;
1214 		//	Skip random generator ID.
1215 		if ((!Name.ICmp("random") || !Name.ICmp("random2")) && sc->Check("["))
1216 		{
1217 			sc->ExpectString();
1218 			sc->Expect("]");
1219 		}
1220 		if (sc->Check("("))
1221 		{
1222 			return ParseMethodCall(sc, *Name.ToLower(), l);
1223 		}
1224 		return new VDecorateSingleName(Name, l);
1225 	}
1226 
1227 	return NULL;
1228 	unguard;
1229 }
1230 
1231 //==========================================================================
1232 //
1233 //	ParseExpressionPriority1
1234 //
1235 //==========================================================================
1236 
ParseExpressionPriority1(VScriptParser * sc)1237 static VExpression* ParseExpressionPriority1(VScriptParser* sc)
1238 {
1239 	guard(ParseExpressionPriority1);
1240 	VExpression* op = ParseExpressionPriority0(sc);
1241 
1242 	TLocation l = sc->GetLoc();
1243 
1244 	if (!op)
1245 		return NULL;
1246 	bool done = false;
1247 	do
1248 	{
1249 		if (sc->Check("["))
1250 		{
1251 			VExpression* ind = ParseExpressionPriority13(sc);
1252 			sc->Expect("]");
1253 			op = new VArrayElement(op, ind, l);
1254 		}
1255 		else
1256 		{
1257 			done = true;
1258 		}
1259 	} while (!done);
1260 
1261 	return op;
1262 	unguard;
1263 }
1264 
1265 //==========================================================================
1266 //
1267 //	ParseExpressionPriority2
1268 //
1269 //==========================================================================
1270 
ParseExpressionPriority2(VScriptParser * sc)1271 static VExpression* ParseExpressionPriority2(VScriptParser* sc)
1272 {
1273 	guard(ParseExpressionPriority2);
1274 	VExpression*	op;
1275 
1276 	TLocation l = sc->GetLoc();
1277 
1278 	if (sc->Check("+"))
1279 	{
1280 		op = ParseExpressionPriority2(sc);
1281 		return new VUnary(VUnary::Plus, op, l);
1282 	}
1283 
1284 	if (sc->Check("-"))
1285 	{
1286 		op = ParseExpressionPriority2(sc);
1287 		return new VUnary(VUnary::Minus, op, l);
1288 	}
1289 
1290 	if (sc->Check("!"))
1291 	{
1292 		op = ParseExpressionPriority2(sc);
1293 		return new VUnary(VUnary::Not, op, l);
1294 	}
1295 
1296 	if (sc->Check("~"))
1297 	{
1298 		op = ParseExpressionPriority2(sc);
1299 		return new VUnary(VUnary::BitInvert, op, l);
1300 	}
1301 
1302 	return ParseExpressionPriority1(sc);
1303 	unguard;
1304 }
1305 
1306 //==========================================================================
1307 //
1308 //	ParseExpressionPriority3
1309 //
1310 //==========================================================================
1311 
ParseExpressionPriority3(VScriptParser * sc)1312 static VExpression* ParseExpressionPriority3(VScriptParser* sc)
1313 {
1314 	guard(ParseExpressionPriority3);
1315 	VExpression* op1 = ParseExpressionPriority2(sc);
1316 	if (!op1)
1317 	{
1318 		return NULL;
1319 	}
1320 	bool done = false;
1321 	do
1322 	{
1323 		TLocation l = sc->GetLoc();
1324 		if (sc->Check("*"))
1325 		{
1326 			VExpression* op2 = ParseExpressionPriority2(sc);
1327 			op1 = new VBinary(VBinary::Multiply, op1, op2, l);
1328 		}
1329 		else if (sc->Check("/"))
1330 		{
1331 			VExpression* op2 = ParseExpressionPriority2(sc);
1332 			op1 = new VBinary(VBinary::Divide, op1, op2, l);
1333 		}
1334 		else if (sc->Check("%"))
1335 		{
1336 			VExpression* op2 = ParseExpressionPriority2(sc);
1337 			op1 = new VBinary(VBinary::Modulus, op1, op2, l);
1338 		}
1339 		else
1340 		{
1341 			done = true;
1342 		}
1343 	}
1344 	while (!done);
1345 	return op1;
1346 	unguard;
1347 }
1348 
1349 //==========================================================================
1350 //
1351 //	ParseExpressionPriority4
1352 //
1353 //==========================================================================
1354 
ParseExpressionPriority4(VScriptParser * sc)1355 static VExpression* ParseExpressionPriority4(VScriptParser* sc)
1356 {
1357 	guard(ParseExpressionPriority4);
1358 	VExpression* op1 = ParseExpressionPriority3(sc);
1359 	if (!op1)
1360 	{
1361 		return NULL;
1362 	}
1363 	bool done = false;
1364 	do
1365 	{
1366 		TLocation l = sc->GetLoc();
1367 		if (sc->Check("+"))
1368 		{
1369 			VExpression* op2 = ParseExpressionPriority3(sc);
1370 			op1 = new VBinary(VBinary::Add, op1, op2, l);
1371 		}
1372 		else if (sc->Check("-"))
1373 		{
1374 			VExpression* op2 = ParseExpressionPriority3(sc);
1375 			op1 = new VBinary(VBinary::Subtract, op1, op2, l);
1376 		}
1377 		else
1378 		{
1379 			done = true;
1380 		}
1381 	}
1382 	while (!done);
1383 	return op1;
1384 	unguard;
1385 }
1386 
1387 //==========================================================================
1388 //
1389 //	ParseExpressionPriority5
1390 //
1391 //==========================================================================
1392 
ParseExpressionPriority5(VScriptParser * sc)1393 static VExpression* ParseExpressionPriority5(VScriptParser* sc)
1394 {
1395 	guard(ParseExpressionPriority5);
1396 	VExpression* op1 = ParseExpressionPriority4(sc);
1397 	if (!op1)
1398 	{
1399 		return NULL;
1400 	}
1401 	bool done = false;
1402 	do
1403 	{
1404 		TLocation l = sc->GetLoc();
1405 		if (sc->Check("<<"))
1406 		{
1407 			VExpression* op2 = ParseExpressionPriority4(sc);
1408 			op1 = new VBinary(VBinary::LShift, op1, op2, l);
1409 		}
1410 		else if (sc->Check(">>"))
1411 		{
1412 			VExpression* op2 = ParseExpressionPriority4(sc);
1413 			op1 = new VBinary(VBinary::RShift, op1, op2, l);
1414 		}
1415 		else
1416 		{
1417 			done = true;
1418 		}
1419 	}
1420 	while (!done);
1421 	return op1;
1422 	unguard;
1423 }
1424 
1425 //==========================================================================
1426 //
1427 //	ParseExpressionPriority6
1428 //
1429 //==========================================================================
1430 
ParseExpressionPriority6(VScriptParser * sc)1431 static VExpression* ParseExpressionPriority6(VScriptParser* sc)
1432 {
1433 	guard(ParseExpressionPriority6);
1434 	VExpression* op1 = ParseExpressionPriority5(sc);
1435 	if (!op1)
1436 	{
1437 		return NULL;
1438 	}
1439 	bool done = false;
1440 	do
1441 	{
1442 		TLocation l = sc->GetLoc();
1443 		if (sc->Check("<"))
1444 		{
1445 			VExpression* op2 = ParseExpressionPriority5(sc);
1446 			op1 = new VBinary(VBinary::Less, op1, op2, l);
1447 		}
1448 		else if (sc->Check("<="))
1449 		{
1450 			VExpression* op2 = ParseExpressionPriority5(sc);
1451 			op1 = new VBinary(VBinary::LessEquals, op1, op2, l);
1452 		}
1453 		else if (sc->Check(">"))
1454 		{
1455 			VExpression* op2 = ParseExpressionPriority5(sc);
1456 			op1 = new VBinary(VBinary::Greater, op1, op2, l);
1457 		}
1458 		else if (sc->Check(">="))
1459 		{
1460 			VExpression* op2 = ParseExpressionPriority5(sc);
1461 			op1 = new VBinary(VBinary::GreaterEquals, op1, op2, l);
1462 		}
1463 		else
1464 		{
1465 			done = true;
1466 		}
1467 	}
1468 	while (!done);
1469 	return op1;
1470 	unguard;
1471 }
1472 
1473 //==========================================================================
1474 //
1475 //	ParseExpressionPriority7
1476 //
1477 //==========================================================================
1478 
ParseExpressionPriority7(VScriptParser * sc)1479 static VExpression* ParseExpressionPriority7(VScriptParser* sc)
1480 {
1481 	guard(ParseExpressionPriority7);
1482 	VExpression* op1 = ParseExpressionPriority6(sc);
1483 	if (!op1)
1484 	{
1485 		return NULL;
1486 	}
1487 	bool done = false;
1488 	do
1489 	{
1490 		TLocation l = sc->GetLoc();
1491 		if (sc->Check("=="))
1492 		{
1493 			VExpression* op2 = ParseExpressionPriority6(sc);
1494 			op1 = new VBinary(VBinary::Equals, op1, op2, l);
1495 		}
1496 		else if (sc->Check("!="))
1497 		{
1498 			VExpression* op2 = ParseExpressionPriority6(sc);
1499 			op1 = new VBinary(VBinary::NotEquals, op1, op2, l);
1500 		}
1501 		else
1502 		{
1503 			done = true;
1504 		}
1505 	} while (!done);
1506 	return op1;
1507 	unguard;
1508 }
1509 
1510 //==========================================================================
1511 //
1512 //	ParseExpressionPriority8
1513 //
1514 //==========================================================================
1515 
ParseExpressionPriority8(VScriptParser * sc)1516 static VExpression* ParseExpressionPriority8(VScriptParser* sc)
1517 {
1518 	guard(ParseExpressionPriority8);
1519 	VExpression* op1 = ParseExpressionPriority7(sc);
1520 	if (!op1)
1521 	{
1522 		return NULL;
1523 	}
1524 	TLocation l = sc->GetLoc();
1525 	while (sc->Check("&"))
1526 	{
1527 		VExpression* op2 = ParseExpressionPriority7(sc);
1528 		op1 = new VBinary(VBinary::And, op1, op2, l);
1529 		l = sc->GetLoc();
1530 	}
1531 	return op1;
1532 	unguard;
1533 }
1534 
1535 //==========================================================================
1536 //
1537 //	ParseExpressionPriority9
1538 //
1539 //==========================================================================
1540 
ParseExpressionPriority9(VScriptParser * sc)1541 static VExpression* ParseExpressionPriority9(VScriptParser* sc)
1542 {
1543 	guard(ParseExpressionPriority9);
1544 	VExpression* op1 = ParseExpressionPriority8(sc);
1545 	if (!op1)
1546 	{
1547 		return NULL;
1548 	}
1549 	TLocation l = sc->GetLoc();
1550 	while (sc->Check("^"))
1551 	{
1552 		VExpression* op2 = ParseExpressionPriority8(sc);
1553 		op1 = new VBinary(VBinary::XOr, op1, op2, l);
1554 		l = sc->GetLoc();
1555 	}
1556 	return op1;
1557 	unguard;
1558 }
1559 
1560 //==========================================================================
1561 //
1562 //	ParseExpressionPriority10
1563 //
1564 //==========================================================================
1565 
ParseExpressionPriority10(VScriptParser * sc)1566 static VExpression* ParseExpressionPriority10(VScriptParser* sc)
1567 {
1568 	guard(ParseExpressionPriority10);
1569 	VExpression* op1 = ParseExpressionPriority9(sc);
1570 	if (!op1)
1571 	{
1572 		return NULL;
1573 	}
1574 	TLocation l = sc->GetLoc();
1575 	while (sc->Check("|"))
1576 	{
1577 		VExpression* op2 = ParseExpressionPriority9(sc);
1578 		op1 = new VBinary(VBinary::Or, op1, op2, l);
1579 		l = sc->GetLoc();
1580 	}
1581 	return op1;
1582 	unguard;
1583 }
1584 
1585 //==========================================================================
1586 //
1587 //	ParseExpressionPriority11
1588 //
1589 //==========================================================================
1590 
ParseExpressionPriority11(VScriptParser * sc)1591 static VExpression* ParseExpressionPriority11(VScriptParser* sc)
1592 {
1593 	guard(ParseExpressionPriority11);
1594 	VExpression* op1 = ParseExpressionPriority10(sc);
1595 	if (!op1)
1596 	{
1597 		return NULL;
1598 	}
1599 	TLocation l = sc->GetLoc();
1600 	while (sc->Check("&&"))
1601 	{
1602 		VExpression* op2 = ParseExpressionPriority10(sc);
1603 		op1 = new VBinaryLogical(VBinaryLogical::And, op1, op2, l);
1604 		l = sc->GetLoc();
1605 	}
1606 	return op1;
1607 	unguard;
1608 }
1609 
1610 //==========================================================================
1611 //
1612 //	ParseExpressionPriority12
1613 //
1614 //==========================================================================
1615 
ParseExpressionPriority12(VScriptParser * sc)1616 static VExpression* ParseExpressionPriority12(VScriptParser* sc)
1617 {
1618 	guard(ParseExpressionPriority12);
1619 	VExpression* op1 = ParseExpressionPriority11(sc);
1620 	if (!op1)
1621 	{
1622 		return NULL;
1623 	}
1624 	TLocation l = sc->GetLoc();
1625 	while (sc->Check("||"))
1626 	{
1627 		VExpression* op2 = ParseExpressionPriority11(sc);
1628 		op1 = new VBinaryLogical(VBinaryLogical::Or, op1, op2, l);
1629 		l = sc->GetLoc();
1630 	}
1631 	return op1;
1632 	unguard;
1633 }
1634 
1635 //==========================================================================
1636 //
1637 //	VParser::ParseExpressionPriority13
1638 //
1639 //==========================================================================
1640 
ParseExpressionPriority13(VScriptParser * sc)1641 static VExpression* ParseExpressionPriority13(VScriptParser* sc)
1642 {
1643 	guard(ParseExpressionPriority13);
1644 	VExpression* op = ParseExpressionPriority12(sc);
1645 	if (!op)
1646 	{
1647 		return NULL;
1648 	}
1649 	TLocation l = sc->GetLoc();
1650 	if (sc->Check("?"))
1651 	{
1652 		VExpression* op1 = ParseExpressionPriority13(sc);
1653 		sc->Expect(":");
1654 		VExpression* op2 = ParseExpressionPriority13(sc);
1655 		op = new VConditional(op, op1, op2, l);
1656 	}
1657 	return op;
1658 	unguard;
1659 }
1660 
1661 //==========================================================================
1662 //
1663 //	ParseExpression
1664 //
1665 //==========================================================================
1666 
ParseExpression(VScriptParser * sc)1667 static VExpression* ParseExpression(VScriptParser* sc)
1668 {
1669 	guard(ParseExpression);
1670 	return ParseExpressionPriority13(sc);
1671 	unguard;
1672 }
1673 
1674 //==========================================================================
1675 //
1676 //	ParseConst
1677 //
1678 //==========================================================================
1679 
ParseConst(VScriptParser * sc)1680 static void ParseConst(VScriptParser* sc)
1681 {
1682 	guard(ParseConst);
1683 	sc->SetCMode(true);
1684 	sc->Expect("int");
1685 	sc->ExpectString();
1686 	TLocation Loc = sc->GetLoc();
1687 	VStr Name = sc->String.ToLower();
1688 	sc->Expect("=");
1689 
1690 	VExpression* Expr = ParseExpression(sc);
1691 	if (!Expr)
1692 	{
1693 		sc->Error("Constant value expected");
1694 	}
1695 	else
1696 	{
1697 		VEmitContext ec(DecPkg);
1698 		Expr = Expr->Resolve(ec);
1699 		if (Expr)
1700 		{
1701 			int Val = Expr->GetIntConst();
1702 			delete Expr;
1703 			Expr = NULL;
1704 			VConstant* C = new VConstant(*Name, DecPkg, Loc);
1705 			C->Type = TYPE_Int;
1706 			C->Value = Val;
1707 		}
1708 	}
1709 	sc->Expect(";");
1710 	sc->SetCMode(false);
1711 	unguard;
1712 }
1713 
1714 //==========================================================================
1715 //
1716 //	ParseAction
1717 //
1718 //==========================================================================
1719 
ParseAction(VScriptParser * sc,VClass * Class)1720 static void ParseAction(VScriptParser* sc, VClass* Class)
1721 {
1722 	guard(ParseAction);
1723 	sc->Expect("native");
1724 	//	Find the method. First try with decorate_ prefix, then without.
1725 	sc->ExpectIdentifier();
1726 	VMethod* M = Class->FindMethod(va("decorate_%s", *sc->String));
1727 	if (!M)
1728 	{
1729 		M = Class->FindMethod(*sc->String);
1730 	}
1731 	if (!M)
1732 	{
1733 		sc->Error(va("Method %s not found in class %s", *sc->String,
1734 			Class->GetName()));
1735 	}
1736 	if (M->ReturnType.Type != TYPE_Void)
1737 	{
1738 		sc->Error(va("State action %s doesn't return void", *sc->String));
1739 	}
1740 	VDecorateStateAction& A = Class->DecorateStateActions.Alloc();
1741 	A.Name = *sc->String.ToLower();
1742 	A.Method = M;
1743 	//	Skip arguments, right now I don't care bout them.
1744 	sc->Expect("(");
1745 	while (!sc->Check(")"))
1746 	{
1747 		sc->ExpectString();
1748 	}
1749 	sc->Expect(";");
1750 	unguard;
1751 }
1752 
1753 //==========================================================================
1754 //
1755 //	ParseClass
1756 //
1757 //==========================================================================
1758 
ParseClass(VScriptParser * sc)1759 static void ParseClass(VScriptParser* sc)
1760 {
1761 	guard(ParseClass);
1762 	sc->SetCMode(true);
1763 	//	Get class name and find the class.
1764 	sc->ExpectString();
1765 	VClass* Class = VClass::FindClass(*sc->String);
1766 	if (!Class)
1767 	{
1768 		sc->Error("Class not found");
1769 	}
1770 	//	I don't care about parent class name because in Vavoom it can be
1771 	// different
1772 	sc->Expect("extends");
1773 	sc->ExpectString();
1774 	sc->Expect("native");
1775 	sc->Expect("{");
1776 	while (!sc->Check("}"))
1777 	{
1778 		if (sc->Check("action"))
1779 		{
1780 			ParseAction(sc, Class);
1781 		}
1782 		else
1783 		{
1784 			sc->Error("Unknown class property");
1785 		}
1786 	}
1787 	sc->SetCMode(false);
1788 	unguard;
1789 }
1790 
1791 //==========================================================================
1792 //
1793 //	ParseEnum
1794 //
1795 //==========================================================================
1796 
ParseEnum(VScriptParser * sc)1797 static void ParseEnum(VScriptParser* sc)
1798 {
1799 	guard(ParseEnum);
1800 	GCon->Logf("Enum");
1801 	sc->Expect("{");
1802 	SkipBlock(sc, 1);
1803 	unguard;
1804 }
1805 
1806 //==========================================================================
1807 //
1808 //	ParseFlag
1809 //
1810 //==========================================================================
1811 
ParseFlag(VScriptParser * sc,VClass * Class,bool Value,TArray<VClassFixup> & ClassFixups)1812 static bool ParseFlag(VScriptParser* sc, VClass* Class, bool Value,
1813 	TArray<VClassFixup>& ClassFixups)
1814 {
1815 	guard(ParseFlag);
1816 	//	Get full name of the flag.
1817 	sc->ExpectIdentifier();
1818 	VName FlagName(*sc->String.ToLower());
1819 	VName ClassFilter(NAME_None);
1820 	if (sc->Check("."))
1821 	{
1822 		sc->ExpectIdentifier();
1823 		ClassFilter = FlagName;
1824 		FlagName = *sc->String.ToLower();
1825 	}
1826 	VObject* DefObj = (VObject*)Class->Defaults;
1827 
1828 	for (int j = 0; j < FlagList.Num(); j++)
1829 	{
1830 		VFlagList& ClassDef = FlagList[j];
1831 		if (ClassFilter != NAME_None &&
1832 			ClassDef.Class->LowerCaseName != ClassFilter)
1833 		{
1834 			continue;
1835 		}
1836 		if (!Class->IsChildOf(ClassDef.Class))
1837 		{
1838 			continue;
1839 		}
1840 		for (int i = ClassDef.FlagsHash[GetTypeHash(FlagName) &
1841 			(FLAGS_HASH_SIZE - 1)]; i != -1; i = ClassDef.Flags[i].HashNext)
1842 		{
1843 			const VFlagDef& F = ClassDef.Flags[i];
1844 			if (FlagName == F.Name)
1845 			{
1846 				switch (F.Type)
1847 				{
1848 				case FLAG_Bool:
1849 					F.Field->SetBool(DefObj, Value);
1850 					break;
1851 				case FLAG_Unsupported:
1852 					GCon->Logf("Unsupported flag %s in %s", *FlagName,
1853 						Class->GetName());
1854 					break;
1855 				case FLAG_Byte:
1856 					F.Field->SetByte(DefObj, Value ? F.BTrue : F.BFalse);
1857 					break;
1858 				case FLAG_Float:
1859 					F.Field->SetFloat(DefObj, Value ? F.FTrue : F.FFalse);
1860 					break;
1861 				case FLAG_Name:
1862 					F.Field->SetName(DefObj, Value ? F.NTrue : F.NFalse);
1863 					break;
1864 				case FLAG_Class:
1865 					AddClassFixup(Class, F.Field, Value ?
1866 						*F.NTrue : *F.NFalse, ClassFixups);
1867 					break;
1868 				case FLAG_NoClip:
1869 					F.Field->SetBool(DefObj, !Value);
1870 					F.Field2->SetBool(DefObj, !Value);
1871 					break;
1872 				}
1873 				return true;
1874 			}
1875 		}
1876 	}
1877 	sc->Error(va("Unknown flag %s", *FlagName));
1878 	return false;
1879 	unguard;
1880 }
1881 
1882 //==========================================================================
1883 //
1884 //	ParseStateString
1885 //
1886 //==========================================================================
1887 
ParseStateString(VScriptParser * sc)1888 static VStr ParseStateString(VScriptParser* sc)
1889 {
1890 	guard(ParseStateString);
1891 	VStr		StateStr;
1892 
1893 	if (!sc->CheckQuotedString())
1894 	{
1895 		sc->ExpectIdentifier();
1896 	}
1897 	StateStr = sc->String;
1898 
1899 	if (sc->Check("::"))
1900 	{
1901 		sc->ExpectIdentifier();
1902 		StateStr += "::";
1903 		StateStr += sc->String;
1904 	}
1905 
1906 	if (sc->Check("."))
1907 	{
1908 		sc->ExpectIdentifier();
1909 		StateStr += ".";
1910 		StateStr += sc->String;
1911 	}
1912 
1913 	return StateStr;
1914 	unguard;
1915 }
1916 
1917 //==========================================================================
1918 //
1919 //	ParseStates
1920 //
1921 //==========================================================================
1922 
ParseStates(VScriptParser * sc,VClass * Class,TArray<VState * > & States)1923 static bool ParseStates(VScriptParser* sc, VClass* Class,
1924 	TArray<VState*>& States)
1925 {
1926 	guard(ParseStates);
1927 	VState* PrevState = NULL;
1928 	VState* LastState = NULL;
1929 	VState* LoopStart = NULL;
1930 	int NewLabelsStart = Class->StateLabelDefs.Num();
1931 
1932 	sc->Expect("{");
1933 	//	Disable escape sequences in states.
1934 	sc->SetEscape(false);
1935 	while (!sc->Check("}"))
1936 	{
1937 		TLocation TmpLoc = sc->GetLoc();
1938 		VStr TmpName = ParseStateString(sc);
1939 
1940 		//	Goto command.
1941 		if (!TmpName.ICmp("Goto"))
1942 		{
1943 			VName GotoLabel = *ParseStateString(sc);
1944 			int GotoOffset = 0;
1945 			if (sc->Check("+"))
1946 			{
1947 				sc->ExpectNumber();
1948 				GotoOffset = sc->Number;
1949 			}
1950 
1951 			if (!LastState && NewLabelsStart == Class->StateLabelDefs.Num())
1952 			{
1953 				sc->Error("Goto before first state");
1954 			}
1955 			if (LastState)
1956 			{
1957 				LastState->GotoLabel = GotoLabel;
1958 				LastState->GotoOffset = GotoOffset;
1959 			}
1960 			for (int i = NewLabelsStart; i < Class->StateLabelDefs.Num(); i++)
1961 			{
1962 				Class->StateLabelDefs[i].GotoLabel = GotoLabel;
1963 				Class->StateLabelDefs[i].GotoOffset = GotoOffset;
1964 			}
1965 			NewLabelsStart = Class->StateLabelDefs.Num();
1966 			PrevState = NULL;
1967 			continue;
1968 		}
1969 
1970 		//	Stop command.
1971 		if (!TmpName.ICmp("Stop"))
1972 		{
1973 			if (!LastState && NewLabelsStart == Class->StateLabelDefs.Num())
1974 			{
1975 				sc->Error("Stop before first state");
1976 				continue;
1977 			}
1978 			if (LastState)
1979 			{
1980 				LastState->NextState = NULL;
1981 			}
1982 			for (int i = NewLabelsStart; i < Class->StateLabelDefs.Num(); i++)
1983 			{
1984 				Class->StateLabelDefs[i].State = NULL;
1985 			}
1986 			NewLabelsStart = Class->StateLabelDefs.Num();
1987 			PrevState = NULL;
1988 			continue;
1989 		}
1990 
1991 		//	Wait command.
1992 		if (!TmpName.ICmp("Wait") || !TmpName.ICmp("Fail"))
1993 		{
1994 			if (!LastState)
1995 			{
1996 				sc->Error(va("%s before first state", *TmpName));
1997 				continue;
1998 			}
1999 			LastState->NextState = LastState;
2000 			PrevState = NULL;
2001 			continue;
2002 		}
2003 
2004 		//	Loop command.
2005 		if (!TmpName.ICmp("Loop"))
2006 		{
2007 			if (!LastState)
2008 			{
2009 				sc->Error("Loop before first state");
2010 				continue;
2011 			}
2012 			LastState->NextState = LoopStart;
2013 			PrevState = NULL;
2014 			continue;
2015 		}
2016 
2017 		//	Check for label.
2018 		if (sc->Check(":"))
2019 		{
2020 			LastState = NULL;
2021 			VStateLabelDef& Lbl = Class->StateLabelDefs.Alloc();
2022 			Lbl.Loc = TmpLoc;
2023 			Lbl.Name = TmpName;
2024 			continue;
2025 		}
2026 
2027 		VState* State = new VState(va("S_%d", States.Num()), Class, TmpLoc);
2028 		States.Append(State);
2029 
2030 		//	Sprite name
2031 		if (TmpName.Length() != 4)
2032 		{
2033 			sc->Error("Invalid sprite name");
2034 		}
2035 		State->SpriteName = *TmpName.ToLower();
2036 
2037 		//  Frame
2038 		sc->ExpectString();
2039 		char FChar = VStr::ToUpper(sc->String[0]);
2040 		if (FChar < 'A' || FChar > ']')
2041 		{
2042 			sc->Error("Frames must be A-Z, [, \\ or ]");
2043 		}
2044 		State->Frame = FChar - 'A';
2045 		VStr FramesString = sc->String;
2046 
2047 		//  Tics
2048 		sc->ExpectNumberWithSign();
2049 		if (sc->Number < 0)
2050 		{
2051 			State->Time = sc->Number;
2052 		}
2053 		else
2054 		{
2055 			State->Time = float(sc->Number) / 35.0;
2056 		}
2057 
2058 		bool NeedsUnget = true;
2059 		while (sc->GetString() && !sc->Crossed)
2060 		{
2061 			//	Check for bright parameter.
2062 			if (!sc->String.ICmp("Bright"))
2063 			{
2064 				State->Frame |= VState::FF_FULLBRIGHT;
2065 				continue;
2066 			}
2067 
2068 			//	Check for offsets.
2069 			if (!sc->String.ICmp("Offset"))
2070 			{
2071 				sc->Expect("(");
2072 				sc->ExpectNumberWithSign();
2073 				State->Misc1 = sc->Number;
2074 				sc->Expect(",");
2075 				sc->ExpectNumberWithSign();
2076 				State->Misc2 = sc->Number;
2077 				sc->Expect(")");
2078 				continue;
2079 			}
2080 
2081 			//	Get function name and parse arguments.
2082 			VStr FuncName = sc->String;
2083 			VStr FuncNameLower = sc->String.ToLower();
2084 			VExpression* Args[VMethod::MAX_PARAMS + 1];
2085 			int NumArgs = 0;
2086 			if (sc->Check("("))
2087 			{
2088 				if (!sc->Check(")"))
2089 				{
2090 					do
2091 					{
2092 						Args[NumArgs] = ParseExpressionPriority13(sc);
2093 						if (NumArgs == VMethod::MAX_PARAMS)
2094 							ParseError(sc->GetLoc(), "Too many arguments");
2095 						else
2096 							NumArgs++;
2097 					} while (sc->Check(","));
2098 					sc->Expect(")");
2099 				}
2100 			}
2101 
2102 			//	Find the state action method. First check action specials, then
2103 			// state actions.
2104 			VMethod* Func = NULL;
2105 			for (int i = 0; i < LineSpecialInfos.Num(); i++)
2106 			{
2107 				if (LineSpecialInfos[i].Name == FuncNameLower)
2108 				{
2109 					Func = Class->FindMethodChecked("A_ExecActionSpecial");
2110 					if (NumArgs > 5)
2111 					{
2112 						sc->Error("Too many arguments");
2113 					}
2114 					else
2115 					{
2116 						//	Add missing arguments.
2117 						while (NumArgs < 5)
2118 						{
2119 							Args[NumArgs] = new VIntLiteral(0, sc->GetLoc());
2120 							NumArgs++;
2121 						}
2122 						//	Add action special number argument.
2123 						Args[5] = new VIntLiteral(LineSpecialInfos[i].Number,
2124 							sc->GetLoc());
2125 						NumArgs++;
2126 					}
2127 					break;
2128 				}
2129 			}
2130 			if (!Func)
2131 			{
2132 				VDecorateStateAction* Act = Class->FindDecorateStateAction(
2133 					*FuncNameLower);
2134 				Func = Act ? Act->Method : NULL;
2135 			}
2136 			if (!Func)
2137 			{
2138 				GCon->Logf("Unknown state action %s in %s", *FuncName, Class->GetName());
2139 			}
2140 			else if (Func->NumParams || NumArgs)
2141 			{
2142 				VInvocation* Expr = new VInvocation(NULL, Func, NULL,
2143 					false, false, sc->GetLoc(), NumArgs, Args);
2144 				Expr->CallerState = State;
2145 				Expr->MultiFrameState = FramesString.Length() > 1;
2146 				VExpressionStatement* Stmt = new VExpressionStatement(Expr);
2147 				VMethod* M = new VMethod(NAME_None, Class, sc->GetLoc());
2148 				M->Flags = FUNC_Final;
2149 				M->ReturnType = TYPE_Void;
2150 				M->Statement = Stmt;
2151 				M->ParamsSize = 1;
2152 				Class->AddMethod(M);
2153 				State->Function = M;
2154 			}
2155 			else
2156 			{
2157 				State->Function = Func;
2158 			}
2159 
2160 			//	If state function is not assigned, it means something is wrong.
2161 			// In that case we need to free argument expressions.
2162 			if (!State->Function)
2163 			{
2164 				for (int i = 0; i < NumArgs; i++)
2165 				{
2166 					if (Args[i])
2167 					{
2168 						delete Args[i];
2169 						Args[i] = NULL;
2170 					}
2171 				}
2172 			}
2173 			NeedsUnget = false;
2174 			break;
2175 		}
2176 		if (NeedsUnget)
2177 		{
2178 			sc->UnGet();
2179 		}
2180 
2181 		//	Link previous state.
2182 		if (PrevState)
2183 		{
2184 			PrevState->NextState = State;
2185 		}
2186 
2187 		//	Assign state to the labels.
2188 		for (int i = NewLabelsStart; i < Class->StateLabelDefs.Num(); i++)
2189 		{
2190 			Class->StateLabelDefs[i].State = State;
2191 			LoopStart = State;
2192 		}
2193 		NewLabelsStart = Class->StateLabelDefs.Num();
2194 		PrevState = State;
2195 		LastState = State;
2196 
2197 		for (size_t i = 1; i < FramesString.Length(); i++)
2198 		{
2199 			char FChar = VStr::ToUpper(FramesString[i]);
2200 			if (FChar < 'A' || FChar > ']')
2201 			{
2202 				sc->Error("Frames must be A-Z, [, \\ or ]");
2203 			}
2204 
2205 			//	Create a new state.
2206 			VState* s2 = new VState(va("S_%d", States.Num()), Class,
2207 				sc->GetLoc());
2208 			States.Append(s2);
2209 			s2->SpriteName = State->SpriteName;
2210 			s2->Frame = (State->Frame & VState::FF_FULLBRIGHT) | (FChar - 'A');
2211 			s2->Time = State->Time;
2212 			s2->Misc1 = State->Misc1;
2213 			s2->Misc2 = State->Misc2;
2214 			s2->Function = State->Function;
2215 
2216 			//	Link previous state.
2217 			PrevState->NextState = s2;
2218 			PrevState = s2;
2219 			LastState = s2;
2220 		}
2221 	}
2222 	//	Re-enable escape sequences.
2223 	sc->SetEscape(true);
2224 	return true;
2225 	unguard;
2226 }
2227 
2228 //==========================================================================
2229 //
2230 //	ParseParentState
2231 //
2232 //	This is for compatibility with old WADs.
2233 //
2234 //==========================================================================
2235 
ParseParentState(VScriptParser * sc,VClass * Class,const char * LblName)2236 static void ParseParentState(VScriptParser* sc, VClass* Class,
2237 	const char* LblName)
2238 {
2239 	guard(ParseParentState);
2240 	TLocation TmpLoc = sc->GetLoc();
2241 	VState* State;
2242 	//	If there's a string token on next line, it gets eaten. Is this a bug?
2243 	if (sc->GetString() && !sc->Crossed)
2244 	{
2245 		sc->UnGet();
2246 		if (sc->Check("0"))
2247 		{
2248 			State = NULL;
2249 		}
2250 		else if (sc->Check("parent"))
2251 		{
2252 			//	Find state in parent class.
2253 			sc->ExpectString();
2254 			VStateLabel* SLbl = Class->ParentClass->FindStateLabel(*sc->String);
2255 			State = SLbl ? SLbl->State : NULL;
2256 
2257 			//	Check for offset.
2258 			int Offs = 0;
2259 			if (sc->Check("+"))
2260 			{
2261 				sc->ExpectNumber();
2262 				Offs = sc->Number;
2263 			}
2264 
2265 			if (!State && Offs)
2266 			{
2267 				sc->Error(va("Attempt to get invalid state from actor %s",
2268 					Class->GetSuperClass()->GetName()));
2269 			}
2270 			else if (State)
2271 			{
2272 				State = State->GetPlus(Offs, true);
2273 			}
2274 		}
2275 		else
2276 		{
2277 			sc->Error("Invalid state assignment");
2278 		}
2279 	}
2280 	else
2281 	{
2282 		State = NULL;
2283 	}
2284 
2285 	VStateLabelDef& Lbl = Class->StateLabelDefs.Alloc();
2286 	Lbl.Loc = TmpLoc;
2287 	Lbl.Name = LblName;
2288 	Lbl.State = State;
2289 	unguard;
2290 }
2291 
2292 //==========================================================================
2293 //
2294 //	ParseActor
2295 //
2296 //==========================================================================
2297 
ParseActor(VScriptParser * sc,TArray<VClassFixup> & ClassFixups)2298 static void ParseActor(VScriptParser* sc, TArray<VClassFixup>& ClassFixups)
2299 {
2300 	guard(ParseActor);
2301 	//	Parse actor name. In order to allow dots in actor names, this is done
2302 	// in non-C mode, so we have to do a little bit more complex parsing.
2303 	sc->ExpectString();
2304 	VStr NameStr;
2305 	VStr ParentStr;
2306 	int ColonPos = sc->String.IndexOf(':');
2307 	if (ColonPos >= 0)
2308 	{
2309 		//	There's a colon inside, so split up the string.
2310 		NameStr = VStr(sc->String, 0, ColonPos);
2311 		ParentStr = VStr(sc->String, ColonPos + 1, sc->String.Length() -
2312 			ColonPos - 1);
2313 	}
2314 	else
2315 	{
2316 		NameStr = sc->String;
2317 	}
2318 
2319 	if (GArgs.CheckParm("-debug_decorate"))
2320 	{
2321 		sc->Message(va("Parsing class %s", *NameStr));
2322 	}
2323 
2324 	VClass* DupCheck = VClass::FindClassLowerCase(*NameStr.ToLower());
2325 	if (DupCheck && DupCheck->MemberType == MEMBER_Class)
2326 	{
2327 		sc->Message(va("Warning: Redeclared class %s", *NameStr));
2328 	}
2329 
2330 	if (ColonPos < 0)
2331 	{
2332 		//	There's no colon, check if next string starts with it.
2333 		sc->ExpectString();
2334 		if (sc->String[0] == ':')
2335 		{
2336 			ColonPos = 0;
2337 			ParentStr = VStr(sc->String, 1, sc->String.Length() - 1);
2338 		}
2339 		else
2340 		{
2341 			sc->UnGet();
2342 		}
2343 	}
2344 
2345 	//	If we got colon but no parent class name, then get it.
2346 	if (ColonPos >= 0 && ParentStr.IsEmpty())
2347 	{
2348 		sc->ExpectString();
2349 		ParentStr = sc->String;
2350 	}
2351 
2352 	VClass* ParentClass = ActorClass;
2353 	if (ParentStr.IsNotEmpty())
2354 	{
2355 		ParentClass = VClass::FindClassLowerCase(*ParentStr.ToLower());
2356 		if (!ParentClass || ParentClass->MemberType != MEMBER_Class)
2357 		{
2358 			sc->Error(va("Parent class %s not found", *ParentStr));
2359 		}
2360 		if (!ParentClass->IsChildOf(ActorClass))
2361 		{
2362 			sc->Error(va("Parent class %s is not an actor class", *ParentStr));
2363 		}
2364 	}
2365 
2366 	VClass* Class = ParentClass->CreateDerivedClass(*NameStr, DecPkg,
2367 		sc->GetLoc());
2368 	DecPkg->ParsedClasses.Append(Class);
2369 
2370 	if (ParentClass)
2371 	{
2372 		//	Copy class fixups of the parent class.
2373 		for (int i = 0; i < ClassFixups.Num(); i++)
2374 		{
2375 			VClassFixup& CF = ClassFixups[i];
2376 			if (CF.Class == ParentClass)
2377 			{
2378 				VClassFixup& NewCF = ClassFixups.Alloc();
2379 				NewCF.Offset = CF.Offset;
2380 				NewCF.Name = CF.Name;
2381 				NewCF.ReqParent = CF.ReqParent;
2382 				NewCF.Class = Class;
2383 			}
2384 		}
2385 	}
2386 
2387 	VClass* ReplaceeClass = NULL;
2388 	if (sc->Check("replaces"))
2389 	{
2390 		sc->ExpectString();
2391 		ReplaceeClass = VClass::FindClassLowerCase(*sc->String.ToLower());
2392 		if (!ReplaceeClass || ReplaceeClass->MemberType != MEMBER_Class)
2393 		{
2394 			sc->Error(va("Replaced class %s not found", *sc->String));
2395 		}
2396 		if (!ReplaceeClass->IsChildOf(ActorClass))
2397 		{
2398 			sc->Error(va("Replaced class %s is not an actor class", *sc->String));
2399 		}
2400 	}
2401 
2402 	//	Time to switch to the C mode.
2403 	sc->SetCMode(true);
2404 
2405 	int GameFilter = 0;
2406 	int DoomEdNum = -1;
2407 	int SpawnNum = -1;
2408 	TArray<VState*> States;
2409 	bool DropItemsDefined = false;
2410 	VObject* DefObj = (VObject*)Class->Defaults;
2411 
2412 	if (sc->CheckNumber())
2413 	{
2414 		if (sc->Number < -1 || sc->Number > 32767)
2415 		{
2416 			sc->Error("DoomEdNum is out of range [-1, 32767]");
2417 		}
2418 		DoomEdNum = sc->Number;
2419 	}
2420 
2421 	sc->Expect("{");
2422 	while (!sc->Check("}"))
2423 	{
2424 		if (sc->Check("+"))
2425 		{
2426 			if (!ParseFlag(sc, Class, true, ClassFixups))
2427 			{
2428 				return;
2429 			}
2430 			continue;
2431 		}
2432 		if (sc->Check("-"))
2433 		{
2434 			if (!ParseFlag(sc, Class, false, ClassFixups))
2435 			{
2436 				return;
2437 			}
2438 			continue;
2439 		}
2440 
2441 		if (sc->Check("action"))
2442 		{
2443 			ParseAction(sc, Class);
2444 			continue;
2445 		}
2446 
2447 		//	Get full name of the property.
2448 		sc->ExpectIdentifier();
2449 		VStr Prop = sc->String;
2450 		while (sc->Check("."))
2451 		{
2452 			sc->ExpectIdentifier();
2453 			Prop += ".";
2454 			Prop += sc->String;
2455 		}
2456 		VName PropName = *Prop.ToLower();
2457 
2458 		bool FoundProp = false;
2459 		for (int j = 0; j < FlagList.Num() && !FoundProp; j++)
2460 		{
2461 			VFlagList& ClassDef = FlagList[j];
2462 			if (!Class->IsChildOf(ClassDef.Class))
2463 			{
2464 				continue;
2465 			}
2466 			for (int i = ClassDef.PropsHash[GetTypeHash(PropName) &
2467 				(PROPS_HASH_SIZE - 1)]; i != -1; i = ClassDef.Props[i].HashNext)
2468 			{
2469 				VPropDef& P = FlagList[j].Props[i];
2470 				if (PropName != P.Name)
2471 				{
2472 					continue;
2473 				}
2474 				switch (P.Type)
2475 				{
2476 				case PROP_Int:
2477 					sc->ExpectNumberWithSign();
2478 					P.Field->SetInt(DefObj, sc->Number);
2479 					break;
2480 				case PROP_IntConst:
2481 					P.Field->SetInt(DefObj, P.IConst);
2482 					break;
2483 				case PROP_IntUnsupported:
2484 					//FIXME
2485 					sc->CheckNumberWithSign();
2486 					GCon->Logf("Property %s in %s is not yet supported", *Prop, Class->GetName());
2487 					break;
2488 				case PROP_BitIndex:
2489 					sc->ExpectNumber();
2490 					P.Field->SetInt(DefObj, 1 << (sc->Number - 1));
2491 					break;
2492 				case PROP_Float:
2493 					sc->ExpectFloatWithSign();
2494 					P.Field->SetFloat(DefObj, sc->Float);
2495 					break;
2496 				case PROP_Speed:
2497 					sc->ExpectFloatWithSign();
2498 					P.Field->SetFloat(DefObj, sc->Float * 35.0);
2499 					break;
2500 				case PROP_Tics:
2501 					sc->ExpectNumberWithSign();
2502 					P.Field->SetFloat(DefObj, sc->Number / 35.0);
2503 					break;
2504 				case PROP_TicsSecs:
2505 					sc->ExpectNumberWithSign();
2506 					P.Field->SetFloat(DefObj, sc->Number >= 0 ?
2507 						sc->Number / 35.0 : sc->Number);
2508 					break;
2509 				case PROP_Percent:
2510 					sc->ExpectFloat();
2511 					P.Field->SetFloat(DefObj, MID(0, sc->Float, 100) / 100.0);
2512 					break;
2513 				case PROP_FloatClamped:
2514 					sc->ExpectFloatWithSign();
2515 					P.Field->SetFloat(DefObj, MID(P.FMin, sc->Float, P.FMax));
2516 					break;
2517 				case PROP_FloatClamped2:
2518 					sc->ExpectFloatWithSign();
2519 					P.Field->SetFloat(DefObj, MID(P.FMin, sc->Float, P.FMax));
2520 					P.Field2->SetFloat(DefObj, MID(P.FMin, sc->Float, P.FMax));
2521 					break;
2522 				case PROP_FloatOpt2:
2523 					sc->ExpectFloat();
2524 					P.Field->SetFloat(DefObj, sc->Float);
2525 					P.Field2->SetFloat(DefObj, sc->Float);
2526 					if (sc->Check(","))
2527 					{
2528 						sc->ExpectFloat();
2529 						P.Field2->SetFloat(DefObj, sc->Float);
2530 					}
2531 					else if (sc->CheckFloat())
2532 					{
2533 						P.Field2->SetFloat(DefObj, sc->Float);
2534 					}
2535 					break;
2536 				case PROP_Name:
2537 					sc->ExpectString();
2538 					P.Field->SetName(DefObj, *sc->String);
2539 					break;
2540 				case PROP_NameLower:
2541 					sc->ExpectString();
2542 					P.Field->SetName(DefObj, *sc->String.ToLower());
2543 					break;
2544 				case PROP_Str:
2545 					sc->ExpectString();
2546 					P.Field->SetStr(DefObj, sc->String);
2547 					break;
2548 				case PROP_StrUnsupported:
2549 					//FIXME
2550 					sc->ExpectString();
2551 					GCon->Logf("Property %s in %s is not yet supported", *Prop, Class->GetName());
2552 					break;
2553 				case PROP_Class:
2554 					sc->ExpectString();
2555 					AddClassFixup(Class, P.Field, P.CPrefix + sc->String, ClassFixups);
2556 					break;
2557 				case PROP_Power_Class:
2558 					// This is a very inconvenient shit!
2559 					// but ZDoom had to prepend "power" to the name...
2560 					sc->ExpectString();
2561 					AddClassFixup(Class, P.Field, sc->String.StartsWith("Power") || sc->String.StartsWith("power") ?
2562 							sc->String : P.CPrefix + sc->String, ClassFixups);
2563 					break;
2564 				case PROP_BoolConst:
2565 					P.Field->SetBool(DefObj, P.IConst);
2566 					break;
2567 				case PROP_State:
2568 					ParseParentState(sc, Class, *P.PropName);
2569 					break;
2570 				case PROP_Game:
2571 					if (sc->Check("Doom"))
2572 					{
2573 						GameFilter |= GAME_Doom;
2574 					}
2575 					else if (sc->Check("Heretic"))
2576 					{
2577 						GameFilter |= GAME_Heretic;
2578 					}
2579 					else if (sc->Check("Hexen"))
2580 					{
2581 						GameFilter |= GAME_Hexen;
2582 					}
2583 					else if (sc->Check("Strife"))
2584 					{
2585 						GameFilter |= GAME_Strife;
2586 					}
2587 					else if (sc->Check("Raven"))
2588 					{
2589 						GameFilter |= GAME_Raven;
2590 					}
2591 					else if (sc->Check("Any"))
2592 					{
2593 						GameFilter |= GAME_Any;
2594 					}
2595 					else if (GameFilter)
2596 					{
2597 						sc->Error("Unknown game filter");
2598 					}
2599 					break;
2600 				case PROP_SpawnId:
2601 					sc->ExpectNumber();
2602 					SpawnNum = sc->Number;
2603 					break;
2604 				case PROP_ConversationId:
2605 					sc->ExpectNumber();
2606 					P.Field->SetInt(DefObj, sc->Number);
2607 					if (sc->Check(","))
2608 					{
2609 						sc->ExpectNumberWithSign();
2610 						sc->Expect(",");
2611 						sc->ExpectNumberWithSign();
2612 					}
2613 					break;
2614 				case PROP_PainChance:
2615 					if (sc->CheckNumber())
2616 					{
2617 						P.Field->SetFloat(DefObj, float(sc->Number) / 256.0);
2618 					}
2619 					else
2620 					{
2621 						sc->ExpectString();
2622 						VName DamageType = sc->String.ICmp("Normal") ? NAME_None :
2623 							VName(*sc->String);
2624 						sc->Expect(",");
2625 						sc->ExpectNumber();
2626 
2627 						//	Check pain chances array for replacements.
2628 						TArray<VPainChanceInfo>& PainChances = GetClassPainChances(Class);
2629 						VPainChanceInfo* PC = NULL;
2630 						for (int i = 0; i < PainChances.Num(); i++)
2631 						{
2632 							if (PainChances[i].DamageType == DamageType)
2633 							{
2634 								PC = &PainChances[i];
2635 								break;
2636 							}
2637 						}
2638 						if (!PC)
2639 						{
2640 							PC = &PainChances.Alloc();
2641 							PC->DamageType = DamageType;
2642 						}
2643 						PC->Chance = float(sc->Number) / 256.0;
2644 					}
2645 					break;
2646 				case PROP_DamageFactor:
2647 				{
2648 					VName DamageType = NAME_None;
2649 					// Check if we only have a number instead of a string, since
2650 					// there are some custom WAD files that don't specify a DamageType,
2651 					// but specify a DamageFactor
2652 					if (!sc->CheckFloat())
2653 					{
2654 						sc->ExpectString();
2655 						VName DamageType = !sc->String.ICmp("Normal") ? NAME_None :
2656 							VName(*sc->String);
2657 						sc->Expect(",");
2658 						sc->ExpectFloat();
2659 					}
2660 
2661 					//	Check damage factors array for replacements.
2662 					TArray<VDamageFactor> DamageFactors = GetClassDamageFactors(Class);
2663 					VDamageFactor* DF = NULL;
2664 					for (int i = 0; i < DamageFactors.Num(); i++)
2665 					{
2666 						if (DamageFactors[i].DamageType == DamageType)
2667 						{
2668 							DF = &DamageFactors[i];
2669 							break;
2670 						}
2671 					}
2672 					if (!DF)
2673 					{
2674 						DF = &DamageFactors.Alloc();
2675 						DF->DamageType = DamageType;
2676 					}
2677 					DF->Factor = sc->Float;
2678 					break;
2679 				}
2680 				case PROP_MissileDamage:
2681 					if (sc->Check("("))
2682 					{
2683 						VExpression* Expr = ParseExpression(sc);
2684 						if (!Expr)
2685 						{
2686 							ParseError(sc->GetLoc(), "Damage expression expected");
2687 						}
2688 						else
2689 						{
2690 							VMethod* M = new VMethod("GetMissileDamage", Class, sc->GetLoc());
2691 							M->ReturnTypeExpr = new VTypeExpr(TYPE_Int, sc->GetLoc());
2692 							M->ReturnType = TYPE_Int;
2693 							M->NumParams = 2;
2694 							M->Params[0].Name = "Mask";
2695 							M->Params[0].Loc = sc->GetLoc();
2696 							M->Params[0].TypeExpr = new VTypeExpr(TYPE_Int, sc->GetLoc());
2697 							M->Params[1].Name = "Add";
2698 							M->Params[1].Loc = sc->GetLoc();
2699 							M->Params[1].TypeExpr = new VTypeExpr(TYPE_Int, sc->GetLoc());
2700 							M->Statement = new VReturn(Expr, sc->GetLoc());
2701 							Class->AddMethod(M);
2702 							M->Define();
2703 						}
2704 						sc->Expect(")");
2705 					}
2706 					else
2707 					{
2708 						sc->ExpectNumber();
2709 						P.Field->SetInt(DefObj, sc->Number);
2710 					}
2711 					break;
2712 				case PROP_VSpeed:
2713 				{
2714 					sc->ExpectFloatWithSign();
2715 					TVec Val = P.Field->GetVec(DefObj);
2716 					Val.z = sc->Float * 35.0;
2717 					P.Field->SetVec(DefObj, Val);
2718 					break;
2719 				}
2720 				case PROP_RenderStyle:
2721 				{
2722 					int RenderStyle = 0;
2723 					if (sc->Check("None"))
2724 					{
2725 						RenderStyle = STYLE_None;
2726 					}
2727 					else if (sc->Check("Normal"))
2728 					{
2729 						RenderStyle = STYLE_Normal;
2730 					}
2731 					else if (sc->Check("Fuzzy"))
2732 					{
2733 						RenderStyle = STYLE_Fuzzy;
2734 					}
2735 					else if (sc->Check("SoulTrans"))
2736 					{
2737 						RenderStyle = STYLE_SoulTrans;
2738 					}
2739 					else if (sc->Check("OptFuzzy"))
2740 					{
2741 						RenderStyle = STYLE_OptFuzzy;
2742 					}
2743 					else if (sc->Check("Translucent"))
2744 					{
2745 						RenderStyle = STYLE_Translucent;
2746 					}
2747 					else if (sc->Check("Add"))
2748 					{
2749 						RenderStyle = STYLE_Add;
2750 					}
2751 					else if (sc->Check("Stencil"))
2752 					{
2753 						//FIXME
2754 						GCon->Logf("Render style Stencil in %s is not yet supported", Class->GetName());
2755 					}
2756 					else if (sc->Check("Shaded"))
2757 					{
2758 						//FIXME -- This is an aproximated style... but it's not the desired one!
2759 						RenderStyle = STYLE_Fuzzy;
2760 					}
2761 					else
2762 					{
2763 						sc->Error("Bad render style");
2764 					}
2765 					P.Field->SetByte(DefObj, RenderStyle);
2766 					break;
2767 				}
2768 				case PROP_Translation:
2769 					P.Field->SetInt(DefObj, R_ParseDecorateTranslation(sc,
2770 						GameFilter & GAME_Strife ? 7 : 3));
2771 					break;
2772 				case PROP_BloodColour:
2773 				{
2774 					vuint32 Col;
2775 					if (sc->CheckNumber())
2776 					{
2777 						int r = MID(0, sc->Number, 255);
2778 						sc->Check(",");
2779 						sc->ExpectNumber();
2780 						int g = MID(0, sc->Number, 255);
2781 						sc->Check(",");
2782 						sc->ExpectNumber();
2783 						int b = MID(0, sc->Number, 255);
2784 						Col = 0xff000000 | (r << 16) | (g << 8) | b;
2785 					}
2786 					else
2787 					{
2788 						sc->ExpectString();
2789 						Col = M_ParseColour(sc->String);
2790 					}
2791 					P.Field->SetInt(DefObj, Col);
2792 					P.Field2->SetInt(DefObj, R_GetBloodTranslation(Col));
2793 					break;
2794 				}
2795 				case PROP_BloodType:
2796 					sc->ExpectString();
2797 					AddClassFixup(Class, P.Field, sc->String, ClassFixups);
2798 					if (sc->Check(","))
2799 					{
2800 						sc->ExpectString();
2801 					}
2802 					AddClassFixup(Class, P.Field2, sc->String, ClassFixups);
2803 					if (sc->Check(","))
2804 					{
2805 						sc->ExpectString();
2806 					}
2807 					AddClassFixup(Class, "AxeBloodType", sc->String, ClassFixups);
2808 					break;
2809 				case PROP_StencilColour:
2810 					//FIXME
2811 					if (sc->CheckNumber())
2812 					{
2813 						sc->ExpectNumber();
2814 						sc->ExpectNumber();
2815 					}
2816 					else
2817 					{
2818 						sc->ExpectString();
2819 					}
2820 					GCon->Logf("Property StencilColor in %s is not yet supported", Class->GetName());
2821 					break;
2822 				case PROP_Monster:
2823 					SetClassFieldBool(Class, "bShootable", true);
2824 					SetClassFieldBool(Class, "bCountKill", true);
2825 					SetClassFieldBool(Class, "bSolid", true);
2826 					SetClassFieldBool(Class, "bActivatePushWall", true);
2827 					SetClassFieldBool(Class, "bActivateMCross", true);
2828 					SetClassFieldBool(Class, "bPassMobj", true);
2829 					SetClassFieldBool(Class, "bMonster", true);
2830 					SetClassFieldBool(Class, "bCanUseWalls", true);
2831 					break;
2832 				case PROP_Projectile:
2833 					SetClassFieldBool(Class, "bNoBlockmap", true);
2834 					SetClassFieldBool(Class, "bNoGravity", true);
2835 					SetClassFieldBool(Class, "bDropOff", true);
2836 					SetClassFieldBool(Class, "bMissile", true);
2837 					SetClassFieldBool(Class, "bActivateImpact", true);
2838 					SetClassFieldBool(Class, "bActivatePCross", true);
2839 					SetClassFieldBool(Class, "bNoTeleport", true);
2840 					if (GGameInfo->Flags & VGameInfo::GIF_DefaultBloodSplatter)
2841 					{
2842 						SetClassFieldBool(Class, "bBloodSplatter", true);
2843 					}
2844 					break;
2845 				case PROP_BounceType:
2846 					if (sc->Check("None"))
2847 					{
2848 						SetClassFieldByte(Class, "BounceType", BOUNCE_None);
2849 					}
2850 					else if (sc->Check("Doom"))
2851 					{
2852 						SetClassFieldByte(Class, "BounceType", BOUNCE_Doom);
2853 						SetClassFieldBool(Class, "bBounceWalls", true);
2854 						SetClassFieldBool(Class, "bBounceFloors", true);
2855 						SetClassFieldBool(Class, "bBounceCeilings", true);
2856 						SetClassFieldBool(Class, "bBounceOnActors", true);
2857 						SetClassFieldBool(Class, "bBounceAutoOff", true);
2858 					}
2859 					else if (sc->Check("Heretic"))
2860 					{
2861 						SetClassFieldByte(Class, "BounceType", BOUNCE_Heretic);
2862 						SetClassFieldBool(Class, "bBounceFloors", true);
2863 						SetClassFieldBool(Class, "bBounceCeilings", true);
2864 					}
2865 					else if (sc->Check("Hexen"))
2866 					{
2867 						SetClassFieldByte(Class, "BounceType", BOUNCE_Hexen);
2868 						SetClassFieldBool(Class, "bBounceWalls", true);
2869 						SetClassFieldBool(Class, "bBounceFloors", true);
2870 						SetClassFieldBool(Class, "bBounceCeilings", true);
2871 						SetClassFieldBool(Class, "bBounceOnActors", true);
2872 					}
2873 					else if (sc->Check("DoomCompat"))
2874 					{
2875 						SetClassFieldByte(Class, "BounceType", BOUNCE_Doom);
2876 					}
2877 					else if (sc->Check("HereticCompat"))
2878 					{
2879 						SetClassFieldByte(Class, "BounceType", BOUNCE_Heretic);
2880 					}
2881 					else if (sc->Check("HexenCompat"))
2882 					{
2883 						SetClassFieldByte(Class, "BounceType", BOUNCE_Hexen);
2884 					}
2885 					else if (sc->Check("Grenade"))
2886 					{
2887 						// Bounces on walls and flats like ZDoom bounce.
2888 						SetClassFieldByte(Class, "BounceType", BOUNCE_Doom);
2889 						SetClassFieldBool(Class, "bBounceOnActors", false);
2890 					}
2891 					else if (sc->Check("Classic"))
2892 					{
2893 						// Bounces on flats only, but does not die when bouncing.
2894 						SetClassFieldByte(Class, "BounceType", BOUNCE_Heretic);
2895 						SetClassFieldBool(Class, "bMBFBounce", true);
2896 					}
2897 					break;
2898 				case PROP_ClearFlags:
2899 					for (int j = 0; j < FlagList.Num(); j++)
2900 					{
2901 						if (FlagList[j].Class != ActorClass)
2902 						{
2903 							continue;
2904 						}
2905 						for (int i = 0; i < FlagList[j].Flags.Num(); i++)
2906 						{
2907 							VFlagDef& F = FlagList[j].Flags[i];
2908 							switch (F.Type)
2909 							{
2910 							case FLAG_Bool:
2911 								F.Field->SetBool(DefObj, false);
2912 								break;
2913 							}
2914 						}
2915 					}
2916 					SetClassFieldByte(Class, "BounceType", BOUNCE_None);
2917 					SetClassFieldBool(Class, "bColideWithThings", true);
2918 					SetClassFieldBool(Class, "bColideWithWorld", true);
2919 					SetClassFieldBool(Class, "bPickUp", false);
2920 					break;
2921 				case PROP_DropItem:
2922 				{
2923 					if (!DropItemsDefined)
2924 					{
2925 						GetClassDropItems(Class).Clear();
2926 						DropItemsDefined = true;
2927 					}
2928 					sc->ExpectString();
2929 					VDropItemInfo DI;
2930 					DI.TypeName = *sc->String.ToLower();
2931 					DI.Type = NULL;
2932 					DI.Amount = 0;
2933 					DI.Chance = 1.0;
2934 					bool HaveChance = false;
2935 					if (sc->Check(","))
2936 					{
2937 						sc->ExpectNumber();
2938 						HaveChance = true;
2939 					}
2940 					else
2941 					{
2942 						HaveChance = sc->CheckNumber();
2943 					}
2944 					if (HaveChance)
2945 					{
2946 						DI.Chance = float(sc->Number) / 255.0;
2947 						if (sc->Check(","))
2948 						{
2949 							sc->ExpectNumber();
2950 							DI.Amount = sc->Number;
2951 						}
2952 						else if (sc->CheckNumber())
2953 						{
2954 							DI.Amount = sc->Number;
2955 						}
2956 					}
2957 					GetClassDropItems(Class).Insert(0, DI);
2958 					break;
2959 				}
2960 				case PROP_States:
2961 					if (!ParseStates(sc, Class, States))
2962 					{
2963 						return;
2964 					}
2965 					break;
2966 				case PROP_SkipSuper:
2967 				{
2968 					//	Preserve items that should not be copied
2969 					TArray<VDamageFactor> DamageFactors = GetClassDamageFactors(Class);
2970 					TArray<VPainChanceInfo> PainChances = GetClassPainChances(Class);
2971 					//	Copy default properties.
2972 					ActorClass->CopyObject(ActorClass->Defaults, Class->Defaults);
2973 					//	Copy state labels
2974 					Class->StateLabels = ActorClass->StateLabels;
2975 					Class->ClassFlags |= CLASS_SkipSuperStateLabels;
2976 					//	Drop items are reset back to the list of the parent class
2977 					GetClassDropItems(Class) = GetClassDropItems(Class->ParentClass);
2978 					//	Restore items that should not be copied
2979 					GetClassDamageFactors(Class) = DamageFactors;
2980 					GetClassPainChances(Class) = PainChances;
2981 					break;
2982 				}
2983 				case PROP_Args:
2984 					for (int i = 0; i < 5; i++)
2985 					{
2986 						sc->ExpectNumber();
2987 						P.Field->SetInt(DefObj, sc->Number, i);
2988 						if (i < 4 && !sc->Check(","))
2989 						{
2990 							break;
2991 						}
2992 					}
2993 					P.Field2->SetBool(DefObj, true);
2994 					break;
2995 				case PROP_LowMessage:
2996 					sc->ExpectNumber();
2997 					P.Field->SetInt(DefObj, sc->Number);
2998 					sc->Expect(",");
2999 					sc->ExpectString();
3000 					P.Field2->SetStr(DefObj, sc->String);
3001 					break;
3002 				case PROP_PowerupColour:
3003 					if (sc->Check("InverseMap"))
3004 					{
3005 						P.Field->SetInt(DefObj, 0x00123456);
3006 					}
3007 					else if (sc->Check("GoldMap"))
3008 					{
3009 						P.Field->SetInt(DefObj, 0x00123457);
3010 					}
3011 					else if (sc->Check("RedMap"))
3012 					{
3013 						P.Field->SetInt(DefObj, 0x00123458);
3014 					}
3015 					else if (sc->Check("GreenMap"))
3016 					{
3017 						P.Field->SetInt(DefObj, 0x00123459);
3018 					}
3019 					else
3020 					{
3021 						int a, r, g, b;
3022 						if (sc->CheckNumber())
3023 						{
3024 							r = MID(0, sc->Number, 255);
3025 							sc->Check(",");
3026 							sc->ExpectNumber();
3027 							g = MID(0, sc->Number, 255);
3028 							sc->Check(",");
3029 							sc->ExpectNumber();
3030 							b = MID(0, sc->Number, 255);
3031 						}
3032 						else
3033 						{
3034 							vuint32 Col;
3035 							sc->ExpectString();
3036 							Col = M_ParseColour(sc->String);
3037 							r = (Col >> 16) & 0xff;
3038 							g = (Col >> 8) & 0xff;
3039 							b = Col & 0xff;
3040 						}
3041 						sc->Check(",");
3042 						sc->ExpectFloat();
3043 						a = MID(0, int(sc->Float * 255), 254);
3044 						if (a > 250)
3045 						{
3046 							a = 250;
3047 						}
3048 						P.Field->SetInt(DefObj, (r << 16) | (g << 8) | b | (a << 24));
3049 					}
3050 					break;
3051 				case PROP_ColourRange:
3052 					sc->ExpectNumber();
3053 					P.Field->SetInt(DefObj, sc->Number);
3054 					sc->Check(",");
3055 					sc->ExpectNumber();
3056 					P.Field2->SetInt(DefObj, sc->Number);
3057 					break;
3058 				case PROP_DamageScreenColour:
3059 				{
3060 					//	First number is ignored. Is it a bug?
3061 					int Col;
3062 					if (sc->CheckNumber())
3063 					{
3064 						sc->ExpectNumber();
3065 						int r = MID(sc->Number, 0, 255);
3066 						sc->Check(",");
3067 						sc->ExpectNumber();
3068 						int g = MID(sc->Number, 0, 255);
3069 						sc->Check(",");
3070 						sc->ExpectNumber();
3071 						int b = MID(sc->Number, 0, 255);
3072 						Col = 0xff000000 | (r << 16) | (g << 8) | b;
3073 					}
3074 					else
3075 					{
3076 						sc->ExpectString();
3077 						Col = M_ParseColour(sc->String);
3078 					}
3079 					P.Field->SetInt(DefObj, Col);
3080 					break;
3081 				}
3082 				case PROP_HexenArmor:
3083 					sc->ExpectFloat();
3084 					P.Field->SetFloat(DefObj, sc->Float, 0);
3085 					sc->Expect(",");
3086 					sc->ExpectFloat();
3087 					P.Field->SetFloat(DefObj, sc->Float, 1);
3088 					sc->Expect(",");
3089 					sc->ExpectFloat();
3090 					P.Field->SetFloat(DefObj, sc->Float, 2);
3091 					sc->Expect(",");
3092 					sc->ExpectFloat();
3093 					P.Field->SetFloat(DefObj, sc->Float, 3);
3094 					sc->Expect(",");
3095 					sc->ExpectFloat();
3096 					P.Field->SetFloat(DefObj, sc->Float, 4);
3097 					break;
3098 				case PROP_StartItem:
3099 				{
3100 					TArray<VDropItemInfo>& DropItems =
3101 						*(TArray<VDropItemInfo>*)P.Field->GetFieldPtr(DefObj);
3102 					if (!DropItemsDefined)
3103 					{
3104 						DropItems.Clear();
3105 						DropItemsDefined = true;
3106 					}
3107 					sc->ExpectString();
3108 					VDropItemInfo DI;
3109 					DI.TypeName = *sc->String.ToLower();
3110 					DI.Type = NULL;
3111 					DI.Amount = 0;
3112 					DI.Chance = 1.0;
3113 					if (sc->Check(","))
3114 					{
3115 						sc->ExpectNumber();
3116 						DI.Amount = sc->Number;
3117 					}
3118 					else if (sc->CheckNumber())
3119 					{
3120 						DI.Amount = sc->Number;
3121 					}
3122 					DropItems.Insert(0, DI);
3123 					break;
3124 				}
3125 				case PROP_MorphStyle:
3126 					if (sc->CheckNumber())
3127 					{
3128 						P.Field->SetInt(DefObj, sc->Number);
3129 					}
3130 					else
3131 					{
3132 						bool HaveParen = sc->Check("(");
3133 						int Val = 0;
3134 						do
3135 						{
3136 							if (sc->Check("MRF_ADDSTAMINA"))
3137 							{
3138 								Val |= 1;
3139 							}
3140 							else if (sc->Check("MRF_FULLHEALTH"))
3141 							{
3142 								Val |= 2;
3143 							}
3144 							else if (sc->Check("MRF_UNDOBYTOMEOFPOWER"))
3145 							{
3146 								Val |= 4;
3147 							}
3148 							else if (sc->Check("MRF_UNDOBYCHAOSDEVICE"))
3149 							{
3150 								Val |= 8;
3151 							}
3152 							else if (sc->Check("MRF_FAILNOTELEFRAG"))
3153 							{
3154 								Val |= 16;
3155 							}
3156 							else if (sc->Check("MRF_FAILNOLAUGH"))
3157 							{
3158 								Val |= 32;
3159 							}
3160 							else if (sc->Check("MRF_WHENINVULNERABLE"))
3161 							{
3162 								Val |= 64;
3163 							}
3164 							else if (sc->Check("MRF_LOSEACTUALWEAPON"))
3165 							{
3166 								Val |= 128;
3167 							}
3168 							else if (sc->Check("MRF_NEWTIDBEHAVIOUR"))
3169 							{
3170 								Val |= 256;
3171 							}
3172 							else if (sc->Check("MRF_UNDOBYDEATH"))
3173 							{
3174 								Val |= 512;
3175 							}
3176 							else if (sc->Check("MRF_UNDOBYDEATHFORCED"))
3177 							{
3178 								Val |= 1024;
3179 							}
3180 							else if (sc->Check("MRF_UNDOBYDEATHSAVES"))
3181 							{
3182 								Val |= 2048;
3183 							}
3184 							else
3185 							{
3186 								sc->Error("Bad morph style");
3187 							}
3188 						}
3189 						while (sc->Check("|"));
3190 						if (HaveParen)
3191 						{
3192 							sc->Expect(")");
3193 						}
3194 						P.Field->SetInt(DefObj, Val);
3195 					}
3196 					break;
3197 				}
3198 				FoundProp = true;
3199 				break;
3200 			}
3201 		}
3202 		if (FoundProp)
3203 		{
3204 			continue;
3205 		}
3206 
3207 		sc->Error(va("Unknown property \"%s\"", *Prop));
3208 	}
3209 
3210 	sc->SetCMode(false);
3211 
3212 	Class->EmitStateLabels();
3213 
3214 	//	Set up linked list of states.
3215 	if (States.Num())
3216 	{
3217 		Class->States = States[0];
3218 		for (int i = 0; i < States.Num() - 1; i++)
3219 		{
3220 			States[i]->Next = States[i + 1];
3221 		}
3222 
3223 		for (int i = 0; i < States.Num(); i++)
3224 		{
3225 			if (States[i]->GotoLabel != NAME_None)
3226 			{
3227 				States[i]->NextState = Class->ResolveStateLabel(
3228 					States[i]->Loc, States[i]->GotoLabel, States[i]->GotoOffset);
3229 			}
3230 		}
3231 	}
3232 
3233 	if (DoomEdNum > 0)
3234 	{
3235 		mobjinfo_t& MI = VClass::GMobjInfos.Alloc();
3236 		MI.Class = Class;
3237 		MI.DoomEdNum = DoomEdNum;
3238 		MI.GameFilter = GameFilter;
3239 	}
3240 	if (SpawnNum > 0)
3241 	{
3242 		mobjinfo_t& SI = VClass::GScriptIds.Alloc();
3243 		SI.Class = Class;
3244 		SI.DoomEdNum = SpawnNum;
3245 		SI.GameFilter = GameFilter;
3246 	}
3247 	if (ReplaceeClass)
3248 	{
3249 		ReplaceeClass->Replacement = Class;
3250 		Class->Replacee = ReplaceeClass;
3251 	}
3252 	unguard;
3253 }
3254 
3255 //==========================================================================
3256 //
3257 //	ParseOldDecStates
3258 //
3259 //==========================================================================
3260 
ParseOldDecStates(VScriptParser * sc,TArray<VState * > & States,VClass * Class)3261 static void ParseOldDecStates(VScriptParser* sc, TArray<VState*>& States,
3262 	VClass* Class)
3263 {
3264 	guard(ParseOldDecStates);
3265 	TArray<VStr> Tokens;
3266 	sc->String.Split(",\t\r\n", Tokens);
3267 	for (int TokIdx = 0; TokIdx < Tokens.Num(); TokIdx++)
3268 	{
3269 		const char* pFrame = *Tokens[TokIdx];
3270 		int DurColon = Tokens[TokIdx].IndexOf(':');
3271 		float Duration = 4;
3272 		if (DurColon >= 0)
3273 		{
3274 			Duration = atoi(pFrame);
3275 			pFrame = *Tokens[TokIdx] + DurColon + 1;
3276 		}
3277 
3278 		bool GotState = false;
3279 		while (*pFrame)
3280 		{
3281 			if (*pFrame == ' ')
3282 			{
3283 			}
3284 			else if (*pFrame == '*')
3285 			{
3286 				if (!GotState)
3287 				{
3288 					sc->Error("* must come after a frame");
3289 				}
3290 				States[States.Num() - 1]->Frame |= VState::FF_FULLBRIGHT;
3291 			}
3292 			else if (*pFrame < 'A' || *pFrame > ']')
3293 			{
3294 				sc->Error("Frames must be A-Z, [, \\, or ]");
3295 			}
3296 			else
3297 			{
3298 				GotState = true;
3299 				VState* State = new VState(va("S_%d", States.Num()), Class,
3300 					sc->GetLoc());
3301 				States.Append(State);
3302 				State->Frame = *pFrame - 'A';
3303 				State->Time = Duration >= 0 ? float(Duration) / 35.0 : -1.0;
3304 			}
3305 			pFrame++;
3306 		}
3307 	}
3308 	unguard;
3309 }
3310 
3311 //==========================================================================
3312 //
3313 //	ParseOldDecoration
3314 //
3315 //==========================================================================
3316 
ParseOldDecoration(VScriptParser * sc,int Type)3317 static void ParseOldDecoration(VScriptParser* sc, int Type)
3318 {
3319 	guard(ParseOldDecoration);
3320 	//	Get name of the class.
3321 	sc->ExpectString();
3322 	VName ClassName = *sc->String;
3323 
3324 	//	Create class.
3325 	VClass* Class = Type == OLDDEC_Pickup ?
3326 		FakeInventoryClass->CreateDerivedClass(ClassName, DecPkg,
3327 		sc->GetLoc()) :
3328 		ActorClass->CreateDerivedClass(ClassName, DecPkg, sc->GetLoc());
3329 	DecPkg->ParsedClasses.Append(Class);
3330 	if (Type == OLDDEC_Breakable)
3331 	{
3332 		SetClassFieldBool(Class, "bShootable", true);
3333 	}
3334 	if (Type == OLDDEC_Projectile)
3335 	{
3336 		SetClassFieldBool(Class, "bMissile", true);
3337 		SetClassFieldBool(Class, "bDropOff", true);
3338 	}
3339 
3340 	//	Parse game filters.
3341 	int GameFilter = 0;
3342 	while (!sc->Check("{"))
3343 	{
3344 		if (sc->Check("Doom"))
3345 		{
3346 			GameFilter |= GAME_Doom;
3347 		}
3348 		else if (sc->Check("Heretic"))
3349 		{
3350 			GameFilter |= GAME_Heretic;
3351 		}
3352 		else if (sc->Check("Hexen"))
3353 		{
3354 			GameFilter |= GAME_Hexen;
3355 		}
3356 		else if (sc->Check("Strife"))
3357 		{
3358 			GameFilter |= GAME_Strife;
3359 		}
3360 		else if (sc->Check("Raven"))
3361 		{
3362 			GameFilter |= GAME_Raven;
3363 		}
3364 		else if (sc->Check("Any"))
3365 		{
3366 			GameFilter |= GAME_Any;
3367 		}
3368 		else if (GameFilter)
3369 		{
3370 			sc->Error("Unknown game filter");
3371 		}
3372 		else
3373 		{
3374 			sc->Error("Unknown identifier");
3375 		}
3376 	}
3377 
3378 	int DoomEdNum = -1;
3379 	int SpawnNum = -1;
3380 	VName Sprite("tnt1");
3381 	VName DeathSprite(NAME_None);
3382 	TArray<VState*> States;
3383 	int SpawnStart = 0;
3384 	int SpawnEnd = 0;
3385 	int DeathStart = 0;
3386 	int DeathEnd = 0;
3387 	bool DiesAway = false;
3388 	bool SolidOnDeath = false;
3389 	float DeathHeight = 0.0;
3390 	int BurnStart = 0;
3391 	int BurnEnd = 0;
3392 	bool BurnsAway = false;
3393 	bool SolidOnBurn = false;
3394 	float BurnHeight = 0.0;
3395 	int IceStart = 0;
3396 	int IceEnd = 0;
3397 	bool GenericIceDeath = false;
3398 	bool Explosive = false;
3399 
3400 	while (!sc->Check("}"))
3401 	{
3402 		if (sc->Check("DoomEdNum"))
3403 		{
3404 			sc->ExpectNumber();
3405 			if (sc->Number < -1 || sc->Number > 32767)
3406 			{
3407 				sc->Error("DoomEdNum is out of range [-1, 32767]");
3408 			}
3409 			DoomEdNum = sc->Number;
3410 		}
3411 		else if (sc->Check("SpawnNum"))
3412 		{
3413 			sc->ExpectNumber();
3414 			if (sc->Number < 0 || sc->Number > 255)
3415 			{
3416 				sc->Error("SpawnNum is out of range [0, 255]");
3417 			}
3418 			SpawnNum = sc->Number;
3419 		}
3420 
3421 		//	Spawn state
3422 		else if (sc->Check("Sprite"))
3423 		{
3424 			sc->ExpectString();
3425 			if (sc->String.Length() != 4)
3426 			{
3427 				sc->Error("Sprite name must be 4 characters long");
3428 			}
3429 			Sprite = *sc->String.ToLower();
3430 		}
3431 		else if (sc->Check("Frames"))
3432 		{
3433 			sc->ExpectString();
3434 			SpawnStart = States.Num();
3435 			ParseOldDecStates(sc, States, Class);
3436 			SpawnEnd = States.Num();
3437 		}
3438 
3439 		//	Death states
3440 		else if ((Type == OLDDEC_Breakable || Type == OLDDEC_Projectile) &&
3441 			sc->Check("DeathSprite"))
3442 		{
3443 			sc->ExpectString();
3444 			if (sc->String.Length() != 4)
3445 			{
3446 				sc->Error("Sprite name must be 4 characters long");
3447 			}
3448 			DeathSprite = *sc->String.ToLower();
3449 		}
3450 		else if ((Type == OLDDEC_Breakable || Type == OLDDEC_Projectile) &&
3451 			sc->Check("DeathFrames"))
3452 		{
3453 			sc->ExpectString();
3454 			DeathStart = States.Num();
3455 			ParseOldDecStates(sc, States, Class);
3456 			DeathEnd = States.Num();
3457 		}
3458 		else if (Type == OLDDEC_Breakable && sc->Check("DiesAway"))
3459 		{
3460 			DiesAway = true;
3461 		}
3462 		else if (Type == OLDDEC_Breakable && sc->Check("BurnDeathFrames"))
3463 		{
3464 			sc->ExpectString();
3465 			BurnStart = States.Num();
3466 			ParseOldDecStates(sc, States, Class);
3467 			BurnEnd = States.Num();
3468 		}
3469 		else if (Type == OLDDEC_Breakable && sc->Check("BurnsAway"))
3470 		{
3471 			BurnsAway = true;
3472 		}
3473 		else if (Type == OLDDEC_Breakable && sc->Check("IceDeathFrames"))
3474 		{
3475 			sc->ExpectString();
3476 			IceStart = States.Num();
3477 			ParseOldDecStates(sc, States, Class);
3478 
3479 			//	Make a copy of the last state for A_FreezeDeathChunks
3480 			VState* State = new VState(va("S_%d", States.Num()), Class,
3481 				sc->GetLoc());
3482 			States.Append(State);
3483 			State->Frame = States[States.Num() - 2]->Frame;
3484 
3485 			IceEnd = States.Num();
3486 		}
3487 		else if (Type == OLDDEC_Breakable && sc->Check("GenericIceDeath"))
3488 		{
3489 			GenericIceDeath = true;
3490 		}
3491 
3492 		//	Misc properties
3493 		else if (sc->Check("Radius"))
3494 		{
3495 			sc->ExpectFloat();
3496 			SetClassFieldFloat(Class, "Radius", sc->Float);
3497 		}
3498 		else if (sc->Check("Height"))
3499 		{
3500 			sc->ExpectFloat();
3501 			SetClassFieldFloat(Class, "Height", sc->Float);
3502 		}
3503 		else if (sc->Check("Mass"))
3504 		{
3505 			sc->ExpectFloat();
3506 			SetClassFieldFloat(Class, "Mass", sc->Float);
3507 		}
3508 		else if (sc->Check("Scale"))
3509 		{
3510 			sc->ExpectFloat();
3511 			SetClassFieldFloat(Class, "ScaleX", sc->Float);
3512 			SetClassFieldFloat(Class, "ScaleY", sc->Float);
3513 		}
3514 		else if (sc->Check("Alpha"))
3515 		{
3516 			sc->ExpectFloat();
3517 			SetClassFieldFloat(Class, "Alpha", MID(0.0, sc->Float, 1.0));
3518 		}
3519 		else if (sc->Check("RenderStyle"))
3520 		{
3521 			int RenderStyle = 0;
3522 			if (sc->Check("STYLE_None"))
3523 			{
3524 				RenderStyle = STYLE_None;
3525 			}
3526 			else if (sc->Check("STYLE_Normal"))
3527 			{
3528 				RenderStyle = STYLE_Normal;
3529 			}
3530 			else if (sc->Check("STYLE_Fuzzy"))
3531 			{
3532 				RenderStyle = STYLE_Fuzzy;
3533 			}
3534 			else if (sc->Check("STYLE_SoulTrans"))
3535 			{
3536 				RenderStyle = STYLE_SoulTrans;
3537 			}
3538 			else if (sc->Check("STYLE_OptFuzzy"))
3539 			{
3540 				RenderStyle = STYLE_OptFuzzy;
3541 			}
3542 			else if (sc->Check("STYLE_Translucent"))
3543 			{
3544 				RenderStyle = STYLE_Translucent;
3545 			}
3546 			else if (sc->Check("STYLE_Add"))
3547 			{
3548 				RenderStyle = STYLE_Add;
3549 			}
3550 			else
3551 			{
3552 				sc->Error("Bad render style");
3553 			}
3554 			SetClassFieldByte(Class, "RenderStyle", RenderStyle);
3555 		}
3556 		else if (sc->Check("Translation1"))
3557 		{
3558 			sc->ExpectNumber();
3559 			if (sc->Number < 0 || sc->Number > 2)
3560 			{
3561 				sc->Error("Translation1 is out of range [0, 2]");
3562 			}
3563 			SetClassFieldInt(Class, "Translation", (TRANSL_Standard <<
3564 				TRANSL_TYPE_SHIFT) + sc->Number);
3565 		}
3566 		else if (sc->Check("Translation2"))
3567 		{
3568 			sc->ExpectNumber();
3569 			if (sc->Number < 0 || sc->Number > MAX_LEVEL_TRANSLATIONS)
3570 			{
3571 				sc->Error(va("Translation2 is out of range [0, %d]",
3572 					MAX_LEVEL_TRANSLATIONS));
3573 			}
3574 			SetClassFieldInt(Class, "Translation", (TRANSL_Level <<
3575 				TRANSL_TYPE_SHIFT) + sc->Number);
3576 		}
3577 
3578 		//	Breakable decoration properties.
3579 		else if (Type == OLDDEC_Breakable && sc->Check("Health"))
3580 		{
3581 			sc->ExpectNumber();
3582 			SetClassFieldInt(Class, "Health", sc->Number);
3583 		}
3584 		else if (Type == OLDDEC_Breakable && sc->Check("DeathHeight"))
3585 		{
3586 			sc->ExpectFloat();
3587 			DeathHeight = sc->Float;
3588 		}
3589 		else if (Type == OLDDEC_Breakable && sc->Check("BurnHeight"))
3590 		{
3591 			sc->ExpectFloat();
3592 			BurnHeight = sc->Float;
3593 		}
3594 		else if (Type == OLDDEC_Breakable && sc->Check("SolidOnDeath"))
3595 		{
3596 			SolidOnDeath = true;
3597 		}
3598 		else if (Type == OLDDEC_Breakable && sc->Check("SolidOnBurn"))
3599 		{
3600 			SolidOnBurn = true;
3601 		}
3602 		else if ((Type == OLDDEC_Breakable || Type == OLDDEC_Projectile) &&
3603 			sc->Check("DeathSound"))
3604 		{
3605 			sc->ExpectString();
3606 			SetClassFieldName(Class, "DeathSound", *sc->String);
3607 		}
3608 		else if (Type == OLDDEC_Breakable && sc->Check("BurnDeathSound"))
3609 		{
3610 			sc->ExpectString();
3611 			SetClassFieldName(Class, "ActiveSound", *sc->String);
3612 		}
3613 
3614 		//	Projectile properties
3615 		else if (Type == OLDDEC_Projectile && sc->Check("Speed"))
3616 		{
3617 			sc->ExpectFloat();
3618 			SetClassFieldFloat(Class, "Speed", sc->Float * 35.0);
3619 		}
3620 		else if (Type == OLDDEC_Projectile && sc->Check("Damage"))
3621 		{
3622 			sc->ExpectNumber();
3623 			SetClassFieldFloat(Class, "MissileDamage", sc->Number);
3624 		}
3625 		else if (Type == OLDDEC_Projectile && sc->Check("DamageType"))
3626 		{
3627 			if (sc->Check("Normal"))
3628 			{
3629 				SetClassFieldName(Class, "DamageType", NAME_None);
3630 			}
3631 			else
3632 			{
3633 				sc->ExpectString();
3634 				SetClassFieldName(Class, "DamageType", *sc->String);
3635 			}
3636 		}
3637 		else if (Type == OLDDEC_Projectile && sc->Check("SpawnSound"))
3638 		{
3639 			sc->ExpectString();
3640 			SetClassFieldName(Class, "SightSound", *sc->String);
3641 		}
3642 		else if (Type == OLDDEC_Projectile && sc->Check("ExplosionRadius"))
3643 		{
3644 			sc->ExpectNumber();
3645 			SetClassFieldFloat(Class, "ExplosionRadius", sc->Number);
3646 			Explosive = true;
3647 		}
3648 		else if (Type == OLDDEC_Projectile && sc->Check("ExplosionDamage"))
3649 		{
3650 			sc->ExpectNumber();
3651 			SetClassFieldFloat(Class, "ExplosionDamage", sc->Number);
3652 			Explosive = true;
3653 		}
3654 		else if (Type == OLDDEC_Projectile && sc->Check("DoNotHurtShooter"))
3655 		{
3656 			SetClassFieldBool(Class, "bExplosionDontHurtSelf", true);
3657 		}
3658 		else if (Type == OLDDEC_Projectile && sc->Check("DoomBounce"))
3659 		{
3660 			SetClassFieldByte(Class, "BounceType", BOUNCE_Doom);
3661 		}
3662 		else if (Type == OLDDEC_Projectile && sc->Check("HereticBounce"))
3663 		{
3664 			SetClassFieldByte(Class, "BounceType", BOUNCE_Heretic);
3665 		}
3666 		else if (Type == OLDDEC_Projectile && sc->Check("HexenBounce"))
3667 		{
3668 			SetClassFieldByte(Class, "BounceType", BOUNCE_Hexen);
3669 		}
3670 
3671 		//	Pickup properties
3672 		else if (Type == OLDDEC_Pickup && sc->Check("PickupMessage"))
3673 		{
3674 			sc->ExpectString();
3675 			SetClassFieldStr(Class, "PickupMessage", sc->String);
3676 		}
3677 		else if (Type == OLDDEC_Pickup && sc->Check("PickupSound"))
3678 		{
3679 			sc->ExpectString();
3680 			SetClassFieldName(Class, "PickupSound", *sc->String);
3681 		}
3682 		else if (Type == OLDDEC_Pickup && sc->Check("Respawns"))
3683 		{
3684 			SetClassFieldBool(Class, "bRespawns", true);
3685 		}
3686 
3687 		//	Compatibility flags
3688 		else if (sc->Check("LowGravity"))
3689 		{
3690 			SetClassFieldFloat(Class, "Gravity", 0.125);
3691 		}
3692 		else if (sc->Check("FireDamage"))
3693 		{
3694 			SetClassFieldName(Class, "DamageType", "Fire");
3695 		}
3696 
3697 		//	Flags
3698 		else if (sc->Check("Solid"))
3699 		{
3700 			SetClassFieldBool(Class, "bSolid", true);
3701 		}
3702 		else if (sc->Check("NoSector"))
3703 		{
3704 			SetClassFieldBool(Class, "bNoSector", true);
3705 		}
3706 		else if (sc->Check("NoBlockmap"))
3707 		{
3708 			SetClassFieldBool(Class, "bNoBlockmap", true);
3709 		}
3710 		else if (sc->Check("SpawnCeiling"))
3711 		{
3712 			SetClassFieldBool(Class, "bSpawnCeiling", true);
3713 		}
3714 		else if (sc->Check("NoGravity"))
3715 		{
3716 			SetClassFieldBool(Class, "bNoGravity", true);
3717 		}
3718 		else if (sc->Check("Shadow"))
3719 		{
3720 			GCon->Logf("Shadow flag is not currently supported");
3721 		}
3722 		else if (sc->Check("NoBlood"))
3723 		{
3724 			SetClassFieldBool(Class, "bNoBlood", true);
3725 		}
3726 		else if (sc->Check("CountItem"))
3727 		{
3728 			SetClassFieldBool(Class, "bCountItem", true);
3729 		}
3730 		else if (sc->Check("WindThrust"))
3731 		{
3732 			SetClassFieldBool(Class, "bWindThrust", true);
3733 		}
3734 		else if (sc->Check("FloorClip"))
3735 		{
3736 			SetClassFieldBool(Class, "bFloorClip", true);
3737 		}
3738 		else if (sc->Check("SpawnFloat"))
3739 		{
3740 			SetClassFieldBool(Class, "bSpawnFloat", true);
3741 		}
3742 		else if (sc->Check("NoTeleport"))
3743 		{
3744 			SetClassFieldBool(Class, "bNoTeleport", true);
3745 		}
3746 		else if (sc->Check("Ripper"))
3747 		{
3748 			SetClassFieldBool(Class, "bRip", true);
3749 		}
3750 		else if (sc->Check("Pushable"))
3751 		{
3752 			SetClassFieldBool(Class, "bPushable", true);
3753 		}
3754 		else if (sc->Check("SlidesOnWalls"))
3755 		{
3756 			SetClassFieldBool(Class, "bSlide", true);
3757 		}
3758 		else if (sc->Check("CanPass"))
3759 		{
3760 			SetClassFieldBool(Class, "bPassMobj", true);
3761 		}
3762 		else if (sc->Check("CannotPush"))
3763 		{
3764 			SetClassFieldBool(Class, "bCannotPush", true);
3765 		}
3766 		else if (sc->Check("ThruGhost"))
3767 		{
3768 			SetClassFieldBool(Class, "bThruGhost", true);
3769 		}
3770 		else if (sc->Check("NoDamageThrust"))
3771 		{
3772 			SetClassFieldBool(Class, "bNoDamageThrust", true);
3773 		}
3774 		else if (sc->Check("Telestomp"))
3775 		{
3776 			SetClassFieldBool(Class, "bTelestomp", true);
3777 		}
3778 		else if (sc->Check("FloatBob"))
3779 		{
3780 			SetClassFieldBool(Class, "bFloatBob", true);
3781 		}
3782 		else if (sc->Check("ActivateImpact"))
3783 		{
3784 			SetClassFieldBool(Class, "bActivateImpact", true);
3785 		}
3786 		else if (sc->Check("CanPushWalls"))
3787 		{
3788 			SetClassFieldBool(Class, "bActivatePushWall", true);
3789 		}
3790 		else if (sc->Check("ActivateMCross"))
3791 		{
3792 			SetClassFieldBool(Class, "bActivateMCross", true);
3793 		}
3794 		else if (sc->Check("ActivatePCross"))
3795 		{
3796 			SetClassFieldBool(Class, "bActivatePCross", true);
3797 		}
3798 		else if (sc->Check("Reflective"))
3799 		{
3800 			SetClassFieldBool(Class, "bReflective", true);
3801 		}
3802 		else if (sc->Check("FloorHugger"))
3803 		{
3804 			SetClassFieldBool(Class, "bIgnoreFloorStep", true);
3805 		}
3806 		else if (sc->Check("CeilingHugger"))
3807 		{
3808 			SetClassFieldBool(Class, "bIgnoreCeilingStep", true);
3809 		}
3810 		else if (sc->Check("DontSplash"))
3811 		{
3812 			SetClassFieldBool(Class, "bNoSplash", true);
3813 		}
3814 		else
3815 		{
3816 			Sys_Error("Unknown property %s", *sc->String);
3817 		}
3818 	}
3819 
3820 	if (SpawnEnd == 0)
3821 	{
3822 		sc->Error(va("%s has no Frames definition", *ClassName));
3823 	}
3824 	if (Type == OLDDEC_Breakable && DeathEnd == 0)
3825 	{
3826 		sc->Error(va("%s has no DeathFrames definition", *ClassName));
3827 	}
3828 	if (GenericIceDeath && IceEnd != 0)
3829 	{
3830 		sc->Error("IceDeathFrames and GenericIceDeath are mutually exclusive");
3831 	}
3832 
3833 	if (DoomEdNum > 0)
3834 	{
3835 		mobjinfo_t& MI = VClass::GMobjInfos.Alloc();
3836 		MI.Class = Class;
3837 		MI.DoomEdNum = DoomEdNum;
3838 		MI.GameFilter = GameFilter;
3839 	}
3840 	if (SpawnNum > 0)
3841 	{
3842 		mobjinfo_t& SI = VClass::GScriptIds.Alloc();
3843 		SI.Class = Class;
3844 		SI.DoomEdNum = SpawnNum;
3845 		SI.GameFilter = GameFilter;
3846 	}
3847 
3848 	//	Set up linked list of states.
3849 	Class->States = States[0];
3850 	for (int i = 0; i < States.Num() - 1; i++)
3851 	{
3852 		States[i]->Next = States[i + 1];
3853 	}
3854 
3855 	//	Set up default sprite for all states.
3856 	for (int i = 0; i < States.Num(); i++)
3857 	{
3858 		States[i]->SpriteName = Sprite;
3859 	}
3860 	//	Set death sprite if it's defined.
3861 	if (DeathSprite != NAME_None && DeathEnd != 0)
3862 	{
3863 		for (int i = DeathStart; i < DeathEnd; i++)
3864 		{
3865 			States[i]->SpriteName = DeathSprite;
3866 		}
3867 	}
3868 
3869 	//	Set up links of spawn states.
3870 	if (SpawnEnd - SpawnStart == 1)
3871 	{
3872 		States[SpawnStart]->Time = -1.0;
3873 	}
3874 	else
3875 	{
3876 		for (int i = SpawnStart; i < SpawnEnd - 1; i++)
3877 		{
3878 			States[i]->NextState = States[i + 1];
3879 		}
3880 		States[SpawnEnd - 1]->NextState = States[SpawnStart];
3881 	}
3882 	Class->SetStateLabel("Spawn", States[SpawnStart]);
3883 
3884 	//	Set up links of death states.
3885 	if (DeathEnd != 0)
3886 	{
3887 		for (int i = DeathStart; i < DeathEnd - 1; i++)
3888 		{
3889 			States[i]->NextState = States[i + 1];
3890 		}
3891 		if (!DiesAway && Type != OLDDEC_Projectile)
3892 		{
3893 			States[DeathEnd - 1]->Time = -1.0;
3894 		}
3895 		if (Type == OLDDEC_Projectile)
3896 		{
3897 			if (Explosive)
3898 			{
3899 				States[DeathStart]->Function = FuncA_ExplodeParms;
3900 			}
3901 		}
3902 		else
3903 		{
3904 			//	First death state plays death sound, second makes it
3905 			// non-blocking unless it should stay solid.
3906 			States[DeathStart]->Function = FuncA_Scream;
3907 			if (!SolidOnDeath)
3908 			{
3909 				if (DeathEnd - DeathStart > 1)
3910 				{
3911 					States[DeathStart + 1]->Function = FuncA_NoBlocking;
3912 				}
3913 				else
3914 				{
3915 					States[DeathStart]->Function = FuncA_ScreamAndUnblock;
3916 				}
3917 			}
3918 
3919 			if (!DeathHeight)
3920 			{
3921 				DeathHeight = GetClassFieldFloat(Class, "Height");
3922 			}
3923 			SetClassFieldFloat(Class, "DeathHeight", DeathHeight);
3924 		}
3925 
3926 		Class->SetStateLabel("Death", States[DeathStart]);
3927 	}
3928 
3929 	//	Set up links of burn death states.
3930 	if (BurnEnd != 0)
3931 	{
3932 		for (int i = BurnStart; i < BurnEnd - 1; i++)
3933 		{
3934 			States[i]->NextState = States[i + 1];
3935 		}
3936 		if (!BurnsAway)
3937 		{
3938 			States[BurnEnd - 1]->Time = -1.0;
3939 		}
3940 		//	First death state plays active sound, second makes it
3941 		// non-blocking unless it should stay solid.
3942 		States[BurnStart]->Function = FuncA_ActiveSound;
3943 		if (!SolidOnBurn)
3944 		{
3945 			if (BurnEnd - BurnStart > 1)
3946 			{
3947 				States[BurnStart + 1]->Function = FuncA_NoBlocking;
3948 			}
3949 			else
3950 			{
3951 				States[BurnStart]->Function = FuncA_ActiveAndUnblock;
3952 			}
3953 		}
3954 
3955 		if (!BurnHeight)
3956 		{
3957 			BurnHeight = GetClassFieldFloat(Class, "Height");
3958 		}
3959 		SetClassFieldFloat(Class, "BurnHeight", BurnHeight);
3960 
3961 		TArray<VName> Names;
3962 		Names.Append("Death");
3963 		Names.Append("Fire");
3964 		Class->SetStateLabel(Names, States[BurnStart]);
3965 	}
3966 
3967 	//	Set up links of ice death states.
3968 	if (IceEnd != 0)
3969 	{
3970 		for (int i = IceStart; i < IceEnd - 1; i++)
3971 		{
3972 			States[i]->NextState = States[i + 1];
3973 		}
3974 
3975 		States[IceEnd - 2]->Time = 5.0 / 35.0;
3976 		States[IceEnd - 2]->Function = FuncA_FreezeDeath;
3977 
3978 		States[IceEnd - 1]->NextState = States[IceEnd - 1];
3979 		States[IceEnd - 1]->Time = 1.0 / 35.0;
3980 		States[IceEnd - 1]->Function = FuncA_FreezeDeathChunks;
3981 
3982 		TArray<VName> Names;
3983 		Names.Append("Death");
3984 		Names.Append("Ice");
3985 		Class->SetStateLabel(Names, States[IceStart]);
3986 	}
3987 	else if (GenericIceDeath)
3988 	{
3989 		VStateLabel* Lbl = Class->FindStateLabel("GenericIceDeath");
3990 		TArray<VName> Names;
3991 		Names.Append("Death");
3992 		Names.Append("Ice");
3993 		Class->SetStateLabel(Names, Lbl ? Lbl->State : NULL);
3994 	}
3995 	unguard;
3996 }
3997 
3998 //==========================================================================
3999 //
4000 //	ParseDecorate
4001 //
4002 //==========================================================================
4003 
ParseDecorate(VScriptParser * sc,TArray<VClassFixup> & ClassFixups)4004 static void ParseDecorate(VScriptParser* sc, TArray<VClassFixup>& ClassFixups)
4005 {
4006 	guard(ParseDecorate);
4007 	while (!sc->AtEnd())
4008 	{
4009 		if (sc->Check("#include"))
4010 		{
4011 			sc->ExpectString();
4012 			int Lump = W_CheckNumForFileName(sc->String);
4013 			//	Check WAD lump only if it's no longer than 8 characters and
4014 			// has no path separator.
4015 			if (Lump < 0 && sc->String.Length() <= 8 &&
4016 				sc->String.IndexOf('/') < 0)
4017 			{
4018 				Lump = W_CheckNumForName(VName(*sc->String, VName::AddLower8));
4019 			}
4020 			if (Lump < 0)
4021 			{
4022 				sc->Error(va("Lump %s not found", *sc->String));
4023 			}
4024 			ParseDecorate(new VScriptParser(sc->String,
4025 				W_CreateLumpReaderNum(Lump)), ClassFixups);
4026 		}
4027 		else if (sc->Check("const"))
4028 		{
4029 			ParseConst(sc);
4030 		}
4031 		else if (sc->Check("enum"))
4032 		{
4033 			ParseEnum(sc);
4034 		}
4035 		else if (sc->Check("class"))
4036 		{
4037 			ParseClass(sc);
4038 		}
4039 		else if (sc->Check("actor"))
4040 		{
4041 			ParseActor(sc, ClassFixups);
4042 		}
4043 		else if (sc->Check("breakable"))
4044 		{
4045 			ParseOldDecoration(sc, OLDDEC_Breakable);
4046 		}
4047 		else if (sc->Check("pickup"))
4048 		{
4049 			ParseOldDecoration(sc, OLDDEC_Pickup);
4050 		}
4051 		else if (sc->Check("projectile"))
4052 		{
4053 			ParseOldDecoration(sc, OLDDEC_Projectile);
4054 		}
4055 		else
4056 		{
4057 			ParseOldDecoration(sc, OLDDEC_Decoration);
4058 		}
4059 	}
4060 	delete sc;
4061 	sc = NULL;
4062 	unguard;
4063 }
4064 
4065 //==========================================================================
4066 //
4067 //	ReadLineSpecialInfos
4068 //
4069 //==========================================================================
4070 
ReadLineSpecialInfos()4071 void ReadLineSpecialInfos()
4072 {
4073 	guard(ReadLineSpecialInfos);
4074 	VStream* Strm = FL_OpenFileRead("line_specials.txt");
4075 	check(Strm);
4076 	VScriptParser* sc = new VScriptParser("line_specials.txt", Strm);
4077 	while (!sc->AtEnd())
4078 	{
4079 		VLineSpecInfo& I = LineSpecialInfos.Alloc();
4080 		sc->ExpectNumber();
4081 		I.Number = sc->Number;
4082 		sc->ExpectString();
4083 		I.Name = sc->String.ToLower();
4084 	}
4085 	delete sc;
4086 	sc = NULL;
4087 	unguard;
4088 }
4089 
4090 //==========================================================================
4091 //
4092 //	ProcessDecorateScripts
4093 //
4094 //==========================================================================
4095 
ProcessDecorateScripts()4096 void ProcessDecorateScripts()
4097 {
4098 	guard(ProcessDecorateScripts);
4099 	GCon->Logf(NAME_Init, "Parsing DECORATE definition files");
4100 	for (int Lump = W_IterateFile(-1, "vavoom_decorate_defs.xml"); Lump != -1;
4101 		Lump = W_IterateFile(Lump, "vavoom_decorate_defs.xml"))
4102 	{
4103 		VStream* Strm = W_CreateLumpReaderNum(Lump);
4104 		check(Strm);
4105 		VXmlDocument* Doc = new VXmlDocument();
4106 		Doc->Parse(*Strm, "vavoom_decorate_defs.xml");
4107 		delete Strm;
4108 		Strm = NULL;
4109 		ParseDecorateDef(*Doc);
4110 		delete Doc;
4111 		Doc = NULL;
4112 	}
4113 
4114 	GCon->Logf(NAME_Init, "Processing DECORATE scripts");
4115 
4116 	DecPkg = new VPackage(NAME_decorate);
4117 
4118 	//	Find classes.
4119 	ActorClass = VClass::FindClass("Actor");
4120 	FakeInventoryClass = VClass::FindClass("FakeInventory");
4121 	InventoryClass = VClass::FindClass("Inventory");
4122 	AmmoClass = VClass::FindClass("Ammo");
4123 	BasicArmorPickupClass = VClass::FindClass("BasicArmorPickup");
4124 	BasicArmorBonusClass = VClass::FindClass("BasicArmorBonus");
4125 	HealthClass = VClass::FindClass("Health");
4126 	PowerupGiverClass = VClass::FindClass("PowerupGiver");
4127 	PuzzleItemClass = VClass::FindClass("PuzzleItem");
4128 	WeaponClass = VClass::FindClass("Weapon");
4129 	WeaponPieceClass = VClass::FindClass("WeaponPiece");
4130 	PlayerPawnClass = VClass::FindClass("PlayerPawn");
4131 	MorphProjectileClass = VClass::FindClass("MorphProjectile");
4132 
4133 	//	Find methods used by old style decorations.
4134 	FuncA_Scream = ActorClass->FindMethodChecked("A_Scream");
4135 	FuncA_NoBlocking = ActorClass->FindMethodChecked("A_NoBlocking");
4136 	FuncA_ScreamAndUnblock = ActorClass->FindMethodChecked("A_ScreamAndUnblock");
4137 	FuncA_ActiveSound = ActorClass->FindMethodChecked("A_ActiveSound");
4138 	FuncA_ActiveAndUnblock = ActorClass->FindMethodChecked("A_ActiveAndUnblock");
4139 	FuncA_ExplodeParms = ActorClass->FindMethodChecked("A_ExplodeParms");
4140 	FuncA_FreezeDeath = ActorClass->FindMethodChecked("A_FreezeDeath");
4141 	FuncA_FreezeDeathChunks = ActorClass->FindMethodChecked("A_FreezeDeathChunks");
4142 
4143 	//	Parse scripts.
4144 	TArray<VClassFixup> ClassFixups;
4145 	for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
4146 		Lump = W_IterateNS(Lump, WADNS_Global))
4147 	{
4148 		if (W_LumpName(Lump) == NAME_decorate)
4149 		{
4150 			ParseDecorate(new VScriptParser(*W_LumpName(Lump),
4151 				W_CreateLumpReaderNum(Lump)), ClassFixups);
4152 		}
4153 	}
4154 
4155 	//	Make sure all import classes were defined.
4156 	if (VMemberBase::GDecorateClassImports.Num())
4157 	{
4158 		for (int i = 0; i < VMemberBase::GDecorateClassImports.Num(); i++)
4159 		{
4160 			GCon->Logf("Undefined DECORATE class %s",
4161 				VMemberBase::GDecorateClassImports[i]->GetName());
4162 		}
4163 		Sys_Error("Not all DECORATE class imports were defined");
4164 	}
4165 
4166 	GCon->Logf(NAME_Init, "Post-procesing");
4167 
4168 	//	Set class properties.
4169 	for (int i = 0; i < ClassFixups.Num(); i++)
4170 	{
4171 		VClassFixup& CF = ClassFixups[i];
4172 		check(CF.ReqParent);
4173 		if (!CF.Name.ICmp("None"))
4174 		{
4175 			*(VClass**)(CF.Class->Defaults + CF.Offset) = NULL;
4176 		}
4177 		else
4178 		{
4179 			VClass* C = VClass::FindClassLowerCase(*CF.Name.ToLower());
4180 			if (!C)
4181 			{
4182 				GCon->Logf("No such class %s", *CF.Name);
4183 			}
4184 			else if (!C->IsChildOf(CF.ReqParent))
4185 			{
4186 				GCon->Logf("Class %s is not a descendant of %s",
4187 					*CF.Name, CF.ReqParent->GetName());
4188 			}
4189 			else
4190 			{
4191 				*(VClass**)(CF.Class->Defaults + CF.Offset) = C;
4192 			}
4193 		}
4194 	}
4195 	VField* DropItemListField = ActorClass->FindFieldChecked("DropItemList");
4196 	for (int i = 0; i < DecPkg->ParsedClasses.Num(); i++)
4197 	{
4198 		TArray<VDropItemInfo>& List =
4199 			*(TArray<VDropItemInfo>*)DropItemListField->GetFieldPtr(
4200 			(VObject*)DecPkg->ParsedClasses[i]->Defaults);
4201 		for (int j = 0; j < List.Num(); j++)
4202 		{
4203 			VDropItemInfo& DI = List[j];
4204 			if (DI.TypeName == NAME_None)
4205 			{
4206 				continue;
4207 			}
4208 			VClass* C = VClass::FindClassLowerCase(DI.TypeName);
4209 			if (!C)
4210 			{
4211 				GCon->Logf("No such class %s", *DI.TypeName);
4212 			}
4213 			else if (!C->IsChildOf(ActorClass))
4214 			{
4215 				GCon->Logf("Class %s is not an actor class", *DI.TypeName);
4216 			}
4217 			else
4218 			{
4219 				DI.Type = C;
4220 			}
4221 		}
4222 	}
4223 
4224 	//	Emit code.
4225 	for (int i = 0; i < DecPkg->ParsedClasses.Num(); i++)
4226 	{
4227 		if (GArgs.CheckParm("-debug_decorate"))
4228 		{
4229 			GCon->Logf("Emiting Class %s", *DecPkg->ParsedClasses[i]->GetFullName());
4230 		}
4231 		DecPkg->ParsedClasses[i]->DecorateEmit();
4232 	}
4233 	//	Compile and set up for execution.
4234 	for (int i = 0; i < DecPkg->ParsedClasses.Num(); i++)
4235 	{
4236 		if (GArgs.CheckParm("-debug_decorate"))
4237 		{
4238 			GCon->Logf("Compiling Class %s", *DecPkg->ParsedClasses[i]->GetFullName());
4239 		}
4240 		DecPkg->ParsedClasses[i]->DecoratePostLoad();
4241 	}
4242 
4243 	if (NumErrors)
4244 	{
4245 		BailOut();
4246 	}
4247 
4248 	VClass::StaticReinitStatesLookup();
4249 
4250 	TLocation::ClearSourceFiles();
4251 	unguard;
4252 }
4253 
4254 //==========================================================================
4255 //
4256 //	ShutdownDecorate
4257 //
4258 //==========================================================================
4259 
ShutdownDecorate()4260 void ShutdownDecorate()
4261 {
4262 	guard(ShutdownDecorate);
4263 	FlagList.Clear();
4264 	LineSpecialInfos.Clear();
4265 	unguard;
4266 }
4267 
4268 //==========================================================================
4269 //
4270 //	VEntity::SetDecorateFlag
4271 //
4272 //==========================================================================
4273 
SetDecorateFlag(const VStr & Flag,bool Value)4274 void VEntity::SetDecorateFlag(const VStr& Flag, bool Value)
4275 {
4276 	guard(VEntity::SetDecorateFlag);
4277 	VName FlagName;
4278 	VName ClassFilter(NAME_None);
4279 	int DotPos = Flag.IndexOf('.');
4280 	if (DotPos >= 0)
4281 	{
4282 		ClassFilter = *VStr(Flag, 0, DotPos).ToLower();
4283 		FlagName = *VStr(Flag, DotPos + 1, Flag.Length() - DotPos - 1).ToLower();
4284 	}
4285 	else
4286 	{
4287 		FlagName = *Flag.ToLower();
4288 	}
4289 	for (int j = 0; j < FlagList.Num(); j++)
4290 	{
4291 		VFlagList& ClassDef = FlagList[j];
4292 		if (ClassFilter != NAME_None &&
4293 			ClassDef.Class->LowerCaseName != ClassFilter)
4294 		{
4295 			continue;
4296 		}
4297 		if (!IsA(ClassDef.Class))
4298 		{
4299 			continue;
4300 		}
4301 		for (int i = ClassDef.FlagsHash[GetTypeHash(FlagName) &
4302 			(FLAGS_HASH_SIZE - 1)]; i != -1; i = ClassDef.Flags[i].HashNext)
4303 		{
4304 			const VFlagDef& F = ClassDef.Flags[i];
4305 			if (FlagName == F.Name)
4306 			{
4307 				switch (F.Type)
4308 				{
4309 				case FLAG_Bool:
4310 					F.Field->SetBool(this, Value);
4311 					break;
4312 				case FLAG_Unsupported:
4313 					GCon->Logf("Unsupported flag %s in %s", *Flag,
4314 						GetClass()->GetName());
4315 					break;
4316 				case FLAG_Byte:
4317 					F.Field->SetByte(this, Value ? F.BTrue : F.BFalse);
4318 					break;
4319 				case FLAG_Float:
4320 					F.Field->SetFloat(this, Value ? F.FTrue : F.FFalse);
4321 					break;
4322 				case FLAG_Name:
4323 					F.Field->SetName(this, Value ? F.NTrue : F.NFalse);
4324 					break;
4325 				case FLAG_Class:
4326 					F.Field->SetClass(this, Value ?
4327 						F.NTrue != NAME_None ? VClass::FindClass(*F.NTrue) : NULL :
4328 						F.NFalse != NAME_None ? VClass::FindClass(*F.NFalse) : NULL);
4329 					break;
4330 				case FLAG_NoClip:
4331 					F.Field->SetBool(this, !Value);
4332 					F.Field2->SetBool(this, !Value);
4333 					break;
4334 				}
4335 				return;
4336 			}
4337 		}
4338 	}
4339 	GCon->Logf("Unknown flag %s", *Flag);
4340 	unguard;
4341 }
4342