From ac86a535e7c3c7899c70519a9b22714141ca5b46 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 14 Nov 2016 14:12:27 +0100 Subject: [PATCH] - fixed: State labels were resolved in the calling function's context instead of the called function one's. This could cause problems with functions that take states as parameters but use them to set them internally instead of passing them through the A_Jump interface back to the caller, like A_Chase or A_LookEx. This required some quite significant refactoring because the entire state resolution logic had been baked into the compiler which turned out to be a major maintenance problem. Fixed this by adding a new builtin type 'statelabel'. This is an opaque identifier representing a state, with the actual data either directly encoded into the number for single label state or an index into a state information table. The state resolution is now the task of the called function as it should always have remained. Note, that this required giving back the 'action' qualifier to most state jumping functions. - refactored most A_Jump checkers to a two stage setup with a pure checker that returns a boolean and a scripted A_Jump wrapper, for some simpler checks the checker function was entirely omitted and calculated inline in the A_Jump function. It is strongly recommended to use the boolean checkers unless using an inline function invocation in a state as they lead to vastly clearer code and offer more flexibility. - let Min() and Max() use the OP_MIN and OP_MAX opcodes. Although these were present, these function were implemented using some grossly inefficient branching tests. - the DECORATE 'state' cast kludge will now actually call ResolveState because a state label is not a state and needs conversion. --- src/d_dehacked.cpp | 2 +- src/dobjtype.cpp | 29 +- src/dobjtype.h | 14 +- src/info.h | 38 ++ src/namedef.h | 4 +- src/p_actionfunctions.cpp | 429 +++--------------- src/p_mobj.cpp | 4 +- src/p_pspr.cpp | 19 +- src/p_pspr.h | 1 + src/p_states.cpp | 90 ++++ src/scripting/codegeneration/codegen.cpp | 273 +++-------- src/scripting/codegeneration/codegen.h | 8 +- src/scripting/decorate/thingdef_parse.cpp | 5 +- src/scripting/decorate/thingdef_states.cpp | 7 +- src/scripting/vm/vm.h | 12 +- src/scripting/zscript/zcc_compile.cpp | 10 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 47 +- wadsrc/static/zscript/actor_checks.txt | 274 +++++++++++ wadsrc/static/zscript/doom/bossbrain.txt | 2 +- wadsrc/static/zscript/heretic/hereticimp.txt | 2 +- wadsrc/static/zscript/hexen/bats.txt | 2 +- wadsrc/static/zscript/hexen/bishop.txt | 4 +- wadsrc/static/zscript/shared/inventory.txt | 8 +- .../static/zscript/strife/strifeweapons.txt | 2 +- 25 files changed, 641 insertions(+), 646 deletions(-) create mode 100644 wadsrc/static/zscript/actor_checks.txt diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index eef9b137a..880cd7dfe 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1494,7 +1494,7 @@ static int PatchFrame (int frameNum) DEFINE_ACTION_FUNCTION(AActor, isDEHState) { PARAM_PROLOGUE; - PARAM_STATE(state); + PARAM_POINTER(state, FState); ACTION_RETURN_BOOL(state != nullptr && (state->DefineFlags & SDF_DEHACKED)); } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f3fda2b14..2c88da92a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -82,6 +82,7 @@ PName *TypeName; PSound *TypeSound; PColor *TypeColor; PStatePointer *TypeState; +PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; PPointer *TypeNullPtr; @@ -546,7 +547,8 @@ void PType::StaticInit() RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - + RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); + // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeVoid = new PVoidType); @@ -564,6 +566,7 @@ void PType::StaticInit() TypeTable.AddType(TypeSound = new PSound); TypeTable.AddType(TypeColor = new PColor); TypeTable.AddType(TypeState = new PStatePointer); + TypeTable.AddType(TypeStateLabel = new PStateLabel); TypeTable.AddType(TypeNullPtr = new PPointer); TypeVector2 = new PStruct(NAME_Vector2, nullptr); @@ -701,7 +704,7 @@ IMPLEMENT_CLASS(PInt, false, false, false, false) //========================================================================== PInt::PInt() -: PBasicType(4, 4), Unsigned(false) +: PBasicType(4, 4), Unsigned(false), IntCompatible(true) { mDescriptiveName = "SInt32"; Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); @@ -715,8 +718,8 @@ PInt::PInt() // //========================================================================== -PInt::PInt(unsigned int size, bool unsign) -: PBasicType(size, size), Unsigned(unsign) +PInt::PInt(unsigned int size, bool unsign, bool compatible) +: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) { mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); @@ -1308,7 +1311,7 @@ IMPLEMENT_CLASS(PName, false, false, false, false) //========================================================================== PName::PName() -: PInt(sizeof(FName), true) +: PInt(sizeof(FName), true, false) { mDescriptiveName = "Name"; assert(sizeof(FName) == __alignof(FName)); @@ -1414,6 +1417,22 @@ PColor::PColor() assert(sizeof(PalEntry) == __alignof(PalEntry)); } +/* PStateLabel *****************************************************************/ + +IMPLEMENT_CLASS(PStateLabel, false, false, false, false) + +//========================================================================== +// +// PStateLabel Default Constructor +// +//========================================================================== + +PStateLabel::PStateLabel() + : PInt(sizeof(int), false, false) +{ + mDescriptiveName = "StateLabel"; +} + /* PStatePointer **********************************************************/ IMPLEMENT_CLASS(PStatePointer, false, false, false, false) diff --git a/src/dobjtype.h b/src/dobjtype.h index e1bfd0796..1ca5df832 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -227,6 +227,7 @@ public: PType(unsigned int size = 1, unsigned int align = 1); virtual ~PType(); + virtual bool isNumeric() { return false; } bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)); @@ -417,7 +418,7 @@ class PInt : public PBasicType { DECLARE_CLASS(PInt, PBasicType); public: - PInt(unsigned int size, bool unsign); + PInt(unsigned int size, bool unsign, bool compatible = true); void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -426,8 +427,10 @@ public: virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual double GetValueFloat(void *addr) const; + virtual bool isNumeric() override { return IntCompatible; } bool Unsigned; + bool IntCompatible; protected: PInt(); void SetOps(); @@ -453,6 +456,7 @@ public: virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual double GetValueFloat(void *addr) const; + virtual bool isNumeric() override { return true; } protected: PFloat(); void SetOps(); @@ -516,6 +520,13 @@ public: PColor(); }; +class PStateLabel : public PInt +{ + DECLARE_CLASS(PStateLabel, PInt); +public: + PStateLabel(); +}; + // Pointers ----------------------------------------------------------------- class PStatePointer : public PBasicType @@ -903,6 +914,7 @@ extern PColor *TypeColor; extern PStruct *TypeVector2; extern PStruct *TypeVector3; extern PStatePointer *TypeState; +extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; // A constant value --------------------------------------------------------- diff --git a/src/info.h b/src/info.h index 6aee02bed..e198bb26c 100644 --- a/src/info.h +++ b/src/info.h @@ -313,6 +313,44 @@ struct FDoomEdEntry int Args[5]; }; +struct FStateLabelStorage +{ + TArray Storage; + + int AddPointer(FState *ptr) + { + if (ptr != nullptr) + { + int pos = Storage.Reserve(sizeof(ptr) + sizeof(int)); + memset(&Storage[pos], 0, sizeof(int)); + memcpy(&Storage[pos + sizeof(int)], &ptr, sizeof(ptr)); + return pos / 4 + 1; + } + else return 0; + } + + int AddNames(TArray &names) + { + int siz = names.Size(); + if (siz > 1) + { + int pos = Storage.Reserve(sizeof(int) + sizeof(FName) * names.Size()); + memcpy(&Storage[pos], &siz, sizeof(int)); + memcpy(&Storage[pos + sizeof(int)], &names[0], sizeof(FName) * names.Size()); + return pos / 4 + 1; + } + else + { + // don't store single name states in the array. + return names[0].GetIndex() + 0x10000000; + } + } + + FState *GetState(int pos, PClassActor *cls); +}; + +extern FStateLabelStorage StateLabels; + enum ESpecialMapthings { SMT_Player1Start = 1, diff --git a/src/namedef.h b/src/namedef.h index 8f1a54337..ee7d08f40 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -730,10 +730,10 @@ xx(stateinfo) xx(__decorate_internal_int__) xx(__decorate_internal_bool__) -xx(__decorate_internal_state__) xx(__decorate_internal_float__) +xx(ResolveState) xx(DamageFunction) xx(Length) xx(Unit) -xx(A_Jump) \ No newline at end of file +xx(StateLabel) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index b6ecb5cf8..9440dc0d6 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -715,7 +715,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) //=========================================================================== // -// __decorate_internal_state__ // __decorate_internal_int__ // __decorate_internal_bool__ // __decorate_internal_float__ @@ -725,13 +724,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_state__) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(returnme); - ACTION_RETURN_STATE(returnme); -} - DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_int__) { PARAM_SELF_PROLOGUE(AActor); @@ -1158,7 +1150,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(maxchance); paramnum++; // Increment paramnum to point at the first jump target @@ -1166,7 +1158,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) if (count > 0 && (maxchance >= 256 || pr_cajump() < maxchance)) { int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); - PARAM_STATE_AT(paramnum + jumpnum, jumpto); + PARAM_STATE_ACTION_AT(paramnum + jumpnum, jumpto); ACTION_RETURN_STATE(jumpto); } ACTION_RETURN_STATE(NULL); @@ -1177,137 +1169,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (health); - PARAM_STATE (jump); - PARAM_INT_DEF (ptr_selector); - AActor *measured; - - measured = COPY_AAPTR(self, ptr_selector); - - if (measured != NULL && measured->health < health) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (!self->CheckMeleeRange()) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->CheckMeleeRange()) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -static int DoJumpIfCloser(AActor *target, VM_ARGS) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT (dist); - PARAM_STATE (jump); - PARAM_BOOL_DEF(noz); - - if (!target) - { // No target - no jump - ACTION_RETURN_STATE(NULL); - } - if (self->Distance2D(target) < dist && - (noz || - ((self->Z() > target->Z() && self->Z() - target->Top() < dist) || - (self->Z() <= target->Z() && target->Z() - self->Top() < dist)))) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *target; - - if (self->player == NULL) - { - target = self->target; - } - else - { - // Does the player aim at something that can be shot? - FTranslatedLineTarget t; - P_BulletSlope(self, &t, ALF_PORTALRESTRICT); - target = t.linetarget; - } - return DoJumpIfCloser(target, VM_ARGS_NAMES); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfCloser(self->tracer, VM_ARGS_NAMES); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfCloser(self->master, VM_ARGS_NAMES); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -int DoJumpIfInventory(AActor *owner, VM_ARGS) +DEFINE_ACTION_FUNCTION(AActor, CheckInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (itemtype, AInventory); PARAM_INT (itemamount); - PARAM_STATE (label); - PARAM_INT_DEF (setowner) { setowner = AAPTR_DEFAULT; } + PARAM_INT_DEF (setowner); - if (itemtype == NULL) + if (itemtype == nullptr) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } - owner = COPY_AAPTR(owner, setowner); - if (owner == NULL) + AActor *owner = COPY_AAPTR(self, setowner); + if (owner == nullptr) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } AInventory *item = owner->FindInventory(itemtype); @@ -1318,48 +1195,32 @@ int DoJumpIfInventory(AActor *owner, VM_ARGS) { if (item->Amount >= itemamount) { - ACTION_RETURN_STATE(label); + ACTION_RETURN_BOOL(true); } } else if (item->Amount >= item->MaxAmount) { - ACTION_RETURN_STATE(label); + ACTION_RETURN_BOOL(true); } } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfInventory(self, VM_ARGS_NAMES); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfInventory(self->target, VM_ARGS_NAMES); -} //========================================================================== // // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckArmorType) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME (type); - PARAM_STATE (label); PARAM_INT_DEF(amount); ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor); - if (armor && armor->ArmorType == type && armor->Amount >= amount) - { - ACTION_RETURN_STATE(label); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(armor && armor->ArmorType == type && armor->Amount >= amount); } //========================================================================== @@ -1910,7 +1771,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) { PARAM_ACTION_PROLOGUE(AActor); - PARAM_STATE(jump); + PARAM_STATE_ACTION(jump); if (!ACTION_CALL_FROM_PSPRITE() || self->player->ReadyWeapon == nullptr) { @@ -3637,10 +3498,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) // jumps if no player can see this actor // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfSeen) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); for (int i = 0; i < MAXPLAYERS; i++) { @@ -3649,17 +3509,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Always check sight from each player. if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, then check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } //=========================================================================== @@ -3706,11 +3566,10 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckSightOrRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); - PARAM_STATE(jump); PARAM_BOOL_DEF(twodi); range *= range; @@ -3721,25 +3580,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi, true)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi, true)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); - PARAM_STATE(jump); PARAM_BOOL_DEF(twodi); range *= range; @@ -3750,17 +3608,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi, false)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi, false)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(false); } @@ -3813,20 +3671,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) } -//=========================================================================== -// -// A_JumpIf -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL (condition); - PARAM_STATE (jump); - - ACTION_RETURN_STATE(condition ? jump : NULL); -} - //=========================================================================== // // A_CountdownArg @@ -3917,43 +3761,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) return 0; } -//=========================================================================== -// -// A_CheckFloor -// [GRB] Jumps if actor is standing on floor -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->Z() <= self->floorz) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//=========================================================================== -// -// A_CheckCeiling -// [GZ] Totally copied from A_CheckFloor, jumps if actor touches ceiling -// - -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->Top() >= self->ceilingz) // Height needs to be counted - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - //=========================================================================== // // A_Stop @@ -4077,17 +3884,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) +DEFINE_ACTION_FUNCTION(AActor, PlayerSkinCheck) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - if (self->player != NULL && - skins[self->player->userinfo.GetSkin()].othergame) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(self->player != NULL && + skins[self->player->userinfo.GetSkin()].othergame); } // [KS] *** Start of my modifications *** @@ -4220,7 +4022,7 @@ ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) return TRACE_Abort; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckLOF) { // Check line of fire @@ -4233,7 +4035,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) DVector3 vel; PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); PARAM_INT_DEF (flags) PARAM_FLOAT_DEF (range) PARAM_FLOAT_DEF (minrange) @@ -4290,7 +4091,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) double distance = self->Distance3D(target); if (distance > range) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } @@ -4339,7 +4140,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double cp = pitch.Cos(); @@ -4377,7 +4178,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { if (minrange > 0 && trace.Distance < minrange) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor)) { @@ -4385,9 +4186,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor; if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor; } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } //========================================================================== @@ -4422,10 +4223,9 @@ enum JLOS_flags JLOSF_CHECKTRACER = 1 << 12, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfTargetInLOS) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); PARAM_ANGLE_DEF (fov) PARAM_INT_DEF (flags) PARAM_FLOAT_DEF (dist_max) @@ -4456,11 +4256,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -4472,7 +4272,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (!t.linetarget) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } target = t.linetarget; @@ -4498,24 +4298,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If target is not a combatant, don't jump if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double distance = self->Distance3D(target); if (dist_max && (distance > dist_max)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) fov = 0.; @@ -4529,7 +4329,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_FLIPFOV) @@ -4546,10 +4346,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2)) { - ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return + ACTION_RETURN_BOOL(false); // [KS] Outside of FOV - return } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } @@ -4560,10 +4360,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfInTargetLOS) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); PARAM_ANGLE_DEF (fov) PARAM_INT_DEF (flags) PARAM_FLOAT_DEF (dist_max) @@ -4589,19 +4388,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double distance = self->Distance3D(target); if (dist_max && (distance > dist_max)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } bool doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -4610,7 +4409,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) { if (flags & JLOSF_CLOSENOJUMP) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) fov = 0.; @@ -4625,14 +4424,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (an > (fov / 2)) { - ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return + ACTION_RETURN_BOOL(false); // [KS] Outside of FOV - return } } if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } //=========================================================================== @@ -4650,7 +4449,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) ACTION_RETURN_STATE(NULL); } PARAM_INT (count); - PARAM_STATE (jump); + PARAM_STATE_ACTION (jump); PARAM_BOOL_DEF (dontincrement); if (numret > 0) @@ -4727,24 +4526,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckFlag) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (flagname); - PARAM_STATE (jumpto); PARAM_INT_DEF (checkpointer); AActor *owner = COPY_AAPTR(self, checkpointer); - if (owner == NULL) - { - ACTION_RETURN_STATE(NULL); - } - - if (CheckActorFlag(owner, flagname)) - { - ACTION_RETURN_STATE(jumpto); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(owner != nullptr && CheckActorFlag(owner, flagname)); } @@ -5175,7 +4964,7 @@ enum T_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_DEF (teleport_state) PARAM_CLASS_DEF (target_type, ASpecialSpot) PARAM_CLASS_DEF (fog_type, AActor) @@ -5605,7 +5394,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(destination_selector); PARAM_FLOAT_DEF(xofs) PARAM_FLOAT_DEF(yofs) @@ -5902,27 +5691,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) ACTION_RETURN_INT(given); } -//=========================================================================== -// -// A_CheckSpecies -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - PARAM_NAME_DEF(species); - PARAM_INT_DEF(ptr); - - AActor *mobj = COPY_AAPTR(self, ptr); - - if (mobj != NULL && jump && mobj->GetSpecies() == species) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - //========================================================================== // // A_SetTics @@ -6666,44 +6434,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) return 0; } -//=========================================================================== -// A_JumpIfHigherOrLower -// -// Jumps if a target, master, or tracer is higher or lower than the calling -// actor. Can also specify how much higher/lower the actor needs to be than -// itself. Can also take into account the height of the actor in question, -// depending on which it's checking. This means adding height of the -// calling actor's self if the pointer is higher, or height of the pointer -// if its lower. -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(high); - PARAM_STATE(low); - PARAM_FLOAT_DEF(offsethigh); - PARAM_FLOAT_DEF(offsetlow); - PARAM_BOOL_DEF(includeHeight); - PARAM_INT_DEF(ptr); - - AActor *mobj = COPY_AAPTR(self, ptr); - - - if (mobj != NULL && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. - { - if ((high) && (mobj->Z() > ((includeHeight ? self->Height : 0) + self->Z() + offsethigh))) - { - ACTION_RETURN_STATE(high); - } - else if ((low) && (mobj->Z() + (includeHeight ? mobj->Height : 0)) < (self->Z() + offsetlow)) - { - ACTION_RETURN_STATE(low); - } - } - ACTION_RETURN_STATE(NULL); -} - //=========================================================================== // A_SetSpecies(str species, ptr) // @@ -6760,29 +6490,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) // Checks to see if a certain actor class is close to the // actor/pointer within distance, in numbers. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckProximity) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); PARAM_CLASS(classname, AActor); PARAM_FLOAT(distance); PARAM_INT_DEF(count); PARAM_INT_DEF(flags); PARAM_INT_DEF(ptr); - if (!jump) - { - if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) - { - ACTION_RETURN_STATE(NULL); - } - } - - if (P_Thing_CheckProximity(self, classname, distance, count, flags, ptr) && jump) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(!!P_Thing_CheckProximity(self, classname, distance, count, flags, ptr)); } /*=========================================================================== @@ -6806,10 +6523,9 @@ enum CBF CBF_ABSOLUTEANGLE = 1 << 8, //Absolute angle for offsets. }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckBlock) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(block) PARAM_INT_DEF(flags) PARAM_INT_DEF(ptr) PARAM_FLOAT_DEF(xofs) @@ -6822,7 +6538,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //Needs at least one state jump to work. if (!mobj) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (!(flags & CBF_ABSOLUTEANGLE)) @@ -6872,7 +6588,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) if (checker) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (mobj->BlockingMobj) @@ -6886,23 +6602,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) } } - //[MC] If modders don't want jumping, but just getting the pointer, only abort at - //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. - //It gets the mobj blocking, if any, and doesn't jump at all. - if (!block) - { - ACTION_RETURN_STATE(NULL); - } //[MC] I don't know why I let myself be persuaded not to include a flag. //If an actor is loaded with pointers, they don't really have any options to spare. //Also, fail if a dropoff or a step is too great to pass over when checking for dropoffs. - if ((!(flags & CBF_NOACTORS) && (mobj->BlockingMobj)) || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL) || - ((flags & CBF_DROPOFF) && !checker)) - { - ACTION_RETURN_STATE(block); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL((!(flags & CBF_NOACTORS) && (mobj->BlockingMobj)) || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL) || + ((flags & CBF_DROPOFF) && !checker)); } //=========================================================================== diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index db6b9a287..05cfb7cc4 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -159,6 +159,7 @@ extern FFlagDef ActorFlagDefs[]; void AActor::InitNativeFields() { + PType *TypePlayer = NewPointer(TypeVoid); // placeholder PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); PType *TypeActorClass = NewClassPointer(RUNTIME_CLASS(AActor)); PType *TypeInventory = NewPointer(RUNTIME_CLASS(AInventory)); @@ -168,6 +169,7 @@ void AActor::InitNativeFields() auto meta = RUNTIME_CLASS(AActor); + meta->AddNativeField("Player", TypePlayer, myoffsetof(AActor, player)); meta->AddNativeField("Pos", TypeVector3, myoffsetof(AActor, __Pos), VARF_ReadOnly); meta->AddNativeField(NAME_X, TypeFloat64, myoffsetof(AActor, __Pos.X), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! meta->AddNativeField(NAME_Y, TypeFloat64, myoffsetof(AActor, __Pos.Y), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! @@ -694,7 +696,7 @@ bool AActor::SetState (FState *newstate, bool nofunction) DEFINE_ACTION_FUNCTION(AActor, SetState) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(state); + PARAM_POINTER(state, FState); PARAM_BOOL_DEF(nofunction); ACTION_RETURN_BOOL(self->SetState(state, nofunction)); }; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 4938063ec..f371c6888 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -886,7 +886,7 @@ static void P_CheckWeaponButtons (player_t *player) DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_ReFire) { PARAM_ACTION_PROLOGUE(AActor); - PARAM_STATE_DEF(state); + PARAM_STATE_ACTION_DEF(state); A_ReFire(self, state); return 0; } @@ -1224,7 +1224,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT (layer); - PARAM_STATE_DEF(state); + PARAM_STATE_ACTION_DEF(state); PARAM_BOOL_DEF(dontoverride); player_t *player = self->player; @@ -1294,7 +1294,7 @@ enum GF_Flags DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) { PARAM_ACTION_PROLOGUE(AActor); - PARAM_STATE_DEF(flash); + PARAM_STATE_ACTION_DEF(flash); PARAM_INT_DEF(flags); player_t *player = self->player; @@ -1361,6 +1361,19 @@ DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimfla return pitch; } +AActor *P_AimTarget(AActor *mo) +{ + FTranslatedLineTarget t; + P_BulletSlope(mo, &t, ALF_PORTALRESTRICT); + return t.linetarget; +} + +DEFINE_ACTION_FUNCTION(AActor, AimTarget) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_OBJECT(P_AimTarget(self)); +} + // // P_GunShot diff --git a/src/p_pspr.h b/src/p_pspr.h index 2809216a7..3f819714c 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -110,6 +110,7 @@ void P_FireWeapon (player_t *player); void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); +AActor *P_AimTarget(AActor *mo); void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch); diff --git a/src/p_states.cpp b/src/p_states.cpp index 00b011e3d..2c1b88eaf 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -42,6 +42,9 @@ #include "vm.h" #include "thingdef.h" +// stores indices for symbolic state labels for some old-style DECORATE functions. +FStateLabelStorage StateLabels; + // 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 @@ -258,7 +261,94 @@ FState *PClassActor::FindStateByString(const char *name, bool exact) } +//========================================================================== +// +// validate a runtime state index. +// +//========================================================================== +static bool VerifyJumpTarget(PClassActor *cls, FState *CallingState, int index) +{ + while (cls != RUNTIME_CLASS(AActor)) + { + // both calling and target state need to belong to the same class. + if (cls->OwnsState(CallingState)) + { + return cls->OwnsState(CallingState + index); + } + + // We can safely assume the ParentClass is of type PClassActor + // since we stop when we see the Actor base class. + cls = static_cast(cls->ParentClass); + } + return false; +} + +//========================================================================== +// +// Get a statw pointer from a symbolic label +// +//========================================================================== + +FState *FStateLabelStorage::GetState(int pos, PClassActor *cls) +{ + if (pos > 0x10000000) + { + return cls? cls->FindState(ENamedName(pos - 0x10000000)) : nullptr; + } + else if (pos < 0) + { + // decode the combined value produced by the script. + int index = (pos >> 16) & 32767; + pos = ((pos & 65535) - 1) * 4; + FState *state; + memcpy(&state, &Storage[pos + sizeof(int)], sizeof(state)); + if (VerifyJumpTarget(cls, state, index)) + return state + index; + else + return nullptr; + } + else if (pos > 0) + { + int val; + pos = (pos - 1) * 4; + memcpy(&val, &Storage[pos], sizeof(int)); + + if (val == 0) + { + FState *state; + memcpy(&state, &Storage[pos + sizeof(int)], sizeof(state)); + return state; + } + else if (cls != nullptr) + { + FName *labels = (FName*)&Storage[pos + sizeof(int)]; + return cls->FindState(val, labels, false); + } + } + return nullptr; +} + +//========================================================================== +// +// State label conversion function for scripts +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, FindState) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATE(newstate); + ACTION_RETURN_STATE(newstate); +} + +// same as above but context aware. +DEFINE_ACTION_FUNCTION_PARAMS(AActor, ResolveState) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_STATE_ACTION(newstate); + ACTION_RETURN_STATE(newstate); +} //========================================================================== // diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index cbe9183e2..103e38eff 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -812,7 +812,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) if (basex->ValueType->GetRegType() == REGT_INT) { - if (basex->ValueType != TypeName || Explicit) // names can be converted to int, but only with an explicit type cast. + if (basex->ValueType->isNumeric() || Explicit) // names can be converted to int, but only with an explicit type cast. { FxExpression *x = basex; x->ValueType = ValueType; @@ -822,7 +822,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) } else { - // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( + // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this serious error needs to be reduced to a warning. :( // At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE. if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); @@ -919,7 +919,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) } else if (basex->ValueType->GetRegType() == REGT_INT) { - if (basex->ValueType != TypeName) + if (basex->ValueType->isNumeric()) { if (basex->isConstant()) { @@ -1428,8 +1428,15 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } - else if (ValueType == TypeState) + else if (ValueType == TypeStateLabel) { + if (basex->ValueType == TypeNullPtr) + { + auto x = new FxConstant(0, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; + } // Right now this only supports string constants. There should be an option to pass a string variable, too. if (basex->isConstant() && (basex->ValueType == TypeString || basex->ValueType == TypeName)) { @@ -4022,6 +4029,10 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) ValueType = TypeSInt32; else if (truex->IsNumeric() && falsex->IsNumeric()) ValueType = TypeFloat64; + else if (truex->IsPointer() && falsex->ValueType == TypeNullPtr) + ValueType = truex->ValueType; + else if (falsex->IsPointer() && truex->ValueType == TypeNullPtr) + ValueType = falsex->ValueType; else ValueType = TypeVoid; //else if (truex->ValueType != falsex->ValueType) @@ -4519,23 +4530,21 @@ static void EmitLoad(VMFunctionBuilder *build, const ExpEmit resultreg, const Ex ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) { unsigned i; - int opcode, opA; + int opcode; assert(choices.Size() > 0); - assert(OP_LTF_RK == OP_LTF_RR+1); - assert(OP_LT_RK == OP_LT_RR+1); - assert(OP_LEF_RK == OP_LEF_RR+1); - assert(OP_LE_RK == OP_LE_RR+1); + assert(OP_MAXF_RK == OP_MAXF_RR+1); + assert(OP_MAX_RK == OP_MAX_RR+1); + assert(OP_MIN_RK == OP_MIN_RR+1); + assert(OP_MIN_RK == OP_MIN_RR+1); if (Type == NAME_Min) { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LEF_RR : OP_LE_RR; - opA = 1; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MINF_RR : OP_MIN_RR; } else { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LTF_RR : OP_LT_RR; - opA = 0; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MAXF_RR : OP_MAX_RR; } ExpEmit bestreg; @@ -4556,17 +4565,8 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) { ExpEmit checkreg = choices[i]->Emit(build); assert(checkreg.RegType == bestreg.RegType); - build->Emit(opcode + checkreg.Konst, opA, bestreg.RegNum, checkreg.RegNum); - build->Emit(OP_JMP, 1); - if (checkreg.Konst) - { - build->Emit(bestreg.RegType == REGT_FLOAT ? OP_LKF : OP_LK, bestreg.RegNum, checkreg.RegNum); - } - else - { - build->Emit(bestreg.RegType == REGT_FLOAT ? OP_MOVEF : OP_MOVE, bestreg.RegNum, checkreg.RegNum, 0); - checkreg.Free(build); - } + build->Emit(opcode + checkreg.Konst, bestreg.RegNum, bestreg.RegNum, checkreg.RegNum); + checkreg.Free(build); } return bestreg; } @@ -6121,7 +6121,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_Name: case NAME_Color: case NAME_Sound: - case NAME_State: if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) { PType *type = @@ -6131,8 +6130,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) MethodName == NAME_Float ? TypeFloat64 : MethodName == NAME_Double ? TypeFloat64 : MethodName == NAME_Name ? TypeName : - MethodName == NAME_Color ? TypeColor : - MethodName == NAME_State? TypeState :(PType*)TypeSound; + MethodName == NAME_Color ? TypeColor : (PType*)TypeSound; func = new FxTypeCast(ArgList[0], type, true, true); ArgList[0] = nullptr; @@ -6819,7 +6817,6 @@ bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, Ex FName funcname = Function->SymbolName; if (funcname == NAME___decorate_internal_int__ || funcname == NAME___decorate_internal_bool__ || - funcname == NAME___decorate_internal_state__ || funcname == NAME___decorate_internal_float__) { FxExpression *arg = ArgList[0]; @@ -7926,6 +7923,13 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) } else { + // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) + if (ctx.ReturnProto != nullptr && ctx.Function->SymbolName != NAME_None) + { + Value = new FxTypeCast(Value, ctx.ReturnProto->ReturnTypes[0], false, false); + Value = Value->Resolve(ctx); + ABORT(Value); + } retproto = Value->ReturnProto(); } @@ -8135,7 +8139,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) //========================================================================== // -// +// Symbolic state labels. +// Conversion will not happen inside the compiler anymore because it causes +// just too many problems. // //========================================================================== @@ -8155,7 +8161,9 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) delete this; return nullptr; } - FxExpression *x = new FxConstant(aclass->OwnedStates + index, ScriptPosition); + int symlabel = StateLabels.AddPointer(aclass->OwnedStates + index); + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; delete this; return x; } @@ -8169,8 +8177,7 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) : FxExpression(EFX_RuntimeStateIndex, index->ScriptPosition), Index(index) { - EmitTail = false; - ValueType = TypeState; + ValueType = TypeStateLabel; } FxRuntimeStateIndex::~FxRuntimeStateIndex() @@ -8178,12 +8185,6 @@ FxRuntimeStateIndex::~FxRuntimeStateIndex() SAFE_DELETE(Index); } -PPrototype *FxRuntimeStateIndex::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -8206,13 +8207,15 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) } else if (index == 0) { - auto x = new FxConstant((FState*)nullptr, ScriptPosition); + int symlabel = StateLabels.AddPointer(nullptr); + auto x = new FxConstant(symlabel, ScriptPosition); delete this; - return x->Resolve(ctx); + x->ValueType = TypeStateLabel; + return x; } else { - auto x = new FxStateByIndex(index, ScriptPosition); + auto x = new FxStateByIndex(ctx.StateIndex + index, ScriptPosition); delete this; return x->Resolve(ctx); } @@ -8222,84 +8225,21 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) Index = new FxIntCast(Index, ctx.FromDecorate); SAFE_RESOLVE(Index, ctx); } - + auto aclass = dyn_cast(ctx.Class); + assert(aclass != nullptr && aclass->NumOwnedStates > 0); + symlabel = StateLabels.AddPointer(aclass->OwnedStates + ctx.StateIndex); + ValueType = TypeStateLabel; return this; } -static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int index) -{ - PClassActor *cls = stateowner->GetClass(); - - if (stateinfo->mCallingState != nullptr) - { - while (cls != RUNTIME_CLASS(AActor)) - { - // both calling and target state need to belong to the same class. - if (cls->OwnsState(stateinfo->mCallingState)) - { - return cls->OwnsState(stateinfo->mCallingState + index); - } - - // We can safely assume the ParentClass is of type PClassActor - // since we stop when we see the Actor base class. - cls = static_cast(cls->ParentClass); - } - } - return false; -} - -static int BuiltinHandleRuntimeState(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(stateowner, AActor); - PARAM_POINTER(stateinfo, FStateParamInfo); - PARAM_INT(index); - - if (index == 0 || !VerifyJumpTarget(stateowner, stateinfo, index)) - { - // Null is returned if the location was invalid which means that no jump will be performed - // if used as return value - // 0 always meant the same thing so we handle it here for compatibility - ACTION_RETURN_STATE(nullptr); - } - else - { - ACTION_RETURN_STATE(stateinfo->mCallingState + index); - } -} - ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) { - // This can only be called from inline state functions which must be VARF_Action. - assert(build->NumImplicits >= NAP && build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits && - "FxRuntimeStateIndex is only valid inside action functions"); - - ExpEmit out(build, REGT_POINTER); - - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // stateowner - build->Emit(OP_PARAM, 0, REGT_POINTER, 2); // stateinfo - ExpEmit id = Index->Emit(build); - build->Emit(OP_PARAM, 0, REGT_INT | (id.Konst ? REGT_KONST : 0), id.RegNum); // index - - VMFunction *callfunc; - PSymbol *sym; - - sym = FindBuiltinFunction(NAME_BuiltinHandleRuntimeState, BuiltinHandleRuntimeState); - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - if (EmitTail) - { - build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - out.Final = true; - } - else - { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); - } - + ExpEmit out = Index->Emit(build); + // out = (clamp(Index, 0, 32767) << 16) | symlabel | 0x80000000; 0x80000000 is here to make it negative. + build->Emit(OP_MAX_RK, out.RegNum, out.RegNum, build->GetConstantInt(0)); + build->Emit(OP_MIN_RK, out.RegNum, out.RegNum, build->GetConstantInt(32767)); + build->Emit(OP_SLL_RI, out.RegNum, out.RegNum, 16); + build->Emit(OP_OR_RK, out.RegNum, out.RegNum, build->GetConstantInt(symlabel|0x80000000)); return out; } @@ -8340,6 +8280,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); ABORT(ctx.Class); + int symlabel; if (names[0] == NAME_None) { @@ -8379,107 +8320,17 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) return this; } } - FxExpression *x = new FxConstant(destination, ScriptPosition); - delete this; - return x; - } - names.Delete(0); - names.ShrinkToFit(); - ValueType = TypeState; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames) -{ - PARAM_OBJECT_AT(0, self, AActor); - FState *state = self->GetClass()->FindState(numparam - 1, names); - if (state == nullptr) - { - const char *dot = ""; - Printf("Jump target '"); - for (int i = 0; i < numparam - 1; i++) - { - Printf("%s%s", dot, names[i].GetChars()); - dot = "."; - } - Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars()); - } - ret->SetPointer(state, ATAG_STATE); - return 1; -} - -// Find a state with any number of dots in its name. -int BuiltinFindMultiNameState(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) -{ - assert(numparam > 1); - assert(numret == 1); - assert(ret->RegType == REGT_POINTER); - - FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); - for (int i = 1; i < numparam; ++i) - { - PARAM_NAME_AT(i, zaname); - names[i - 1] = zaname; - } - return DoFindState(stack, param, numparam, ret, names, numparam - 1); -} - -// Find a state without any dots in its name. -int BuiltinFindSingleNameState(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 2); - assert(numret == 1); - assert(ret->RegType == REGT_POINTER); - - PARAM_NAME_AT(1, zaname); - return DoFindState(stack, param, numparam, ret, &zaname, 1); -} - -ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) -{ - ExpEmit dest(build, REGT_POINTER); - if (build->NumImplicits == NAP) - { - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + symlabel = StateLabels.AddPointer(destination); } else { - build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + names.Delete(0); + symlabel = StateLabels.AddNames(names); } - for (unsigned i = 0; i < names.Size(); ++i) - { - build->EmitParamInt(names[i]); - } - - // For one name, use the BuiltinFindSingleNameState function. For more than - // one name, use the BuiltinFindMultiNameState function. - VMFunction *callfunc; - PSymbol *sym; - - if (names.Size() == 1) - { - sym = FindBuiltinFunction(NAME_BuiltinFindSingleNameState, BuiltinFindSingleNameState); - } - else - { - sym = FindBuiltinFunction(NAME_BuiltinFindMultiNameState, BuiltinFindMultiNameState); - } - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); - names.Clear(); - names.ShrinkToFit(); - return dest; + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; } //========================================================================== diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index b9679ad31..f1778512f 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -310,9 +310,9 @@ public: virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); virtual bool CheckReturn() { return false; } - bool IsNumeric() const { return ValueType != TypeName && ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } + bool IsNumeric() const { return ValueType->isNumeric(); } bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; } - bool IsInteger() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT); } + bool IsInteger() const { return ValueType->isNumeric() && (ValueType->GetRegType() == REGT_INT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } @@ -1684,14 +1684,13 @@ public: class FxRuntimeStateIndex : public FxExpression { - bool EmitTail; FxExpression *Index; + int symlabel; public: FxRuntimeStateIndex(FxExpression *index); ~FxRuntimeStateIndex(); FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1709,7 +1708,6 @@ public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index e292e1844..151d88521 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -174,14 +174,15 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c val.Int = v; x = new FxConstant(val, sc); } - else if (type == TypeState) + else if (type == TypeStateLabel) { // This forces quotation marks around the state name. if (sc.CheckToken(TK_StringConst)) { if (sc.String[0] == 0 || sc.Compare("None")) { - x = new FxConstant((FState*)nullptr, sc); + x = new FxConstant(0, sc); + x->ValueType = TypeStateLabel; } else if (sc.Compare("*")) { diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index e3cb74c32..c9be2c747 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -626,7 +626,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray 0) { FxExpression *x; - if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) + if (statedef != NULL && params[pnum] == TypeStateLabel && sc.CheckNumber()) { // Special case: State label as an offset if (sc.Number > 0 && statestring.Len() > 1) @@ -646,7 +646,8 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArrayValueType = TypeStateLabel; } } else @@ -703,7 +704,7 @@ FName CheckCastKludges(FName in) case NAME_Bool: return NAME___decorate_internal_bool__; case NAME_State: - return NAME___decorate_internal_state__; + return NAME_ResolveState; case NAME_Float: return NAME___decorate_internal_float__; default: diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 019d6c3a6..2f98c8d81 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -940,15 +940,12 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; #define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f; #define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); -#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); FState *x = (FState *)param[p].a; +#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass()); +#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); #define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); -// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: -// PARAM_INT_OPT(0,myint) { myint = 55; } -// Just make sure to fill it in when using these macros, because the compiler isn't likely -// to give useful error messages if you don't. #define PARAM_EXISTS(p) ((p) < numparam && param[p].Type != REGT_NIL) #define ASSERTINT(p) assert((p).Type == REGT_INT) #define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) @@ -965,7 +962,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_FLOAT_DEF_AT(p,x) double x; if (PARAM_EXISTS(p)) { ASSERTFLOAT(param[p]); x = param[p].f; } else { ASSERTFLOAT(defaultparam[p]); x = defaultparam[p].f; } #define PARAM_ANGLE_DEF_AT(p,x) DAngle x; if (PARAM_EXISTS(p)) { ASSERTFLOAT(param[p]); x = param[p].f; } else { ASSERTFLOAT(defaultparam[p]); x = defaultparam[p].f; } #define PARAM_STRING_DEF_AT(p,x) FString x; if (PARAM_EXISTS(p)) { ASSERTSTRING(param[p]); x = param[p].s; } else { ASSERTSTRING(defaultparam[p]); x = defaultparam[p].s; } -#define PARAM_STATE_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTSTATE(param[p]); x = (FState*)param[p].a; } else { ASSERTSTATE(defaultparam[p]); x = (FState*)defaultparam[p].a; } +#define PARAM_STATE_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, self->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, self->GetClass()); } +#define PARAM_STATE_ACTION_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, stateowner->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, stateowner->GetClass()); } #define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; } #define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; } #define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } @@ -982,6 +980,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_ANGLE(x) ++paramnum; PARAM_ANGLE_AT(paramnum,x) #define PARAM_STRING(x) ++paramnum; PARAM_STRING_AT(paramnum,x) #define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x) +#define PARAM_STATE_ACTION(x) ++paramnum; PARAM_STATE_ACTION_AT(paramnum,x) #define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type) #define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type) #define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base) @@ -995,6 +994,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_ANGLE_DEF(x) ++paramnum; PARAM_ANGLE_DEF_AT(paramnum,x) #define PARAM_STRING_DEF(x) ++paramnum; PARAM_STRING_DEF_AT(paramnum,x) #define PARAM_STATE_DEF(x) ++paramnum; PARAM_STATE_DEF_AT(paramnum,x) +#define PARAM_STATE_ACTION_DEF(x) ++paramnum; PARAM_STATE_ACTION_DEF_AT(paramnum,x) #define PARAM_POINTER_DEF(x,type) ++paramnum; PARAM_POINTER_DEF_AT(paramnum,x,type) #define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type) #define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 7e0af9ee4..b8c0a2a38 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1429,7 +1429,15 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n break; case ZCC_UserType: - retval = ResolveUserType(btype, &outertype->Symbols); + // statelabel is not a token - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? + if (btype->UserType->Id == NAME_StateLabel) + { + retval = TypeStateLabel; + } + else + { + retval = ResolveUserType(btype, &outertype->Symbols); + } break; } break; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 8ea4bb114..42f32a447 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,6 +1,7 @@ zscript/base.txt zscript/constants.txt zscript/actor.txt +zscript/actor_checks.txt zscript/shared/inventory.txt zscript/shared/player.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7634ccaea..f3cd9aa3c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -71,6 +71,7 @@ class Actor : Thinker native native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); native void FaceMovementDirection(); + native Actor AimTarget(); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); @@ -90,6 +91,9 @@ class Actor : Thinker native native void NewChaseDir(); native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); + native state FindState(statelabel st); // do we need exact later? + bool SetStateLabel(statelabel st, bool nofunction = false) { return SetState(FindState(st), nofunction); } + native action state ResolveState(statelabel st); // this one, unlike FindState, is context aware. native void LinkToWorld(); native void UnlinkFromWorld(); native bool CanSeek(Actor target); @@ -282,7 +286,7 @@ class Actor : Thinker native void A_Fall() { A_NoBlocking(); } native void A_XScream(); native void A_Look(); - native void A_Chase(state melee = null, state missile = null, int flags = 0); + native void A_Chase(statelabel melee = null, statelabel missile = null, int flags = 0); native void A_Scream(); native void A_VileChase(); native void A_BossDeath(); @@ -332,18 +336,10 @@ class Actor : Thinker native deprecated native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0); deprecated native void A_StopSoundEx(name slot); native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); - native state A_Jump(int chance, state label, ...); + native action state A_Jump(int chance, statelabel label, ...); native void A_CustomMissile(class missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); native void A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, float Spawnheight = 32, float Spawnofs_xy = 0); native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = null, float spawnofs_z = 0, int spiraloffset = 270, int limit = 0); - native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); - native state A_JumpIfCloser(float distance, state label, bool noz = false); - native state A_JumpIfTracerCloser(float distance, state label, bool noz = false); - native state A_JumpIfMasterCloser(float distance, state label, bool noz = false); - native state A_JumpIfTargetOutsideMeleeRange(state label); - native state A_JumpIfTargetInsideMeleeRange(state label); - native state A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); - native state A_JumpIfArmorType(name Type, state label, int amount = 1); native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); @@ -361,33 +357,29 @@ class Actor : Thinker native native void A_FadeTo(float target, float amount = 0.1, int flags = 0); native void A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, float size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1, float sizestep = 0); - native state A_CheckSight(state label); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); native void A_DropInventory(class itemtype); native void A_SetBlend(color color1, float alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); - deprecated native state A_CheckFlag(string flagname, state label, int check_pointer = AAPTR_DEFAULT); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); - native state A_JumpIf(bool expression, state label); native void A_RaiseMaster(bool copy = 0); native void A_RaiseChildren(bool copy = 0); native void A_RaiseSiblings(bool copy = 0); - native state A_CheckFloor(state label); - native state A_CheckCeiling(state label); - native state A_PlayerSkinCheck(state label); deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); - native state, bool A_Teleport(state teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 128, int ptr = AAPTR_DEFAULT); - native state, bool A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = null, float heightoffset = 0, float radiusoffset = 0, float pitch = 0); action native bool A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); native void A_Weave(int xspeed, int yspeed, float xdist, float ydist); + + native state, bool A_Teleport(statelabel teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 128, int ptr = AAPTR_DEFAULT); + native state, bool A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, statelabel success_state = null, float heightoffset = 0, float radiusoffset = 0, float pitch = 0); + native void A_CountdownArg(int argnum, statelabel targstate = null); + native state A_MonsterRefire(int chance, statelabel label); + native void A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, statelabel label = null); + native void A_Recoil(float xyvel); - native state A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class filter = null, name species = "None", float mindist = 0, int limit = 0); - native state A_CheckSpecies(state jump, name species = 'none', int ptr = AAPTR_DEFAULT); - native void A_CountdownArg(int argnum, state targstate = null); native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); native void A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); @@ -399,11 +391,7 @@ class Actor : Thinker native native void A_Respawn(int flags = 1); native void A_QueueCorpse(); native void A_DeQueueCorpse(); - native void A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = null); native void A_ClearLastHeard(); - native state A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, float offsetforward = 0); - native state A_JumpIfTargetInLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native state A_JumpIfInTargetLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); native bool A_SelectWeapon(class whichweapon, int flags = 0); action native void A_Punch(); native void A_Feathers(); @@ -416,7 +404,6 @@ class Actor : Thinker native native void A_RemoveForcefield(); native void A_DropWeaponPieces(class p1, class p2, class p3); native void A_PigPain (); - native state A_MonsterRefire(int chance, state label); native void A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(float roll, int flags = 0, int ptr = AAPTR_DEFAULT); @@ -455,13 +442,8 @@ class Actor : Thinker native native void A_SwapTeleFog(); native void A_SetHealth(int health, int ptr = AAPTR_DEFAULT); native void A_ResetHealth(int ptr = AAPTR_DEFAULT); - native state A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET); native void A_SetSpecies(name species, int ptr = AAPTR_DEFAULT); native void A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT); - native state A_CheckProximity(state jump, class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); - native state A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0); - native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false); - native state A_CheckRange(float distance, state label, bool two_dimension = false); native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); native bool A_CopySpriteFrame(int from, int to, int flags = 0); @@ -472,7 +454,7 @@ class Actor : Thinker native native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); native void A_CopyFriendliness(int ptr_source = AAPTR_MASTER); - action native bool A_Overlay(int layer, state start = null, bool nooverride = false); + action native bool A_Overlay(int layer, statelabel start = null, bool nooverride = false); native void A_WeaponOffset(float wx = 0, float wy = 32, int flags = 0); action native void A_OverlayOffset(int layer = PSP_WEAPON, float wx = 0, float wy = 32, int flags = 0); action native void A_OverlayFlags(int layer, int flags, bool set); @@ -525,7 +507,6 @@ class Actor : Thinker native } // Internal functions - deprecated private native state __decorate_internal_state__(state s); deprecated private native int __decorate_internal_int__(int i); deprecated private native bool __decorate_internal_bool__(bool b); deprecated private native float __decorate_internal_float__(float f); diff --git a/wadsrc/static/zscript/actor_checks.txt b/wadsrc/static/zscript/actor_checks.txt new file mode 100644 index 000000000..806539753 --- /dev/null +++ b/wadsrc/static/zscript/actor_checks.txt @@ -0,0 +1,274 @@ +extend class Actor +{ + //========================================================================== + // + // This file contains all the A_Jump* checker functions, all split up + // into an actual checker and a simple wrapper around ResolveState. + // + //========================================================================== + + action state A_JumpIf(bool expression, statelabel label) + { + return expression? ResolveState(label) : null; + } + + + //========================================================================== + // + // + // + //========================================================================== + + action state A_JumpIfHealthLower(int health, statelabel label, int ptr_selector = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr_selector); + return aptr && aptr.health < health? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + bool CheckIfCloser(Actor targ, float dist, bool noz = false) + { + if (!targ) return false; + return + (Distance2D(target) < dist && (noz || + ((pos.z > targ.pos.z && pos.z - targ.pos.z - targ.height < dist) || + (pos.z <= targ.pos.z && targ.pos.z - pos.z - height < dist) + ) + )); + } + + action state A_JumpIfCloser(float distance, statelabel label, bool noz = false) + { + Actor targ; + + if (player == NULL) + { + targ = target; + } + else + { + // Does the player aim at something that can be shot? + targ = AimTarget(); + } + + return CheckIfCloser(targ, distance, noz)? ResolveState(label) : null; + } + + action state A_JumpIfTracerCloser(float distance, statelabel label, bool noz = false) + { + return CheckIfCloser(tracer, distance, noz)? ResolveState(label) : null; + } + + action state A_JumpIfMasterCloser(float distance, statelabel label, bool noz = false) + { + return CheckIfCloser(master, distance, noz)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_JumpIfTargetOutsideMeleeRange(statelabel label) + { + return CheckMeleeRange()? null : ResolveState(label); + } + + action state A_JumpIfTargetInsideMeleeRange(statelabel label) + { + return CheckMeleeRange()? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckInventory(class itemtype, int itemamount, int owner = AAPTR_DEFAULT); + + action state A_JumpIfInventory(class itemtype, int itemamount, statelabel label, int owner = AAPTR_DEFAULT) + { + return CheckInventory(itemtype, itemamount, owner)? ResolveState(label) : null; + } + + action state A_JumpIfInTargetInventory(class itemtype, int amount, statelabel label, int forward_ptr = AAPTR_DEFAULT) + { + if (target == null) return null; + return target.CheckInventory(itemtype, amount, forward_ptr)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckArmorType(name Type, int amount = 1); + + action state A_JumpIfArmorType(name Type, statelabel label, int amount = 1) + { + return CheckArmorType(Type, amount)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckIfSeen(); + native bool CheckSightOrRange(float distance, bool two_dimension = false); + native bool CheckRange(float distance, bool two_dimension = false); + + action state A_CheckSight(statelabel label) + { + return CheckIfSeen()? ResolveState(label) : null; + } + + action state A_CheckSightOrRange(float distance, statelabel label, bool two_dimension = false) + { + return CheckSightOrRange(distance, two_dimension)? ResolveState(label) : null; + } + + action state A_CheckRange(float distance, statelabel label, bool two_dimension = false) + { + return CheckRange(distance, two_dimension)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_CheckFloor(statelabel label) + { + return pos.z <= floorz? ResolveState(label) : null; + } + + action state A_CheckCeiling(statelabel label) + { + return pos.z + height >= ceilingz? ResolveState(label) : null; + } + + //========================================================================== + // + // since this is deprecated the checker is private. + // + //========================================================================== + + private native bool CheckFlag(string flagname, int check_pointer = AAPTR_DEFAULT); + + deprecated action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT) + { + return CheckFlag(flagname, check_pointer)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool PlayerSkinCheck(); + + action state A_PlayerSkinCheck(statelabel label) + { + return PlayerSkinCheck()? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_CheckSpecies(statelabel label, name species = 'none', int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + return aptr && aptr.GetSpecies() == species? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckLOF(int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, float offsetforward = 0); + native bool CheckIfTargetInLOS (float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); + native bool CheckIfInTargetLOS (float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); + native bool CheckProximity(class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); + native bool CheckBlock(int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0); + + action state A_CheckLOF(statelabel label, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, float offsetforward = 0) + { + return CheckLOF(flags, range, minrange, angle, pitch, offsetheight, offsetwidth, ptr_target, offsetforward)? ResolveState(label) : null; + } + + action state A_JumpIfTargetInLOS (statelabel label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0) + { + return CheckIfTargetInLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; + } + + action state A_JumpIfInTargetLOS (statelabel label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0) + { + return CheckIfInTargetLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; + } + + action state A_CheckProximity(statelabel label, class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT) + { + // This one was doing some weird stuff that needs to be preserved. + state jumpto = ResolveState(label); + if (!jumpto) + { + if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) + { + return null; + } + } + return CheckProximity(classname, distance, count, flags, ptr)? jumpto : null; + } + + action state A_CheckBlock(statelabel label, int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0) + { + return CheckBlock(flags, ptr, xofs, yofs, zofs, angle)? ResolveState(label) : null; + } + + //=========================================================================== + // A_JumpIfHigherOrLower + // + // Jumps if a target, master, or tracer is higher or lower than the calling + // actor. Can also specify how much higher/lower the actor needs to be than + // itself. Can also take into account the height of the actor in question, + // depending on which it's checking. This means adding height of the + // calling actor's self if the pointer is higher, or height of the pointer + // if its lower. + //=========================================================================== + + action state A_JumpIfHigherOrLower(statelabel high, statelabel low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET) + { + Actor mobj = GetPointer(ptr); + + if (mobj != null && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. + { + if ((high) && (mobj.pos.z > ((includeHeight ? Height : 0) + pos.z + offsethigh))) + { + return ResolveState(high); + } + else if ((low) && (mobj.pos.z + (includeHeight ? mobj.Height : 0)) < (pos.z + offsetlow)) + { + return ResolveState(low); + } + } + return null; + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index b1aa901a3..f097e2c3b 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -162,7 +162,7 @@ extend class Actor boom.DeathSound = "misc/brainexplode"; boom.Vel.z = random[BrainScream](0, 255)/128.; - boom.SetState ("BossBrain::Brainexplode"); + boom.SetStateLabel ("BossBrain::Brainexplode"); boom.bRocketTrail = false; boom.SetDamage(0); // disables collision detection which is not wanted here boom.tics -= random[BrainScream](0, 7); diff --git a/wadsrc/static/zscript/heretic/hereticimp.txt b/wadsrc/static/zscript/heretic/hereticimp.txt index 34738ed56..c1443de03 100644 --- a/wadsrc/static/zscript/heretic/hereticimp.txt +++ b/wadsrc/static/zscript/heretic/hereticimp.txt @@ -113,7 +113,7 @@ class HereticImp : Actor if (extremecrash) { - SetState ("XCrash"); + SetStateLabel ("XCrash"); } } diff --git a/wadsrc/static/zscript/hexen/bats.txt b/wadsrc/static/zscript/hexen/bats.txt index a530da176..aaefaaeb7 100644 --- a/wadsrc/static/zscript/hexen/bats.txt +++ b/wadsrc/static/zscript/hexen/bats.txt @@ -92,7 +92,7 @@ class Bat : Actor { if (special2 < 0) { - SetState ("Death"); + SetStateLabel ("Death"); } special2 -= 2; // Called every 2 tics diff --git a/wadsrc/static/zscript/hexen/bishop.txt b/wadsrc/static/zscript/hexen/bishop.txt index d846a6402..32f0f3e63 100644 --- a/wadsrc/static/zscript/hexen/bishop.txt +++ b/wadsrc/static/zscript/hexen/bishop.txt @@ -131,7 +131,7 @@ class Bishop : Actor { if (random[BishopDecide]() >= 220) { - SetState ("Blur"); + SetStateLabel ("Blur"); } } @@ -210,7 +210,7 @@ class Bishop : Actor { if (random[BishopPainBlur]() < 64) { - SetState ("Blur"); + SetStateLabel ("Blur"); return; } double xo = random2[BishopPainBlur]() / 16.; diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index fc037d13f..e38ddbdb1 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -41,7 +41,7 @@ class Inventory : Actor native class StateProvider : Inventory native { - action native state A_JumpIfNoAmmo(state label); + action native state A_JumpIfNoAmmo(statelabel label); action native void A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = 0, sound MissSound = ""); action native void A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0, class missile = null, float Spawnheight = 32, float Spawnofs_xy = 0); action native void A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); @@ -73,13 +73,13 @@ class StateProvider : Inventory native action void A_BFGsound() { A_PlaySound("weapons/bfgf", CHAN_WEAPON); } action native void A_FireBFG(); action native void A_FireOldBFG(); - action native void A_ReFire(state flash = null); + action native void A_ReFire(statelabel flash = null); action native void A_ClearReFire(); action native void A_CheckReload(); - action native void A_GunFlash(state flash = null, int flags = 0); + action native void A_GunFlash(statelabel flash = null, int flags = 0); action native void A_FireAssaultGun(); action native void A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float spread_xy = 2.8125, float spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); - action native state A_CheckForReload(int counter, state label, bool dontincrement = false); + action native state A_CheckForReload(int counter, statelabel label, bool dontincrement = false); action native void A_ResetReloadCounter(); } diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index 178b2b27a..9e4463893 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -816,7 +816,7 @@ class StrifeGrenadeLauncher : StrifeWeapon Inventory.PickupMessage "$TXT_GLAUNCHER"; } - action native void A_FireGrenade (class grenadetype, float angleofs, state flash); + action native void A_FireGrenade (class grenadetype, float angleofs, statelabel flash); States {