Skip to content

Commit

Permalink
- dsdehacked: allow dynamic creation of new states.
Browse files Browse the repository at this point in the history
  • Loading branch information
coelckers committed Sep 12, 2021
1 parent f783a94 commit 61654a2
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 23 deletions.
41 changes: 35 additions & 6 deletions src/gamedata/d_dehacked.cpp
Expand Up @@ -150,7 +150,7 @@ struct MBFArgs
int argsused;
};
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
// List of states that are hacked to use a codepointer
Expand Down Expand Up @@ -341,7 +341,7 @@ FString PatchName;
static int PatchSize;
static char *Line1, *Line2;
static int dversion, pversion;
static bool including, includenotext;
static bool including, includenotext, dsdhacked = false;
static int LumpFileNum;

static const char *unknown_str = "Unknown key %s encountered in %s %d.\n";
Expand Down Expand Up @@ -373,6 +373,8 @@ static int PatchPars (int);
static int PatchCodePtrs (int);
static int PatchMusic (int);
static int DoInclude (int);
static int PatchSpriteNames (int);
static int PatchSoundNames (int);
static bool DoDehPatch();

static const struct {
Expand All @@ -396,6 +398,8 @@ static const struct {
{ "[PARS]", PatchPars },
{ "[CODEPTR]", PatchCodePtrs },
{ "[MUSIC]", PatchMusic },
{ "[SPRITES]", PatchSpriteNames },
{ "[SOUNDS]", PatchSoundNames },
{ NULL, NULL },
};

Expand Down Expand Up @@ -456,12 +460,12 @@ static int FindSprite (const char *sprname)
return f == UnchangedSpriteNames.Size() ? -1 : f;
}

static FState *FindState (int statenum)
static FState *FindState (int statenum, bool mustexist)
{
int stateacc;
unsigned i;

if (statenum == 0)
if (statenum <= 0)
return NULL;

for (i = 0, stateacc = 1; i < StateMap.Size(); i++)
Expand All @@ -480,6 +484,18 @@ static FState *FindState (int statenum)
}
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);
state = {};
state->tics = -1;
state->NextState = state;
state->DehIndex = statenum;

}
return NULL;
}

Expand Down Expand Up @@ -745,7 +761,7 @@ static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int v
// misc1 = state, misc2 = probability
static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state)
{ // A_Jump
auto symlabel = StateLabels.AddPointer(FindState(value1));
auto symlabel = StateLabels.AddPointer(FindState(value1, true));

emitters.AddParameterIntConst(value2); // maxchance
emitters.AddParameterIntConst(symlabel); // jumpto
Expand Down Expand Up @@ -2283,7 +2299,7 @@ static int PatchPointer (int ptrNum)
{
if ((unsigned)ptrNum < CodePConv.Size() && (!stricmp (Line1, "Codep Frame")))
{
FState *state = FindState (CodePConv[ptrNum]);
FState *state = FindState (CodePConv[ptrNum], true);
if (state)
{
int index = atoi(Line2);
Expand Down Expand Up @@ -3093,6 +3109,11 @@ static bool DoDehPatch()
dversion = 1;
else if (dversion == 21)
dversion = 4;
else if (dversion == 2021)
{
dversion = 4;
dsdhacked = true;
}
else
{
Printf ("Patch created with unknown DOOM version.\nAssuming version 1.9.\n");
Expand Down Expand Up @@ -3300,6 +3321,7 @@ static bool LoadDehSupp ()
else if (sc.Compare("StateMap"))
{
bool addit = StateMap.Size() == 0;
int dehcount = 0;

sc.MustGetStringName("{");
while (!sc.CheckString("}"))
Expand Down Expand Up @@ -3341,6 +3363,13 @@ static bool LoadDehSupp ()

if (sc.CheckString("}")) break;
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"))
Expand Down
3 changes: 3 additions & 0 deletions src/gamedata/info.h
Expand Up @@ -111,6 +111,7 @@ struct FState
uint8_t DefineFlags;
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 DehIndex; // we need this to resolve offsets in P_SetSafeFlash.
public:
inline int GetFrame() const
{
Expand Down Expand Up @@ -177,6 +178,8 @@ struct FState

};

extern TMap<int, FState*> dehExtStates;

struct FStateLabels;
struct FStateLabel
{
Expand Down
17 changes: 12 additions & 5 deletions src/p_states.cpp
Expand Up @@ -43,6 +43,7 @@

// stores indices for symbolic state labels for some old-style DECORATE functions.
FStateLabelStorage StateLabels;
TMap<int, FState*> dehExtStates;

// 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
Expand Down Expand Up @@ -137,6 +138,7 @@ FString FState::StaticGetStateName(const FState *state, PClassActor *info)
}
if (so == nullptr)
{
if (state->DehIndex > 0) return FStringf("DehExtraState.%d", state->DehIndex);
return "<unknown>";
}
return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->GetStates()));
Expand Down Expand Up @@ -1028,6 +1030,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor)

for (i = 0; i < count; i++)
{
realstates[i].DehIndex = -1;
// resolve labels and jumps
switch (realstates[i].DefineFlags)
{
Expand Down Expand Up @@ -1073,16 +1076,20 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix)
{
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)
{
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
{
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)
Expand Down Expand Up @@ -1134,7 +1141,7 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo)
{
// Safely calculate the distance between two states.
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);
}
Expand Down
1 change: 0 additions & 1 deletion src/playsim/p_actionfunctions.cpp
Expand Up @@ -126,7 +126,6 @@ static int CallStateChain (AActor *self, AActor *actor, FState *state)
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.
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",
FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName.GetChars());
state->ActionFunc = nullptr;
Expand Down
30 changes: 20 additions & 10 deletions src/playsim/p_pspr.cpp
Expand Up @@ -1300,25 +1300,35 @@ void P_SetSafeFlash(AActor *weapon, player_t *player, FState *flashstate, int in
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
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);
return;
}
else break; // no need to continue.
}
// try again with parent class
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.
// The only way to check this would be to go through all Dehacked modifiable actors, convert
// their states into a single flat array and find the correct one.
// Rather than that, just check to make sure it belongs to something.
if (FState::StaticFindStateOwner(flashstate + index) == NULL)
{ // Invalid state. With no index offset, it should at least be valid.
index = 0;

// if we get here the target state doesn't belong to any class in the inheritance chain.
// This can happen with Dehacked if the flash states are remapped.
// In this case we should check the Dehacked state map to get the proper state.
if (flashstate->DehIndex >= 0)
{
auto pTargetstate = dehExtStates.CheckKey(flashstate->DehIndex + index);
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);
}
Expand Down
16 changes: 15 additions & 1 deletion src/serializer_doom.cpp
Expand Up @@ -346,6 +346,13 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
arc.w->Uint((uint32_t)(state - info->GetStates()));
arc.w->EndArray();
}
else if (state->DehIndex >= 0)
{
arc.w->StartArray();
arc.w->String("@DehExtraState@");
arc.w->Uint(state->DehIndex);
arc.w->EndArray();
}
else
{
arc.w->Null();
Expand Down Expand Up @@ -373,11 +380,18 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
assert(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())
{
state = clas->GetStates() + ndx.GetUint();
}
else if (!strcmp(str, "@DehExtraState@"))
{
state = nullptr;
auto pState = dehExtStates.CheckKey(ndx.GetInt());
if (pState) state = *pState;
}
else
{
// this can actually happen by changing the DECORATE so treat it as a warning, not an error.
Expand Down

0 comments on commit 61654a2

Please sign in to comment.