1 /*
2 ** p_states.cpp
3 ** state management
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2008 Randy Heit
7 ** Copyright 2006-2008 Christoph Oelckers
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 **
14 ** 1. Redistributions of source code must retain the above copyright
15 **    notice, this list of conditions and the following disclaimer.
16 ** 2. Redistributions in binary form must reproduce the above copyright
17 **    notice, this list of conditions and the following disclaimer in the
18 **    documentation and/or other materials provided with the distribution.
19 ** 3. The name of the author may not be used to endorse or promote products
20 **    derived from this software without specific prior written permission.
21 **
22 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 **---------------------------------------------------------------------------
33 **
34 **
35 */
36 #include "actor.h"
37 #include "farchive.h"
38 #include "templates.h"
39 #include "cmdlib.h"
40 #include "i_system.h"
41 #include "c_dispatch.h"
42 #include "v_text.h"
43 #include "thingdef/thingdef.h"
44 
45 // Each state is owned by an actor. Actors can own any number of
46 // states, but a single state cannot be owned by more than one
47 // actor. States are archived by recording the actor they belong
48 // to and the index into that actor's list of states.
49 
50 // For NULL states, which aren't owned by any actor, the owner
51 // is recorded as AActor with the following state. AActor should
52 // never actually have this many states of its own, so this
53 // is (relatively) safe.
54 
55 #define NULL_STATE_INDEX	127
56 
57 //==========================================================================
58 //
59 //
60 //==========================================================================
61 
operator <<(FArchive & arc,FState * & state)62 FArchive &operator<< (FArchive &arc, FState *&state)
63 {
64 	const PClass *info;
65 
66 	if (arc.IsStoring ())
67 	{
68 		if (state == NULL)
69 		{
70 			arc.UserWriteClass (RUNTIME_CLASS(AActor));
71 			arc.WriteCount (NULL_STATE_INDEX);
72 			return arc;
73 		}
74 
75 		info = FState::StaticFindStateOwner (state);
76 
77 		if (info != NULL)
78 		{
79 			arc.UserWriteClass (info);
80 			arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates));
81 		}
82 		else
83 		{
84 			/* this was never working as intended.
85 			I_Error ("Cannot find owner for state %p:\n"
86 					 "%s %c%c %3d [%p] -> %p", state,
87 					 sprites[state->sprite].name,
88 					 state->GetFrame() + 'A',
89 					 state->GetFullbright() ? '*' : ' ',
90 					 state->GetTics(),
91 					 state->GetAction(),
92 					 state->GetNextState());
93 			*/
94 		}
95 	}
96 	else
97 	{
98 		const PClass *info;
99 		DWORD ofs;
100 
101 		arc.UserReadClass (info);
102 		ofs = arc.ReadCount ();
103 		if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
104 		{
105 			state = NULL;
106 		}
107 		else if (info->ActorInfo != NULL)
108 		{
109 			state = info->ActorInfo->OwnedStates + ofs;
110 		}
111 		else
112 		{
113 			state = NULL;
114 		}
115 	}
116 	return arc;
117 }
118 
119 //==========================================================================
120 //
121 // Find the actor that a state belongs to.
122 //
123 //==========================================================================
124 
StaticFindStateOwner(const FState * state)125 const PClass *FState::StaticFindStateOwner (const FState *state)
126 {
127 	for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
128 	{
129 		FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
130 		if (state >= info->OwnedStates &&
131 			state <  info->OwnedStates + info->NumOwnedStates)
132 		{
133 			return info->Class;
134 		}
135 	}
136 
137 	return NULL;
138 }
139 
140 //==========================================================================
141 //
142 // Find the actor that a state belongs to, but restrict the search to
143 // the specified type and its ancestors.
144 //
145 //==========================================================================
146 
StaticFindStateOwner(const FState * state,const FActorInfo * info)147 const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info)
148 {
149 	while (info != NULL)
150 	{
151 		if (state >= info->OwnedStates &&
152 			state <  info->OwnedStates + info->NumOwnedStates)
153 		{
154 			return info->Class;
155 		}
156 		info = info->Class->ParentClass->ActorInfo;
157 	}
158 	return NULL;
159 }
160 
161 
162 //==========================================================================
163 //
164 //
165 //==========================================================================
166 
FindLabel(FName label)167 FStateLabel *FStateLabels::FindLabel (FName label)
168 {
169 	return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label));
170 }
171 
Destroy()172 void FStateLabels::Destroy ()
173 {
174 	for(int i=0; i<NumLabels;i++)
175 	{
176 		if (Labels[i].Children != NULL)
177 		{
178 			Labels[i].Children->Destroy();
179 			free (Labels[i].Children);	// These are malloc'd, not new'd!
180 			Labels[i].Children=NULL;
181 		}
182 	}
183 }
184 
185 
186 //===========================================================================
187 //
188 // HasStates
189 //
190 // Checks whether the actor has special death states.
191 //
192 //===========================================================================
193 
HasSpecialDeathStates() const194 bool AActor::HasSpecialDeathStates () const
195 {
196 	const FActorInfo *info = GetClass()->ActorInfo;
197 
198 	if (info->StateList != NULL)
199 	{
200 		FStateLabel *slabel = info->StateList->FindLabel (NAME_Death);
201 		if (slabel != NULL && slabel->Children != NULL)
202 		{
203 			for(int i=0;i<slabel->Children->NumLabels;i++)
204 			{
205 				if (slabel->Children->Labels[i].State != NULL) return true;
206 			}
207 		}
208 	}
209 	return false;
210 }
211 
212 //==========================================================================
213 //
214 // Creates a list of names from a string. Dots are used as separator
215 //
216 //==========================================================================
217 
MakeStateNameList(const char * fname)218 TArray<FName> &MakeStateNameList(const char * fname)
219 {
220 	static TArray<FName> namelist(3);
221 	FName firstpart, secondpart;
222 	char * c;
223 
224 	// Handle the old names for the existing death states
225 	char * name = copystring(fname);
226 	firstpart = strtok(name, ".");
227 	switch (firstpart)
228 	{
229 	case NAME_Burn:
230 		firstpart = NAME_Death;
231 		secondpart = NAME_Fire;
232 		break;
233 	case NAME_Ice:
234 		firstpart = NAME_Death;
235 		secondpart = NAME_Ice;
236 		break;
237 	case NAME_Disintegrate:
238 		firstpart = NAME_Death;
239 		secondpart = NAME_Disintegrate;
240 		break;
241 	case NAME_XDeath:
242 		firstpart = NAME_Death;
243 		secondpart = NAME_Extreme;
244 		break;
245 	}
246 
247 	namelist.Clear();
248 	namelist.Push(firstpart);
249 	if (secondpart!=NAME_None) namelist.Push(secondpart);
250 
251 	while ((c = strtok(NULL, "."))!=NULL)
252 	{
253 		FName cc = c;
254 		namelist.Push(cc);
255 	}
256 	delete [] name;
257 	return namelist;
258 }
259 
260 //===========================================================================
261 //
262 // FindState (multiple names version)
263 //
264 // Finds a state that matches as many of the supplied names as possible.
265 // A state with more names than those provided does not match.
266 // A state with fewer names can match if there are no states with the exact
267 // same number of names.
268 //
269 // The search proceeds like this. For the current class, keeping matching
270 // names until there are no more. If both the argument list and the state
271 // are out of names, it's an exact match, so return it. If the state still
272 // has names, ignore it. If the argument list still has names, remember it.
273 //
274 //===========================================================================
FindState(int numnames,FName * names,bool exact) const275 FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const
276 {
277 	FStateLabels *labels = StateList;
278 	FState *best = NULL;
279 
280 	if (labels != NULL)
281 	{
282 		int count = 0;
283 		FStateLabel *slabel = NULL;
284 		FName label;
285 
286 		// Find the best-matching label for this class.
287 		while (labels != NULL && count < numnames)
288 		{
289 			label = *names++;
290 			slabel = labels->FindLabel (label);
291 
292 			if (slabel != NULL)
293 			{
294 				count++;
295 				labels = slabel->Children;
296 				best = slabel->State;
297 			}
298 			else
299 			{
300 				break;
301 			}
302 		}
303 		if (count < numnames && exact) return NULL;
304 	}
305 	return best;
306 }
307 
308 //==========================================================================
309 //
310 // Finds the state associated with the given string
311 //
312 //==========================================================================
313 
FindStateByString(const char * name,bool exact)314 FState *FActorInfo::FindStateByString(const char *name, bool exact)
315 {
316 	TArray<FName> &namelist = MakeStateNameList(name);
317 	return FindState(namelist.Size(), &namelist[0], exact);
318 }
319 
320 
321 
322 
323 //==========================================================================
324 //
325 // Search one list of state definitions for the given name
326 //
327 //==========================================================================
328 
FindStateLabelInList(TArray<FStateDefine> & list,FName name,bool create)329 FStateDefine *FStateDefinitions::FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
330 {
331 	for(unsigned i = 0; i<list.Size(); i++)
332 	{
333 		if (list[i].Label == name) return &list[i];
334 	}
335 	if (create)
336 	{
337 		FStateDefine def;
338 		def.Label = name;
339 		def.State = NULL;
340 		def.DefineFlags = SDF_NEXT;
341 		return &list[list.Push(def)];
342 	}
343 	return NULL;
344 }
345 
346 //==========================================================================
347 //
348 // Finds the address of a state label given by name.
349 // Adds the state label if it doesn't exist
350 //
351 //==========================================================================
352 
FindStateAddress(const char * name)353 FStateDefine * FStateDefinitions::FindStateAddress(const char *name)
354 {
355 	FStateDefine *statedef = NULL;
356 	TArray<FName> &namelist = MakeStateNameList(name);
357 	TArray<FStateDefine> *statelist = &StateLabels;
358 
359 	for(unsigned i = 0; i < namelist.Size(); i++)
360 	{
361 		statedef = FindStateLabelInList(*statelist, namelist[i], true);
362 		statelist = &statedef->Children;
363 	}
364 	return statedef;
365 }
366 
367 //==========================================================================
368 //
369 // Adds a new state to the curremt list
370 //
371 //==========================================================================
372 
SetStateLabel(const char * statename,FState * state,BYTE defflags)373 void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYTE defflags)
374 {
375 	FStateDefine *std = FindStateAddress(statename);
376 	std->State = state;
377 	std->DefineFlags = defflags;
378 }
379 
380 //==========================================================================
381 //
382 // Adds a new state to the current list
383 //
384 //==========================================================================
385 
AddStateLabel(const char * statename)386 void FStateDefinitions::AddStateLabel (const char *statename)
387 {
388 	intptr_t index = StateArray.Size();
389 	FStateDefine *std = FindStateAddress(statename);
390 	std->State = (FState *)(index+1);
391 	std->DefineFlags = SDF_INDEX;
392 	laststate = NULL;
393 	lastlabel = index;
394 }
395 
396 //==========================================================================
397 //
398 // Returns the index a state label points to. May only be called before
399 // installing states.
400 //
401 //==========================================================================
402 
GetStateLabelIndex(FName statename)403 int FStateDefinitions::GetStateLabelIndex (FName statename)
404 {
405 	FStateDefine *std = FindStateLabelInList(StateLabels, statename, false);
406 	if (std == NULL)
407 	{
408 		return -1;
409 	}
410 	assert((size_t)std->State <= StateArray.Size() + 1);
411 	return (int)((ptrdiff_t)std->State - 1);
412 }
413 
414 //==========================================================================
415 //
416 // Finds the state associated with the given name
417 // returns NULL if none found
418 //
419 //==========================================================================
420 
FindState(const char * name)421 FState * FStateDefinitions::FindState(const char * name)
422 {
423 	FStateDefine * statedef=NULL;
424 
425 	TArray<FName> &namelist = MakeStateNameList(name);
426 
427 	TArray<FStateDefine> * statelist = &StateLabels;
428 	for(unsigned i=0;i<namelist.Size();i++)
429 	{
430 		statedef = FindStateLabelInList(*statelist, namelist[i], false);
431 		if (statedef == NULL) return NULL;
432 		statelist = &statedef->Children;
433 	}
434 	return statedef? statedef->State : NULL;
435 }
436 
437 //==========================================================================
438 //
439 // Creates the final list of states from the state definitions
440 //
441 //==========================================================================
442 
labelcmp(const void * a,const void * b)443 static int STACK_ARGS labelcmp(const void * a, const void * b)
444 {
445 	FStateLabel * A = (FStateLabel *)a;
446 	FStateLabel * B = (FStateLabel *)b;
447 	return ((int)A->Label - (int)B->Label);
448 }
449 
CreateStateLabelList(TArray<FStateDefine> & statelist)450 FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & statelist)
451 {
452 	// First delete all empty labels from the list
453 	for (int i=statelist.Size()-1;i>=0;i--)
454 	{
455 		if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0))
456 		{
457 			statelist.Delete(i);
458 		}
459 	}
460 
461 	int count=statelist.Size();
462 
463 	if (count == 0) return NULL;
464 
465 	FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
466 	list->NumLabels = count;
467 
468 	for (int i=0;i<count;i++)
469 	{
470 		list->Labels[i].Label = statelist[i].Label;
471 		list->Labels[i].State = statelist[i].State;
472 		list->Labels[i].Children = CreateStateLabelList(statelist[i].Children);
473 	}
474 	qsort(list->Labels, count, sizeof(FStateLabel), labelcmp);
475 	return list;
476 }
477 
478 //===========================================================================
479 //
480 // InstallStates
481 //
482 // Creates the actor's state list from the current definition
483 //
484 //===========================================================================
485 
InstallStates(FActorInfo * info,AActor * defaults)486 void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults)
487 {
488 	// First ensure we have a valid spawn state.
489 	FState *state = FindState("Spawn");
490 
491 	if (state == NULL)
492 	{
493 		// A NULL spawn state will crash the engine so set it to something valid.
494 		SetStateLabel("Spawn", GetDefault<AActor>()->SpawnState);
495 	}
496 
497 	if (info->StateList != NULL)
498 	{
499 		info->StateList->Destroy();
500 		M_Free(info->StateList);
501 	}
502 	info->StateList = CreateStateLabelList(StateLabels);
503 
504 	// Cache these states as member veriables.
505 	defaults->SpawnState = info->FindState(NAME_Spawn);
506 	defaults->SeeState = info->FindState(NAME_See);
507 	// Melee and Missile states are manipulated by the scripted marines so they
508 	// have to be stored locally
509 	defaults->MeleeState = info->FindState(NAME_Melee);
510 	defaults->MissileState = info->FindState(NAME_Missile);
511 }
512 
513 //===========================================================================
514 //
515 // MakeStateDefines
516 //
517 // Creates a list of state definitions from an existing actor
518 // Used by Dehacked to modify an actor's state list
519 //
520 //===========================================================================
521 
MakeStateList(const FStateLabels * list,TArray<FStateDefine> & dest)522 void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
523 {
524 	dest.Clear();
525 	if (list != NULL) for(int i=0;i<list->NumLabels;i++)
526 	{
527 		FStateDefine def;
528 
529 		def.Label = list->Labels[i].Label;
530 		def.State = list->Labels[i].State;
531 		def.DefineFlags = SDF_STATE;
532 		dest.Push(def);
533 		if (list->Labels[i].Children != NULL)
534 		{
535 			MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
536 		}
537 	}
538 }
539 
MakeStateDefines(const PClass * cls)540 void FStateDefinitions::MakeStateDefines(const PClass *cls)
541 {
542 	StateArray.Clear();
543 	laststate = NULL;
544 	laststatebeforelabel = NULL;
545 	lastlabel = -1;
546 
547 	if (cls != NULL && cls->ActorInfo != NULL && cls->ActorInfo->StateList != NULL)
548 	{
549 		MakeStateList(cls->ActorInfo->StateList, StateLabels);
550 	}
551 	else
552 	{
553 		StateLabels.Clear();
554 	}
555 }
556 
557 //===========================================================================
558 //
559 // AddStateDefines
560 //
561 // Adds a list of states to the current definitions
562 //
563 //===========================================================================
564 
AddStateDefines(const FStateLabels * list)565 void FStateDefinitions::AddStateDefines(const FStateLabels *list)
566 {
567 	if (list != NULL) for(int i=0;i<list->NumLabels;i++)
568 	{
569 		if (list->Labels[i].Children == NULL)
570 		{
571 			if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false))
572 			{
573 				FStateDefine def;
574 
575 				def.Label = list->Labels[i].Label;
576 				def.State = list->Labels[i].State;
577 				def.DefineFlags = SDF_STATE;
578 				StateLabels.Push(def);
579 			}
580 		}
581 	}
582 }
583 
584 //==========================================================================
585 //
586 // RetargetState(Pointer)s
587 //
588 // These functions are used when a goto follows one or more labels.
589 // Because multiple labels are permitted to occur consecutively with no
590 // intervening states, it is not enough to remember the last label defined
591 // and adjust it. So these functions search for all labels that point to
592 // the current position in the state array and give them a copy of the
593 // target string instead.
594 //
595 //==========================================================================
596 
RetargetStatePointers(intptr_t count,const char * target,TArray<FStateDefine> & statelist)597 void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
598 {
599 	for(unsigned i = 0;i<statelist.Size(); i++)
600 	{
601 		if (statelist[i].State == (FState*)count && statelist[i].DefineFlags == SDF_INDEX)
602 		{
603 			if (target == NULL)
604 			{
605 				statelist[i].State = NULL;
606 				statelist[i].DefineFlags = SDF_STOP;
607 			}
608 			else
609 			{
610 				statelist[i].State = (FState *)copystring (target);
611 				statelist[i].DefineFlags = SDF_LABEL;
612 			}
613 		}
614 		if (statelist[i].Children.Size() > 0)
615 		{
616 			RetargetStatePointers(count, target, statelist[i].Children);
617 		}
618 	}
619 }
620 
RetargetStates(intptr_t count,const char * target)621 void FStateDefinitions::RetargetStates (intptr_t count, const char *target)
622 {
623 	RetargetStatePointers(count, target, StateLabels);
624 }
625 
626 
627 //==========================================================================
628 //
629 // ResolveGotoLabel
630 //
631 // Resolves any strings being stored in a state's NextState field
632 //
633 //==========================================================================
634 
ResolveGotoLabel(AActor * actor,const PClass * mytype,char * name)635 FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name)
636 {
637 	const PClass *type=mytype;
638 	FState *state;
639 	char *namestart = name;
640 	char *label, *offset, *pt;
641 	int v;
642 
643 	// Check for classname
644 	if ((pt = strstr (name, "::")) != NULL)
645 	{
646 		const char *classname = name;
647 		*pt = '\0';
648 		name = pt + 2;
649 
650 		// The classname may either be "Super" to identify this class's immediate
651 		// superclass, or it may be the name of any class that this one derives from.
652 		if (stricmp (classname, "Super") == 0)
653 		{
654 			type = type->ParentClass;
655 			actor = GetDefaultByType (type);
656 		}
657 		else
658 		{
659 			// first check whether a state of the desired name exists
660 			const PClass *stype = PClass::FindClass (classname);
661 			if (stype == NULL)
662 			{
663 				I_Error ("%s is an unknown class.", classname);
664 			}
665 			if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
666 			{
667 				I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
668 			}
669 			if (!stype->IsAncestorOf (type))
670 			{
671 				I_Error ("%s is not derived from %s so cannot access its states.",
672 					type->TypeName.GetChars(), stype->TypeName.GetChars());
673 			}
674 			if (type != stype)
675 			{
676 				type = stype;
677 				actor = GetDefaultByType (type);
678 			}
679 		}
680 	}
681 	label = name;
682 	// Check for offset
683 	offset = NULL;
684 	if ((pt = strchr (name, '+')) != NULL)
685 	{
686 		*pt = '\0';
687 		offset = pt + 1;
688 	}
689 	v = offset ? strtol (offset, NULL, 0) : 0;
690 
691 	// Get the state's address.
692 	if (type==mytype) state = FindState (label);
693 	else state = type->ActorInfo->FindStateByString(label, true);
694 
695 	if (state != NULL)
696 	{
697 		state += v;
698 	}
699 	else if (v != 0)
700 	{
701 		I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
702 	}
703 	else
704 	{
705 		Printf (TEXTCOLOR_RED "Attempt to get invalid state %s from actor %s.\n", label, type->TypeName.GetChars());
706 	}
707 	delete[] namestart;		// free the allocated string buffer
708 	return state;
709 }
710 
711 //==========================================================================
712 //
713 // FixStatePointers
714 //
715 // Fixes an actor's default state pointers.
716 //
717 //==========================================================================
718 
FixStatePointers(FActorInfo * actor,TArray<FStateDefine> & list)719 void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
720 {
721 	for(unsigned i=0;i<list.Size(); i++)
722 	{
723 		if (list[i].DefineFlags == SDF_INDEX)
724 		{
725 			size_t v=(size_t)list[i].State;
726 			list[i].State = actor->OwnedStates + v - 1;
727 			list[i].DefineFlags = SDF_STATE;
728 		}
729 		if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
730 	}
731 }
732 
733 //==========================================================================
734 //
735 // ResolveGotoLabels
736 //
737 // Resolves an actor's state pointers that were specified as jumps.
738 //
739 //==========================================================================
740 
ResolveGotoLabels(FActorInfo * actor,AActor * defaults,TArray<FStateDefine> & list)741 void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
742 {
743 	for(unsigned i=0;i<list.Size(); i++)
744 	{
745 		if (list[i].State != NULL && list[i].DefineFlags == SDF_LABEL)
746 		{ // It's not a valid state, so it must be a label string. Resolve it.
747 			list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State);
748 			list[i].DefineFlags = SDF_STATE;
749 		}
750 		if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children);
751 	}
752 }
753 
754 
755 //==========================================================================
756 //
757 // SetGotoLabel
758 //
759 // sets a jump at the current state or retargets a label
760 //
761 //==========================================================================
762 
SetGotoLabel(const char * string)763 bool FStateDefinitions::SetGotoLabel(const char *string)
764 {
765 	// copy the text - this must be resolved later!
766 	if (laststate != NULL)
767 	{ // Following a state definition: Modify it.
768 		laststate->NextState = (FState*)copystring(string);
769 		laststate->DefineFlags = SDF_LABEL;
770 		laststatebeforelabel = NULL;
771 		return true;
772 	}
773 	else if (lastlabel >= 0)
774 	{ // Following a label: Retarget it.
775 		RetargetStates (lastlabel+1, string);
776 		if (laststatebeforelabel != NULL)
777 		{
778 			laststatebeforelabel->NextState = (FState*)copystring(string);
779 			laststatebeforelabel->DefineFlags = SDF_LABEL;
780 			laststatebeforelabel = NULL;
781 		}
782 		return true;
783 	}
784 	return false;
785 }
786 
787 //==========================================================================
788 //
789 // SetStop
790 //
791 // sets a stop operation
792 //
793 //==========================================================================
794 
SetStop()795 bool FStateDefinitions::SetStop()
796 {
797 	if (laststate != NULL)
798 	{
799 		laststate->DefineFlags = SDF_STOP;
800 		laststatebeforelabel = NULL;
801 		return true;
802 	}
803 	else if (lastlabel >=0)
804 	{
805 		RetargetStates (lastlabel+1, NULL);
806 		if (laststatebeforelabel != NULL)
807 		{
808 			laststatebeforelabel->DefineFlags = SDF_STOP;
809 			laststatebeforelabel = NULL;
810 		}
811 		return true;
812 	}
813 	return false;
814 }
815 
816 //==========================================================================
817 //
818 // SetWait
819 //
820 // sets a wait or fail operation
821 //
822 //==========================================================================
823 
SetWait()824 bool FStateDefinitions::SetWait()
825 {
826 	if (laststate != NULL)
827 	{
828 		laststate->DefineFlags = SDF_WAIT;
829 		laststatebeforelabel = NULL;
830 		return true;
831 	}
832 	return false;
833 }
834 
835 //==========================================================================
836 //
837 // SetLoop
838 //
839 // sets a loop operation
840 //
841 //==========================================================================
842 
SetLoop()843 bool FStateDefinitions::SetLoop()
844 {
845 	if (laststate != NULL)
846 	{
847 		laststate->DefineFlags = SDF_INDEX;
848 		laststate->NextState = (FState*)(lastlabel+1);
849 		laststatebeforelabel = NULL;
850 		return true;
851 	}
852 	return false;
853 }
854 
855 //==========================================================================
856 //
857 // AddStates
858 // adds some state to the current definition set
859 //
860 //==========================================================================
861 
AddStates(FState * state,const char * framechars)862 bool FStateDefinitions::AddStates(FState *state, const char *framechars)
863 {
864 	bool error = false;
865 	int frame = 0;
866 
867 	while (*framechars)
868 	{
869 		bool noframe = false;
870 
871 		if (*framechars == '#')
872 			noframe = true;
873 		else if (*framechars == '^')
874 			frame = '\\' - 'A';
875 		else
876 			frame = (*framechars & 223) - 'A';
877 
878 		framechars++;
879 		if (frame < 0 || frame > 28)
880 		{
881 			frame = 0;
882 			error = true;
883 		}
884 
885 		state->Frame = frame;
886 		state->SameFrame = noframe;
887 		StateArray.Push(*state);
888 
889 		// NODELAY flag is not carried past the first state
890 		state->NoDelay = false;
891 	}
892 	laststate = &StateArray[StateArray.Size() - 1];
893 	laststatebeforelabel = laststate;
894 	return !error;
895 }
896 
897 //==========================================================================
898 //
899 // FinishStates
900 // copies a state block and fixes all state links using the current list of labels
901 //
902 //==========================================================================
903 
FinishStates(FActorInfo * actor,AActor * defaults)904 int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults)
905 {
906 	int count = StateArray.Size();
907 
908 	if (count > 0)
909 	{
910 		FState *realstates = new FState[count];
911 		int i;
912 
913 		memcpy(realstates, &StateArray[0], count*sizeof(FState));
914 		actor->OwnedStates = realstates;
915 		actor->NumOwnedStates = count;
916 
917 		// adjust the state pointers
918 		// In the case new states are added these must be adjusted, too!
919 		FixStatePointers(actor, StateLabels);
920 
921 		// Fix state pointers that are gotos
922 		ResolveGotoLabels(actor, defaults, StateLabels);
923 
924 		for (i = 0; i < count; i++)
925 		{
926 			// resolve labels and jumps
927 			switch (realstates[i].DefineFlags)
928 			{
929 			case SDF_STOP:	// stop
930 				realstates[i].NextState = NULL;
931 				break;
932 
933 			case SDF_WAIT:	// wait
934 				realstates[i].NextState = &realstates[i];
935 				break;
936 
937 			case SDF_NEXT:		// next
938 				realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
939 				break;
940 
941 			case SDF_INDEX:		// loop
942 				realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
943 				break;
944 
945 			case SDF_LABEL:
946 				realstates[i].NextState = ResolveGotoLabel(defaults, actor->Class, (char *)realstates[i].NextState);
947 				break;
948 			}
949 		}
950 	}
951 	else
952 	{
953 		// Fix state pointers that are gotos
954 		ResolveGotoLabels(actor, defaults, StateLabels);
955 	}
956 
957 	return count;
958 }
959 
960 
961 //==========================================================================
962 //
963 // Prints all state label info to the logfile
964 //
965 //==========================================================================
966 
DumpStateHelper(FStateLabels * StateList,const FString & prefix)967 void DumpStateHelper(FStateLabels *StateList, const FString &prefix)
968 {
969 	for (int i = 0; i < StateList->NumLabels; i++)
970 	{
971 		if (StateList->Labels[i].State != NULL)
972 		{
973 			const PClass *owner = FState::StaticFindStateOwner(StateList->Labels[i].State);
974 			if (owner == NULL)
975 			{
976 				Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars());
977 			}
978 			else
979 			{
980 				Printf(PRINT_LOG, "%s%s: %s.%d\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(),
981 					owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->ActorInfo->OwnedStates));
982 			}
983 		}
984 		if (StateList->Labels[i].Children != NULL)
985 		{
986 			DumpStateHelper(StateList->Labels[i].Children, prefix + '.' + StateList->Labels[i].Label.GetChars());
987 		}
988 	}
989 }
990 
CCMD(dumpstates)991 CCMD(dumpstates)
992 {
993 	for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
994 	{
995 		FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
996 		Printf(PRINT_LOG, "State labels for %s\n", info->Class->TypeName.GetChars());
997 		DumpStateHelper(info->StateList, "");
998 		Printf(PRINT_LOG, "----------------------------\n");
999 	}
1000 }
1001