diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 11640ec94..52a269873 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3298,6 +3298,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) // see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced. if (this == existclass->ParentClass) { + existclass->ObjectFlags &= OF_Transient; return existclass; } } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 66832c21c..5b03d4a60 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1910,13 +1910,10 @@ void APowerMorph::InitEffect( ) { Super::InitEffect(); - if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) + if (Owner != nullptr && Owner->player != nullptr && PlayerClass != nullptr) { player_t *realplayer = Owner->player; // Remember the identity of the player - PClassActor *morph_flash = PClass::FindActor(MorphFlash); - PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); - PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass (PlayerClass)); - if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash)) + if (P_MorphPlayer(realplayer, realplayer, PlayerClass, -1/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) @@ -1960,7 +1957,7 @@ void APowerMorph::EndEffect( ) } // Unmorph if possible - if (!bNoCallUndoMorph) + if (!bInUndoMorph) { int savedMorphTics = Player->morphTics; P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS)); diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 163094d32..bd7e86323 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -280,13 +280,14 @@ class APowerMorph : public APowerup public: virtual void Serialize(FSerializer &arc); - void SetNoCallUndoMorph() { bNoCallUndoMorph = true; } + void SetNoCallUndoMorph() { bInUndoMorph = true; } // Variables - FNameNoInit PlayerClass, MorphFlash, UnMorphFlash; + PClassPlayerPawn *PlayerClass; + PClassActor *MorphFlash, *UnMorphFlash; int MorphStyle; player_t *Player; - bool bNoCallUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively + bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: void InitEffect (); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 506f18b2f..49ea525bb 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -620,17 +620,13 @@ IMPLEMENT_CLASS(AMorphProjectile, false, false, false, false) int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { - PClassActor *morph_flash = PClass::FindActor(MorphFlash); - PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); if (target->player) { - PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass(PlayerClass)); - P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } else { - PClassActor *monster_class = PClass::FindActor(MonsterClass); - P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } return -1; } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 65f9d90b6..6911c6688 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -192,7 +192,8 @@ public: void Serialize(FSerializer &arc); - FNameNoInit PlayerClass, MonsterClass, MorphFlash, UnMorphFlash; + PClassPlayerPawn *PlayerClass; + PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash; int Duration, MorphStyle; }; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 9dcf3a16f..d6c53dd8d 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -68,6 +68,7 @@ // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); +TArray OptionalClassPtrs; // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; @@ -390,8 +391,21 @@ void LoadActors () { if (ti->Size == TentativeClass) { - Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; + if (ti->ObjectFlags & OF_Transient) + { + 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; + } + } + else + { + Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } continue; } @@ -431,4 +445,6 @@ void LoadActors () QuestItemClasses[i] = PClass::FindActor(fmt); } StateSourceLines.Clear(); + OptionalClassPtrs.Clear(); + OptionalClassPtrs.ShrinkToFit(); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 7faab937b..8968dc1d6 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -71,13 +71,14 @@ #include "r_data/colormaps.h" #include "vmbuilder.h" +extern TArray OptionalClassPtrs; //========================================================================== // // Gets a class pointer and performs an error check for correct type // //========================================================================== -static PClassActor *FindClassTentative(const char *name, PClass *ancestor) +static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool optional = false) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -91,23 +92,27 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor) { I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars()); } + if (cls->Size == TentativeClass && optional) + { + cls->ObjectFlags |= OF_Transient; // since this flag has no meaning in class types, let's use it for marking the type optional. + } return static_cast(cls); } -static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name) +static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional)); } -static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name) +static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon), optional)); } -static APowerup::MetaClass *FindClassTentativePowerup(const char *name) +static APowerup::MetaClass *FindClassTentativePowerup(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup), optional)); } -static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name) +static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn), optional)); } //========================================================================== @@ -2984,21 +2989,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MonsterClass = FName(str); + defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MonsterClass); } //========================================================================== @@ -3020,12 +3027,13 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== @@ -3034,16 +3042,18 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== @@ -3056,21 +3066,23 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); }