diff --git a/src/am_map.cpp b/src/am_map.cpp index 99fda3bd63..8fb46ed6b9 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 dadacde553..fd9079c1e3 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/cmdlib.cpp b/src/cmdlib.cpp index 5799a23423..266ef47beb 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 b035842cdf..6e9fcd622f 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_dehacked.cpp b/src/d_dehacked.cpp index 6f9687aeac..ed2310d459 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/d_iwad.cpp b/src/d_iwad.cpp index 1fc63e03d3..b80cbaf988 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 dad2b86d95..a2cb181f18 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(); + } } } @@ -1838,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")) { @@ -2592,44 +2598,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 +2653,7 @@ void D_DoomMain (void) } D_DoomLoop (); // this only returns if a 'restart' CCMD is given. - +maxberestart: // // Clean up after a restart // @@ -2654,6 +2664,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(); diff --git a/src/d_player.h b/src/d_player.h index 4cdfb8b793..81a1c43a69 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/decallib.cpp b/src/decallib.cpp index 9fe2966eb4..5d24e44d51 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/dobject.cpp b/src/dobject.cpp index b05ae69acf..6b973de336 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 7d27133dc3..ed9c0fffa9 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 dba5544982..5e1316d71b 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,15 +3330,15 @@ 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); - } TypeTable.ReplaceType(type, existclass, bucket); + StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. + // 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); + 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; } diff --git a/src/doomerrors.h b/src/doomerrors.h index f4b0c9566e..c389c6b052 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/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 6b0059981e..7cd599b11d 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 0b2f27680e..28330e9e98 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 b852607b3c..81b2ce21ec 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 50829e0008..f0409a3f0b 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; diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index a75b9ecd44..4afe74f1f0 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 7e9956d73b..bb821b5d63 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 91b88a0537..bdd1b6dc66 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) @@ -254,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)); } @@ -422,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)); } @@ -1409,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)); } @@ -1427,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)); } @@ -1606,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_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 99dad87131..32914e3e52 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 e1a7fe33bb..2fe14ae91d 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 e0db150077..a8c6a2e76d 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 19a30dcd89..3b3b765d6d 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) @@ -148,24 +151,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 c6424075d3..1b12584012 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_mapinfo.cpp b/src/g_mapinfo.cpp index b839059014..5ffb04732b 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/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 2e4597617f..187b215b8f 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 138210061e..cb66577967 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_morph.cpp b/src/g_shared/a_morph.cpp index f223188396..136c096a31 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)); @@ -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 0087690f71..001df5488e 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/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 026185d07a..335f10aced 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]; @@ -401,10 +402,10 @@ 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_CLASS (cls, AActor); + PARAM_SELF_PROLOGUE(ASpecialSpot); + 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/info.cpp b/src/info.cpp index b8bf3acde9..d3cb4e2743 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; } @@ -619,19 +638,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 bb21524a52..54aac3e3c4 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/menu/menudef.cpp b/src/menu/menudef.cpp index 0fcf4e4d5a..d09cb40b6e 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/namedef.h b/src/namedef.h index 9cb4e8d231..c3866a0be8 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/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 477ed37f24..12645561bb 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) @@ -247,7 +259,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); } @@ -1773,9 +1785,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 +1856,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 +1986,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 +2063,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 +2167,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 +4455,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 +4508,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_ceiling.cpp b/src/p_ceiling.cpp index 932b4c6493..4da81db46d 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 751f92a30e..da4e3cc45a 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; @@ -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 8fd5ad038c..4b1f243d5b 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 e6729096cf..9aa178e64d 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 11036d1716..f25c336126 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 aa29a1c5e7..31b4125988 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 f1f33425a9..88653fca9a 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 () @@ -749,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; } @@ -817,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)); } @@ -852,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; } @@ -1007,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)); } @@ -1040,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)); } @@ -1261,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); @@ -1484,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; } @@ -1998,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)); } @@ -4667,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); @@ -5654,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; @@ -6161,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); @@ -6381,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; } @@ -6413,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) @@ -6528,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); @@ -6566,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)); @@ -6584,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; } @@ -6593,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; @@ -6624,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)); } @@ -6641,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; @@ -6687,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; @@ -6721,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)); } /* @@ -6751,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; @@ -6758,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)) { @@ -6908,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)); } @@ -6980,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)); } @@ -7017,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)); } @@ -7056,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)); @@ -7578,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)); } @@ -7618,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) @@ -7690,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); } @@ -7715,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)); } @@ -7743,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)); } @@ -7911,5 +7921,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); } } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 610ade35a2..2bd3696d42 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); @@ -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 319d5b3ecc..21aa1bbe3d 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_slopes.cpp b/src/p_slopes.cpp index 66b3d07476..7413922e25 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/src/p_states.cpp b/src/p_states.cpp index 7daaa5e41c..87a1bae2fe 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/p_things.cpp b/src/p_things.cpp index ea01d38ed1..6aac786f07 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -608,6 +608,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); } diff --git a/src/p_user.cpp b/src/p_user.cpp index 74b07e0ca2..b808dd9c3d 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/po_man.cpp b/src/po_man.cpp index fafa227eee..15c8d5a52c 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1775,7 +1775,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; + } + } } //========================================================================== diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 254caed625..ccfb01ac52 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 28b20e289b..a0491f69d8 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -288,6 +288,60 @@ 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(); +} + + +//========================================================================== +// +// +// +//========================================================================== + +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); +} + //========================================================================== // // @@ -584,7 +638,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); @@ -757,26 +811,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 @@ -791,6 +826,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) { @@ -1210,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; } @@ -1788,10 +1834,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; } @@ -1889,6 +1936,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) { @@ -2261,14 +2319,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 { @@ -2280,7 +2353,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; } @@ -3141,7 +3215,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); @@ -3171,11 +3245,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 @@ -3214,16 +3292,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)); +} + //========================================================================== // // @@ -3421,7 +3515,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); @@ -3435,13 +3529,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; @@ -3474,14 +3572,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)); +} + //========================================================================== // // @@ -4078,23 +4191,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; @@ -4464,21 +4573,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); @@ -4518,7 +4623,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()); @@ -4591,7 +4696,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"); @@ -5590,8 +5701,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) { @@ -8424,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(); } @@ -8722,7 +8830,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) break; default: - line->Emit(build); + line->EmitStatement(build); break; } } @@ -8876,68 +8984,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->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->EmitStatement(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(); } @@ -9045,35 +9113,27 @@ 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) { - ExpEmit code = Code->Emit(build); - code.Free(build); + Code->EmitStatement(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(); } @@ -9142,25 +9202,23 @@ 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. 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(); @@ -9234,7 +9292,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) @@ -9247,17 +9305,14 @@ 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) { - ExpEmit code = Code->Emit(build); - code.Free(build); + Code->EmitStatement(build); } // Iteration statement. @@ -9271,10 +9326,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(); @@ -9655,7 +9707,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) @@ -9923,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; } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c54c8dc62a..49999206d4 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -328,6 +328,8 @@ 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; PType *ValueType = nullptr; @@ -565,6 +567,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 +737,7 @@ public: ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; //========================================================================== @@ -934,7 +938,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 +955,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/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 442e52884f..f53b970067 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/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 1cb0a91afd..671481de13 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 77120c9477..5d2d251a9f 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]; @@ -220,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) { @@ -230,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); } } @@ -365,7 +364,7 @@ static void CheckStates(PClassActor *obj) void ParseScripts(); void ParseAllDecorate(); -void LoadActors () +void LoadActors() { cycle_t timer; @@ -387,8 +386,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) @@ -396,10 +396,7 @@ 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 { @@ -418,7 +415,7 @@ void LoadActors () CheckStates(ti); - + if (ti->bDecorateClass && ti->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) { // either a DECORATE based weapon or CustomInventory. @@ -427,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) { @@ -445,6 +442,4 @@ void LoadActors () QuestItemClasses[i] = PClass::FindActor(fmt); } StateSourceLines.Clear(); - OptionalClassPtrs.Clear(); - OptionalClassPtrs.ShrinkToFit(); } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index dd8529252f..9d41b5265b 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_data.cpp b/src/scripting/thingdef_data.cpp index b34157b36a..18962fbca0 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/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 9bff91a805..9eb050a83e 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 @@ -666,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); } //========================================================================== @@ -2307,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) { @@ -2998,7 +2995,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 +3004,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 +3031,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 +3040,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 +3049,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 +3067,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 +3076,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); } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 9bd0a4bc9a..1869c410b3 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 @@ -130,6 +131,11 @@ enum CAST_V32S, CAST_SID2S, CAST_TID2S, + + CASTB_I, + CASTB_F, + CASTB_A, + CASTB_S }; // Register types for VMParam @@ -184,6 +190,14 @@ enum EVMAbortException X_BAD_SELF, }; +class CVMAbortException : public CDoomError +{ +public: + static FString stacktrace; + CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap); + void MaybePrintMessage(); +}; + enum EVMOpMode { MODE_ASHIFT = 0, @@ -795,6 +809,12 @@ union FVoidObj void *v; }; +struct FStatementInfo +{ + uint16_t InstructionIndex; + uint16_t LineNumber; +}; + class VMScriptFunction : public VMFunction { DECLARE_CLASS(VMScriptFunction, VMFunction); @@ -802,18 +822,21 @@ 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; FString *KonstS; FVoidObj *KonstA; int ExtraSpace; int CodeSize; // Size of code in instructions (not bytes) + unsigned LineInfoCount; VM_UBYTE NumRegD; VM_UBYTE NumRegF; VM_UBYTE NumRegS; @@ -829,6 +852,7 @@ public: void InitExtra(void *addr); void DestroyExtra(void *addr); int AllocExtraStack(PType *type); + int PCToLine(const VMOP *pc); }; class VMFrameStack @@ -946,6 +970,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; @@ -961,6 +988,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) @@ -983,6 +1013,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; @@ -1000,6 +1031,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) @@ -1014,6 +1048,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)*/ @@ -1115,8 +1150,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/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index f358fce7b6..3e833af79c 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -75,18 +75,45 @@ 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) + { + FStatementInfo 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) + { + 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) @@ -734,6 +761,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 +782,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 @@ -867,7 +907,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 d533935183..da099256ed 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. @@ -69,6 +72,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); @@ -95,6 +100,9 @@ private: VM_ATAG Tag; }; + TArray LineNumbers; + TArray StatementStack; + TArray IntConstantList; TArray FloatConstantList; TArray AddressConstantList; @@ -141,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/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 2158139abb..d21e38d207 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.cpp b/src/scripting/vm/vmexec.cpp index f51038f365..79d0b7fe6b 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__) @@ -82,8 +87,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 +96,7 @@ } #define GETADDR(a,o,x) \ - if (a == NULL) { THROW(x); } \ + if (a == NULL) { ThrowAbortException(x, nullptr); } \ ptr = (VM_SBYTE *)a + o static const VM_UWORD ZapTable[16] = @@ -228,3 +231,5 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } } } + + diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 225c73cabd..4152facc18 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 @@ -419,12 +418,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 +431,29 @@ begin: } NEXTOP; + OP(CASTB): + if (C == CASTB_I) + { + ASSERTD(a); ASSERTD(B); + reg.d[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) @@ -573,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 { @@ -617,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 @@ -681,7 +723,7 @@ begin: assert(try_depth < MAX_TRY_DEPTH); if (try_depth >= MAX_TRY_DEPTH) { - THROW(X_TOO_MANY_TRIES); + ThrowAbortException(X_TOO_MANY_TRIES, nullptr); } assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH); exception_frames[try_depth++] = pc + JMPOFS(pc) + 1; @@ -694,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(BC); + ThrowAbortException(EVMAbortException(BC), nullptr); } NEXTOP; OP(CATCH): @@ -713,13 +755,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); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); } NEXTOP; @@ -727,9 +766,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); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); } NEXTOP; @@ -737,9 +774,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); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); } NEXTOP; @@ -886,7 +921,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; @@ -894,7 +929,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; @@ -902,7 +937,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; @@ -911,7 +946,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)reg.d[C]); NEXTOP; @@ -919,7 +954,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] / (unsigned)konstd[C]); NEXTOP; @@ -927,7 +962,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] / (unsigned)reg.d[C]); NEXTOP; @@ -936,7 +971,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; @@ -944,7 +979,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; @@ -952,7 +987,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; @@ -961,7 +996,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)reg.d[C]); NEXTOP; @@ -969,7 +1004,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)reg.d[B] % (unsigned)konstd[C]); NEXTOP; @@ -977,7 +1012,7 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = int((unsigned)konstd[B] % (unsigned)reg.d[C]); NEXTOP; @@ -1155,7 +1190,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; @@ -1163,7 +1198,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTKF(C); if (konstf[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; @@ -1171,7 +1206,7 @@ begin: ASSERTF(a); ASSERTKF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -1182,7 +1217,7 @@ begin: Do_MODF: if (fc == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = luai_nummod(fb, fc); NEXTOP; @@ -1595,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; } @@ -1827,12 +1869,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 d3ce5d5f97..f9f04e4258 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 @@ -422,7 +453,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 { @@ -453,48 +484,6 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } - catch (EVMAbortException exception) - { - if (allocated) - { - PopFrame(); - } - if (trap != nullptr) - { - *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"); - - return -1; - } catch (...) { if (allocated) @@ -504,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; +} diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index e5b6d34ebb..826bdb4e3e 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++ diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 685c401e78..5ba5a204ea 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_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6eb675b891..5f7ff836ad 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; } diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 64ac2c86d2..8a16181273 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/teaminfo.cpp b/src/teaminfo.cpp index bf0ef8a40b..38ba56f4cd 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 653d2a7988..c0bd6807a2 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1098,7 +1098,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/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index d34b006079..d24cd92d11 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; diff --git a/src/v_font.cpp b/src/v_font.cpp index 0eb28a67c3..f024e2d2ba 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 7192c5d033..efe93aa04a 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 890ab6d638..971aa6c13d 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. diff --git a/src/zstring.h b/src/zstring.h index fba61884f5..128197fd5e 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/compatibility.txt b/wadsrc/static/compatibility.txt index d8bfefc1b7..d88230f729 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 diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 00904b1341..bf42fcbcd7 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 62040ca15f..2baba9a5d9 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 166d2d202d..6268f52c93 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 a1e2efb0cd..5f822d870e 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 c2dbf959a6..be9a6ef652 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 7126c56059..d4fefba860 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 15f71389d1..12768a5c36 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" } diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 4d24314d51..f12e554bba 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,212 +1,212 @@ -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 -zscript/shared/dynlights.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" +#include "zscript/shared/dynlights.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" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index bd00ffc98f..ee4c92adde 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/constants.txt b/wadsrc/static/zscript/constants.txt index 2ccfb70481..c199258997 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 }; diff --git a/wadsrc/static/zscript/heretic/weaponwand.txt b/wadsrc/static/zscript/heretic/weaponwand.txt index bd1475adb6..9516aa76c1 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) { diff --git a/wadsrc/static/zscript/hexen/heresiarch.txt b/wadsrc/static/zscript/hexen/heresiarch.txt index 9cfdde19d5..db4860c349 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); } //============================================================================ diff --git a/wadsrc/static/zscript/raven/ravenambient.txt b/wadsrc/static/zscript/raven/ravenambient.txt index 3495dc4e04..e0cff04d32 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; } } diff --git a/wadsrc/static/zscript/shared/ice.txt b/wadsrc/static/zscript/shared/ice.txt index 5341137855..9b72e2455d 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; } diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt index 20bee61d01..37918aa964 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 (); }