diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 6cbda931d..006ada99e 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,8 @@ December 16, 2006 (Changes by Graf Zahl) +- Changed state label storage so that each actor owns all the state labels itself + and doesn't have to traverse parent lists to find them. This is required for + Dehacked actors that inherit states (e.g. NonsolidMeat and Spectre) but it also + makes the data much easier to handle. - Merged the fallingdamage setting into one menu item and added Strife damage to it. - Moved deathmatch options into their own category in the gameplay options menu. - Added the sv_smartaim code from GZDoom which tries to avoid autoaiming diff --git a/src/decorations.cpp b/src/decorations.cpp index 8bf4eb938..0297871ee 100644 --- a/src/decorations.cpp +++ b/src/decorations.cpp @@ -357,7 +357,7 @@ static void ParseDecorate (void (*process)(FState *, int)) info = type->ActorInfo; info->GameFilter = 0x80; Decorations.Push (info); - ClearStateLabels(); + MakeStateDefines(parent->ActorInfo->StateList); SC_MustGetString (); while (!SC_Compare ("{")) diff --git a/src/info.cpp b/src/info.cpp index 01c732940..1469ccb68 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -432,19 +432,14 @@ void FStateLabels::Destroy () FState *AActor::FindState (FName label) const { const FActorInfo *info = GetClass()->ActorInfo; - FStateLabel *slabel; - while (info != NULL) + if (info->StateList != NULL) { - if (info->StateList != NULL) + FStateLabel *slabel = info->StateList->FindLabel (label); + if (slabel != NULL) { - slabel = info->StateList->FindLabel (label); - if (slabel != NULL && slabel->valid) - { - return slabel->State; - } + return slabel->State; } - info = info->Class->ParentClass->ActorInfo; } return NULL; } @@ -460,33 +455,17 @@ FState *AActor::FindState (FName label) const bool AActor::HasSpecialDeathStates () const { const FActorInfo *info = GetClass()->ActorInfo; - FStateLabel *slabel; - TArray checkedTypes; - while (info != NULL) + if (info->StateList != NULL) { - if (info->StateList != NULL) + FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); + if (slabel != NULL && slabel->Children != NULL) { - slabel = info->StateList->FindLabel (NAME_Death); - if (slabel != NULL && slabel->Children != NULL) + for(int i=0;iChildren->NumLabels;i++) { - for(int i=0;iChildren->NumLabels;i++) - { - unsigned int j; - for(j=0;jChildren->Labels[i].Label == checkedTypes[j]) break; - } - // Only check if this damage type hasn't been checked by another class with higher priority. - if (j==checkedTypes.Size()) - { - if (slabel->Children->Labels[i].State != NULL) return true; - else if (slabel->Children->Labels[i].valid) checkedTypes.Push(slabel->Children->Labels[i].Label); - } - } + if (slabel->Children->Labels[i].State != NULL) return true; } } - info = info->Class->ParentClass->ActorInfo; } return false; } @@ -504,8 +483,6 @@ bool AActor::HasSpecialDeathStates () const // names until there are no more. If both the argument list and the state // are out of names, it's an exact match, so return it. If the state still // has names, ignore it. If the argument list still has names, remember it. -// Repeat with each successive ancestor class. The state with the longest -// match not exceeding the supplied number of names is returned. // //=========================================================================== @@ -533,53 +510,33 @@ FState *AActor::FindState (int numnames, va_list arglist) const FState *FActorInfo::FindState (int numnames, va_list arglist) const { - const FActorInfo *info = this; + FStateLabels *labels = StateList; FState *best = NULL; - int bestcount = 0; - // Search this actor's class, plus all its ancestors for a match. - while (info != NULL && bestcount < numnames) + if (labels != NULL) { - FStateLabels *labels = info->StateList; + va_list names = arglist; + int count = 0; + FStateLabel *slabel = NULL; + FName label; - if (labels != NULL) + // Find the best-matching label for this class. + while (labels != NULL && count < numnames) { - va_list names = arglist; - int count = 0; - FStateLabel *slabel = NULL; - FName label; + label = ENamedName(va_arg (names, int)); + slabel = labels->FindLabel (label); - // Find the best-matching label for this class. - while (labels != NULL && count < numnames) + if (slabel != NULL) { - label = ENamedName(va_arg (names, int)); - slabel = labels->FindLabel (label); - - if (slabel != NULL) - { - count++; - labels = slabel->Children; - - // Labels that are more specific than what we want do not match. - // Less specific labels do match. - if (slabel->valid && count > bestcount) - { - if (count == numnames) - { - return slabel->State; - } - bestcount = count; - best = slabel->State; - } - } - else - { - break; - } + count++; + labels = slabel->Children; + best = slabel->State; + } + else + { + break; } } - // Walk up the class hierarchy and repeat. - info = info->Class->ParentClass->ActorInfo; } return best; } @@ -602,44 +559,36 @@ FState *FActorInfo::FindStateExact (int numnames, ...) const FState *FActorInfo::FindStateExact (int numnames, va_list arglist) const { - const FActorInfo *info = this; + FStateLabels *labels = StateList; - // Search this actor's class, plus all its ancestors for a match. - while (info != NULL) + if (labels != NULL) { - FStateLabels *labels = info->StateList; + va_list names = arglist; + int count = 0; + FStateLabel *slabel = NULL; + FName label; - if (labels != NULL) + // Look for a matching label for this class. + while (labels != NULL && count < numnames) { - va_list names = arglist; - int count = 0; - FStateLabel *slabel = NULL; - FName label; + label = ENamedName(va_arg (names, int)); + slabel = labels->FindLabel (label); - // Look for a matching label for this class. - while (labels != NULL && count < numnames) + if (slabel != NULL) { - label = ENamedName(va_arg (names, int)); - slabel = labels->FindLabel (label); - - if (slabel != NULL) - { - count++; - labels = slabel->Children; - } - else - { - break; - } + count++; + labels = slabel->Children; } - // Only exact matches count. - if (slabel != NULL && slabel->valid && count == numnames) + else { - return slabel->State; + break; } } - // Walk up the class hierarchy and repeat. - info = info->Class->ParentClass->ActorInfo; + // Only exact matches count. + if (slabel != NULL && count == numnames) + { + return slabel->State; + } } return NULL; } diff --git a/src/info.h b/src/info.h index bb83df647..f6af173d2 100644 --- a/src/info.h +++ b/src/info.h @@ -153,7 +153,6 @@ struct FStateLabels; struct FStateLabel { FName Label; - bool valid; // needed to recognize genuine NULL states FState *State; FStateLabels *Children; }; diff --git a/src/infodefaults.cpp b/src/infodefaults.cpp index 8dd76058c..d3325abfa 100644 --- a/src/infodefaults.cpp +++ b/src/infodefaults.cpp @@ -70,12 +70,6 @@ void FActorInfo::BuildDefaults () { memset (Class->Defaults + parent->Size, 0, Class->Size - parent->Size); } - if (parent == RUNTIME_CLASS(AActor) && OwnedStates == NULL) - { // Stateless actors that are direct subclasses of AActor - // have their spawnstate default to something that won't - // immediately destroy them. - ((AActor *)(Class->Defaults))->SpawnState = &AActor::States[0]; - } } ApplyDefaults (Class->Defaults); } @@ -358,7 +352,14 @@ void FActorInfo::ApplyDefaults (BYTE *defaults) sgClass = Class; sgDefaults = defaults; - ClearStateLabels(); + if (Class != RUNTIME_CLASS(AActor)) + { + MakeStateDefines(Class->ParentClass->ActorInfo->StateList); + } + else + { + ClearStateLabels(); + } #if _MSC_VER const BYTE *parser = DefaultList; diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 4b8314e83..8ee43eb39 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -774,7 +774,6 @@ static const ActorProps *is_actorprop (const char *str); struct FStateDefine { FName Label; - bool valid; TArray Children; FState *State; }; @@ -803,7 +802,6 @@ static FStateDefine * FindStateLabelInList(TArray & list, FName na FStateDefine def; def.Label=name; def.State=NULL; - def.valid=false; return &list[list.Push(def)]; } return NULL; @@ -882,7 +880,6 @@ void AddState (const char * statename, FState * state) { FStateDefine * std = FindStateAddress(statename); std->State = state; - std->valid = true; } //========================================================================== @@ -902,12 +899,7 @@ FState * FindState(AActor * actor, const PClass * type, const char * name) for(unsigned i=0;iParentClass->ActorInfo; - if (parentinfo) return parentinfo->FindStateExact(namelist.Size(), (va_list)&namelist[0]); - else return NULL; - } + if (statedef == NULL) return NULL; statelist = &statedef->Children; } return statedef? statedef->State : NULL; @@ -961,6 +953,15 @@ static int STACK_ARGS labelcmp(const void * a, const void * b) static FStateLabels * CreateStateLabelList(TArray & statelist) { + // First delete all empty labels from the list + for (int i=statelist.Size()-1;i>=0;i--) + { + if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) + { + statelist.Delete(i); + } + } + int count=statelist.Size(); if (count == 0) return NULL; @@ -968,17 +969,11 @@ static FStateLabels * CreateStateLabelList(TArray & statelist) FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); list->NumLabels = count; - int j=0; - for (unsigned i=0;iLabels[j].Label = statelist[i].Label; - list->Labels[j].State = statelist[i].State; - list->Labels[j].valid = statelist[i].valid; - list->Labels[j].Children = CreateStateLabelList(statelist[i].Children); - j++; - } + list->Labels[i].Label = statelist[i].Label; + list->Labels[i].State = statelist[i].State; + list->Labels[i].Children = CreateStateLabelList(statelist[i].Children); } qsort(list->Labels, count, sizeof(FStateLabel), labelcmp); return list; @@ -994,14 +989,28 @@ static FStateLabels * CreateStateLabelList(TArray & statelist) void InstallStates(FActorInfo *info, AActor *defaults) { + // First ensure we have a valid spawn state. FState * state = FindState(defaults, info->Class, "Spawn"); - // If the actor doesn't provide a valid spawn state we have to substutute it - // with the default. - if (state == &AActor::States[2] || state == NULL) + + // Stateless actors that are direct subclasses of AActor + // have their spawnstate default to something that won't + // immediately destroy them. + if (state == &AActor::States[2] && info->Class->ParentClass == RUNTIME_CLASS(AActor)) { AddState("Spawn", &AActor::States[0]); } + else if (state == NULL) + { + // A NULL spawn state will crash the engine so set it to something that will make + // the actor disappear as quickly as possible. + AddState("Spawn", &AActor::States[2]); + } + if (info->StateList != NULL) + { + info->StateList->Destroy(); + free(info->StateList); + } info->StateList = CreateStateLabelList(StateLabels); // Cache these states as member veriables. @@ -1032,7 +1041,6 @@ static void MakeStateList(const FStateLabels *list, TArray &dest) def.Label = list->Labels[i].Label; def.State = list->Labels[i].State; - def.valid = list->Labels[i].valid; dest.Push(def); if (list->Labels[i].Children != NULL) { @@ -1150,7 +1158,7 @@ static FActorInfo * CreateNewActor(FActorInfo ** parentc, Baggage *bag) FActorInfo * info = ti->ActorInfo; Decorations.Push (info); - ClearStateLabels(); + MakeStateDefines(parent->ActorInfo->StateList); info->NumOwnedStates = 0; info->OwnedStates = NULL; info->SpawnID = 0;