mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 14:51:40 +00:00
- Used the one unused byte in the state structure as a flag to tell what type
the NextState parameter is. The code did some rather unsafe checks with it to determine its type. - moved all state related code into a new file: p_states.cpp. - merged all FindState functions. All the different variations are now inlined and call the same function to do the real work. SVN r1243 (trunk)
This commit is contained in:
parent
b523ebd2a7
commit
954955c5a5
16 changed files with 1001 additions and 904 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
September 22, 2008 (Changes by Graf Zahl)
|
||||||
|
- Used the one unused byte in the state structure as a flag to tell what type
|
||||||
|
the NextState parameter is. The code did some rather unsafe checks with it
|
||||||
|
to determine its type.
|
||||||
|
- moved all state related code into a new file: p_states.cpp.
|
||||||
|
- merged all FindState functions. All the different variations are now inlined
|
||||||
|
and call the same function to do the real work.
|
||||||
|
|
||||||
September 21, 2008 (Changes by Graf Zahl)
|
September 21, 2008 (Changes by Graf Zahl)
|
||||||
- did some code cleanup and reorganization in thingdef.cpp.
|
- did some code cleanup and reorganization in thingdef.cpp.
|
||||||
- Replaced the translation parser for TEXTURES with FRemapTable::AddToTranslation.
|
- Replaced the translation parser for TEXTURES with FRemapTable::AddToTranslation.
|
||||||
|
|
14
src/actor.h
14
src/actor.h
|
@ -785,8 +785,18 @@ public:
|
||||||
bool isFast();
|
bool isFast();
|
||||||
void SetIdle();
|
void SetIdle();
|
||||||
|
|
||||||
FState *FindState (FName label) const;
|
FState *FindState (FName label) const
|
||||||
FState *FindState (FName label, FName sublabel, bool exact = false) const;
|
{
|
||||||
|
return GetClass()->ActorInfo->FindState(1, &label);
|
||||||
|
}
|
||||||
|
|
||||||
|
FState *FindState (FName label, FName sublabel, bool exact = false) const
|
||||||
|
{
|
||||||
|
FName names[]={label, sublabel};
|
||||||
|
return GetClass()->ActorInfo->FindState(2, &label, exact);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HasSpecialDeathStates () const;
|
bool HasSpecialDeathStates () const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -682,6 +682,7 @@ static int PatchThing (int thingy)
|
||||||
bool hadHeight = false;
|
bool hadHeight = false;
|
||||||
bool hadTranslucency = false;
|
bool hadTranslucency = false;
|
||||||
bool hadStyle = false;
|
bool hadStyle = false;
|
||||||
|
FStateDefinitions statedef;
|
||||||
bool patchedStates = false;
|
bool patchedStates = false;
|
||||||
int oldflags;
|
int oldflags;
|
||||||
const PClass *type;
|
const PClass *type;
|
||||||
|
@ -813,36 +814,36 @@ static int PatchThing (int thingy)
|
||||||
|
|
||||||
if (type != NULL && !patchedStates)
|
if (type != NULL && !patchedStates)
|
||||||
{
|
{
|
||||||
MakeStateDefines(type->ActorInfo->StateList);
|
statedef.MakeStateDefines(type);
|
||||||
patchedStates = true;
|
patchedStates = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strnicmp (Line1, "Initial", 7))
|
if (!strnicmp (Line1, "Initial", 7))
|
||||||
AddState("Spawn", state ? state : GetDefault<AActor>()->SpawnState);
|
statedef.AddState("Spawn", state ? state : GetDefault<AActor>()->SpawnState);
|
||||||
else if (!strnicmp (Line1, "First moving", 12))
|
else if (!strnicmp (Line1, "First moving", 12))
|
||||||
AddState("See", state);
|
statedef.AddState("See", state);
|
||||||
else if (!strnicmp (Line1, "Injury", 6))
|
else if (!strnicmp (Line1, "Injury", 6))
|
||||||
AddState("Pain", state);
|
statedef.AddState("Pain", state);
|
||||||
else if (!strnicmp (Line1, "Close attack", 12))
|
else if (!strnicmp (Line1, "Close attack", 12))
|
||||||
{
|
{
|
||||||
if (thingy != 1) // Not for players!
|
if (thingy != 1) // Not for players!
|
||||||
{
|
{
|
||||||
AddState("Melee", state);
|
statedef.AddState("Melee", state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strnicmp (Line1, "Far attack", 10))
|
else if (!strnicmp (Line1, "Far attack", 10))
|
||||||
{
|
{
|
||||||
if (thingy != 1) // Not for players!
|
if (thingy != 1) // Not for players!
|
||||||
{
|
{
|
||||||
AddState("Missile", state);
|
statedef.AddState("Missile", state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strnicmp (Line1, "Death", 5))
|
else if (!strnicmp (Line1, "Death", 5))
|
||||||
AddState("Death", state);
|
statedef.AddState("Death", state);
|
||||||
else if (!strnicmp (Line1, "Exploding", 9))
|
else if (!strnicmp (Line1, "Exploding", 9))
|
||||||
AddState("XDeath", state);
|
statedef.AddState("XDeath", state);
|
||||||
else if (!strnicmp (Line1, "Respawn", 7))
|
else if (!strnicmp (Line1, "Respawn", 7))
|
||||||
AddState("Raise", state);
|
statedef.AddState("Raise", state);
|
||||||
}
|
}
|
||||||
else if (stricmp (Line1 + linelen - 6, " sound") == 0)
|
else if (stricmp (Line1 + linelen - 6, " sound") == 0)
|
||||||
{
|
{
|
||||||
|
@ -1048,7 +1049,7 @@ static int PatchThing (int thingy)
|
||||||
}
|
}
|
||||||
if (patchedStates)
|
if (patchedStates)
|
||||||
{
|
{
|
||||||
InstallStates(type->ActorInfo, info);
|
statedef.InstallStates(type->ActorInfo, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,6 +1360,7 @@ static int PatchWeapon (int weapNum)
|
||||||
AWeapon *info;
|
AWeapon *info;
|
||||||
BYTE dummy[sizeof(AWeapon)];
|
BYTE dummy[sizeof(AWeapon)];
|
||||||
bool patchedStates = false;
|
bool patchedStates = false;
|
||||||
|
FStateDefinitions statedef;
|
||||||
|
|
||||||
if (weapNum >= 0 && weapNum < 9)
|
if (weapNum >= 0 && weapNum < 9)
|
||||||
{
|
{
|
||||||
|
@ -1385,20 +1387,20 @@ static int PatchWeapon (int weapNum)
|
||||||
|
|
||||||
if (type != NULL && !patchedStates)
|
if (type != NULL && !patchedStates)
|
||||||
{
|
{
|
||||||
MakeStateDefines(type->ActorInfo->StateList);
|
statedef.MakeStateDefines(type);
|
||||||
patchedStates = true;
|
patchedStates = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strnicmp (Line1, "Deselect", 8) == 0)
|
if (strnicmp (Line1, "Deselect", 8) == 0)
|
||||||
AddState("Select", state);
|
statedef.AddState("Select", state);
|
||||||
else if (strnicmp (Line1, "Select", 6) == 0)
|
else if (strnicmp (Line1, "Select", 6) == 0)
|
||||||
AddState("Deselect", state);
|
statedef.AddState("Deselect", state);
|
||||||
else if (strnicmp (Line1, "Bobbing", 7) == 0)
|
else if (strnicmp (Line1, "Bobbing", 7) == 0)
|
||||||
AddState("Ready", state);
|
statedef.AddState("Ready", state);
|
||||||
else if (strnicmp (Line1, "Shooting", 8) == 0)
|
else if (strnicmp (Line1, "Shooting", 8) == 0)
|
||||||
AddState("Fire", state);
|
statedef.AddState("Fire", state);
|
||||||
else if (strnicmp (Line1, "Firing", 6) == 0)
|
else if (strnicmp (Line1, "Firing", 6) == 0)
|
||||||
AddState("Flash", state);
|
statedef.AddState("Flash", state);
|
||||||
}
|
}
|
||||||
else if (stricmp (Line1, "Ammo type") == 0)
|
else if (stricmp (Line1, "Ammo type") == 0)
|
||||||
{
|
{
|
||||||
|
@ -1455,7 +1457,7 @@ static int PatchWeapon (int weapNum)
|
||||||
|
|
||||||
if (patchedStates)
|
if (patchedStates)
|
||||||
{
|
{
|
||||||
InstallStates(type->ActorInfo, info);
|
statedef.InstallStates(type->ActorInfo, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -2582,13 +2584,14 @@ void FinishDehPatch ()
|
||||||
memcpy (defaults2, defaults1, sizeof(AActor));
|
memcpy (defaults2, defaults1, sizeof(AActor));
|
||||||
|
|
||||||
// Make a copy the state labels
|
// Make a copy the state labels
|
||||||
MakeStateDefines(type->ActorInfo->StateList);
|
|
||||||
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||||
{
|
{
|
||||||
// If this is a hacked non-inventory item we must also copy AInventory's special states
|
// If this is a hacked non-inventory item we must also copy AInventory's special states
|
||||||
AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList);
|
FStateDefinitions statedef;
|
||||||
|
statedef.MakeStateDefines(type);
|
||||||
|
statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList);
|
||||||
|
statedef.InstallStates(subclass->ActorInfo, defaults2);
|
||||||
}
|
}
|
||||||
InstallStates(subclass->ActorInfo, defaults2);
|
|
||||||
|
|
||||||
// Use the DECORATE replacement feature to redirect all spawns
|
// Use the DECORATE replacement feature to redirect all spawns
|
||||||
// of the original class to the new one.
|
// of the original class to the new one.
|
||||||
|
|
319
src/info.cpp
319
src/info.cpp
|
@ -51,122 +51,6 @@
|
||||||
|
|
||||||
extern void LoadDecorations ();
|
extern void LoadDecorations ();
|
||||||
|
|
||||||
// Each state is owned by an actor. Actors can own any number of
|
|
||||||
// states, but a single state cannot be owned by more than one
|
|
||||||
// actor. States are archived by recording the actor they belong
|
|
||||||
// to and the index into that actor's list of states.
|
|
||||||
|
|
||||||
// For NULL states, which aren't owned by any actor, the owner
|
|
||||||
// is recorded as AActor with the following state. AActor should
|
|
||||||
// never actually have this many states of its own, so this
|
|
||||||
// is (relatively) safe.
|
|
||||||
|
|
||||||
#define NULL_STATE_INDEX 127
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FArchive &operator<< (FArchive &arc, FState *&state)
|
|
||||||
{
|
|
||||||
const PClass *info;
|
|
||||||
|
|
||||||
if (arc.IsStoring ())
|
|
||||||
{
|
|
||||||
if (state == NULL)
|
|
||||||
{
|
|
||||||
arc.UserWriteClass (RUNTIME_CLASS(AActor));
|
|
||||||
arc.WriteCount (NULL_STATE_INDEX);
|
|
||||||
return arc;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = FState::StaticFindStateOwner (state);
|
|
||||||
|
|
||||||
if (info != NULL)
|
|
||||||
{
|
|
||||||
arc.UserWriteClass (info);
|
|
||||||
arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* this was never working as intended.
|
|
||||||
I_Error ("Cannot find owner for state %p:\n"
|
|
||||||
"%s %c%c %3d [%p] -> %p", state,
|
|
||||||
sprites[state->sprite].name,
|
|
||||||
state->GetFrame() + 'A',
|
|
||||||
state->GetFullbright() ? '*' : ' ',
|
|
||||||
state->GetTics(),
|
|
||||||
state->GetAction(),
|
|
||||||
state->GetNextState());
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const PClass *info;
|
|
||||||
DWORD ofs;
|
|
||||||
|
|
||||||
arc.UserReadClass (info);
|
|
||||||
ofs = arc.ReadCount ();
|
|
||||||
if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
|
|
||||||
{
|
|
||||||
state = NULL;
|
|
||||||
}
|
|
||||||
else if (info->ActorInfo != NULL)
|
|
||||||
{
|
|
||||||
state = info->ActorInfo->OwnedStates + ofs;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arc;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Find the actor that a state belongs to.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
const PClass *FState::StaticFindStateOwner (const FState *state)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
|
|
||||||
{
|
|
||||||
FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
|
|
||||||
if (state >= info->OwnedStates &&
|
|
||||||
state < info->OwnedStates + info->NumOwnedStates)
|
|
||||||
{
|
|
||||||
return info->Class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Find the actor that a state belongs to, but restrict the search to
|
|
||||||
// the specified type and its ancestors.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info)
|
|
||||||
{
|
|
||||||
while (info != NULL)
|
|
||||||
{
|
|
||||||
if (state >= info->OwnedStates &&
|
|
||||||
state < info->OwnedStates + info->NumOwnedStates)
|
|
||||||
{
|
|
||||||
return info->Class;
|
|
||||||
}
|
|
||||||
info = info->Class->ParentClass->ActorInfo;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -344,209 +228,6 @@ void FActorInfo::SetPainChance(FName type, int chance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FStateLabel *FStateLabels::FindLabel (FName label)
|
|
||||||
{
|
|
||||||
return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FStateLabels::Destroy ()
|
|
||||||
{
|
|
||||||
for(int i=0; i<NumLabels;i++)
|
|
||||||
{
|
|
||||||
if (Labels[i].Children != NULL)
|
|
||||||
{
|
|
||||||
Labels[i].Children->Destroy();
|
|
||||||
free (Labels[i].Children); // These are malloc'd, not new'd!
|
|
||||||
Labels[i].Children=NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// HasStates
|
|
||||||
//
|
|
||||||
// Checks whether the actor has special death states.
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
bool AActor::HasSpecialDeathStates () const
|
|
||||||
{
|
|
||||||
const FActorInfo *info = GetClass()->ActorInfo;
|
|
||||||
|
|
||||||
if (info->StateList != NULL)
|
|
||||||
{
|
|
||||||
FStateLabel *slabel = info->StateList->FindLabel (NAME_Death);
|
|
||||||
if (slabel != NULL && slabel->Children != NULL)
|
|
||||||
{
|
|
||||||
for(int i=0;i<slabel->Children->NumLabels;i++)
|
|
||||||
{
|
|
||||||
if (slabel->Children->Labels[i].State != NULL) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// FindState (one name version)
|
|
||||||
//
|
|
||||||
// Finds a state with the exact specified name.
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
FState *AActor::FindState (FName label) const
|
|
||||||
{
|
|
||||||
const FActorInfo *info = GetClass()->ActorInfo;
|
|
||||||
|
|
||||||
if (info->StateList != NULL)
|
|
||||||
{
|
|
||||||
FStateLabel *slabel = info->StateList->FindLabel (label);
|
|
||||||
if (slabel != NULL)
|
|
||||||
{
|
|
||||||
return slabel->State;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// FindState (two name version)
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
FState *AActor::FindState (FName label, FName sublabel, bool exact) const
|
|
||||||
{
|
|
||||||
const FActorInfo *info = GetClass()->ActorInfo;
|
|
||||||
|
|
||||||
if (info->StateList != NULL)
|
|
||||||
{
|
|
||||||
FStateLabel *slabel = info->StateList->FindLabel (label);
|
|
||||||
if (slabel != NULL)
|
|
||||||
{
|
|
||||||
if (slabel->Children != NULL)
|
|
||||||
{
|
|
||||||
FStateLabel *slabel2 = slabel->Children->FindLabel(sublabel);
|
|
||||||
if (slabel2 != NULL)
|
|
||||||
{
|
|
||||||
return slabel2->State;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!exact) return slabel->State;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// FindState (multiple names version)
|
|
||||||
//
|
|
||||||
// Finds a state that matches as many of the supplied names as possible.
|
|
||||||
// A state with more names than those provided does not match.
|
|
||||||
// A state with fewer names can match if there are no states with the exact
|
|
||||||
// same number of names.
|
|
||||||
//
|
|
||||||
// The search proceeds like this. For the current class, keeping matching
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
FState *FActorInfo::FindState (FName name) const
|
|
||||||
{
|
|
||||||
return FindState(1, &name);
|
|
||||||
}
|
|
||||||
|
|
||||||
FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const
|
|
||||||
{
|
|
||||||
FStateLabels *labels = StateList;
|
|
||||||
FState *best = NULL;
|
|
||||||
|
|
||||||
if (labels != NULL)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
FStateLabel *slabel = NULL;
|
|
||||||
FName label;
|
|
||||||
|
|
||||||
// Find the best-matching label for this class.
|
|
||||||
while (labels != NULL && count < numnames)
|
|
||||||
{
|
|
||||||
label = *names++;
|
|
||||||
slabel = labels->FindLabel (label);
|
|
||||||
|
|
||||||
if (slabel != NULL)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
labels = slabel->Children;
|
|
||||||
best = slabel->State;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count < numnames && exact) return NULL;
|
|
||||||
}
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Creates a list of names from a string. Dots are used as separator
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void MakeStateNameList(const char * fname, TArray<FName> * out)
|
|
||||||
{
|
|
||||||
FName firstpart, secondpart;
|
|
||||||
char * c;
|
|
||||||
|
|
||||||
// Handle the old names for the existing death states
|
|
||||||
char * name = copystring(fname);
|
|
||||||
firstpart = strtok(name, ".");
|
|
||||||
switch (firstpart)
|
|
||||||
{
|
|
||||||
case NAME_Burn:
|
|
||||||
firstpart = NAME_Death;
|
|
||||||
secondpart = NAME_Fire;
|
|
||||||
break;
|
|
||||||
case NAME_Ice:
|
|
||||||
firstpart = NAME_Death;
|
|
||||||
secondpart = NAME_Ice;
|
|
||||||
break;
|
|
||||||
case NAME_Disintegrate:
|
|
||||||
firstpart = NAME_Death;
|
|
||||||
secondpart = NAME_Disintegrate;
|
|
||||||
break;
|
|
||||||
case NAME_XDeath:
|
|
||||||
firstpart = NAME_Death;
|
|
||||||
secondpart = NAME_Extreme;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out->Clear();
|
|
||||||
out->Push(firstpart);
|
|
||||||
if (secondpart!=NAME_None) out->Push(secondpart);
|
|
||||||
|
|
||||||
while ((c = strtok(NULL, "."))!=NULL)
|
|
||||||
{
|
|
||||||
FName cc = c;
|
|
||||||
out->Push(cc);
|
|
||||||
}
|
|
||||||
delete [] name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -89,6 +89,7 @@ struct FState
|
||||||
SBYTE Misc1;
|
SBYTE Misc1;
|
||||||
BYTE Misc2;
|
BYTE Misc2;
|
||||||
BYTE Frame;
|
BYTE Frame;
|
||||||
|
BYTE DefineFlags; // Unused byte so let's use it during state creation.
|
||||||
FState *NextState;
|
FState *NextState;
|
||||||
actionf_p ActionFunc;
|
actionf_p ActionFunc;
|
||||||
int ParameterIndex;
|
int ParameterIndex;
|
||||||
|
@ -204,8 +205,12 @@ struct FActorInfo
|
||||||
void SetDamageFactor(FName type, fixed_t factor);
|
void SetDamageFactor(FName type, fixed_t factor);
|
||||||
void SetPainChance(FName type, int chance);
|
void SetPainChance(FName type, int chance);
|
||||||
|
|
||||||
FState *FindState (FName name) const;
|
|
||||||
FState *FindState (int numnames, FName *names, bool exact=false) const;
|
FState *FindState (int numnames, FName *names, bool exact=false) const;
|
||||||
|
FState *FindStateByString(const char *name, bool exact=false);
|
||||||
|
FState *FindState (FName name) const
|
||||||
|
{
|
||||||
|
return FindState(1, &name);
|
||||||
|
}
|
||||||
|
|
||||||
FActorInfo *GetReplacement ();
|
FActorInfo *GetReplacement ();
|
||||||
FActorInfo *GetReplacee ();
|
FActorInfo *GetReplacee ();
|
||||||
|
@ -252,6 +257,6 @@ private:
|
||||||
extern FDoomEdMap DoomEdMap;
|
extern FDoomEdMap DoomEdMap;
|
||||||
|
|
||||||
int GetSpriteIndex(const char * spritename);
|
int GetSpriteIndex(const char * spritename);
|
||||||
void MakeStateNameList(const char * fname, TArray<FName> * out);
|
TArray<FName> &MakeStateNameList(const char * fname);
|
||||||
|
|
||||||
#endif // __INFO_H__
|
#endif // __INFO_H__
|
||||||
|
|
|
@ -5230,16 +5230,13 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_SETACTORSTATE:
|
case PCD_SETACTORSTATE:
|
||||||
{
|
{
|
||||||
const char *statename = FBehavior::StaticLookupString (STACK(2));
|
const char *statename = FBehavior::StaticLookupString (STACK(2));
|
||||||
TArray<FName> statelist;
|
|
||||||
FState *state;
|
FState *state;
|
||||||
|
|
||||||
MakeStateNameList(statename, &statelist);
|
|
||||||
|
|
||||||
if (STACK(3) == 0)
|
if (STACK(3) == 0)
|
||||||
{
|
{
|
||||||
if (activator != NULL)
|
if (activator != NULL)
|
||||||
{
|
{
|
||||||
state = activator->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1));
|
state = activator->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1));
|
||||||
if (state != NULL)
|
if (state != NULL)
|
||||||
{
|
{
|
||||||
activator->SetState (state);
|
activator->SetState (state);
|
||||||
|
@ -5259,7 +5256,7 @@ int DLevelScript::RunScript ()
|
||||||
|
|
||||||
while ( (actor = iterator.Next ()) )
|
while ( (actor = iterator.Next ()) )
|
||||||
{
|
{
|
||||||
state = actor->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1));
|
state = actor->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1));
|
||||||
if (state != NULL)
|
if (state != NULL)
|
||||||
{
|
{
|
||||||
actor->SetState (state);
|
actor->SetState (state);
|
||||||
|
|
|
@ -4811,10 +4811,6 @@ int AActor::DoSpecialDamage (AActor *target, int damage)
|
||||||
|
|
||||||
int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype)
|
int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype)
|
||||||
{
|
{
|
||||||
// If the actor does not have a corresponding death state, then it does not take damage.
|
|
||||||
// Note that DeathState matches every kind of damagetype, so if an actor has that, it can
|
|
||||||
// be hurt with any type of damage. Exception: Massacre damage always succeeds, because
|
|
||||||
// it needs to work.
|
|
||||||
FState *death;
|
FState *death;
|
||||||
|
|
||||||
if (flags5 & MF5_NODAMAGE)
|
if (flags5 & MF5_NODAMAGE)
|
||||||
|
@ -4828,7 +4824,7 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN
|
||||||
// it needs to work.
|
// it needs to work.
|
||||||
|
|
||||||
// Always kill if there is a regular death state or no death states at all.
|
// Always kill if there is a regular death state or no death states at all.
|
||||||
if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates())
|
if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates() || damagetype == NAME_Massacre)
|
||||||
{
|
{
|
||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
|
|
814
src/p_states.cpp
Normal file
814
src/p_states.cpp
Normal file
|
@ -0,0 +1,814 @@
|
||||||
|
/*
|
||||||
|
** p_states.cpp
|
||||||
|
** state management
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 1998-2008 Randy Heit
|
||||||
|
** Copyright 2006-2008 Christoph Oelckers
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions
|
||||||
|
** are met:
|
||||||
|
**
|
||||||
|
** 1. Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in the
|
||||||
|
** documentation and/or other materials provided with the distribution.
|
||||||
|
** 3. The name of the author may not be used to endorse or promote products
|
||||||
|
** derived from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
#include "actor.h"
|
||||||
|
#include "farchive.h"
|
||||||
|
#include "templates.h"
|
||||||
|
#include "cmdlib.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "thingdef/thingdef.h"
|
||||||
|
|
||||||
|
// Each state is owned by an actor. Actors can own any number of
|
||||||
|
// states, but a single state cannot be owned by more than one
|
||||||
|
// actor. States are archived by recording the actor they belong
|
||||||
|
// to and the index into that actor's list of states.
|
||||||
|
|
||||||
|
// For NULL states, which aren't owned by any actor, the owner
|
||||||
|
// is recorded as AActor with the following state. AActor should
|
||||||
|
// never actually have this many states of its own, so this
|
||||||
|
// is (relatively) safe.
|
||||||
|
|
||||||
|
#define NULL_STATE_INDEX 127
|
||||||
|
|
||||||
|
TArray<FName> JumpParameters;
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FArchive &operator<< (FArchive &arc, FState *&state)
|
||||||
|
{
|
||||||
|
const PClass *info;
|
||||||
|
|
||||||
|
if (arc.IsStoring ())
|
||||||
|
{
|
||||||
|
if (state == NULL)
|
||||||
|
{
|
||||||
|
arc.UserWriteClass (RUNTIME_CLASS(AActor));
|
||||||
|
arc.WriteCount (NULL_STATE_INDEX);
|
||||||
|
return arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = FState::StaticFindStateOwner (state);
|
||||||
|
|
||||||
|
if (info != NULL)
|
||||||
|
{
|
||||||
|
arc.UserWriteClass (info);
|
||||||
|
arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* this was never working as intended.
|
||||||
|
I_Error ("Cannot find owner for state %p:\n"
|
||||||
|
"%s %c%c %3d [%p] -> %p", state,
|
||||||
|
sprites[state->sprite].name,
|
||||||
|
state->GetFrame() + 'A',
|
||||||
|
state->GetFullbright() ? '*' : ' ',
|
||||||
|
state->GetTics(),
|
||||||
|
state->GetAction(),
|
||||||
|
state->GetNextState());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const PClass *info;
|
||||||
|
DWORD ofs;
|
||||||
|
|
||||||
|
arc.UserReadClass (info);
|
||||||
|
ofs = arc.ReadCount ();
|
||||||
|
if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
|
||||||
|
{
|
||||||
|
state = NULL;
|
||||||
|
}
|
||||||
|
else if (info->ActorInfo != NULL)
|
||||||
|
{
|
||||||
|
state = info->ActorInfo->OwnedStates + ofs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Find the actor that a state belongs to.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
const PClass *FState::StaticFindStateOwner (const FState *state)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
|
||||||
|
{
|
||||||
|
FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
|
||||||
|
if (state >= info->OwnedStates &&
|
||||||
|
state < info->OwnedStates + info->NumOwnedStates)
|
||||||
|
{
|
||||||
|
return info->Class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Find the actor that a state belongs to, but restrict the search to
|
||||||
|
// the specified type and its ancestors.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info)
|
||||||
|
{
|
||||||
|
while (info != NULL)
|
||||||
|
{
|
||||||
|
if (state >= info->OwnedStates &&
|
||||||
|
state < info->OwnedStates + info->NumOwnedStates)
|
||||||
|
{
|
||||||
|
return info->Class;
|
||||||
|
}
|
||||||
|
info = info->Class->ParentClass->ActorInfo;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FStateLabel *FStateLabels::FindLabel (FName label)
|
||||||
|
{
|
||||||
|
return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FStateLabels::Destroy ()
|
||||||
|
{
|
||||||
|
for(int i=0; i<NumLabels;i++)
|
||||||
|
{
|
||||||
|
if (Labels[i].Children != NULL)
|
||||||
|
{
|
||||||
|
Labels[i].Children->Destroy();
|
||||||
|
free (Labels[i].Children); // These are malloc'd, not new'd!
|
||||||
|
Labels[i].Children=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// HasStates
|
||||||
|
//
|
||||||
|
// Checks whether the actor has special death states.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
bool AActor::HasSpecialDeathStates () const
|
||||||
|
{
|
||||||
|
const FActorInfo *info = GetClass()->ActorInfo;
|
||||||
|
|
||||||
|
if (info->StateList != NULL)
|
||||||
|
{
|
||||||
|
FStateLabel *slabel = info->StateList->FindLabel (NAME_Death);
|
||||||
|
if (slabel != NULL && slabel->Children != NULL)
|
||||||
|
{
|
||||||
|
for(int i=0;i<slabel->Children->NumLabels;i++)
|
||||||
|
{
|
||||||
|
if (slabel->Children->Labels[i].State != NULL) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Resolves a label parameter
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FState *P_GetState(AActor *self, FState *CallingState, int offset)
|
||||||
|
{
|
||||||
|
if (offset == 0 || offset == INT_MIN)
|
||||||
|
{
|
||||||
|
return NULL; // 0 means 'no state'
|
||||||
|
}
|
||||||
|
else if (offset>0)
|
||||||
|
{
|
||||||
|
if (CallingState == NULL) return NULL;
|
||||||
|
return CallingState + offset;
|
||||||
|
}
|
||||||
|
else if (self != NULL)
|
||||||
|
{
|
||||||
|
FName *params = &JumpParameters[-offset];
|
||||||
|
|
||||||
|
FName classname = params[0];
|
||||||
|
const PClass *cls;
|
||||||
|
cls = classname==NAME_None? RUNTIME_TYPE(self) : PClass::FindClass(classname);
|
||||||
|
if (cls==NULL || cls->ActorInfo==NULL) return NULL; // shouldn't happen
|
||||||
|
|
||||||
|
int numnames = (int)params[1];
|
||||||
|
FState *jumpto = cls->ActorInfo->FindState(numnames, ¶ms[2]);
|
||||||
|
if (jumpto == NULL)
|
||||||
|
{
|
||||||
|
const char *dot="";
|
||||||
|
Printf("Jump target '");
|
||||||
|
if (classname != NAME_None) Printf("%s::", classname.GetChars());
|
||||||
|
for (int i=0;i<numnames;i++)
|
||||||
|
{
|
||||||
|
Printf("%s%s", dot, params[2+i].GetChars());
|
||||||
|
dot = ".";
|
||||||
|
}
|
||||||
|
Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
return jumpto;
|
||||||
|
}
|
||||||
|
else return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Creates a list of names from a string. Dots are used as separator
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
TArray<FName> &MakeStateNameList(const char * fname)
|
||||||
|
{
|
||||||
|
static TArray<FName> namelist(3);
|
||||||
|
FName firstpart, secondpart;
|
||||||
|
char * c;
|
||||||
|
|
||||||
|
// Handle the old names for the existing death states
|
||||||
|
char * name = copystring(fname);
|
||||||
|
firstpart = strtok(name, ".");
|
||||||
|
switch (firstpart)
|
||||||
|
{
|
||||||
|
case NAME_Burn:
|
||||||
|
firstpart = NAME_Death;
|
||||||
|
secondpart = NAME_Fire;
|
||||||
|
break;
|
||||||
|
case NAME_Ice:
|
||||||
|
firstpart = NAME_Death;
|
||||||
|
secondpart = NAME_Ice;
|
||||||
|
break;
|
||||||
|
case NAME_Disintegrate:
|
||||||
|
firstpart = NAME_Death;
|
||||||
|
secondpart = NAME_Disintegrate;
|
||||||
|
break;
|
||||||
|
case NAME_XDeath:
|
||||||
|
firstpart = NAME_Death;
|
||||||
|
secondpart = NAME_Extreme;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
namelist.Clear();
|
||||||
|
namelist.Push(firstpart);
|
||||||
|
if (secondpart!=NAME_None) namelist.Push(secondpart);
|
||||||
|
|
||||||
|
while ((c = strtok(NULL, "."))!=NULL)
|
||||||
|
{
|
||||||
|
FName cc = c;
|
||||||
|
namelist.Push(cc);
|
||||||
|
}
|
||||||
|
delete [] name;
|
||||||
|
return namelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// FindState (multiple names version)
|
||||||
|
//
|
||||||
|
// Finds a state that matches as many of the supplied names as possible.
|
||||||
|
// A state with more names than those provided does not match.
|
||||||
|
// A state with fewer names can match if there are no states with the exact
|
||||||
|
// same number of names.
|
||||||
|
//
|
||||||
|
// The search proceeds like this. For the current class, keeping matching
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const
|
||||||
|
{
|
||||||
|
FStateLabels *labels = StateList;
|
||||||
|
FState *best = NULL;
|
||||||
|
|
||||||
|
if (labels != NULL)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
FStateLabel *slabel = NULL;
|
||||||
|
FName label;
|
||||||
|
|
||||||
|
// Find the best-matching label for this class.
|
||||||
|
while (labels != NULL && count < numnames)
|
||||||
|
{
|
||||||
|
label = *names++;
|
||||||
|
slabel = labels->FindLabel (label);
|
||||||
|
|
||||||
|
if (slabel != NULL)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
labels = slabel->Children;
|
||||||
|
best = slabel->State;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count < numnames && exact) return NULL;
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Finds the state associated with the given string
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FState *FActorInfo::FindStateByString(const char *name, bool exact)
|
||||||
|
{
|
||||||
|
TArray<FName> &namelist = MakeStateNameList(name);
|
||||||
|
return FindState(namelist.Size(), &namelist[0], exact);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Search one list of state definitions for the given name
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FStateDefine *FStateDefinitions::FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i<list.Size(); i++)
|
||||||
|
{
|
||||||
|
if (list[i].Label == name) return &list[i];
|
||||||
|
}
|
||||||
|
if (create)
|
||||||
|
{
|
||||||
|
FStateDefine def;
|
||||||
|
def.Label=name;
|
||||||
|
def.State=NULL;
|
||||||
|
def.DefineFlags = SDF_NEXT;
|
||||||
|
return &list[list.Push(def)];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Finds the address of a state label given by name.
|
||||||
|
// Adds the state label if it doesn't exist
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FStateDefine * FStateDefinitions::FindStateAddress(const char *name)
|
||||||
|
{
|
||||||
|
FStateDefine * statedef=NULL;
|
||||||
|
|
||||||
|
TArray<FName> &namelist = MakeStateNameList(name);
|
||||||
|
|
||||||
|
TArray<FStateDefine> * statelist = &StateLabels;
|
||||||
|
for(unsigned i=0;i<namelist.Size();i++)
|
||||||
|
{
|
||||||
|
statedef = FindStateLabelInList(*statelist, namelist[i], true);
|
||||||
|
statelist = &statedef->Children;
|
||||||
|
}
|
||||||
|
return statedef;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Adds a new state tp the curremt list
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::AddState (const char *statename, FState *state, BYTE defflags)
|
||||||
|
{
|
||||||
|
FStateDefine *std = FindStateAddress(statename);
|
||||||
|
std->State = state;
|
||||||
|
std->DefineFlags = defflags;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Finds the state associated with the given name
|
||||||
|
// returns NULL if none found
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FState * FStateDefinitions::FindState(const char * name)
|
||||||
|
{
|
||||||
|
FStateDefine * statedef=NULL;
|
||||||
|
|
||||||
|
TArray<FName> &namelist = MakeStateNameList(name);
|
||||||
|
|
||||||
|
TArray<FStateDefine> * statelist = &StateLabels;
|
||||||
|
for(unsigned i=0;i<namelist.Size();i++)
|
||||||
|
{
|
||||||
|
statedef = FindStateLabelInList(*statelist, namelist[i], false);
|
||||||
|
if (statedef == NULL) return NULL;
|
||||||
|
statelist = &statedef->Children;
|
||||||
|
}
|
||||||
|
return statedef? statedef->State : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Creates the final list of states from the state definitions
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static int STACK_ARGS labelcmp(const void * a, const void * b)
|
||||||
|
{
|
||||||
|
FStateLabel * A = (FStateLabel *)a;
|
||||||
|
FStateLabel * B = (FStateLabel *)b;
|
||||||
|
return ((int)A->Label - (int)B->Label);
|
||||||
|
}
|
||||||
|
|
||||||
|
FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & 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;
|
||||||
|
|
||||||
|
FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
|
||||||
|
list->NumLabels = count;
|
||||||
|
|
||||||
|
for (int i=0;i<count;i++)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// InstallStates
|
||||||
|
//
|
||||||
|
// Creates the actor's state list from the current definition
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults)
|
||||||
|
{
|
||||||
|
// First ensure we have a valid spawn state.
|
||||||
|
FState *state = FindState("Spawn");
|
||||||
|
|
||||||
|
if (state == NULL)
|
||||||
|
{
|
||||||
|
// A NULL spawn state will crash the engine so set it to something valid.
|
||||||
|
AddState("Spawn", GetDefault<AActor>()->SpawnState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->StateList != NULL)
|
||||||
|
{
|
||||||
|
info->StateList->Destroy();
|
||||||
|
M_Free(info->StateList);
|
||||||
|
}
|
||||||
|
info->StateList = CreateStateLabelList(StateLabels);
|
||||||
|
|
||||||
|
// Cache these states as member veriables.
|
||||||
|
defaults->SpawnState = info->FindState(NAME_Spawn);
|
||||||
|
defaults->SeeState = info->FindState(NAME_See);
|
||||||
|
// Melee and Missile states are manipulated by the scripted marines so they
|
||||||
|
// have to be stored locally
|
||||||
|
defaults->MeleeState = info->FindState(NAME_Melee);
|
||||||
|
defaults->MissileState = info->FindState(NAME_Missile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// MakeStateDefines
|
||||||
|
//
|
||||||
|
// Creates a list of state definitions from an existing actor
|
||||||
|
// Used by Dehacked to modify an actor's state list
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
|
||||||
|
{
|
||||||
|
dest.Clear();
|
||||||
|
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||||
|
{
|
||||||
|
FStateDefine def;
|
||||||
|
|
||||||
|
def.Label = list->Labels[i].Label;
|
||||||
|
def.State = list->Labels[i].State;
|
||||||
|
dest.Push(def);
|
||||||
|
if (list->Labels[i].Children != NULL)
|
||||||
|
{
|
||||||
|
MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FStateDefinitions::MakeStateDefines(const PClass *cls)
|
||||||
|
{
|
||||||
|
if (cls->ActorInfo && cls->ActorInfo->StateList)
|
||||||
|
{
|
||||||
|
MakeStateList(cls->ActorInfo->StateList, StateLabels);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearStateLabels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AddStateDefines
|
||||||
|
//
|
||||||
|
// Adds a list of states to the current definitions
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::AddStateDefines(const FStateLabels *list)
|
||||||
|
{
|
||||||
|
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||||
|
{
|
||||||
|
if (list->Labels[i].Children == NULL)
|
||||||
|
{
|
||||||
|
if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false))
|
||||||
|
{
|
||||||
|
FStateDefine def;
|
||||||
|
|
||||||
|
def.Label = list->Labels[i].Label;
|
||||||
|
def.State = list->Labels[i].State;
|
||||||
|
StateLabels.Push(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// RetargetState(Pointer)s
|
||||||
|
//
|
||||||
|
// These functions are used when a goto follows one or more labels.
|
||||||
|
// Because multiple labels are permitted to occur consecutively with no
|
||||||
|
// intervening states, it is not enough to remember the last label defined
|
||||||
|
// and adjust it. So these functions search for all labels that point to
|
||||||
|
// the current position in the state array and give them a copy of the
|
||||||
|
// target string instead.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0;i<statelist.Size(); i++)
|
||||||
|
{
|
||||||
|
if (statelist[i].State == (FState*)count)
|
||||||
|
{
|
||||||
|
if (target == NULL)
|
||||||
|
{
|
||||||
|
statelist[i].State = NULL;
|
||||||
|
statelist[i].DefineFlags = SDF_STOP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statelist[i].State = (FState *)copystring (target);
|
||||||
|
statelist[i].DefineFlags = SDF_LABEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (statelist[i].Children.Size() > 0)
|
||||||
|
{
|
||||||
|
RetargetStatePointers(count, target, statelist[i].Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FStateDefinitions::RetargetStates (intptr_t count, const char *target)
|
||||||
|
{
|
||||||
|
RetargetStatePointers(count, target, StateLabels);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ResolveGotoLabel
|
||||||
|
//
|
||||||
|
// Resolves any strings being stored in a state's NextState field
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name)
|
||||||
|
{
|
||||||
|
const PClass *type=mytype;
|
||||||
|
FState *state;
|
||||||
|
char *namestart = name;
|
||||||
|
char *label, *offset, *pt;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
// Check for classname
|
||||||
|
if ((pt = strstr (name, "::")) != NULL)
|
||||||
|
{
|
||||||
|
const char *classname = name;
|
||||||
|
*pt = '\0';
|
||||||
|
name = pt + 2;
|
||||||
|
|
||||||
|
// The classname may either be "Super" to identify this class's immediate
|
||||||
|
// superclass, or it may be the name of any class that this one derives from.
|
||||||
|
if (stricmp (classname, "Super") == 0)
|
||||||
|
{
|
||||||
|
type = type->ParentClass;
|
||||||
|
actor = GetDefaultByType (type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// first check whether a state of the desired name exists
|
||||||
|
const PClass *stype = PClass::FindClass (classname);
|
||||||
|
if (stype == NULL)
|
||||||
|
{
|
||||||
|
I_Error ("%s is an unknown class.", classname);
|
||||||
|
}
|
||||||
|
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
||||||
|
{
|
||||||
|
I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
if (!stype->IsAncestorOf (type))
|
||||||
|
{
|
||||||
|
I_Error ("%s is not derived from %s so cannot access its states.",
|
||||||
|
type->TypeName.GetChars(), stype->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
if (type != stype)
|
||||||
|
{
|
||||||
|
type = stype;
|
||||||
|
actor = GetDefaultByType (type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label = name;
|
||||||
|
// Check for offset
|
||||||
|
offset = NULL;
|
||||||
|
if ((pt = strchr (name, '+')) != NULL)
|
||||||
|
{
|
||||||
|
*pt = '\0';
|
||||||
|
offset = pt + 1;
|
||||||
|
}
|
||||||
|
v = offset ? strtol (offset, NULL, 0) : 0;
|
||||||
|
|
||||||
|
// Get the state's address.
|
||||||
|
if (type==mytype) state = FindState (label);
|
||||||
|
else state = type->ActorInfo->FindStateByString(label, true);
|
||||||
|
|
||||||
|
if (state != NULL)
|
||||||
|
{
|
||||||
|
state += v;
|
||||||
|
}
|
||||||
|
else if (v != 0)
|
||||||
|
{
|
||||||
|
I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
delete[] namestart; // free the allocated string buffer
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FixStatePointers
|
||||||
|
//
|
||||||
|
// Fixes an actor's default state pointers.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
|
||||||
|
{
|
||||||
|
for(unsigned i=0;i<list.Size(); i++)
|
||||||
|
{
|
||||||
|
size_t v=(size_t)list[i].State;
|
||||||
|
if (v >= 1 && v < 0x10000)
|
||||||
|
{
|
||||||
|
list[i].State = actor->OwnedStates + v - 1;
|
||||||
|
}
|
||||||
|
if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ResolveGotoLabels
|
||||||
|
//
|
||||||
|
// Resolves an actor's state pointers that were specified as jumps.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
|
||||||
|
{
|
||||||
|
for(unsigned i=0;i<list.Size(); i++)
|
||||||
|
{
|
||||||
|
if (list[i].State != NULL && list[i].DefineFlags == SDF_LABEL)
|
||||||
|
{ // It's not a valid state, so it must be a label string. Resolve it.
|
||||||
|
list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State);
|
||||||
|
list[i].DefineFlags = SDF_STATE;
|
||||||
|
}
|
||||||
|
if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FinishStates
|
||||||
|
// copies a state block and fixes all state links using the current list of labels
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray)
|
||||||
|
{
|
||||||
|
static int c=0;
|
||||||
|
int count = StateArray.Size();
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
FState *realstates = new FState[count];
|
||||||
|
int i;
|
||||||
|
int currange;
|
||||||
|
|
||||||
|
memcpy(realstates, &StateArray[0], count*sizeof(FState));
|
||||||
|
actor->OwnedStates = realstates;
|
||||||
|
actor->NumOwnedStates = count;
|
||||||
|
|
||||||
|
// adjust the state pointers
|
||||||
|
// In the case new states are added these must be adjusted, too!
|
||||||
|
FixStatePointers (actor, StateLabels);
|
||||||
|
|
||||||
|
for(i = currange = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// resolve labels and jumps
|
||||||
|
switch(realstates[i].DefineFlags)
|
||||||
|
{
|
||||||
|
case SDF_STOP: // stop
|
||||||
|
realstates[i].NextState = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDF_WAIT: // wait
|
||||||
|
realstates[i].NextState = &realstates[i];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDF_NEXT: // next
|
||||||
|
realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDF_INDEX: // loop
|
||||||
|
realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDF_LABEL:
|
||||||
|
realstates[i].NextState = ResolveGotoLabel (defaults, actor->Class, (char *)realstates[i].NextState);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix state pointers that are gotos
|
||||||
|
ResolveGotoLabels (actor, defaults, StateLabels);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
|
@ -103,8 +103,8 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name);
|
||||||
|
|
||||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||||
|
|
||||||
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
||||||
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc);
|
FExtraInfo &extra, EDefinitionType def, FScanner &sc);
|
||||||
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc);
|
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc);
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
@ -135,12 +135,13 @@ static const char *RenderStyles[] =
|
||||||
|
|
||||||
void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
{
|
{
|
||||||
TArray<FState> states;
|
Baggage bag;
|
||||||
FExtraInfo extra;
|
FExtraInfo extra;
|
||||||
|
FActorInfo *info;
|
||||||
PClass *type;
|
PClass *type;
|
||||||
PClass *parent;
|
PClass *parent;
|
||||||
FActorInfo *info;
|
|
||||||
FName typeName;
|
FName typeName;
|
||||||
|
FStateDefinitions statedef;
|
||||||
|
|
||||||
if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory);
|
if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory);
|
||||||
else parent = RUNTIME_CLASS(AActor);
|
else parent = RUNTIME_CLASS(AActor);
|
||||||
|
@ -148,19 +149,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
typeName = FName(sc.String);
|
typeName = FName(sc.String);
|
||||||
type = parent->CreateDerivedClass (typeName, parent->Size);
|
type = parent->CreateDerivedClass (typeName, parent->Size);
|
||||||
info = type->ActorInfo;
|
ResetBaggage(&bag, parent);
|
||||||
info->GameFilter = 0x80;
|
info = bag.Info = type->ActorInfo;
|
||||||
MakeStateDefines(parent->ActorInfo->StateList);
|
|
||||||
|
|
||||||
info->GameFilter = GAME_Any;
|
info->GameFilter = GAME_Any;
|
||||||
sc.MustGetStringName("{");
|
sc.MustGetStringName("{");
|
||||||
|
|
||||||
states.Clear ();
|
|
||||||
memset (&extra, 0, sizeof(extra));
|
memset (&extra, 0, sizeof(extra));
|
||||||
ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def, sc);
|
ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc);
|
||||||
|
|
||||||
info->NumOwnedStates = states.Size();
|
bag.Info->NumOwnedStates = bag.StateArray.Size();
|
||||||
if (info->NumOwnedStates == 0)
|
if (bag.Info->NumOwnedStates == 0)
|
||||||
{
|
{
|
||||||
sc.ScriptError ("%s does not define any animation frames", typeName.GetChars() );
|
sc.ScriptError ("%s does not define any animation frames", typeName.GetChars() );
|
||||||
}
|
}
|
||||||
|
@ -180,13 +179,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
if (extra.IceDeathEnd != 0)
|
if (extra.IceDeathEnd != 0)
|
||||||
{
|
{
|
||||||
// Make a copy of the final frozen frame for A_FreezeDeathChunks
|
// Make a copy of the final frozen frame for A_FreezeDeathChunks
|
||||||
FState icecopy = states[extra.IceDeathEnd-1];
|
FState icecopy = bag.StateArray[extra.IceDeathEnd-1];
|
||||||
states.Push (icecopy);
|
bag.StateArray.Push (icecopy);
|
||||||
info->NumOwnedStates += 1;
|
info->NumOwnedStates += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->OwnedStates = new FState[info->NumOwnedStates];
|
info->OwnedStates = new FState[info->NumOwnedStates];
|
||||||
memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
|
memcpy (info->OwnedStates, &bag.StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
|
||||||
if (info->NumOwnedStates == 1)
|
if (info->NumOwnedStates == 1)
|
||||||
{
|
{
|
||||||
info->OwnedStates->Tics = -1;
|
info->OwnedStates->Tics = -1;
|
||||||
|
@ -247,7 +246,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
|
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
|
||||||
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
|
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
|
||||||
}
|
}
|
||||||
AddState("Death", &info->OwnedStates[extra.DeathStart]);
|
statedef.AddState("Death", &info->OwnedStates[extra.DeathStart]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burn states are the same as death states, except they can optionally terminate
|
// Burn states are the same as death states, except they can optionally terminate
|
||||||
|
@ -285,7 +284,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
|
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
|
||||||
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
|
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
|
||||||
|
|
||||||
AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
|
statedef.AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ice states are similar to burn and death, except their final frame enters
|
// Ice states are similar to burn and death, except their final frame enters
|
||||||
|
@ -306,11 +305,11 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
info->OwnedStates[i].Tics = 1;
|
info->OwnedStates[i].Tics = 1;
|
||||||
info->OwnedStates[i].Misc1 = 0;
|
info->OwnedStates[i].Misc1 = 0;
|
||||||
info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks"));
|
info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks"));
|
||||||
AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
|
statedef.AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
|
||||||
}
|
}
|
||||||
else if (extra.bGenericIceDeath)
|
else if (extra.bGenericIceDeath)
|
||||||
{
|
{
|
||||||
AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath));
|
statedef.AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def == DEF_BreakableDecoration)
|
if (def == DEF_BreakableDecoration)
|
||||||
|
@ -321,8 +320,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
{
|
{
|
||||||
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
|
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
|
||||||
}
|
}
|
||||||
AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
|
statedef.AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
|
||||||
InstallStates (info, ((AActor *)(type->Defaults)));
|
statedef.InstallStates (info, ((AActor *)(type->Defaults)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -333,8 +332,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
||||||
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc)
|
FExtraInfo &extra, EDefinitionType def, FScanner &sc)
|
||||||
{
|
{
|
||||||
AFakeInventory *const inv = static_cast<AFakeInventory *>(defaults);
|
AFakeInventory *const inv = static_cast<AFakeInventory *>(defaults);
|
||||||
char sprite[5] = "TNT1";
|
char sprite[5] = "TNT1";
|
||||||
|
@ -349,7 +348,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
{
|
{
|
||||||
sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
||||||
}
|
}
|
||||||
info->DoomEdNum = (SWORD)sc.Number;
|
bag.Info->DoomEdNum = (SWORD)sc.Number;
|
||||||
}
|
}
|
||||||
else if (sc.Compare ("SpawnNum"))
|
else if (sc.Compare ("SpawnNum"))
|
||||||
{
|
{
|
||||||
|
@ -358,7 +357,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
{
|
{
|
||||||
sc.ScriptError ("SpawnNum must be in the range [0,255]");
|
sc.ScriptError ("SpawnNum must be in the range [0,255]");
|
||||||
}
|
}
|
||||||
info->SpawnID = (BYTE)sc.Number;
|
bag.Info->SpawnID = (BYTE)sc.Number;
|
||||||
}
|
}
|
||||||
else if (sc.Compare ("Sprite") || (
|
else if (sc.Compare ("Sprite") || (
|
||||||
(def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
(def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
||||||
|
@ -383,31 +382,31 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
else if (sc.Compare ("Frames"))
|
else if (sc.Compare ("Frames"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
extra.SpawnStart = states.Size();
|
extra.SpawnStart = bag.StateArray.Size();
|
||||||
ParseSpriteFrames (info, states, sc);
|
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||||
extra.SpawnEnd = states.Size();
|
extra.SpawnEnd = bag.StateArray.Size();
|
||||||
}
|
}
|
||||||
else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
||||||
sc.Compare ("DeathFrames"))
|
sc.Compare ("DeathFrames"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
extra.DeathStart = states.Size();
|
extra.DeathStart = bag.StateArray.Size();
|
||||||
ParseSpriteFrames (info, states, sc);
|
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||||
extra.DeathEnd = states.Size();
|
extra.DeathEnd = bag.StateArray.Size();
|
||||||
}
|
}
|
||||||
else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames"))
|
else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
extra.IceDeathStart = states.Size();
|
extra.IceDeathStart = bag.StateArray.Size();
|
||||||
ParseSpriteFrames (info, states, sc);
|
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||||
extra.IceDeathEnd = states.Size();
|
extra.IceDeathEnd = bag.StateArray.Size();
|
||||||
}
|
}
|
||||||
else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames"))
|
else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
extra.FireDeathStart = states.Size();
|
extra.FireDeathStart = bag.StateArray.Size();
|
||||||
ParseSpriteFrames (info, states, sc);
|
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||||
extra.FireDeathEnd = states.Size();
|
extra.FireDeathEnd = bag.StateArray.Size();
|
||||||
}
|
}
|
||||||
else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath"))
|
else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath"))
|
||||||
{
|
{
|
||||||
|
@ -464,18 +463,18 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
|
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
|
||||||
{
|
{
|
||||||
sc.MustGetNumber ();
|
sc.MustGetNumber ();
|
||||||
info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number);
|
bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number);
|
||||||
extra.bExplosive = true;
|
extra.bExplosive = true;
|
||||||
}
|
}
|
||||||
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
|
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
|
||||||
{
|
{
|
||||||
sc.MustGetNumber ();
|
sc.MustGetNumber ();
|
||||||
info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number);
|
bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number);
|
||||||
extra.bExplosive = true;
|
extra.bExplosive = true;
|
||||||
}
|
}
|
||||||
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
|
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
|
||||||
{
|
{
|
||||||
info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true);
|
bag.Info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true);
|
||||||
}
|
}
|
||||||
else if (def == DEF_Projectile && sc.Compare ("Damage"))
|
else if (def == DEF_Projectile && sc.Compare ("Damage"))
|
||||||
{
|
{
|
||||||
|
@ -560,7 +559,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String);
|
bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String);
|
||||||
}
|
}
|
||||||
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
||||||
{
|
{
|
||||||
|
@ -576,8 +575,6 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
}
|
}
|
||||||
else if (sc.String[0] != '*')
|
else if (sc.String[0] != '*')
|
||||||
{
|
{
|
||||||
Baggage bag;
|
|
||||||
bag.Info = info;
|
|
||||||
HandleActorFlag(sc, bag, sc.String, NULL, '+');
|
HandleActorFlag(sc, bag, sc.String, NULL, '+');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -590,16 +587,16 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int spr = GetSpriteIndex(sprite);
|
int spr = GetSpriteIndex(sprite);
|
||||||
|
|
||||||
for (i = 0; i < states.Size(); ++i)
|
for (i = 0; i < bag.StateArray.Size(); ++i)
|
||||||
{
|
{
|
||||||
states[i].sprite = spr;
|
bag.StateArray[i].sprite = spr;
|
||||||
}
|
}
|
||||||
if (extra.DeathSprite[0] && extra.DeathEnd != 0)
|
if (extra.DeathSprite[0] && extra.DeathEnd != 0)
|
||||||
{
|
{
|
||||||
int spr = GetSpriteIndex(extra.DeathSprite);
|
int spr = GetSpriteIndex(extra.DeathSprite);
|
||||||
for (i = extra.DeathStart; i < extra.DeathEnd; ++i)
|
for (i = extra.DeathStart; i < extra.DeathEnd; ++i)
|
||||||
{
|
{
|
||||||
states[i].sprite = spr;
|
bag.StateArray[i].sprite = spr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,8 +169,8 @@ int ParseParameter(FScanner &sc, PClass *cls, char type, bool constant)
|
||||||
// be checked here.
|
// be checked here.
|
||||||
JumpParameters.Push(NAME_None);
|
JumpParameters.Push(NAME_None);
|
||||||
}
|
}
|
||||||
TArray<FName> names;
|
|
||||||
MakeStateNameList(statestring, &names);
|
TArray<FName> &names = MakeStateNameList(statestring);
|
||||||
|
|
||||||
if (stype != NULL)
|
if (stype != NULL)
|
||||||
{
|
{
|
||||||
|
@ -420,8 +420,6 @@ static FActorInfo *CreateNewActor(FName typeName, FName parentName, FName replac
|
||||||
info = ti->ActorInfo;
|
info = ti->ActorInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeStateDefines(parent->ActorInfo->StateList);
|
|
||||||
|
|
||||||
info->DoomEdNum = -1;
|
info->DoomEdNum = -1;
|
||||||
if (parent->ActorInfo->DamageFactors != NULL)
|
if (parent->ActorInfo->DamageFactors != NULL)
|
||||||
{
|
{
|
||||||
|
@ -522,7 +520,7 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FActorInfo *info = CreateNewActor(typeName, parentName, replaceName, DoomEdNum, native);
|
FActorInfo *info = CreateNewActor(typeName, parentName, replaceName, DoomEdNum, native);
|
||||||
ResetBaggage (bag);
|
ResetBaggage (bag, info->Class->ParentClass);
|
||||||
bag->Info = info;
|
bag->Info = info;
|
||||||
bag->Lumpnum = sc.LumpNum;
|
bag->Lumpnum = sc.LumpNum;
|
||||||
return info;
|
return info;
|
||||||
|
@ -577,8 +575,8 @@ void ParseActor(FScanner &sc)
|
||||||
sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars());
|
sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
FinishActor(sc, info, bag);
|
|
||||||
}
|
}
|
||||||
|
FinishActor(sc, info, bag);
|
||||||
sc.SetCMode (false);
|
sc.SetCMode (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,68 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// State parser
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
extern TArray<int> StateParameters;
|
||||||
|
extern TArray<FName> JumpParameters;
|
||||||
|
|
||||||
|
struct FStateLabels;
|
||||||
|
|
||||||
|
enum EStateDefineFlags
|
||||||
|
{
|
||||||
|
SDF_NEXT = 0,
|
||||||
|
SDF_STATE = 1,
|
||||||
|
SDF_STOP = 2,
|
||||||
|
SDF_WAIT = 3,
|
||||||
|
SDF_LABEL = 4,
|
||||||
|
SDF_INDEX = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FStateDefine
|
||||||
|
{
|
||||||
|
FName Label;
|
||||||
|
TArray<FStateDefine> Children;
|
||||||
|
FState *State;
|
||||||
|
BYTE DefineFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FStateDefinitions
|
||||||
|
{
|
||||||
|
TArray<FStateDefine> StateLabels;
|
||||||
|
|
||||||
|
static FStateDefine *FindStateLabelInList(TArray<FStateDefine> &list, FName name, bool create);
|
||||||
|
static FStateLabels *CreateStateLabelList(TArray<FStateDefine> &statelist);
|
||||||
|
static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest);
|
||||||
|
static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist);
|
||||||
|
FStateDefine *FindStateAddress(const char *name);
|
||||||
|
FState *FindState(const char *name);
|
||||||
|
|
||||||
|
FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name);
|
||||||
|
static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list);
|
||||||
|
void ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
void ClearStateLabels()
|
||||||
|
{
|
||||||
|
StateLabels.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddState (const char * statename, FState * state, BYTE defflags = SDF_STATE);
|
||||||
|
void InstallStates(FActorInfo *info, AActor *defaults);
|
||||||
|
int FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray);
|
||||||
|
|
||||||
|
void MakeStateDefines(const PClass *cls);
|
||||||
|
void AddStateDefines(const FStateLabels *list);
|
||||||
|
void RetargetStates (intptr_t count, const char *target);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Extra info maintained while defining an actor.
|
// Extra info maintained while defining an actor.
|
||||||
|
@ -62,16 +124,20 @@ struct Baggage
|
||||||
bool StateSet;
|
bool StateSet;
|
||||||
int CurrentState;
|
int CurrentState;
|
||||||
int Lumpnum;
|
int Lumpnum;
|
||||||
|
FStateDefinitions statedef;
|
||||||
|
TArray<FState> StateArray;
|
||||||
|
|
||||||
FDropItem *DropItemList;
|
FDropItem *DropItemList;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void ResetBaggage (Baggage *bag)
|
inline void ResetBaggage (Baggage *bag, const PClass *stateclass)
|
||||||
{
|
{
|
||||||
bag->DropItemList = NULL;
|
bag->DropItemList = NULL;
|
||||||
bag->DropItemSet = false;
|
bag->DropItemSet = false;
|
||||||
bag->CurrentState = 0;
|
bag->CurrentState = 0;
|
||||||
bag->StateSet = false;
|
bag->StateSet = false;
|
||||||
|
bag->StateArray.Clear();
|
||||||
|
bag->statedef.MakeStateDefines(stateclass);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -90,25 +156,8 @@ AFuncDesc * FindFunction(const char * string);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// State parser
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
extern TArray<int> StateParameters;
|
|
||||||
extern TArray<FName> JumpParameters;
|
|
||||||
|
|
||||||
void ClearStateLabels();
|
|
||||||
void AddState (const char * statename, FState * state);
|
|
||||||
FState * FindState(AActor * actor, const PClass * type, const char * name);
|
|
||||||
void InstallStates(FActorInfo *info, AActor *defaults);
|
|
||||||
void MakeStateDefines(const FStateLabels *list);
|
|
||||||
void AddStateDefines(const FStateLabels *list);
|
|
||||||
FState *P_GetState(AActor *self, FState *CallingState, int offset);
|
FState *P_GetState(AActor *self, FState *CallingState, int offset);
|
||||||
int FinishStates (FActorInfo *actor, AActor *defaults);
|
|
||||||
int ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag);
|
int ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag);
|
||||||
FState *CheckState(FScanner &sc, PClass *type);
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -507,7 +507,7 @@ void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||||
}
|
}
|
||||||
else if (MatchString(propname, statenames) != -1)
|
else if (MatchString(propname, statenames) != -1)
|
||||||
{
|
{
|
||||||
AddState(propname, CheckState (sc, bag.Info->Class));
|
bag.statedef.AddState(propname, CheckState (sc, bag.Info->Class));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -528,13 +528,14 @@ void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FinishStates (info, defaults);
|
bag.statedef.FinishStates (info, defaults, bag.StateArray);
|
||||||
}
|
}
|
||||||
catch (CRecoverableError &err)
|
catch (CRecoverableError &err)
|
||||||
{
|
{
|
||||||
sc.ScriptError(err.GetMessage());
|
sc.ScriptError(err.GetMessage());
|
||||||
}
|
}
|
||||||
InstallStates (info, defaults);
|
bag.statedef.InstallStates (info, defaults);
|
||||||
|
bag.StateArray.Clear ();
|
||||||
if (bag.DropItemSet)
|
if (bag.DropItemSet)
|
||||||
{
|
{
|
||||||
if (bag.DropItemList == NULL)
|
if (bag.DropItemList == NULL)
|
||||||
|
|
|
@ -573,8 +573,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
|
||||||
{
|
{
|
||||||
FreeDropItemChain (bag.DropItemList);
|
FreeDropItemChain (bag.DropItemList);
|
||||||
}
|
}
|
||||||
ResetBaggage (&bag);
|
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
|
||||||
MakeStateDefines(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -57,9 +57,7 @@
|
||||||
#include "colormatcher.h"
|
#include "colormatcher.h"
|
||||||
|
|
||||||
TArray<int> StateParameters;
|
TArray<int> StateParameters;
|
||||||
TArray<FName> JumpParameters;
|
|
||||||
static TArray<AFuncDesc> AFTable;
|
static TArray<AFuncDesc> AFTable;
|
||||||
static TArray<FState> StateArray;
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -132,291 +130,8 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Find a state address
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
struct FStateDefine
|
|
||||||
{
|
|
||||||
FName Label;
|
|
||||||
TArray<FStateDefine> Children;
|
|
||||||
FState *State;
|
|
||||||
};
|
|
||||||
|
|
||||||
static TArray<FStateDefine> StateLabels;
|
|
||||||
|
|
||||||
void ClearStateLabels()
|
|
||||||
{
|
|
||||||
StateLabels.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Search one list of state definitions for the given name
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static FStateDefine * FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
|
|
||||||
{
|
|
||||||
for(unsigned i = 0; i<list.Size(); i++)
|
|
||||||
{
|
|
||||||
if (list[i].Label == name) return &list[i];
|
|
||||||
}
|
|
||||||
if (create)
|
|
||||||
{
|
|
||||||
FStateDefine def;
|
|
||||||
def.Label=name;
|
|
||||||
def.State=NULL;
|
|
||||||
return &list[list.Push(def)];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Finds the address of a state given by name.
|
|
||||||
// Adds the state if it doesn't exist
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static FStateDefine * FindStateAddress(const char * name)
|
|
||||||
{
|
|
||||||
static TArray<FName> namelist(3);
|
|
||||||
FStateDefine * statedef=NULL;
|
|
||||||
|
|
||||||
MakeStateNameList(name, &namelist);
|
|
||||||
|
|
||||||
TArray<FStateDefine> * statelist = &StateLabels;
|
|
||||||
for(unsigned i=0;i<namelist.Size();i++)
|
|
||||||
{
|
|
||||||
statedef = FindStateLabelInList(*statelist, namelist[i], true);
|
|
||||||
statelist = &statedef->Children;
|
|
||||||
}
|
|
||||||
return statedef;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddState (const char * statename, FState * state)
|
|
||||||
{
|
|
||||||
FStateDefine * std = FindStateAddress(statename);
|
|
||||||
std->State = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Finds the state associated with the given name
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FState * FindState(AActor * actor, const PClass * type, const char * name)
|
|
||||||
{
|
|
||||||
static TArray<FName> namelist(3);
|
|
||||||
FStateDefine * statedef=NULL;
|
|
||||||
|
|
||||||
MakeStateNameList(name, &namelist);
|
|
||||||
|
|
||||||
TArray<FStateDefine> * statelist = &StateLabels;
|
|
||||||
for(unsigned i=0;i<namelist.Size();i++)
|
|
||||||
{
|
|
||||||
statedef = FindStateLabelInList(*statelist, namelist[i], false);
|
|
||||||
if (statedef == NULL) return NULL;
|
|
||||||
statelist = &statedef->Children;
|
|
||||||
}
|
|
||||||
return statedef? statedef->State : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Finds the state associated with the given name
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FState * FindStateInClass(AActor * actor, const PClass * type, const char * name)
|
|
||||||
{
|
|
||||||
static TArray<FName> namelist(3);
|
|
||||||
|
|
||||||
MakeStateNameList(name, &namelist);
|
|
||||||
FActorInfo * info = type->ActorInfo;
|
|
||||||
if (info) return info->FindState(namelist.Size(), &namelist[0], true);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Checks if a state list is empty
|
|
||||||
// A list is empty if it doesn't contain any states and no children
|
|
||||||
// that contain any states
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static bool IsStateListEmpty(TArray<FStateDefine> & statelist)
|
|
||||||
{
|
|
||||||
for(unsigned i=0;i<statelist.Size();i++)
|
|
||||||
{
|
|
||||||
if (statelist[i].State!=NULL || !IsStateListEmpty(statelist[i].Children)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Creates the final list of states from the state definitions
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static int STACK_ARGS labelcmp(const void * a, const void * b)
|
|
||||||
{
|
|
||||||
FStateLabel * A = (FStateLabel *)a;
|
|
||||||
FStateLabel * B = (FStateLabel *)b;
|
|
||||||
return ((int)A->Label - (int)B->Label);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FStateLabels * CreateStateLabelList(TArray<FStateDefine> & 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;
|
|
||||||
|
|
||||||
FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
|
|
||||||
list->NumLabels = count;
|
|
||||||
|
|
||||||
for (int i=0;i<count;i++)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// InstallStates
|
|
||||||
//
|
|
||||||
// Creates the actor's state list from the current definition
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
void InstallStates(FActorInfo *info, AActor *defaults)
|
|
||||||
{
|
|
||||||
// First ensure we have a valid spawn state.
|
|
||||||
FState * state = FindState(defaults, info->Class, "Spawn");
|
|
||||||
|
|
||||||
if (state == NULL)
|
|
||||||
{
|
|
||||||
// A NULL spawn state will crash the engine so set it to something valid.
|
|
||||||
AddState("Spawn", GetDefault<AActor>()->SpawnState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->StateList != NULL)
|
|
||||||
{
|
|
||||||
info->StateList->Destroy();
|
|
||||||
M_Free(info->StateList);
|
|
||||||
}
|
|
||||||
info->StateList = CreateStateLabelList(StateLabels);
|
|
||||||
|
|
||||||
// Cache these states as member veriables.
|
|
||||||
defaults->SpawnState = info->FindState(NAME_Spawn);
|
|
||||||
defaults->SeeState = info->FindState(NAME_See);
|
|
||||||
// Melee and Missile states are manipulated by the scripted marines so they
|
|
||||||
// have to be stored locally
|
|
||||||
defaults->MeleeState = info->FindState(NAME_Melee);
|
|
||||||
defaults->MissileState = info->FindState(NAME_Missile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// MakeStateDefines
|
|
||||||
//
|
|
||||||
// Creates a list of state definitions from an existing actor
|
|
||||||
// Used by Dehacked to modify an actor's state list
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
|
|
||||||
{
|
|
||||||
dest.Clear();
|
|
||||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
|
||||||
{
|
|
||||||
FStateDefine def;
|
|
||||||
|
|
||||||
def.Label = list->Labels[i].Label;
|
|
||||||
def.State = list->Labels[i].State;
|
|
||||||
dest.Push(def);
|
|
||||||
if (list->Labels[i].Children != NULL)
|
|
||||||
{
|
|
||||||
MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MakeStateDefines(const FStateLabels *list)
|
|
||||||
{
|
|
||||||
MakeStateList(list, StateLabels);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddStateDefines(const FStateLabels *list)
|
|
||||||
{
|
|
||||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
|
||||||
{
|
|
||||||
if (list->Labels[i].Children == NULL)
|
|
||||||
{
|
|
||||||
if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false))
|
|
||||||
{
|
|
||||||
FStateDefine def;
|
|
||||||
|
|
||||||
def.Label = list->Labels[i].Label;
|
|
||||||
def.State = list->Labels[i].State;
|
|
||||||
StateLabels.Push(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// RetargetState(Pointer)s
|
|
||||||
//
|
|
||||||
// These functions are used when a goto follows one or more labels.
|
|
||||||
// Because multiple labels are permitted to occur consecutively with no
|
|
||||||
// intervening states, it is not enough to remember the last label defined
|
|
||||||
// and adjust it. So these functions search for all labels that point to
|
|
||||||
// the current position in the state array and give them a copy of the
|
|
||||||
// target string instead.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
|
|
||||||
{
|
|
||||||
for(unsigned i = 0;i<statelist.Size(); i++)
|
|
||||||
{
|
|
||||||
if (statelist[i].State == (FState*)count)
|
|
||||||
{
|
|
||||||
statelist[i].State = target == NULL ? NULL : (FState *)copystring (target);
|
|
||||||
}
|
|
||||||
if (statelist[i].Children.Size() > 0)
|
|
||||||
{
|
|
||||||
RetargetStatePointers(count, target, statelist[i].Children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RetargetStates (intptr_t count, const char *target)
|
|
||||||
{
|
|
||||||
RetargetStatePointers(count, target, StateLabels);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -552,10 +267,11 @@ do_goto:
|
||||||
if (laststate != NULL)
|
if (laststate != NULL)
|
||||||
{ // Following a state definition: Modify it.
|
{ // Following a state definition: Modify it.
|
||||||
laststate->NextState = (FState*)copystring(statestring);
|
laststate->NextState = (FState*)copystring(statestring);
|
||||||
|
laststate->DefineFlags = SDF_LABEL;
|
||||||
}
|
}
|
||||||
else if (lastlabel >= 0)
|
else if (lastlabel >= 0)
|
||||||
{ // Following a label: Retarget it.
|
{ // Following a label: Retarget it.
|
||||||
RetargetStates (count+1, statestring);
|
bag.statedef.RetargetStates (count+1, statestring);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -567,11 +283,11 @@ do_goto:
|
||||||
do_stop:
|
do_stop:
|
||||||
if (laststate!=NULL)
|
if (laststate!=NULL)
|
||||||
{
|
{
|
||||||
laststate->NextState=(FState*)-1;
|
laststate->DefineFlags = SDF_STOP;
|
||||||
}
|
}
|
||||||
else if (lastlabel >=0)
|
else if (lastlabel >=0)
|
||||||
{
|
{
|
||||||
RetargetStates (count+1, NULL);
|
bag.statedef.RetargetStates (count+1, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -586,7 +302,7 @@ do_stop:
|
||||||
sc.ScriptError("%s before first state", sc.String);
|
sc.ScriptError("%s before first state", sc.String);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
laststate->NextState=(FState*)-2;
|
laststate->DefineFlags = SDF_WAIT;
|
||||||
}
|
}
|
||||||
else if (!statestring.CompareNoCase("LOOP"))
|
else if (!statestring.CompareNoCase("LOOP"))
|
||||||
{
|
{
|
||||||
|
@ -596,6 +312,7 @@ do_stop:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
laststate->NextState=(FState*)(lastlabel+1);
|
laststate->NextState=(FState*)(lastlabel+1);
|
||||||
|
laststate->DefineFlags = SDF_INDEX;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -608,7 +325,7 @@ do_stop:
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
lastlabel = count;
|
lastlabel = count;
|
||||||
AddState(statestring, (FState *) (count+1));
|
bag.statedef.AddState(statestring, (FState *) (count+1), SDF_INDEX);
|
||||||
statestring = ParseStateString(sc);
|
statestring = ParseStateString(sc);
|
||||||
if (!statestring.CompareNoCase("GOTO"))
|
if (!statestring.CompareNoCase("GOTO"))
|
||||||
{
|
{
|
||||||
|
@ -789,7 +506,7 @@ do_stop:
|
||||||
}
|
}
|
||||||
sc.UnGet();
|
sc.UnGet();
|
||||||
endofstate:
|
endofstate:
|
||||||
StateArray.Push(state);
|
bag.StateArray.Push(state);
|
||||||
while (*statestrp)
|
while (*statestrp)
|
||||||
{
|
{
|
||||||
int frame=((*statestrp++)&223)-'A';
|
int frame=((*statestrp++)&223)-'A';
|
||||||
|
@ -801,10 +518,10 @@ endofstate:
|
||||||
}
|
}
|
||||||
|
|
||||||
state.Frame=(state.Frame&(SF_FULLBRIGHT))|frame;
|
state.Frame=(state.Frame&(SF_FULLBRIGHT))|frame;
|
||||||
StateArray.Push(state);
|
bag.StateArray.Push(state);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
laststate=&StateArray[count];
|
laststate=&bag.StateArray[count];
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -816,186 +533,3 @@ endofstate:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ResolveGotoLabel
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name)
|
|
||||||
{
|
|
||||||
const PClass *type=mytype;
|
|
||||||
FState *state;
|
|
||||||
char *namestart = name;
|
|
||||||
char *label, *offset, *pt;
|
|
||||||
int v;
|
|
||||||
|
|
||||||
// Check for classname
|
|
||||||
if ((pt = strstr (name, "::")) != NULL)
|
|
||||||
{
|
|
||||||
const char *classname = name;
|
|
||||||
*pt = '\0';
|
|
||||||
name = pt + 2;
|
|
||||||
|
|
||||||
// The classname may either be "Super" to identify this class's immediate
|
|
||||||
// superclass, or it may be the name of any class that this one derives from.
|
|
||||||
if (stricmp (classname, "Super") == 0)
|
|
||||||
{
|
|
||||||
type = type->ParentClass;
|
|
||||||
actor = GetDefaultByType (type);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// first check whether a state of the desired name exists
|
|
||||||
const PClass *stype = PClass::FindClass (classname);
|
|
||||||
if (stype == NULL)
|
|
||||||
{
|
|
||||||
I_Error ("%s is an unknown class.", classname);
|
|
||||||
}
|
|
||||||
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
|
||||||
{
|
|
||||||
I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
|
||||||
}
|
|
||||||
if (!stype->IsAncestorOf (type))
|
|
||||||
{
|
|
||||||
I_Error ("%s is not derived from %s so cannot access its states.",
|
|
||||||
type->TypeName.GetChars(), stype->TypeName.GetChars());
|
|
||||||
}
|
|
||||||
if (type != stype)
|
|
||||||
{
|
|
||||||
type = stype;
|
|
||||||
actor = GetDefaultByType (type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label = name;
|
|
||||||
// Check for offset
|
|
||||||
offset = NULL;
|
|
||||||
if ((pt = strchr (name, '+')) != NULL)
|
|
||||||
{
|
|
||||||
*pt = '\0';
|
|
||||||
offset = pt + 1;
|
|
||||||
}
|
|
||||||
v = offset ? strtol (offset, NULL, 0) : 0;
|
|
||||||
|
|
||||||
// Get the state's address.
|
|
||||||
if (type==mytype) state = FindState (actor, type, label);
|
|
||||||
else state = FindStateInClass (actor, type, label);
|
|
||||||
|
|
||||||
if (state != NULL)
|
|
||||||
{
|
|
||||||
state += v;
|
|
||||||
}
|
|
||||||
else if (v != 0)
|
|
||||||
{
|
|
||||||
I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
|
|
||||||
}
|
|
||||||
delete[] namestart; // free the allocated string buffer
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FixStatePointers
|
|
||||||
//
|
|
||||||
// Fixes an actor's default state pointers.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
|
|
||||||
{
|
|
||||||
for(unsigned i=0;i<list.Size(); i++)
|
|
||||||
{
|
|
||||||
size_t v=(size_t)list[i].State;
|
|
||||||
if (v >= 1 && v < 0x10000)
|
|
||||||
{
|
|
||||||
list[i].State = actor->OwnedStates + v - 1;
|
|
||||||
}
|
|
||||||
if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FixStatePointersAgain
|
|
||||||
//
|
|
||||||
// Resolves an actor's state pointers that were specified as jumps.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void FixStatePointersAgain (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
|
|
||||||
{
|
|
||||||
for(unsigned i=0;i<list.Size(); i++)
|
|
||||||
{
|
|
||||||
if (list[i].State != NULL && FState::StaticFindStateOwner (list[i].State, actor) == NULL)
|
|
||||||
{ // It's not a valid state, so it must be a label string. Resolve it.
|
|
||||||
list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State);
|
|
||||||
}
|
|
||||||
if (list[i].Children.Size() > 0) FixStatePointersAgain(actor, defaults, list[i].Children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FinishStates
|
|
||||||
// copies a state block and fixes all state links
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
int FinishStates (FActorInfo *actor, AActor *defaults)
|
|
||||||
{
|
|
||||||
static int c=0;
|
|
||||||
int count = StateArray.Size();
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
FState *realstates = new FState[count];
|
|
||||||
int i;
|
|
||||||
int currange;
|
|
||||||
|
|
||||||
memcpy(realstates, &StateArray[0], count*sizeof(FState));
|
|
||||||
actor->OwnedStates = realstates;
|
|
||||||
actor->NumOwnedStates = count;
|
|
||||||
|
|
||||||
// adjust the state pointers
|
|
||||||
// In the case new states are added these must be adjusted, too!
|
|
||||||
FixStatePointers (actor, StateLabels);
|
|
||||||
|
|
||||||
for(i = currange = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
// resolve labels and jumps
|
|
||||||
switch((ptrdiff_t)realstates[i].NextState)
|
|
||||||
{
|
|
||||||
case 0: // next
|
|
||||||
realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -1: // stop
|
|
||||||
realstates[i].NextState = NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -2: // wait
|
|
||||||
realstates[i].NextState = &realstates[i];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: // loop
|
|
||||||
if ((size_t)realstates[i].NextState < 0x10000)
|
|
||||||
{
|
|
||||||
realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
|
|
||||||
}
|
|
||||||
else // goto
|
|
||||||
{
|
|
||||||
realstates[i].NextState = ResolveGotoLabel (defaults, actor->Class, (char *)realstates[i].NextState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StateArray.Clear ();
|
|
||||||
|
|
||||||
// Fix state pointers that are gotos
|
|
||||||
FixStatePointersAgain (actor, defaults, StateLabels);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ const int SXF_ABSOLUTEMOMENTUM=8;
|
||||||
const int SXF_SETMASTER=16;
|
const int SXF_SETMASTER=16;
|
||||||
const int SXF_NOCHECKPOSITION = 32;
|
const int SXF_NOCHECKPOSITION = 32;
|
||||||
const int SXF_TELEFRAG=64;
|
const int SXF_TELEFRAG=64;
|
||||||
const int SXF_TRANSFERAMBUSHFLAG=128;
|
// 128 was uses by Skulltag
|
||||||
|
const int SXF_TRANSFERAMBUSHFLAG=256;
|
||||||
|
|
||||||
// Flags for A_Chase
|
// Flags for A_Chase
|
||||||
const int CHF_FASTCHASE = 1;
|
const int CHF_FASTCHASE = 1;
|
||||||
|
|
|
@ -840,6 +840,10 @@
|
||||||
RelativePath=".\src\p_spec.cpp"
|
RelativePath=".\src\p_spec.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\p_states.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\p_switch.cpp"
|
RelativePath=".\src\p_switch.cpp"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue