diff --git a/src/dobject.h b/src/dobject.h index 41b5e2824..7510a4cff 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -486,6 +486,7 @@ public: PalEntry &ColorVar(FName field); FName &NameVar(FName field); double &FloatVar(FName field); + FString &StringVar(FName field); template T*& PointerVar(FName field); // If you need to replace one object with another and want to diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index dcb93599d..1d5cd1512 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2892,6 +2892,7 @@ PClass::PClass() bExported = false; bDecorateClass = false; ConstructNative = nullptr; + Meta = nullptr; mDescriptiveName = "Class"; PClass::AllClasses.Push(this); @@ -3085,11 +3086,10 @@ void PClass::InitializeSpecials(void *addr, void *defaults, TArrayInitializeSpecials(addr, defaults, Inits); for (auto tao : (this->*Inits)) { @@ -3179,11 +3179,27 @@ void PClass::InitializeDefaults() memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); } + assert(MetaSize >= ParentClass->MetaSize); if (MetaSize != 0) { Meta = (BYTE*)M_Malloc(MetaSize); - memset(Meta, 0, MetaSize); - if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + + // Copy the defaults from the parent but leave the DObject part alone because it contains important data. + if (ParentClass->Meta != nullptr) + { + memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + if (MetaSize > ParentClass->MetaSize) + { + memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize); + } + } + else + { + memset(Meta, 0, MetaSize); + } + + if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + else memset(Meta, 0, MetaSize); } } @@ -3199,10 +3215,14 @@ void PClass::InitializeDefaults() { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } + } + } + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); } } } @@ -3264,6 +3284,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->bRuntimeClass = true; Derive(type, name); type->Size = size; + type->MetaSize = MetaSize; if (size != TentativeClass) { type->InitializeDefaults(); @@ -3344,7 +3365,7 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before // setting up any defaults for any class. - if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) + if (field != nullptr && !(flags & VARF_Native)) { Meta = (BYTE *)M_Realloc(Meta, MetaSize); memset(Meta + oldsize, 0, MetaSize - oldsize); @@ -3380,6 +3401,7 @@ PClass *PClass::FindClassTentative(FName name) PClass *type = static_cast(GetClass()->CreateNew()); DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); + assert(MetaSize == 0); Derive(type, name); type->Size = TentativeClass; TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); diff --git a/src/dobjtype.h b/src/dobjtype.h index c88b00930..76e17b133 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -603,6 +603,7 @@ public: void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); + void InitMeta(); void DestroySpecials(void *addr); const PClass *NativeClass() const; @@ -742,6 +743,11 @@ inline double &DObject::FloatVar(FName field) return *(double*)ScriptVar(field, TypeFloat64); } +inline FString &DObject::StringVar(FName field) +{ + return *(FString*)ScriptVar(field, TypeString); +} + template inline T *&DObject::PointerVar(FName field) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 53e7d84ed..df6679d41 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -50,8 +50,6 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) -DEFINE_FIELD(AInventory, GiveQuest) -DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -115,8 +113,7 @@ void AInventory::Serialize(FSerializer &arc) ("icon", Icon, def->Icon) ("pickupsound", PickupSound, def->PickupSound) ("spawnpointclass", SpawnPointClass, def->SpawnPointClass) - ("droptime", DropTime, def->DropTime) - ("givequest", GiveQuest, def->GiveQuest); + ("droptime", DropTime, def->DropTime); } //=========================================================================== diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 817fcf176..9258d320a 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -87,7 +87,6 @@ public: FTextureID Icon; // Icon to show on status bar or HUD int DropTime; // Countdown after dropping PClassActor *SpawnPointClass; // For respawning like Heretic's mace - int GiveQuest; // Optionally give one of the quest items. FTextureID AltHUDIcon; DWORD ItemFlags; diff --git a/src/info.cpp b/src/info.cpp index 7cac3569d..2bba8afb4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -354,7 +354,6 @@ void PClassActor::DeriveData(PClass *newclass) } // Inventory stuff - newa->PickupMsg = PickupMsg; newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newa->RestrictedToPlayerClass = RestrictedToPlayerClass; diff --git a/src/info.h b/src/info.h index 6d6329f88..f0f0f6c3c 100644 --- a/src/info.h +++ b/src/info.h @@ -321,7 +321,6 @@ public: double MissileHeight; // These are only valid for inventory items. - FString PickupMsg; TArray RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; diff --git a/src/namedef.h b/src/namedef.h index 28de56818..df2841daa 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -398,6 +398,8 @@ xx(VisibleStartPitch) xx(VisibleEndAngle) xx(VisibleEndPitch) xx(Format) +xx(PickupMsg) +xx(Respawnable) // Various actor names which are used internally xx(MapSpot) diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 50e8f9c6a..5c5714ba3 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -541,11 +541,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - bag.Info->PickupMsg = sc.String; + inv->StringVar(NAME_PickupMsg) = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { - inv->BoolVar("Respawnable") = true; + inv->BoolVar(NAME_Respawnable) = true; } else if (def == DEF_BreakableDecoration && sc.Compare ("SolidOnDeath")) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index bd4d781a1..e70059fec 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -874,7 +874,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) { sc.MustGetString(); - *(FString*)addr = sc.String; + *(FString*)addr = strbin1(sc.String); } else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index cf70b19ae..527782382 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1831,16 +1831,6 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor)); } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->PickupMsg = str; -} - //========================================================================== // //========================================================================== @@ -1875,15 +1865,6 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) defaults->UseSound = str; } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(givequest, I, Inventory) -{ - PROP_INT_PARM(i, 0); - defaults->GiveQuest = i; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6f902648e..1a9dfbe8d 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1007,6 +1007,11 @@ void ZCCCompiler::CompileAllFields() type->Size = Classes[i]->Type()->ParentClass->Size; } } + if (Classes[i]->Type()->ParentClass) + type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize; + else + type->MetaSize = 0; + if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index e742e806d..092a93846 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -37,7 +37,7 @@ class Ammo : Inventory { int BackpackAmount; int BackpackMaxAmount; - /*meta*/ int DropAmount; + meta int DropAmount; property BackpackAmount: BackpackAmount; property BackpackMaxAmount: BackpackMaxAmount; diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index 230b3575b..e2fb8eacf 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -36,8 +36,8 @@ class Health : Inventory { transient int PrevHealth; - /*meta*/ int LowHealth; - /*meta*/ String LowHealthMessage; + meta int LowHealth; + meta String LowHealthMessage; property LowMessage: LowHealth, LowHealthMessage; diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt index 441566786..ce4bf805b 100644 --- a/wadsrc/static/zscript/inventory/inv_misc.txt +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -87,8 +87,8 @@ class MapRevealer : Inventory class PuzzleItem : Inventory { - /*meta*/ int PuzzleItemNumber; - /*meta*/ String PuzzFailMessage; + meta int PuzzleItemNumber; + meta String PuzzFailMessage; property Number: PuzzleItemNumber; property FailMessage: PuzzFailMessage; diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index 06caedad7..cac9b9b8f 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -23,8 +23,11 @@ class Inventory : Actor native native bool bPickupGood; native bool bCreateCopyMoved; native bool bInitEffectFailed; - native meta String PickupMsg; - native /*meta*/ int GiveQuest; + meta String PickupMsg; + meta int GiveQuest; + + Property PickupMessage: PickupMsg; + Property GiveQuest: GiveQuest; Default { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index c76aaef54..de9464726 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -33,7 +33,7 @@ class Weapon : StateProvider native native float FOVScale; native int Crosshair; // 0 to use player's crosshair native bool GivenAsMorphWeapon; - native bool bAltFire; // Set when self weapon's alternate fire is used. + native bool bAltFire; // Set when this weapon's alternate fire is used. native readonly bool bDehAmmo; Default