From 5261acce1d519bf6a1d9b0bd080e6e1b1494e37d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Feb 2016 17:55:43 +0100 Subject: [PATCH 1/5] - undid incorrect part of CheckClass fix. --- src/thingdef/thingdef_expression.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b86c690f5..0038bc337 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -52,6 +52,7 @@ #include "thingdef_exp.h" #include "m_fixed.h" #include "vmbuilder.h" +#include "v_text.h" ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) @@ -3546,15 +3547,25 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (clsname != NAME_None) { - // for backwards compatibility with old times it cannot be made a fatal error, if the class is not defined. :( - cls = desttype->FindClassTentative(clsname, false); - if (!cls->IsDescendantOf(desttype)) + cls = PClass::FindClass(clsname); + if (cls == NULL) { - ScriptPosition.Message(MSG_ERROR,"class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - delete this; - return NULL; + /* lax */ + // Since this happens in released WADs it must pass without a terminal error... :( + ScriptPosition.Message(MSG_WARNING, + "Unknown class name '%s'", + clsname.GetChars(), desttype->TypeName.GetChars()); } - ScriptPosition.Message(MSG_DEBUG,"resolving '%s' as class name", clsname.GetChars()); + else + { + if (!cls->IsDescendantOf(desttype)) + { + ScriptPosition.Message(MSG_ERROR, "class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); + delete this; + return NULL; + } + } + ScriptPosition.Message(MSG_DEBUG, "resolving '%s' as class name", clsname.GetChars()); } FxExpression *x = new FxConstant(cls, ScriptPosition); delete this; From ff70cf1ee766d6c4c36090708bb0edcb563de3cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Feb 2016 19:02:44 +0100 Subject: [PATCH 2/5] - fixed: Resolving non-constant DECORATE expressions must be delayed until everything has been parsed. If done as before, forward-declared classes cannot be found, and the immediate resolving is only needed for constant expressions, so explicitly enabling it in the 4 places where it is needed ensures that those unresolvable expressions remain intact until the final processing pass righr before the code generator is started. --- src/thingdef/thingdef_exp.cpp | 9 ++++++--- src/thingdef/thingdef_exp.h | 2 +- src/thingdef/thingdef_expression.cpp | 2 +- src/thingdef/thingdef_parse.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index e198ec20b..e8a043d31 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -72,12 +72,15 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls); -FxExpression *ParseExpression (FScanner &sc, PClassActor *cls) +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve) { FxExpression *data = ParseExpressionM (sc, cls); - FCompileContext ctx(cls); - data = data->Resolve(ctx); + if (mustresolve) + { + FCompileContext ctx(cls); + data = data->Resolve(ctx); + } return data; } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 6dd11a681..f81dd2b54 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -984,7 +984,7 @@ public: }; -FxExpression *ParseExpression (FScanner &sc, PClassActor *cls); +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve = false); #endif diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 0038bc337..8b2c52405 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3564,8 +3564,8 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) delete this; return NULL; } + ScriptPosition.Message(MSG_DEBUG, "resolving '%s' as class name", clsname.GetChars()); } - ScriptPosition.Message(MSG_DEBUG, "resolving '%s' as class name", clsname.GetChars()); } FxExpression *x = new FxConstant(cls, ScriptPosition); delete this; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 1db878bfa..cf76fb10b 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -79,7 +79,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c } else if (type == TypeSInt32 || type == TypeFloat64) { - x = ParseExpression (sc, cls); + x = ParseExpression (sc, cls, constant); if (constant && !x->isConstant()) { sc.ScriptMessage("Default parameter must be constant."); @@ -190,7 +190,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) sc.MustGetToken(TK_Identifier); FName symname = sc.String; sc.MustGetToken('='); - FxExpression *expr = ParseExpression (sc, cls); + FxExpression *expr = ParseExpression (sc, cls, true); sc.MustGetToken(';'); if (!expr->isConstant()) @@ -248,7 +248,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FName symname = sc.String; if (sc.CheckToken('=')) { - FxExpression *expr = ParseExpression (sc, cls); + FxExpression *expr = ParseExpression (sc, cls, true); if (!expr->isConstant()) { sc.ScriptMessage("'%s' must be constant", symname.GetChars()); @@ -536,7 +536,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { - FxExpression *expr = ParseExpression(sc, cls); + FxExpression *expr = ParseExpression(sc, cls, true); if (!expr->isConstant()) { sc.ScriptMessage("Array size must be a constant"); From b484cbf18ab36a3303d8ed7302411367cbfe3f50 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Feb 2016 23:08:51 +0100 Subject: [PATCH 3/5] - fixed: It is not guaranteed that the class object that is created by FindClassTentative actually matches the real object that is required later, so it needs to be replaced wherever it could be referenced once the real object is created. - removed some unneeded code from earlier attempts to fix the class type resolving issue. --- src/d_player.h | 1 + src/dobject.h | 1 + src/dobjtype.cpp | 37 +++++++++++++++++++++------------- src/dobjtype.h | 3 +-- src/g_shared/a_pickups.cpp | 12 +++++++++++ src/g_shared/a_pickups.h | 2 ++ src/g_shared/a_weaponpiece.cpp | 12 +++++++++++ src/g_shared/a_weaponpiece.h | 11 +++++++++- src/g_shared/a_weapons.cpp | 13 ++++++++++++ src/info.cpp | 31 ++++++++++++++++++++++++++++ src/info.h | 1 + src/p_user.cpp | 10 +++++++++ src/thingdef/thingdef.cpp | 9 ++------- 13 files changed, 119 insertions(+), 24 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 168327f8a..9a4e60d0f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -80,6 +80,7 @@ public: FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } void SetPainFlash(FName type, PalEntry color); bool GetPainFlash(FName type, PalEntry *color) const; + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString DisplayName; // Display name (used in menus, etc.) FString SoundClass; // Sound class diff --git a/src/dobject.h b/src/dobject.h index 4b6f1ec49..f478cfc08 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -98,6 +98,7 @@ enum CLASSREG_PClassPlayerPawn, CLASSREG_PClassType, CLASSREG_PClassClass, + CLASSREG_PClassWeaponPiece }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7e80eca0c..f16bd588d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -44,6 +44,7 @@ #include "autosegs.h" #include "v_text.h" #include "a_pickups.h" +#include "a_weaponpiece.h" #include "d_player.h" #include "fragglescript/t_fs.h" @@ -2163,6 +2164,7 @@ PClass *ClassReg::RegisterClass() &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, + &PClassWeaponPiece::RegistrationInfo, }; // Skip classes that have already been registered @@ -2318,34 +2320,29 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) assert (size >= Size); PClass *type; bool notnew; + size_t bucket; - const PClass *existclass = FindClass(name); + PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); // This is a placeholder so fill it in - if (existclass != NULL && (existclass->Size == TClass_Fatal || existclass->Size == TClass_Nonfatal)) + if (existclass != NULL && (existclass->Size == TentativeClass)) { type = const_cast(existclass); if (!IsDescendantOf(type->ParentClass)) { - if (existclass->Size == TClass_Fatal) - { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); - } - else - { - Printf(TEXTCOLOR_RED "%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); - } + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } DPrintf("Defining placeholder class %s\n", name.GetChars()); notnew = true; } else { - // Create a new type object of the same type as us. (We may be a derived class of PClass.) - type = static_cast(GetClass()->CreateNew()); notnew = false; } + // Create a new type object of the same type as us. (We may be a derived class of PClass.) + type = static_cast(GetClass()->CreateNew()); + type->TypeName = name; type->Size = size; type->bRuntimeClass = true; @@ -2354,6 +2351,18 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { type->InsertIntoHash(); } + 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); + } return type; } @@ -2403,11 +2412,11 @@ PClass *PClass::FindClassTentative(FName name, bool fatal) return static_cast(found); } PClass *type = static_cast(GetClass()->CreateNew()); - DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); + Printf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; - type->Size = fatal? TClass_Fatal : TClass_Nonfatal; + type->Size = TentativeClass; type->bRuntimeClass = true; TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); return type; diff --git a/src/dobjtype.h b/src/dobjtype.h index 900059cab..8e0331f2f 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -601,8 +601,7 @@ public: enum { - TClass_Fatal = UINT_MAX, - TClass_Nonfatal = UINT_MAX - 1 + TentativeClass = UINT_MAX, }; class PClassClass; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index f6bca1294..f192f650f 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -39,6 +39,18 @@ void PClassInventory::Derive(PClass *newclass) newc->PickupMessage = PickupMessage; newc->GiveQuest = GiveQuest; newc->AltHUDIcon = AltHUDIcon; + newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newc->RestrictedToPlayerClass = RestrictedToPlayerClass; +} + +void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + Super::ReplaceClassRef(oldclass, newclass); + AInventory *def = (AInventory*)Defaults; + if (def != NULL) + { + if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + } } IMPLEMENT_CLASS(PClassAmmo) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index ef693394a..9c9c1e48c 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -139,6 +139,7 @@ protected: virtual void Derive(PClass *newclass); public: PClassInventory(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString PickupMessage; int GiveQuest; // Optionally give one of the quest items. @@ -269,6 +270,7 @@ protected: virtual void Derive(PClass *newclass); public: PClassWeapon(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); int SlotNumber; fixed_t SlotPriority; diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_shared/a_weaponpiece.cpp index 6862c1911..1a4c27882 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_shared/a_weaponpiece.cpp @@ -3,8 +3,20 @@ #include "doomstat.h" #include "farchive.h" +IMPLEMENT_CLASS(PClassWeaponPiece) IMPLEMENT_CLASS (AWeaponHolder) +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 (FArchive &arc) { Super::Serialize(arc); diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index 9f495a06e..dfa30f5d7 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -1,7 +1,16 @@ +// Ammo: Something a weapon needs to operate +class PClassWeaponPiece : public PClassInventory +{ + DECLARE_CLASS(PClassWeaponPiece, PClassInventory) +protected: +public: + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); +}; + class AWeaponPiece : public AInventory { - DECLARE_CLASS (AWeaponPiece, AInventory) + DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece) HAS_OBJECT_POINTERS protected: bool PrivateShouldStay (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index c972c7120..e7242ad3f 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -54,6 +54,19 @@ void PClassWeapon::Derive(PClass *newclass) newc->SlotPriority = SlotPriority; } + +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); + } +} + //=========================================================================== // // AWeapon :: Serialize diff --git a/src/info.cpp b/src/info.cpp index 8c2ae06a6..1ca53470c 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -522,6 +522,37 @@ void PClassActor::SetPainChance(FName type, int chance) } } +//========================================================================== +// +// PClassActor :: ReplaceClassRef +// +//========================================================================== + +void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + for (unsigned i = 0; i < VisibleToPlayerClass.Size(); i++) + { + if (VisibleToPlayerClass[i] == oldclass) + VisibleToPlayerClass[i] = static_cast(newclass); + } + for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) + { + if (ForbiddenToPlayerClass[i] == oldclass) + ForbiddenToPlayerClass[i] = static_cast(newclass); + } + for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) + { + if (RestrictedToPlayerClass[i] == oldclass) + RestrictedToPlayerClass[i] = static_cast(newclass); + } + 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); + } +} + //========================================================================== // // DmgFactors :: CheckFactor diff --git a/src/info.h b/src/info.h index 2d0c627ec..52ccca305 100644 --- a/src/info.h +++ b/src/info.h @@ -200,6 +200,7 @@ public: PClassActor(); ~PClassActor(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); void BuildDefaults(); void ApplyDefaults(BYTE *defaults); void RegisterIDs(); diff --git a/src/p_user.cpp b/src/p_user.cpp index 0427bd64f..e23ccff7b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -581,6 +581,16 @@ 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 diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b12f45abe..30d94c6a3 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -340,15 +340,10 @@ static void FinishThingdef() { PClassActor *ti = PClassActor::AllActorClasses[i]; - if (ti->Size == TClass_Fatal || ti->Size == TClass_Nonfatal) + if (ti->Size == TentativeClass) { Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - if (ti->Size == TClass_Fatal) errorcount++; - else - { - // In order to prevent a crash, this class needs to be completed, even though it defines nothing. - ti->ParentClass->CreateDerivedClass(ti->TypeName, ti->ParentClass->Size); - } + errorcount++; continue; } From 6ce0c9f78ec92f3f579c727f9f4e3e03ef7e0fec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Feb 2016 00:17:00 +0100 Subject: [PATCH 4/5] - split up PClass::Derive and its child functions because part of them is also needed when initializing an inherited native class with the properties of its parent - but calling the base version in PClass is not possible. - moved a few AActor properties out of the EXE so that I could easily test if it works. --- src/d_player.h | 2 +- src/dobjtype.cpp | 1 + src/dobjtype.h | 5 +++-- src/g_shared/a_pickups.cpp | 12 ++++++------ src/g_shared/a_pickups.h | 11 +++++------ src/g_shared/a_puzzleitems.cpp | 4 ++-- src/g_shared/a_weapons.cpp | 4 ++-- src/info.cpp | 8 +------- src/info.h | 2 +- src/p_user.cpp | 4 ++-- src/thingdef/thingdef.cpp | 1 + wadsrc/static/actors/actor.txt | 4 ++++ 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 9a4e60d0f..60acb25d2 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -73,9 +73,9 @@ class PClassPlayerPawn : public PClassActor { DECLARE_CLASS(PClassPlayerPawn, PClassActor); protected: - virtual void Derive(PClass *newclass); public: PClassPlayerPawn(); + virtual void DeriveData(PClass *newclass); void EnumColorSets(TArray *out); FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } void SetPainFlash(FName type, PalEntry color); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f16bd588d..1762079fb 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2347,6 +2347,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Size = size; type->bRuntimeClass = true; Derive(type); + DeriveData(type); if (!notnew) { type->InsertIntoHash(); diff --git a/src/dobjtype.h b/src/dobjtype.h index 8e0331f2f..9ba327658 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -610,13 +610,14 @@ class PClass : public PStruct DECLARE_CLASS(PClass, PStruct); HAS_OBJECT_POINTERS; protected: - virtual void Derive(PClass *newclass); // We unravel _WITH_META here just as we did for PType. enum { MetaClassNum = CLASSREG_PClassClass }; + virtual void Derive(PClass *newclass); public: typedef PClassClass MetaClass; MetaClass *GetClass() const; + virtual void DeriveData(PClass *newclass) {} static void StaticInit(); static void StaticShutdown(); static void StaticBootstrap(); @@ -677,9 +678,9 @@ class PClassType : public PClass { DECLARE_CLASS(PClassType, PClass); protected: - virtual void Derive(PClass *newclass); public: PClassType(); + virtual void Derive(PClass *newclass); PClass *TypeTableType; // The type to use for hashing into the type table }; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index f192f650f..c19564f78 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -30,10 +30,10 @@ PClassInventory::PClassInventory() AltHUDIcon.SetNull(); } -void PClassInventory::Derive(PClass *newclass) +void PClassInventory::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); - Super::Derive(newclass); + Super::DeriveData(newclass); PClassInventory *newc = static_cast(newclass); newc->PickupMessage = PickupMessage; @@ -60,10 +60,10 @@ PClassAmmo::PClassAmmo() DropAmount = 0; } -void PClassAmmo::Derive(PClass *newclass) +void PClassAmmo::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); - Super::Derive(newclass); + Super::DeriveData(newclass); PClassAmmo *newc = static_cast(newclass); newc->DropAmount = DropAmount; @@ -1684,10 +1684,10 @@ PClassHealth::PClassHealth() // //=========================================================================== -void PClassHealth::Derive(PClass *newclass) +void PClassHealth::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); - Super::Derive(newclass); + Super::DeriveData(newclass); PClassHealth *newc = static_cast(newclass); newc->LowHealth = LowHealth; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 9c9c1e48c..a927f1919 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -135,10 +135,9 @@ enum class PClassInventory : public PClassActor { DECLARE_CLASS(PClassInventory, PClassActor) -protected: - virtual void Derive(PClass *newclass); public: PClassInventory(); + virtual void DeriveData(PClass *newclass); virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString PickupMessage; @@ -242,7 +241,7 @@ class PClassAmmo : public PClassInventory { DECLARE_CLASS(PClassAmmo, PClassInventory) protected: - virtual void Derive(PClass *newclass); + virtual void DeriveData(PClass *newclass); public: PClassAmmo(); @@ -267,7 +266,7 @@ class PClassWeapon : public PClassInventory { DECLARE_CLASS(PClassWeapon, PClassInventory); protected: - virtual void Derive(PClass *newclass); + virtual void DeriveData(PClass *newclass); public: PClassWeapon(); virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); @@ -403,9 +402,9 @@ class PClassHealth : public PClassInventory { DECLARE_CLASS(PClassHealth, PClassInventory) protected: - virtual void Derive(PClass *newclass); public: PClassHealth(); + virtual void DeriveData(PClass *newclass); FString LowHealthMessage; int LowHealth; @@ -520,8 +519,8 @@ class PClassPuzzleItem : public PClassInventory { DECLARE_CLASS(PClassPuzzleItem, PClassInventory); protected: - virtual void Derive(PClass *newclass); public: + virtual void DeriveData(PClass *newclass); FString PuzzFailMessage; }; diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp index 0d60ab829..837ac3463 100644 --- a/src/g_shared/a_puzzleitems.cpp +++ b/src/g_shared/a_puzzleitems.cpp @@ -11,9 +11,9 @@ IMPLEMENT_CLASS(PClassPuzzleItem) -void PClassPuzzleItem::Derive(PClass *newclass) +void PClassPuzzleItem::DeriveData(PClass *newclass) { - Super::Derive(newclass); + Super::DeriveData(newclass); assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; } diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index e7242ad3f..09ab0ffd8 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -44,10 +44,10 @@ PClassWeapon::PClassWeapon() SlotPriority = FIXED_MAX; } -void PClassWeapon::Derive(PClass *newclass) +void PClassWeapon::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - Super::Derive(newclass); + Super::DeriveData(newclass); PClassWeapon *newc = static_cast(newclass); newc->SlotNumber = SlotNumber; diff --git a/src/info.cpp b/src/info.cpp index 1ca53470c..c2aff93d4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -201,16 +201,11 @@ PClassActor::PClassActor() FastSpeed = FIXED_MIN; RDFactor = FRACUNIT; CameraHeight = FIXED_MIN; - BloodType = NAME_Blood; - BloodType2 = NAME_BloodSplatter; - BloodType3 = NAME_AxeBlood; DropItems = NULL; DontHurtShooter = false; - ExplosionDamage = 128; ExplosionRadius = -1; - MissileHeight = 32*FRACUNIT; MeleeDamage = 0; // Record this in the master list. @@ -250,10 +245,9 @@ PClassActor::~PClassActor() // //========================================================================== -void PClassActor::Derive(PClass *newclass) +void PClassActor::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); - Super::Derive(newclass); PClassActor *newa = static_cast(newclass); newa->Obituary = Obituary; diff --git a/src/info.h b/src/info.h index 52ccca305..9014a2f55 100644 --- a/src/info.h +++ b/src/info.h @@ -192,10 +192,10 @@ class PClassActor : public PClass DECLARE_CLASS(PClassActor, PClass); HAS_OBJECT_POINTERS; protected: - virtual void Derive(PClass *newclass); public: static void StaticInit (); static void StaticSetActorNums (); + virtual void DeriveData(PClass *newclass); PClassActor(); ~PClassActor(); diff --git a/src/p_user.cpp b/src/p_user.cpp index e23ccff7b..59098e83a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -515,10 +515,10 @@ PClassPlayerPawn::PClassPlayerPawn() ColorRangeEnd = 0; } -void PClassPlayerPawn::Derive(PClass *newclass) +void PClassPlayerPawn::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - Super::Derive(newclass); + Super::DeriveData(newclass); PClassPlayerPawn *newp = static_cast(newclass); size_t i; diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 30d94c6a3..99d46baca 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -137,6 +137,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par goto create; } ti->InitializeNativeDefaults(); + ti->ParentClass->DeriveData(ti); } else { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8677cfb82..8a79dd170 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -32,6 +32,10 @@ ACTOR Actor native //: Thinker RipLevelMin 0 RipLevelMax 0 DefThreshold 100 + BloodType "Blood", "BloodSplatter", "AxeBlood" + ExplosionDamage 128 + MissileHeight 32 + // Functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); From 3358181f18ec057793ff88a878bdc3f0b59b580a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Feb 2016 00:46:51 +0100 Subject: [PATCH 5/5] - cleaned up the class data organization: * moved RestrictedToPlayerClass and ForbiddenToPlayerClass arrays to AInventory. * moved all copy-from-parent code into DeriveData functions. --- src/g_shared/a_pickups.cpp | 12 +++++++++++- src/g_shared/a_pickups.h | 2 ++ src/info.cpp | 26 ++++++++++++++++---------- src/info.h | 2 -- src/thingdef/thingdef.cpp | 17 ----------------- src/thingdef/thingdef_properties.cpp | 8 ++++---- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index c19564f78..4a73212aa 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -50,6 +50,16 @@ void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) if (def != NULL) { if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) + { + if (ForbiddenToPlayerClass[i] == oldclass) + ForbiddenToPlayerClass[i] = static_cast(newclass); + } + for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) + { + if (RestrictedToPlayerClass[i] == oldclass) + RestrictedToPlayerClass[i] = static_cast(newclass); + } } } @@ -1536,7 +1546,7 @@ bool AInventory::CanPickup (AActor *toucher) if (!toucher) return false; - PClassActor *ai = GetClass(); + PClassInventory *ai = GetClass(); // Is the item restricted to certain player classes? if (ai->RestrictedToPlayerClass.Size() != 0) { diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index a927f1919..10391e0c8 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -143,6 +143,8 @@ public: FString PickupMessage; int GiveQuest; // Optionally give one of the quest items. FTextureID AltHUDIcon; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; }; class AInventory : public AActor diff --git a/src/info.cpp b/src/info.cpp index c2aff93d4..3a800e2cf 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -275,6 +275,22 @@ void PClassActor::DeriveData(PClass *newclass) newa->MeleeSound = MeleeSound; newa->MissileName = MissileName; newa->MissileHeight = MissileHeight; + + newa->VisibleToPlayerClass = VisibleToPlayerClass; + + if (DamageFactors != NULL) + { + // copy damage factors from parent + newa->DamageFactors = new DmgFactors; + *newa->DamageFactors = *DamageFactors; + } + if (PainChances != NULL) + { + // copy pain chances from parent + newa->PainChances = new PainChanceList; + *newa->PainChances = *PainChances; + } + } //========================================================================== @@ -529,16 +545,6 @@ void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass) if (VisibleToPlayerClass[i] == oldclass) VisibleToPlayerClass[i] = static_cast(newclass); } - for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) - { - if (ForbiddenToPlayerClass[i] == oldclass) - ForbiddenToPlayerClass[i] = static_cast(newclass); - } - for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) - { - if (RestrictedToPlayerClass[i] == oldclass) - RestrictedToPlayerClass[i] = static_cast(newclass); - } AActor *def = (AActor*)Defaults; if (def != NULL) { diff --git a/src/info.h b/src/info.h index 9014a2f55..460adb0fb 100644 --- a/src/info.h +++ b/src/info.h @@ -237,8 +237,6 @@ public: PainChanceList *PainChances; TArray VisibleToPlayerClass; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 99d46baca..a85f0ea08 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -145,23 +145,6 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = static_cast(parent->CreateDerivedClass (typeName, parent->Size)); } - // Copy class lists from parent - ti->ForbiddenToPlayerClass = parent->ForbiddenToPlayerClass; - ti->RestrictedToPlayerClass = parent->RestrictedToPlayerClass; - ti->VisibleToPlayerClass = parent->VisibleToPlayerClass; - - if (parent->DamageFactors != NULL) - { - // copy damage factors from parent - ti->DamageFactors = new DmgFactors; - *ti->DamageFactors = *parent->DamageFactors; - } - if (parent->PainChances != NULL) - { - // copy pain chances from parent - ti->PainChances = new PainChanceList; - *ti->PainChances = *parent->PainChances; - } ti->Replacee = ti->Replacement = NULL; ti->DoomEdNum = -1; return ti; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index cecdfb172..57de3684f 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1534,12 +1534,12 @@ DEFINE_PROPERTY(riplevelmax, I, Actor) //========================================================================== DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) { - info->RestrictedToPlayerClass.Clear(); + static_cast(info)->RestrictedToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - info->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1548,12 +1548,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) { - info->ForbiddenToPlayerClass.Clear(); + static_cast(info)->ForbiddenToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - info->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } }