mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-07 09:01:57 +00:00
- dsdehacked: allow dynamic creation of new states.
This commit is contained in:
parent
99983b37ca
commit
b44741b8aa
6 changed files with 85 additions and 23 deletions
|
@ -150,7 +150,7 @@ struct MBFArgs
|
||||||
int argsused;
|
int argsused;
|
||||||
};
|
};
|
||||||
static TMap<FState*, MBFArgs> stateargs;
|
static TMap<FState*, MBFArgs> stateargs;
|
||||||
static FState* FindState(int statenum);
|
static FState* FindState(int statenum, bool mustexist = false);
|
||||||
|
|
||||||
// DeHackEd trickery to support MBF-style parameters
|
// DeHackEd trickery to support MBF-style parameters
|
||||||
// List of states that are hacked to use a codepointer
|
// List of states that are hacked to use a codepointer
|
||||||
|
@ -341,7 +341,7 @@ FString PatchName;
|
||||||
static int PatchSize;
|
static int PatchSize;
|
||||||
static char *Line1, *Line2;
|
static char *Line1, *Line2;
|
||||||
static int dversion, pversion;
|
static int dversion, pversion;
|
||||||
static bool including, includenotext;
|
static bool including, includenotext, dsdhacked = false;
|
||||||
static int LumpFileNum;
|
static int LumpFileNum;
|
||||||
|
|
||||||
static const char *unknown_str = "Unknown key %s encountered in %s %d.\n";
|
static const char *unknown_str = "Unknown key %s encountered in %s %d.\n";
|
||||||
|
@ -373,6 +373,8 @@ static int PatchPars (int);
|
||||||
static int PatchCodePtrs (int);
|
static int PatchCodePtrs (int);
|
||||||
static int PatchMusic (int);
|
static int PatchMusic (int);
|
||||||
static int DoInclude (int);
|
static int DoInclude (int);
|
||||||
|
static int PatchSpriteNames (int);
|
||||||
|
static int PatchSoundNames(int) {} // todo
|
||||||
static bool DoDehPatch();
|
static bool DoDehPatch();
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -396,6 +398,8 @@ static const struct {
|
||||||
{ "[PARS]", PatchPars },
|
{ "[PARS]", PatchPars },
|
||||||
{ "[CODEPTR]", PatchCodePtrs },
|
{ "[CODEPTR]", PatchCodePtrs },
|
||||||
{ "[MUSIC]", PatchMusic },
|
{ "[MUSIC]", PatchMusic },
|
||||||
|
{ "[SPRITES]", PatchSpriteNames },
|
||||||
|
{ "[SOUNDS]", PatchSoundNames },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -456,12 +460,12 @@ static int FindSprite (const char *sprname)
|
||||||
return f == UnchangedSpriteNames.Size() ? -1 : f;
|
return f == UnchangedSpriteNames.Size() ? -1 : f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FState *FindState (int statenum)
|
static FState *FindState (int statenum, bool mustexist)
|
||||||
{
|
{
|
||||||
int stateacc;
|
int stateacc;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
if (statenum == 0)
|
if (statenum <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = 0, stateacc = 1; i < StateMap.Size(); i++)
|
for (i = 0, stateacc = 1; i < StateMap.Size(); i++)
|
||||||
|
@ -480,6 +484,18 @@ static FState *FindState (int statenum)
|
||||||
}
|
}
|
||||||
stateacc += StateMap[i].StateSpan;
|
stateacc += StateMap[i].StateSpan;
|
||||||
}
|
}
|
||||||
|
if (dsdhacked && !mustexist)
|
||||||
|
{
|
||||||
|
auto p = dehExtStates.CheckKey(statenum);
|
||||||
|
if (p) return *p;
|
||||||
|
auto state = (FState*)ClassDataAllocator.Alloc(sizeof(FState));
|
||||||
|
dehExtStates.Insert(statenum, state);
|
||||||
|
memset(state, 0, sizeof(*state));
|
||||||
|
state->Tics = -1;
|
||||||
|
state->NextState = state;
|
||||||
|
state->DehIndex = statenum;
|
||||||
|
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,7 +761,7 @@ static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int v
|
||||||
// misc1 = state, misc2 = probability
|
// misc1 = state, misc2 = probability
|
||||||
static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state)
|
static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state)
|
||||||
{ // A_Jump
|
{ // A_Jump
|
||||||
auto symlabel = StateLabels.AddPointer(FindState(value1));
|
auto symlabel = StateLabels.AddPointer(FindState(value1, true));
|
||||||
|
|
||||||
emitters.AddParameterIntConst(value2); // maxchance
|
emitters.AddParameterIntConst(value2); // maxchance
|
||||||
emitters.AddParameterIntConst(symlabel); // jumpto
|
emitters.AddParameterIntConst(symlabel); // jumpto
|
||||||
|
@ -2288,7 +2304,7 @@ static int PatchPointer (int ptrNum)
|
||||||
{
|
{
|
||||||
if ((unsigned)ptrNum < CodePConv.Size() && (!stricmp (Line1, "Codep Frame")))
|
if ((unsigned)ptrNum < CodePConv.Size() && (!stricmp (Line1, "Codep Frame")))
|
||||||
{
|
{
|
||||||
FState *state = FindState (CodePConv[ptrNum]);
|
FState *state = FindState (CodePConv[ptrNum], true);
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
int index = atoi(Line2);
|
int index = atoi(Line2);
|
||||||
|
@ -3112,6 +3128,11 @@ static bool DoDehPatch()
|
||||||
dversion = 1;
|
dversion = 1;
|
||||||
else if (dversion == 21)
|
else if (dversion == 21)
|
||||||
dversion = 4;
|
dversion = 4;
|
||||||
|
else if (dversion == 2021)
|
||||||
|
{
|
||||||
|
dversion = 4;
|
||||||
|
dsdhacked = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Printf ("Patch created with unknown DOOM version.\nAssuming version 1.9.\n");
|
Printf ("Patch created with unknown DOOM version.\nAssuming version 1.9.\n");
|
||||||
|
@ -3319,6 +3340,7 @@ static bool LoadDehSupp ()
|
||||||
else if (sc.Compare("StateMap"))
|
else if (sc.Compare("StateMap"))
|
||||||
{
|
{
|
||||||
bool addit = StateMap.Size() == 0;
|
bool addit = StateMap.Size() == 0;
|
||||||
|
int dehcount = 0;
|
||||||
|
|
||||||
sc.MustGetStringName("{");
|
sc.MustGetStringName("{");
|
||||||
while (!sc.CheckString("}"))
|
while (!sc.CheckString("}"))
|
||||||
|
@ -3360,6 +3382,13 @@ static bool LoadDehSupp ()
|
||||||
|
|
||||||
if (sc.CheckString("}")) break;
|
if (sc.CheckString("}")) break;
|
||||||
sc.MustGetStringName(",");
|
sc.MustGetStringName(",");
|
||||||
|
// This mapping is mainly for P_SetSafeFlash.
|
||||||
|
for (int i = 0; i < s.StateSpan; i++)
|
||||||
|
{
|
||||||
|
dehExtStates.Insert(dehcount, s.State + i);
|
||||||
|
s.State[i].DehIndex = dehcount;
|
||||||
|
dehcount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sc.Compare("SoundMap"))
|
else if (sc.Compare("SoundMap"))
|
||||||
|
|
|
@ -112,6 +112,7 @@ struct FState
|
||||||
uint8_t DefineFlags;
|
uint8_t DefineFlags;
|
||||||
int32_t Misc1; // Was changed to int8_t, reverted to long for MBF compat
|
int32_t Misc1; // Was changed to int8_t, reverted to long for MBF compat
|
||||||
int32_t Misc2; // Was changed to uint8_t, reverted to long for MBF compat
|
int32_t Misc2; // Was changed to uint8_t, reverted to long for MBF compat
|
||||||
|
int32_t DehIndex; // we need this to resolve offsets in P_SetSafeFlash.
|
||||||
public:
|
public:
|
||||||
inline int GetFrame() const
|
inline int GetFrame() const
|
||||||
{
|
{
|
||||||
|
@ -178,6 +179,8 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern TMap<int, FState*> dehExtStates;
|
||||||
|
|
||||||
struct FStateLabels;
|
struct FStateLabels;
|
||||||
struct FStateLabel
|
struct FStateLabel
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
// stores indices for symbolic state labels for some old-style DECORATE functions.
|
// stores indices for symbolic state labels for some old-style DECORATE functions.
|
||||||
FStateLabelStorage StateLabels;
|
FStateLabelStorage StateLabels;
|
||||||
|
TMap<int, FState*> dehExtStates;
|
||||||
|
|
||||||
// Each state is owned by an actor. Actors can own any number of
|
// 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
|
// states, but a single state cannot be owned by more than one
|
||||||
|
@ -138,6 +139,7 @@ FString FState::StaticGetStateName(const FState *state, PClassActor *info)
|
||||||
}
|
}
|
||||||
if (so == nullptr)
|
if (so == nullptr)
|
||||||
{
|
{
|
||||||
|
if (state->DehIndex > 0) return FStringf("DehExtraState.%d", state->DehIndex);
|
||||||
return "<unknown>";
|
return "<unknown>";
|
||||||
}
|
}
|
||||||
return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->GetStates()));
|
return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->GetStates()));
|
||||||
|
@ -1029,6 +1031,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor)
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
|
realstates[i].DehIndex = -1;
|
||||||
// resolve labels and jumps
|
// resolve labels and jumps
|
||||||
switch (realstates[i].DefineFlags)
|
switch (realstates[i].DefineFlags)
|
||||||
{
|
{
|
||||||
|
@ -1074,16 +1077,20 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < StateList->NumLabels; i++)
|
for (int i = 0; i < StateList->NumLabels; i++)
|
||||||
{
|
{
|
||||||
if (StateList->Labels[i].State != NULL)
|
auto state = StateList->Labels[i].State;
|
||||||
|
if (state != NULL)
|
||||||
{
|
{
|
||||||
const PClassActor *owner = FState::StaticFindStateOwner(StateList->Labels[i].State);
|
const PClassActor *owner = FState::StaticFindStateOwner(state);
|
||||||
if (owner == NULL)
|
if (owner == NULL)
|
||||||
{
|
{
|
||||||
Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars());
|
if (state->DehIndex >= 0)
|
||||||
|
Printf(PRINT_LOG, "%s%s: DehExtra %d\n", prefix.GetChars(), state->DehIndex);
|
||||||
|
else
|
||||||
|
Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Printf(PRINT_LOG, "%s%s: %s\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), FState::StaticGetStateName(StateList->Labels[i].State).GetChars());
|
Printf(PRINT_LOG, "%s%s: %s\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), FState::StaticGetStateName(state).GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StateList->Labels[i].Children != NULL)
|
if (StateList->Labels[i].Children != NULL)
|
||||||
|
@ -1135,7 +1142,7 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo)
|
||||||
{
|
{
|
||||||
// Safely calculate the distance between two states.
|
// Safely calculate the distance between two states.
|
||||||
auto o1 = FState::StaticFindStateOwner(self);
|
auto o1 = FState::StaticFindStateOwner(self);
|
||||||
if (o1->OwnsState(other)) retv = int(other - self);
|
if (o1 && o1->OwnsState(other)) retv = int(other - self);
|
||||||
}
|
}
|
||||||
ACTION_RETURN_INT(retv);
|
ACTION_RETURN_INT(retv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,6 @@ static int CallStateChain (AActor *self, AActor *actor, FState *state)
|
||||||
if (state->ActionFunc->Unsafe)
|
if (state->ActionFunc->Unsafe)
|
||||||
{
|
{
|
||||||
// If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash.
|
// If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash.
|
||||||
auto owner = FState::StaticFindStateOwner(state);
|
|
||||||
Printf(TEXTCOLOR_RED "Unsafe state call in state %s to %s which accesses user variables. The action function has been removed from this state\n",
|
Printf(TEXTCOLOR_RED "Unsafe state call in state %s to %s which accesses user variables. The action function has been removed from this state\n",
|
||||||
FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName);
|
FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName);
|
||||||
state->ActionFunc = nullptr;
|
state->ActionFunc = nullptr;
|
||||||
|
|
|
@ -1352,25 +1352,35 @@ void P_SetSafeFlash(AActor *weapon, player_t *player, FState *flashstate, int in
|
||||||
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
|
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else if (flashstate->DehIndex < 0)
|
||||||
{
|
{
|
||||||
// oh, no! The state is beyond the end of the state table so use the original flash state.
|
// oh, no! The state is beyond the end of the state table so use the original flash state if it does not have a Dehacked index.
|
||||||
P_SetPsprite(player, PSP_FLASH, flashstate, true);
|
P_SetPsprite(player, PSP_FLASH, flashstate, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else break; // no need to continue.
|
||||||
}
|
}
|
||||||
// try again with parent class
|
// try again with parent class
|
||||||
cls = static_cast<PClassActor *>(cls->ParentClass);
|
cls = static_cast<PClassActor *>(cls->ParentClass);
|
||||||
}
|
}
|
||||||
// if we get here the state doesn't seem to belong to any class in the inheritance chain
|
|
||||||
// This can happen with Dehacked if the flash states are remapped.
|
// if we get here the target state doesn't belong to any class in the inheritance chain.
|
||||||
// The only way to check this would be to go through all Dehacked modifiable actors, convert
|
// This can happen with Dehacked if the flash states are remapped.
|
||||||
// their states into a single flat array and find the correct one.
|
// In this case we should check the Dehacked state map to get the proper state.
|
||||||
// Rather than that, just check to make sure it belongs to something.
|
if (flashstate->DehIndex >= 0)
|
||||||
if (FState::StaticFindStateOwner(flashstate + index) == NULL)
|
{
|
||||||
{ // Invalid state. With no index offset, it should at least be valid.
|
auto pTargetstate = dehExtStates.CheckKey(flashstate->DehIndex + index);
|
||||||
index = 0;
|
if (pTargetstate)
|
||||||
|
{
|
||||||
|
P_SetPsprite(player, PSP_FLASH, *pTargetstate, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we still haven't found anything here, just use the base flash state.
|
||||||
|
// Normally this code should not be reachable.
|
||||||
|
index = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
|
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,6 +346,13 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
|
||||||
arc.w->Uint((uint32_t)(state - info->GetStates()));
|
arc.w->Uint((uint32_t)(state - info->GetStates()));
|
||||||
arc.w->EndArray();
|
arc.w->EndArray();
|
||||||
}
|
}
|
||||||
|
else if (state->DehIndex >= 0)
|
||||||
|
{
|
||||||
|
arc.w->StartArray();
|
||||||
|
arc.w->String("@DehExtraState@");
|
||||||
|
arc.w->Uint(state->DehIndex);
|
||||||
|
arc.w->EndArray();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arc.w->Null();
|
arc.w->Null();
|
||||||
|
@ -373,11 +380,18 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
|
||||||
assert(cls.IsString() && ndx.IsUint());
|
assert(cls.IsString() && ndx.IsUint());
|
||||||
if (cls.IsString() && ndx.IsUint())
|
if (cls.IsString() && ndx.IsUint())
|
||||||
{
|
{
|
||||||
PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString()));
|
auto str = UnicodeToString(cls.GetString());
|
||||||
|
PClassActor *clas = PClass::FindActor(str);
|
||||||
if (clas && ndx.GetUint() < (unsigned)clas->GetStateCount())
|
if (clas && ndx.GetUint() < (unsigned)clas->GetStateCount())
|
||||||
{
|
{
|
||||||
state = clas->GetStates() + ndx.GetUint();
|
state = clas->GetStates() + ndx.GetUint();
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(str, "@DehExtraState@"))
|
||||||
|
{
|
||||||
|
state = nullptr;
|
||||||
|
auto pState = dehExtStates.CheckKey(ndx.GetInt());
|
||||||
|
if (pState) state = *pState;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// this can actually happen by changing the DECORATE so treat it as a warning, not an error.
|
// this can actually happen by changing the DECORATE so treat it as a warning, not an error.
|
||||||
|
|
Loading…
Reference in a new issue