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 {