From a350275bdfa182a1c2e0fbae247bb435dae3a7ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 19:03:46 +0100 Subject: [PATCH 01/35] - re-added two lost parentheses in A_FireGoldWandPL1. --- wadsrc/static/zscript/heretic/weaponwand.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/heretic/weaponwand.txt b/wadsrc/static/zscript/heretic/weaponwand.txt index bd1475adb..9516aa76c 100644 --- a/wadsrc/static/zscript/heretic/weaponwand.txt +++ b/wadsrc/static/zscript/heretic/weaponwand.txt @@ -59,7 +59,7 @@ class GoldWand : HereticWeapon return; } double pitch = BulletSlope(); - int damage = 7 + random[FireGoldWand]() & 7; + int damage = 7 + (random[FireGoldWand]() & 7); double ang = angle; if (player.refire) { From 3f98ba9069e1fce4676f6aff927b97f779a75c9f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 19:08:58 +0100 Subject: [PATCH 02/35] - fixed: The Raven ambient sounds lost their looping flag when they were rewritten to use A_PlaySound instead of A_PlaySoundEx. --- wadsrc/static/zscript/raven/ravenambient.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/raven/ravenambient.txt b/wadsrc/static/zscript/raven/ravenambient.txt index 3495dc4e0..e0cff04d3 100644 --- a/wadsrc/static/zscript/raven/ravenambient.txt +++ b/wadsrc/static/zscript/raven/ravenambient.txt @@ -13,7 +13,7 @@ class SoundWind : Actor States { Spawn: - TNT1 A 2 A_PlaySound("world/wind", CHAN_6); + TNT1 A 2 A_PlaySound("world/wind", CHAN_6, 1, true); Loop; } } @@ -36,7 +36,7 @@ class SoundWaterfall : Actor States { Spawn: - TNT1 A 2 A_PlaySound("world/waterfall", CHAN_6); + TNT1 A 2 A_PlaySound("world/waterfall", CHAN_6, 1, true); Loop; } } From 1895feb185cb2156a620de4a86004e456feb1026 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 19:22:56 +0100 Subject: [PATCH 03/35] - fixed two apparently bogus asserts with returning gloating point constants. --- src/scripting/vm/vmexec.h | 4 ++-- src/scripting/vm/vmframe.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 225c73cab..f5e61b5b9 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1827,12 +1827,12 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ case REGT_FLOAT: if (regtype & REGT_KONST) { - assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF); + assert(regnum < func->NumKonstF); src = &func->KonstF[regnum]; } else { - assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF); + assert(regnum < frame->NumRegF); src = ®.f[regnum]; } if (regtype & REGT_MULTIREG3) diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index d3ce5d5f9..871a46673 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -422,7 +422,7 @@ VMFrame *VMFrameStack::PopFrame() int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) { - assert(this == VMGlobalStack); // why would anyone even want to create a local stack? + assert(this == &GlobalVMStack); // why would anyone even want to create a local stack? bool allocated = false; try { From 07c110d5f7670bbf54f05d117bbabdd43c46311d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 30 Nov 2016 16:51:20 +0100 Subject: [PATCH 04/35] - Fixed GCC compilation error. It didn't like 'cvar' being declared between 'goto foundit' and the 'foundit' label. --- src/scripting/codegeneration/codegen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 28b20e289..da919e139 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5590,8 +5590,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) goto foundit; } - auto cvar = FindCVar(Identifier.GetChars(), nullptr); - if (cvar != nullptr) + if (auto *cvar = FindCVar(Identifier.GetChars(), nullptr)) { if (cvar->GetFlags() & CVAR_USERINFO) { From 0233c21e33f7458bf1d8ea28e4888831dff71377 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 19:48:52 +0100 Subject: [PATCH 05/35] - fixed: When a bogus class is deleted from AllActorClasses, the entry should also be removed from the array instead of leaving a null pointer behind. --- src/scripting/thingdef.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 77120c947..cdf35283a 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -387,8 +387,9 @@ void LoadActors () } FScriptPosition::ResetErrorCounter(); - for (auto ti : PClassActor::AllActorClasses) + for (int i = PClassActor::AllActorClasses.Size()-1; i>=0;i--) { + auto ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) { if (ti->ObjectFlags & OF_Transient) @@ -400,6 +401,7 @@ void LoadActors () { if (*op == ti) *op = nullptr; } + PClassActor::AllActorClasses.Delete(i); } else { From 87484950cf5704219db4b62649b3be8bc8a84977 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Dec 2016 00:05:23 +0100 Subject: [PATCH 06/35] - removed an assert from APowerMorph::EndEffect. With some recent changes to DestroyAllInventory it appears that the asserted condition no longer is true at this point when ending a game. - fixed: When replacing a tentative class, the pointers in the morph objects were not replaced. Instead of adding more ReplaceClassRef methods I chose to integrate this part into the PointerSubstitution mechanism and delete ReplaceClassRef entirely. The code had some oversights anyway that would have caused problems, now that non-actors can be created. --- src/d_player.h | 1 - src/dobject.cpp | 16 +++++++++++- src/dobject.h | 2 +- src/dobjtype.cpp | 14 +++-------- src/g_inventory/a_artifacts.cpp | 35 +++++++++++---------------- src/g_inventory/a_artifacts.h | 13 +++------- src/g_inventory/a_pickups.cpp | 11 +++++++-- src/g_inventory/a_pickups.h | 2 +- src/g_inventory/a_weaponpiece.cpp | 18 +------------- src/g_inventory/a_weaponpiece.h | 11 +-------- src/g_inventory/a_weapons.cpp | 18 -------------- src/g_inventory/a_weapons.h | 1 - src/g_shared/a_morph.cpp | 9 ++++++- src/g_shared/a_sharedglobal.h | 1 + src/info.cpp | 13 +++++----- src/info.h | 2 +- src/p_mobj.cpp | 2 ++ src/p_user.cpp | 11 +-------- src/scripting/thingdef.cpp | 15 +++--------- src/scripting/thingdef_properties.cpp | 9 ------- 20 files changed, 72 insertions(+), 132 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 4cdfb8b79..81a1c43a6 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -81,7 +81,6 @@ public: FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } void SetPainFlash(FName type, PalEntry color); bool GetPainFlash(FName type, PalEntry *color) const; - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString DisplayName; // Display name (used in menus, etc.) FString SoundClass; // Sound class diff --git a/src/dobject.cpp b/src/dobject.cpp index b05ae69ac..6b973de33 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -423,7 +423,7 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) // //========================================================================== -size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) +size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults) { DObject *probe; size_t changed = 0; @@ -438,6 +438,20 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) last = probe; } + if (scandefaults) + { + for (auto p : PClassActor::AllActorClasses) + { + auto def = GetDefaultByType(p); + if (def != nullptr) + { + def->Class = p; + def->DObject::PointerSubstitution(old, notOld); + def->Class = nullptr; // reset pointer. Defaults should not have a valid class pointer. + } + } + } + // Go through the bodyque. for (i = 0; i < BODYQUESIZE; ++i) { diff --git a/src/dobject.h b/src/dobject.h index 7d27133dc..ed9c0fffa 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -482,7 +482,7 @@ public: // change any pointers from the old object to the new object, // use this method. virtual size_t PointerSubstitution (DObject *old, DObject *notOld); - static size_t StaticPointerSubstitution (DObject *old, DObject *notOld); + static size_t StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults = false); PClass *GetClass() const { diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index dba554498..c33caf12f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3008,8 +3008,6 @@ PClass *ClassReg::RegisterClass() &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, - &PClassWeaponPiece::RegistrationInfo, - &PClassPowerupGiver::RegistrationInfo, }; // Skip classes that have already been registered @@ -3332,14 +3330,10 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) } else { - PClassActor::AllActorClasses.Pop(); // remove the newly added class from the list - // todo: replace all affected fields - for (unsigned i = 0; i < PClassActor::AllActorClasses.Size(); i++) - { - PClassActor::AllActorClasses[i]->ReplaceClassRef(existclass, type); - if (PClassActor::AllActorClasses[i] == existclass) - PClassActor::AllActorClasses[i] = static_cast(type); - } + StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. + // Delete the old class from the actor classes list, if it is in there. + auto index = PClassActor::AllActorClasses.Find(static_cast(existclass)); + if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index); TypeTable.ReplaceType(type, existclass, bucket); } return type; diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index a75b9ecd4..4afe74f1f 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -45,19 +45,12 @@ IMPLEMENT_CLASS(APowerup, false, false) // Powerup-Giver ------------------------------------------------------------- -IMPLEMENT_CLASS(PClassPowerupGiver, false, false) -void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - APowerupGiver *def = (APowerupGiver*)Defaults; - if (def != NULL) - { - if (def->PowerupType == oldclass) def->PowerupType = static_cast(newclass); - } -} +IMPLEMENT_CLASS(APowerupGiver, false, true) -IMPLEMENT_CLASS(APowerupGiver, false, false) +IMPLEMENT_POINTERS_START(APowerupGiver) +IMPLEMENT_POINTER(PowerupType) +IMPLEMENT_POINTERS_END DEFINE_FIELD(APowerupGiver, PowerupType) DEFINE_FIELD(APowerupGiver, EffectTics) @@ -1855,7 +1848,14 @@ void APowerDoubleFiringSpeed::EndEffect( ) // Morph powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerMorph, false, false) +IMPLEMENT_CLASS(APowerMorph, false, true) + +IMPLEMENT_POINTERS_START(APowerMorph) + IMPLEMENT_POINTER(PlayerClass) + IMPLEMENT_POINTER(MorphFlash) + IMPLEMENT_POINTER(UnMorphFlash) +IMPLEMENT_POINTERS_END + DEFINE_FIELD(APowerMorph, PlayerClass) DEFINE_FIELD(APowerMorph, MorphFlash) @@ -1916,19 +1916,12 @@ void APowerMorph::EndEffect( ) { Super::EndEffect(); - // Abort if owner already destroyed - if (Owner == NULL) + // Abort if owner already destroyed or unmorphed + if (Owner == nullptr || MorphedPlayer == nullptr) { - assert(MorphedPlayer == NULL); return; } - // Abort if owner already unmorphed - if (MorphedPlayer == NULL) - { - return; - } - // Abort if owner is dead; their Die() method will // take care of any required unmorphing on death. if (MorphedPlayer->health <= 0) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 7e9956d73..bb821b5d6 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -35,19 +35,11 @@ protected: friend void InitAllPowerupEffects(AInventory *item); }; -class PClassPowerupGiver: public PClassInventory -{ - DECLARE_CLASS(PClassPowerupGiver, PClassInventory) -protected: -public: - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); -}; - - // An artifact is an item that gives the player a powerup when activated. class APowerupGiver : public AInventory { - DECLARE_CLASS_WITH_META (APowerupGiver, AInventory, PClassPowerupGiver) + DECLARE_CLASS (APowerupGiver, AInventory) + HAS_OBJECT_POINTERS public: virtual bool Use (bool pickup) override; virtual void Serialize(FSerializer &arc) override; @@ -272,6 +264,7 @@ protected: class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) + HAS_OBJECT_POINTERS public: virtual void Serialize(FSerializer &arc) override; diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 91b88a053..51072023b 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -45,9 +45,9 @@ void PClassInventory::DeriveData(PClass *newclass) newc->RestrictedToPlayerClass = RestrictedToPlayerClass; } -void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) +size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass) { - Super::ReplaceClassRef(oldclass, newclass); + size_t changed = Super::PointerSubstitution(oldclass, newclass); AInventory *def = (AInventory*)Defaults; if (def != NULL) { @@ -55,14 +55,21 @@ void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) { if (ForbiddenToPlayerClass[i] == oldclass) + { ForbiddenToPlayerClass[i] = static_cast(newclass); + changed++; + } } for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) { if (RestrictedToPlayerClass[i] == oldclass) + { RestrictedToPlayerClass[i] = static_cast(newclass); + changed++; + } } } + return changed; } void PClassInventory::Finalize(FStateDefinitions &statedef) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 99dad8713..32914e3e5 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -55,7 +55,7 @@ class PClassInventory : public PClassActor public: PClassInventory(); virtual void DeriveData(PClass *newclass); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); + virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); void Finalize(FStateDefinitions &statedef); FString PickupMessage; diff --git a/src/g_inventory/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp index e1a7fe33b..2fe14ae91 100644 --- a/src/g_inventory/a_weaponpiece.cpp +++ b/src/g_inventory/a_weaponpiece.cpp @@ -38,7 +38,6 @@ #include "doomstat.h" #include "serializer.h" -IMPLEMENT_CLASS(PClassWeaponPiece, false, false) IMPLEMENT_CLASS(AWeaponHolder, false, false) DEFINE_FIELD(AWeaponHolder, PieceMask); @@ -50,22 +49,6 @@ DEFINE_FIELD(AWeaponHolder, PieceWeapon); // //=========================================================================== -void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - AWeaponPiece *def = (AWeaponPiece*)Defaults; - if (def != NULL) - { - if (def->WeaponClass == oldclass) def->WeaponClass = static_cast(newclass); - } -} - -//=========================================================================== -// -// -// -//=========================================================================== - void AWeaponHolder::Serialize(FSerializer &arc) { Super::Serialize(arc); @@ -77,6 +60,7 @@ IMPLEMENT_CLASS(AWeaponPiece, false, true) IMPLEMENT_POINTERS_START(AWeaponPiece) IMPLEMENT_POINTER(FullWeapon) + IMPLEMENT_POINTER(WeaponClass) IMPLEMENT_POINTERS_END //=========================================================================== diff --git a/src/g_inventory/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h index e0db15007..a8c6a2e76 100644 --- a/src/g_inventory/a_weaponpiece.h +++ b/src/g_inventory/a_weaponpiece.h @@ -2,18 +2,9 @@ #include "a_pickups.h" #include "a_weapons.h" -// -class PClassWeaponPiece : public PClassInventory -{ - DECLARE_CLASS(PClassWeaponPiece, PClassInventory) -protected: -public: - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); -}; - class AWeaponPiece : public AInventory { - DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece) + DECLARE_CLASS(AWeaponPiece, AInventory) HAS_OBJECT_POINTERS protected: bool PrivateShouldStay (); diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 19a30dcd8..c312f15b3 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -148,24 +148,6 @@ void PClassWeapon::DeriveData(PClass *newclass) } -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - AWeapon *def = (AWeapon*)Defaults; - if (def != NULL) - { - if (def->AmmoType1 == oldclass) def->AmmoType1 = static_cast(newclass); - if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast(newclass); - if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast(newclass); - } -} - //=========================================================================== // // diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index c6424075d..1b1258401 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -95,7 +95,6 @@ protected: virtual void DeriveData(PClass *newclass); public: PClassWeapon(); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); void Finalize(FStateDefinitions &statedef); int SlotNumber; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index f22318839..03f76c0c0 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -613,7 +613,14 @@ void InitAllPowerupEffects(AInventory *item) // Base class for morphing projectiles -------------------------------------- -IMPLEMENT_CLASS(AMorphProjectile, false, false) +IMPLEMENT_CLASS(AMorphProjectile, false, true) + +IMPLEMENT_POINTERS_START(AMorphProjectile) + IMPLEMENT_POINTER(PlayerClass) + IMPLEMENT_POINTER(MonsterClass) + IMPLEMENT_POINTER(MorphFlash) + IMPLEMENT_POINTER(UnMorphFlash) +IMPLEMENT_POINTERS_END DEFINE_FIELD(AMorphProjectile, PlayerClass) DEFINE_FIELD(AMorphProjectile, MonsterClass) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 0087690f7..001df5488 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -187,6 +187,7 @@ private: class AMorphProjectile : public AActor { DECLARE_CLASS (AMorphProjectile, AActor) + HAS_OBJECT_POINTERS; public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); diff --git a/src/info.cpp b/src/info.cpp index b8bf3acde..a0117a71f 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -619,19 +619,18 @@ void PClassActor::SetPainChance(FName type, int chance) // //========================================================================== -void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass) +size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { + auto changed = Super::PointerSubstitution(oldclass, newclass); for (unsigned i = 0; i < VisibleToPlayerClass.Size(); i++) { if (VisibleToPlayerClass[i] == oldclass) + { VisibleToPlayerClass[i] = static_cast(newclass); + changed++; + } } - AActor *def = (AActor*)Defaults; - if (def != NULL) - { - if (def->TeleFogSourceType == oldclass) def->TeleFogSourceType = static_cast(newclass); - if (def->TeleFogDestType == oldclass) def->TeleFogDestType = static_cast(newclass); - } + return changed; } //========================================================================== diff --git a/src/info.h b/src/info.h index bb21524a5..54aac3e3c 100644 --- a/src/info.h +++ b/src/info.h @@ -248,7 +248,7 @@ public: PClassActor(); ~PClassActor(); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); + virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); void BuildDefaults(); void ApplyDefaults(BYTE *defaults); void RegisterIDs(); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f1f33425a..5a37561c9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -145,6 +145,8 @@ IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(Poisoner) IMPLEMENT_POINTER(DamageFunc) IMPLEMENT_POINTER(alternative) + IMPLEMENT_POINTER(TeleFogSourceType) + IMPLEMENT_POINTER(TeleFogDestType) IMPLEMENT_POINTERS_END AActor::~AActor () diff --git a/src/p_user.cpp b/src/p_user.cpp index 74b07e0ca..b808dd9c3 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -607,16 +607,6 @@ bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const return false; } -void PClassPlayerPawn::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - APlayerPawn *def = (APlayerPawn*)Defaults; - if (def != NULL) - { - if (def->FlechetteType == oldclass) def->FlechetteType = static_cast(newclass); - } -} - //=========================================================================== // // player_t :: SendPitchLimits @@ -648,6 +638,7 @@ IMPLEMENT_CLASS(APlayerPawn, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvSel) + IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTERS_END IMPLEMENT_CLASS(APlayerChunk, false, false) diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index cdf35283a..e1d5f9b27 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -68,7 +68,6 @@ // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); -TArray OptionalClassPtrs; // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; @@ -365,7 +364,7 @@ static void CheckStates(PClassActor *obj) void ParseScripts(); void ParseAllDecorate(); -void LoadActors () +void LoadActors() { cycle_t timer; @@ -387,7 +386,7 @@ void LoadActors () } FScriptPosition::ResetErrorCounter(); - for (int i = PClassActor::AllActorClasses.Size()-1; i>=0;i--) + for (int i = PClassActor::AllActorClasses.Size() - 1; i >= 0; i--) { auto ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) @@ -397,10 +396,6 @@ void LoadActors () Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; DObject::StaticPointerSubstitution(ti, nullptr); - for (auto op : OptionalClassPtrs) - { - if (*op == ti) *op = nullptr; - } PClassActor::AllActorClasses.Delete(i); } else @@ -420,7 +415,7 @@ void LoadActors () CheckStates(ti); - + if (ti->bDecorateClass && ti->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) { // either a DECORATE based weapon or CustomInventory. @@ -429,7 +424,7 @@ void LoadActors () // hits an unsafe state. If we can find something here it can be handled wuth a compile error rather than a runtime error. CheckForUnsafeStates(ti); } - + } if (FScriptPosition::ErrorCounter > 0) { @@ -447,6 +442,4 @@ void LoadActors () QuestItemClasses[i] = PClass::FindActor(fmt); } StateSourceLines.Clear(); - OptionalClassPtrs.Clear(); - OptionalClassPtrs.ShrinkToFit(); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 9bff91a80..2eb5f6781 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -74,8 +74,6 @@ #include "a_health.h" #include "a_keys.h" -extern TArray OptionalClassPtrs; - //========================================================================== // // Gets a class pointer and performs an error check for correct type @@ -2998,7 +2996,6 @@ DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== @@ -3008,7 +3005,6 @@ DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MonsterClass); } //========================================================================== @@ -3036,7 +3032,6 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== @@ -3046,7 +3041,6 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); } //========================================================================== @@ -3056,7 +3050,6 @@ DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) { PROP_STRING_PARM(str, 0); defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== @@ -3075,7 +3068,6 @@ DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== @@ -3085,7 +3077,6 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); - if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); } From 7688e14becbe5f1aa13e5825c2dc90897377c9b1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Dec 2016 01:13:53 +0100 Subject: [PATCH 07/35] - added a boolean cast VM instruction. Although this already helps a lot with the messed up code generated for comparisons it's not really a solution for this - it still needs a proper implementation to generate efficient code. --- src/scripting/codegeneration/codegen.cpp | 20 +----------------- src/scripting/vm/vm.h | 5 +++++ src/scripting/vm/vmdisasm.cpp | 11 ++++++++++ src/scripting/vm/vmexec.h | 27 ++++++++++++++++++++++-- src/scripting/vm/vmops.h | 1 + 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index da919e139..df9d2bb46 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -758,25 +758,7 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) ExpEmit to(build, REGT_INT); from.Free(build); // Preload result with 0. - build->Emit(OP_LI, to.RegNum, 0); - - // Check source against 0. - if (from.RegType == REGT_INT) - { - build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum); - } - else if (from.RegType == REGT_FLOAT) - { - build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.)); - } - else if (from.RegType == REGT_POINTER) - { - build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - } - build->Emit(OP_JMP, 1); - - // Reload result with 1 if the comparison fell through. - build->Emit(OP_LI, to.RegNum, 1); + build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A); return to; } else diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 9bd0a4bc9..0ccde006f 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -130,6 +130,11 @@ enum CAST_V32S, CAST_SID2S, CAST_TID2S, + + CASTB_I, + CASTB_F, + CASTB_A, + CASTB_S }; // Register types for VMParam diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 2158139ab..d21e38d20 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -90,6 +90,7 @@ #define THROW MODE_AIMMZ | MODE_BCTHROW #define CATCH MODE_AIMMZ | MODE_BCCATCH #define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST +#define CASTB MODE_AI | MODE_BX | MODE_CIMMZ | MODE_BCCAST #define RSRSRS MODE_AS | MODE_BS | MODE_CS #define RIRS MODE_AI | MODE_BS | MODE_CUNUSED @@ -381,10 +382,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; default: + + if ((mode & MODE_BCTYPE) == MODE_BCCAST) { switch (code[i].c) { + case CASTB_I: + mode = MODE_AI | MODE_BI | MODE_CUNUSED; + break; + case CASTB_A: + mode = MODE_AI | MODE_BP | MODE_CUNUSED; + break; case CAST_I2F: case CAST_U2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; @@ -398,6 +407,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; case CAST_F2I: case CAST_F2U: + case CASTB_F: mode = MODE_AI | MODE_BF | MODE_CUNUSED; break; case CAST_F2S: @@ -412,6 +422,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case CAST_S2So: case CAST_S2N: case CAST_S2I: + case CASTB_S: mode = MODE_AI | MODE_BS | MODE_CUNUSED; break; case CAST_S2F: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index f5e61b5b9..d19850554 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -419,12 +419,12 @@ begin: if (C == CAST_I2F) { ASSERTF(a); ASSERTD(B); - reg.f[A] = reg.d[B]; + reg.f[a] = reg.d[B]; } else if (C == CAST_F2I) { ASSERTD(a); ASSERTF(B); - reg.d[A] = (int)reg.f[B]; + reg.d[a] = (int)reg.f[B]; } else { @@ -432,6 +432,29 @@ begin: } NEXTOP; + OP(CASTB): + if (C == CASTB_I) + { + ASSERTD(a); ASSERTD(B); + reg.f[a] = !!reg.d[B]; + } + else if (C == CASTB_F) + { + ASSERTD(a); ASSERTF(B); + reg.d[a] = reg.f[B] != 0; + } + else if (c == CASTB_A) + { + ASSERTD(a); ASSERTA(B); + reg.d[a] = reg.a[B] != nullptr; + } + else + { + ASSERTD(a); ASSERTS(B); + reg.d[a] = reg.s[B].Len() > 0; + } + NEXTOP; + OP(TEST): ASSERTD(a); if (reg.d[a] != BC) diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index e5b6d34eb..826bdb4e3 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -83,6 +83,7 @@ xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements) xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements) xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C +xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C // Control flow. xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++ From 44d7d0b5f6b345c43f8f2053dccb634e6bd940a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Dec 2016 09:44:52 +0100 Subject: [PATCH 08/35] - fixed a typo in the bool cast. - fixed a few places for unsigned values. --- src/scripting/codegeneration/codegen.cpp | 5 +++-- src/scripting/vm/vmexec.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index df9d2bb46..b6de3a664 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -584,7 +584,7 @@ static ExpEmit EmitKonst(VMFunctionBuilder *build, ExpEmit &emit) ExpEmit FxVectorValue::Emit(VMFunctionBuilder *build) { - // no const handling here. Ultimstely it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places) + // no const handling here. Ultimately it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places) // and the negatives (excessive allocation of float constants) outweigh the positives (saved a few instructions) assert(xyz[0] != nullptr); assert(xyz[1] != nullptr); @@ -1770,10 +1770,11 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) { int result = ~static_cast(Operand)->GetValue().GetInt(); FxExpression *e = new FxConstant(result, ScriptPosition); + e->ValueType = Operand->ValueType == TypeUInt32 ? TypeUInt32 : TypeSInt32; delete this; return e; } - ValueType = TypeSInt32; + ValueType = Operand->ValueType == TypeUInt32? TypeUInt32 : TypeSInt32; return this; } diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index d19850554..65e2e756c 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -443,7 +443,7 @@ begin: ASSERTD(a); ASSERTF(B); reg.d[a] = reg.f[B] != 0; } - else if (c == CASTB_A) + else if (C == CASTB_A) { ASSERTD(a); ASSERTA(B); reg.d[a] = reg.a[B] != nullptr; From 96df8f6729eae0bde91efafeed19587458c92f13 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Dec 2016 10:38:43 +0100 Subject: [PATCH 09/35] - another typo... --- src/scripting/vm/vmexec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 65e2e756c..8f79bd90b 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -436,7 +436,7 @@ begin: if (C == CASTB_I) { ASSERTD(a); ASSERTD(B); - reg.f[a] = !!reg.d[B]; + reg.d[a] = !!reg.d[B]; } else if (C == CASTB_F) { From cbd61d963f829729465ee2c39ea8eaa8be2e0c7f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 00:29:32 +0100 Subject: [PATCH 10/35] - removed test messages. --- wadsrc/static/zscript/hexen/heresiarch.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/wadsrc/static/zscript/hexen/heresiarch.txt b/wadsrc/static/zscript/hexen/heresiarch.txt index 9cfdde19d..db4860c34 100644 --- a/wadsrc/static/zscript/hexen/heresiarch.txt +++ b/wadsrc/static/zscript/hexen/heresiarch.txt @@ -583,7 +583,6 @@ class SorcBall1 : SorcBall { Super.BeginPlay (); AngleOffset = Heresiarch.BALL1_ANGLEOFFSET; - A_Log("Ball1 begins " .. AngleOffset); } //============================================================================ @@ -683,7 +682,6 @@ class SorcBall2 : SorcBall { Super.BeginPlay (); AngleOffset = Heresiarch.BALL2_ANGLEOFFSET; - A_Log("Ball2 begins " .. AngleOffset); } //============================================================================ @@ -733,7 +731,6 @@ class SorcBall3 : SorcBall { Super.BeginPlay (); AngleOffset = Heresiarch.BALL3_ANGLEOFFSET; - A_Log("Ball3 begins " .. AngleOffset); } //============================================================================ From 17d9a152e74c420ecee65772682f35eb1ae1f2f6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Dec 2016 23:44:23 +0100 Subject: [PATCH 11/35] - added missing THINGSPEC constants --- wadsrc/static/zscript/constants.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 2ccfb7048..c19925899 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -368,6 +368,9 @@ enum EActivationFlags THINGSPEC_ClearSpecial = 32, THINGSPEC_NoDeathSpecial = 64, THINGSPEC_TriggerActs = 128, + THINGSPEC_Activate = 1<<8, // The thing is activated when triggered + THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered + THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered // Shorter aliases for same AF_Default = 0, @@ -379,6 +382,9 @@ enum EActivationFlags AF_ClearSpecial = 32, AF_NoDeathSpecial = 64, AF_TriggerActs = 128, + AF_Activate = 1<<8, // The thing is activated when triggered + AF_Deactivate = 1<<9, // The thing is deactivated when triggered + AF_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered }; From 77192fa9dd4d0021790b95c1c672fe4658056408 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 00:51:29 +0100 Subject: [PATCH 12/35] - branch optimization. --- src/scripting/codegeneration/codegen.cpp | 241 ++++++++++++++--------- src/scripting/codegeneration/codegen.h | 7 + src/scripting/vm/vmbuilder.cpp | 13 ++ src/scripting/vm/vmbuilder.h | 2 + 4 files changed, 166 insertions(+), 97 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index b6de3a664..2d93dc866 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -288,6 +288,45 @@ ExpEmit FxExpression::Emit (VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit op = Emit(build); + ExpEmit i; + assert(op.RegType != REGT_NIL && op.RegCount == 1 && !op.Konst); + switch (op.RegType) + { + case REGT_INT: + build->Emit(OP_EQ_K, !invert, op.RegNum, build->GetConstantInt(0)); + break; + + case REGT_FLOAT: + build->Emit(OP_EQF_K, !invert, op.RegNum, build->GetConstantFloat(0)); + break; + + case REGT_POINTER: + build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); + break; + + case REGT_STRING: + i = ExpEmit(build, REGT_INT); + build->Emit(OP_LENS, i.RegNum, op.RegNum); + build->Emit(OP_EQ_K, !invert, i.RegNum, build->GetConstantInt(0)); + i.Free(build); + break; + + default: + break; + } + patchspots_no.Push(build->Emit(OP_JMP, 0)); + op.Free(build); +} + //========================================================================== // // @@ -757,7 +796,6 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) { ExpEmit to(build, REGT_INT); from.Free(build); - // Preload result with 0. build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A); return to; } @@ -773,6 +811,17 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) // //========================================================================== +void FxBoolCast::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + basex->EmitCompare(build, invert, patchspots_yes, patchspots_no); +} + +//========================================================================== +// +// +// +//========================================================================== + FxIntCast::FxIntCast(FxExpression *x, bool nowarn, bool explicitly) : FxExpression(EFX_IntCast, x->ScriptPosition) { @@ -1872,6 +1921,17 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) // //========================================================================== +void FxUnaryNotBoolean::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + Operand->EmitCompare(build, !invert, patchspots_yes, patchspots_no); +} + +//========================================================================== +// +// +// +//========================================================================== + FxSizeAlign::FxSizeAlign(FxExpression *operand, int which) : FxExpression(EFX_SizeAlign, operand->ScriptPosition) { @@ -3124,7 +3184,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) // //========================================================================== -ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) +ExpEmit FxCompareRel::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert) { ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); @@ -3154,11 +3214,15 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { op2.Free(build); } + if (invert) a ^= CMP_CHECK; - build->Emit(OP_LI, to.RegNum, 0, 0); + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } return to; } else @@ -3197,16 +3261,32 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { op1.Free(build); } + if (invert) check ^= 1; // See FxBoolCast for comments, since it's the same thing. - build->Emit(OP_LI, to.RegNum, 0, 0); + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); build->Emit(instr, check, op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } return to; } } +ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) +{ + return EmitCommon(build, false, false); +} + +void FxCompareRel::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit emit = EmitCommon(build, true, invert); + emit.Free(build); + patchspots_no.Push(build->Emit(OP_JMP, 0)); +} + //========================================================================== // // @@ -3404,7 +3484,7 @@ error: // //========================================================================== -ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) +ExpEmit FxCompareEq::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert) { ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); @@ -3418,13 +3498,17 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) int a = Operator == TK_Eq ? CMP_EQ : Operator == TK_Neq ? CMP_EQ | CMP_CHECK : CMP_EQ | CMP_APPROX; - if (op1.Konst) a|= CMP_BK; + if (op1.Konst) a |= CMP_BK; if (op2.Konst) a |= CMP_CK; + if (invert) a ^= CMP_CHECK; - build->Emit(OP_LI, to.RegNum, 0, 0); + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } op1.Free(build); op2.Free(build); return to; @@ -3457,14 +3541,29 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) } // See FxUnaryNotBoolean for comments, since it's the same thing. - build->Emit(OP_LI, to.RegNum, 0, 0); - build->Emit(instr, Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0), op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, int(invert) ^ (Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0)), op1.RegNum, op2.RegNum); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } return to; } } +ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) +{ + return EmitCommon(build, false, false); +} + +void FxCompareEq::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit emit = EmitCommon(build, true, invert); + emit.Free(build); + patchspots_no.Push(build->Emit(OP_JMP, 0)); +} + //========================================================================== // // @@ -4447,21 +4546,17 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) ExpEmit FxConditional::Emit(VMFunctionBuilder *build) { - size_t truejump, falsejump; - ExpEmit out; + size_t truejump; + ExpEmit out, falseout; // The true and false expressions ought to be assigned to the // same temporary instead of being copied to it. Oh well; good enough // for now. - ExpEmit cond = condition->Emit(build); - assert(cond.RegType == REGT_INT && !cond.Konst); + TArray yes, no; + condition->EmitCompare(build, false, yes, no); - // Test condition. - build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0)); - falsejump = build->Emit(OP_JMP, 0); - cond.Free(build); + build->BackpatchListToHere(yes); - // Evaluate true expression. if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT) { out = ExpEmit(build, REGT_INT); @@ -4501,7 +4596,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) truejump = build->Emit(OP_JMP, 0); // Evaluate false expression. - build->BackpatchToHere(falsejump); + build->BackpatchListToHere(no); if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT) { build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt()); @@ -8858,68 +8953,28 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) { ExpEmit v; - size_t jumpspot; - FxExpression *path1, *path2; - int condcheck; + size_t jumpspot = ~0u; - // This is pretty much copied from FxConditional, except we don't - // keep any results. - ExpEmit cond = Condition->Emit(build); - assert(cond.RegType != REGT_STRING && !cond.Konst); + TArray yes, no; + Condition->EmitCompare(build, false, yes, no); if (WhenTrue != nullptr) { - path1 = WhenTrue; - path2 = WhenFalse; - condcheck = 1; + build->BackpatchListToHere(yes); + WhenTrue->Emit(build); + } + if (WhenFalse != nullptr) + { + if (!WhenTrue->CheckReturn()) jumpspot = build->Emit(OP_JMP, 0); // no need to emit a jump if the block returns. + build->BackpatchListToHere(no); + WhenFalse->Emit(build); + if (jumpspot != ~0u) build->BackpatchToHere(jumpspot); + if (WhenTrue == nullptr) build->BackpatchListToHere(yes); } else { - // When there is only a false path, reverse the condition so we can - // treat it as a true path. - assert(WhenFalse != nullptr); - path1 = WhenFalse; - path2 = nullptr; - condcheck = 0; + build->BackpatchListToHere(no); } - - // Test condition. - - switch (cond.RegType) - { - default: - case REGT_INT: - build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0)); - break; - - case REGT_FLOAT: - build->Emit(OP_EQF_K, condcheck, cond.RegNum, build->GetConstantFloat(0)); - break; - - case REGT_POINTER: - build->Emit(OP_EQA_K, condcheck, cond.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - break; - } - jumpspot = build->Emit(OP_JMP, 0); - cond.Free(build); - - // Evaluate first path - v = path1->Emit(build); - v.Free(build); - if (path2 != nullptr) - { - size_t path1jump; - - // if the branch ends with a return we do not need a terminating jmp. - if (!path1->CheckReturn()) path1jump = build->Emit(OP_JMP, 0); - else path1jump = 0xffffffff; - // Evaluate second path - build->BackpatchToHere(jumpspot); - v = path2->Emit(build); - v.Free(build); - jumpspot = path1jump; - } - if (jumpspot != 0xffffffff) build->BackpatchToHere(jumpspot); return ExpEmit(); } @@ -9027,19 +9082,17 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) assert(Condition->ValueType == TypeBool); size_t loopstart, loopend; - size_t jumpspot; + TArray yes, no; // Evaluate the condition and execute/break out of the loop. loopstart = build->GetAddress(); if (!Condition->isConstant()) { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 0); - jumpspot = build->Emit(OP_JMP, 0); - cond.Free(build); + Condition->EmitCompare(build, false, yes, no); } else assert(static_cast(Condition)->GetValue().GetBool() == true); + build->BackpatchListToHere(yes); // Execute the loop's content. if (Code != nullptr) { @@ -9049,13 +9102,8 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) // Loop back. build->Backpatch(build->Emit(OP_JMP, 0), loopstart); + build->BackpatchListToHere(no); loopend = build->GetAddress(); - - if (!Condition->isConstant()) - { - build->Backpatch(jumpspot, loopend); - } - Backpatch(build, loopstart, loopend); return ExpEmit(); } @@ -9132,17 +9180,16 @@ ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build) loopstart = build->GetAddress(); if (!Condition->isConstant()) { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 1); - cond.Free(build); - build->Backpatch(build->Emit(OP_JMP, 0), codestart); + TArray yes, no; + Condition->EmitCompare(build, true, yes, no); + build->BackpatchList(no, codestart); + build->BackpatchListToHere(yes); } else if (static_cast(Condition)->GetValue().GetBool() == true) { // Always looping build->Backpatch(build->Emit(OP_JMP, 0), codestart); } loopend = build->GetAddress(); - Backpatch(build, loopstart, loopend); return ExpEmit(); diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c54c8dc62..c5e6f4e68 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -328,6 +328,7 @@ public: bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } virtual ExpEmit Emit(VMFunctionBuilder *build); + virtual void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); FScriptPosition ScriptPosition; PType *ValueType = nullptr; @@ -565,6 +566,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; class FxIntCast : public FxExpression @@ -734,6 +736,7 @@ public: ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; //========================================================================== @@ -934,7 +937,9 @@ public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); + ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; //========================================================================== @@ -949,7 +954,9 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); + ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; //========================================================================== diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index f358fce7b..9b399ad60 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -734,6 +734,13 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target) Code[loc].i24 = offset; } +void VMFunctionBuilder::BackpatchList(TArray &locs, size_t target) +{ + for (auto loc : locs) + Backpatch(loc, target); +} + + //========================================================================== // // VMFunctionBuilder :: BackpatchToHere @@ -748,6 +755,12 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc) Backpatch(loc, Code.Size()); } +void VMFunctionBuilder::BackpatchListToHere(TArray &locs) +{ + for (auto loc : locs) + Backpatch(loc, Code.Size()); +} + //========================================================================== // // FFunctionBuildList diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index d53393518..7434f3a21 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -69,6 +69,8 @@ public: void Backpatch(size_t addr, size_t target); void BackpatchToHere(size_t addr); + void BackpatchList(TArray &addrs, size_t target); + void BackpatchListToHere(TArray &addrs); // Write out complete constant tables. void FillIntConstants(int *konst); From 719be058e5db54d95325fe029cc800494fb9308c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 00:54:40 +0100 Subject: [PATCH 13/35] - use the immediate versions for loading integer constants when possible. --- src/scripting/codegeneration/codegen.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 2d93dc866..1629c8135 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2304,14 +2304,29 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) ExpEmit pointer = Base->Emit(build); Address = pointer; - ExpEmit result = Right->Emit(build); + ExpEmit result; + bool intconst = false; + int intconstval; + + if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) + { + intconst = true; + intconstval = static_cast(Right)->GetValue().GetInt(); + result.Konst = true; + result.RegType = REGT_INT; + } + else + { + result = Right->Emit(build); + } assert(result.RegType <= REGT_TYPE); if (pointer.Target) { if (result.Konst) { - build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); + else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); } else { @@ -2323,7 +2338,8 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) if (result.Konst) { ExpEmit temp(build, result.RegType); - build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); + if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); + else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); result.Free(build); result = temp; } From fb7a8fb553a185c0cfca20fe2487025de2b66ae9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 00:56:54 +0100 Subject: [PATCH 14/35] - branch optimization for for loops. --- src/scripting/codegeneration/codegen.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 1629c8135..7900f7262 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9279,7 +9279,7 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) size_t loopstart, loopend; size_t codestart; - size_t jumpspot; + TArray yes, no; // Init statement (only used by DECORATE. ZScript is pulling it before the loop statement and enclosing the entire loop in a compound statement so that Init can have local variables.) if (Init != nullptr) @@ -9292,12 +9292,10 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) codestart = build->GetAddress(); if (Condition != nullptr) { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 0); - cond.Free(build); - jumpspot = build->Emit(OP_JMP, 0); + Condition->EmitCompare(build, false, yes, no); } + build->BackpatchListToHere(yes); // Execute the loop's content. if (Code != nullptr) { @@ -9316,10 +9314,7 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) // End of loop. loopend = build->GetAddress(); - if (Condition != nullptr) - { - build->Backpatch(jumpspot, loopend); - } + build->BackpatchListToHere(no); Backpatch(build, loopstart, loopend); return ExpEmit(); From 4dd22d74dd672ff2adf5465757527b3af6da1b99 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 01:16:32 +0100 Subject: [PATCH 15/35] - partial optimization of chained comparisons. --- src/scripting/codegeneration/codegen.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 7900f7262..20c98acbe 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4176,23 +4176,19 @@ void FxBinaryLogical::Flatten() ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) { - TArray patchspots; + TArray yes, no; + bool invert = Operator == TK_OrOr; - int zero = build->GetConstantInt(0); for (unsigned i = 0; i < list.Size(); i++) { - assert(list[i]->ValueType->GetRegType() == REGT_INT); - ExpEmit op1 = list[i]->Emit(build); - assert(!op1.Konst); - op1.Free(build); - build->Emit(OP_EQ_K, (Operator == TK_AndAnd) ? 1 : 0, op1.RegNum, zero); - patchspots.Push(build->Emit(OP_JMP, 0, 0, 0)); + list[i]->EmitCompare(build, invert, yes, no); } + build->BackpatchListToHere(yes); ExpEmit to(build, REGT_INT); build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 1 : 0); build->Emit(OP_JMP, 1); + build->BackpatchListToHere(no); auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); - for (auto addr : patchspots) build->Backpatch(addr, ctarget); list.DeleteAndClear(); list.ShrinkToFit(); return to; @@ -4685,7 +4681,13 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(val, ctx); - + if (val->ValueType == TypeBool) // abs of a boolean is always the same as the operand + { + auto v = val; + val = nullptr; + delete this; + return v; + } if (!val->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); From 05cc3dde72fd135db1fd9f74e2527a58dfa5d4ab Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 01:33:18 +0100 Subject: [PATCH 16/35] - fixed: Dehacked did not copy the defaults for DehackedPickup replacements anymore. --- src/d_dehacked.cpp | 1 + src/p_mobj.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 6f9687aea..ed2310d45 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3020,6 +3020,7 @@ void FinishDehPatch () while (subclass == nullptr); AActor *defaults2 = GetDefaultByType (subclass); + memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); // Make a copy of the replaced class's state labels FStateDefinitions statedef; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5a37561c9..26e362d8f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7913,5 +7913,6 @@ void PrintMiscActorInfo(AActor *query) query->floorz, query->ceilingz); Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n", query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length()); + Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y); } } From 82c26706171f411a4e75c6a1f8c00ab1b39133f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 11:42:33 +0100 Subject: [PATCH 17/35] - removed redundant DoDropItem function. A_DropItem already exists and can be used instead. --- wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/strife/strifestuff.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index bd00ffc98..ee4c92add 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -303,7 +303,6 @@ class Actor : Thinker native native void DaggerAlert(Actor target); native void ClearBounce(); native TerrainDef GetFloorTerrain(); - native Inventory DoDropItem(Class type, int dropamount, int chance); native bool CheckLocalView(int consoleplayer); native void ExplodeMissile(line lin = null, Actor target = null); diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt index 20bee61d0..37918aa96 100644 --- a/wadsrc/static/zscript/strife/strifestuff.txt +++ b/wadsrc/static/zscript/strife/strifestuff.txt @@ -1864,7 +1864,7 @@ class PowerCoupling : Actor players[i].mo.GiveInventoryType ("QuestItem6"); S_Sound ("svox/voc13", CHAN_VOICE); players[i].SetLogNumber (13); - DoDropItem ("BrokenPowerCoupling", -1, 256); + A_DropItem ("BrokenPowerCoupling", -1, 256); Destroy (); } From f9441cd9d98684d2db56ab8082f3ce9de02c541e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 12:06:49 +0100 Subject: [PATCH 18/35] - added null pointer validation to any relevant exported function. In most cases null pointers were already being treated as 'do nothing', but there's several places where this can make the code silently fail so in these cases a VM exception will be raised, once the VM's exception handling has been repaired to provide useful diagnostics. (Right now all it does is catch the exception, print a useless message and return to the caller as if nothing has happened.) --- src/g_inventory/a_pickups.cpp | 10 +- src/g_shared/a_morph.cpp | 2 +- src/g_shared/a_specialspot.cpp | 3 +- src/p_actionfunctions.cpp | 2 +- src/p_ceiling.cpp | 2 +- src/p_enemy.cpp | 16 +-- src/p_floor.cpp | 2 +- src/p_interaction.cpp | 2 +- src/p_map.cpp | 3 +- src/p_maputl.cpp | 2 +- src/p_mobj.cpp | 162 ++++++++++++----------- src/p_pspr.cpp | 58 ++++---- src/p_sight.cpp | 2 +- src/p_states.cpp | 13 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/vm/vm.h | 11 ++ src/scripting/vm/vmexec.cpp | 4 + 17 files changed, 160 insertions(+), 136 deletions(-) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 51072023b..bdd1b6dc6 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -261,7 +261,7 @@ bool AInventory::SpecialDropAction (AActor *dropper) DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(dropper, AActor); + PARAM_OBJECT_NOT_NULL(dropper, AActor); ACTION_RETURN_BOOL(self->SpecialDropAction(dropper)); } @@ -429,7 +429,7 @@ bool AInventory::HandlePickup (AInventory *item) DEFINE_ACTION_FUNCTION(AInventory, HandlePickup) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->HandlePickup(item)); } @@ -1416,7 +1416,7 @@ bool AInventory::TryPickup (AActor *&toucher) DEFINE_ACTION_FUNCTION(AInventory, TryPickup) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_POINTER(toucher, AActor*); + PARAM_POINTER_NOT_NULL(toucher, AActor*); ACTION_RETURN_BOOL(self->TryPickup(*toucher)); } @@ -1434,7 +1434,7 @@ bool AInventory::TryPickupRestricted (AActor *&toucher) DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_POINTER(toucher, AActor*); + PARAM_POINTER_NOT_NULL(toucher, AActor*); ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher)); } @@ -1613,7 +1613,7 @@ void AInventory::AttachToOwner (AActor *other) DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); self->AttachToOwner(other); return 0; } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 03f76c0c0..136c096a3 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -363,7 +363,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, DEFINE_ACTION_FUNCTION(_PlayerInfo, UndoPlayerMorph) { PARAM_SELF_STRUCT_PROLOGUE(player_t); - PARAM_POINTER(player, player_t); + PARAM_POINTER_NOT_NULL(player, player_t); PARAM_INT_DEF(unmorphflag); PARAM_BOOL_DEF(force); ACTION_RETURN_BOOL(P_UndoPlayerMorph(self, player, unmorphflag, force)); diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 026185d07..b5debf2df 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -265,6 +265,7 @@ DEFINE_ACTION_FUNCTION(DSpotState, GetSpotState) FSpotList *DSpotState::FindSpotList(PClassActor *type) { + if (type == nullptr) return nullptr; for(unsigned i = 0; i < SpotLists.Size(); i++) { if (SpotLists[i].Type == type) return &SpotLists[i]; @@ -404,7 +405,7 @@ void ASpecialSpot::Destroy() DEFINE_ACTION_FUNCTION(AActor, A_SpawnSingleItem) { PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS (cls, AActor); + PARAM_CLASS_NOT_NULL(cls, AActor); PARAM_INT_DEF (fail_sp) PARAM_INT_DEF (fail_co) PARAM_INT_DEF (fail_dm) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 477ed37f2..115bc1f54 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -247,7 +247,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass) PARAM_BOOL_DEF (match_superclass); self = COPY_AAPTR(self, pick_pointer); - if (self == NULL) + if (self == nullptr || checktype == nullptr) { ret->SetInt(false); } diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 932b4c649..4da81db46 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -461,7 +461,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling) { PARAM_PROLOGUE; - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_INT(type); PARAM_POINTER(ln, line_t); PARAM_FLOAT(speed); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 751f92a30..beaa1548f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1307,6 +1307,11 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams double mindist; DAngle fov; + if (other == nullptr) + { + return false; + } + if (params != NULL) { maxdist = params->maxDist; @@ -3095,7 +3100,7 @@ void A_FaceTarget(AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_Face) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(faceto, AActor) + PARAM_OBJECT_NOT_NULL(faceto, AActor) PARAM_ANGLE_DEF(max_turn) PARAM_ANGLE_DEF(max_pitch) PARAM_ANGLE_DEF(ang_offset) @@ -3323,15 +3328,6 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c return NULL; } -DEFINE_ACTION_FUNCTION(AActor, DoDropItem) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(cls, AActor); - PARAM_INT(amt); - PARAM_INT(chance); - ACTION_RETURN_OBJECT(P_DropItem(self, cls, amt, chance)); -} - //============================================================================ // // P_TossItem diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 8fd5ad038..4b1f243d5 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -495,7 +495,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, DEFINE_ACTION_FUNCTION(DFloor, CreateFloor) { PARAM_PROLOGUE; - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_INT(floortype); PARAM_POINTER(ln, line_t); PARAM_FLOAT(speed); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index e6729096c..9aa178e64 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1639,7 +1639,7 @@ void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage DEFINE_ACTION_FUNCTION(AActor, PoisonMobj) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT_NOT_NULL(inflictor, AActor); PARAM_OBJECT(source, AActor); PARAM_INT(damage); PARAM_INT(duration); diff --git a/src/p_map.cpp b/src/p_map.cpp index 11036d171..f25c33612 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4513,6 +4513,7 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack) PARAM_POINTER_DEF(victim, FTranslatedLineTarget); int acdmg; + if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from. auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg); if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT); if (numret > 1) ret[1].SetInt(acdmg), numret = 2; @@ -4716,7 +4717,7 @@ DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed) { PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget); PARAM_INT(damage); - PARAM_OBJECT(missile, AActor); + PARAM_OBJECT_NOT_NULL(missile, AActor); P_TraceBleed(damage, self, missile); return 0; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index aa29a1c5e..31b412598 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1193,7 +1193,7 @@ IMPLEMENT_CLASS(DBlockThingsIterator, false, false); DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Create) { PARAM_PROLOGUE; - PARAM_OBJECT(origin, AActor); + PARAM_OBJECT_NOT_NULL(origin, AActor); PARAM_FLOAT_DEF(radius); PARAM_BOOL_DEF(ignore); ACTION_RETURN_OBJECT(new DBlockThingsIterator(origin, radius, ignore)); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 26e362d8f..88653fca9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -751,7 +751,7 @@ void AActor::AddInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, AddInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); self->AddInventory(item); return 0; } @@ -819,7 +819,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) DEFINE_ACTION_FUNCTION(AActor, Inventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->UseInventory(item)); } @@ -854,7 +854,7 @@ void AActor::RemoveInventory(AInventory *item) DEFINE_ACTION_FUNCTION(AActor, RemoveInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); self->RemoveInventory(item); return 0; } @@ -1009,7 +1009,7 @@ bool AActor::UseInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, UseInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->UseInventory(item)); } @@ -1042,7 +1042,7 @@ AInventory *AActor::DropInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, DropInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_OBJECT(self->DropInventory(item)); } @@ -1263,7 +1263,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); PARAM_BOOL_DEF(changetarget); PARAM_BOOL_DEF(resethealth); self->CopyFriendliness(other, changetarget, resethealth); @@ -1486,7 +1486,7 @@ void AActor::Touch (AActor *toucher) DEFINE_ACTION_FUNCTION(AActor, Touch) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(toucher, AActor); + PARAM_OBJECT_NOT_NULL(toucher, AActor); self->Touch(toucher); return 0; } @@ -2000,7 +2000,7 @@ bool AActor::CanSeek(AActor *target) const DEFINE_ACTION_FUNCTION(AActor, CanSeek) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); ACTION_RETURN_BOOL(self->CanSeek(target)); } @@ -4669,7 +4669,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a DEFINE_ACTION_FUNCTION(AActor, Spawn) { PARAM_PROLOGUE; - PARAM_CLASS(type, AActor); + PARAM_CLASS_NOT_NULL(type, AActor); PARAM_FLOAT_DEF(x); PARAM_FLOAT_DEF(y); PARAM_FLOAT_DEF(z); @@ -5656,6 +5656,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 AActor *puff; DVector3 pos = pos1; + if (pufftype == nullptr) return nullptr; + if (!(flags & PF_NORANDOMZ)) pos.Z += pr_spawnpuff.Random2() / 64.; puff = Spawn(pufftype, pos, ALLOW_REPLACE); if (puff == NULL) return NULL; @@ -6163,7 +6165,7 @@ foundone: DEFINE_ACTION_FUNCTION(AActor, HitWater) { PARAM_SELF_PROLOGUE(AActor); - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_FLOAT(z); @@ -6383,7 +6385,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) DEFINE_ACTION_FUNCTION(AActor, PlaySpawnSound) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(missile, AActor); + PARAM_OBJECT_NOT_NULL(missile, AActor); P_PlaySpawnSound(missile, self); return 0; } @@ -6415,47 +6417,11 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); -} - -DEFINE_ACTION_FUNCTION(AActor, SpawnMissile) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(dest, AActor); - PARAM_CLASS(type, AActor); - PARAM_OBJECT_DEF(owner, AActor); - ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); -} - -AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosAtZ(z), source, dest, type); -} - -DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); - PARAM_CLASS(type, AActor); - ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type)); -} - AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } if (dest == NULL) @@ -6530,19 +6496,56 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileXYZ) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); PARAM_BOOL_DEF(check); PARAM_OBJECT_DEF(owner, AActor); ACTION_RETURN_OBJECT(P_SpawnMissileXYZ(DVector3(x,y,z), self, dest, type, check, owner)); } +AActor *P_SpawnMissile(AActor *source, AActor *dest, PClassActor *type, AActor *owner) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); +} + +AActor *P_SpawnMissileZ(AActor *source, double z, AActor *dest, PClassActor *type) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosAtZ(z), source, dest, type); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type)); +} + + AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *th = Spawn (type, source->PosPlusZ(32.), ALLOW_REPLACE); @@ -6568,7 +6571,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); PARAM_OBJECT_DEF(owner, AActor); ACTION_RETURN_OBJECT(P_OldSpawnMissile(self, owner, dest, type)); @@ -6586,7 +6589,7 @@ DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, double vz) { - if (source == NULL) + if (source == nullptr || type == nullptr) { return NULL; } @@ -6595,14 +6598,18 @@ AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, do AActor *P_SpawnMissileAngleZ (AActor *source, double z, PClassActor *type, DAngle angle, double vz) { + if (type == nullptr) + { + return nullptr; + } return P_SpawnMissileAngleZSpeed (source, z, type, angle, vz, GetDefaultSpeed (type)); } AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } DAngle an; double dist; @@ -6626,7 +6633,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); ACTION_RETURN_OBJECT(P_SpawnMissileZAimed(self, z, dest, type)); } @@ -6643,9 +6650,9 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z, PClassActor *type, DAngle angle, double vz, double speed, AActor *owner, bool checkspawn) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *mo; @@ -6689,9 +6696,9 @@ AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target) { AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE); - if (other == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } other->target = target; @@ -6723,7 +6730,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnSubMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(cls, AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); ACTION_RETURN_OBJECT(P_SpawnSubMissile(self, cls, target)); } /* @@ -6753,6 +6760,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, PClassActor *type, DAngle angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor, bool nofreeaim, bool noautoaim, int aimflags) { + if (source == nullptr || type == nullptr) + { + return nullptr; + } + static const double angdiff[3] = { -5.625, 5.625, 0 }; DAngle an = angle; DAngle pitch; @@ -6760,10 +6772,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, AActor *defaultobject = GetDefaultByType(type); DAngle vrange = nofreeaim ? 35. : 0.; - if (source == NULL) - { - return NULL; - } if (!pLineTarget) pLineTarget = &scratch; if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim)) { @@ -6910,7 +6918,7 @@ bool AActor::IsTeammate (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isTeammate) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsTeammate(other)); } @@ -6982,7 +6990,7 @@ bool AActor::IsFriend (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isFriend) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsFriend(other)); } @@ -7019,7 +7027,7 @@ bool AActor::IsHostile (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isHostile) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsHostile(other)); } @@ -7058,7 +7066,7 @@ int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); PARAM_INT(damage); PARAM_NAME(damagetype); ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); @@ -7580,14 +7588,14 @@ DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global? DEFINE_ACTION_FUNCTION(AActor, Distance2D) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_FLOAT(self->Distance2D(other)); } DEFINE_ACTION_FUNCTION(AActor, Distance3D) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_FLOAT(self->Distance3D(other)); } @@ -7620,7 +7628,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType) { PARAM_PROLOGUE; PARAM_CLASS(cls, AActor); - ACTION_RETURN_OBJECT(GetDefaultByType(cls)); + ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls)); } DEFINE_ACTION_FUNCTION(AActor, GetBobOffset) @@ -7692,7 +7700,7 @@ DEFINE_ACTION_FUNCTION(AActor, Thrust) DEFINE_ACTION_FUNCTION(AActor, AngleTo) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(targ, AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); PARAM_BOOL_DEF(absolute); ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees); } @@ -7717,7 +7725,7 @@ DEFINE_ACTION_FUNCTION(AActor, RotateVector) DEFINE_ACTION_FUNCTION(AActor, DistanceBySpeed) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(targ, AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); PARAM_FLOAT(speed); ACTION_RETURN_FLOAT(self->DistanceBySpeed(targ, speed)); } @@ -7745,14 +7753,14 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2Angle) DEFINE_ACTION_FUNCTION(AActor, Vec3To) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(t, AActor) + PARAM_OBJECT_NOT_NULL(t, AActor) ACTION_RETURN_VEC3(self->Vec3To(t)); } DEFINE_ACTION_FUNCTION(AActor, Vec2To) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(t, AActor) + PARAM_OBJECT_NOT_NULL(t, AActor) ACTION_RETURN_VEC2(self->Vec2To(t)); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 610ade35a..733741cb2 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1605,38 +1605,40 @@ void player_t::DestroyPSprites() void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) { - - PClassActor *cls = weapon->GetClass(); - while (cls != RUNTIME_CLASS(AWeapon)) + if (flashstate != nullptr) { - if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) + PClassActor *cls = weapon->GetClass(); + while (cls != RUNTIME_CLASS(AWeapon)) { - // The flash state belongs to this class. - // Now let's check if the actually wanted state does also - if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) { - // we're ok so set the state - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); - return; - } - else - { - // oh, no! The state is beyond the end of the state table so use the original flash state. - P_SetPsprite(player, PSP_FLASH, flashstate, true); - return; + // The flash state belongs to this class. + // Now let's check if the actually wanted state does also + if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + { + // we're ok so set the state + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); + return; + } + else + { + // oh, no! The state is beyond the end of the state table so use the original flash state. + P_SetPsprite(player, PSP_FLASH, flashstate, true); + return; + } } + // try again with parent class + cls = static_cast(cls->ParentClass); + } + // if we get here the state doesn't seem to belong to any class in the inheritance chain + // This can happen with Dehacked if the flash states are remapped. + // The only way to check this would be to go through all Dehacked modifiable actors, convert + // their states into a single flat array and find the correct one. + // Rather than that, just check to make sure it belongs to something. + if (FState::StaticFindStateOwner(flashstate + index) == NULL) + { // Invalid state. With no index offset, it should at least be valid. + index = 0; } - // try again with parent class - cls = static_cast(cls->ParentClass); - } - // if we get here the state doesn't seem to belong to any class in the inheritance chain - // This can happen with Dehacked if the flash states are remapped. - // The only way to check this would be to go through all Dehacked modifiable actors, convert - // their states into a single flat array and find the correct one. - // Rather than that, just check to make sure it belongs to something. - if (FState::StaticFindStateOwner(flashstate + index) == NULL) - { // Invalid state. With no index offset, it should at least be valid. - index = 0; } P_SetPsprite(player, PSP_FLASH, flashstate + index, true); } @@ -1644,7 +1646,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash) { PARAM_SELF_STRUCT_PROLOGUE(player_t); - PARAM_OBJECT(weapon, AWeapon); + PARAM_OBJECT_NOT_NULL(weapon, AWeapon); PARAM_POINTER(state, FState); PARAM_INT(index); P_SetSafeFlash(weapon, self, state, index); diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 319d5b3ec..21aa1bbe3 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -908,7 +908,7 @@ done: DEFINE_ACTION_FUNCTION(AActor, CheckSight) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); PARAM_INT_DEF(flags); ACTION_RETURN_BOOL(P_CheckSight(self, target, flags)); } diff --git a/src/p_states.cpp b/src/p_states.cpp index 7daaa5e41..87a1bae2f 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -1083,11 +1083,12 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo) { PARAM_SELF_STRUCT_PROLOGUE(FState); PARAM_POINTER(other, FState); - - // Safely calculate the distance between two states. - auto o1 = FState::StaticFindStateOwner(self); - int retv; - if (other < o1->OwnedStates || other >= o1->OwnedStates + o1->NumOwnedStates) retv = INT_MIN; - else retv = int(other - self); + int retv = INT_MIN; + if (other != nullptr) + { + // Safely calculate the distance between two states. + auto o1 = FState::StaticFindStateOwner(self); + if (other >= o1->OwnedStates && other < o1->OwnedStates + o1->NumOwnedStates) retv = int(other - self); + } ACTION_RETURN_INT(retv); } diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 20c98acbe..3a2dc6034 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9697,7 +9697,7 @@ int BuiltinClassCast(VMValue *param, TArray &defaultparam, int numparam PARAM_PROLOGUE; PARAM_CLASS(from, DObject); PARAM_CLASS(to, DObject); - ACTION_RETURN_OBJECT(from->IsDescendantOf(to) ? from : nullptr); + ACTION_RETURN_OBJECT(from && to && from->IsDescendantOf(to) ? from : nullptr); } ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 0ccde006f..d105d396c 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -951,6 +951,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction // Use these to collect the parameters in a native function. // variable name at position

+void NullParam(const char *varname); + +#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr) // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; @@ -966,6 +969,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #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))); +#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); +#define PARAM_OBJECT_NOT_NULL_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_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_NOT_NULL_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_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_EXISTS(p) ((p) < numparam) #define ASSERTINT(p) assert((p).Type == REGT_INT) @@ -988,6 +994,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #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; } +#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; @@ -1005,6 +1012,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #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) +#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type) +#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type) +#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base) #define PARAM_INT_DEF(x) ++paramnum; PARAM_INT_DEF_AT(paramnum,x) #define PARAM_BOOL_DEF(x) ++paramnum; PARAM_BOOL_DEF_AT(paramnum,x) @@ -1019,6 +1029,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #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) +#define PARAM_CLASS_DEF_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_DEF_NOT_NULL_AT(paramnum,x,base) typedef int(*actionf_p)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index f51038f36..183cc728c 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -228,3 +228,7 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } } } + +void NullParam(const char *varname) +{ +} \ No newline at end of file From 9dbfa6d04ed14044f134634fc63a7261dfe906f6 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Fri, 2 Dec 2016 13:22:42 +0100 Subject: [PATCH 19/35] - Fixed uninitialized line number info in thing map parsing. --- src/p_things.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_things.cpp b/src/p_things.cpp index d94ba6a01..ba377abeb 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -601,6 +601,7 @@ static void ParseSpawnMap(FScanner &sc, SpawnMap & themap, const char *descript) } defined[ednum] = true; editem.classname = sc.String; + editem.linenum = sc.Line; themap.Insert(ednum, editem); } From 967f6c0269e090cc42468c8c31f20b27895553c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 16:56:50 +0100 Subject: [PATCH 20/35] - use a separate exception type for reporting errors from FraggleScript. CRecoverableError is used in other parts as well and it might create interference. --- src/fragglescript/t_func.cpp | 4 ++-- src/fragglescript/t_parse.cpp | 16 ++++++++++++++-- src/fragglescript/t_script.cpp | 2 +- src/fragglescript/t_script.h | 10 ++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 6b0059981..7cd599b11 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2014,13 +2014,13 @@ void FParser::SF_CeilingTexture(void) void FParser::SF_ChangeHubLevel(void) { - I_Error("FS hub system permanently disabled\n"); + script_error("FS hub system permanently disabled\n"); } // for start map: start new game on a particular skill void FParser::SF_StartSkill(void) { - I_Error("startskill is not supported by this implementation!\n"); + script_error("startskill is not supported by this implementation!\n"); } //========================================================================== diff --git a/src/fragglescript/t_parse.cpp b/src/fragglescript/t_parse.cpp index 0b2f27680..28330e9e9 100644 --- a/src/fragglescript/t_parse.cpp +++ b/src/fragglescript/t_parse.cpp @@ -113,7 +113,7 @@ void FParser::NextToken() } if(!Section) { - I_Error("section not found!\n"); + script_error("section not found!\n"); return; } } @@ -708,6 +708,18 @@ void FParser::EvaluateExpression(svalue_t &result, int start, int stop) // //========================================================================== +void FS_Error(const char *error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + throw CFraggleScriptError(errortext); +} + + void FParser::ErrorMessage(FString msg) { int linenum = 0; @@ -721,7 +733,7 @@ void FParser::ErrorMessage(FString msg) } //lineinfo.Format("Script %d, line %d: ", Script->scriptnum, linenum); - I_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars()); + FS_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars()); } //========================================================================== diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index b852607b3..81b2ce21e 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -251,7 +251,7 @@ void DFsScript::ParseScript(char *position) FParser parse(this); parse.Run(position, data, data + len); } - catch (CRecoverableError &err) + catch (CFraggleScriptError &err) { Printf ("%s\n", err.GetMessage()); } diff --git a/src/fragglescript/t_script.h b/src/fragglescript/t_script.h index 50829e000..f0409a3f0 100644 --- a/src/fragglescript/t_script.h +++ b/src/fragglescript/t_script.h @@ -41,12 +41,22 @@ #include "p_lnspec.h" #include "m_fixed.h" #include "actor.h" +#include "doomerrors.h" #ifdef _MSC_VER // This pragma saves 8kb of wasted code. #pragma pointers_to_members( full_generality, single_inheritance ) #endif + +class CFraggleScriptError : public CDoomError +{ +public: + CFraggleScriptError() : CDoomError() {} + CFraggleScriptError(const char *message) : CDoomError(message) {} +}; + + class DRunningScript; From 1e01e6e4df263992b7c5550dcd88fefa833e02ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 17:36:29 +0100 Subject: [PATCH 21/35] - record all line numbers during function generation. This is useful for error reporting and eventually debugging. - throw a useful exception when a VM abort occurs, the simple enum was incapable of reporting anything more than the barest minimum, which at least for array index out of bounds errors was insufficient. The current exception mechanism is still insufficient. It really has to report a proper crash location and print a stack trace to the maximum extent possible. Instead it just prints a message and happily goes on. This is not a good solution. --- src/doomerrors.h | 8 +++- src/sc_man.cpp | 2 +- src/scripting/codegeneration/codegen.cpp | 34 +++++++++----- src/scripting/codegeneration/codegen.h | 1 + src/scripting/vm/vm.h | 9 ++++ src/scripting/vm/vmbuilder.cpp | 33 +++++++++++++- src/scripting/vm/vmbuilder.h | 12 +++++ src/scripting/vm/vmexec.cpp | 57 ++++++++++++++++++++++-- src/scripting/vm/vmexec.h | 49 +++++++++----------- src/scripting/vm/vmframe.cpp | 32 +------------ 10 files changed, 159 insertions(+), 78 deletions(-) diff --git a/src/doomerrors.h b/src/doomerrors.h index f4b0c9566..c389c6b05 100644 --- a/src/doomerrors.h +++ b/src/doomerrors.h @@ -56,6 +56,12 @@ public: strncpy (m_Message, message, MAX_ERRORTEXT-1); m_Message[MAX_ERRORTEXT-1] = '\0'; } + void AppendMessage(const char *message) + { + size_t len = strlen(m_Message); + strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len); + m_Message[MAX_ERRORTEXT - 1] = '\0'; + } const char *GetMessage (void) const { if (m_Message[0] != '\0') @@ -64,7 +70,7 @@ public: return NULL; } -private: +protected: char m_Message[MAX_ERRORTEXT]; }; diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 254caed62..ccfb01ac5 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1007,7 +1007,7 @@ void FScanner::CheckOpen() //========================================================================== int FScriptPosition::ErrorCounter; int FScriptPosition::WarnCounter; -bool FScriptPosition::StrictErrors; // makes all OPTERRPR messages real errors. +bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors. FScriptPosition::FScriptPosition(const FScriptPosition &other) { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 3a2dc6034..6a0f840a5 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -288,6 +288,21 @@ ExpEmit FxExpression::Emit (VMFunctionBuilder *build) } +//========================================================================== +// +// Emits a statement and records its position in the source. +// +//========================================================================== + +void FxExpression::EmitStatement(VMFunctionBuilder *build) +{ + build->BeginStatement(this); + ExpEmit exp = Emit(build); + exp.Free(build); + build->EndStatement(); +} + + //========================================================================== // // @@ -8519,9 +8534,7 @@ ExpEmit FxSequence::Emit(VMFunctionBuilder *build) { for (unsigned i = 0; i < Expressions.Size(); ++i) { - ExpEmit v = Expressions[i]->Emit(build); - // Throw away any result. We don't care about it. - v.Free(build); + Expressions[i]->EmitStatement(build); } return ExpEmit(); } @@ -8817,7 +8830,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) break; default: - line->Emit(build); + line->EmitStatement(build); break; } } @@ -8979,13 +8992,13 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) if (WhenTrue != nullptr) { build->BackpatchListToHere(yes); - WhenTrue->Emit(build); + WhenTrue->EmitStatement(build); } if (WhenFalse != nullptr) { if (!WhenTrue->CheckReturn()) jumpspot = build->Emit(OP_JMP, 0); // no need to emit a jump if the block returns. build->BackpatchListToHere(no); - WhenFalse->Emit(build); + WhenFalse->EmitStatement(build); if (jumpspot != ~0u) build->BackpatchToHere(jumpspot); if (WhenTrue == nullptr) build->BackpatchListToHere(yes); } @@ -9114,8 +9127,7 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) // Execute the loop's content. if (Code != nullptr) { - ExpEmit code = Code->Emit(build); - code.Free(build); + Code->EmitStatement(build); } // Loop back. @@ -9190,8 +9202,7 @@ ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build) codestart = build->GetAddress(); if (Code != nullptr) { - ExpEmit code = Code->Emit(build); - code.Free(build); + Code->EmitStatement(build); } // Evaluate the condition and execute/break out of the loop. @@ -9301,8 +9312,7 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) // Execute the loop's content. if (Code != nullptr) { - ExpEmit code = Code->Emit(build); - code.Free(build); + Code->EmitStatement(build); } // Iteration statement. diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c5e6f4e68..49999206d 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -328,6 +328,7 @@ public: bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } virtual ExpEmit Emit(VMFunctionBuilder *build); + void EmitStatement(VMFunctionBuilder *build); virtual void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); FScriptPosition ScriptPosition; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index d105d396c..7285fb48d 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -5,6 +5,7 @@ #include "autosegs.h" #include "vectors.h" #include "cmdlib.h" +#include "doomerrors.h" #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function @@ -189,6 +190,13 @@ enum EVMAbortException X_BAD_SELF, }; +class CVMAbortException : public CDoomError +{ +public: + static FString stacktrace; + CVMAbortException(EVMAbortException reason, const char *moreinfo, ...); +}; + enum EVMOpMode { MODE_ASHIFT = 0, @@ -813,6 +821,7 @@ public: const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } VMOP *Code; + FString SourceFileName; int *KonstD; double *KonstF; FString *KonstS; diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 9b399ad60..65ec0bb26 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -75,12 +75,38 @@ VMFunctionBuilder::~VMFunctionBuilder() //========================================================================== // -// VMFunctionBuilder :: MakeFunction +// VMFunctionBuilder :: BeginStatement // -// Creates a new VMScriptFunction out of the data passed to this class. +// Records the start of a new statement. // //========================================================================== +void VMFunctionBuilder::BeginStatement(FxExpression *stmt) +{ + // pop empty statement records. + while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop(); + // only add a new entry if the line number differs. + if (LineNumbers.Size() == 0 || stmt->ScriptPosition.ScriptLine != LineNumbers.Last().LineNumber) + { + StatementInfo si = { (uint16_t)Code.Size(), (uint16_t)stmt->ScriptPosition.ScriptLine }; + LineNumbers.Push(si); + } + StatementStack.Push(stmt); +} + +void VMFunctionBuilder::EndStatement() +{ + // pop empty statement records. + while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop(); + StatementStack.Pop(); + // Re-enter the previous statement. + if (StatementStack.Size() > 0) + { + StatementInfo si = { (uint16_t)Code.Size(), (uint16_t)StatementStack.Last()->ScriptPosition.ScriptLine }; + LineNumbers.Push(si); + } +} + void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) { func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size()); @@ -880,7 +906,10 @@ void FFunctionBuildList::Build() // Emit code try { + sfunc->SourceFileName = item.Code->ScriptPosition.FileName; // remember the file name for printing error messages if something goes wrong in the VM. + buildit.BeginStatement(item.Code); item.Code->Emit(&buildit); + buildit.EndStatement(); buildit.MakeFunction(sfunc); sfunc->NumArgs = 0; // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 7434f3a21..d319b2280 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -4,6 +4,7 @@ #include "dobject.h" class VMFunctionBuilder; +class FxExpression; struct ExpEmit { @@ -42,6 +43,8 @@ public: VMFunctionBuilder(int numimplicits); ~VMFunctionBuilder(); + void BeginStatement(FxExpression *stmt); + void EndStatement(); void MakeFunction(VMScriptFunction *func); // Returns the constant register holding the value. @@ -97,6 +100,15 @@ private: VM_ATAG Tag; }; + struct StatementInfo + { + uint16_t InstructionIndex; + uint16_t LineNumber; + }; + + TArray LineNumbers; + TArray StatementStack; + TArray IntConstantList; TArray FloatConstantList; TArray AddressConstantList; diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 183cc728c..198410864 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -82,8 +82,6 @@ #define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) #define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) -#define THROW(x) throw(EVMAbortException(x)) - #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ assert(pc[1].op == OP_JMP); \ @@ -93,7 +91,7 @@ } #define GETADDR(a,o,x) \ - if (a == NULL) { THROW(x); } \ + if (a == NULL) { throw CVMAbortException(x, nullptr); } \ ptr = (VM_SBYTE *)a + o static const VM_UWORD ZapTable[16] = @@ -231,4 +229,55 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) void NullParam(const char *varname) { -} \ No newline at end of file + throw CVMAbortException(X_READ_NIL, "In function parameter %s", varname); +} + +FString CVMAbortException::stacktrace; + +CVMAbortException::CVMAbortException(EVMAbortException reason, const char *moreinfo, ...) +{ + SetMessage("VM execution aborted: "); + switch (reason) + { + case X_READ_NIL: + AppendMessage("tried to read from address zero."); + break; + + case X_WRITE_NIL: + AppendMessage("tried to write to address zero."); + break; + + case X_TOO_MANY_TRIES: + AppendMessage("too many try-catch blocks."); + break; + + case X_ARRAY_OUT_OF_BOUNDS: + AppendMessage("array access out of bounds."); + break; + + case X_DIVISION_BY_ZERO: + AppendMessage("division by zero."); + break; + + case X_BAD_SELF: + AppendMessage("invalid self pointer."); + break; + + default: + { + size_t len = strlen(m_Message); + mysnprintf(m_Message + len, MAX_ERRORTEXT - len, "Unknown reason %d", reason); + break; + } + } + if (moreinfo != nullptr) + { + AppendMessage(" "); + va_list ap; + va_start(ap, moreinfo); + size_t len = strlen(m_Message); + myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap); + va_end(ap); + } +} + diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 8f79bd90b..1e688365d 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -704,7 +704,7 @@ begin: assert(try_depth < MAX_TRY_DEPTH); if (try_depth >= MAX_TRY_DEPTH) { - THROW(X_TOO_MANY_TRIES); + throw CVMAbortException(X_TOO_MANY_TRIES, nullptr); } assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH); exception_frames[try_depth++] = pc + JMPOFS(pc) + 1; @@ -727,7 +727,7 @@ begin: } else { - THROW(BC); + throw CVMAbortException(EVMAbortException(BC), nullptr); } NEXTOP; OP(CATCH): @@ -736,13 +736,10 @@ begin: assert(0); NEXTOP; - // Fixme: This really needs to throw something more informative than a number. Printing the message here instead of passing it to the exception is not sufficient. OP(BOUND): if (reg.d[a] >= BC) { - assert(false); - Printf("Array access out of bounds: Max. index = %u, current index = %u\n", BC, reg.d[a]); - THROW(X_ARRAY_OUT_OF_BOUNDS); + throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); } NEXTOP; @@ -750,9 +747,7 @@ begin: ASSERTKD(BC); if (reg.d[a] >= konstd[BC]) { - assert(false); - Printf("Array access out of bounds: Max. index = %u, current index = %u\n", konstd[BC], reg.d[a]); - THROW(X_ARRAY_OUT_OF_BOUNDS); + throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); } NEXTOP; @@ -760,9 +755,7 @@ begin: ASSERTD(B); if (reg.d[a] >= reg.d[B]) { - assert(false); - Printf("Array access out of bounds: Max. index = %u, current index = %u\n", reg.d[B], reg.d[a]); - THROW(X_ARRAY_OUT_OF_BOUNDS); + throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); } NEXTOP; @@ -909,7 +902,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; @@ -917,7 +910,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; @@ -925,7 +918,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; @@ -934,7 +927,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)reg.d[C]); NEXTOP; @@ -942,7 +935,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)konstd[C]); NEXTOP; @@ -950,7 +943,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] / (unsigned)reg.d[C]); NEXTOP; @@ -959,7 +952,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; @@ -967,7 +960,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; @@ -975,7 +968,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; @@ -984,7 +977,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)reg.d[C]); NEXTOP; @@ -992,7 +985,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)konstd[C]); NEXTOP; @@ -1000,7 +993,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] % (unsigned)reg.d[C]); NEXTOP; @@ -1178,7 +1171,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; @@ -1186,7 +1179,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTKF(C); if (konstf[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; @@ -1194,7 +1187,7 @@ begin: ASSERTF(a); ASSERTKF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -1205,7 +1198,7 @@ begin: Do_MODF: if (fc == 0.) { - THROW(X_DIVISION_BY_ZERO); + throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = luai_nummod(fb, fc); NEXTOP; diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 871a46673..3a7d9b3bf 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -453,7 +453,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } - catch (EVMAbortException exception) + catch (CVMAbortException &exception) { if (allocated) { @@ -464,35 +464,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur *trap = nullptr; } - Printf("VM execution aborted: "); - switch (exception) - { - case X_READ_NIL: - Printf("tried to read from address zero."); - break; - - case X_WRITE_NIL: - Printf("tried to write to address zero."); - break; - - case X_TOO_MANY_TRIES: - Printf("too many try-catch blocks."); - break; - - case X_ARRAY_OUT_OF_BOUNDS: - Printf("array access out of bounds."); - break; - - case X_DIVISION_BY_ZERO: - Printf("division by zero."); - break; - - case X_BAD_SELF: - Printf("invalid self pointer."); - break; - } - Printf("\n"); - + Printf("%s\n", exception.GetMessage()); return -1; } catch (...) From fbf80849995724d5907da4eea2c732f3d68fe8e8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 18:52:58 +0100 Subject: [PATCH 22/35] - corrected the export signatures of several script exports to contain the correct classes, so that the fudging in FindFunction could be removed. - fixed PARAM_ACTION_PROLOGUE to assign correct types to the implicit pointers. It gave the actual class to the wrong one, which until now did not matter because all functions were using 'Actor', regardless of actual class association. - fixed the definition of IceChunk and removed some redundant code here. Since A_FreezeDeathChunks already calls SetState, which in turn calls the state's action function, there is no need to call it again explicitly. --- src/g_shared/a_action.cpp | 32 ----------------------- src/g_shared/a_bridge.cpp | 4 +-- src/g_shared/a_specialspot.cpp | 4 +-- src/p_actionfunctions.cpp | 28 ++++++++++---------- src/p_pspr.cpp | 16 ++++++------ src/scripting/thingdef_data.cpp | 39 ++++++++++------------------ src/scripting/vm/vm.h | 4 +-- wadsrc/static/zscript/shared/ice.txt | 16 ++++++++++-- 8 files changed, 56 insertions(+), 87 deletions(-) diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 2e4597617..187b215b8 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -13,7 +13,6 @@ #include "r_data/r_translate.h" static FRandom pr_freezedeath ("FreezeDeath"); -static FRandom pr_icesettics ("IceSetTics"); static FRandom pr_freeze ("FreezeDeathChunks"); @@ -121,36 +120,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) return 0; } -//============================================================================ -// -// A_IceSetTics -// -//============================================================================ - -void IceSetTics(AActor *self) -{ - - int floor; - - self->tics = 70 + (pr_icesettics() & 63); - floor = P_GetThingFloorType(self); - if (Terrains[floor].DamageMOD == NAME_Fire) - { - self->tics >>= 2; - } - else if (Terrains[floor].DamageMOD == NAME_Ice) - { - self->tics <<= 1; - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) -{ - PARAM_SELF_PROLOGUE(AActor); - IceSetTics(self); - return 0; -} - //============================================================================ // // A_FreezeDeathChunks @@ -193,7 +162,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) mo->Vel.X = pr_freeze.Random2() / 128.; mo->Vel.Y = pr_freeze.Random2() / 128.; mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4; - IceSetTics(mo); // set a random tic wait mo->RenderStyle = self->RenderStyle; mo->Alpha = self->Alpha; } diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 138210061..cb6657796 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -114,7 +114,7 @@ static void BridgeOrbit(AActor *self) self->ceilingz = self->target->ceilingz; } -DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) +DEFINE_ACTION_FUNCTION(ABridgeBall, A_BridgeOrbit) { PARAM_SELF_PROLOGUE(AActor); BridgeOrbit(self); @@ -122,7 +122,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) } -DEFINE_ACTION_FUNCTION(AActor, A_BridgeInit) +DEFINE_ACTION_FUNCTION(ACustomBridge, A_BridgeInit) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF(balltype, AActor); diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index b5debf2df..335f10ace 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -402,9 +402,9 @@ void ASpecialSpot::Destroy() // will build a list of all mace spots in the level and spawn a // mace. The rest of the spots will do nothing. -DEFINE_ACTION_FUNCTION(AActor, A_SpawnSingleItem) +DEFINE_ACTION_FUNCTION(ASpecialSpot, A_SpawnSingleItem) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(ASpecialSpot); PARAM_CLASS_NOT_NULL(cls, AActor); PARAM_INT_DEF (fail_sp) PARAM_INT_DEF (fail_co) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 115bc1f54..83844ffd7 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1773,9 +1773,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomComboAttack) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_JumpIfNoAmmo) +DEFINE_ACTION_FUNCTION(AStateProvider, A_JumpIfNoAmmo) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_STATE_ACTION(jump); if (!ACTION_CALL_FROM_PSPRITE() || self->player->ReadyWeapon == nullptr) @@ -1844,9 +1844,9 @@ static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, b } } -DEFINE_ACTION_FUNCTION(AActor, A_FireBullets) +DEFINE_ACTION_FUNCTION(AStateProvider, A_FireBullets) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_ANGLE (spread_xy); PARAM_ANGLE (spread_z); PARAM_INT (numbullets); @@ -1974,9 +1974,9 @@ enum FP_Flags FPF_TRANSFERTRANSLATION = 2, FPF_NOAUTOAIM = 4, }; -DEFINE_ACTION_FUNCTION(AActor, A_FireCustomMissile) +DEFINE_ACTION_FUNCTION(AStateProvider, A_FireCustomMissile) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_CLASS (ti, AActor); PARAM_ANGLE_DEF (angle); PARAM_BOOL_DEF (useammo); @@ -2051,9 +2051,9 @@ enum CPF_STEALARMOR = 32, }; -DEFINE_ACTION_FUNCTION(AActor, A_CustomPunch) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_INT (damage); PARAM_BOOL_DEF (norandom); PARAM_INT_DEF (flags); @@ -2155,9 +2155,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomPunch) // customizable railgun attack function // //========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_RailAttack) +DEFINE_ACTION_FUNCTION(AStateProvider, A_RailAttack) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_INT (damage); PARAM_INT_DEF (spawnofs_xy); PARAM_BOOL_DEF (useammo); @@ -4443,9 +4443,9 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfInTargetLOS) // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_CheckForReload) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); if ( self->player == NULL || self->player->ReadyWeapon == NULL ) { @@ -4496,9 +4496,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckForReload) // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ResetReloadCounter) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); if (self->player == NULL || self->player->ReadyWeapon == NULL) return 0; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 733741cb2..2bd3696d4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -828,7 +828,7 @@ void DoReadyWeapon(AActor *self) DEFINE_ACTION_FUNCTION(AStateProvider, A_WeaponReady) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_INT_DEF(flags); DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch)); @@ -960,7 +960,7 @@ static void P_CheckWeaponButtons (player_t *player) DEFINE_ACTION_FUNCTION(AStateProvider, A_ReFire) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_STATE_ACTION_DEF(state); A_ReFire(self, state); return 0; @@ -998,7 +998,7 @@ void A_ReFire(AActor *self, FState *state) DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); player_t *player = self->player; if (NULL != player) @@ -1020,7 +1020,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire) DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckReload) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); if (self->player != NULL) { @@ -1208,7 +1208,7 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayID) DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); player_t *player = self->player; DPSprite *psp; @@ -1254,9 +1254,9 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_Raise) +DEFINE_ACTION_FUNCTION(AStateProvider, A_Raise) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); if (self == nullptr) { @@ -1368,7 +1368,7 @@ enum GF_Flags DEFINE_ACTION_FUNCTION(AStateProvider, A_GunFlash) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_STATE_ACTION_DEF(flash); PARAM_INT_DEF(flags); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index b34157b36..18962fbca 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -583,35 +583,24 @@ FPropertyInfo *FindProperty(const char * string) AFuncDesc *FindFunction(PStruct *cls, const char * string) { - for (int i = 0; i < 2; i++) + int min = 0, max = AFTable.Size() - 1; + + while (min <= max) { - // Since many functions have been declared with Actor as owning class, despite being members of something else, let's hack around this until they have been fixed or exported. - // Since most of these are expected to be scriptified anyway, there's no point fixing them all before they get exported. - if (i == 1) + int mid = (min + max) / 2; + int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); + if (lexval == 0) { - if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) break; - cls = RUNTIME_CLASS(AActor); + return &AFTable[mid]; } - - int min = 0, max = AFTable.Size() - 1; - - while (min <= max) + else if (lexval > 0) { - int mid = (min + max) / 2; - int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1); - if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); - if (lexval == 0) - { - return &AFTable[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } + min = mid + 1; + } + else + { + max = mid - 1; } } return nullptr; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 7285fb48d..aeb52dabb 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1140,8 +1140,8 @@ class AActor; // callingstate - State this action was called from #define PARAM_ACTION_PROLOGUE(type) \ PARAM_PROLOGUE; \ - PARAM_OBJECT (self, type); \ - PARAM_OBJECT (stateowner, AActor) \ + PARAM_OBJECT (self, AActor); \ + PARAM_OBJECT (stateowner, type) \ PARAM_POINTER (stateinfo, FStateParamInfo) \ // Number of action paramaters diff --git a/wadsrc/static/zscript/shared/ice.txt b/wadsrc/static/zscript/shared/ice.txt index 534113785..9b72e2455 100644 --- a/wadsrc/static/zscript/shared/ice.txt +++ b/wadsrc/static/zscript/shared/ice.txt @@ -21,12 +21,24 @@ class IceChunk : Actor +NOBLOCKMAP +MOVEWITHSECTOR } - native void A_IceSetTics (); + + void A_IceSetTics () + { + tics = 70 + (random[IceTics]() & 63); + Name dtype = GetFloorTerrain().DamageMOD; + if (dtype == 'Fire') + { + tics >>= 2; + } + else if (dtype == 'Ice') + { + tics <<= 1; + } + } States { Spawn: - ICEC A 1; ICEC ABCD 10 A_IceSetTics; Stop; } From 91c3ddf6920d3f043eff9e724c6b69f593e3ca7c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 19:30:58 +0100 Subject: [PATCH 23/35] - fixed: When a tentative class is being replaced, the old one should be removed entirely so that it cannot cause any problems later. --- src/dobjtype.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c33caf12f..5e1316d71 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3330,11 +3330,15 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) } else { + TypeTable.ReplaceType(type, existclass, bucket); StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. - // Delete the old class from the actor classes list, if it is in there. + // Delete the old class from the class lists, both the full one and the actor list. auto index = PClassActor::AllActorClasses.Find(static_cast(existclass)); if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index); - TypeTable.ReplaceType(type, existclass, bucket); + index = PClass::AllClasses.Find(existclass); + if (index < PClass::AllClasses.Size()) PClass::AllClasses.Delete(index); + // Now we can destroy the old class as nothing should reference it anymore + existclass->Destroy(); } return type; } From 60b1f5c25ab1ef89b1cc17075c5684fae35855e4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 19:37:54 +0100 Subject: [PATCH 24/35] - fixed: FPNGTexture::fr could be left uninitialized. --- src/textures/pngtexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index d34b00607..d24cd92d1 100644 --- a/src/textures/pngtexture.cpp +++ b/src/textures/pngtexture.cpp @@ -211,6 +211,7 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename int i; if (lumpnum == -1) fr = &lump; + else fr = nullptr; UseType = TEX_MiscPatch; LeftOffset = 0; From 87d2991256ffa089159783b31a9c7ab78c229c94 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 20:13:30 +0100 Subject: [PATCH 25/35] - removed all cluster music definitions so that the default from the gameinfo section can be used to change it. --- wadsrc/static/mapinfo/chex.txt | 4 ---- wadsrc/static/mapinfo/doom1.txt | 4 ---- wadsrc/static/mapinfo/doom2.txt | 7 ------- wadsrc/static/mapinfo/heretic.txt | 5 ----- wadsrc/static/mapinfo/hexen.txt | 4 ---- wadsrc/static/mapinfo/plutonia.txt | 6 ------ wadsrc/static/mapinfo/tnt.txt | 6 ------ 7 files changed, 36 deletions(-) diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 00904b134..bf42fcbcd 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -255,28 +255,24 @@ map E1M5 lookup "CHUSTR_E1M5" cluster 1 { flat = "FLOOR4_8" - music = "$MUSIC_VICTOR" exittext = lookup, "CE1TEXT" } cluster 2 { flat = "SFLR6_1" - music = "$MUSIC_VICTOR" exittext = lookup, "CE2TEXT" } cluster 3 { flat = "MFLR8_4" - music = "$MUSIC_VICTOR" exittext = lookup, "CE3TEXT" } cluster 4 { flat = "MFLR8_3" - music = "$MUSIC_VICTOR" exittext = lookup, "CE4TEXT" } diff --git a/wadsrc/static/mapinfo/doom1.txt b/wadsrc/static/mapinfo/doom1.txt index 62040ca15..2baba9a5d 100644 --- a/wadsrc/static/mapinfo/doom1.txt +++ b/wadsrc/static/mapinfo/doom1.txt @@ -506,28 +506,24 @@ map E4M9 lookup "HUSTR_E4M9" cluster 1 { flat = "$bgflatE1" - music = "$MUSIC_VICTOR" exittext = lookup, "E1TEXT" } cluster 2 { flat = "$bgflatE2" - music = "$MUSIC_VICTOR" exittext = lookup, "E2TEXT" } cluster 3 { flat = "$bgflatE3" - music = "$MUSIC_VICTOR" exittext = lookup, "E3TEXT" } cluster 4 { flat = "$bgflatE4" - music = "$MUSIC_VICTOR" exittext = lookup, "E4TEXT" } diff --git a/wadsrc/static/mapinfo/doom2.txt b/wadsrc/static/mapinfo/doom2.txt index 166d2d202..6268f52c9 100644 --- a/wadsrc/static/mapinfo/doom2.txt +++ b/wadsrc/static/mapinfo/doom2.txt @@ -380,7 +380,6 @@ map MAP32 lookup "HUSTR_32" cluster 5 { flat = "$BGFLAT06" - music = "$MUSIC_READ_M" exittext = lookup, "C1TEXT" } @@ -390,7 +389,6 @@ cluster 5 cluster 6 { flat = "$BGFLAT11" - music = "$MUSIC_READ_M" exittext = lookup, "C2TEXT" } @@ -400,7 +398,6 @@ cluster 6 cluster 7 { flat = "$BGFLAT20" - music = "$MUSIC_READ_M" exittext = lookup, "C3TEXT" } @@ -409,7 +406,6 @@ cluster 7 cluster 8 { flat = "$BGFLAT30" - music = "$MUSIC_READ_M" exittext = lookup, "C4TEXT" } @@ -418,7 +414,6 @@ cluster 8 cluster 9 { flat = "$BGFLAT15" - music = "$MUSIC_READ_M" entertext = lookup, "C5TEXT" } @@ -427,7 +422,6 @@ cluster 9 cluster 10 { flat = "$BGFLAT31" - music = "$MUSIC_READ_M" entertext = lookup, "C6TEXT" } @@ -537,7 +531,6 @@ map LEVEL09 lookup "NHUSTR_9" cluster 11 { flat = "SLIME16" - music = "$MUSIC_READ_M" exittext = lookup, "NERVETEXT" } diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index a1e2efb0c..5f822d870 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -805,35 +805,30 @@ map E6M3 "Untitled" cluster 1 { flat = "FLOOR25" - music = "MUS_CPTD" exittext = lookup, "HE1TEXT" } cluster 2 { flat = "FLATHUH1" - music = "MUS_CPTD" exittext = lookup, "HE2TEXT" } cluster 3 { flat = "FLTWAWA2" - music = "MUS_CPTD" exittext = lookup, "HE3TEXT" } cluster 4 { flat = "FLOOR28" - music = "MUS_CPTD" exittext = lookup, "HE4TEXT" } cluster 5 { flat = "FLOOR08" - music = "MUS_CPTD" exittext = lookup, "HE5TEXT" } diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index c2dbf959a..be9a6ef65 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -464,7 +464,6 @@ cluster 1 hub exittext = "clus1msg" exittextislump - music = "hub" pic = "interpic" } @@ -473,7 +472,6 @@ cluster 2 hub exittext = "clus2msg" exittextislump - music = "hub" pic = "interpic" } @@ -482,7 +480,6 @@ cluster 3 hub exittext = "clus3msg" exittextislump - music = "hub" pic = "interpic" } @@ -491,7 +488,6 @@ cluster 4 hub exittext = "clus4msg" exittextislump - music = "hub" pic = "interpic" } diff --git a/wadsrc/static/mapinfo/plutonia.txt b/wadsrc/static/mapinfo/plutonia.txt index 7126c5605..d4fefba86 100644 --- a/wadsrc/static/mapinfo/plutonia.txt +++ b/wadsrc/static/mapinfo/plutonia.txt @@ -374,7 +374,6 @@ map MAP32 lookup "PHUSTR_32" cluster 5 { flat = "$BGFLAT06" - music = "$MUSIC_READ_M" exittext = lookup, "P1TEXT" } @@ -383,7 +382,6 @@ cluster 5 cluster 6 { flat = "$BGFLAT11" - music = "$MUSIC_READ_M" exittext = lookup, "P2TEXT" } @@ -392,7 +390,6 @@ cluster 6 cluster 7 { flat = "$BGFLAT20" - music = "$MUSIC_READ_M" exittext = lookup, "P3TEXT" } @@ -401,7 +398,6 @@ cluster 7 cluster 8 { flat = "$BGFLAT30" - music = "$MUSIC_READ_M" exittext = lookup, "P4TEXT" } @@ -410,7 +406,6 @@ cluster 8 cluster 9 { flat = "$BGFLAT15" - music = "$MUSIC_READ_M" entertext = lookup, "P5TEXT" } @@ -419,7 +414,6 @@ cluster 9 cluster 10 { flat = "$BGFLAT31" - music = "$MUSIC_READ_M" entertext = lookup, "P6TEXT" } diff --git a/wadsrc/static/mapinfo/tnt.txt b/wadsrc/static/mapinfo/tnt.txt index 15f71389d..12768a5c3 100644 --- a/wadsrc/static/mapinfo/tnt.txt +++ b/wadsrc/static/mapinfo/tnt.txt @@ -374,7 +374,6 @@ map MAP32 lookup "THUSTR_32" cluster 5 { flat = "$BGFLAT06" - music = "$MUSIC_READ_M" exittext = lookup, "T1TEXT" } @@ -383,7 +382,6 @@ cluster 5 cluster 6 { flat = "$BGFLAT11" - music = "$MUSIC_READ_M" exittext = lookup, "T2TEXT" } @@ -392,7 +390,6 @@ cluster 6 cluster 7 { flat = "$BGFLAT20" - music = "$MUSIC_READ_M" exittext = lookup, "T3TEXT" } @@ -401,7 +398,6 @@ cluster 7 cluster 8 { flat = "$BGFLAT30" - music = "$MUSIC_READ_M" exittext = lookup, "T4TEXT" } @@ -410,7 +406,6 @@ cluster 8 cluster 9 { flat = "$BGFLAT15" - music = "$MUSIC_READ_M" entertext = lookup, "T5TEXT" } @@ -419,6 +414,5 @@ cluster 9 cluster 10 { flat = "$BGFLAT31" - music = "$MUSIC_READ_M" entertext = lookup, "T6TEXT" } From d93b6e31d6df1e6c9d6baee590f18c536e9ab000 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 22:10:15 +0100 Subject: [PATCH 26/35] - fixed: The ammo and sister weapon type pointers were not properly declared as pointers to the type system. --- src/g_inventory/a_weapons.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index c312f15b3..3b3b765d6 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -66,6 +66,9 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(Ammo1) IMPLEMENT_POINTER(Ammo2) IMPLEMENT_POINTER(SisterWeapon) + IMPLEMENT_POINTER(AmmoType1) + IMPLEMENT_POINTER(AmmoType2) + IMPLEMENT_POINTER(SisterWeaponType) IMPLEMENT_POINTERS_END DEFINE_FIELD(AWeapon, WeaponFlags) From b3783a3850891233906d6f5aab9393cebbcf76ec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 12:23:13 +0100 Subject: [PATCH 27/35] redid the exception mechanism for script-side access violations to be of more use for diagnosing problems. The original implementation just printed a mostly information-free message and then went on as if nothing has happened, making it ridiculously easy to write broken code and release it. Changed it to: * Any VMAbortException will now terminate the game session and go back to the console. * It will also print a VM stack trace with all open functions, including source file and line numbers pointing to the problem spots. For this the relevant information had to be added to the VMScriptFunction class. An interesting effect here was that just throwing the exception object increased the VM's Exec function's stack size from 900 bytes to 70kb, because the compiler allocates a separate local buffer for every single instance of the exception object. The obvious solution was to put this part into a subfunction so that it won't pollute the Exec function's own stack frame. Interesting side effect of this: Exec's stack requirement went down from 900 bytes to 600 bytes. This is still on the high side but already a lot better. --- src/d_main.cpp | 6 ++ src/info.cpp | 31 ++++++-- src/p_actionfunctions.cpp | 14 +++- src/scripting/vm/vm.h | 14 +++- src/scripting/vm/vmbuilder.cpp | 7 +- src/scripting/vm/vmbuilder.h | 8 +- src/scripting/vm/vmexec.cpp | 60 ++------------- src/scripting/vm/vmexec.h | 78 +++++++++++++------- src/scripting/vm/vmframe.cpp | 129 +++++++++++++++++++++++++++++---- 9 files changed, 232 insertions(+), 115 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index dad2b86d9..bffb4136d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1027,6 +1027,12 @@ void D_DoomLoop () } D_ErrorCleanup (); } + catch (CVMAbortException &error) + { + error.MaybePrintMessage(); + Printf("%s", error.stacktrace); + D_ErrorCleanup(); + } } } diff --git a/src/info.cpp b/src/info.cpp index a0117a71f..d3cb4e274 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -89,16 +89,35 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, stateret = NULL; } } - if (stateret == NULL) + try { - GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); + if (stateret == NULL) + { + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); + } + else + { + VMReturn ret; + ret.PointerAt((void **)stateret); + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); + } } - else + catch (CVMAbortException &err) { - VMReturn ret; - ret.PointerAt((void **)stateret); - GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); + err.MaybePrintMessage(); + auto owner = FState::StaticFindStateOwner(this); + int offs = int(this - owner->OwnedStates); + const char *callinfo = ""; + if (info != nullptr && info->mStateType == STATE_Psprite) + { + if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon "; + else callinfo = "overlay "; + } + err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); + throw; + throw; } + ActionCycles.Unclock(); return true; } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 83844ffd7..12645561b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -183,7 +183,19 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) numret = 2; } } - GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + try + { + GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + auto owner = FState::StaticFindStateOwner(state); + int offs = int(state - owner->OwnedStates); + err.stacktrace.AppendFormat("Called from state %s.%d in inventory state chain in %s\n", owner->TypeName.GetChars(), offs, GetClass()->TypeName.GetChars()); + throw; + } + // As long as even one state succeeds, the whole chain succeeds unless aborted below. // A state that wants to jump does not count as "succeeded". if (nextstate == NULL) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index aeb52dabb..1869c410b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -194,7 +194,8 @@ class CVMAbortException : public CDoomError { public: static FString stacktrace; - CVMAbortException(EVMAbortException reason, const char *moreinfo, ...); + CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap); + void MaybePrintMessage(); }; enum EVMOpMode @@ -808,6 +809,12 @@ union FVoidObj void *v; }; +struct FStatementInfo +{ + uint16_t InstructionIndex; + uint16_t LineNumber; +}; + class VMScriptFunction : public VMFunction { DECLARE_CLASS(VMScriptFunction, VMFunction); @@ -815,12 +822,13 @@ public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); size_t PropagateMark(); - void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta); + void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } VMOP *Code; + FStatementInfo *LineInfo; FString SourceFileName; int *KonstD; double *KonstF; @@ -828,6 +836,7 @@ public: FVoidObj *KonstA; int ExtraSpace; int CodeSize; // Size of code in instructions (not bytes) + unsigned LineInfoCount; VM_UBYTE NumRegD; VM_UBYTE NumRegF; VM_UBYTE NumRegS; @@ -843,6 +852,7 @@ public: void InitExtra(void *addr); void DestroyExtra(void *addr); int AllocExtraStack(PType *type); + int PCToLine(const VMOP *pc); }; class VMFrameStack diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 65ec0bb26..3e833af79 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -88,7 +88,7 @@ void VMFunctionBuilder::BeginStatement(FxExpression *stmt) // only add a new entry if the line number differs. if (LineNumbers.Size() == 0 || stmt->ScriptPosition.ScriptLine != LineNumbers.Last().LineNumber) { - StatementInfo si = { (uint16_t)Code.Size(), (uint16_t)stmt->ScriptPosition.ScriptLine }; + FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)stmt->ScriptPosition.ScriptLine }; LineNumbers.Push(si); } StatementStack.Push(stmt); @@ -102,17 +102,18 @@ void VMFunctionBuilder::EndStatement() // Re-enter the previous statement. if (StatementStack.Size() > 0) { - StatementInfo si = { (uint16_t)Code.Size(), (uint16_t)StatementStack.Last()->ScriptPosition.ScriptLine }; + FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)StatementStack.Last()->ScriptPosition.ScriptLine }; LineNumbers.Push(si); } } void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) { - func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size()); + func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size(), LineNumbers.Size()); // Copy code block. memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); + memcpy(func->LineInfo, &LineNumbers[0], LineNumbers.Size() * sizeof(LineNumbers[0])); // Create constant tables. if (IntConstantList.Size() > 0) diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index d319b2280..7c086ac0c 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -100,13 +100,7 @@ private: VM_ATAG Tag; }; - struct StatementInfo - { - uint16_t InstructionIndex; - uint16_t LineNumber; - }; - - TArray LineNumbers; + TArray LineNumbers; TArray StatementStack; TArray IntConstantList; diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 198410864..79d0b7fe6 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -40,6 +40,11 @@ #include "textures/textures.h" #include "math/cmath.h" +// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown. +void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...); +// intentionally implemented in a different source file tp prevent inlining. +void ThrowVMException(VMException *x); + #define IMPLEMENT_VMEXEC #if !defined(COMPGOTO) && defined(__GNUC__) @@ -91,7 +96,7 @@ } #define GETADDR(a,o,x) \ - if (a == NULL) { throw CVMAbortException(x, nullptr); } \ + if (a == NULL) { ThrowAbortException(x, nullptr); } \ ptr = (VM_SBYTE *)a + o static const VM_UWORD ZapTable[16] = @@ -227,57 +232,4 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } } -void NullParam(const char *varname) -{ - throw CVMAbortException(X_READ_NIL, "In function parameter %s", varname); -} - -FString CVMAbortException::stacktrace; - -CVMAbortException::CVMAbortException(EVMAbortException reason, const char *moreinfo, ...) -{ - SetMessage("VM execution aborted: "); - switch (reason) - { - case X_READ_NIL: - AppendMessage("tried to read from address zero."); - break; - - case X_WRITE_NIL: - AppendMessage("tried to write to address zero."); - break; - - case X_TOO_MANY_TRIES: - AppendMessage("too many try-catch blocks."); - break; - - case X_ARRAY_OUT_OF_BOUNDS: - AppendMessage("array access out of bounds."); - break; - - case X_DIVISION_BY_ZERO: - AppendMessage("division by zero."); - break; - - case X_BAD_SELF: - AppendMessage("invalid self pointer."); - break; - - default: - { - size_t len = strlen(m_Message); - mysnprintf(m_Message + len, MAX_ERRORTEXT - len, "Unknown reason %d", reason); - break; - } - } - if (moreinfo != nullptr) - { - AppendMessage(" "); - va_list ap; - va_start(ap, moreinfo); - size_t len = strlen(m_Message); - myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap); - va_end(ap); - } -} diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 1e688365d..4152facc1 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -2,7 +2,6 @@ #error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead. #endif - static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) { #if COMPGOTO @@ -596,7 +595,17 @@ begin: FillReturns(reg, f, returns, pc+1, C); if (call->Native) { - numret = static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); + try + { + numret = static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } } else { @@ -640,7 +649,17 @@ begin: if (call->Native) { - return static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); + try + { + return static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } } else { // FIXME: Not a true tail call @@ -704,7 +723,7 @@ begin: assert(try_depth < MAX_TRY_DEPTH); if (try_depth >= MAX_TRY_DEPTH) { - throw CVMAbortException(X_TOO_MANY_TRIES, nullptr); + ThrowAbortException(X_TOO_MANY_TRIES, nullptr); } assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH); exception_frames[try_depth++] = pc + JMPOFS(pc) + 1; @@ -717,17 +736,17 @@ begin: if (a == 0) { ASSERTA(B); - throw((VMException *)reg.a[B]); + ThrowVMException((VMException *)reg.a[B]); } else if (a == 1) { ASSERTKA(B); assert(konstatag[B] == ATAG_OBJECT); - throw((VMException *)konsta[B].o); + ThrowVMException((VMException *)konsta[B].o); } else { - throw CVMAbortException(EVMAbortException(BC), nullptr); + ThrowAbortException(EVMAbortException(BC), nullptr); } NEXTOP; OP(CATCH): @@ -739,7 +758,7 @@ begin: OP(BOUND): if (reg.d[a] >= BC) { - throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); } NEXTOP; @@ -747,7 +766,7 @@ begin: ASSERTKD(BC); if (reg.d[a] >= konstd[BC]) { - throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); } NEXTOP; @@ -755,7 +774,7 @@ begin: ASSERTD(B); if (reg.d[a] >= reg.d[B]) { - throw CVMAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); } NEXTOP; @@ -902,7 +921,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; @@ -910,7 +929,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; @@ -918,7 +937,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; @@ -927,7 +946,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)reg.d[C]); NEXTOP; @@ -935,7 +954,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)konstd[C]); NEXTOP; @@ -943,7 +962,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] / (unsigned)reg.d[C]); NEXTOP; @@ -952,7 +971,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; @@ -960,7 +979,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; @@ -968,7 +987,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; @@ -977,7 +996,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)reg.d[C]); NEXTOP; @@ -985,7 +1004,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)konstd[C]); NEXTOP; @@ -993,7 +1012,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] % (unsigned)reg.d[C]); NEXTOP; @@ -1171,7 +1190,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); if (reg.f[C] == 0.) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; @@ -1179,7 +1198,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTKF(C); if (konstf[C] == 0.) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; @@ -1187,7 +1206,7 @@ begin: ASSERTF(a); ASSERTKF(B); ASSERTF(C); if (reg.f[C] == 0.) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -1198,7 +1217,7 @@ begin: Do_MODF: if (fc == 0.) { - throw CVMAbortException(X_DIVISION_BY_ZERO, nullptr); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = luai_nummod(fb, fc); NEXTOP; @@ -1611,6 +1630,13 @@ begin: // Nothing caught it. Rethrow and let somebody else deal with it. throw; } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } return 0; } diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 3a7d9b3bf..f9f04e425 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -3,6 +3,7 @@ ** **--------------------------------------------------------------------------- ** Copyright -2016 Randy Heit +** Copyright 2016 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -33,6 +34,7 @@ #include #include "dobject.h" +#include "v_text.h" IMPLEMENT_CLASS(VMException, false, false) IMPLEMENT_CLASS(VMFunction, true, true) @@ -48,11 +50,13 @@ VMScriptFunction::VMScriptFunction(FName name) { Native = false; Name = name; + LineInfo = nullptr; Code = NULL; KonstD = NULL; KonstF = NULL; KonstS = NULL; KonstA = NULL; + LineInfoCount = 0; ExtraSpace = 0; CodeSize = 0; NumRegD = 0; @@ -82,7 +86,7 @@ VMScriptFunction::~VMScriptFunction() } } -void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta) +void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers) { assert(Code == NULL); assert(numops > 0); @@ -90,14 +94,27 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko assert(numkonstf >= 0 && numkonstf <= 65535); assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535); + assert(numlinenumbers >= 0 && numlinenumbers <= 65535); void *mem = M_Malloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + - numkonsta * (sizeof(FVoidObj) + 1)); + numkonsta * (sizeof(FVoidObj) + 1) + + numlinenumbers * sizeof(FStatementInfo)); Code = (VMOP *)mem; mem = (void *)((VMOP *)mem + numops); + if (numlinenumbers > 0) + { + LineInfo = (FStatementInfo*)mem; + LineInfoCount = numlinenumbers; + mem = LineInfo + numlinenumbers; + } + else + { + LineInfo = nullptr; + LineInfoCount = 0; + } if (numkonstd > 0) { KonstD = (int *)mem; @@ -190,6 +207,20 @@ int VMScriptFunction::AllocExtraStack(PType *type) return address; } +int VMScriptFunction::PCToLine(const VMOP *pc) +{ + int PCIndex = int(pc - Code); + if (LineInfoCount == 1) return LineInfo[0].LineNumber; + for (unsigned i = 1; i < LineInfoCount; i++) + { + if (LineInfo[i].InstructionIndex > PCIndex) + { + return LineInfo[i - 1].LineNumber; + } + } + return -1; +} + //=========================================================================== // // VMFrame :: InitRegS @@ -453,20 +484,6 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } - catch (CVMAbortException &exception) - { - if (allocated) - { - PopFrame(); - } - if (trap != nullptr) - { - *trap = nullptr; - } - - Printf("%s\n", exception.GetMessage()); - return -1; - } catch (...) { if (allocated) @@ -476,3 +493,83 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur throw; } } + +// Exception stuff for the VM is intentionally placed there, because having this in vmexec.cpp would subject it to inlining +// which we do not want because it increases the local stack requirements of Exec which are already too high. +FString CVMAbortException::stacktrace; + +CVMAbortException::CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap) +{ + SetMessage("VM execution aborted: "); + switch (reason) + { + case X_READ_NIL: + AppendMessage("tried to read from address zero."); + break; + + case X_WRITE_NIL: + AppendMessage("tried to write to address zero."); + break; + + case X_TOO_MANY_TRIES: + AppendMessage("too many try-catch blocks."); + break; + + case X_ARRAY_OUT_OF_BOUNDS: + AppendMessage("array access out of bounds."); + break; + + case X_DIVISION_BY_ZERO: + AppendMessage("division by zero."); + break; + + case X_BAD_SELF: + AppendMessage("invalid self pointer."); + break; + + default: + { + size_t len = strlen(m_Message); + mysnprintf(m_Message + len, MAX_ERRORTEXT - len, "Unknown reason %d", reason); + break; + } + } + if (moreinfo != nullptr) + { + AppendMessage(" "); + size_t len = strlen(m_Message); + myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap); + } + stacktrace = ""; +} + +// Print this only once on the first catch block. +void CVMAbortException::MaybePrintMessage() +{ + auto m = GetMessage(); + if (m != nullptr) + { + Printf(TEXTCOLOR_RED); + Printf("%s\n", m); + SetMessage(""); + } +} + + +void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...) +{ + va_list ap; + va_start(ap, moreinfo); + throw CVMAbortException(reason, moreinfo, ap); + va_end(ap); +} + +void NullParam(const char *varname) +{ + ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); +} + +void ThrowVMException(VMException *x) +{ + throw x; +} From 136e976b2a99ff56df81f46410c81e8fb74b141a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 12:33:58 +0100 Subject: [PATCH 28/35] - added an error check for duplicate local variable definitions. Note that this only applies if both are in the same block. Just like in C++, it is perfectly legal to have the same variable name in two different nested scopes. --- src/scripting/codegeneration/codegen.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6a0f840a5..c392d97d3 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9975,6 +9975,19 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) if (Init) Init = new FxTypeCast(Init, ValueType, false); SAFE_RESOLVE_OPT(Init, ctx); } + if (Name != NAME_None) + { + for (auto l : ctx.Block->LocalVars) + { + if (l->Name == Name) + { + ScriptPosition.Message(MSG_ERROR, "Local variable %s already defined", Name.GetChars()); + l->ScriptPosition.Message(MSG_ERROR, "Original definition is here "); + delete this; + return nullptr; + } + } + } ctx.Block->LocalVars.Push(this); return this; } From 0da233a6646a3e726cd51878ed958b125ff9c27f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 13:16:09 +0100 Subject: [PATCH 29/35] changed ZScript include mechanism. * It will now use #include, just like most other definition formats and can be mixed with regular definitions. However, due to how the Lemon-generated parser works this will not recursively pull in all files, but store them in a list and process them sequentially. Functionally this shouldn't make a difference, because ZScript is mostly order-independent - the only thing where order is important is native classes, but these are completely internal to zdoom.pk3 where proper order is observed. --- src/namedef.h | 1 + src/scripting/zscript/zcc-parse.lemon | 6 + src/scripting/zscript/zcc_parser.cpp | 61 ++-- src/zstring.h | 67 ++++- wadsrc/static/zscript.txt | 406 +++++++++++++------------- 5 files changed, 297 insertions(+), 244 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index 9cb4e8d23..c3866a0be 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -715,6 +715,7 @@ xx(String) xx(Vector) xx(Map) xx(Array) +xx(Include) xx(Sound) xx(State) xx(Fixed) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 685c401e7..5ba5a204e 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -140,6 +140,7 @@ external_declaration(X) ::= class_definition(A). { X = A; /*X-overwrites-A* external_declaration(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ } external_declaration(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } external_declaration(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } +external_declaration(X) ::= include_def. { X = nullptr; } /* Optional bits. */ opt_semicolon ::= . @@ -156,6 +157,11 @@ opt_expr(X) ::= . opt_expr(X) ::= expr(X). +include_def ::= INCLUDE string_constant(A). +{ + AddInclude(A); +} + /************ Class Definition ************/ /* Can only occur at global scope. */ diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 64ac2c86d..8a1618127 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -44,7 +44,19 @@ #include "zcc_parser.h" #include "zcc_compile.h" +TArray Includes; +TArray IncludeLocs; + static FString ZCCTokenName(int terminal); +void AddInclude(ZCC_ExprConstant *node) +{ + assert(node->Type == TypeString); + if (Includes.Find(*node->StringVal) >= Includes.Size()) + { + Includes.Push(*node->StringVal); + IncludeLocs.Push(*node); + } +} #include "zcc-parse.h" #include "zcc-parse.c" @@ -152,6 +164,7 @@ static void InitTokenMap() TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map); TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array); + TOKENDEF2(TK_Include, ZCC_INCLUDE, NAME_Include); TOKENDEF (TK_Void, ZCC_VOID); TOKENDEF (TK_True, ZCC_TRUE); TOKENDEF (TK_False, ZCC_FALSE); @@ -316,42 +329,24 @@ static void DoParse(int lumpnum) sc.OpenLumpNum(lumpnum); auto saved = sc.SavePos(); - bool parsed = false; - if (sc.GetToken()) - { - if (sc.TokenType == TK_Class || sc.TokenType == TK_Enum || sc.TokenType == TK_Struct || sc.TokenType == TK_Const || sc.TokenType == TK_Native) - { - if (sc.CheckToken(TK_Identifier)) - { - // This looks like an actual definition file and not a file list. - ParseSingleFile(nullptr, lumpnum, parser, state); - parsed = true; - } - } - } - if (!parsed) - { - sc.RestorePos(saved); - // parse all files from this list in one go. - while (sc.GetString()) - { - FixPathSeperator(sc.String); - if (Wads.GetLumpFile(sc.LumpNum) == 0) - { - int includefile = Wads.GetLumpFile(Wads.CheckNumForFullName(sc.String, true)); - if (includefile != 0) - { - I_FatalError("File %s is overriding core lump %s.", - Wads.GetWadFullName(includefile), sc.String); - } - } -#ifndef NDEBUG - if (f) fprintf(f, "Starting parsing %s\n", sc.String); -#endif - ParseSingleFile(sc.String, 0, parser, state); + ParseSingleFile(nullptr, lumpnum, parser, state); + for (unsigned i = 0; i < Includes.Size(); i++) + { + lumpnum = Wads.CheckNumForFullName(Includes[i], true); + if (lumpnum == -1) + { + IncludeLocs[i].Message(MSG_ERROR, "Include script lump %s not found", Includes[i].GetChars()); + } + else + { + ParseSingleFile(nullptr, lumpnum, parser, state); } } + Includes.Clear(); + Includes.ShrinkToFit(); + IncludeLocs.Clear(); + IncludeLocs.ShrinkToFit(); value.Int = -1; value.SourceLoc = sc.GetMessageLine(); diff --git a/src/zstring.h b/src/zstring.h index fba61884f..128197fd5 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -298,17 +298,68 @@ protected: friend struct FStringData; +public: + bool operator == (const FString &other) const + { + return Compare(other) == 0; + } + + bool operator != (const FString &other) const + { + return Compare(other) != 0; + } + + bool operator < (const FString &other) const + { + return Compare(other) < 0; + } + + bool operator > (const FString &other) const + { + return Compare(other) > 0; + } + + bool operator <= (const FString &other) const + { + return Compare(other) <= 0; + } + + bool operator >= (const FString &other) const + { + return Compare(other) >= 0; + } + + bool operator == (const char *) const = delete; + bool operator != (const char *) const = delete; + bool operator < (const char *) const = delete; + bool operator > (const char *) const = delete; + bool operator <= (const char *) const = delete; + bool operator >= (const char *) const = delete; + + bool operator == (FName) const = delete; + bool operator != (FName) const = delete; + bool operator < (FName) const = delete; + bool operator > (FName) const = delete; + bool operator <= (FName) const = delete; + bool operator >= (FName) const = delete; + private: - // Prevent these from being called as current practices are to use Compare. - // Without this FStrings will be accidentally compared against char* ptrs. - bool operator == (const FString &illegal) const; - bool operator != (const FString &illegal) const; - bool operator < (const FString &illegal) const; - bool operator > (const FString &illegal) const; - bool operator <= (const FString &illegal) const; - bool operator >= (const FString &illegal) const; }; +bool operator == (const char *, const FString &) = delete; +bool operator != (const char *, const FString &) = delete; +bool operator < (const char *, const FString &) = delete; +bool operator > (const char *, const FString &) = delete; +bool operator <= (const char *, const FString &) = delete; +bool operator >= (const char *, const FString &) = delete; + +bool operator == (FName, const FString &) = delete; +bool operator != (FName, const FString &) = delete; +bool operator < (FName, const FString &) = delete; +bool operator > (FName, const FString &) = delete; +bool operator <= (FName, const FString &) = delete; +bool operator >= (FName, const FString &) = delete; + class FStringf : public FString { public: diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index a2b89da01..341fdc9fb 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,211 +1,211 @@ -zscript/base.txt -zscript/constants.txt -zscript/actor.txt -zscript/actor_checks.txt +#include "zscript/base.txt" +#include "zscript/constants.txt" +#include "zscript/actor.txt" +#include "zscript/actor_checks.txt" -zscript/shared/inventory.txt -zscript/shared/inv_misc.txt -zscript/shared/weapons.txt -zscript/shared/armor.txt -zscript/shared/powerups.txt -zscript/shared/player.txt -zscript/shared/morph.txt -zscript/shared/botstuff.txt -zscript/shared/sharedmisc.txt -zscript/shared/blood.txt -zscript/shared/debris.txt -zscript/shared/decal.txt -zscript/shared/splashes.txt -zscript/shared/itemeffects.txt -zscript/shared/fountain.txt -zscript/shared/spark.txt -zscript/shared/soundsequence.txt -zscript/shared/soundenvironment.txt -zscript/shared/bridge.txt -zscript/shared/specialspot.txt -zscript/shared/teleport.txt -zscript/shared/camera.txt -zscript/shared/movingcamera.txt -zscript/shared/mapmarker.txt -zscript/shared/waterzone.txt -zscript/shared/skies.txt -zscript/shared/hatetarget.txt -zscript/shared/secrettrigger.txt -zscript/shared/setcolor.txt -zscript/shared/sectoraction.txt -zscript/shared/ice.txt -zscript/shared/dog.txt -zscript/shared/fastprojectile.txt +#include "zscript/shared/inventory.txt" +#include "zscript/shared/inv_misc.txt" +#include "zscript/shared/weapons.txt" +#include "zscript/shared/armor.txt" +#include "zscript/shared/powerups.txt" +#include "zscript/shared/player.txt" +#include "zscript/shared/morph.txt" +#include "zscript/shared/botstuff.txt" +#include "zscript/shared/sharedmisc.txt" +#include "zscript/shared/blood.txt" +#include "zscript/shared/debris.txt" +#include "zscript/shared/decal.txt" +#include "zscript/shared/splashes.txt" +#include "zscript/shared/itemeffects.txt" +#include "zscript/shared/fountain.txt" +#include "zscript/shared/spark.txt" +#include "zscript/shared/soundsequence.txt" +#include "zscript/shared/soundenvironment.txt" +#include "zscript/shared/bridge.txt" +#include "zscript/shared/specialspot.txt" +#include "zscript/shared/teleport.txt" +#include "zscript/shared/camera.txt" +#include "zscript/shared/movingcamera.txt" +#include "zscript/shared/mapmarker.txt" +#include "zscript/shared/waterzone.txt" +#include "zscript/shared/skies.txt" +#include "zscript/shared/hatetarget.txt" +#include "zscript/shared/secrettrigger.txt" +#include "zscript/shared/setcolor.txt" +#include "zscript/shared/sectoraction.txt" +#include "zscript/shared/ice.txt" +#include "zscript/shared/dog.txt" +#include "zscript/shared/fastprojectile.txt" -zscript/doom/doomplayer.txt -zscript/doom/possessed.txt -zscript/doom/doomimp.txt -zscript/doom/demon.txt -zscript/doom/lostsoul.txt -zscript/doom/cacodemon.txt -zscript/doom/bruiser.txt -zscript/doom/revenant.txt -zscript/doom/arachnotron.txt -zscript/doom/fatso.txt -zscript/doom/painelemental.txt -zscript/doom/archvile.txt -zscript/doom/cyberdemon.txt -zscript/doom/spidermaster.txt -zscript/doom/keen.txt -zscript/doom/bossbrain.txt -zscript/doom/weaponfist.txt -zscript/doom/weaponpistol.txt -zscript/doom/weaponshotgun.txt -zscript/doom/weaponssg.txt -zscript/doom/weaponchaingun.txt -zscript/doom/weaponchainsaw.txt -zscript/doom/weaponrlaunch.txt -zscript/doom/weaponplasma.txt -zscript/doom/weaponbfg.txt +#include "zscript/doom/doomplayer.txt" +#include "zscript/doom/possessed.txt" +#include "zscript/doom/doomimp.txt" +#include "zscript/doom/demon.txt" +#include "zscript/doom/lostsoul.txt" +#include "zscript/doom/cacodemon.txt" +#include "zscript/doom/bruiser.txt" +#include "zscript/doom/revenant.txt" +#include "zscript/doom/arachnotron.txt" +#include "zscript/doom/fatso.txt" +#include "zscript/doom/painelemental.txt" +#include "zscript/doom/archvile.txt" +#include "zscript/doom/cyberdemon.txt" +#include "zscript/doom/spidermaster.txt" +#include "zscript/doom/keen.txt" +#include "zscript/doom/bossbrain.txt" +#include "zscript/doom/weaponfist.txt" +#include "zscript/doom/weaponpistol.txt" +#include "zscript/doom/weaponshotgun.txt" +#include "zscript/doom/weaponssg.txt" +#include "zscript/doom/weaponchaingun.txt" +#include "zscript/doom/weaponchainsaw.txt" +#include "zscript/doom/weaponrlaunch.txt" +#include "zscript/doom/weaponplasma.txt" +#include "zscript/doom/weaponbfg.txt" -zscript/doom/deadthings.txt -zscript/doom/doomammo.txt -zscript/doom/doomarmor.txt -zscript/doom/doomartifacts.txt -zscript/doom/doomhealth.txt -zscript/doom/doomkeys.txt -zscript/doom/doommisc.txt -zscript/doom/doomdecorations.txt -zscript/doom/doomweapons.txt -zscript/doom/stealthmonsters.txt -zscript/doom/scriptedmarine.txt +#include "zscript/doom/deadthings.txt" +#include "zscript/doom/doomammo.txt" +#include "zscript/doom/doomarmor.txt" +#include "zscript/doom/doomartifacts.txt" +#include "zscript/doom/doomhealth.txt" +#include "zscript/doom/doomkeys.txt" +#include "zscript/doom/doommisc.txt" +#include "zscript/doom/doomdecorations.txt" +#include "zscript/doom/doomweapons.txt" +#include "zscript/doom/stealthmonsters.txt" +#include "zscript/doom/scriptedmarine.txt" -zscript/raven/artiegg.txt -zscript/raven/artitele.txt -zscript/raven/ravenartifacts.txt -zscript/raven/ravenhealth.txt -zscript/raven/ravenambient.txt -zscript/raven/minotaur.txt +#include "zscript/raven/artiegg.txt" +#include "zscript/raven/artitele.txt" +#include "zscript/raven/ravenartifacts.txt" +#include "zscript/raven/ravenhealth.txt" +#include "zscript/raven/ravenambient.txt" +#include "zscript/raven/minotaur.txt" -zscript/heretic/hereticplayer.txt -zscript/heretic/hereticammo.txt -zscript/heretic/hereticarmor.txt -zscript/heretic/hereticartifacts.txt -zscript/heretic/heretickeys.txt -zscript/heretic/hereticdecorations.txt -zscript/heretic/hereticmisc.txt -zscript/heretic/mummy.txt -zscript/heretic/clink.txt -zscript/heretic/beast.txt -zscript/heretic/snake.txt -zscript/heretic/hereticimp.txt -zscript/heretic/knight.txt -zscript/heretic/wizard.txt -zscript/heretic/ironlich.txt -zscript/heretic/dsparil.txt -zscript/heretic/chicken.txt -zscript/heretic/weaponstaff.txt -zscript/heretic/weaponwand.txt -zscript/heretic/weaponcrossbow.txt -zscript/heretic/weapongauntlets.txt -zscript/heretic/weaponmace.txt -zscript/heretic/weaponblaster.txt -zscript/heretic/weaponskullrod.txt -zscript/heretic/weaponphoenix.txt +#include "zscript/heretic/hereticplayer.txt" +#include "zscript/heretic/hereticammo.txt" +#include "zscript/heretic/hereticarmor.txt" +#include "zscript/heretic/hereticartifacts.txt" +#include "zscript/heretic/heretickeys.txt" +#include "zscript/heretic/hereticdecorations.txt" +#include "zscript/heretic/hereticmisc.txt" +#include "zscript/heretic/mummy.txt" +#include "zscript/heretic/clink.txt" +#include "zscript/heretic/beast.txt" +#include "zscript/heretic/snake.txt" +#include "zscript/heretic/hereticimp.txt" +#include "zscript/heretic/knight.txt" +#include "zscript/heretic/wizard.txt" +#include "zscript/heretic/ironlich.txt" +#include "zscript/heretic/dsparil.txt" +#include "zscript/heretic/chicken.txt" +#include "zscript/heretic/weaponstaff.txt" +#include "zscript/heretic/weaponwand.txt" +#include "zscript/heretic/weaponcrossbow.txt" +#include "zscript/heretic/weapongauntlets.txt" +#include "zscript/heretic/weaponmace.txt" +#include "zscript/heretic/weaponblaster.txt" +#include "zscript/heretic/weaponskullrod.txt" +#include "zscript/heretic/weaponphoenix.txt" -zscript/hexen/baseweapons.txt -zscript/hexen/korax.txt -zscript/hexen/fighterplayer.txt -zscript/hexen/clericplayer.txt -zscript/hexen/mageplayer.txt -zscript/hexen/pig.txt -zscript/hexen/flame.txt -zscript/hexen/flies.txt -zscript/hexen/hexenarmor.txt -zscript/hexen/hexendecorations.txt -zscript/hexen/hexenkeys.txt -zscript/hexen/hexenspecialdecs.txt -zscript/hexen/mana.txt -zscript/hexen/puzzleitems.txt -zscript/hexen/scriptprojectiles.txt -zscript/hexen/speedboots.txt -zscript/hexen/ettin.txt -zscript/hexen/centaur.txt -zscript/hexen/demons.txt -zscript/hexen/firedemon.txt -zscript/hexen/fog.txt -zscript/hexen/summon.txt -zscript/hexen/flechette.txt -zscript/hexen/clericboss.txt -zscript/hexen/fighterboss.txt -zscript/hexen/mageboss.txt -zscript/hexen/bats.txt -zscript/hexen/bishop.txt -zscript/hexen/blastradius.txt -zscript/hexen/boostarmor.txt -zscript/hexen/clericmace.txt -zscript/hexen/clericflame.txt -zscript/hexen/clericholy.txt -zscript/hexen/clericstaff.txt -zscript/hexen/magewand.txt -zscript/hexen/magecone.txt -zscript/hexen/magelightning.txt -zscript/hexen/magestaff.txt -zscript/hexen/fighterfist.txt -zscript/hexen/fighteraxe.txt -zscript/hexen/fighterhammer.txt -zscript/hexen/fighterquietus.txt -zscript/hexen/dragon.txt -zscript/hexen/healingradius.txt -zscript/hexen/teleportother.txt -zscript/hexen/iceguy.txt -zscript/hexen/serpent.txt -zscript/hexen/spike.txt -zscript/hexen/wraith.txt -zscript/hexen/heresiarch.txt +#include "zscript/hexen/baseweapons.txt" +#include "zscript/hexen/korax.txt" +#include "zscript/hexen/fighterplayer.txt" +#include "zscript/hexen/clericplayer.txt" +#include "zscript/hexen/mageplayer.txt" +#include "zscript/hexen/pig.txt" +#include "zscript/hexen/flame.txt" +#include "zscript/hexen/flies.txt" +#include "zscript/hexen/hexenarmor.txt" +#include "zscript/hexen/hexendecorations.txt" +#include "zscript/hexen/hexenkeys.txt" +#include "zscript/hexen/hexenspecialdecs.txt" +#include "zscript/hexen/mana.txt" +#include "zscript/hexen/puzzleitems.txt" +#include "zscript/hexen/scriptprojectiles.txt" +#include "zscript/hexen/speedboots.txt" +#include "zscript/hexen/ettin.txt" +#include "zscript/hexen/centaur.txt" +#include "zscript/hexen/demons.txt" +#include "zscript/hexen/firedemon.txt" +#include "zscript/hexen/fog.txt" +#include "zscript/hexen/summon.txt" +#include "zscript/hexen/flechette.txt" +#include "zscript/hexen/clericboss.txt" +#include "zscript/hexen/fighterboss.txt" +#include "zscript/hexen/mageboss.txt" +#include "zscript/hexen/bats.txt" +#include "zscript/hexen/bishop.txt" +#include "zscript/hexen/blastradius.txt" +#include "zscript/hexen/boostarmor.txt" +#include "zscript/hexen/clericmace.txt" +#include "zscript/hexen/clericflame.txt" +#include "zscript/hexen/clericholy.txt" +#include "zscript/hexen/clericstaff.txt" +#include "zscript/hexen/magewand.txt" +#include "zscript/hexen/magecone.txt" +#include "zscript/hexen/magelightning.txt" +#include "zscript/hexen/magestaff.txt" +#include "zscript/hexen/fighterfist.txt" +#include "zscript/hexen/fighteraxe.txt" +#include "zscript/hexen/fighterhammer.txt" +#include "zscript/hexen/fighterquietus.txt" +#include "zscript/hexen/dragon.txt" +#include "zscript/hexen/healingradius.txt" +#include "zscript/hexen/teleportother.txt" +#include "zscript/hexen/iceguy.txt" +#include "zscript/hexen/serpent.txt" +#include "zscript/hexen/spike.txt" +#include "zscript/hexen/wraith.txt" +#include "zscript/hexen/heresiarch.txt" -zscript/strife/strifehumanoid.txt -zscript/strife/strifeplayer.txt -zscript/strife/strifeweapons.txt -zscript/strife/spectral.txt -zscript/strife/acolyte.txt -zscript/strife/alienspectres.txt -zscript/strife/beggars.txt -zscript/strife/coin.txt -zscript/strife/crusader.txt -zscript/strife/entityboss.txt -zscript/strife/inquisitor.txt -zscript/strife/klaxon.txt -zscript/strife/loremaster.txt -zscript/strife/macil.txt -zscript/strife/merchants.txt -zscript/strife/peasants.txt -zscript/strife/strifebishop.txt -zscript/strife/oracle.txt -zscript/strife/programmer.txt -zscript/strife/questitems.txt -zscript/strife/ratbuddy.txt -zscript/strife/rebels.txt -zscript/strife/reaver.txt -zscript/strife/sentinel.txt -zscript/strife/stalker.txt -zscript/strife/strifeammo.txt -zscript/strife/strifearmor.txt -zscript/strife/strifefunctions.txt -zscript/strife/strifeitems.txt -zscript/strife/strifekeys.txt -zscript/strife/strifestuff.txt -zscript/strife/thingstoblowup.txt -zscript/strife/templar.txt -zscript/strife/zombie.txt -zscript/strife/weapondagger.txt -zscript/strife/weaponcrossbow.txt -zscript/strife/weaponassault.txt -zscript/strife/weaponmissile.txt -zscript/strife/weaponflamer.txt -zscript/strife/weapongrenade.txt -zscript/strife/weaponmauler.txt -zscript/strife/sigil.txt +#include "zscript/strife/strifehumanoid.txt" +#include "zscript/strife/strifeplayer.txt" +#include "zscript/strife/strifeweapons.txt" +#include "zscript/strife/spectral.txt" +#include "zscript/strife/acolyte.txt" +#include "zscript/strife/alienspectres.txt" +#include "zscript/strife/beggars.txt" +#include "zscript/strife/coin.txt" +#include "zscript/strife/crusader.txt" +#include "zscript/strife/entityboss.txt" +#include "zscript/strife/inquisitor.txt" +#include "zscript/strife/klaxon.txt" +#include "zscript/strife/loremaster.txt" +#include "zscript/strife/macil.txt" +#include "zscript/strife/merchants.txt" +#include "zscript/strife/peasants.txt" +#include "zscript/strife/strifebishop.txt" +#include "zscript/strife/oracle.txt" +#include "zscript/strife/programmer.txt" +#include "zscript/strife/questitems.txt" +#include "zscript/strife/ratbuddy.txt" +#include "zscript/strife/rebels.txt" +#include "zscript/strife/reaver.txt" +#include "zscript/strife/sentinel.txt" +#include "zscript/strife/stalker.txt" +#include "zscript/strife/strifeammo.txt" +#include "zscript/strife/strifearmor.txt" +#include "zscript/strife/strifefunctions.txt" +#include "zscript/strife/strifeitems.txt" +#include "zscript/strife/strifekeys.txt" +#include "zscript/strife/strifestuff.txt" +#include "zscript/strife/thingstoblowup.txt" +#include "zscript/strife/templar.txt" +#include "zscript/strife/zombie.txt" +#include "zscript/strife/weapondagger.txt" +#include "zscript/strife/weaponcrossbow.txt" +#include "zscript/strife/weaponassault.txt" +#include "zscript/strife/weaponmissile.txt" +#include "zscript/strife/weaponflamer.txt" +#include "zscript/strife/weapongrenade.txt" +#include "zscript/strife/weaponmauler.txt" +#include "zscript/strife/sigil.txt" -zscript/chex/chexmonsters.txt -zscript/chex/chexkeys.txt -zscript/chex/chexammo.txt -zscript/chex/chexweapons.txt -zscript/chex/chexitems.txt -zscript/chex/chexdecorations.txt -zscript/chex/chexplayer.txt +#include "zscript/chex/chexmonsters.txt" +#include "zscript/chex/chexkeys.txt" +#include "zscript/chex/chexammo.txt" +#include "zscript/chex/chexweapons.txt" +#include "zscript/chex/chexitems.txt" +#include "zscript/chex/chexdecorations.txt" +#include "zscript/chex/chexplayer.txt" From 28604bad62ab89b50d791f6bf2af424f4aee02d6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 14:06:51 +0100 Subject: [PATCH 30/35] - fixed: The polyobject init specials must be cleared after Polyobject initialization is done, because they can block usage of regular lines colinear with the polyobject --- src/po_man.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index c779a8049..05d067e52 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1773,7 +1773,14 @@ void PO_Init (void) } } } - + // clear all polyobj specials so that they do not obstruct using other lines. + for (int i = 0; i < numlines; i++) + { + if (lines[i].special == Polyobj_ExplicitLine || lines[i].special == Polyobj_StartLine) + { + lines[i].special = 0; + } + } } //========================================================================== From 5117b32431f946ea3ce08277dcf80c0a1fe2ad2c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 14:42:06 +0100 Subject: [PATCH 31/35] - fixed: The math for emulating the old slop overflow was not correct and made the affected sectors in void.wad display incorrectly. - set compat_polyobj for void.wad because its polyobjects glitch quite a bit with the normal setting. --- src/p_slopes.cpp | 4 ++-- wadsrc/static/compatibility.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index 66b3d0747..7413922e2 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -178,8 +178,8 @@ void P_SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi, const D if (ib_compatflags & BCOMPATF_SETSLOPEOVERFLOW) { // We have to consider an integer multiplication overflow here. - norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos())); - norm[1] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Sin())); + norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos())) / 65536.; + norm[1] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Sin())) / 65536.; } else { diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index d964cbf75..73a4f5af2 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -27,6 +27,7 @@ setwallyscale 717 front bot 1.090909 setslopeoverflow + polyobj } B2D8DA03489D1C67F60DC87FBC4EA338 // map01 - Massmouth 2 From 30cbce051e08a7ff6b8f7161cee44159e24ad90e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 15:44:46 +0100 Subject: [PATCH 32/35] - fixed: Custom automap colors were not invalidated on restart. - fixed: D_DoomMain has 3 calls to D_DoomLoop but only the main call of these was capable of a clean restart. --- src/am_map.cpp | 5 ++++ src/am_map.h | 1 + src/d_main.cpp | 69 +++++++++++++++++++++++++++----------------------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index d74927b68..70153404a 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -473,6 +473,11 @@ static AMColorset AMMod; static AMColorset AMModOverlay; +void AM_ClearColorsets() +{ + AMModOverlay.defined = false; + AMMod.defined = false; +} //============================================================================= // // diff --git a/src/am_map.h b/src/am_map.h index dadacde55..fd9079c1e 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -27,6 +27,7 @@ class FSerializer; void AM_StaticInit(); +void AM_ClearColorsets(); // reset data for a restart. // Called by main loop. bool AM_Responder (event_t* ev, bool last); diff --git a/src/d_main.cpp b/src/d_main.cpp index dad2b86d9..1f9fcdbca 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2592,44 +2592,48 @@ void D_DoomMain (void) G_DeferedPlayDemo (v); D_DoomLoop (); // never returns } - - v = Args->CheckValue ("-timedemo"); - if (v) + else { - G_TimeDemo (v); - D_DoomLoop (); // never returns - } - - if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon) - { - if (autostart || netgame) + v = Args->CheckValue("-timedemo"); + if (v) { - // Do not do any screenwipes when autostarting a game. - if (!Args->CheckParm("-warpwipe")) - { - NoWipe = TICRATE; - } - CheckWarpTransMap (startmap, true); - if (demorecording) - G_BeginRecording (startmap); - G_InitNew (startmap, false); - if (StoredWarp.IsNotEmpty()) - { - AddCommandString(StoredWarp.LockBuffer()); - StoredWarp = NULL; - } + G_TimeDemo(v); + D_DoomLoop(); // never returns } else { - D_StartTitle (); // start up intro loop + if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon) + { + if (autostart || netgame) + { + // Do not do any screenwipes when autostarting a game. + if (!Args->CheckParm("-warpwipe")) + { + NoWipe = TICRATE; + } + CheckWarpTransMap(startmap, true); + if (demorecording) + G_BeginRecording(startmap); + G_InitNew(startmap, false); + if (StoredWarp.IsNotEmpty()) + { + AddCommandString(StoredWarp.LockBuffer()); + StoredWarp = NULL; + } + } + else + { + D_StartTitle(); // start up intro loop + } + } + else if (demorecording) + { + G_BeginRecording(NULL); + } + + atterm(D_QuitNetGame); // killough } } - else if (demorecording) - { - G_BeginRecording (NULL); - } - - atterm (D_QuitNetGame); // killough } else { @@ -2643,7 +2647,7 @@ void D_DoomMain (void) } D_DoomLoop (); // this only returns if a 'restart' CCMD is given. - +maxberestart: // // Clean up after a restart // @@ -2654,6 +2658,7 @@ void D_DoomMain (void) M_ClearMenus(); // close menu if open F_EndFinale(); // If an intermission is active, end it now + AM_ClearColorsets(); // clean up game state ST_Clear(); From 1fc90b1ba9762aa606ebf857b8621e5035ca7839 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 15:59:02 +0100 Subject: [PATCH 33/35] - fixed: A_Face* should not require the target to be non-null. --- src/p_enemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index beaa1548f..da4e3cc45 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3100,7 +3100,7 @@ void A_FaceTarget(AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_Face) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT_NOT_NULL(faceto, AActor) + PARAM_OBJECT(faceto, AActor) PARAM_ANGLE_DEF(max_turn) PARAM_ANGLE_DEF(max_pitch) PARAM_ANGLE_DEF(ang_offset) From 21e3aba1c7cd9f539ab02160671efb5ae40d8ecc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 16:27:53 +0100 Subject: [PATCH 34/35] - optionally allow passing a script position object to V_GetColor and subfunctions for better error output. Implemented this for all occurences where this info was available. --- src/cmdlib.cpp | 21 +++------------ src/cmdlib.h | 4 +-- src/d_iwad.cpp | 4 +-- src/d_main.cpp | 4 +-- src/decallib.cpp | 8 +++--- src/g_mapinfo.cpp | 4 +-- src/menu/menudef.cpp | 4 +-- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef_properties.cpp | 3 +-- src/teaminfo.cpp | 2 +- src/textures/multipatchtexture.cpp | 2 +- src/v_font.cpp | 6 ++--- src/v_video.cpp | 31 +++++++++++++++-------- src/v_video.h | 8 +++--- 15 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 5799a2342..266ef47be 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -15,6 +15,7 @@ #include "cmdlib.h" #include "i_system.h" #include "v_text.h" +#include "sc_man.h" #include #include @@ -324,7 +325,7 @@ FString ExtractFileBase (const char *path, bool include_extension) // //========================================================================== -int ParseHex (const char *hex) +int ParseHex (const char *hex, FScriptPosition *sc) { const char *str; int num; @@ -342,7 +343,8 @@ int ParseHex (const char *hex) else if (*str >= 'A' && *str <= 'F') num += 10 + *str-'A'; else { - Printf ("Bad hex number: %s\n",hex); + if (!sc) Printf ("Bad hex number: %s\n",hex); + else sc->Message(MSG_WARNING, "Bad hex number: %s", hex); return 0; } str++; @@ -351,21 +353,6 @@ int ParseHex (const char *hex) return num; } -//========================================================================== -// -// ParseNum -// -//========================================================================== - -int ParseNum (const char *str) -{ - if (str[0] == '$') - return ParseHex (str+1); - if (str[0] == '0' && str[1] == 'x') - return ParseHex (str+2); - return atol (str); -} - //========================================================================== // // IsNum diff --git a/src/cmdlib.h b/src/cmdlib.h index b035842cd..6e9fcd622 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -33,8 +33,8 @@ void DefaultExtension (FString &path, const char *extension); FString ExtractFilePath (const char *path); FString ExtractFileBase (const char *path, bool keep_extension=false); -int ParseHex (const char *str); -int ParseNum (const char *str); +struct FScriptPosition; +int ParseHex(const char *str, FScriptPosition *sc = nullptr); bool IsNum (const char *str); // [RH] added char *copystring(const char *s); diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 1fc63e03d..b80cbaf98 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -193,10 +193,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize) { sc.MustGetStringName("="); sc.MustGetString(); - iwad->FgColor = V_GetColor(NULL, sc.String); + iwad->FgColor = V_GetColor(NULL, sc); sc.MustGetStringName(","); sc.MustGetString(); - iwad->BkColor = V_GetColor(NULL, sc.String); + iwad->BkColor = V_GetColor(NULL, sc); } else if (sc.Compare("Load")) { diff --git a/src/d_main.cpp b/src/d_main.cpp index 7cc40cc05..a2cb181f1 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1844,10 +1844,10 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char else if (!nextKey.CompareNoCase("STARTUPCOLORS")) { sc.MustGetString(); - DoomStartupInfo.FgColor = V_GetColor(NULL, sc.String); + DoomStartupInfo.FgColor = V_GetColor(NULL, sc); sc.MustGetStringName(","); sc.MustGetString(); - DoomStartupInfo.BkColor = V_GetColor(NULL, sc.String); + DoomStartupInfo.BkColor = V_GetColor(NULL, sc); } else if (!nextKey.CompareNoCase("STARTUPTYPE")) { diff --git a/src/decallib.cpp b/src/decallib.cpp index 9fe2966eb..5d24e44d5 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -532,7 +532,7 @@ void FDecalLib::ParseDecal (FScanner &sc) sc.MustGetString (); if (!sc.Compare("BloodDefault")) { - newdecal.ShadeColor = V_GetColor (NULL, sc.String); + newdecal.ShadeColor = V_GetColor (NULL, sc); } else { @@ -547,8 +547,8 @@ void FDecalLib::ParseDecal (FScanner &sc) case DECAL_COLORS: DWORD startcolor, endcolor; - sc.MustGetString (); startcolor = V_GetColor (NULL, sc.String); - sc.MustGetString (); endcolor = V_GetColor (NULL, sc.String); + sc.MustGetString (); startcolor = V_GetColor (NULL, sc); + sc.MustGetString (); endcolor = V_GetColor (NULL, sc); newdecal.Translation = GenerateTranslation (startcolor, endcolor)->Index; break; @@ -819,7 +819,7 @@ void FDecalLib::ParseColorchanger (FScanner &sc) else if (sc.Compare ("Color")) { sc.MustGetString (); - goal = V_GetColor (NULL, sc.String); + goal = V_GetColor (NULL, sc); } else { diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index b83905901..5ffb04732 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -860,14 +860,14 @@ DEFINE_MAP_OPTION(fade, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->fadeto = V_GetColor(NULL, parse.sc.String); + info->fadeto = V_GetColor(NULL, parse.sc); } DEFINE_MAP_OPTION(outsidefog, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->outsidefog = V_GetColor(NULL, parse.sc.String); + info->outsidefog = V_GetColor(NULL, parse.sc); } DEFINE_MAP_OPTION(titlepatch, true) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 0fcf4e4d5..d09cb40b6 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -400,10 +400,10 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); - PalEntry c1 = V_GetColor(NULL, sc.String); + PalEntry c1 = V_GetColor(NULL, sc); sc.MustGetStringName(","); sc.MustGetString(); - PalEntry c2 = V_GetColor(NULL, sc.String); + PalEntry c2 = V_GetColor(NULL, sc); if (sc.CheckString(",")) { sc.MustGetNumber(); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c392d97d3..a0491f69d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1256,7 +1256,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) } else { - FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString()), ScriptPosition); + FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString(), &ScriptPosition), ScriptPosition); delete this; return x; } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 442e52884..f53b97006 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -165,7 +165,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c } else { - int c = V_GetColor (NULL, sc.String); + int c = V_GetColor (NULL, sc); // 0 needs to be the default so we have to mark the color. v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 2eb5f6781..ef6309d4b 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2305,8 +2305,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) *pBlendColor = MakeSpecialColormap(65535); return; } - - color = V_GetColor(NULL, name); + color = V_GetColor(NULL, name, &bag.ScriptPosition); } if (PROP_PARM_COUNT > 2) { diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp index bf0ef8a40..38ba56f4c 100644 --- a/src/teaminfo.cpp +++ b/src/teaminfo.cpp @@ -182,7 +182,7 @@ void FTeam::ParseTeamDefinition (FScanner &Scan) case TEAMINFO_PlayerColor: Scan.MustGetString (); - Team.m_iPlayerColor = V_GetColor (NULL, Scan.String); + Team.m_iPlayerColor = V_GetColor (NULL, Scan); break; case TEAMINFO_TextColor: diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index de3dd2f13..e68c4e20f 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1097,7 +1097,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) if (!sc.CheckNumber()) { sc.MustGetString(); - part.Blend = V_GetColor(NULL, sc.String); + part.Blend = V_GetColor(NULL, sc); } else { diff --git a/src/v_font.cpp b/src/v_font.cpp index 0eb28a67c..f024e2d2b 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -2300,19 +2300,19 @@ void V_InitFontColors () else if (sc.Compare ("Flat:")) { sc.MustGetString(); - logcolor = V_GetColor (NULL, sc.String); + logcolor = V_GetColor (NULL, sc); } else { // Get first color - c = V_GetColor (NULL, sc.String); + c = V_GetColor (NULL, sc); tparm.Start[0] = RPART(c); tparm.Start[1] = GPART(c); tparm.Start[2] = BPART(c); // Get second color sc.MustGetString(); - c = V_GetColor (NULL, sc.String); + c = V_GetColor (NULL, sc); tparm.End[0] = RPART(c); tparm.End[1] = GPART(c); tparm.End[2] = BPART(c); diff --git a/src/v_video.cpp b/src/v_video.cpp index 7192c5d03..efe93aa04 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -44,6 +44,7 @@ #include "i_video.h" #include "v_video.h" #include "v_text.h" +#include "sc_man.h" #include "w_wad.h" @@ -437,7 +438,7 @@ void DCanvas::ReleaseScreenshotBuffer() // //========================================================================== -int V_GetColorFromString (const DWORD *palette, const char *cstr) +int V_GetColorFromString (const DWORD *palette, const char *cstr, FScriptPosition *sc) { int c[3], i, p; char val[3]; @@ -456,7 +457,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr) { val[0] = cstr[1 + i*2]; val[1] = cstr[2 + i*2]; - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } else if (len == 4) @@ -465,7 +466,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr) for (i = 0; i < 3; ++i) { val[1] = val[0] = cstr[1 + i]; - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } else @@ -518,7 +519,7 @@ normal: { val[1] = val[0]; } - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } } @@ -538,7 +539,7 @@ normal: // //========================================================================== -FString V_GetColorStringByName (const char *name) +FString V_GetColorStringByName (const char *name, FScriptPosition *sc) { FMemLump rgbNames; char *rgbEnd; @@ -552,7 +553,8 @@ FString V_GetColorStringByName (const char *name) rgblump = Wads.CheckNumForName ("X11R6RGB"); if (rgblump == -1) { - Printf ("X11R6RGB lump not found\n"); + if (!sc) Printf ("X11R6RGB lump not found\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump not found"); return FString(); } @@ -614,7 +616,8 @@ FString V_GetColorStringByName (const char *name) } if (rgb < rgbEnd) { - Printf ("X11R6RGB lump is corrupt\n"); + if (!sc) Printf ("X11R6RGB lump is corrupt\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt"); } return FString(); } @@ -627,22 +630,28 @@ FString V_GetColorStringByName (const char *name) // //========================================================================== -int V_GetColor (const DWORD *palette, const char *str) +int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc) { - FString string = V_GetColorStringByName (str); + FString string = V_GetColorStringByName (str, sc); int res; if (!string.IsEmpty()) { - res = V_GetColorFromString (palette, string); + res = V_GetColorFromString (palette, string, sc); } else { - res = V_GetColorFromString (palette, str); + res = V_GetColorFromString (palette, str, sc); } return res; } +int V_GetColor(const DWORD *palette, FScanner &sc) +{ + FScriptPosition scc = sc; + return V_GetColor(palette, sc.String, &scc); +} + //========================================================================== // // BuildTransTable diff --git a/src/v_video.h b/src/v_video.h index 890ab6d63..971aa6c13 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -497,15 +497,17 @@ void V_Shutdown (); void V_MarkRect (int x, int y, int width, int height); +class FScanner; // Returns the closest color to the one desired. String // should be of the form "rr gg bb". -int V_GetColorFromString (const DWORD *palette, const char *colorstring); +int V_GetColorFromString (const DWORD *palette, const char *colorstring, FScriptPosition *sc = nullptr); // Scans through the X11R6RGB lump for a matching color // and returns a color string suitable for V_GetColorFromString. -FString V_GetColorStringByName (const char *name); +FString V_GetColorStringByName (const char *name, FScriptPosition *sc = nullptr); // Tries to get color by name, then by string -int V_GetColor (const DWORD *palette, const char *str); +int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc = nullptr); +int V_GetColor(const DWORD *palette, FScanner &sc); void V_DrawFrame (int left, int top, int width, int height); // If the view size is not full screen, draws a border around it. From 71bda99c3b7da3f1816e988d59793b9579c79f2d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Dec 2016 18:14:07 +0100 Subject: [PATCH 35/35] - fixed: DECORATE didn't pass all needed arguments to FunctionBuildList.AddFunction. Removed the default parameter values from this function's declaration to prevent it from happening again. --- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef.cpp | 4 ++-- src/scripting/thingdef.h | 2 +- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/vm/vmbuilder.h | 2 +- src/scripting/zscript/zcc_compile.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 1cb0a91af..671481de1 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -343,7 +343,7 @@ endofstate: if (ScriptCode != nullptr) { auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags); - state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); } int count = bag.statedef.AddStates(&state, statestring, scp); if (count < 0) diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index e1d5f9b27..5d2d251a9 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -219,7 +219,7 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam // //========================================================================== -void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate) +void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum) { if (id == nullptr) { @@ -229,7 +229,7 @@ void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, { auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0); - defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate); + defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); } } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index dd8529252..9d41b5265 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -160,7 +160,7 @@ FName CheckCastKludges(FName in); void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, DWORD funcflags, int useflags); PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); -void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate); +void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== // diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index ef6309d4b..9eb050a83 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -664,7 +664,7 @@ DEFINE_PROPERTY(damage, X, Actor) defaults->DamageVal = dmgval; // Only DECORATE can get here with a valid expression. - CreateDamageFunction(bag.Info, defaults, id, true); + CreateDamageFunction(bag.Info, defaults, id, true, bag.Lumpnum); } //========================================================================== diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 7c086ac0c..da099256e 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -149,7 +149,7 @@ class FFunctionBuildList TArray mItems; public: - VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate = -1, int statecnt = 0, int lumpnum = -1); + VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum); void Build(); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6eb675b89..5f7ff836a 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1842,7 +1842,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro if (namenode->Id == NAME_DamageFunction) { auto x = ConvertNode(prop->Values); - CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false); + CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false, Lump); ((AActor *)bag.Info->Defaults)->DamageVal = -1; return; }