diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index e4acc75a6..f79924b2b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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 &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 &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); } diff --git a/src/info.cpp b/src/info.cpp index 49f139ebe..7198a5de4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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. diff --git a/src/info.h b/src/info.h index 6d3de5015..6ced755a3 100644 --- a/src/info.h +++ b/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) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 39b0f423e..be875b951 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 36aa00aae..d91b7ab00 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -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) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index d522ad573..21ab33dfb 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -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 diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 1fbb67fe4..77c2fcbd1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -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; } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d500458a2..04410189a 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -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 diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 317a69846..52b354028 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -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)