mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 08:31:45 +00:00
- fixed: The morph actors stored their required classes as names, not as class pointers.
This prevented any kind of error check on them. Unfortunately, due to backwards compatibility needs, on DECORATE the missing class may not be fatal so a workaround had to be added to clear those bogus pointers later if they are discovered to be broken. For ZScript, though, this will result in a compile error, which was the intention behind this change.
This commit is contained in:
parent
5e67cf79d3
commit
7527141ad4
7 changed files with 64 additions and 40 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PClassPlayerPawn>(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));
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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<PClassPlayerPawn>(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;
|
||||
}
|
||||
|
|
|
@ -192,7 +192,8 @@ public:
|
|||
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
FNameNoInit PlayerClass, MonsterClass, MorphFlash, UnMorphFlash;
|
||||
PClassPlayerPawn *PlayerClass;
|
||||
PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash;
|
||||
int Duration, MorphStyle;
|
||||
};
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
void InitThingdef();
|
||||
TArray<PClassActor **> OptionalClassPtrs;
|
||||
|
||||
// STATIC FUNCTION PROTOTYPES --------------------------------------------
|
||||
PClassActor *QuestItemClasses[31];
|
||||
|
@ -389,9 +390,22 @@ void LoadActors ()
|
|||
for (auto ti : PClassActor::AllActorClasses)
|
||||
{
|
||||
if (ti->Size == TentativeClass)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -71,13 +71,14 @@
|
|||
#include "r_data/colormaps.h"
|
||||
#include "vmbuilder.h"
|
||||
|
||||
extern TArray<PClassActor **> 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<PClassActor *>(cls);
|
||||
}
|
||||
static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name)
|
||||
static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
|
||||
{
|
||||
return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo)));
|
||||
return static_cast<AAmmo::MetaClass *>(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<AWeapon::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AWeapon)));
|
||||
return static_cast<AWeapon::MetaClass *>(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<APowerup::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APowerup)));
|
||||
return static_cast<APowerup::MetaClass *>(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<APlayerPawn::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn)));
|
||||
return static_cast<APlayerPawn::MetaClass *>(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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue