1 /*
2 ** thingdef.cpp
3 **
4 **---------------------------------------------------------------------------
5 ** Copyright 2011 Braden Obrzut
6 ** All rights reserved.
7 **
8 ** Redistribution and use in source and binary forms, with or without
9 ** modification, are permitted provided that the following conditions
10 ** are met:
11 **
12 ** 1. Redistributions of source code must retain the above copyright
13 **    notice, this list of conditions and the following disclaimer.
14 ** 2. Redistributions in binary form must reproduce the above copyright
15 **    notice, this list of conditions and the following disclaimer in the
16 **    documentation and/or other materials provided with the distribution.
17 ** 3. The name of the author may not be used to endorse or promote products
18 **    derived from this software without specific prior written permission.
19 **
20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 **---------------------------------------------------------------------------
31 **
32 **
33 */
34 
35 #include "actor.h"
36 #include "a_inventory.h"
37 #include "doomerrors.h"
38 #include "id_ca.h"
39 #include "lnspec.h"
40 #include "m_random.h"
41 #include "r_sprites.h"
42 #include "scanner.h"
43 #include "w_wad.h"
44 #include "wl_def.h"
45 #include "wl_draw.h"
46 #include "thingdef/thingdef.h"
47 #include "thingdef/thingdef_type.h"
48 #include "thingdef/thingdef_expression.h"
49 #include "thinker.h"
50 #include "templates.h"
51 #include "g_mapinfo.h"
52 
53 #include <climits>
54 
55 // Code pointer stuff
56 void InitFunctionTable(ActionTable *table);
57 void ReleaseFunctionTable();
58 ActionInfo *LookupFunction(const FName &func, const ActionTable *table);
59 
60 typedef DWORD flagstype_t;
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 
64 #define DEFINE_FLAG(prefix, flag, type, variable) { NATIVE_CLASS(type), prefix##_##flag, #type, #flag, typeoffsetof(A##type,variable) }
65 const struct FlagDef
66 {
67 	public:
68 		const ClassDef * const &cls;
69 		const flagstype_t	value;
70 		const char* const	prefix;
71 		const char* const	name;
72 		const int			varOffset;
73 } flags[] =
74 {
75 	DEFINE_FLAG(FL, ALWAYSFAST, Actor, flags),
76 	DEFINE_FLAG(WF, ALWAYSGRIN, Weapon, weaponFlags),
77 	DEFINE_FLAG(IF, ALWAYSPICKUP, Inventory, itemFlags),
78 	DEFINE_FLAG(FL, AMBUSH, Actor, flags),
79 	DEFINE_FLAG(IF, AUTOACTIVATE, Inventory, itemFlags),
80 	DEFINE_FLAG(FL, BRIGHT, Actor, flags),
81 	DEFINE_FLAG(FL, CANUSEWALLS, Actor, flags),
82 	DEFINE_FLAG(FL, COUNTITEM, Actor, flags),
83 	DEFINE_FLAG(FL, COUNTKILL, Actor, flags),
84 	DEFINE_FLAG(FL, COUNTSECRET, Actor, flags),
85 	DEFINE_FLAG(WF, DONTBOB, Weapon, weaponFlags),
86 	DEFINE_FLAG(FL, DONTRIP, Actor, flags),
87 	DEFINE_FLAG(FL, DROPBASEDONTARGET, Actor, flags),
88 	DEFINE_FLAG(IF, INVBAR, Inventory, itemFlags),
89 	DEFINE_FLAG(FL, ISMONSTER, Actor, flags),
90 	DEFINE_FLAG(FL, MISSILE, Actor, flags),
91 	DEFINE_FLAG(WF, NOALERT, Weapon, weaponFlags),
92 	DEFINE_FLAG(WF, NOAUTOFIRE, Weapon, weaponFlags),
93 	DEFINE_FLAG(WF, NOGRIN, Weapon, weaponFlags),
94 	DEFINE_FLAG(FL, OLDRANDOMCHASE, Actor, flags),
95 	DEFINE_FLAG(FL, PICKUP, Actor, flags),
96 	DEFINE_FLAG(FL, PLOTONAUTOMAP, Actor, flags),
97 	DEFINE_FLAG(FL, RANDOMIZE, Actor, flags),
98 	DEFINE_FLAG(FL, RIPPER, Actor, flags),
99 	DEFINE_FLAG(FL, REQUIREKEYS, Actor, flags),
100 	DEFINE_FLAG(FL, SHOOTABLE, Actor, flags),
101 	DEFINE_FLAG(FL, SOLID, Actor, flags)
102 };
103 extern const PropDef properties[];
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 
StateLabel(const FString & str,const ClassDef * parent,bool noRelative)107 StateLabel::StateLabel(const FString &str, const ClassDef *parent, bool noRelative)
108 {
109 	Scanner sc(str.GetChars(), str.Len());
110 	Parse(sc, parent, noRelative);
111 }
112 
StateLabel(Scanner & sc,const ClassDef * parent,bool noRelative)113 StateLabel::StateLabel(Scanner &sc, const ClassDef *parent, bool noRelative)
114 {
115 	Parse(sc, parent, noRelative);
116 }
117 
Resolve() const118 const Frame *StateLabel::Resolve() const
119 {
120 	return cls->FindStateInList(label) + offset;
121 }
122 
Resolve(AActor * owner,const Frame * caller,const Frame * def) const123 const Frame *StateLabel::Resolve(AActor *owner, const Frame *caller, const Frame *def) const
124 {
125 	if(isRelative)
126 		return caller + offset;
127 	else if(isDefault)
128 		return def;
129 
130 	const Frame *frame = owner->GetClass()->FindStateInList(label);
131 	if(frame)
132 		return frame + offset;
133 	return NULL;
134 }
135 
Parse(Scanner & sc,const ClassDef * parent,bool noRelative)136 void StateLabel::Parse(Scanner &sc, const ClassDef *parent, bool noRelative)
137 {
138 	cls = parent;
139 
140 	if(!noRelative && sc.CheckToken(TK_IntConst))
141 	{
142 		isRelative = true;
143 		offset = sc->number;
144 		return;
145 	}
146 
147 	isRelative = false;
148 	isDefault = sc.CheckToken('*');
149 	if(isDefault)
150 		return;
151 
152 	sc.MustGetToken(TK_Identifier);
153 	label = sc->str;
154 	if(sc.CheckToken(TK_ScopeResolution))
155 	{
156 		if(label.CompareNoCase("Super") == 0)
157 		{
158 			// This should never happen in normal use, but just in case.
159 			if(parent->parent == NULL)
160 				sc.ScriptMessage(Scanner::ERROR, "This actor does not have a super class.");
161 			cls = parent->parent;
162 		}
163 		else
164 		{
165 			do
166 			{
167 				cls = cls->parent;
168 				if(cls == NULL)
169 					sc.ScriptMessage(Scanner::ERROR, "%s is not a super class.", label.GetChars());
170 			}
171 			while(stricmp(cls->GetName().GetChars(), label.GetChars()) != 0);
172 		}
173 
174 		sc.MustGetToken(TK_Identifier);
175 		label = sc->str;
176 	}
177 
178 	while(sc.CheckToken('.'))
179 	{
180 		sc.MustGetToken(TK_Identifier);
181 		label = label + "." + sc->str;
182 	}
183 
184 	if(sc.CheckToken('+'))
185 	{
186 		sc.MustGetToken(TK_IntConst);
187 		offset = sc->number;
188 	}
189 	else
190 		offset = 0;
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 
195 struct StateDefinition
196 {
197 	public:
198 		enum NextType
199 		{
200 			GOTO,
201 			LOOP,
202 			WAIT,
203 			STOP,
204 
205 			NORMAL
206 		};
207 
208 		FString		label;
209 		char		sprite[5];
210 		FString		frames;
211 		int			duration;
212 		unsigned	randDuration;
213 		bool		fullbright;
214 		NextType	nextType;
215 		FString		nextArg;
216 		StateLabel	jumpLabel;
217 		Frame::ActionCall	functions[2];
218 };
219 
220 static TArray<const SymbolInfo *> *symbolPool = NULL;
221 
SymbolInfo(const ClassDef * cls,const FName & var,const int offset)222 SymbolInfo::SymbolInfo(const ClassDef *cls, const FName &var, const int offset) :
223 	cls(cls), var(var), offset(offset)
224 {
225 	if(symbolPool == NULL)
226 		symbolPool = new TArray<const SymbolInfo *>();
227 	symbolPool->Push(this);
228 }
229 
SymbolCompare(const void * s1,const void * s2)230 int SymbolCompare(const void *s1, const void *s2)
231 {
232 	const Symbol * const sym1 = *((const Symbol **)s1);
233 	const Symbol * const sym2 = *((const Symbol **)s2);
234 	if(sym1->GetName() < sym2->GetName())
235 		return -1;
236 	else if(sym1->GetName() > sym2->GetName())
237 		return 1;
238 	return 0;
239 }
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 
ExprSin(AActor * self,ExpressionNode::Value & out,ExpressionNode * const * args,FRandom * rng)243 void ExprSin(AActor *self, ExpressionNode::Value &out, ExpressionNode* const *args, FRandom *rng)
244 {
245 	out = double(finesine[(args[0]->Evaluate(self).GetInt()%360)*FINEANGLES/360])/FRACUNIT;
246 }
247 
ExprCos(AActor * self,ExpressionNode::Value & out,ExpressionNode * const * args,FRandom * rng)248 void ExprCos(AActor *self, ExpressionNode::Value &out, ExpressionNode* const *args, FRandom *rng)
249 {
250 	out = double(finecosine[(args[0]->Evaluate(self).GetInt()%360)*FINEANGLES/360])/FRACUNIT;
251 }
252 
ExprRandom(AActor * self,ExpressionNode::Value & out,ExpressionNode * const * args,FRandom * rng)253 void ExprRandom(AActor *self, ExpressionNode::Value &out, ExpressionNode* const *args, FRandom *rng)
254 {
255 	int64_t min = args[0]->Evaluate(self).GetInt();
256 	int64_t max = args[1]->Evaluate(self).GetInt();
257 	if(min > max)
258 		out = max+(*rng)((int)(min-max+1));
259 	else
260 		out = min+(*rng)((int)(max-min+1));
261 }
262 
ExprFRandom(AActor * self,ExpressionNode::Value & out,ExpressionNode * const * args,FRandom * rng)263 void ExprFRandom(AActor *self, ExpressionNode::Value &out, ExpressionNode* const *args, FRandom *rng)
264 {
265 	static const unsigned int randomPrecision = 0x80000000;
266 
267 	double min = args[0]->Evaluate(self).GetDouble();
268 	double max = args[1]->Evaluate(self).GetDouble();
269 	out = min+(double((*rng)(randomPrecision))/randomPrecision)*(max-min);
270 }
271 
272 static const struct ExpressionFunction
273 {
274 	const char* const				name;
275 	int								ret;
276 	unsigned short					args;
277 	bool							takesRNG;
278 	FunctionSymbol::ExprFunction	function;
279 } functions[] =
280 {
281 	{ "cos",		TypeHierarchy::FLOAT,	1,	false,	ExprCos },
282 	{ "frandom",	TypeHierarchy::FLOAT,	2,	true,	ExprFRandom },
283 	{ "random",		TypeHierarchy::INT,		2,	true,	ExprRandom },
284 	{ "sin",		TypeHierarchy::FLOAT,	1,	false,	ExprSin },
285 
286 	{ NULL, 0, false, false }
287 };
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 
291 class MetaTable::Data
292 {
293 	public:
Data(MetaTable::Type type,uint32_t id)294 		Data(MetaTable::Type type, uint32_t id) : id(id), type(type), inherited(false), next(NULL) {}
~Data()295 		~Data()
296 		{
297 			SetType(MetaTable::INTEGER);
298 		}
299 
SetType(MetaTable::Type type)300 		void	SetType(MetaTable::Type type)
301 		{
302 			// As soon as we try to change the value consider the meta data new
303 			inherited = false;
304 			if(this->type == type)
305 				return;
306 
307 			if(this->type == MetaTable::STRING)
308 			{
309 				delete[] value.string;
310 				value.string = NULL;
311 			}
312 
313 			this->type = type;
314 		}
315 
operator =(const Data & other)316 		const Data &operator= (const Data &other)
317 		{
318 			id = other.id;
319 			SetType(other.type);
320 			inherited = true;
321 
322 			switch(type)
323 			{
324 				case MetaTable::INTEGER:
325 					value.integer = other.value.integer;
326 					break;
327 				case MetaTable::STRING:
328 					value.string = new char[strlen(other.value.string)+1];
329 					strcpy(value.string, other.value.string);
330 					break;
331 				case MetaTable::FIXED:
332 					value.fixedPoint = other.value.fixedPoint;
333 					break;
334 			}
335 
336 			return other;
337 		}
338 
339 		uint32_t		id;
340 		MetaTable::Type	type;
341 		bool			inherited;
342 		union
343 		{
344 			int			integer;
345 			fixed		fixedPoint;
346 			char*		string;
347 		} value;
348 		Data			*next;
349 };
350 
MetaTable()351 MetaTable::MetaTable() : head(NULL)
352 {
353 }
354 
~MetaTable()355 MetaTable::~MetaTable()
356 {
357 	FreeTable();
358 }
359 
CopyMeta(const MetaTable & other)360 void MetaTable::CopyMeta(const MetaTable &other)
361 {
362 	Data *data = other.head;
363 	while(data)
364 	{
365 		Data *copyData = FindMetaData(data->id);
366 		*copyData = *data;
367 
368 		data = data->next;
369 	}
370 }
371 
FindMeta(uint32_t id) const372 MetaTable::Data *MetaTable::FindMeta(uint32_t id) const
373 {
374 	Data *data = head;
375 
376 	while(data != NULL)
377 	{
378 		if(data->id == id)
379 			break;
380 
381 		data = data->next;
382 	}
383 
384 	return data;
385 }
386 
FindMetaData(uint32_t id)387 MetaTable::Data *MetaTable::FindMetaData(uint32_t id)
388 {
389 	Data *data = FindMeta(id);
390 	if(data == NULL)
391 	{
392 		data = new MetaTable::Data(MetaTable::INTEGER, id);
393 		data->next = head;
394 		head = data;
395 	}
396 
397 	return data;
398 }
399 
FreeTable()400 void MetaTable::FreeTable()
401 {
402 	Data *data = head;
403 	while(data != NULL)
404 	{
405 		Data *prevData = data;
406 		data = data->next;
407 		delete prevData;
408 	}
409 }
410 
GetMetaInt(uint32_t id,int def) const411 int MetaTable::GetMetaInt(uint32_t id, int def) const
412 {
413 	Data *data = FindMeta(id);
414 	if(!data)
415 		return def;
416 	return data->value.integer;
417 }
418 
GetMetaFixed(uint32_t id,fixed def) const419 fixed MetaTable::GetMetaFixed(uint32_t id, fixed def) const
420 {
421 	Data *data = FindMeta(id);
422 	if(!data)
423 		return def;
424 	return data->value.fixedPoint;
425 }
426 
GetMetaString(uint32_t id) const427 const char* MetaTable::GetMetaString(uint32_t id) const
428 {
429 	Data *data = FindMeta(id);
430 	if(!data)
431 		return NULL;
432 	return data->value.string;
433 }
434 
IsInherited(uint32_t id)435 bool MetaTable::IsInherited(uint32_t id)
436 {
437 	Data *data = FindMetaData(id);
438 	return data->inherited;
439 }
440 
SetMetaInt(uint32_t id,int value)441 void MetaTable::SetMetaInt(uint32_t id, int value)
442 {
443 	Data *data = FindMetaData(id);
444 	data->SetType(MetaTable::INTEGER);
445 	data->value.integer = value;
446 }
447 
SetMetaFixed(uint32_t id,fixed value)448 void MetaTable::SetMetaFixed(uint32_t id, fixed value)
449 {
450 	Data *data = FindMetaData(id);
451 	data->SetType(MetaTable::FIXED);
452 	data->value.fixedPoint = value;
453 }
454 
SetMetaString(uint32_t id,const char * value)455 void MetaTable::SetMetaString(uint32_t id, const char* value)
456 {
457 	Data *data = FindMetaData(id);
458 	if(data->type == MetaTable::STRING && data->value.string != NULL)
459 		delete[] data->value.string;
460 	else
461 		data->SetType(MetaTable::STRING);
462 
463 	data->value.string = new char[strlen(value)+1];
464 	strcpy(data->value.string, value);
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////
468 
469 static TMap<int, ClassDef *> EditorNumberTable, ConversationIDTable;
470 SymbolTable ClassDef::globalSymbols;
471 bool ClassDef::bShutdown = false;
472 
ClassDef()473 ClassDef::ClassDef() : tentative(false)
474 {
475 	defaultInstance = NULL;
476 	FlatPointers = Pointers = NULL;
477 	replacement = replacee = NULL;
478 }
479 
~ClassDef()480 ClassDef::~ClassDef()
481 {
482 	if(defaultInstance)
483 	{
484 		M_Free(defaultInstance);
485 	}
486 	for(unsigned int i = 0;i < symbols.Size();++i)
487 		delete symbols[i];
488 }
489 
ClassTable()490 TMap<FName, ClassDef *> &ClassDef::ClassTable()
491 {
492 	static TMap<FName, ClassDef *> classTable;
493 	return classTable;
494 }
495 
496 const size_t ClassDef::POINTER_END = ~(size_t)0;
497 // [BL] Pulled from ZDoom more or less.
498 /*
499 ** dobjtype.cpp
500 ** Implements the type information class
501 **
502 **---------------------------------------------------------------------------
503 ** Copyright 1998-2008 Randy Heit
504 ** All rights reserved.
505 **
506 ** Redistribution and use in source and binary forms, with or without
507 ** modification, are permitted provided that the following conditions
508 ** are met:
509 **
510 ** 1. Redistributions of source code must retain the above copyright
511 **    notice, this list of conditions and the following disclaimer.
512 ** 2. Redistributions in binary form must reproduce the above copyright
513 **    notice, this list of conditions and the following disclaimer in the
514 **    documentation and/or other materials provided with the distribution.
515 ** 3. The name of the author may not be used to endorse or promote products
516 **    derived from this software without specific prior written permission.
517 **
518 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
519 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
520 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
521 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
522 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
523 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
524 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
525 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
526 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
527 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
528 **---------------------------------------------------------------------------
529 **
530 */
531 // Create the FlatPointers array, if it doesn't exist already.
532 // It comprises all the Pointers from superclasses plus this class's own Pointers.
533 // If this class does not define any new Pointers, then FlatPointers will be set
534 // to the same array as the super class's.
BuildFlatPointers()535 void ClassDef::BuildFlatPointers()
536 {
537 	if (FlatPointers != NULL)
538 	{ // Already built: Do nothing.
539 		return;
540 	}
541 	else if (parent == NULL)
542 	{ // No parent: FlatPointers is the same as Pointers.
543 		if (Pointers == NULL)
544 		{ // No pointers: Make FlatPointers a harmless non-NULL.
545 			FlatPointers = &POINTER_END;
546 		}
547 		else
548 		{
549 			FlatPointers = Pointers;
550 		}
551 	}
552 	else
553 	{
554 		const_cast<ClassDef *>(parent)->BuildFlatPointers ();
555 		if (Pointers == NULL)
556 		{ // No new pointers: Just use the same FlatPointers as the parent.
557 			FlatPointers = parent->FlatPointers;
558 		}
559 		else
560 		{ // New pointers: Create a new FlatPointers array and add them.
561 			int numPointers, numSuperPointers;
562 
563 			// Count pointers defined by this class.
564 			for (numPointers = 0; Pointers[numPointers] != POINTER_END; numPointers++)
565 			{ }
566 			// Count pointers defined by superclasses.
567 			for (numSuperPointers = 0; parent->FlatPointers[numSuperPointers] != POINTER_END; numSuperPointers++)
568 			{ }
569 
570 			// Concatenate them into a new array
571 			size_t *flat = new size_t[numPointers + numSuperPointers + 1];
572 			if (numSuperPointers > 0)
573 			{
574 				memcpy (flat, parent->FlatPointers, sizeof(size_t)*numSuperPointers);
575 			}
576 			memcpy (flat + numSuperPointers, Pointers, sizeof(size_t)*(numPointers+1));
577 			FlatPointers = flat;
578 		}
579 	}
580 }
581 
CreateInstance() const582 AActor *ClassDef::CreateInstance() const
583 {
584 	if(IsDescendantOf(NATIVE_CLASS(Actor)) && !((AActor*)defaultInstance)->SpawnState)
585 	{
586 		((AActor*)defaultInstance)->MeleeState = FindState(NAME_Melee);
587 		((AActor*)defaultInstance)->MissileState = FindState(NAME_Missile);
588 		((AActor*)defaultInstance)->PainState = FindState(NAME_Pain);
589 		((AActor*)defaultInstance)->PathState = FindState(NAME_Path);
590 		((AActor*)defaultInstance)->SpawnState = FindState(NAME_Spawn);
591 		((AActor*)defaultInstance)->SeeState = FindState(NAME_See);
592 	}
593 
594 	AActor *newactor = (AActor *) M_Malloc(size);
595 	memcpy((void*)newactor, (void*)defaultInstance, size);
596 	ConstructNative(this, newactor);
597 	newactor->Init();
598 	return newactor;
599 }
600 
FindClass(unsigned int ednum)601 const ClassDef *ClassDef::FindClass(unsigned int ednum)
602 {
603 	ClassDef **ret = EditorNumberTable.CheckKey(ednum);
604 	if(ret == NULL)
605 		return NULL;
606 	return *ret;
607 }
608 
FindClass(const FName & className)609 const ClassDef *ClassDef::FindClass(const FName &className)
610 {
611 	ClassDef **ret = ClassTable().CheckKey(className);
612 	if(ret == NULL)
613 		return NULL;
614 	return *ret;
615 }
616 
FindConversationClass(unsigned int convid)617 const ClassDef *ClassDef::FindConversationClass(unsigned int convid)
618 {
619 	ClassDef **ret = ConversationIDTable.CheckKey(convid);
620 	if(ret == NULL)
621 		return NULL;
622 	return *ret;
623 }
624 
FindClassTentative(const FName & className,const ClassDef * parent)625 const ClassDef *ClassDef::FindClassTentative(const FName &className, const ClassDef *parent)
626 {
627 	const ClassDef *search = FindClass(className);
628 	if(search)
629 	{
630 		if(!search->parent->IsDescendantOf(parent))
631 			I_Error("%s does not inherit %s!", className.GetChars(), parent->GetName().GetChars());
632 		return search;
633 	}
634 
635 	ClassDef *newClass = new ClassDef();
636 	ClassTable()[className] = newClass;
637 
638 	newClass->tentative = true;
639 	newClass->name = className;
640 	newClass->parent = parent;
641 	return newClass;
642 }
643 
FindFunction(const FName & function,int & specialNum) const644 const ActionInfo *ClassDef::FindFunction(const FName &function, int &specialNum) const
645 {
646 	Specials::LineSpecials special = Specials::LookupFunctionNum(function);
647 	if(special != Specials::NUM_POSSIBLE_SPECIALS)
648 	{
649 		specialNum = special;
650 		return FindFunction("A_CallSpecial", specialNum);
651 	}
652 
653 	if(actions.Size() != 0)
654 	{
655 		ActionInfo *func = LookupFunction(function, &actions);
656 		if(func)
657 			return func;
658 	}
659 	if(parent)
660 		return parent->FindFunction(function, specialNum);
661 	return NULL;
662 }
663 
FindState(const FName & stateName) const664 const Frame *ClassDef::FindState(const FName &stateName) const
665 {
666 	const Frame *ret = FindStateInList(stateName);
667 	return ret;
668 }
669 
FindStateInList(const FName & stateName) const670 const Frame *ClassDef::FindStateInList(const FName &stateName) const
671 {
672 	const unsigned int *ret = stateList.CheckKey(stateName);
673 	if(ret == NULL)
674 		return (!parent ? NULL : parent->FindStateInList(stateName));
675 
676 	// Change the frameLists
677 	return ResolveStateIndex(*ret);
678 }
679 
FindSymbol(const FName & symbol) const680 Symbol *ClassDef::FindSymbol(const FName &symbol) const
681 {
682 	unsigned int min = 0;
683 	unsigned int max = symbols.Size()-1;
684 	unsigned int mid = max/2;
685 	if(symbols.Size() > 0)
686 	{
687 		do
688 		{
689 			if(symbols[mid]->GetName() == symbol)
690 				return symbols[mid];
691 
692 			if(symbols[mid]->GetName() > symbol)
693 				max = mid-1;
694 			else if(symbols[mid]->GetName() < symbol)
695 				min = mid+1;
696 			mid = (min+max)/2;
697 		}
698 		while(max >= min && max < symbols.Size());
699 	}
700 
701 	if(parent)
702 		return parent->FindSymbol(symbol);
703 	else if(globalSymbols.Size() > 0)
704 	{
705 		// Search globals.
706 		min = 0;
707 		max = globalSymbols.Size()-1;
708 		mid = max/2;
709 		do
710 		{
711 			if(globalSymbols[mid]->GetName() == symbol)
712 				return globalSymbols[mid];
713 
714 			if(globalSymbols[mid]->GetName() > symbol)
715 				max = mid-1;
716 			else if(globalSymbols[mid]->GetName() < symbol)
717 				min = mid+1;
718 			mid = (min+max)/2;
719 		}
720 		while(max >= min && max < globalSymbols.Size());
721 	}
722 	return NULL;
723 }
724 
GetReplacement(bool respectMapinfo) const725 const ClassDef *ClassDef::GetReplacement(bool respectMapinfo) const
726 {
727 	return replacement ? replacement->GetReplacement(false) : this;
728 }
729 
730 struct Goto
731 {
732 	public:
733 		Frame		*frame;
734 		FString		remapLabel; // Label: goto Label2
735 		StateLabel	jumpLabel;
736 };
InstallStates(const TArray<StateDefinition> & stateDefs)737 void ClassDef::InstallStates(const TArray<StateDefinition> &stateDefs)
738 {
739 	// We need to resolve gotos after we install the states.
740 	TArray<Goto> gotos;
741 
742 	// Count the number of states we need so that we can allocate the memory
743 	// in one go and keep our pointers valid.
744 	unsigned int numStates = 0;
745 	for(unsigned int iter = 0;iter < stateDefs.Size();++iter)
746 	{
747 		if(!stateDefs[iter].label.IsEmpty() && stateDefs[iter].sprite[0] == 0)
748 			continue;
749 		numStates += (unsigned int)stateDefs[iter].frames.Len();
750 	}
751 	frameList.Resize(numStates);
752 
753 	FString thisLabel;
754 	Frame *prevFrame = NULL;
755 	Frame *loopPoint = NULL;
756 	Frame *thisFrame = &frameList[0];
757 	for(unsigned int iter = 0;iter < stateDefs.Size();++iter)
758 	{
759 		const StateDefinition &thisStateDef = stateDefs[iter];
760 
761 		// Special case, `Label: stop`, remove state.  Hmm... I wonder if ZDoom handles fall throughs on this.
762 		if(!thisStateDef.label.IsEmpty() && thisStateDef.sprite[0] == 0)
763 		{
764 			switch(thisStateDef.nextType)
765 			{
766 				case StateDefinition::STOP:
767 					stateList[thisStateDef.label] = INT_MAX;
768 					break;
769 				case StateDefinition::NORMAL:
770 					stateList[thisStateDef.label] = (unsigned int)(thisFrame - &frameList[0]);
771 					continue;
772 				case StateDefinition::GOTO:
773 				{
774 					Goto thisGoto;
775 					thisGoto.frame = NULL;
776 					thisGoto.remapLabel = thisStateDef.label;
777 					thisGoto.jumpLabel = thisStateDef.jumpLabel;
778 					gotos.Push(thisGoto);
779 					continue;
780 				}
781 				default:
782 					Quit("Tried to use a loop on a frameless state.\n");
783 					break;
784 			}
785 			continue;
786 		}
787 
788 		for(unsigned int i = 0;i < thisStateDef.frames.Len();++i)
789 		{
790 			if(i == 0 && !thisStateDef.label.IsEmpty())
791 			{
792 				stateList[thisStateDef.label] = (unsigned int)(thisFrame - &frameList[0]);
793 				loopPoint = thisFrame;
794 			}
795 			memcpy(thisFrame->sprite, thisStateDef.sprite, 4);
796 			thisFrame->frame = thisStateDef.frames[i]-'A';
797 			thisFrame->duration = thisStateDef.duration;
798 			thisFrame->randDuration = thisStateDef.randDuration;
799 			thisFrame->fullbright = thisStateDef.fullbright;
800 			thisFrame->action = thisStateDef.functions[0];
801 			thisFrame->thinker = thisStateDef.functions[1];
802 			thisFrame->next = NULL;
803 			thisFrame->index = (unsigned int)(thisFrame - &frameList[0]);
804 			thisFrame->spriteInf = 0;
805 			// Only free the action arguments if we are the last frame using them.
806 			thisFrame->freeActionArgs = i == thisStateDef.frames.Len()-1;
807 			if(i == thisStateDef.frames.Len()-1) // Handle nextType
808 			{
809 				if(thisStateDef.nextType == StateDefinition::WAIT)
810 					thisFrame->next = thisFrame;
811 				else if(thisStateDef.nextType == StateDefinition::LOOP)
812 					thisFrame->next = loopPoint;
813 				// Add to goto list
814 				else if(thisStateDef.nextType == StateDefinition::GOTO)
815 				{
816 					Goto thisGoto;
817 					thisGoto.frame = thisFrame;
818 					thisGoto.jumpLabel = thisStateDef.jumpLabel;
819 					gotos.Push(thisGoto);
820 				}
821 			}
822 			if(prevFrame != NULL)
823 				prevFrame->next = thisFrame;
824 
825 			if(thisStateDef.nextType == StateDefinition::NORMAL || i != thisStateDef.frames.Len()-1)
826 				prevFrame = thisFrame;
827 			else
828 				prevFrame = NULL;
829 			//printf("Adding frame: %s %c %d\n", thisStateDef.sprite, thisFrame->frame, thisFrame->duration);
830 			++thisFrame;
831 		}
832 	}
833 
834 	// Safe guard to make sure state counting stays in sync
835 	assert(thisFrame == &frameList[frameList.Size()]);
836 
837 	// Resolve Gotos
838 	for(unsigned int iter = 0;iter < gotos.Size();++iter)
839 	{
840 		const Frame *result = gotos[iter].jumpLabel.Resolve();
841 		if(gotos[iter].frame)
842 			gotos[iter].frame->next = result;
843 		else
844 		{
845 			unsigned int frameIndex = result->index;
846 			const ClassDef *owner = this;
847 			while(!owner->IsStateOwner(result))
848 			{
849 				frameIndex += owner->frameList.Size();
850 				owner = owner->parent;
851 			}
852 			stateList[gotos[iter].remapLabel] = frameIndex;
853 		}
854 	}
855 }
856 
IsDescendantOf(const ClassDef * parent) const857 bool ClassDef::IsDescendantOf(const ClassDef *parent) const
858 {
859 	const ClassDef *currentParent = this;
860 	while(currentParent != NULL)
861 	{
862 		if(currentParent == parent)
863 			return true;
864 		currentParent = currentParent->parent;
865 	}
866 	return false;
867 }
868 
LoadActors()869 void ClassDef::LoadActors()
870 {
871 	printf("ClassDef: Loading actor definitions.\n");
872 	atterm(&ClassDef::UnloadActors);
873 
874 	// First iterate through the native classes and fix their parent pointers
875 	// In order to keep things simple what I did was in DeclareNativeClass I
876 	// force a const ClassDef ** into the parent, so we just need to cast back
877 	// and get the value of the pointer.
878 	{
879 		TMap<FName, ClassDef *>::Iterator iter(ClassTable());
880 		TMap<FName, ClassDef *>::Pair *pair;
881 		while(iter.NextPair(pair))
882 		{
883 			ClassDef * const cls = pair->Value;
884 			if(cls->parent)
885 				cls->parent = *(const ClassDef **)cls->parent;
886 		}
887 	}
888 
889 	InitFunctionTable(NULL);
890 
891 	// Add function symbols
892 	const ExpressionFunction *func = functions;
893 	do
894 	{
895 		globalSymbols.Push(new FunctionSymbol(func->name, TypeHierarchy::staticTypes.GetType(TypeHierarchy::PrimitiveTypes(func->ret)), func->args, func->function, func->takesRNG));
896 	}
897 	while((++func)->name != NULL);
898 	qsort(&globalSymbols[0], globalSymbols.Size(), sizeof(globalSymbols[0]), SymbolCompare);
899 
900 	int lastLump = 0;
901 	int lump = 0;
902 	while((lump = Wads.FindLump("DECORATE", &lastLump)) != -1)
903 	{
904 		ParseDecorateLump(lump);
905 	}
906 
907 	ReleaseFunctionTable();
908 	delete symbolPool;
909 #if 0
910 	// Debug code - Dump actor tree visually.
911 	DumpClasses();
912 #endif
913 
914 	R_InitSprites();
915 
916 	{
917 		unsigned int index = 0;
918 
919 		TMap<FName, ClassDef *>::Iterator iter(ClassTable());
920 		TMap<FName, ClassDef *>::Pair *pair;
921 		while(iter.NextPair(pair))
922 		{
923 			ClassDef * const cls = pair->Value;
924 
925 			if(cls->tentative)
926 			{
927 				FString error;
928 				error.Format("The actor '%s' is referenced but never defined.", cls->GetName().GetChars());
929 				throw CFatalError(error);
930 			}
931 
932 			cls->ClassIndex = index++;
933 			for(unsigned int i = 0;i < cls->frameList.Size();++i)
934 				cls->frameList[i].spriteInf = R_GetSprite(cls->frameList[i].sprite);
935 		}
936 	}
937 }
938 
ParseActor(Scanner & sc)939 void ClassDef::ParseActor(Scanner &sc)
940 {
941 	// Read the header
942 	sc.MustGetToken(TK_Identifier);
943 	ClassDef **classRef = ClassTable().CheckKey(sc->str);
944 	ClassDef *newClass;
945 	bool previouslyDefined = classRef != NULL;
946 	if(!previouslyDefined)
947 	{
948 		newClass = new ClassDef();
949 		ClassTable()[sc->str] = newClass;
950 	}
951 	else
952 		newClass = *classRef;
953 	bool native = false;
954 	newClass->name = sc->str;
955 	if(sc.CheckToken(':'))
956 	{
957 		sc.MustGetToken(TK_Identifier);
958 		const ClassDef *parent = FindClass(sc->str);
959 		if(parent == NULL || parent->tentative)
960 			sc.ScriptMessage(Scanner::ERROR, "Could not find parent actor '%s'", sc->str.GetChars());
961 		if(newClass->tentative && !parent->IsDescendantOf(newClass->parent))
962 			sc.ScriptMessage(Scanner::ERROR, "Parent for actor expected to be '%s'", newClass->parent->GetName().GetChars());
963 		newClass->parent = parent;
964 	}
965 	else
966 	{
967 		// If no class was specified to inherit from, inherit from AActor, but not for AActor.
968 		if(newClass != NATIVE_CLASS(Actor))
969 			newClass->parent = NATIVE_CLASS(Actor);
970 	}
971 
972 	// Handle class replacements
973 	if(sc.CheckToken(TK_Identifier))
974 	{
975 		if(sc->str.CompareNoCase("replaces") == 0)
976 		{
977 			sc.MustGetToken(TK_Identifier);
978 
979 			if(sc->str.CompareNoCase(newClass->name) == 0)
980 				sc.ScriptMessage(Scanner::ERROR, "Actor '%s' attempting to replace itself!", sc->str.GetChars());
981 
982 			ClassDef *replacee = const_cast<ClassDef *>(FindClassTentative(sc->str, NATIVE_CLASS(Actor)));
983 			replacee->replacement = newClass;
984 			newClass->replacee = replacee;
985 		}
986 		else
987 			sc.Rewind();
988 	}
989 
990 	if(sc.CheckToken(TK_IntConst))
991 	{
992 		if(EditorNumberTable.CheckKey(sc->number) != NULL)
993 			sc.ScriptMessage(Scanner::WARNING, "Overwriting editor number %d previously assigned to '%s', use replaces instead.", sc->number, EditorNumberTable[sc->number]->GetName().GetChars());
994 		EditorNumberTable[sc->number] = newClass;
995 	}
996 	if(sc.CheckToken(TK_Identifier))
997 	{
998 		if(sc->str.CompareNoCase("native") == 0)
999 			native = true;
1000 		else
1001 			sc.ScriptMessage(Scanner::ERROR, "Unknown keyword '%s'.", sc->str.GetChars());
1002 	}
1003 	if(previouslyDefined && !native && !newClass->tentative)
1004 		sc.ScriptMessage(Scanner::ERROR, "Actor '%s' already defined.", newClass->name.GetChars());
1005 	else
1006 		newClass->tentative = false;
1007 
1008 	if(!native) // Initialize the default instance to the nearest native class.
1009 	{
1010 		newClass->ConstructNative = newClass->parent->ConstructNative;
1011 		newClass->size = newClass->parent->size;
1012 
1013 		newClass->defaultInstance = (DObject *) M_Malloc(newClass->parent->size);
1014 		memcpy((void*)newClass->defaultInstance, (void*)newClass->parent->defaultInstance, newClass->parent->size);
1015 	}
1016 	else
1017 	{
1018 		// This could happen if a non-native actor is declared native or
1019 		// possibly in the case of a stuck dependency.
1020 		if(!newClass->defaultInstance)
1021 			sc.ScriptMessage(Scanner::ERROR, "Uninitialized default instance for '%s'.", newClass->GetName().GetChars());
1022 
1023 		// Copy the parents defaults for native classes
1024 		if(newClass->parent)
1025 			memcpy((void*)newClass->defaultInstance, (void*)newClass->parent->defaultInstance, newClass->parent->size);
1026 	}
1027 	// Copy properties and flags.
1028 	if(newClass->parent != NULL)
1029 	{
1030 		memcpy((void*)newClass->defaultInstance, (void*)newClass->parent->defaultInstance, newClass->parent->size);
1031 		newClass->defaultInstance->Class = newClass;
1032 		newClass->Meta = newClass->parent->Meta;
1033 	}
1034 
1035 	bool actionsSorted = true;
1036 	sc.MustGetToken('{');
1037 	while(!sc.CheckToken('}'))
1038 	{
1039 		if(sc.CheckToken('+') || sc.CheckToken('-'))
1040 		{
1041 			bool set = sc->token == '+';
1042 			FString prefix;
1043 			sc.MustGetToken(TK_Identifier);
1044 			FString flagName = sc->str;
1045 			if(sc.CheckToken('.'))
1046 			{
1047 				prefix = flagName;
1048 				sc.MustGetToken(TK_Identifier);
1049 				flagName = sc->str;
1050 			}
1051 			if(!SetFlag(newClass, (AActor*)newClass->defaultInstance, prefix, flagName, set))
1052 				sc.ScriptMessage(Scanner::WARNING, "Unknown flag '%s' for actor '%s'.", flagName.GetChars(), newClass->name.GetChars());
1053 		}
1054 		else
1055 		{
1056 			sc.MustGetToken(TK_Identifier);
1057 			if(sc->str.CompareNoCase("states") == 0)
1058 			{
1059 				if(!actionsSorted)
1060 					InitFunctionTable(&newClass->actions);
1061 
1062 				TArray<StateDefinition> stateDefs;
1063 
1064 				sc.MustGetToken('{');
1065 				//sc.MustGetToken(TK_Identifier); // We should already have grabbed the identifier in all other cases.
1066 				bool needIdentifier = true;
1067 				bool infiniteLoopProtection = false;
1068 				while(sc->token != '}' && !sc.CheckToken('}'))
1069 				{
1070 					StateDefinition thisState;
1071 					thisState.sprite[0] = thisState.sprite[4] = 0;
1072 					thisState.duration = 0;
1073 					thisState.randDuration = 0;
1074 					thisState.nextType = StateDefinition::NORMAL;
1075 
1076 					if(needIdentifier)
1077 						sc.MustGetToken(TK_Identifier);
1078 					else
1079 						needIdentifier = true;
1080 					FString stateString = sc->str;
1081 					if(sc.CheckToken(':'))
1082 					{
1083 						infiniteLoopProtection = false;
1084 						thisState.label = stateString;
1085 						// New state
1086 						if(sc.CheckToken('}'))
1087 							sc.ScriptMessage(Scanner::ERROR, "State defined with no frames.");
1088 						sc.MustGetToken(TK_Identifier);
1089 
1090 						if(sc->str.CompareNoCase("stop") == 0)
1091 						{
1092 							thisState.nextType = StateDefinition::STOP;
1093 							if(!sc.CheckToken('}'))
1094 								sc.MustGetToken(TK_Identifier);
1095 						}
1096 						else if(sc->str.CompareNoCase("goto") == 0)
1097 						{
1098 							thisState.jumpLabel = StateLabel(sc, newClass, true);
1099 							thisState.nextType = StateDefinition::GOTO;
1100 							if(!sc.CheckToken('}'))
1101 								sc.MustGetToken(TK_Identifier);
1102 						}
1103 
1104 						stateString = sc->str;
1105 					}
1106 
1107 					if(thisState.nextType == StateDefinition::NORMAL &&
1108 						(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_StringConst)))
1109 					{
1110 						bool invalidSprite = (stateString.Len() != 4);
1111 						strncpy(thisState.sprite, stateString, 4);
1112 
1113 						infiniteLoopProtection = false;
1114 						if(invalidSprite) // We now know this is a frame so check sprite length
1115 							sc.ScriptMessage(Scanner::ERROR, "Sprite name must be exactly 4 characters long.");
1116 
1117 						R_LoadSprite(thisState.sprite);
1118 						thisState.frames = sc->str;
1119 						if(sc.CheckToken('-'))
1120 						{
1121 							sc.MustGetToken(TK_FloatConst);
1122 							thisState.duration = -1;
1123 						}
1124 						else
1125 						{
1126 							if(sc.CheckToken(TK_FloatConst))
1127 							{
1128 								// Eliminate confusion about fractional frame delays
1129 								if(!CheckTicsValid(sc->decimal))
1130 									sc.ScriptMessage(Scanner::ERROR, "Fractional frame durations must be exactly .5!");
1131 
1132 								thisState.duration = static_cast<int> (sc->decimal*2);
1133 							}
1134 							else if(stricmp(thisState.sprite, "goto") == 0)
1135 							{
1136 								thisState.nextType = StateDefinition::GOTO;
1137 								thisState.nextArg = thisState.frames;
1138 								thisState.frames = FString();
1139 							}
1140 							else if(sc.CheckToken(TK_Identifier))
1141 							{
1142 								if(sc->str.CompareNoCase("random") != 0)
1143 									sc.ScriptMessage(Scanner::ERROR, "Expected random frame duration.");
1144 
1145 								sc.MustGetToken('(');
1146 								sc.MustGetToken(TK_FloatConst);
1147 								if(!CheckTicsValid(sc->decimal))
1148 									sc.ScriptMessage(Scanner::ERROR, "Fractional frame durations must be exactly .5!");
1149 								thisState.duration = static_cast<int> (sc->decimal*2);
1150 								sc.MustGetToken(',');
1151 								sc.MustGetToken(TK_FloatConst);
1152 								if(!CheckTicsValid(sc->decimal))
1153 									sc.ScriptMessage(Scanner::ERROR, "Fractional frame durations must be exactly .5!");
1154 								thisState.randDuration = static_cast<int> (sc->decimal*2);
1155 								sc.MustGetToken(')');
1156 							}
1157 							else
1158 								sc.ScriptMessage(Scanner::ERROR, "Expected frame duration.");
1159 						}
1160 						thisState.functions[0].pointer = thisState.functions[1].pointer = NULL;
1161 						thisState.fullbright = false;
1162 
1163 						do
1164 						{
1165 							if(sc.CheckToken('}'))
1166 								goto FinishState;
1167 							else
1168 								sc.MustGetToken(TK_Identifier);
1169 
1170 							if(sc->str.CompareNoCase("bright") == 0)
1171 								thisState.fullbright = true;
1172 							else
1173 								break;
1174 						}
1175 						while(true);
1176 
1177 						if(thisState.nextType == StateDefinition::NORMAL)
1178 						{
1179 							for(int func = 0;func <= 2;func++)
1180 							{
1181 								if(sc.CheckToken(':'))
1182 								{
1183 									// We have a state label!
1184 									needIdentifier = false;
1185 									sc.Rewind();
1186 									break;
1187 								}
1188 								if(sc->str.Len() == 4 || func == 2)
1189 								{
1190 									if(sc->str.CompareNoCase("goto") == 0)
1191 									{
1192 										thisState.jumpLabel = StateLabel(sc, newClass, true);
1193 										thisState.nextType = StateDefinition::GOTO;
1194 									}
1195 									else if(sc->str.CompareNoCase("wait") == 0 || sc->str.CompareNoCase("fail") == 0)
1196 									{
1197 										thisState.nextType = StateDefinition::WAIT;
1198 									}
1199 									else if(sc->str.CompareNoCase("loop") == 0)
1200 									{
1201 										thisState.nextType = StateDefinition::LOOP;
1202 									}
1203 									else if(sc->str.CompareNoCase("stop") == 0)
1204 									{
1205 										thisState.nextType = StateDefinition::STOP;
1206 									}
1207 									else
1208 										needIdentifier = false;
1209 									break;
1210 								}
1211 								else
1212 								{
1213 									if(sc->str.CompareNoCase("NOP") != 0)
1214 									{
1215 										int specialNum = -1;
1216 										const ActionInfo *funcInf = newClass->FindFunction(sc->str, specialNum);
1217 										if(funcInf)
1218 										{
1219 											thisState.functions[func].pointer = *funcInf->func;
1220 
1221 											CallArguments *&ca = thisState.functions[func].args;
1222 											ca = new CallArguments();
1223 											CallArguments::Value val;
1224 											unsigned int argc = 0;
1225 
1226 											// When using a line special we have to inject a parameter.
1227 											if(specialNum >= 0)
1228 											{
1229 												val.useType = CallArguments::Value::VAL_INTEGER;
1230 												val.isExpression = false;
1231 												val.val.i = specialNum;
1232 												ca->AddArgument(val);
1233 												++argc;
1234 											}
1235 
1236 											if(sc.CheckToken('('))
1237 											{
1238 												if(funcInf->maxArgs == 0)
1239 													sc.MustGetToken(')');
1240 												else if(!(funcInf->minArgs == 0 && sc.CheckToken(')')))
1241 												{
1242 													do
1243 													{
1244 														val.isExpression = false;
1245 
1246 														const Type *argType = funcInf->ArgType(argc);
1247 														if(argType == TypeHierarchy::staticTypes.GetType(TypeHierarchy::INT) ||
1248 															argType == TypeHierarchy::staticTypes.GetType(TypeHierarchy::FLOAT) ||
1249 															argType == TypeHierarchy::staticTypes.GetType(TypeHierarchy::BOOL))
1250 														{
1251 															val.isExpression = true;
1252 															if(argType == TypeHierarchy::staticTypes.GetType(TypeHierarchy::INT))
1253 																val.useType = CallArguments::Value::VAL_INTEGER;
1254 															else
1255 																val.useType = CallArguments::Value::VAL_DOUBLE;
1256 															val.expr = ExpressionNode::ParseExpression(newClass, TypeHierarchy::staticTypes, sc);
1257 														}
1258 														else if(argType == TypeHierarchy::staticTypes.GetType(TypeHierarchy::STATE))
1259 														{
1260 															val.useType = CallArguments::Value::VAL_STATE;
1261 															if(sc.CheckToken(TK_IntConst))
1262 															{
1263 																if(thisState.frames.Len() > 1)
1264 																	sc.ScriptMessage(Scanner::ERROR, "State offsets not allowed on multistate definitions.");
1265 																FString label;
1266 																label.Format("%d", sc->number);
1267 																val.label = StateLabel(label, newClass);
1268 															}
1269 															else
1270 															{
1271 																sc.MustGetToken(TK_StringConst);
1272 																val.label = StateLabel(sc->str, newClass);
1273 															}
1274 														}
1275 														else
1276 														{
1277 															sc.MustGetToken(TK_StringConst);
1278 															val.useType = CallArguments::Value::VAL_STRING;
1279 															val.str = sc->str;
1280 														}
1281 														ca->AddArgument(val);
1282 														++argc;
1283 
1284 														// Check if we can or should take another argument
1285 														if(!funcInf->varArgs && argc >= funcInf->maxArgs)
1286 															break;
1287 													}
1288 													while(sc.CheckToken(','));
1289 													sc.MustGetToken(')');
1290 												}
1291 											}
1292 											if(argc < funcInf->minArgs)
1293 												sc.ScriptMessage(Scanner::ERROR, "Too few arguments.");
1294 											else
1295 											{
1296 												// Push unused defaults.
1297 												while(argc < funcInf->maxArgs)
1298 													ca->AddArgument(funcInf->defaults[(argc++)-funcInf->minArgs]);
1299 											}
1300 										}
1301 										else
1302 											sc.ScriptMessage(Scanner::WARNING, "Could not find function %s.", sc->str.GetChars());
1303 									}
1304 								}
1305 
1306 								if(!sc.CheckToken(TK_Identifier))
1307 									break;
1308 								else if(sc.CheckToken(':'))
1309 								{
1310 									needIdentifier = false;
1311 									sc.Rewind();
1312 									break;
1313 								}
1314 							}
1315 						}
1316 					}
1317 					else
1318 					{
1319 						thisState.sprite[0] = 0;
1320 						needIdentifier = false;
1321 						if(infiniteLoopProtection)
1322 							sc.ScriptMessage(Scanner::ERROR, "Malformed script.");
1323 						infiniteLoopProtection = true;
1324 					}
1325 				FinishState:
1326 					stateDefs.Push(thisState);
1327 				}
1328 
1329 				newClass->InstallStates(stateDefs);
1330 			}
1331 			else if(sc->str.CompareNoCase("action") == 0)
1332 			{
1333 				actionsSorted = false;
1334 				sc.MustGetToken(TK_Identifier);
1335 				if(sc->str.CompareNoCase("native") != 0)
1336 					sc.ScriptMessage(Scanner::ERROR, "Custom actions not supported.");
1337 				sc.MustGetToken(TK_Identifier);
1338 				ActionInfo *funcInf = LookupFunction(sc->str, NULL);
1339 				if(!funcInf)
1340 					sc.ScriptMessage(Scanner::ERROR, "The specified function %s could not be located.", sc->str.GetChars());
1341 				newClass->actions.Push(funcInf);
1342 				sc.MustGetToken('(');
1343 				if(!sc.CheckToken(')'))
1344 				{
1345 					bool optRequired = false;
1346 					do
1347 					{
1348 						// If we have processed at least one argument, then we can take varArgs.
1349 						if(funcInf->minArgs > 0 && sc.CheckToken(TK_Ellipsis))
1350 						{
1351 							funcInf->varArgs = true;
1352 							break;
1353 						}
1354 
1355 						sc.MustGetToken(TK_Identifier);
1356 						const Type *type = TypeHierarchy::staticTypes.GetType(sc->str);
1357 						if(type == NULL)
1358 							sc.ScriptMessage(Scanner::ERROR, "Unknown type %s.\n", sc->str.GetChars());
1359 						funcInf->types.Push(type);
1360 
1361 						if(sc->str.CompareNoCase("class") == 0)
1362 						{
1363 							sc.MustGetToken('<');
1364 							sc.MustGetToken(TK_Identifier);
1365 							sc.MustGetToken('>');
1366 						}
1367 						sc.MustGetToken(TK_Identifier);
1368 						if(optRequired || sc.CheckToken('='))
1369 						{
1370 							if(optRequired)
1371 								sc.MustGetToken('=');
1372 							else
1373 								optRequired = true;
1374 
1375 							CallArguments::Value defVal;
1376 							defVal.isExpression = false;
1377 
1378 							if(type == TypeHierarchy::staticTypes.GetType(TypeHierarchy::INT) ||
1379 								type == TypeHierarchy::staticTypes.GetType(TypeHierarchy::FLOAT)
1380 							)
1381 							{
1382 								ExpressionNode *node = ExpressionNode::ParseExpression(newClass, TypeHierarchy::staticTypes, sc);
1383 								const ExpressionNode::Value &val = node->Evaluate(NULL);
1384 								if(type == TypeHierarchy::staticTypes.GetType(TypeHierarchy::INT))
1385 								{
1386 									defVal.useType = CallArguments::Value::VAL_INTEGER;
1387 									defVal.val.i = val.GetInt();
1388 								}
1389 								else
1390 								{
1391 									defVal.useType = CallArguments::Value::VAL_DOUBLE;
1392 									defVal.val.d = val.GetDouble();
1393 								}
1394 								delete node;
1395 							}
1396 							else if(type == TypeHierarchy::staticTypes.GetType(TypeHierarchy::BOOL))
1397 							{
1398 								sc.MustGetToken(TK_BoolConst);
1399 								defVal.useType = CallArguments::Value::VAL_INTEGER;
1400 								defVal.val.i = sc->boolean;
1401 							}
1402 							else if(type == TypeHierarchy::staticTypes.GetType(TypeHierarchy::STATE))
1403 							{
1404 								defVal.useType = CallArguments::Value::VAL_STATE;
1405 								if(sc.CheckToken(TK_IntConst))
1406 									sc.ScriptMessage(Scanner::ERROR, "State offsets not allowed for defaults.");
1407 								else
1408 								{
1409 									sc.MustGetToken(TK_StringConst);
1410 									defVal.label = StateLabel(sc->str, newClass);
1411 								}
1412 							}
1413 							else
1414 							{
1415 								sc.MustGetToken(TK_StringConst);
1416 								defVal.useType = CallArguments::Value::VAL_STRING;
1417 								defVal.str = sc->str;
1418 							}
1419 							funcInf->defaults.Push(defVal);
1420 						}
1421 						else
1422 							++funcInf->minArgs;
1423 						++funcInf->maxArgs;
1424 					}
1425 					while(sc.CheckToken(','));
1426 					sc.MustGetToken(')');
1427 				}
1428 				sc.MustGetToken(';');
1429 			}
1430 			else if(sc->str.CompareNoCase("native") == 0)
1431 			{
1432 				sc.MustGetToken(TK_Identifier);
1433 				const Type *type = TypeHierarchy::staticTypes.GetType(sc->str);
1434 				if(type == NULL)
1435 					sc.ScriptMessage(Scanner::ERROR, "Unknown type %s.\n", sc->str.GetChars());
1436 				sc.MustGetToken(TK_Identifier);
1437 				FName varName(sc->str);
1438 				const SymbolInfo *symInf = NULL;
1439 				for(unsigned int i = 0;i < symbolPool->Size();++i)
1440 				{
1441 					// I think the symbol pool will be small enough to do a
1442 					// linear search on.
1443 					if((*symbolPool)[i]->cls == newClass && (*symbolPool)[i]->var == varName)
1444 					{
1445 						symInf = (*symbolPool)[i];
1446 						break;
1447 					}
1448 				}
1449 				if(symInf == NULL)
1450 					sc.ScriptMessage(Scanner::ERROR, "Could not identify symbol %s::%s.\n", newClass->name.GetChars(), varName.GetChars());
1451 				sc.MustGetToken(';');
1452 
1453 				newClass->symbols.Push(new VariableSymbol(varName, type, symInf->offset));
1454 			}
1455 			else
1456 			{
1457 				FString className("actor");
1458 				FString propertyName = sc->str;
1459 				if(sc.CheckToken('.'))
1460 				{
1461 					className = propertyName;
1462 					sc.MustGetToken(TK_Identifier);
1463 					propertyName = sc->str;
1464 				}
1465 
1466 				if(!SetProperty(newClass, className, propertyName, sc))
1467 				{
1468 					do
1469 					{
1470 						sc.GetNextToken();
1471 					}
1472 					while(sc.CheckToken(','));
1473 					sc.ScriptMessage(Scanner::WARNING, "Unknown property '%s' for actor '%s'.", propertyName.GetChars(), newClass->name.GetChars());
1474 				}
1475 			}
1476 		}
1477 	}
1478 
1479 	// Now sort the symbol table.
1480 	qsort(&newClass->symbols[0], newClass->symbols.Size(), sizeof(newClass->symbols[0]), SymbolCompare);
1481 	if(!actionsSorted)
1482 		InitFunctionTable(&newClass->actions);
1483 
1484 	// Register conversation id into table if assigned
1485 	if(int convid = newClass->Meta.GetMetaInt(AMETA_ConversationID))
1486 		ConversationIDTable[convid] = newClass;
1487 }
1488 
ParseDecorateLump(int lumpNum)1489 void ClassDef::ParseDecorateLump(int lumpNum)
1490 {
1491 	FWadLump lump = Wads.OpenLumpNum(lumpNum);
1492 	char* data = new char[Wads.LumpLength(lumpNum)];
1493 	lump.Read(data, Wads.LumpLength(lumpNum));
1494 	Scanner sc(data, Wads.LumpLength(lumpNum));
1495 	sc.SetScriptIdentifier(Wads.GetLumpFullName(lumpNum));
1496 
1497 	while(sc.TokensLeft())
1498 	{
1499 		if(sc.CheckToken('#'))
1500 		{
1501 			sc.MustGetToken(TK_Identifier);
1502 			if(sc->str.CompareNoCase("include") != 0)
1503 				sc.ScriptMessage(Scanner::ERROR, "Expected 'include' got '%s' instead.", sc->str.GetChars());
1504 			sc.MustGetToken(TK_StringConst);
1505 
1506 			int lmp = Wads.CheckNumForFullName(sc->str, true);
1507 			if(lmp == -1)
1508 				sc.ScriptMessage(Scanner::ERROR, "Could not find lump \"%s\".", sc->str.GetChars());
1509 			ParseDecorateLump(lmp);
1510 			continue;
1511 		}
1512 
1513 		sc.MustGetToken(TK_Identifier);
1514 		if(sc->str.CompareNoCase("actor") == 0)
1515 		{
1516 			ParseActor(sc);
1517 		}
1518 		else if(sc->str.CompareNoCase("const") == 0)
1519 		{
1520 			sc.MustGetToken(TK_Identifier);
1521 			const Type *type = TypeHierarchy::staticTypes.GetType(sc->str);
1522 			if(type == NULL)
1523 				sc.ScriptMessage(Scanner::ERROR, "Unknown type %s.\n", sc->str.GetChars());
1524 			sc.MustGetToken(TK_Identifier);
1525 			FName constName(sc->str);
1526 			sc.MustGetToken('=');
1527 			ExpressionNode *expr = ExpressionNode::ParseExpression(NATIVE_CLASS(Actor), TypeHierarchy::staticTypes, sc);
1528 			ConstantSymbol *newSym = new ConstantSymbol(constName, type, expr->Evaluate(NULL));
1529 			delete expr;
1530 			sc.MustGetToken(';');
1531 
1532 			// We must insert the constant into the table at the proper place
1533 			// now since the next const may try to reference it.
1534 			if(globalSymbols.Size() > 0)
1535 			{
1536 				unsigned int min = 0;
1537 				unsigned int max = globalSymbols.Size()-1;
1538 				unsigned int mid = max/2;
1539 				if(max > 0)
1540 				{
1541 					do
1542 					{
1543 						if(globalSymbols[mid]->GetName() > constName)
1544 							max = mid-1;
1545 						else if(globalSymbols[mid]->GetName() < constName)
1546 							min = mid+1;
1547 						else
1548 							break;
1549 						mid = (min+max)/2;
1550 					}
1551 					while(max >= min && max < globalSymbols.Size());
1552 				}
1553 				if(globalSymbols[mid]->GetName() <= constName)
1554 					++mid;
1555 				globalSymbols.Insert(mid, newSym);
1556 			}
1557 			else
1558 				globalSymbols.Push(newSym);
1559 		}
1560 		else
1561 			sc.ScriptMessage(Scanner::ERROR, "Unknown thing section '%s'.", sc->str.GetChars());
1562 	}
1563 	delete[] data;
1564 }
1565 
ResolveStateIndex(unsigned int index) const1566 const Frame *ClassDef::ResolveStateIndex(unsigned int index) const
1567 {
1568 	if(index == INT_MAX) // Deleted state (Label: stop)
1569 		return NULL;
1570 	if(index > frameList.Size() && parent)
1571 		return parent->ResolveStateIndex(index - frameList.Size());
1572 	return &frameList[index];
1573 }
1574 
SetFlag(const ClassDef * newClass,AActor * instance,const FString & prefix,const FString & flagName,bool set)1575 bool ClassDef::SetFlag(const ClassDef *newClass, AActor *instance, const FString &prefix, const FString &flagName, bool set)
1576 {
1577 	int min = 0;
1578 	int max = sizeof(flags)/sizeof(FlagDef) - 1;
1579 	while(min <= max)
1580 	{
1581 		int mid = (min+max)/2;
1582 		int ret = flagName.CompareNoCase(flags[mid].name);
1583 		if(ret == 0 && !prefix.IsEmpty())
1584 			ret = prefix.CompareNoCase(flags[mid].prefix);
1585 
1586 		if(ret == 0)
1587 		{
1588 			if(!newClass->IsDescendantOf(flags[mid].cls))
1589 				return false;
1590 
1591 			if(set)
1592 				*reinterpret_cast<flagstype_t *>((int8_t*)instance + flags[mid].varOffset) |= flags[mid].value;
1593 			else
1594 				*reinterpret_cast<flagstype_t *>((int8_t*)instance + flags[mid].varOffset) &= ~flags[mid].value;
1595 			return true;
1596 		}
1597 		else if(ret < 0)
1598 			max = mid-1;
1599 		else
1600 			min = mid+1;
1601 	}
1602 	return false;
1603 }
1604 
SetProperty(ClassDef * newClass,const char * className,const char * propName,Scanner & sc)1605 bool ClassDef::SetProperty(ClassDef *newClass, const char* className, const char* propName, Scanner &sc)
1606 {
1607 	static unsigned int NUM_PROPERTIES = 0;
1608 	if(NUM_PROPERTIES == 0)
1609 	{
1610 		// Calculate NUM_PROPERTIES if needed.
1611 		while(properties[NUM_PROPERTIES++].name != NULL)
1612 			;
1613 	}
1614 
1615 	int min = 0;
1616 	int max = NUM_PROPERTIES - 1;
1617 	while(min <= max)
1618 	{
1619 		int mid = (min+max)/2;
1620 		int ret = stricmp(properties[mid].name, propName);
1621 		if(ret == 0)
1622 		{
1623 			if(!newClass->IsDescendantOf(properties[mid].className) ||
1624 				stricmp(properties[mid].prefix, className) != 0)
1625 				sc.ScriptMessage(Scanner::ERROR, "Property %s.%s not available in this scope.\n", properties[mid].className->name.GetChars(), propName);
1626 
1627 			PropertyParam* params = new PropertyParam[strlen(properties[mid].params)];
1628 			// Key:
1629 			//   K - Keyword (Identifier)
1630 			//   I - Integer
1631 			//   F - Float
1632 			//   S - String
1633 			bool optional = false;
1634 			bool done = false;
1635 			const char* p = properties[mid].params;
1636 			unsigned int paramc = 0;
1637 			if(*p != 0)
1638 			{
1639 				do
1640 				{
1641 					if(*p != 0)
1642 					{
1643 						while(*p == '_') // Optional
1644 						{
1645 							optional = true;
1646 							p++;
1647 						}
1648 
1649 						bool negate = false;
1650 						params[paramc].i = 0; // Try to default to 0
1651 
1652 						switch(*p)
1653 						{
1654 							case 'K':
1655 								if(!optional)
1656 									sc.MustGetToken(TK_Identifier);
1657 								else if(!sc.CheckToken(TK_Identifier))
1658 								{
1659 									done = true;
1660 									break;
1661 								}
1662 								params[paramc].s = new char[sc->str.Len()+1];
1663 								strcpy(params[paramc].s, sc->str);
1664 								break;
1665 							default:
1666 							case 'I':
1667 								if(sc.CheckToken('('))
1668 								{
1669 									params[paramc].isExpression = true;
1670 									params[paramc].expr = ExpressionNode::ParseExpression(newClass, TypeHierarchy::staticTypes, sc, NULL);
1671 									sc.MustGetToken(')');
1672 									break;
1673 								}
1674 								else
1675 									params[paramc].isExpression = false;
1676 
1677 								if(sc.CheckToken('-'))
1678 									negate = true;
1679 
1680 								if(!optional) // Float also includes integers
1681 									sc.MustGetToken(TK_FloatConst);
1682 								else if(!sc.CheckToken(TK_FloatConst))
1683 								{
1684 									done = true;
1685 									break;
1686 								}
1687 								params[paramc].i = (negate ? -1 : 1) * static_cast<int64_t> (sc->decimal);
1688 								break;
1689 							case 'F':
1690 								if(sc.CheckToken('-'))
1691 									negate = true;
1692 
1693 								if(!optional)
1694 									sc.MustGetToken(TK_FloatConst);
1695 								else if(!sc.CheckToken(TK_FloatConst))
1696 								{
1697 									done = true;
1698 									break;
1699 								}
1700 								params[paramc].f = (negate ? -1 : 1) * sc->decimal;
1701 								break;
1702 							case 'S':
1703 								if(!optional)
1704 									sc.MustGetToken(TK_StringConst);
1705 								else if(!sc.CheckToken(TK_StringConst))
1706 								{
1707 									done = true;
1708 									break;
1709 								}
1710 								params[paramc].s = new char[sc->str.Len()+1];
1711 								strcpy(params[paramc].s, sc->str);
1712 								break;
1713 						}
1714 						paramc++;
1715 						p++;
1716 					}
1717 					else
1718 						sc.GetNextToken();
1719 				}
1720 				while(sc.CheckToken(','));
1721 			}
1722 			if(!optional && *p != 0 && *p != '_')
1723 				sc.ScriptMessage(Scanner::ERROR, "Not enough parameters.");
1724 
1725 			properties[mid].handler(newClass, (AActor*)newClass->defaultInstance, paramc, params);
1726 
1727 			// Clean up
1728 			p = properties[mid].params;
1729 			unsigned int i = 0;
1730 			do
1731 			{
1732 				if(*p == 'S' || *p == 'K')
1733 					delete[] params[i].s;
1734 				i++;
1735 			}
1736 			while(*(++p) != 0 && i < paramc);
1737 			delete[] params;
1738 			return true;
1739 		}
1740 		else if(ret > 0)
1741 			max = mid-1;
1742 		else
1743 			min = mid+1;
1744 	}
1745 	return false;
1746 }
1747 
UnloadActors()1748 void ClassDef::UnloadActors()
1749 {
1750 	TMap<FName, ClassDef *>::Pair *pair;
1751 
1752 	// Clean up the frames in case any expressions use the symbols
1753 	for(TMap<FName, ClassDef *>::Iterator iter(ClassTable());iter.NextPair(pair);)
1754 			pair->Value->frameList.Clear();
1755 
1756 	// Also contains code from ZDoom
1757 
1758 	bShutdown = true;
1759 
1760 	TArray<size_t *> uniqueFPs;
1761 	for(TMap<FName, ClassDef *>::Iterator iter(ClassTable());iter.NextPair(pair);)
1762 	{
1763 		ClassDef *type = pair->Value;
1764 		if (type->FlatPointers != &POINTER_END && type->FlatPointers != type->Pointers)
1765 		{
1766 			// FlatPointers are shared by many classes, so we must check for
1767 			// duplicates and only delete those that are unique.
1768 			unsigned int j;
1769 			for (j = 0; j < uniqueFPs.Size(); ++j)
1770 			{
1771 				if (type->FlatPointers == uniqueFPs[j])
1772 				{
1773 					break;
1774 				}
1775 			}
1776 			if (j == uniqueFPs.Size())
1777 			{
1778 				uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers));
1779 			}
1780 		}
1781 		type->FlatPointers = NULL;
1782 
1783 		delete type;
1784 	}
1785 	for (unsigned int i = 0; i < uniqueFPs.Size(); ++i)
1786 	{
1787 		delete[] uniqueFPs[i];
1788 	}
1789 
1790 	// Also clear globals
1791 	// but first clear the damage expression table since it relies on some of the symbols.
1792 	AActor::damageExpressions.Clear();
1793 	for(unsigned int i = 0;i < globalSymbols.Size();++i)
1794 		delete globalSymbols[i];
1795 }
1796 
1797 ////////////////////////////////////////////////////////////////////////////////
1798 
DumpClasses()1799 void ClassDef::DumpClasses()
1800 {
1801 	struct ClassTree
1802 	{
1803 		public:
1804 			ClassTree(const ClassDef *classType) : child(NULL), next(NULL), thisClass(classType)
1805 			{
1806 				ClassTree **nextChild = &child;
1807 				TMap<FName, ClassDef *>::Pair *pair;
1808 				for(TMap<FName, ClassDef *>::Iterator iter(ClassTable());iter.NextPair(pair);)
1809 				{
1810 					if(pair->Value->parent == classType)
1811 					{
1812 						*nextChild = new ClassTree(pair->Value);
1813 						nextChild = &(*nextChild)->next;
1814 					}
1815 				}
1816 			}
1817 
1818 			~ClassTree()
1819 			{
1820 				if(child != NULL)
1821 					delete child;
1822 				if(next != NULL)
1823 					delete next;
1824 			}
1825 
1826 			void Dump(int spacing)
1827 			{
1828 				for(int i = spacing;i > 0;--i)
1829 					printf("  ");
1830 				printf("%s\n", thisClass->name.GetChars());
1831 				if(child != NULL)
1832 					child->Dump(spacing+1);
1833 				if(next != NULL)
1834 					next->Dump(spacing);
1835 			}
1836 
1837 			ClassTree		*child;
1838 			ClassTree		*next;
1839 			const ClassDef	*thisClass;
1840 	};
1841 
1842 	ClassTree root(FindClass("Actor"));
1843 	root.Dump(0);
1844 }
1845 
1846 ////////////////////////////////////////////////////////////////////////////////
1847 
~CallArguments()1848 CallArguments::~CallArguments()
1849 {
1850 	for(unsigned int i = 0;i < args.Size();++i)
1851 	{
1852 		if(args[i].isExpression)
1853 			delete args[i].expr;
1854 	}
1855 }
1856 
AddArgument(const CallArguments::Value & val)1857 void CallArguments::AddArgument(const CallArguments::Value &val)
1858 {
1859 	args.Push(val);
1860 }
1861 
Evaluate(AActor * self)1862 void CallArguments::Evaluate(AActor *self)
1863 {
1864 	for(unsigned int i = 0;i < args.Size();++i)
1865 	{
1866 		if(args[i].isExpression)
1867 		{
1868 			const ExpressionNode::Value &val = args[i].expr->Evaluate(self);
1869 			if(args[i].useType == Value::VAL_INTEGER)
1870 				args[i].val.i = val.GetInt();
1871 			else
1872 				args[i].val.d = val.GetDouble();
1873 		}
1874 	}
1875 }
1876