mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-27 22:42:57 +00:00
- changed action function interface so that callers can be identified directly, instead of guessing it from looking at the parameters.
With arbitrary PSP layers the old method was no longer safe because the layer ID was not available in the action function.
This commit is contained in:
parent
7ccdbf9b62
commit
cfaa3e3fa9
9 changed files with 54 additions and 32 deletions
|
@ -807,11 +807,12 @@ void SetDehParams(FState *state, int codepointer)
|
|||
VMFunctionBuilder buildit;
|
||||
// Allocate registers used to pass parameters in.
|
||||
// self, stateowner, state (all are pointers)
|
||||
buildit.Registers[REGT_POINTER].Get(3);
|
||||
buildit.Registers[REGT_POINTER].Get(NAP);
|
||||
// Emit code to pass the standard action function parameters.
|
||||
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0);
|
||||
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1);
|
||||
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2);
|
||||
for (int i = 0; i < NAP; i++)
|
||||
{
|
||||
buildit.Emit(OP_PARAM, 0, REGT_POINTER, i);
|
||||
}
|
||||
// Emit code for action parameters.
|
||||
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
|
||||
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0);
|
||||
|
@ -2114,7 +2115,7 @@ static int PatchCodePtrs (int dummy)
|
|||
else
|
||||
{
|
||||
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
||||
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > 3 && !(args[3] & VARF_Optional)))
|
||||
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
||||
{
|
||||
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
|
||||
sym = NULL;
|
||||
|
@ -2726,7 +2727,7 @@ static bool LoadDehSupp ()
|
|||
else
|
||||
{
|
||||
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
||||
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > 3 && !(args[3] & VARF_Optional)))
|
||||
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
||||
{
|
||||
sc.ScriptMessage("Incompatible code pointer '%s'", sc.String);
|
||||
}
|
||||
|
|
|
@ -69,14 +69,14 @@ void FState::SetAction(const char *name)
|
|||
ActionFunc = FindGlobalActionFunction(name)->Variants[0].Implementation;
|
||||
}
|
||||
|
||||
bool FState::CallAction(AActor *self, AActor *stateowner, FState **stateret)
|
||||
bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret)
|
||||
{
|
||||
if (ActionFunc != NULL)
|
||||
{
|
||||
ActionCycles.Clock();
|
||||
|
||||
static VMFrameStack stack;
|
||||
VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) };
|
||||
VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) };
|
||||
// If the function returns a state, store it at *stateret.
|
||||
// If it doesn't return a state but stateret is non-NULL, we need
|
||||
// to set *stateret to NULL.
|
||||
|
|
19
src/info.h
19
src/info.h
|
@ -55,6 +55,21 @@ struct FActorInfo;
|
|||
class FArchive;
|
||||
class FIntCVar;
|
||||
|
||||
enum EStateType
|
||||
{
|
||||
STATE_Actor,
|
||||
STATE_Psprite,
|
||||
STATE_StateChain,
|
||||
};
|
||||
|
||||
struct FStateParamInfo
|
||||
{
|
||||
FState *mCallingState;
|
||||
EStateType mStateType;
|
||||
int mPSPIndex;
|
||||
};
|
||||
|
||||
|
||||
// Sprites that are fixed in position because they can have special meanings.
|
||||
enum
|
||||
{
|
||||
|
@ -129,7 +144,7 @@ struct FState
|
|||
void SetAction(VMFunction *func) { ActionFunc = func; }
|
||||
void ClearAction() { ActionFunc = NULL; }
|
||||
void SetAction(const char *name);
|
||||
bool CallAction(AActor *self, AActor *stateowner, FState **stateret);
|
||||
bool CallAction(AActor *self, AActor *stateowner, FStateParamInfo *stateinfo, FState **stateret);
|
||||
static PClassActor *StaticFindStateOwner (const FState *state);
|
||||
static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info);
|
||||
static FRandom pr_statetics;
|
||||
|
@ -338,7 +353,7 @@ void AddStateLight(FState *state, const char *lname);
|
|||
PARAM_PROLOGUE; \
|
||||
PARAM_OBJECT (self, type); \
|
||||
PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \
|
||||
PARAM_STATE_OPT (callingstate) { callingstate = NULL; } \
|
||||
PARAM_STATEINFO_OPT (stateinfo) { stateinfo = nullptr; } \
|
||||
|
||||
#define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor)
|
||||
|
||||
|
|
|
@ -556,7 +556,8 @@ bool AActor::SetState (FState *newstate, bool nofunction)
|
|||
if (!nofunction)
|
||||
{
|
||||
FState *returned_state;
|
||||
if (newstate->CallAction(this, this, &returned_state))
|
||||
FStateParamInfo stp = { newstate, STATE_Actor, PSP_WEAPON };
|
||||
if (newstate->CallAction(this, this, &stp, &returned_state))
|
||||
{
|
||||
// Check whether the called action function resulted in destroying the actor
|
||||
if (ObjectFlags & OF_EuthanizeMe)
|
||||
|
@ -3866,7 +3867,8 @@ bool AActor::CheckNoDelay()
|
|||
// For immediately spawned objects with the NoDelay flag set for their
|
||||
// Spawn state, explicitly call the current state's function.
|
||||
FState *newstate;
|
||||
if (state->CallAction(this, this, &newstate))
|
||||
FStateParamInfo stp = { state, STATE_Actor, PSP_WEAPON };
|
||||
if (state->CallAction(this, this, &stp, &newstate))
|
||||
{
|
||||
if (ObjectFlags & OF_EuthanizeMe)
|
||||
{
|
||||
|
|
|
@ -321,7 +321,8 @@ void DPSprite::SetState(FState *newstate, bool pending)
|
|||
if (Owner->mo != nullptr)
|
||||
{
|
||||
FState *nextstate;
|
||||
if (newstate->CallAction(Owner->mo, Caller, &nextstate))
|
||||
FStateParamInfo stp = { newstate, STATE_Psprite, ID };
|
||||
if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate))
|
||||
{
|
||||
// It's possible this call resulted in this very layer being replaced.
|
||||
if (ObjectFlags & OF_EuthanizeMe)
|
||||
|
|
|
@ -350,7 +350,7 @@ int MatchString (const char *in, const char **strings);
|
|||
//#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall
|
||||
|
||||
#define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \
|
||||
VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATE) }; \
|
||||
VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATEINFO) }; \
|
||||
stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \
|
||||
}
|
||||
|
||||
|
@ -360,7 +360,7 @@ int MatchString (const char *in, const char **strings);
|
|||
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)
|
||||
|
||||
// Checks to see what called the current action function
|
||||
#define ACTION_CALL_FROM_ACTOR() (callingstate == self->state)
|
||||
#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && !(stateowner->flags5 & MF5_INSTATECALL))
|
||||
#define ACTION_CALL_FROM_INVENTORY() (!(stateowner->flags5 & MF5_INSTATECALL))
|
||||
#define ACTION_CALL_FROM_ACTOR() (stateinfo == nullptr || stateinfo->mStateType == STATE_Actor)
|
||||
#define ACTION_CALL_FROM_WEAPON() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite)
|
||||
#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain)
|
||||
#endif
|
||||
|
|
|
@ -133,8 +133,9 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
|
|||
VMFrameStack stack;
|
||||
PPrototype *proto = state->ActionFunc->Proto;
|
||||
VMReturn *wantret;
|
||||
FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON };
|
||||
|
||||
params[2] = VMValue(state, ATAG_STATE);
|
||||
params[2] = VMValue(&stp, ATAG_STATEINFO);
|
||||
retval = true; // assume success
|
||||
wantret = NULL; // assume no return value wanted
|
||||
numret = 0;
|
||||
|
@ -5839,22 +5840,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics)
|
|||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_INT(tics_to_set);
|
||||
|
||||
if (self->player != nullptr)
|
||||
{ // Need to check psp states for a match, then. Blah.
|
||||
DPSprite *pspr = self->player->psprites;
|
||||
while (pspr)
|
||||
if (ACTION_CALL_FROM_WEAPON())
|
||||
{
|
||||
DPSprite *pspr = self->player->FindPSprite(stateinfo->mPSPIndex);
|
||||
if (pspr != nullptr)
|
||||
{
|
||||
if (pspr->GetState() == callingstate)
|
||||
{
|
||||
pspr->Tics = tics_to_set;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pspr = pspr->GetNext();
|
||||
pspr->Tics = tics_to_set;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Just set tics for self.
|
||||
self->tics = tics_to_set;
|
||||
else if (ACTION_CALL_FROM_ACTOR())
|
||||
{
|
||||
// Just set tics for self.
|
||||
self->tics = tics_to_set;
|
||||
}
|
||||
// for inventory state chains this needs to be ignored.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2916,7 +2916,7 @@ ExpEmit FxDamage::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage)));
|
||||
|
||||
// If it's non-null...
|
||||
build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(0, ATAG_GENERIC));
|
||||
build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
|
||||
size_t nulljump = build->Emit(OP_JMP, 0);
|
||||
|
||||
// ...call it
|
||||
|
|
|
@ -152,6 +152,7 @@ enum
|
|||
ATAG_AREGISTER, // pointer to an address register
|
||||
|
||||
ATAG_STATE, // pointer to FState
|
||||
ATAG_STATEINFO, // FState plus some info.
|
||||
ATAG_RNG, // pointer to FRandom
|
||||
};
|
||||
|
||||
|
@ -914,6 +915,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_ANGLE_OPT_AT(p,x) DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
|
||||
#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else
|
||||
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
|
||||
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
|
||||
#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
|
||||
#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
|
||||
#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else
|
||||
|
@ -943,6 +945,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_ANGLE_OPT(x) ++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x)
|
||||
#define PARAM_STRING_OPT(x) ++paramnum; PARAM_STRING_OPT_AT(paramnum,x)
|
||||
#define PARAM_STATE_OPT(x) ++paramnum; PARAM_STATE_OPT_AT(paramnum,x)
|
||||
#define PARAM_STATEINFO_OPT(x) ++paramnum; PARAM_STATEINFO_OPT_AT(paramnum,x)
|
||||
#define PARAM_POINTER_OPT(x,type) ++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type)
|
||||
#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type)
|
||||
#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base)
|
||||
|
|
Loading…
Reference in a new issue