diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 09413318a..38d121331 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -622,7 +622,7 @@ file( GLOB HEADER_FILES sound/*.h textures/*.h scripting/*.h - scripting/codegeneration/*.h + scripting/backend/*.h scripting/decorate/*.h scripting/zscript/*.h scripting/vm/*.h @@ -1016,17 +1016,18 @@ set (PCH_SOURCES r_data/voxels.cpp r_data/renderstyle.cpp r_data/r_interpolate.cpp + scripting/symbols.cpp scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp - scripting/codegeneration/codegen.cpp - scripting/codegeneration/dynarrays.cpp + scripting/backend/codegen.cpp + scripting/backend/dynarrays.cpp + scripting/backend/vmbuilder.cpp + scripting/backend/vmdisasm.cpp scripting/decorate/olddecorations.cpp scripting/decorate/thingdef_exp.cpp scripting/decorate/thingdef_parse.cpp scripting/decorate/thingdef_states.cpp - scripting/vm/vmbuilder.cpp - scripting/vm/vmdisasm.cpp scripting/vm/vmexec.cpp scripting/vm/vmframe.cpp scripting/zscript/ast.cpp @@ -1206,9 +1207,9 @@ source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+") source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") -source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") -source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) -source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+") +source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") +source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) +source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+") source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") diff --git a/src/actor.h b/src/actor.h index f930e81e9..3adc0a345 100644 --- a/src/actor.h +++ b/src/actor.h @@ -573,12 +573,9 @@ struct FLinkContext msecnode_t *render_list = nullptr; }; -class DDropItem : public DObject +struct FDropItem { - DECLARE_CLASS(DDropItem, DObject) - HAS_OBJECT_POINTERS -public: - DDropItem *Next; + FDropItem *Next; FName Name; int Probability; int Amount; @@ -597,6 +594,7 @@ public: AActor &operator= (const AActor &other); ~AActor (); + virtual void Finalize(FStateDefinitions &statedef); virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; virtual void PostSerialize() override; @@ -610,7 +608,7 @@ public: return (AActor *)(this->GetClass()->Defaults); } - DDropItem *GetDropItems() const; + FDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (double dist); @@ -699,7 +697,7 @@ public: // Give an item to the actor and pick it up. // Returns true if the item pickup succeeded. - bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); + bool GiveInventory (PClassActor *type, int amount, bool givecheat = false); // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); @@ -736,7 +734,7 @@ public: AInventory *FirstInv (); // Tries to give the actor some ammo. - bool GiveAmmo (PClassInventory *type, int amount); + bool GiveAmmo (PClassActor *type, int amount); // Destroys all the inventory the actor is holding. void DestroyAllInventory (); @@ -973,7 +971,7 @@ public: { SetOrigin(Pos() + vel, true); } - void SetOrigin(double x, double y, double z, bool moving); + virtual void SetOrigin(double x, double y, double z, bool moving); void SetOrigin(const DVector3 & npos, bool moving) { SetOrigin(npos.X, npos.Y, npos.Z, moving); diff --git a/src/am_map.cpp b/src/am_map.cpp index 5c33412be..1013749f0 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2858,7 +2858,7 @@ void AM_drawThings () // Find the key's own color. // Only works correctly if single-key locks have lower numbers than any-key locks. // That is the case for all default keys, however. - if (t->IsKindOf(PClass::FindActor(NAME_Key))) + if (t->IsKindOf(NAME_Key)) { if (G_SkillProperty(SKILLP_EasyKey)) { diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 54d154a3e..637494333 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -263,7 +263,7 @@ void InitBotStuff() for(unsigned i=0;iIsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls != NULL && cls->IsDescendantOf(NAME_Weapon)) { AWeapon *w = (AWeapon*)GetDefaultByType(cls); if (w != NULL) diff --git a/src/b_think.cpp b/src/b_think.cpp index 7ce276aa0..da3fb6124 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item) //if(pos && !bglobal.thingvis[pos->id][item->id]) continue; // if (item->IsKindOf (RUNTIME_CLASS(AArtifact))) // return; // don't know how to use artifacts - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // FIXME AWeapon *heldWeapon; diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 7428fceea..e8f9509e5 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1210,7 +1210,7 @@ static void PrintSecretString(const char *string, bool thislevel) { while ((actor = it.Next())) { - if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue; + if (!actor->IsKindOf("SecretTrigger")) continue; foundone = true; break; } diff --git a/src/c_console.cpp b/src/c_console.cpp index 4340cc3f8..493625bf9 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1752,11 +1752,10 @@ void C_MidPrintBold (FFont *font, const char *msg) DEFINE_ACTION_FUNCTION(_Console, MidPrint) { PARAM_PROLOGUE; - PARAM_STRING(font); + PARAM_POINTER_NOT_NULL(fnt, FFont); PARAM_STRING(text); PARAM_BOOL_DEF(bold); - FFont *fnt = FFont::FindFont(font); const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars(); if (!bold) C_MidPrint(fnt, txt); else C_MidPrintBold(fnt, txt); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 7fecec550..36c32bf5b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -73,7 +73,7 @@ #include "thingdef.h" #include "info.h" #include "v_text.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -1658,7 +1658,7 @@ static int PatchWeapon (int weapNum) { val = 5; } - info->AmmoType1 = (PClassInventory*)AmmoNames[val]; + info->AmmoType1 = AmmoNames[val]; if (info->AmmoType1 != NULL) { info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2; @@ -1983,7 +1983,7 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; while (di != NULL) { if (di->Name == NAME_Clip) @@ -2916,7 +2916,7 @@ static bool LoadDehSupp () else { auto cls = PClass::FindActor(sc.String); - if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Ammo)) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } @@ -2934,7 +2934,7 @@ static bool LoadDehSupp () { sc.MustGetString(); PClass *cls = PClass::FindClass(sc.String); - if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Weapon)) { sc.ScriptError("Unknown weapon type '%s'", sc.String); } diff --git a/src/d_main.cpp b/src/d_main.cpp index 8ba11ad38..fd113d792 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2468,6 +2468,9 @@ void D_DoomMain (void) TexMan.Init(); C_InitConback(); + StartScreen->Progress(); + V_InitFonts(); + // [CW] Parse any TEAMINFO lumps. if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); @@ -2705,6 +2708,8 @@ void D_DoomMain (void) // delete all data that cannot be left until reinitialization V_ClearFonts(); // must clear global font pointers + ColorSets.Clear(); + PainFlashes.Clear(); R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo @@ -2715,7 +2720,7 @@ void D_DoomMain (void) GC::FullGC(); // clean up before taking down the object list. - // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + // Delete the reference to the VM functions here which were deleted and will be recreated after the restart. FAutoSegIterator probe(ARegHead, ARegTail); while (*++probe != NULL) { diff --git a/src/d_net.cpp b/src/d_net.cpp index c3bc01e92..ade486e82 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2540,7 +2540,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_MORPHEX: { s = ReadString (stream); - const char *msg = cht_Morph (players + player, dyn_cast(PClass::FindClass (s)), false); + const char *msg = cht_Morph (players + player, PClass::FindActor (s), false); if (player == consoleplayer) { Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); @@ -2639,7 +2639,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(i = 0; i < count; ++i) { - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer); } } @@ -2648,7 +2648,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2656,7 +2656,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index d3ce8c943..62beb5460 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - PClassPlayerPawn *type = PlayerClasses[i].Type; + auto type = PlayerClasses[i].Type; if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { @@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); + colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet()); } if (colorset != NULL) { diff --git a/src/d_player.h b/src/d_player.h index cba5de7cb..92f05c346 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -67,39 +67,17 @@ struct FPlayerColorSet ExtraRange Extra[6]; }; -typedef TMap FPlayerColorSetMap; -typedef TMap PainFlashList; +typedef TArray> PainFlashList; +typedef TArray> ColorSetList; -class PClassPlayerPawn : public PClassActor -{ - DECLARE_CLASS(PClassPlayerPawn, PClassActor); -protected: -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); - bool GetPainFlash(FName type, PalEntry *color) const; +extern PainFlashList PainFlashes; +extern ColorSetList ColorSets; - FString DisplayName; // Display name (used in menus, etc.) - FString SoundClass; // Sound class - FString Face; // Doom status bar face (when used) - FString Portrait; - FString Slot[10]; - FName InvulMode; - FName HealingRadiusType; - double HexenArmor[5]; - BYTE ColorRangeStart; // Skin color range - BYTE ColorRangeEnd; - FPlayerColorSetMap ColorSets; - PainFlashList PainFlashes; -}; -FString GetPrintableDisplayName(PClassPlayerPawn *cls); +FString GetPrintableDisplayName(PClassActor *cls); class APlayerPawn : public AActor { - DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) + DECLARE_CLASS(APlayerPawn, AActor) HAS_OBJECT_POINTERS public: @@ -120,9 +98,9 @@ public: void TweakSpeeds (double &forwardmove, double &sidemove); void MorphPlayerThink (); void ActivateMorphWeapon (); - AWeapon *PickNewWeapon (PClassInventory *ammotype); - AWeapon *BestWeapon (PClassInventory *ammotype); - void CheckWeaponSwitch(PClassInventory *ammotype); + AWeapon *PickNewWeapon (PClassActor *ammotype); + AWeapon *BestWeapon (PClassActor *ammotype); + void CheckWeaponSwitch(PClassActor *ammotype); void GiveDeathmatchInventory (); void FilterCoopRespawnInventory (APlayerPawn *oldplayer); @@ -177,6 +155,17 @@ public: // [SP] ViewBob Multiplier double ViewBob; + // Former class properties that were moved into the object to get rid of the meta class. + FName SoundClass; // Sound class + FName Face; // Doom status bar face (when used) + FName Portrait; + FName Slot[10]; + FName InvulMode; + FName HealingRadiusType; + double HexenArmor[5]; + BYTE ColorRangeStart; // Skin color range + BYTE ColorRangeEnd; + }; // @@ -273,7 +262,7 @@ public: bool CheckSkin (int skin); - PClassPlayerPawn *Type; + PClassActor *Type; DWORD Flags; TArray Skins; }; @@ -345,7 +334,7 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_PlayerClass)); } - PClassPlayerPawn *GetPlayerClassType() const + PClassActor *GetPlayerClassType() const { return PlayerClasses[GetPlayerClassNum()].Type; } @@ -403,7 +392,7 @@ public: userinfo_t userinfo; // [RH] who is this? - PClassPlayerPawn *cls; // class of associated PlayerPawn + PClassActor *cls; // class of associated PlayerPawn float DesiredFOV; // desired field of vision float FOV; // current field of vision @@ -461,7 +450,7 @@ public: short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedlightlevel; int morphTics; // player is a chicken/pig if > 0 - PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed + PClassActor *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr PremorphWeapon; // ready weapon before morphing @@ -540,12 +529,16 @@ public: // Make sure that a state is properly set after calling this unless // you are 100% sure the context already implies the layer exists. DPSprite *GetPSprite(PSPLayers layer); + + bool GetPainFlash(FName type, PalEntry *color) const; }; // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale); +void EnumColorSets(PClassActor *pc, TArray *out); +FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/dobject.cpp b/src/dobject.cpp index 10b37f636..68f3aab8e 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -301,42 +301,17 @@ DObject::~DObject () PClass *type = GetClass(); if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { - DObject **probe; - - if (!(ObjectFlags & OF_YesReallyDelete)) + if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released))) { Printf("Warning: '%s' is freed outside the GC process.\n", type != NULL ? type->TypeName.GetChars() : "==some object=="); } - // Find all pointers that reference this object and NULL them. - StaticPointerSubstitution(this, NULL); - - // Now unlink this object from the GC list. - for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + if (!(ObjectFlags & OF_Released)) { - if (*probe == this) - { - *probe = ObjNext; - if (&ObjNext == GC::SweepPos) - { - GC::SweepPos = probe; - } - break; - } - } - - // If it's gray, also unlink it from the gray list. - if (this->IsGray()) - { - for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) - { - if (*probe == this) - { - *probe = GCNext; - break; - } - } + // Find all pointers that reference this object and NULL them. + StaticPointerSubstitution(this, NULL); + Release(); } } @@ -347,6 +322,41 @@ DObject::~DObject () } } +void DObject::Release() +{ + DObject **probe; + + // Unlink this object from the GC list. + for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + { + if (*probe == this) + { + *probe = ObjNext; + if (&ObjNext == GC::SweepPos) + { + GC::SweepPos = probe; + } + break; + } + } + + // If it's gray, also unlink it from the gray list. + if (this->IsGray()) + { + for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) + { + if (*probe == this) + { + *probe = GCNext; + break; + } + } + } + ObjNext = nullptr; + GCNext = nullptr; + ObjectFlags |= OF_Released; +} + //========================================================================== // // @@ -397,6 +407,23 @@ size_t DObject::PropagateMark() GC::Mark((DObject **)((BYTE *)this + *offsets)); offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + GC::Mark(&p); + } + offsets++; + } + return info->Size; } return 0; @@ -427,6 +454,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) } offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + if (p == old) + { + p = notOld; + changed++; + } + } + offsets++; + } + + return changed; } diff --git a/src/dobject.h b/src/dobject.h index 6b9b87c75..6797d2436 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,11 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassInventory, - CLASSREG_PClassWeapon, - CLASSREG_PClassPlayerPawn, - CLASSREG_PClassType, - CLASSREG_PClassClass, }; struct ClassReg @@ -208,6 +203,7 @@ enum EObjectFlags OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) + OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function }; template class TObjPtr; @@ -460,6 +456,7 @@ public: virtual ~DObject (); inline bool IsKindOf (const PClass *base) const; + inline bool IsKindOf(FName base) const; inline bool IsA (const PClass *type) const; void SerializeUserVars(FSerializer &arc); @@ -470,6 +467,9 @@ public: Class = NULL; } + // Releases the object from the GC, letting the caller care of any maintenance. + void Release(); + // For catching Serialize functions in derived classes // that don't call their base class. void CheckIfSerialized () const; @@ -606,6 +606,7 @@ static inline void GC::WriteBarrier(DObject *pointed) } } +#include "symbols.h" #include "dobjtype.h" inline bool DObject::IsKindOf (const PClass *base) const @@ -613,6 +614,11 @@ inline bool DObject::IsKindOf (const PClass *base) const return base->IsAncestorOf (GetClass ()); } +inline bool DObject::IsKindOf(FName base) const +{ + return GetClass()->IsDescendantOf(base); +} + inline bool DObject::IsA (const PClass *type) const { return (type == GetClass()); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index df1760dd7..8e9333934 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) curr->Destroy(); } + /* + if (curr->IsKindOf(RUNTIME_CLASS(PSymbol))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->SymbolName.GetChars()); + else if (curr->IsKindOf(RUNTIME_CLASS(PType))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->DescriptiveName()); + else + Printf("Collecting %s\n", curr->GetClass()->TypeName.GetChars()); + */ curr->ObjectFlags |= OF_Cleanup; delete curr; finalized++; @@ -277,7 +285,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) void Mark(DObject **obj) { DObject *lobj = *obj; - if (lobj != NULL) + + assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released)); + if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released)) { if (lobj->ObjectFlags & OF_EuthanizeMe) { @@ -361,23 +371,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // Mark action functions - if (!FinalGC) - { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - Mark(*(afunc->VMPointer)); - } - } - // Mark types - TypeTable.Mark(); - for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) - { - Mark(PClass::AllClasses[i]); - } // Mark global symbols Namespaces.MarkSymbols(); // Mark bot stuff. @@ -458,8 +451,8 @@ static size_t SingleStep() { // Nothing more to sweep? State = GCS_Finalize; } - assert(old >= AllocBytes); - Estimate -= old - AllocBytes; + //assert(old >= AllocBytes); + Estimate -= MAX(0, old - AllocBytes); return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST; } @@ -559,9 +552,12 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { + assert(pointed->GetClass() < (void*)0x1000000000000000); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); + assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong. + if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects. // The invariant only needs to be maintained in the propagate state. if (State == GCS_Propagate) { @@ -776,7 +772,7 @@ CCMD(gc) { if (argv.argc() == 1) { - Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n"); + Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n"); return; } if (stricmp(argv[1], "stop") == 0) @@ -791,6 +787,12 @@ CCMD(gc) { GC::FullGC(); } + else if (stricmp(argv[1], "count") == 0) + { + int cnt = 0; + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); + Printf("%d active objects counted\n", cnt); + } else if (stricmp(argv[1], "pause") == 0) { if (argv.argc() == 2) @@ -814,3 +816,4 @@ CCMD(gc) } } } + diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7468b6dab..25e27b846 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -64,8 +64,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FNamespaceManager Namespaces; +FMemArena ClassDataAllocator(32768); // use this for all static class data that can be released in bulk when the type system is shut down. FTypeTable TypeTable; TArray PClass::AllClasses; @@ -88,6 +87,7 @@ PColor *TypeColor; PTextureID *TypeTextureID; PSpriteID *TypeSpriteID; PStatePointer *TypeState; +PPointer *TypeFont; PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; @@ -98,7 +98,7 @@ PPointer *TypeVoidPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -// A harmless non-NULL FlatPointer for classes without pointers. +// A harmless non-nullptr FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- @@ -117,7 +117,7 @@ void DumpTypeTable() { int len = 0; Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { Printf(" -> %s", ty->DescriptiveName()); len++; @@ -149,59 +149,9 @@ void DumpTypeTable() Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); } -/* PClassType *************************************************************/ - -IMPLEMENT_CLASS(PClassType, false, false) - -//========================================================================== -// -// PClassType Constructor -// -//========================================================================== - -PClassType::PClassType() -: TypeTableType(NULL) -{ -} - -//========================================================================== -// -// PClassType :: DeriveData -// -//========================================================================== - -void PClassType::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); - Super::DeriveData(newclass); - static_cast(newclass)->TypeTableType = TypeTableType; -} - -/* PClassClass ************************************************************/ - -IMPLEMENT_CLASS(PClassClass, false, false) - -//========================================================================== -// -// PClassClass Constructor -// -// The only thing we want to do here is automatically set TypeTableType -// to PClass. -// -//========================================================================== - -PClassClass::PClassClass() -{ - TypeTableType = RUNTIME_CLASS(PClass); -} - /* PType ******************************************************************/ -IMPLEMENT_CLASS(PType, true, true) - -IMPLEMENT_POINTERS_START(PType) - IMPLEMENT_POINTER(HashNext) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PType, true, false) //========================================================================== // @@ -210,7 +160,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(NULL) +: Size(size), Align(align), HashNext(nullptr) { mDescriptiveName = "Type"; loadOp = OP_NOP; @@ -230,18 +180,6 @@ PType::~PType() { } -//========================================================================== -// -// PType :: PropagateMark -// -//========================================================================== - -size_t PType::PropagateMark() -{ - size_t marked = Symbols.MarkSymbols(); - return marked + Super::PropagateMark(); -} - //========================================================================== // // PType :: WriteValue @@ -285,6 +223,10 @@ void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) con { } +void PType::SetPointerArray(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -377,40 +319,10 @@ const char *PType::DescriptiveName() const // // PType :: StaticInit STATIC // -// Set up TypeTableType values for every PType child and create basic types. -// //========================================================================== void PType::StaticInit() { - // Add types to the global symbol table. - - // Set up TypeTable hash keys. - RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); - RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); - RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); - RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); - RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); - RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); - RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); - RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); - RUNTIME_CLASS(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); - RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); - RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); - RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); - RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); - RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); - RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); - RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray); - RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); - RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); - RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); - RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); - RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); - RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); - RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); - // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeAuto = new PErrorType(2)); @@ -437,6 +349,7 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. TypeStringStruct = NewNativeStruct("Stringstruct", nullptr); + TypeFont = NewPointer(NewNativeStruct("Font", nullptr)); #ifdef __BIG_ENDIAN__ TypeColorStruct->AddField(NAME_a, TypeUInt8); TypeColorStruct->AddField(NAME_r, TypeUInt8); @@ -527,11 +440,7 @@ IMPLEMENT_CLASS(PCompoundType, true, false) /* PNamedType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, true) - -IMPLEMENT_POINTERS_START(PNamedType) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PNamedType, true, false) //========================================================================== // @@ -559,20 +468,6 @@ void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = TypeName; } -//========================================================================== -// -// PNamedType :: QualifiedName -// -//========================================================================== - -FString PNamedType::QualifiedName() const -{ - FString out; - if (Outer != nullptr) out = Outer->QualifiedName(); - out << "::" << TypeName; - return out; -} - /* PInt *******************************************************************/ IMPLEMENT_CLASS(PInt, false, false) @@ -829,7 +724,7 @@ PBool::PBool() MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); - assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); maxsym->Value = 1; } @@ -1145,7 +1040,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const { if (base != nullptr) new((BYTE *)base + offset) FString; - if (special != NULL) + if (special != nullptr) { special->Push(std::make_pair(this, offset)); } @@ -1400,11 +1295,7 @@ PStateLabel::PStateLabel() /* PPointer ***************************************************************/ -IMPLEMENT_CLASS(PPointer, false, true) - -IMPLEMENT_POINTERS_START(PPointer) - IMPLEMENT_POINTER(PointedType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PPointer, false, false) //========================================================================== // @@ -1413,7 +1304,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1440,8 +1331,9 @@ PPointer::PPointer(PType *pointsat, bool isconst) void PPointer::SetOps() { - storeOp = OP_SP; loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + storeOp = (loadOp == OP_LO && !static_cast(PointedType)->IsDescendantOf(RUNTIME_CLASS(DThinker))) ? OP_SO : OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; } @@ -1474,7 +1366,7 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const //========================================================================== // -// PPointer :: SetDefaultValue +// PPointer :: SetPointer // //========================================================================== @@ -1495,13 +1387,18 @@ void PPointer::SetPointer(void *base, unsigned offset, TArray *special) void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar(key, *(PClass **)addr); - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - ar(key, *(DObject **)addr); + auto pt = static_cast(PointedType); + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ar(key, *(PClass **)addr); + } + else + { + ar(key, *(DObject **)addr); + } } else { @@ -1518,16 +1415,19 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - bool res = false; - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return res; - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool res = false; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + auto pt = static_cast(PointedType); + bool res = true; + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + } + else + { + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + } return res; } return false; @@ -1545,7 +1445,7 @@ PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PPointer(type, isconst); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); @@ -1598,23 +1498,7 @@ bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) cons /* PClassPointer **********************************************************/ -IMPLEMENT_CLASS(PClassPointer,false, true) - -IMPLEMENT_POINTERS_START(PClassPointer) - IMPLEMENT_POINTER(ClassRestriction) -IMPLEMENT_POINTERS_END - -//========================================================================== -// -// PClassPointer - Default Constructor -// -//========================================================================== - -PClassPointer::PClassPointer() -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) -{ - mDescriptiveName = "ClassPointer"; -} +IMPLEMENT_CLASS(PClassPointer,false, false) //========================================================================== // @@ -1627,6 +1511,10 @@ PClassPointer::PClassPointer(PClass *restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; + // class pointers do not need write barriers because all classes are stored in the global type table and won't get collected. + // This means we can use the cheapoer non-barriered opcodes here. + loadOp = OP_LOS; + storeOp = OP_SP; } //========================================================================== @@ -1681,7 +1569,7 @@ PClassPointer *NewClassPointer(PClass *restrict) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PClassPointer(restrict); TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); @@ -1691,11 +1579,7 @@ PClassPointer *NewClassPointer(PClass *restrict) /* PEnum ******************************************************************/ -IMPLEMENT_CLASS(PEnum, false, true) - -IMPLEMENT_POINTERS_START(PEnum) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PEnum, false, false) //========================================================================== // @@ -1737,7 +1621,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); - if (etype == NULL) + if (etype == nullptr) { etype = new PEnum(name, outer); TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); @@ -1747,11 +1631,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) /* PArray *****************************************************************/ -IMPLEMENT_CLASS(PArray, false, true) - -IMPLEMENT_POINTERS_START(PArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PArray, false, false) //========================================================================== // @@ -1760,7 +1640,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PArray::PArray() -: ElementType(NULL), ElementCount(0) +: ElementType(nullptr), ElementCount(0) { mDescriptiveName = "Array"; } @@ -1900,7 +1780,7 @@ PArray *NewArray(PType *type, unsigned int count) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PArray(type, count); TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); @@ -1974,7 +1854,7 @@ PResizableArray *NewResizableArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PResizableArray(type); TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket); @@ -1984,11 +1864,7 @@ PResizableArray *NewResizableArray(PType *type) /* PDynArray **************************************************************/ -IMPLEMENT_CLASS(PDynArray, false, true) - -IMPLEMENT_POINTERS_START(PDynArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PDynArray, false, false) //========================================================================== // @@ -1997,7 +1873,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PDynArray::PDynArray() -: ElementType(NULL) +: ElementType(nullptr) { mDescriptiveName = "DynArray"; Size = sizeof(FArray); @@ -2010,8 +1886,8 @@ PDynArray::PDynArray() // //========================================================================== -PDynArray::PDynArray(PType *etype) -: ElementType(etype) +PDynArray::PDynArray(PType *etype,PStruct *backing) +: ElementType(etype), BackingType(backing) { mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); Size = sizeof(FArray); @@ -2044,6 +1920,152 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *deff) const +{ + const FArray *def = (const FArray*)deff; + FArray *aray = (FArray*)addr; + + if (def == nullptr || def->Count == 0) + { + // Empty arrays do not need construction. + *aray = { nullptr, 0, 0 }; + } + else if (ElementType->GetRegType() != REGT_STRING) + { + // These are just integral values which can be done without any constructor hackery. + size_t blocksize = ElementType->Size * def->Count; + aray->Array = M_Malloc(blocksize); + memcpy(aray->Array, def->Array, blocksize); + aray->Most = aray->Count = def->Count; + } + else + { + // non-empty string arrays require explicit construction. + new(addr) TArray(*(TArray*)def); + } +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + FArray *aray = (FArray*)addr; + + if (aray->Array != nullptr) + { + if (ElementType->GetRegType() != REGT_STRING) + { + M_Free(aray->Array); + } + else + { + // Damn those cursed strings again. :( + ((TArray*)addr)->~TArray(); + } + } + aray->Count = aray->Most = 0; + aray->Array = nullptr; +} + +//========================================================================== +// +// PDynArray :: SetDefaultValue +// +//========================================================================== + +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PDynArray :: SetPointer +// +//========================================================================== + +void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *special) const +{ + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ElementType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointer arrays for this class. + special->Push(offset); + } +} + +//========================================================================== +// +// PDynArray :: WriteValue +// +//========================================================================== + +void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FArray *aray = (FArray*)addr; + if (aray->Count > 0) + { + if (ar.BeginArray(key)) + { + const BYTE *addrb = (const BYTE *)aray->Array; + for (unsigned i = 0; i < aray->Count; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + } + } +} + +//========================================================================== +// +// PDynArray :: ReadValue +// +//========================================================================== + +bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FArray *aray = (FArray*)addr; + DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. + + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + + size_t blocksize = ElementType->Size * count; + aray->Array = M_Malloc(blocksize); + memset(aray->Array, 0, blocksize); + aray->Most = aray->Count = count; + + BYTE *addrb = (BYTE *)aray->Array; + for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; + readsomething |= ElementType->ReadValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + return readsomething; + } + return false; +} + //========================================================================== // // NewDynArray @@ -2057,9 +2079,35 @@ PDynArray *NewDynArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { - atype = new PDynArray(type); + FString backingname; + + switch (type->GetRegType()) + { + case REGT_INT: + backingname.Format("DynArray_I%d", type->Size * 8); + break; + + case REGT_FLOAT: + backingname.Format("DynArray_F%d", type->Size * 8); + break; + + case REGT_STRING: + backingname = "DynArray_String"; + break; + + case REGT_POINTER: + backingname = "DynArray_Ptr"; + break; + + default: + I_Error("Unsupported dynamic array requested"); + break; + } + + auto backing = NewNativeStruct(backingname, nullptr); + atype = new PDynArray(type, backing); TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); } return (PDynArray *)atype; @@ -2067,12 +2115,7 @@ PDynArray *NewDynArray(PType *type) /* PMap *******************************************************************/ -IMPLEMENT_CLASS(PMap, false, true) - -IMPLEMENT_POINTERS_START(PMap) - IMPLEMENT_POINTER(KeyType) - IMPLEMENT_POINTER(ValueType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PMap, false, false) //========================================================================== // @@ -2081,7 +2124,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PMap::PMap() -: KeyType(NULL), ValueType(NULL) +: KeyType(nullptr), ValueType(nullptr) { mDescriptiveName = "Map"; Size = sizeof(FMap); @@ -2141,7 +2184,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) { size_t bucket; PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket); - if (maptype == NULL) + if (maptype == nullptr) { maptype = new PMap(keytype, valuetype); TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); @@ -2280,7 +2323,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const foundsomething = true; const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == NULL) + if (sym == nullptr) { DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); @@ -2304,7 +2347,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const // PStruct :: AddField // // Appends a new field to the end of a struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2322,10 +2365,10 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // its fields. Align = MAX(Align, type->Align); - if (Symbols.AddSymbol(field) == NULL) + if (Symbols.AddSymbol(field) == nullptr) { // name is already in use - delete field; - return NULL; + field->Destroy(); + return nullptr; } Fields.Push(field); @@ -2337,7 +2380,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // PStruct :: AddField // // Appends a new native field to the struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2355,18 +2398,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD f return field; } -//========================================================================== -// -// PStruct :: PropagateMark -// -//========================================================================== - -size_t PStruct::PropagateMark() -{ - GC::MarkArray(Fields); - return Fields.Size() * sizeof(void*) + Super::PropagateMark(); -} - //========================================================================== // // NewStruct @@ -2380,7 +2411,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2419,7 +2450,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PNativeStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2438,7 +2469,7 @@ IMPLEMENT_CLASS(PField, false, false) //========================================================================== PField::PField() -: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) +: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) { } @@ -2571,7 +2602,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray { size_t bucket; PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == NULL) + if (proto == nullptr) { proto = new PPrototype(rettypes, argtypes); TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); @@ -2579,76 +2610,9 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray return static_cast(proto); } -/* PFunction **************************************************************/ - -IMPLEMENT_CLASS(PFunction, false, false) - -//========================================================================== -// -// PFunction :: PropagataMark -// -//========================================================================== - -size_t PFunction::PropagateMark() -{ - for (unsigned i = 0; i < Variants.Size(); ++i) - { - GC::Mark(Variants[i].Proto); - GC::Mark(Variants[i].Implementation); - } - return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); -} - -//========================================================================== -// -// PFunction :: AddVariant -// -// Adds a new variant for this function. Does not check if a matching -// variant already exists. -// -//========================================================================== - -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) -{ - Variant variant; - - // I do not think we really want to deal with overloading here... - assert(Variants.Size() == 0); - - variant.Flags = flags; - variant.UseFlags = useflags; - variant.Proto = proto; - variant.ArgFlags = std::move(argflags); - variant.ArgNames = std::move(argnames); - variant.Implementation = impl; - if (impl != nullptr) impl->Proto = proto; - - // SelfClass can differ from OwningClass, but this is variant-dependent. - // Unlike the owner there can be cases where different variants can have different SelfClasses. - // (Of course only if this ever gets enabled...) - if (flags & VARF_Method) - { - assert(proto->ArgumentTypes.Size() > 0); - auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); - assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); - assert(variant.SelfClass != nullptr); - } - else - { - variant.SelfClass = nullptr; - } - - return Variants.Push(variant); -} - /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, true) - -IMPLEMENT_POINTERS_START(PClass) - IMPLEMENT_POINTER(ParentClass) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClass, false, false) //========================================================================== // @@ -2661,7 +2625,7 @@ IMPLEMENT_POINTERS_END static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr) { - if (type != NULL) + if (type != nullptr) { RecurseWriteFields(type->ParentClass, ar, addr); // Don't write this part if it has no non-transient variables @@ -2745,7 +2709,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { // Only read it if the type is related to this one. const PClass *parent; - for (parent = this; parent != NULL; parent = parent->ParentClass) + for (parent = this; parent != nullptr; parent = parent->ParentClass) { if (parent == type) { @@ -2807,7 +2771,7 @@ void PClass::StaticInit () FAutoSegIterator probe(CRegHead, CRegTail); - while (*++probe != NULL) + while (*++probe != nullptr) { ((ClassReg *)*probe)->RegisterClass (); } @@ -2831,62 +2795,40 @@ void PClass::StaticInit () // // PClass :: StaticShutdown STATIC // -// Frees FlatPointers belonging to all classes. Only really needed to avoid -// memory leak warnings at exit. +// Frees all static class data. // //========================================================================== void PClass::StaticShutdown () { - TArray uniqueFPs(64); - unsigned int i, j; - // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { *p = nullptr; } FunctionPtrList.Clear(); + VMFunction::DeleteAll(); - // Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down. + // Make a full garbage collection here so that all destroyed but uncollected higher level objects + // that still exist are properly taken down before the low level data is deleted. GC::FullGC(); // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. // This flags DObject::Destroy not to call any scripted OnDestroy methods anymore. bVMOperational = false; + // PendingWeapon must be cleared manually because it is not subjected to the GC if it contains WP_NOCHANGE, which is just RUNTIME_CLASS(AWWeapon). + // But that will get cleared here, confusing the GC if the value is left in. + for (auto &p : players) + { + p.PendingWeapon = nullptr; + } + // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. + bShutdown = true; TypeTable.Clear(); Namespaces.ReleaseSymbols(); - - for (i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) - { - // FlatPointers are shared by many classes, so we must check for - // duplicates and only delete those that are unique. - for (j = 0; j < uniqueFPs.Size(); ++j) - { - if (type->FlatPointers == uniqueFPs[j]) - { - break; - } - } - if (j == uniqueFPs.Size()) - { - uniqueFPs.Push(const_cast(type->FlatPointers)); - } - } - type->Destroy(); - } - for (i = 0; i < uniqueFPs.Size(); ++i) - { - delete[] uniqueFPs[i]; - } - bShutdown = true; - + ClassDataAllocator.FreeAllBlocks(); AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -2904,30 +2846,19 @@ void PClass::StaticShutdown () // // PClass :: StaticBootstrap STATIC // -// PClass and PClassClass have intermingling dependencies on their -// definitions. To sort this out, we explicitly define them before -// proceeding with the RegisterClass loop in StaticInit(). -// //========================================================================== void PClass::StaticBootstrap() { - PClassClass *clscls = new PClassClass; - PClassClass::RegistrationInfo.SetupClass(clscls); - - PClassClass *cls = new PClassClass; + PClass *cls = new PClass; PClass::RegistrationInfo.SetupClass(cls); - // The PClassClass constructor initialized these to NULL, because the + // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. - clscls->TypeTableType = cls; - cls->TypeTableType = cls; - clscls->InsertIntoHash(); cls->InsertIntoHash(); // Create parent objects before we go so that these definitions are complete. - clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); } @@ -2943,6 +2874,7 @@ PClass::PClass() ParentClass = nullptr; Pointers = nullptr; FlatPointers = nullptr; + ArrayPointers = nullptr; HashNext = nullptr; Defaults = nullptr; bRuntimeClass = false; @@ -2962,10 +2894,10 @@ PClass::PClass() PClass::~PClass() { - if (Defaults != NULL) + if (Defaults != nullptr) { M_Free(Defaults); - Defaults = NULL; + Defaults = nullptr; } } @@ -2984,15 +2916,10 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassInventory::RegistrationInfo, - &PClassWeapon::RegistrationInfo, - &PClassPlayerPawn::RegistrationInfo, - &PClassType::RegistrationInfo, - &PClassClass::RegistrationInfo, }; // Skip classes that have already been registered - if (MyClass != NULL) + if (MyClass != nullptr) { return MyClass; } @@ -3031,7 +2958,7 @@ PClass *ClassReg::RegisterClass() void ClassReg::SetupClass(PClass *cls) { - assert(MyClass == NULL); + assert(MyClass == nullptr); MyClass = cls; cls->TypeName = FName(Name+1); cls->Size = SizeOf; @@ -3054,7 +2981,7 @@ void PClass::InsertIntoHash () PType *found; found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != NULL) + if (found != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } @@ -3074,14 +3001,14 @@ void PClass::InsertIntoHash () const PClass *PClass::FindParentClass(FName name) const { - for (const PClass *type = this; type != NULL; type = type->ParentClass) + for (const PClass *type = this; type != nullptr; type = type->ParentClass) { if (type->TypeName == name) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3096,9 +3023,9 @@ PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { - return NULL; + return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL)); + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); } //========================================================================== @@ -3112,10 +3039,10 @@ PClass *PClass::FindClass (FName zaname) DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); - assert (mem != NULL); + assert (mem != nullptr); // Set this object's defaults before constructing it. - if (Defaults != NULL) + if (Defaults != nullptr) memcpy (mem, Defaults, Size); else memset (mem, 0, Size); @@ -3142,7 +3069,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(addr, defaults); for (auto tao : SpecialInits) { @@ -3167,7 +3094,7 @@ void PClass::DestroySpecials(void *addr) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->DestroySpecials(addr); for (auto tao : SpecialInits) { @@ -3203,7 +3130,7 @@ void PClass::InitializeDefaults() { if (IsKindOf(RUNTIME_CLASS(PClassActor))) { - assert(Defaults == NULL); + assert(Defaults == nullptr); Defaults = (BYTE *)M_Malloc(Size); // run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them. @@ -3220,7 +3147,7 @@ void PClass::InitializeDefaults() // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Defaults != NULL) + if (ParentClass->Defaults != nullptr) { memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); if (Size > ParentClass->Size) @@ -3237,7 +3164,7 @@ void PClass::InitializeDefaults() if (bRuntimeClass) { // Copy parent values from the parent defaults. - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) @@ -3272,48 +3199,31 @@ void PClass::DeriveData(PClass *newclass) PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { - assert (size >= Size); + assert(size >= Size); PClass *type; bool notnew; - size_t bucket; - PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); + const PClass *existclass = FindClass(name); // This is a placeholder so fill it in - if (existclass != nullptr) + if (existclass != NULL && existclass->Size == (unsigned)-1) { - if (existclass->Size == TentativeClass) + type = const_cast(existclass); + if (!IsDescendantOf(type->ParentClass)) { - if (!IsDescendantOf(existclass->ParentClass)) - { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), existclass->ParentClass->TypeName.GetChars()); - } - - if (size == TentativeClass) - { - // 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; - } - } - notnew = true; - } - else - { - // a different class with the same name already exists. Let the calling code deal with this. - return nullptr; + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); + notnew = true; } else { + 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->bRuntimeClass = true; Derive(type, name); type->Size = size; if (size != TentativeClass) @@ -3322,22 +3232,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Virtuals = Virtuals; DeriveData(type); } + else + type->ObjectFlags &= OF_Transient; + if (!notnew) { type->InsertIntoHash(); } - else - { - 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; } @@ -3376,14 +3277,14 @@ PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { - return NULL; + return nullptr; } size_t bucket; PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket); - if (found != NULL) + if (found != nullptr) { return static_cast(found); } @@ -3456,14 +3357,14 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) void PClass::BuildFlatPointers () { - if (FlatPointers != NULL) + if (FlatPointers != nullptr) { // Already built: Do nothing. return; } - else if (ParentClass == NULL) + else if (ParentClass == nullptr) { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - if (Pointers == NULL) - { // No pointers: Make FlatPointers a harmless non-NULL. + if (Pointers == nullptr) + { // No pointers: Make FlatPointers a harmless non-nullptr. FlatPointers = &TheEnd; } else @@ -3508,7 +3409,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3527,6 +3428,68 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: BuildArrayPointers +// +// same as above, but creates a list to dynamic object arrays +// +//========================================================================== + +void PClass::BuildArrayPointers() +{ + if (ArrayPointers != nullptr) + { // Already built: Do nothing. + return; + } + else if (ParentClass == nullptr) + { // No parent (i.e. DObject: FlatPointers is the same as Pointers. + ArrayPointers = &TheEnd; + } + else + { + ParentClass->BuildArrayPointers(); + + TArray ScriptPointers; + + // Collect all arrays to pointers in scripted fields. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointerArray(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (ScriptPointers.Size() == 0) + { // No new pointers: Just use the same ArrayPointers as the parent. + ArrayPointers = ParentClass->ArrayPointers; + } + else + { // New pointers: Create a new FlatPointers array and add them. + int numSuperPointers; + + // Count pointers defined by superclasses. + for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) + { + } + + // Concatenate them into a new array + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + if (numSuperPointers > 0) + { + memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0; + ArrayPointers = flat; + } + } +} + //========================================================================== // // PClass :: NativeClass @@ -3576,43 +3539,18 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) { size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - if (bucketnum != NULL) + if (bucketnum != nullptr) { *bucketnum = bucket; } - for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { - if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } } - return NULL; -} - -//========================================================================== -// -// FTypeTable :: ReplaceType -// -// Replaces an existing type in the table with a new version of the same -// type. For use when redefining actors in DECORATE. Does nothing if the -// old version is not in the table. -// -//========================================================================== - -void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) -{ - for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) - { - PType *type = *type_p; - if (type == oldtype) - { - newtype->HashNext = type->HashNext; - type->HashNext = NULL; - *type_p = newtype; - break; - } - } + return nullptr; } //========================================================================== @@ -3625,13 +3563,13 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t { #ifdef _DEBUG size_t bucketcheck; - assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); - assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif + type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3642,18 +3580,19 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t void FTypeTable::AddType(PType *type) { - PClass *metatype; intptr_t parm1, parm2; size_t bucket; - metatype = type->GetClass()->TypeTableType; + // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. + type->TypeTableType = type->GetClass(); + PClass *metatype = type->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3692,36 +3631,23 @@ size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) } } -//========================================================================== -// -// FTypeTable :: Mark -// -// Mark all types in this table for the garbage collector. -// -//========================================================================== - -void FTypeTable::Mark() -{ - for (int i = HASH_SIZE - 1; i >= 0; --i) - { - if (TypeHash[i] != NULL) - { - GC::Mark(TypeHash[i]); - } - } -} - //========================================================================== // // FTypeTable :: Clear // -// Removes everything from the table. We let the garbage collector worry -// about deleting them. -// //========================================================================== void FTypeTable::Clear() { + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) + { + auto next = ty->HashNext; + delete ty; + ty = next; + } + } memset(TypeHash, 0, sizeof(TypeHash)); } @@ -3731,232 +3657,3 @@ CCMD(typetable) DumpTypeTable(); } -// Symbol tables ------------------------------------------------------------ - -IMPLEMENT_CLASS(PTypeBase, true, false); -IMPLEMENT_CLASS(PSymbol, true, false); -IMPLEMENT_CLASS(PSymbolConst, false, false); -IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); -IMPLEMENT_CLASS(PSymbolConstString, false, false); -IMPLEMENT_CLASS(PSymbolTreeNode, false, false) -IMPLEMENT_CLASS(PSymbolType, false, true) - -IMPLEMENT_POINTERS_START(PSymbolType) - IMPLEMENT_POINTER(Type) -IMPLEMENT_POINTERS_END - -IMPLEMENT_CLASS(PSymbolVMFunction, false, true) - -IMPLEMENT_POINTERS_START(PSymbolVMFunction) - IMPLEMENT_POINTER(Function) -IMPLEMENT_POINTERS_END - -//========================================================================== -// -// -// -//========================================================================== - -PSymbol::~PSymbol() -{ -} - -PSymbolTable::PSymbolTable() -: ParentSymbolTable(NULL) -{ -} - -PSymbolTable::PSymbolTable(PSymbolTable *parent) -: ParentSymbolTable(parent) -{ -} - -PSymbolTable::~PSymbolTable () -{ - ReleaseSymbols(); -} - -size_t PSymbolTable::MarkSymbols() -{ - size_t count = 0; - MapType::Iterator it(Symbols); - MapType::Pair *pair; - - while (it.NextPair(pair)) - { - GC::Mark(pair->Value); - count++; - } - return count * sizeof(*pair); -} - -void PSymbolTable::ReleaseSymbols() -{ - // The GC will take care of deleting the symbols. We just need to - // clear our references to them. - Symbols.Clear(); -} - -void PSymbolTable::SetParentTable (PSymbolTable *parent) -{ - ParentSymbolTable = parent; -} - -PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL && searchparents && ParentSymbolTable != NULL) - { - return ParentSymbolTable->FindSymbol(symname, searchparents); - } - return value != NULL ? *value : NULL; -} - -PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL) - { - if (ParentSymbolTable != NULL) - { - return ParentSymbolTable->FindSymbolInTable(symname, symtable); - } - symtable = NULL; - return NULL; - } - symtable = this; - return *value; -} - -PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) -{ - // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != NULL) - { - return NULL; - } - Symbols.Insert(sym->SymbolName, sym); - return sym; -} - -void PSymbolTable::RemoveSymbol(PSymbol *sym) -{ - auto mysym = Symbols.CheckKey(sym->SymbolName); - if (mysym == nullptr || *mysym != sym) return; - Symbols.Remove(sym->SymbolName); -} - -PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) -{ - // If a symbol with a matching name exists, take its place and return it. - PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); - if (symslot != NULL) - { - PSymbol *oldsym = *symslot; - *symslot = newsym; - return oldsym; - } - // Else, just insert normally and return NULL since there was no - // symbol to replace. - Symbols.Insert(newsym->SymbolName, newsym); - return NULL; -} - -IMPLEMENT_CLASS(PNamespace, false, true) - -IMPLEMENT_POINTERS_START(PNamespace) -IMPLEMENT_POINTER(Parent) -IMPLEMENT_POINTERS_END - -PNamespace::PNamespace(int filenum, PNamespace *parent) -{ - Parent = parent; - if (parent) Symbols.SetParentTable(&parent->Symbols); - FileNum = filenum; -} - -size_t PNamespace::PropagateMark() -{ - GC::Mark(Parent); - return Symbols.MarkSymbols() + 1; -} - -FNamespaceManager::FNamespaceManager() -{ - GlobalNamespace = nullptr; -} - -PNamespace *FNamespaceManager::NewNamespace(int filenum) -{ - PNamespace *parent = nullptr; - // The parent will be the last namespace with this or a lower filenum. - // This ensures that DECORATE won't see the symbols of later files. - for (int i = AllNamespaces.Size() - 1; i >= 0; i--) - { - if (AllNamespaces[i]->FileNum <= filenum) - { - parent = AllNamespaces[i]; - break; - } - } - auto newns = new PNamespace(filenum, parent); - AllNamespaces.Push(newns); - return newns; -} - -size_t FNamespaceManager::MarkSymbols() -{ - for (auto ns : AllNamespaces) - { - GC::Mark(ns); - } - return AllNamespaces.Size(); -} - -void FNamespaceManager::ReleaseSymbols() -{ - GlobalNamespace = nullptr; - AllNamespaces.Clear(); -} - -// removes all symbols from the symbol tables. -// After running the compiler these are not needed anymore. -// Only the namespaces themselves are kept because the type table references them. -int FNamespaceManager::RemoveSymbols() -{ - int count = 0; - for (auto ns : AllNamespaces) - { - count += ns->Symbols.Symbols.CountUsed(); - ns->Symbols.ReleaseSymbols(); - } - return count; -} - -void RemoveUnusedSymbols() -{ - // Global symbols are not needed anymore after running the compiler. - int count = Namespaces.RemoveSymbols(); - - // We do not need any non-field and non-function symbols in structs and classes anymore. - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) - { - if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) - { - auto it = ty->Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) - { - ty->Symbols.RemoveSymbol(pair->Value); - count++; - } - } - } - } - } - DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); -} diff --git a/src/dobjtype.h b/src/dobjtype.h index 2726ebff1..cc0a17da8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -6,6 +6,7 @@ #endif typedef std::pair FTypeAndOffset; +class PStruct; #include "vm.h" @@ -38,36 +39,6 @@ enum VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature }; -// Symbol information ------------------------------------------------------- - -class PTypeBase : public DObject -{ - DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) - -public: - virtual FString QualifiedName() const - { - return ""; - } -}; - -class PSymbol : public PTypeBase -{ - DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); -public: - virtual ~PSymbol(); - - virtual FString QualifiedName() const - { - return SymbolName.GetChars(); - } - - FName SymbolName; - -protected: - PSymbol(FName name) { SymbolName = name; } -}; - // An action function ------------------------------------------------------- struct FState; @@ -78,101 +49,6 @@ struct VMReturn; class VMFunction; struct FNamespaceManager; -// A VM function ------------------------------------------------------------ - -class PSymbolVMFunction : public PSymbol -{ - DECLARE_CLASS(PSymbolVMFunction, PSymbol); - HAS_OBJECT_POINTERS; -public: - VMFunction *Function; - - PSymbolVMFunction(FName name) : PSymbol(name) {} - PSymbolVMFunction() : PSymbol(NAME_None) {} -}; - -// A symbol for a type ------------------------------------------------------ - -class PSymbolType : public PSymbol -{ - DECLARE_CLASS(PSymbolType, PSymbol); - HAS_OBJECT_POINTERS; -public: - class PType *Type; - - PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} - PSymbolType() : PSymbol(NAME_None) {} -}; - -// A symbol table ----------------------------------------------------------- - -struct PSymbolTable -{ - PSymbolTable(); - PSymbolTable(PSymbolTable *parent); - ~PSymbolTable(); - - size_t MarkSymbols(); - - // Sets the table to use for searches if this one doesn't contain the - // requested symbol. - void SetParentTable (PSymbolTable *parent); - PSymbolTable *GetParentTable() const - { - return ParentSymbolTable; - } - - // Finds a symbol in the table, optionally searching parent tables - // as well. - PSymbol *FindSymbol (FName symname, bool searchparents) const; - - // Like FindSymbol with searchparents set true, but also returns the - // specific symbol table the symbol was found in. - PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); - - - // Places the symbol in the table and returns a pointer to it or NULL if - // a symbol with the same name is already in the table. This symbol is - // not copied and will be freed when the symbol table is destroyed. - PSymbol *AddSymbol (PSymbol *sym); - - // Similar to AddSymbol but always succeeds. Returns the symbol that used - // to be in the table with this name, if any. - PSymbol *ReplaceSymbol(PSymbol *sym); - - void RemoveSymbol(PSymbol *sym); - - // Frees all symbols from this table. - void ReleaseSymbols(); - - typedef TMap MapType; - - MapType::Iterator GetIterator() - { - return MapType::Iterator(Symbols); - } - -private: - - PSymbolTable *ParentSymbolTable; - MapType Symbols; - - friend class DObject; - friend struct FNamespaceManager; -}; - -// A symbol for a compiler tree node ---------------------------------------- - -class PSymbolTreeNode : public PSymbol -{ - DECLARE_CLASS(PSymbolTreeNode, PSymbol); -public: - struct ZCC_TreeNode *Node; - - PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} - PSymbolTreeNode() : PSymbol(NAME_None) {} -}; - // Basic information shared by all types ------------------------------------ // Only one copy of a type is ever instantiated at one time. @@ -198,22 +74,13 @@ public: // Prototype *+ *+ struct ZCC_ExprConstant; -class PClassType; class PType : public PTypeBase { - //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); - // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, - // and we can't define it until we've defined PClass. But we can't define that - // without defining PType. DECLARE_ABSTRACT_CLASS(PType, PTypeBase) - HAS_OBJECT_POINTERS; protected: - enum { MetaClassNum = CLASSREG_PClassType }; public: - typedef PClassType MetaClass; - MetaClass *GetClass() const; - + PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -246,6 +113,7 @@ public: // object is destroyed. virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; + virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; @@ -302,8 +170,6 @@ public: const char *DescriptiveName() const; - size_t PropagateMark(); - static void StaticInit(); }; @@ -341,7 +207,6 @@ class PCompoundType : public PType class PNamedType : public PCompoundType { DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); - HAS_OBJECT_POINTERS; public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name @@ -355,7 +220,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - virtual FString QualifiedName() const; }; // Basic types -------------------------------------------------------------- @@ -498,7 +362,6 @@ public: class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); - HAS_OBJECT_POINTERS; public: PPointer(); PPointer(PType *pointsat, bool isconst = false); @@ -531,9 +394,8 @@ public: class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); - HAS_OBJECT_POINTERS; public: - PClassPointer(class PClass *restrict); + PClassPointer(class PClass *restrict = nullptr); class PClass *ClassRestriction; @@ -541,54 +403,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PClassPointer(); -}; - -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PField : public PSymbol -{ - DECLARE_CLASS(PField, PSymbol); - HAS_OBJECT_POINTERS -public: - PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0); - - size_t Offset; - PType *Type; - DWORD Flags; - int BitValue; -protected: - PField(); -}; - -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PProperty : public PSymbol -{ - DECLARE_CLASS(PProperty, PSymbol); -public: - PProperty(FName name, TArray &variables); - - TArray Variables; - -protected: - PProperty(); -}; - -class PPropFlag : public PSymbol -{ - DECLARE_CLASS(PPropFlag, PSymbol); -public: - PPropFlag(FName name, PField *offset, int bitval); - - PField *Offset; - int bitval; - -protected: - PPropFlag(); }; // Compound types ----------------------------------------------------------- @@ -596,7 +410,6 @@ protected: class PEnum : public PInt { DECLARE_CLASS(PEnum, PInt); - HAS_OBJECT_POINTERS; public: PEnum(FName name, PTypeBase *outer); @@ -609,7 +422,6 @@ protected: class PArray : public PCompoundType { DECLARE_CLASS(PArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PArray(PType *etype, unsigned int ecount); @@ -633,7 +445,6 @@ protected: class PResizableArray : public PArray { DECLARE_CLASS(PResizableArray, PArray); - HAS_OBJECT_POINTERS; public: PResizableArray(PType *etype); @@ -647,14 +458,22 @@ protected: class PDynArray : public PCompoundType { DECLARE_CLASS(PDynArray, PCompoundType); - HAS_OBJECT_POINTERS; public: - PDynArray(PType *etype); + PDynArray(PType *etype, PStruct *backing); PType *ElementType; + PStruct *BackingType; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const override; + protected: PDynArray(); }; @@ -662,7 +481,6 @@ protected: class PMap : public PCompoundType { DECLARE_CLASS(PMap, PCompoundType); - HAS_OBJECT_POINTERS; public: PMap(PType *keytype, PType *valtype); @@ -691,8 +509,6 @@ public: virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); - size_t PropagateMark(); - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; @@ -729,36 +545,6 @@ protected: PPrototype(); }; -// TBD: Should we really support overloading? -class PFunction : public PSymbol -{ - DECLARE_CLASS(PFunction, PSymbol); -public: - struct Variant - { - PPrototype *Proto; - VMFunction *Implementation; - TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes - TArray ArgNames; // we need the names to access them later when the function gets compiled. - uint32_t Flags; - int UseFlags; - PStruct *SelfClass; - }; - TArray Variants; - PStruct *OwningClass = nullptr; - - unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); - int GetImplicitArgs() - { - if (Variants[0].Flags & VARF_Action) return 3; - else if (Variants[0].Flags & VARF_Method) return 1; - return 0; - } - - size_t PropagateMark(); - - PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} -}; // Meta-info for every class derived from DObject --------------------------- @@ -767,22 +553,16 @@ enum TentativeClass = UINT_MAX, }; -class PClassClass; class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); - HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. - enum { MetaClassNum = CLASSREG_PClassClass }; TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: - typedef PClassClass MetaClass; - MetaClass *GetClass() const; - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -799,6 +579,7 @@ public: PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default + const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script @@ -816,6 +597,7 @@ public: PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); + void BuildArrayPointers(); void DestroySpecials(void *addr) const; const PClass *NativeClass() const; @@ -830,11 +612,24 @@ public: } return false; } + inline bool IsDescendantOf(const PClass *ti) const { return ti->IsAncestorOf(this); } + inline bool IsDescendantOf(FName ti) const + { + auto me = this; + while (me) + { + if (me->TypeName == ti) + return true; + me = me->ParentClass; + } + return false; + } + // Find a type, given its name. const PClass *FindParentClass(FName name) const; PClass *FindParentClass(FName name) { return const_cast(const_cast(this)->FindParentClass(name)); } @@ -858,34 +653,6 @@ public: static bool bVMOperational; }; -class PClassType : public PClass -{ - DECLARE_CLASS(PClassType, PClass); -protected: -public: - PClassType(); - virtual void DeriveData(PClass *newclass); - - PClass *TypeTableType; // The type to use for hashing into the type table -}; - -inline PType::MetaClass *PType::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - -class PClassClass : public PClassType -{ - DECLARE_CLASS(PClassClass, PClassType); -public: - PClassClass(); -}; - -inline PClass::MetaClass *PClass::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - // Type tables -------------------------------------------------------------- struct FTypeTable @@ -895,10 +662,8 @@ struct FTypeTable PType *TypeHash[HASH_SIZE]; PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); - void ReplaceType(PType *newtype, PType *oldtype, size_t bucket); void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); void AddType(PType *type); - void Mark(); void Clear(); static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); @@ -940,86 +705,11 @@ extern PStruct *TypeVector3; extern PStruct *TypeColorStruct; extern PStruct *TypeStringStruct; extern PStatePointer *TypeState; +extern PPointer *TypeFont; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; extern PPointer *TypeVoidPtr; -// A constant value --------------------------------------------------------- - -class PSymbolConst : public PSymbol -{ - DECLARE_CLASS(PSymbolConst, PSymbol); -public: - PType *ValueType; - - PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} - PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} -}; - -// A constant numeric value ------------------------------------------------- - -class PSymbolConstNumeric : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); -public: - union - { - int Value; - double Float; - void *Pad; - }; - - PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} - PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} - PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} - PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} - PSymbolConstNumeric() {} -}; - -// A constant string value -------------------------------------------------- - -class PSymbolConstString : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstString, PSymbolConst); -public: - FString Str; - - PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {} - PSymbolConstString() {} -}; - -// Namespaces -------------------------------------------------- - -class PNamespace : public PTypeBase -{ - DECLARE_CLASS(PNamespace, PTypeBase) - HAS_OBJECT_POINTERS; - -public: - PSymbolTable Symbols; - PNamespace *Parent; - int FileNum; // This is for blocking DECORATE access to later files. - - PNamespace() {} - PNamespace(int filenum, PNamespace *parent); - size_t PropagateMark(); -}; - -struct FNamespaceManager -{ - PNamespace *GlobalNamespace; - TArray AllNamespaces; - - FNamespaceManager(); - PNamespace *NewNamespace(int filenum); - size_t MarkSymbols(); - void ReleaseSymbols(); - int RemoveSymbols(); -}; - -extern FNamespaceManager Namespaces; - - // Enumerations for serializing types in an archive ------------------------- inline bool &DObject::BoolVar(FName field) diff --git a/src/doomtype.h b/src/doomtype.h index f0655263e..adfc9024c 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -42,6 +42,8 @@ #endif #include +#include +#include #include "tarray.h" #include "name.h" #include "zstring.h" @@ -156,12 +158,9 @@ struct PalEntry #endif }; -class PClassInventory; - class FTextureID { friend class FTextureManager; - friend FTextureID GetHUDIcon(PClassInventory *cls); friend void R_InitSpriteDefs(); public: diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 20b53c8fd..68d940704 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum) // Doom index is only supported for the 4 original ammo types // //========================================================================== -static PClassInventory * T_GetAmmo(const svalue_t &t) +static PClassActor * T_GetAmmo(const svalue_t &t) { const char * p; @@ -361,8 +361,8 @@ static PClassInventory * T_GetAmmo(const svalue_t &t) } p=DefAmmo[ammonum]; } - PClassInventory * am=dyn_cast(PClass::FindActor(p)); - if (am == NULL) + auto am = PClass::FindActor(p); + if (am == NULL || !am->IsKindOf(PClass::FindClass(NAME_Ammo))) { script_error("unknown ammo type : %s", p); return NULL; @@ -2434,8 +2434,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount) { type = "BasicArmorPickup"; } - PClassInventory * info = dyn_cast(PClass::FindActor (type)); - if (info == NULL) + auto info = PClass::FindActor (type); + if (info == NULL || !info->IsKindOf(RUNTIME_CLASS(AInventory))) { Printf ("Unknown inventory item: %s\n", type); return; @@ -2564,7 +2564,7 @@ void FParser::SF_PlayerKeys(void) void FParser::SF_PlayerAmmo(void) { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { @@ -2600,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void) void FParser::SF_MaxPlayerAmmo() { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { @@ -2629,7 +2629,7 @@ void FParser::SF_MaxPlayerAmmo() for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem))) + if (item->IsKindOf(NAME_BackpackItem)) { if (t_argc>=4) amount = intvalue(t_argv[3]); else amount*=2; @@ -2675,8 +2675,8 @@ void FParser::SF_PlayerWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2686,7 +2686,7 @@ void FParser::SF_PlayerWeapon() { AActor * wp = players[playernum].mo->FindInventory(ti); t_return.type = svt_int; - t_return.value.i = wp!=NULL;; + t_return.value.i = wp!=NULL; return; } else @@ -2712,7 +2712,7 @@ void FParser::SF_PlayerWeapon() { if (!wp) { - AWeapon * pw=players[playernum].PendingWeapon; + auto pw=players[playernum].PendingWeapon; players[playernum].mo->GiveInventoryType(ti); players[playernum].PendingWeapon=pw; } @@ -2756,8 +2756,8 @@ void FParser::SF_PlayerSelectedWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2862,7 +2862,7 @@ void FParser::SF_SetWeapon() { AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1]))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { } else if (players[playernum].ReadyWeapon == item) @@ -2874,7 +2874,7 @@ void FParser::SF_SetWeapon() } else { - AWeapon *weap = static_cast (item); + auto weap = static_cast (item); if (weap->CheckAmmo (AWeapon::EitherFire, false)) { diff --git a/src/g_game.cpp b/src/g_game.cpp index 38485fd53..dad118973 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1362,7 +1362,7 @@ void G_PlayerReborn (int player) BYTE currclass; userinfo_t userinfo; // [RH] Save userinfo APlayerPawn *actor; - PClassPlayerPawn *cls; + PClassActor *cls; FString log; DBot *Bot; //Added by MC: diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 0ad6b72f1..75d98c2c7 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -187,7 +187,7 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) keygroup->anykeylist.Push (k); //... but only keys get key numbers! - if (mi->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (mi->IsDescendantOf(NAME_Key)) { if (!ignorekey && GetDefaultByType(mi)->special1 == 0) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index fc35d2da4..53e7d84ed 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -25,58 +25,10 @@ EXTERN_CVAR(Bool, sv_unlimited_pickup) -IMPLEMENT_CLASS(PClassInventory, false, false) - -PClassInventory::PClassInventory() -{ - GiveQuest = 0; - AltHUDIcon.SetNull(); -} - -void PClassInventory::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); - Super::DeriveData(newclass); - PClassInventory *newc = static_cast(newclass); - - newc->PickupMsg = PickupMsg; - newc->GiveQuest = GiveQuest; - newc->AltHUDIcon = AltHUDIcon; - newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; - newc->RestrictedToPlayerClass = RestrictedToPlayerClass; -} - -size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass) -{ - size_t changed = Super::PointerSubstitution(oldclass, newclass); - AInventory *def = (AInventory*)Defaults; - 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); - 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) +void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); - ((AActor*)Defaults)->flags |= MF_SPECIAL; + flags |= MF_SPECIAL; } IMPLEMENT_CLASS(AInventory, false, true) @@ -98,8 +50,8 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) -DEFINE_FIELD(PClassInventory, PickupMsg) -DEFINE_FIELD(PClassInventory, GiveQuest) +DEFINE_FIELD(AInventory, GiveQuest) +DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -163,7 +115,8 @@ void AInventory::Serialize(FSerializer &arc) ("icon", Icon, def->Icon) ("pickupsound", PickupSound, def->PickupSound) ("spawnpointclass", SpawnPointClass, def->SpawnPointClass) - ("droptime", DropTime, def->DropTime); + ("droptime", DropTime, def->DropTime) + ("givequest", GiveQuest, def->GiveQuest); } //=========================================================================== @@ -548,7 +501,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CanPickup) if (!toucher) ACTION_RETURN_BOOL(false); - PClassInventory *ai = self->GetClass(); + auto ai = self->GetClass(); // Is the item restricted to certain player classes? if (ai->RestrictedToPlayerClass.Size() != 0) { diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 7ca317397..817fcf176 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -9,7 +9,6 @@ class player_t; class FConfigFile; -class PClassPlayerPawn; struct visstyle_t; /************************************************************************/ @@ -50,28 +49,13 @@ enum }; -class PClassInventory : public PClassActor -{ - DECLARE_CLASS(PClassInventory, PClassActor) -public: - PClassInventory(); - virtual void DeriveData(PClass *newclass); - virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); - void Finalize(FStateDefinitions &statedef); - - FString PickupMsg; - int GiveQuest; // Optionally give one of the quest items. - FTextureID AltHUDIcon; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; -}; - class AInventory : public AActor { - DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) + DECLARE_CLASS(AInventory, AActor) HAS_OBJECT_POINTERS public: + virtual void Finalize(FStateDefinitions &statedef) override; virtual void Serialize(FSerializer &arc) override; virtual void MarkPrecacheSounds() const override; virtual void OnDestroy() override; @@ -103,6 +87,8 @@ 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; PClassActor *PickupFlash; // actor to spawn as pickup flash diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 24661dfd1..af180a4ea 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -64,9 +64,6 @@ 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) @@ -113,55 +110,25 @@ FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray Weapons_ntoh; -TMap Weapons_hton; +TArray Weapons_ntoh; +TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon, false, false) - //=========================================================================== // // // //=========================================================================== -PClassWeapon::PClassWeapon() -{ - SlotNumber = -1; - SlotPriority = INT_MAX; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - Super::DeriveData(newclass); - PClassWeapon *newc = static_cast(newclass); - - newc->SlotNumber = SlotNumber; - newc->SlotPriority = SlotPriority; -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::Finalize(FStateDefinitions &statedef) +void AWeapon::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); FState *ready = FindState(NAME_Ready); FState *select = FindState(NAME_Select); FState *deselect = FindState(NAME_Deselect); FState *fire = FindState(NAME_Fire); + auto TypeName = GetClass()->TypeName; // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. @@ -272,7 +239,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false); if (!gotSome && autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return gotSome; } @@ -281,10 +248,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { return true; } - count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0; - count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0; + count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0; + count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0; - if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL)) + if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr)) { lAmmoUse1 = 0; } @@ -306,7 +273,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { enoughmask = 1 << altFire; } - if (altFire && FindState(NAME_AltFire) == NULL) + if (altFire && FindState(NAME_AltFire) == nullptr) { // If this weapon has no alternate fire, then there is never enough ammo for it enough &= 1; } @@ -317,7 +284,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am // out of ammo, pick a weapon to change to if (autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return false; } @@ -352,7 +319,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) } if (!altFire) { - if (Ammo1 != NULL) + if (Ammo1 != nullptr) { if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO)) { @@ -363,25 +330,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) Ammo1->Amount -= AmmoUse1; } } - if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL) + if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } } else { - if (Ammo2 != NULL) + if (Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } - if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL) + if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr) { Ammo1->Amount -= AmmoUse1; } } - if (Ammo1 != NULL && Ammo1->Amount < 0) + if (Ammo1 != nullptr && Ammo1->Amount < 0) Ammo1->Amount = 0; - if (Ammo2 != NULL && Ammo2->Amount < 0) + if (Ammo2 != nullptr && Ammo2->Amount < 0) Ammo2->Amount = 0; } return true; @@ -546,19 +513,19 @@ FState *AWeapon::GetStateForButtonName (FName button) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon(static_cast(PClass::FindClass(type))); + return AddWeapon(static_cast(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(PClassWeapon *type) +bool FWeaponSlot::AddWeapon(PClassActor *type) { unsigned int i; - if (type == NULL) + if (type == nullptr) { return false; } - if (!type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!type->IsDescendantOf(NAME_Weapon)) { Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars()); return false; @@ -594,10 +561,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) Clear(); } tok = strtok(buff, " "); - while (tok != NULL) + while (tok != nullptr) { AddWeapon(tok); - tok = strtok(NULL, " "); + tok = strtok(nullptr, " "); } } @@ -610,7 +577,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(PClassWeapon *type) +int FWeaponSlot::LocateWeapon(PClassActor *type) { unsigned int i; @@ -641,22 +608,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { int i, j; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } // Does this slot even have any weapons? if (Weapons.Size() == 0) { return player->ReadyWeapon; } - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { for (i = 0; (unsigned)i < Weapons.Size(); i++) { if (Weapons[i].Type == player->ReadyWeapon->GetClass() || (player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP && - player->ReadyWeapon->SisterWeapon != NULL && + player->ReadyWeapon->SisterWeapon != nullptr && player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type)) { for (j = (i == 0 ? Weapons.Size() - 1 : i - 1); @@ -665,7 +632,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -680,7 +647,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -736,7 +703,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { int pos = Weapons[i].Position; - PClassWeapon *type = Weapons[i].Type; + PClassActor *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -785,7 +752,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) { int currSlot, index; @@ -810,7 +777,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) { int i, j; @@ -819,8 +786,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const j = Slots[i].LocateWeapon(type); if (j >= 0) { - if (slot != NULL) *slot = i; - if (index != NULL) *index = j; + if (slot != nullptr) *slot = i; + if (index != nullptr) *index = j; return true; } } @@ -857,14 +824,14 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index) { return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); } - else if (player->ReadyWeapon != NULL) + else if (player->ReadyWeapon != nullptr) { AWeapon *weap = player->ReadyWeapon; if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index)) { // If the current weapon wasn't found and is powered up, // look for its non-powered up version. - if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL) + if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr) { return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index); } @@ -893,16 +860,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = NUM_WEAPON_SLOTS - 1; startindex = Slots[startslot].Size() - 1; @@ -921,9 +888,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -948,16 +915,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon (player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = 0; startindex = 0; @@ -976,9 +943,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -1010,23 +977,23 @@ void FWeaponSlots::AddExtraWeapons() // Append extra weapons to the slots. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClassActor::AllActorClasses[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; - if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!cls->IsDescendantOf(NAME_Weapon)) { continue; } - PClassWeapon *acls = static_cast(cls); - if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && - acls->Replacement == NULL && // Replaced weapons don't get slotted. - !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && - !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. + auto weapdef = ((AWeapon*)GetDefaultByType(cls)); + if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + cls->Replacement == nullptr && // Replaced weapons don't get slotted. + !(weapdef->WeaponFlags & WIF_POWERED_UP) && + !LocateWeapon(cls, nullptr, nullptr) // Don't duplicate it if it's already present. ) { - int slot = acls->SlotNumber; + int slot = weapdef->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; + FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1063,8 +1030,8 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++) { - PClassWeapon *cls = dyn_cast(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); - if (cls == NULL) + PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); + if (cls == nullptr) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", gameinfo.DefaultWeaponSlots[i][j].GetChars()); @@ -1088,7 +1055,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) +void FWeaponSlots::StandardSetup(PClassActor *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1181,14 +1148,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) +void FWeaponSlots::SetFromPlayer(PClassActor *type) { Clear(); + auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot; for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) { - if (!type->Slot[i].IsEmpty()) + if (Slot[i] != NAME_None) { - Slots[i].AddWeaponList(type->Slot[i], false); + Slots[i].AddWeaponList(Slot[i], false); } } } @@ -1260,7 +1228,7 @@ CCMD (setslot) if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) { Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n"); - if (players[consoleplayer].mo != NULL) + if (players[consoleplayer].mo != nullptr) { FString config(GameConfig->GetConfigPath(false)); Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE @@ -1279,7 +1247,7 @@ CCMD (setslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->Slots[slot].Clear(); for (int i = 2; i < argv.argc(); ++i) @@ -1299,7 +1267,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); + Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); } } } @@ -1310,9 +1278,9 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) { - if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) + if (type != nullptr && !Slots[slot].AddWeapon(type) && feedback) { Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot); } @@ -1328,8 +1296,8 @@ CCMD (addslot) return; } - PClassWeapon *type= dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + PClassActor *type= dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf("%s is not a weapon\n", argv[2]); return; @@ -1339,7 +1307,7 @@ CCMD (addslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlot(int(slot), type, false); } @@ -1370,9 +1338,9 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(NAME_Weapon)) { switch (AddDefaultWeapon(slot, type)) { @@ -1395,7 +1363,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) CCMD (addslotdefault) { - PClassWeapon *type; + PClassActor *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1404,8 +1372,8 @@ CCMD (addslotdefault) return; } - type = dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + type = dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1415,7 +1383,7 @@ CCMD (addslotdefault) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlotDefault(int(slot), type, false); } @@ -1443,7 +1411,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) FString cmd(KeyConfWeapons[i]); AddCommandString(cmd.LockBuffer()); } - PlayingKeyConf = NULL; + PlayingKeyConf = nullptr; } //=========================================================================== @@ -1460,20 +1428,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - PClassWeapon *cls; + PClassActor *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); - cls = NULL; - Weapons_ntoh.Push(cls); // Index 0 is always NULL. + cls = nullptr; + Weapons_ntoh.Push(cls); // Index 0 is always nullptr. for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls->IsDescendantOf(NAME_Weapon)) { - Weapons_ntoh.Push(static_cast(cls)); + Weapons_ntoh.Push(static_cast(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1499,8 +1467,8 @@ void P_SetupWeapons_ntohton() static int ntoh_cmp(const void *a, const void *b) { - PClassWeapon *c1 = *(PClassWeapon **)a; - PClassWeapon *c2 = *(PClassWeapon **)b; + PClassActor *c1 = *(PClassActor **)a; + PClassActor *c2 = *(PClassActor **)b; int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) @@ -1540,24 +1508,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - PClassWeapon *type; + PClassActor *type; const char *s; count = ReadWord(demo); Weapons_ntoh.Resize(count); Weapons_hton.Clear(count); - Weapons_ntoh[0] = type = NULL; + Weapons_ntoh[0] = type = nullptr; Weapons_hton[type] = 0; for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = dyn_cast(PClass::FindClass(s)); + type = dyn_cast(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; - if (type != NULL) + if (type != nullptr) { Weapons_hton[type] = i; } @@ -1570,12 +1538,12 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(PClassWeapon *type) +void Net_WriteWeapon(PClassActor *type) { int index, *index_p; index_p = Weapons_hton.CheckKey(type); - if (index_p == NULL) + if (index_p == nullptr) { index = 0; } @@ -1602,7 +1570,7 @@ void Net_WriteWeapon(PClassWeapon *type) // //=========================================================================== -PClassWeapon *Net_ReadWeapon(BYTE **stream) +PClassActor *Net_ReadWeapon(BYTE **stream) { int index; @@ -1613,7 +1581,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) } if ((unsigned)index >= Weapons_ntoh.Size()) { - return NULL; + return nullptr; } return Weapons_ntoh[index]; } diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 21eaf9b89..606c96e98 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -1,7 +1,7 @@ #pragma once #include "a_pickups.h" -class PClassWeapon; +class PClassActor; class AWeapon; class FWeaponSlot @@ -12,13 +12,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (PClassWeapon *type); + bool AddWeapon (PClassActor *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassWeapon *type); + int LocateWeapon (PClassActor *type); - inline PClassWeapon *GetWeapon (int index) const + inline PClassActor *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -35,7 +35,7 @@ public: private: struct WeaponInfo { - PClassWeapon *Type; + PClassActor *Type; int Position; }; void SetInitialPositions(); @@ -61,59 +61,45 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + bool LocateWeapon (PClassActor *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(PClassPlayerPawn *type); - void StandardSetup(PClassPlayerPawn *type); + void SetFromPlayer(PClassActor *type); + void StandardSetup(PClassActor *type); void LocalSetup(PClassActor *type); void SendDifferences(int playernum, const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + void AddSlot(int slot, PClassActor *type, bool feedback); + void AddSlotDefault(int slot, PClassActor *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassActor *type); +PClassActor *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); void P_ReadDemoWeaponsChunk(BYTE **demo); -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - void Finalize(FStateDefinitions &statedef); - - int SlotNumber; - int SlotPriority; -}; - class AWeapon : public AStateProvider { - DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + DECLARE_CLASS(AWeapon, AStateProvider) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot int Kickback; float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *SisterWeaponType; // Another weapon to pick up with this one PClassActor *ProjectileType; // Projectile used by primary attack PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first @@ -123,6 +109,8 @@ public: int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + int SlotNumber; + int SlotPriority; // In-inventory instance variables TObjPtr Ammo1, Ammo2; @@ -135,7 +123,8 @@ public: virtual void MarkPrecacheSounds() const; - virtual void Serialize(FSerializer &arc) override; + void Finalize(FStateDefinitions &statedef) override; + void Serialize(FSerializer &arc) override; void PostMorphWeapon(); diff --git a/src/g_pch.h b/src/g_pch.h index 2c3676f5a..e5653796b 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -20,3 +20,4 @@ #include #include #include +#include diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index aed8457f8..2d1a95cdd 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -42,7 +42,7 @@ void A_Unblock(AActor *self, bool drop) // If the actor has attached metadata for items to drop, drop those. if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - DDropItem *di = self->GetDropItems(); + auto di = self->GetDropItems(); if (di != NULL) { diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 0c95c77b8..359e8a174 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -33,7 +33,7 @@ void InitAllPowerupEffects(AInventory *item); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AInventory *item; APlayerPawn *morphed; @@ -290,8 +290,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // and for the original DOOM status bar. if (player == &players[consoleplayer]) { - FString face = pmo->GetClass()->Face; - if (face.IsNotEmpty() && strcmp(face, "None") != 0) + FName face = pmo->Face; + if (face != NAME_None) { // Assume root-level base skin to begin with size_t skinindex = 0; @@ -337,7 +337,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (correctweapon) { // Better "lose morphed weapon" semantics PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); - if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (morphweapon != nullptr && morphweapon->IsDescendantOf(NAME_Weapon)) { AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon)) @@ -367,7 +367,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (hxarmor != nullptr) { double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr); - Slots[4] = mo->GetClass()->HexenArmor[0]; + Slots[4] = mo->HexenArmor[0]; } return true; } diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index e770e418e..1c0047c69 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -35,7 +35,7 @@ class AActor; class player_t; class AMorphedMonster; -bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, +bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0, PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0, diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 4ab0c8133..d39c16d88 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -122,16 +122,6 @@ static int statspace; DVector2 AM_GetPosition(); int active_con_scaletext(); -FTextureID GetHUDIcon(PClassInventory *cls) -{ - return cls->AltHUDIcon; -} - -void SetHUDIcon(PClassInventory *cls, FTextureID tex) -{ - cls->AltHUDIcon = tex; -} - //--------------------------------------------------------------------------- // // Draws an image into a box with its bottom center at the bottom @@ -437,7 +427,7 @@ static void SetKeyTypes() static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv) { FTextureID icon = FNullTextureID(); - FTextureID AltIcon = GetHUDIcon(inv->GetClass()); + FTextureID AltIcon = inv->AltHUDIcon; if (!AltIcon.Exists()) return; @@ -516,27 +506,27 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray orderedammos; +static TArray orderedammos; static void AddAmmoToList(AWeapon * weapdef) { - for(int i=0; i<2;i++) + for (int i = 0; i < 2; i++) { - PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + auto ti = i == 0 ? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { - auto ammodef=(AInventory*)GetDefaultByType(ti); + auto ammodef = (AInventory*)GetDefaultByType(ti); if (ammodef && !(ammodef->ItemFlags&IF_INVBAR)) { unsigned int j; - for(j=0;jmo->Inventory;inv;inv=inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (inv->IsKindOf(NAME_Weapon)) { AddAmmoToList((AWeapon*)inv); } @@ -646,11 +636,11 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) for(i=orderedammos.Size()-1;i>=0;i--) { - PClassInventory * type = orderedammos[i]; + auto type = orderedammos[i]; auto ammoitem = CPlayer->mo->FindInventory(type); auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]); - FTextureID AltIcon = GetHUDIcon(type); + FTextureID AltIcon = inv->AltHUDIcon; FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; if (!icon.isValid()) continue; @@ -682,7 +672,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) //--------------------------------------------------------------------------- FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO { - FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass()); + FTextureID picnum, AltIcon = item->AltHUDIcon; FState * state=NULL, *ReadyState; picnum.SetNull(); @@ -713,7 +703,7 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL } } // no spawn state - now try the ready state if it's weapon - else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) + else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } @@ -767,7 +757,7 @@ static void DrawWeapons(player_t *CPlayer, int x, int y) // First draw all weapons in the inventory that are not assigned to a weapon slot for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (inv->IsKindOf(NAME_Weapon) && !CPlayer->weapons.LocateWeapon(static_cast(inv)->GetClass(), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast(inv)); @@ -816,7 +806,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y) { if (rover->Amount>0) { - FTextureID AltIcon = GetHUDIcon(rover->GetClass()); + FTextureID AltIcon = rover->AltHUDIcon; if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) ) { @@ -1285,7 +1275,7 @@ void HUD_InitHud() } else tex.SetInvalid(); - if (ti) SetHUDIcon(static_cast(ti), tex); + if (ti) ((AInventory*)GetDefaultByType(ti))->AltHUDIcon = tex; } } } diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index d88ad40f2..d24298b94 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? player->MorphedPlayerClass->Face.GetChars() : skins[skin].face); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index c3950571f..6e6b55bec 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -148,7 +148,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { type = INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -418,7 +418,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (cls->IsDescendantOf(NAME_Key)) { auto key = GetDefaultByType(cls); if (key->special1 == keynum) @@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage { inventoryItem[0] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage sc.MustGetToken(TK_Identifier); inventoryItem[1] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -556,7 +556,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) { int keynum = item->special1; if(keynum) @@ -1078,7 +1078,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if(inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1094,7 +1094,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1160,7 +1160,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem)) + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -1203,7 +1203,7 @@ class CommandDrawNumber : public CommandDrawString if(value == INVENTORY) { inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); inventoryItem = RUNTIME_CLASS(AInventory); @@ -1476,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString num = 0; for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) num++; } break; @@ -2431,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand int rowWidth = 0; for(unsigned int i = 0;i < number+keyOffset;i++) { - while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key))) + while(!item->Icon.isValid() || !item->IsKindOf(NAME_Key)) { item = item->Inventory; if(item == NULL) @@ -2632,7 +2632,7 @@ class CommandDrawBar : public SBarInfoCommand sc.MustGetToken(TK_Identifier); type = AMMO; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo + if (data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); data.inventoryItem = PClass::FindActor(NAME_Ammo); @@ -2660,7 +2660,7 @@ class CommandDrawBar : public SBarInfoCommand if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); data.inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -2672,7 +2672,7 @@ class CommandDrawBar : public SBarInfoCommand { type = INVENTORY; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2894,7 +2894,7 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference { data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) //must be a kind of inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2977,7 +2977,7 @@ class CommandIsSelected : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { weapon[i] = PClass::FindClass(sc.String); - if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i])) + if(weapon[i] == NULL || !weapon[i]->IsDescendantOf(NAME_Weapon)) { sc.ScriptMessage("'%s' is not a type of weapon.", sc.String); weapon[i] = RUNTIME_CLASS(AWeapon); @@ -3130,7 +3130,7 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl if(!sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); weapon = PClass::FindClass(sc.String); - if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon + if (weapon == NULL || !weapon->IsDescendantOf(NAME_Weapon)) //must be a weapon { sc.ScriptMessage("%s is not a kind of weapon.", sc.String); weapon = RUNTIME_CLASS(AWeapon); @@ -3317,7 +3317,7 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { ammo[i] = PClass::FindClass(sc.String); - if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo + if(ammo[i] == NULL || !ammo[i]->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); ammo[i] = PClass::FindActor(NAME_Ammo); @@ -3400,7 +3400,7 @@ class CommandInInventory : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { item[i] = PClass::FindActor(sc.String); - if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) + if (item[i] == NULL || !item[i]->IsDescendantOf(NAME_Inventory)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); item[i] = RUNTIME_CLASS(AInventory); diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 7a548eaa2..5ce79fd09 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox(); inline PClassActor * GetRealType(PClassActor * ti) { PClassActor *rep = ti->GetReplacement(false); - if (rep != ti && rep != NULL && rep->IsDescendantOf(PClass::FindActor(NAME_DehackedPickup))) + if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup)) { return rep; } diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 47283b51a..fe974f4df 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -787,6 +787,10 @@ void gl_InitModels() map[c]=1; } } + else if (sc.Compare("dontcullbackfaces")) + { + smf.flags |= MDL_DONTCULLBACKFACES; + } else { sc.ScriptMessage("Unrecognized string \"%s\"", sc.String); @@ -949,8 +953,9 @@ void gl_RenderModel(GLSprite * spr) gl_RenderState.EnableTexture(true); // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. + // [Nash] Don't do back face culling if explicitly specified in MODELDEF // TO-DO: Implement proper depth sorting. - if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) + if (!(spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES)) { glEnable(GL_CULL_FACE); glFrontFace(GL_CW); @@ -1012,6 +1017,9 @@ void gl_RenderModel(GLSprite * spr) // Model space => World space gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y ); + // [Nash] take SpriteRotation into account + angle += spr->actor->SpriteRotation.Degrees; + if (spr->actor->renderflags & RF_INTERPOLATEANGLES) { // [Nash] use interpolated angles diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index f0267b891..c37b69b5e 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -370,6 +370,7 @@ enum MDL_USEACTORPITCH = 32, MDL_USEACTORROLL = 64, MDL_BADROTATION = 128, + MDL_DONTCULLBACKFACES = 256, }; struct FSpriteModelFrame diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b67cf810e..e9d6b7e1e 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -866,6 +866,14 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo // This should be done after postprocessing, not before. mBuffers->BindCurrentFB(); glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + + if (!toscreen) + { + gl_RenderState.mViewMatrix.loadIdentity(); + gl_RenderState.mProjectionMatrix.ortho(mScreenViewport.left, mScreenViewport.width, mScreenViewport.height, mScreenViewport.top, -1.0f, 1.0f); + gl_RenderState.ApplyMatrices(); + } + DrawBlend(lviewsector); } mDrawingScene2D = false; diff --git a/src/info.cpp b/src/info.cpp index a424c890f..58c7241ad 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, const char *callinfo = ""; if (info != nullptr && info->mStateType == STATE_Psprite) { - if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon "; + if (stateowner->IsKindOf(NAME_Weapon) && 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()); @@ -176,11 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); } -IMPLEMENT_CLASS(PClassActor, false, true) - -IMPLEMENT_POINTERS_START(PClassActor) - IMPLEMENT_POINTER(DropItems) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClassActor, false, false) //========================================================================== // @@ -349,32 +345,12 @@ void PClassActor::DeriveData(PClass *newclass) *newa->PainChances = *PainChances; } -} + // Inventory stuff + newa->PickupMsg = PickupMsg; + newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newa->RestrictedToPlayerClass = RestrictedToPlayerClass; -//========================================================================== -// -// PClassActor :: PropagateMark -// -//========================================================================== - -size_t PClassActor::PropagateMark() -{ - // Mark state functions - for (int i = 0; i < NumOwnedStates; ++i) - { - if (OwnedStates[i].ActionFunc != NULL) - { - GC::Mark(OwnedStates[i].ActionFunc); - } - } - // Mark damage function - if (Defaults != NULL) - { - GC::Mark(((AActor *)Defaults)->DamageFunc); - } - -// marked += ActorInfo->NumOwnedStates * sizeof(FState); - return Super::PropagateMark(); + newa->DisplayName = DisplayName; } //========================================================================== @@ -414,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName) // //========================================================================== -void PClassActor::SetDropItems(DDropItem *drops) +void PClassActor::SetDropItems(FDropItem *drops) { DropItems = drops; - GC::WriteBarrier(this, DropItems); } @@ -429,20 +404,20 @@ void PClassActor::SetDropItems(DDropItem *drops) // //========================================================================== -void PClassActor::Finalize(FStateDefinitions &statedef) +void AActor::Finalize(FStateDefinitions &statedef) { - AActor *defaults = (AActor*)Defaults; + AActor *defaults = this; try { - statedef.FinishStates(this, defaults); + statedef.FinishStates(GetClass(), defaults); } catch (CRecoverableError &) { statedef.MakeStateDefines(NULL); throw; } - statedef.InstallStates(this, defaults); + statedef.InstallStates(GetClass(), defaults); statedef.MakeStateDefines(NULL); } @@ -659,10 +634,33 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (VisibleToPlayerClass[i] == oldclass) { - VisibleToPlayerClass[i] = static_cast(newclass); + VisibleToPlayerClass[i] = static_cast(newclass); changed++; } } + + 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++; + } + } + AInventory *def = dyn_cast((AActor*)Defaults); + if (def != NULL) + { + if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + } + return changed; } diff --git a/src/info.h b/src/info.h index 4a6baa671..05785f90b 100644 --- a/src/info.h +++ b/src/info.h @@ -234,13 +234,11 @@ private: static DamageTypeDefinition *Get(FName type); }; -class DDropItem; -class PClassPlayerPawn; +struct FDropItem; class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); - HAS_OBJECT_POINTERS; protected: public: static void StaticInit (); @@ -256,10 +254,8 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); - size_t PropagateMark(); bool SetReplacement(FName replaceName); - void SetDropItems(DDropItem *drops); - virtual void Finalize(FStateDefinitions &statedef); + void SetDropItems(FDropItem *drops); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); @@ -289,7 +285,7 @@ public: DmgFactors *DamageFactors; PainChanceList *PainChances; - TArray VisibleToPlayerClass; + TArray VisibleToPlayerClass; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee @@ -306,7 +302,7 @@ public: FName BloodType2; // Bloopsplatter replacement type FName BloodType3; // AxeBlood replacement type - DDropItem *DropItems; + FDropItem *DropItems; FString SourceLumpName; FIntCVar *distancecheck; @@ -319,6 +315,14 @@ public: FName MissileName; double MissileHeight; + // These are only valid for inventory items. + FString PickupMsg; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + + // This is from PClassPlayerPawn + FString DisplayName; + // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; }; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 61a61d5f7..2db34d1e1 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -171,7 +171,7 @@ void cht_DoCheat (player_t *player, int cheat) break; case CHT_MORPH: - msg = cht_Morph (player, static_cast(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); + msg = cht_Morph (player, PClass::FindActor (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); break; case CHT_NOTARGET: @@ -318,7 +318,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_RESSURECT: if (player->playerstate != PST_LIVE && player->mo != nullptr) { - if (player->mo->IsKindOf(PClass::FindActor("PlayerChunk"))) + if (player->mo->IsKindOf("PlayerChunk")) { Printf("Unable to resurrect. Player is no longer connected to its body.\n"); } @@ -422,7 +422,7 @@ void cht_DoCheat (player_t *player, int cheat) { lastinvp = invp; invp = &(*invp)->Inventory; - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { AWeapon *weap = static_cast (item); if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || @@ -549,13 +549,13 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); } -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo) { if (player->mo == NULL) { return ""; } - PClassPlayerPawn *oldclass = player->mo->GetClass(); + auto oldclass = player->mo->GetClass(); // Set the standard morph style for the current game int style = MORPH_UNDOBYTOMEOFPOWER; diff --git a/src/m_cheat.h b/src/m_cheat.h index 6b95b16d4..13671b11a 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -30,12 +30,12 @@ // [RH] Functions that actually perform the cheating class player_t; -class PClassPlayerPawn; +class PClassActor; void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); void cht_Suicide (player_t *player); -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo); +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo); #endif diff --git a/src/memarena.cpp b/src/memarena.cpp index 8ea8b5806..af9f91547 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks() FreeBlockChain(FreeBlocks); } +//========================================================================== +// +// FMemArena :: DumpInfo +// +// Prints some info about this arena +// +//========================================================================== + +void FMemArena::DumpInfo() +{ + size_t allocated = 0; + size_t used = 0; + for (auto block = TopBlock; block != NULL; block = block->NextBlock) + { + allocated += BlockSize; + used += BlockSize - ((char*)block->Limit - (char*)block->Avail); + } + Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used); +} + //========================================================================== // // FMemArena :: FreeBlockChain diff --git a/src/memarena.h b/src/memarena.h index 3601469bf..14b735eda 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -46,6 +46,7 @@ public: void *Alloc(size_t size); void FreeAll(); void FreeAllBlocks(); + void DumpInfo(); protected: struct Block; diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 57c8ecf26..ba99aba36 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -435,7 +435,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation() if (mPlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -557,11 +557,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected) return; } - FString portrait = mPlayerClass->Type->Portrait; + FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait; - if (portrait.IsNotEmpty() && !mNoportrait) + if (portrait != NAME_None && !mNoportrait) { - FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch); + FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch); if (texid.isValid()) { FTexture *tex = TexMan(texid); diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 7116608b3..add8e5680 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets() if (li != NULL) { int sel = 0; - PlayerClass->Type->EnumColorSets(&PlayerColorSets); + EnumColorSets(PlayerClass->Type, &PlayerColorSets); li->SetString(0, "Custom"); for(unsigned i=0;iType->GetColorSet(PlayerColorSets[i]); + FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } int mycolorset = players[consoleplayer].userinfo.GetColorSet(); @@ -899,7 +899,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li) players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); PickPlayerClass(); - cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->DisplayName.GetChars()); + cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(PlayerClass->Type).GetChars()); UpdateSkins(); UpdateColorsets(); diff --git a/src/namedef.h b/src/namedef.h index 2bdb74ee6..a010fbb8a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -821,6 +821,8 @@ xx(DamageFunction) xx(Length) xx(Unit) xx(Size) +xx(Copy) +xx(Move) xx(Voidptr) xx(StateLabel) xx(SpriteID) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index f367c4637..fa7b66d65 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -858,7 +858,8 @@ void P_Spawn3DFloors (void) { case ExtraFloor_LightOnly: if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0; - P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0); + if (line.args[0] != 0) + P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0); break; case Sector_Set3DFloor: @@ -877,7 +878,8 @@ void P_Spawn3DFloors (void) line.args[4]=0; } } - P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]); + if (line.args[0] != 0) + P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]); break; default: diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bddcd7f95..00b1d7be8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -114,13 +114,6 @@ FRandom pr_acs ("ACS"); #define HUDMSG_VISIBILITY_MASK (0x00070000) // See HUDMSG visibility enumerations in sbar.h -// Flags for ReplaceTextures -#define NOT_BOTTOM 1 -#define NOT_MIDDLE 2 -#define NOT_TOP 4 -#define NOT_FLOOR 8 -#define NOT_CEILING 16 - // LineAttack flags #define FHF_NORANDOMPUFFZ 1 #define FHF_NOIMPACTDECAL 2 @@ -1193,12 +1186,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - players[i].mo->GiveInventory(static_cast(info), amount); + players[i].mo->GiveInventory(info, amount); } } else { - activator->GiveInventory(static_cast(info), amount); + activator->GiveInventory(info, amount); } } @@ -3322,47 +3315,6 @@ void DLevelScript::SetLineTexture (int lineid, int side, int position, int name) } } -void DLevelScript::ReplaceTextures (int fromnamei, int tonamei, int flags) -{ - const char *fromname = FBehavior::StaticLookupString (fromnamei); - const char *toname = FBehavior::StaticLookupString (tonamei); - FTextureID picnum1, picnum2; - - if (fromname == NULL) - return; - - if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0) - { - picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); - - for (auto &side : level.sides) - { - for(int j=0;j<3;j++) - { - static BYTE bits[]={NOT_TOP, NOT_MIDDLE, NOT_BOTTOM}; - if (!(flags & bits[j]) && side.GetTexture(j) == picnum1) - { - side.SetTexture(j, picnum2); - } - } - } - } - if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0) - { - picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); - - for (auto &sec : level.sectors) - { - if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1) - sec.SetTexture(sector_t::floor, picnum2); - if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1) - sec.SetTexture(sector_t::ceiling, picnum2); - } - } -} - int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force) { PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type)); @@ -5716,7 +5668,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (argCount >= 2) { PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1])); - if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup))) + if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup)) { Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1])); return 0; @@ -8352,9 +8304,14 @@ scriptwait: break; case PCD_REPLACETEXTURES: - ReplaceTextures (STACK(3), STACK(2), STACK(1)); + { + const char *fromname = FBehavior::StaticLookupString(STACK(3)); + const char *toname = FBehavior::StaticLookupString(STACK(2)); + + P_ReplaceTextures(fromname, toname, STACK(1)); sp -= 3; break; + } case PCD_SETLINEBLOCKING: { @@ -9042,7 +8999,7 @@ scriptwait: AInventory *item = activator->FindInventory (dyn_cast( PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { STACK(1) = 0; } @@ -9110,7 +9067,7 @@ scriptwait: } else { - if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) + if (activator != nullptr && activator->IsKindOf("ScriptedMarine")) { SetMarineSprite(activator, type); } @@ -9491,7 +9448,7 @@ scriptwait: { int tag = STACK(7); FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); - PClassPlayerPawn *playerclass = dyn_cast(PClass::FindClass (playerclass_name)); + auto playerclass = PClass::FindActor (playerclass_name); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); PClassActor *monsterclass = PClass::FindActor(monsterclass_name); int duration = STACK(4); diff --git a/src/p_acs.h b/src/p_acs.h index 52665a39b..8265e5b37 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -913,7 +913,6 @@ protected: static void ChangeFlat (int tag, int name, bool floorOrCeiling); static int CountPlayers (); static void SetLineTexture (int lineid, int side, int position, int name); - static void ReplaceTextures (int fromname, int toname, int flags); static int DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force); static int DoSpawn(int type, int x, int y, int z, int tid, int angle, bool force); static bool DoCheckActorTexture(int tid, AActor *activator, int string, bool floor); diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index f89a560ab..69ca13f16 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -79,6 +79,7 @@ #include "thingdef.h" #include "math/cmath.h" #include "g_levellocals.h" +#include "r_utility.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -2386,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { return false; } - if (item->IsKindOf(PClass::FindActor(NAME_Health))) + if (item->IsKindOf(NAME_Health)) { item->Amount *= amount; } @@ -3122,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon) AWeapon *weaponitem = static_cast(self->FindInventory(cls)); - if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon)) { if (self->player->ReadyWeapon != weaponitem) { @@ -5011,7 +5012,7 @@ enum T_Flags DEFINE_ACTION_FUNCTION(AActor, A_Teleport) { PARAM_ACTION_PROLOGUE(AActor); - PARAM_STATE_DEF (teleport_state) + PARAM_STATE_ACTION_DEF (teleport_state) PARAM_CLASS_DEF (target_type, ASpecialSpot) PARAM_CLASS_DEF (fog_type, AActor) PARAM_INT_DEF (flags) @@ -5448,7 +5449,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp) PARAM_FLOAT_DEF(zofs) PARAM_ANGLE_DEF(angle) PARAM_INT_DEF(flags) - PARAM_STATE_DEF(success_state) + PARAM_STATE_ACTION_DEF(success_state) PARAM_FLOAT_DEF(heightoffset) PARAM_FLOAT_DEF(radiusoffset) PARAM_ANGLE_DEF(pitch) @@ -5667,7 +5668,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. AInventory *gift = static_cast(Spawn(item)); - if (gift->IsKindOf(PClass::FindActor(NAME_Health))) + if (gift->IsKindOf(NAME_Health)) { gift->Amount *= amount; } @@ -6913,3 +6914,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetSize) ACTION_RETURN_BOOL(true); } + +DEFINE_ACTION_FUNCTION(AActor, SetCamera) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_OBJECT(cam, AActor); + PARAM_BOOL_DEF(revert); + + if (self->player == nullptr || self->player->mo != self) return 0; + + if (cam == nullptr) + { + cam = self; + revert = false; + } + AActor *oldcamera = self->player->camera; + self->player->camera = cam; + if (revert) self->player->cheats |= CF_REVERTPLEASE; + + if (oldcamera != cam) + { + R_ClearPastViewer(cam); + } + return 0; +} diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a77a7358d..54be79e3c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j].Item = dyn_cast(GetStrifeType(speech.ItemCheck[j])); + auto inv = GetStrifeType(speech.ItemCheck[j]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + node->ItemCheck[j].Item = inv; node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; @@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { - reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); + auto inv = GetStrifeType(rsp->Item[k]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + reply->ItemCheck[k].Item = inv; reply->ItemCheck[k].Amount = rsp->Count[k]; } reply->ItemCheckRequire.Clear(); @@ -1331,7 +1335,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply { if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (reply->GiveType->IsDescendantOf(NAME_Weapon)) { if (player->mo->FindInventory(reply->GiveType) != NULL) { @@ -1357,7 +1361,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } - if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter"))) + if (reply->GiveType->IsDescendantOf("SlideshowStarter")) gameaction = ga_slideshow; } else diff --git a/src/p_conversation.h b/src/p_conversation.h index bd674aa10..8771d95ae 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -12,7 +12,7 @@ struct FBrokenLines; struct FStrifeDialogueItemCheck { - PClassInventory *Item; + PClassActor *Item; int Amount; }; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index d1a7103fc..128141279 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3227,7 +3227,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) if (dropamount > 0) { - if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo))) + if (flagmask != 0 && inv->IsKindOf(NAME_Ammo)) { inv->Amount = int(dropamount * dropammofactor); inv->ItemFlags |= IF_IGNORESKILL; @@ -3253,7 +3253,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) inv->FloatVar("AmmoFactor") = dropammofactor; inv->ItemFlags |= flagmask; } - else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) + else if (inv->IsKindOf(NAME_Weapon)) { // The same goes for ammo from a weapon. static_cast(inv)->AmmoGive1 = int(static_cast(inv)->AmmoGive1 * dropammofactor); diff --git a/src/p_local.h b/src/p_local.h index 1143667f3..b63d28256 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -442,4 +442,15 @@ enum EDmgFlags // bool P_AlignFlat (int linenum, int side, int fc); +enum ETexReplaceFlags +{ + NOT_BOTTOM = 1, + NOT_MIDDLE = 2, + NOT_TOP = 4, + NOT_FLOOR = 8, + NOT_CEILING = 16 +}; + +void P_ReplaceTextures(const char *fromname, const char *toname, int flags); + #endif // __P_LOCAL__ diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8bfd013cc..6edbb41de 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -768,10 +768,12 @@ DEFINE_ACTION_FUNCTION(AActor, AddInventory) // //============================================================================ -bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) +bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat) { bool result = true; + if (type == nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL; bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true; @@ -904,7 +906,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // and infinite ammo is on if (notakeinfinite && ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; @@ -1147,10 +1149,12 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) // //============================================================================ -bool AActor::GiveAmmo (PClassInventory *type, int amount) +bool AActor::GiveAmmo (PClassActor *type, int amount) { if (type != NULL) { + if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AInventory *item = static_cast(Spawn (type)); if (item) { @@ -1543,7 +1547,7 @@ bool AActor::IsVisibleToPlayer() const bool visible = false; for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) { - PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i]; + auto cls = GetClass()->VisibleToPlayerClass[i]; if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { visible = true; @@ -3197,6 +3201,7 @@ void P_NightmareRespawn (AActor *mobj) // spawn it mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true); + mo->health = mobj->SpawnHealth(); if (z == ONFLOORZ) { @@ -7488,7 +7493,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) } -DDropItem *AActor::GetDropItems() const +FDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; } @@ -8096,16 +8101,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) // //---------------------------------------------------------------------------- -IMPLEMENT_CLASS(DDropItem, false, true) - -IMPLEMENT_POINTERS_START(DDropItem) -IMPLEMENT_POINTER(Next) -IMPLEMENT_POINTERS_END - -DEFINE_FIELD(DDropItem, Next) -DEFINE_FIELD(DDropItem, Name) -DEFINE_FIELD(DDropItem, Probability) -DEFINE_FIELD(DDropItem, Amount) +DEFINE_FIELD(FDropItem, Next) +DEFINE_FIELD(FDropItem, Name) +DEFINE_FIELD(FDropItem, Probability) +DEFINE_FIELD(FDropItem, Amount) void PrintMiscActorInfo(AActor *query) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index c443ca7da..bf6c79a82 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -166,7 +166,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) if (Next && Next->ID == ID && ID != 0) Next->Destroy(); // Replace it. - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + if (Caller->IsKindOf(NAME_Weapon) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST); } @@ -353,7 +353,7 @@ void DPSprite::SetState(FState *newstate, bool pending) } else if (!(newstate->UseFlags & SUF_WEAPON)) { - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (Caller->IsKindOf(NAME_Weapon)) { auto so = FState::StaticFindStateOwner(newstate); Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); @@ -1333,7 +1333,7 @@ void player_t::TickPSprites() // or if it's from an inventory item that the player no longer owns. if ((pspr->Caller == nullptr || (pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast(pspr->Caller)->Owner != pspr->Owner->mo) || - (pspr->Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && pspr->Caller != pspr->Owner->ReadyWeapon))) + (pspr->Caller->IsKindOf(NAME_Weapon) && pspr->Caller != pspr->Owner->ReadyWeapon))) { pspr->Destroy(); } diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index f9ca3128d..e898abef7 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -2121,6 +2121,63 @@ bool P_AlignFlat (int linenum, int side, int fc) return true; } + + +//========================================================================== +// +// P_ReplaceTextures +// +//========================================================================== + +void P_ReplaceTextures(const char *fromname, const char *toname, int flags) +{ + FTextureID picnum1, picnum2; + + if (fromname == nullptr) + return; + + if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0) + { + picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); + + for (auto &side : level.sides) + { + for (int j = 0; j<3; j++) + { + static uint8_t bits[] = { NOT_TOP, NOT_MIDDLE, NOT_BOTTOM }; + if (!(flags & bits[j]) && side.GetTexture(j) == picnum1) + { + side.SetTexture(j, picnum2); + } + } + } + } + if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0) + { + picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); + + for (auto &sec : level.sectors) + { + if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1) + sec.SetTexture(sector_t::floor, picnum2); + if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1) + sec.SetTexture(sector_t::ceiling, picnum2); + } + } +} + +DEFINE_ACTION_FUNCTION(_TexMan, ReplaceTextures) +{ + PARAM_PROLOGUE; + PARAM_STRING(from); + PARAM_STRING(to); + PARAM_INT(flags); + P_ReplaceTextures(from, to, flags); + return 0; +} + //========================================================================== // // P_BuildPolyBSP diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e6ab47c24..515905b27 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1097,7 +1097,7 @@ public: { ld->alpha = 0.75; } - if (strifetrans2 && ld->alpha == OPAQUE) + if (strifetrans2 && ld->alpha == 1.) { ld->alpha = 0.25; } diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d40c542a1..f4ebe5ebd 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -57,21 +57,23 @@ class USDFParser : public UDMFParserBase PClassActor *CheckActorType(const char *key) { + PClassActor *type = nullptr; if (namespace_bits == St) { - return GetStrifeType(CheckInt(key)); + type = GetStrifeType(CheckInt(key)); } else if (namespace_bits == Zd) { PClassActor *cls = PClass::FindActor(CheckString(key)); - if (cls == NULL) + if (cls == nullptr) { sc.ScriptMessage("Unknown actor class '%s'", key); - return NULL; + return nullptr; } - return cls; + type = cls; } - return NULL; + if (type && type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return type; + return nullptr; } //=========================================================================== @@ -92,7 +94,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Amount: @@ -266,7 +268,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Count: diff --git a/src/p_user.cpp b/src/p_user.cpp index 20904e699..dd7f181a8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -85,6 +85,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO P_PredictionLerpReset(); } +ColorSetList ColorSets; +PainFlashList PainFlashes; + struct PredictPos { int gametic; @@ -146,7 +149,7 @@ bool FPlayerClass::CheckSkin (int skin) // //=========================================================================== -FString GetPrintableDisplayName(PClassPlayerPawn *cls) +FString GetPrintableDisplayName(PClassActor *cls) { // Fixme; This needs a decent way to access the string table without creating a mess. // [RH] ???? @@ -165,7 +168,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) Printf("Invalid player class '%s'\n", name); return false; } - else if (static_cast(ti)->DisplayName.IsEmpty()) + else if (ti->DisplayName.IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", name); return false; @@ -184,7 +187,7 @@ void SetupPlayerClasses () if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) { newclass.Flags = 0; - newclass.Type = static_cast(cls); + newclass.Type = cls; if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU)) { newclass.Flags |= PCF_NOMENU; @@ -212,7 +215,7 @@ CCMD (addplayerclass) { FPlayerClass newclass; - newclass.Type = static_cast(ti); + newclass.Type = ti; newclass.Flags = 0; int arg = 2; @@ -535,61 +538,34 @@ int player_t::GetSpawnClass() //=========================================================================== // -// PClassPlayerPawn +// EnumColorsets +// +// Only used by the menu so it doesn't really matter that it's a bit +// inefficient. // //=========================================================================== -IMPLEMENT_CLASS(PClassPlayerPawn, false, false) - -PClassPlayerPawn::PClassPlayerPawn() -{ - for (size_t i = 0; i < countof(HexenArmor); ++i) - { - HexenArmor[i] = 0; - } - ColorRangeStart = 0; - ColorRangeEnd = 0; -} - -void PClassPlayerPawn::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - Super::DeriveData(newclass); - PClassPlayerPawn *newp = static_cast(newclass); - size_t i; - - newp->DisplayName = DisplayName; - newp->SoundClass = SoundClass; - newp->Face = Face; - newp->InvulMode = InvulMode; - newp->HealingRadiusType = HealingRadiusType; - newp->ColorRangeStart = ColorRangeStart; - newp->ColorRangeEnd = ColorRangeEnd; - newp->ColorSets = ColorSets; - for (i = 0; i < countof(HexenArmor); ++i) - { - newp->HexenArmor[i] = HexenArmor[i]; - } - for (i = 0; i < countof(Slot); ++i) - { - newp->Slot[i] = Slot[i]; - } -} - static int intcmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } -void PClassPlayerPawn::EnumColorSets(TArray *out) +void EnumColorSets(PClassActor *cls, TArray *out) { - out->Clear(); - FPlayerColorSetMap::Iterator it(ColorSets); - FPlayerColorSetMap::Pair *pair; + TArray deleteds; - while (it.NextPair(pair)) + out->Clear(); + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - out->Push(pair->Key); + if (std::get<0>(ColorSets[i])->IsAncestorOf(cls)) + { + int v = std::get<1>(ColorSets[i]); + if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size()) + { + if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v); + else out->Push(v); + } + } } qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); } @@ -599,20 +575,41 @@ void PClassPlayerPawn::EnumColorSets(TArray *out) // //========================================================================== -bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const +FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum) { - const PClassPlayerPawn *info = this; - - while (info != NULL) + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - const PalEntry *flash = info->PainFlashes.CheckKey(type); - if (flash != NULL) + if (std::get<1>(ColorSets[i]) == setnum && + std::get<0>(ColorSets[i])->IsAncestorOf(cls)) { - *color = *flash; + auto c = &std::get<2>(ColorSets[i]); + return c->Name != NAME_None ? c : nullptr; + } + } + return nullptr; +} + +//========================================================================== +// +// +//========================================================================== + +bool player_t::GetPainFlash(FName type, PalEntry *color) const +{ + PClass *info = mo->GetClass(); + + // go backwards through the list and return the first item with a + // matching damage type for an ancestor of our class. + // This will always return the best fit because any parent class + // must be processed before its children. + for (int i = PainFlashes.Size() - 1; i >= 0; i--) + { + if (std::get<1>(PainFlashes[i]) == type && + std::get<0>(PainFlashes[i])->IsAncestorOf(info)) + { + *color = std::get<2>(PainFlashes[i]); return true; } - // Try parent class - info = dyn_cast(info->ParentClass); } return false; } @@ -661,7 +658,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvSel) - IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTERS_END void APlayerPawn::Serialize(FSerializer &arc) @@ -953,7 +949,7 @@ bool APlayerPawn::UseInventory (AInventory *item) // //=========================================================================== -AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype) { AWeapon *bestMatch = NULL; int bestOrder = INT_MAX; @@ -964,7 +960,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // Find the best weapon the player has. for (item = Inventory; item != NULL; item = item->Inventory) { - if (!item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (!item->IsKindOf(NAME_Weapon)) continue; weap = static_cast (item); @@ -1015,7 +1011,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // //=========================================================================== -AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype) { AWeapon *best = BestWeapon (ammotype); @@ -1043,7 +1039,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) // //=========================================================================== -void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) +void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) { if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && @@ -1062,7 +1058,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) { PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_OBJECT(ammotype, PClassInventory); + PARAM_OBJECT(ammotype, PClassActor); self->CheckWeaponSwitch(ammotype); return 0; } @@ -1137,29 +1133,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) if ((dmflags & DF_COOP_LOSE_KEYS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_Key))) + item->IsKindOf(NAME_Key)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_WEAPONS) && defitem == NULL && - item->IsKindOf(RUNTIME_CLASS(AWeapon))) + item->IsKindOf(NAME_Weapon)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_ARMOR) && - item->IsKindOf(PClass::FindActor(NAME_Armor))) + item->IsKindOf(NAME_Armor)) { if (defitem == NULL) { item->Destroy(); } - else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor))) + else if (item->IsKindOf(NAME_BasicArmor)) { item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent); item->Amount = defitem->Amount; } - else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor))) + else if (item->IsKindOf(NAME_HexenArmor)) { double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr); double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr); @@ -1168,12 +1164,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) } else if ((dmflags & DF_COOP_LOSE_POWERUPS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_PowerupGiver))) + item->IsKindOf(NAME_PowerupGiver)) { item->Destroy(); } else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { if (defitem == NULL) { @@ -1230,8 +1226,8 @@ const char *APlayerPawn::GetSoundClass() const } // [GRB] - PClassPlayerPawn *pclass = GetClass(); - return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player"; + auto pclass = GetClass(); + return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } //=========================================================================== @@ -1368,16 +1364,16 @@ void APlayerPawn::GiveDefaultInventory () // HexenArmor must always be the first item in the inventory because // it provides player class based protection that should not affect // any other protection item. - PClassPlayerPawn *myclass = GetClass(); + auto myclass = GetClass(); GiveInventoryType(PClass::FindActor(NAME_HexenArmor)); auto harmor = FindInventory(NAME_HexenArmor); double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr); - Slots[4] = myclass->HexenArmor[0]; + Slots[4] = HexenArmor[0]; for (int i = 0; i < 4; ++i) { - SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + SlotsIncrement[i] = HexenArmor[i + 1]; } // BasicArmor must come right after that. It should not affect any @@ -1388,7 +1384,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - DDropItem *di = GetDropItems(); + auto di = GetDropItems(); while (di) { @@ -1413,7 +1409,7 @@ void APlayerPawn::GiveDefaultInventory () item = static_cast(Spawn(ti)); item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here item->Amount = di->Amount; - if (item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // To allow better control any weapon is emptied of // ammo before being given to the player. @@ -1433,7 +1429,7 @@ void APlayerPawn::GiveDefaultInventory () item = NULL; } } - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (item != NULL && item->IsKindOf(NAME_Weapon) && static_cast(item)->CheckAmmo(AWeapon::EitherFire, false)) { player->ReadyWeapon = player->PendingWeapon = static_cast (item); @@ -1518,7 +1514,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) AInventory *item; // kgDROP - start - modified copy from a_action.cpp - DDropItem *di = weap->GetDropItems(); + auto di = weap->GetDropItems(); if (di != NULL) { @@ -1537,7 +1533,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) weap->SpawnState != ::GetDefault()->SpawnState) { item = P_DropItem (this, weap->GetClass(), -1, 256); - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item != NULL && item->IsKindOf(NAME_Weapon)) { if (weap->AmmoGive1 && weap->Ammo1) { @@ -1710,9 +1706,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) player_t *player; // [GRB] Parameterized version - if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk"))) + if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk")) { - spawntype = dyn_cast(PClass::FindClass("BloodySkull")); + spawntype = PClass::FindActor("BloodySkull"); if (spawntype == NULL) return 0; } @@ -3249,18 +3245,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, FullHeight) -DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) -DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, SoundClass) -DEFINE_FIELD(PClassPlayerPawn, Face) -DEFINE_FIELD(PClassPlayerPawn, Portrait) -DEFINE_FIELD(PClassPlayerPawn, Slot) -DEFINE_FIELD(PClassPlayerPawn, InvulMode) -DEFINE_FIELD(PClassPlayerPawn, HexenArmor) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd) -DEFINE_FIELD(PClassPlayerPawn, ColorSets) -DEFINE_FIELD(PClassPlayerPawn, PainFlashes) +DEFINE_FIELD(APlayerPawn, HealingRadiusType) +DEFINE_FIELD(APlayerPawn, SoundClass) +DEFINE_FIELD(APlayerPawn, Face) +DEFINE_FIELD(APlayerPawn, Portrait) +DEFINE_FIELD(APlayerPawn, Slot) +DEFINE_FIELD(APlayerPawn, InvulMode) +DEFINE_FIELD(APlayerPawn, HexenArmor) +DEFINE_FIELD(APlayerPawn, ColorRangeStart) +DEFINE_FIELD(APlayerPawn, ColorRangeEnd) + +DEFINE_FIELD(PClassActor, DisplayName) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/portal.cpp b/src/portal.cpp index 43b7ef7b6..f354faa65 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor) unsigned i = level.sectorPortals.Reserve(1); memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; - level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY; + level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY; level.sectorPortals[i].mSkybox = actor; level.sectorPortals[i].mDestination = actor->Sector; return i; diff --git a/src/r_data/renderstyle.cpp b/src/r_data/renderstyle.cpp index 6e656f715..5c9dcc429 100644 --- a/src/r_data/renderstyle.cpp +++ b/src/r_data/renderstyle.cpp @@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha) switch (type) { case STYLEALPHA_Zero: return 0; - case STYLEALPHA_One: return OPAQUE; + case STYLEALPHA_One: return 1.; case STYLEALPHA_Src: return alpha; case STYLEALPHA_InvSrc: return 1. - alpha; default: return 0; diff --git a/src/r_data/renderstyle.h b/src/r_data/renderstyle.h index 501c14c5f..947f9afed 100644 --- a/src/r_data/renderstyle.h +++ b/src/r_data/renderstyle.h @@ -44,10 +44,6 @@ enum { OPAQUE = 65536, - TRANSLUC25 = (OPAQUE / 4), - TRANSLUC33 = (OPAQUE / 3), - TRANSLUC66 = ((OPAQUE * 2) / 3), - TRANSLUC75 = ((OPAQUE * 3) / 4), }; // Legacy render styles diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 7fb59ef94..c3f73760d 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -517,7 +517,7 @@ void R_InitSkins (void) int lastlump; int aliasid; bool remove; - PClassPlayerPawn *basetype, *transtype; + PClassActor *basetype, *transtype; key[sizeof(key)-1] = 0; i = PlayerClasses.Size () - 1; @@ -602,11 +602,11 @@ void R_InitSkins (void) else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); else if (gameinfo.gametype == GAME_Strife) - basetype = dyn_cast(PClass::FindActor(NAME_StrifePlayer)); + basetype = PClass::FindActor(NAME_StrifePlayer); else - basetype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_DoomPlayer); transtype = basetype; @@ -614,7 +614,7 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - transtype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + transtype = PClass::FindActor(NAME_HereticPlayer); skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) @@ -633,7 +633,7 @@ void R_InitSkins (void) { if (gameinfo.gametype == GAME_Heretic) { - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) @@ -709,12 +709,12 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - basetype = transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = transtype = PClass::FindActor(NAME_DoomPlayer); } else if (gameinfo.gametype == GAME_Heretic) { - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else @@ -725,18 +725,22 @@ void R_InitSkins (void) if (!remove) { - skins[i].range0start = transtype->ColorRangeStart; - skins[i].range0end = transtype->ColorRangeEnd; + auto transdef = ((APlayerPawn*)GetDefaultByType(transtype)); + auto basedef = ((APlayerPawn*)GetDefaultByType(basetype)); + + skins[i].range0start = transdef->ColorRangeStart; + skins[i].range0end = transdef->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { - PClassPlayerPawn *type = PlayerClasses[j].Type; + auto type = PlayerClasses[j].Type; + auto type_def = ((APlayerPawn*)GetDefaultByType(type)); if (type->IsDescendantOf (basetype) && GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && - type->ColorRangeStart == basetype->ColorRangeStart && - type->ColorRangeEnd == basetype->ColorRangeEnd) + type_def->ColorRangeStart == basedef->ColorRangeStart && + type_def->ColorRangeEnd == basedef->ColorRangeEnd) { PlayerClasses[j].Skins.Push ((int)i); remove = false; @@ -935,10 +939,10 @@ void R_InitSprites () memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) { // Assume Doom skin by default - PClassPlayerPawn *type = PlayerClasses[0].Type; + auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type)); skins[i].range0start = type->ColorRangeStart; skins[i].range0end = type->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (type)->Scale; + skins[i].Scale = type->Scale; } R_InitSpriteDefs (); @@ -950,11 +954,10 @@ void R_InitSprites () // [GRB] Each player class has its own base skin for (i = 0; i < PlayerClasses.Size (); i++) { - PClassPlayerPawn *basetype = PlayerClasses[i].Type; - FString classface = basetype->Face; + auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type)); strcpy (skins[i].name, "Base"); - if (classface.IsEmpty() || strcmp(classface, "None") == 0) + if (basetype->Face == NAME_None) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; @@ -963,12 +966,12 @@ void R_InitSprites () } else { - strcpy(skins[i].face, classface); + strcpy(skins[i].face, basetype->Face); } skins[i].range0start = basetype->ColorRangeStart; skins[i].range0end = basetype->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (basetype)->Scale; - skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; + skins[i].Scale = basetype->Scale; + skins[i].sprite = basetype->SpawnState->sprite; skins[i].namespc = ns_global; PlayerClasses[i].Skins.Push (i); diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 63ee8fbfb..15c68c3ab 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -338,8 +338,6 @@ void R_Init () { atterm (R_Shutdown); - StartScreen->Progress(); - V_InitFonts(); StartScreen->Progress(); // Colormap init moved back to InitPalette() //R_InitColormaps (); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 2c1354fe8..87374bf78 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -716,6 +716,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, { case SOURCE_None: default: + pos->Zero(); break; case SOURCE_Actor: diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/backend/codegen.cpp similarity index 97% rename from src/scripting/codegeneration/codegen.cpp rename to src/scripting/backend/codegen.cpp index a23811390..71ecfc58c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) { tag = ATAG_STATE; } - else if (value.Type->GetLoadOp() == OP_LO) + else if (value.Type->GetLoadOp() != OP_LP) { tag = ATAG_OBJECT; } @@ -1420,6 +1420,76 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build) return to; } +//========================================================================== +// +// +// +//========================================================================== + +FxFontCast::FxFontCast(FxExpression *x) + : FxExpression(EFX_FontCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeSound; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFontCast::~FxFontCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFontCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeFont) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + // This intentionally does not convert non-constants. + // The sole reason for this cast is to allow passing both font pointers and string constants to printing functions and have the font names checked at compile time. + else if ((basex->ValueType == TypeString || basex->ValueType == TypeName) && basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FFont *font = V_GetFont(constval.GetString()); + // Font must exist. Most internal functions working with fonts do not like null pointers. + // If checking is needed scripts will have to call Font.GetFont themselves. + if (font == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unknown font '%s'", constval.GetString().GetChars()); + delete this; + return nullptr; + } + + FxExpression *x = new FxConstant(font, ScriptPosition); + delete this; + return x; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to font"); + delete this; + return nullptr; + } +} + + //========================================================================== // // generic type cast operator @@ -1649,6 +1719,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) { goto basereturn; } + else if (ValueType == TypeFont) + { + FxExpression *x = new FxFontCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } // todo: pointers to class objects. // All other types are only compatible to themselves and have already been handled above by the equality check. // Anything that falls through here is not compatible and must print an error. @@ -6278,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ob.Free(build); ExpEmit meta(build, REGT_POINTER); build->Emit(OP_META, meta.RegNum, ob.RegNum); - build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; } @@ -6290,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) //========================================================================== FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) - : FxExpression(EFX_GlobalVariable, pos) + : FxMemberBase(EFX_GlobalVariable, mem, pos) { - membervar = mem; - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6470,11 +6545,8 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) //========================================================================== FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos) - : FxExpression(EFX_StackVariable, pos) + : FxMemberBase(EFX_StackVariable, new PField(NAME_None, type, 0, offset), pos) { - membervar = new PField(NAME_None, type, 0, offset); - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6486,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition FxStackVariable::~FxStackVariable() { - // Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap. membervar->ObjectFlags |= OF_YesReallyDelete; delete membervar; } -//========================================================================== -// -// -//========================================================================== - -void FxStackVariable::ReplaceField(PField *newfield) -{ - membervar->ObjectFlags |= OF_YesReallyDelete; - delete membervar; - membervar = newfield; -} - //========================================================================== // // @@ -6573,14 +6632,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) // // //========================================================================== +FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p) + :FxExpression(type, p), membervar(f) +{ +} + FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos) - : FxExpression(EFX_StructMember, pos) + : FxMemberBase(EFX_StructMember, mem, pos) { classx = x; - membervar = mem; - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6652,35 +6713,13 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) + if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable) { - auto parentfield = static_cast(classx)->membervar; + auto parentfield = static_cast(classx)->membervar; // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); newfield->BitValue = membervar->BitValue; - static_cast(classx)->membervar = newfield; - classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = classx->Resolve(ctx); - classx = nullptr; - return x; - } - else if (classx->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); - newfield->BitValue = membervar->BitValue; - static_cast(classx)->membervar = newfield; - classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = classx->Resolve(ctx); - classx = nullptr; - return x; - } - else if (classx->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); - newfield->BitValue = membervar->BitValue; - static_cast(classx)->ReplaceField(newfield); + static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); classx = nullptr; @@ -6868,33 +6907,41 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } - PArray *arraytype = dyn_cast(Array->ValueType); - if (arraytype == nullptr) + PArray *arraytype = nullptr; + PType *elementtype = nullptr; + if (Array->IsDynamicArray()) { - // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. - PPointer *ptype = dyn_cast(Array->ValueType); - if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) - { - ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); - delete this; - return nullptr; - } - arraytype = static_cast(ptype->PointedType); + PDynArray *darraytype = static_cast(Array->ValueType); + elementtype = darraytype->ElementType; + Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged. arrayispointer = true; } + else + { + arraytype = dyn_cast(Array->ValueType); + if (arraytype == nullptr) + { + // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. + PPointer *ptype = dyn_cast(Array->ValueType); + if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) + { + ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); + delete this; + return nullptr; + } + arraytype = static_cast(ptype->PointedType); + arrayispointer = true; + } + elementtype = arraytype->ElementType; + } if (Array->IsResizableArray()) { // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable) { - auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + parentfield->Type->Align; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + parentfield->Type->Align; + auto parentfield = static_cast(Array)->membervar; + SizeAddr = parentfield->Offset + sizeof(void*); } else { @@ -6903,54 +6950,32 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } } - else if (index->isConstant()) + // constant indices can only be resolved at compile time for statically sized arrays. + else if (index->isConstant() && arraytype != nullptr && !arrayispointer) { unsigned indexval = static_cast(index)->GetValue().GetInt(); - if (indexval >= arraytype->ElementCount && !Array->IsResizableArray()) + if (indexval >= arraytype->ElementCount) { ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); delete this; return nullptr; } - if (!arrayispointer) + // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable) { - // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) - { - auto parentfield = static_cast(Array)->membervar; - // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->ReplaceField(newfield); - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } + auto parentfield = static_cast(Array)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; } } - ValueType = arraytype->ElementType; + ValueType = elementtype; if (!Array->RequestAddress(ctx, &AddressWritable)) { ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); @@ -6989,17 +7014,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0)); auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr); - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) - { - static_cast(Array)->membervar = f; - static_cast(Array)->AddressRequested = false; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - static_cast(Array)->membervar = f; - static_cast(Array)->AddressRequested = false; - } - + static_cast(Array)->membervar = f; + static_cast(Array)->AddressRequested = false; Array->ValueType = TypeUInt32; bound = Array->Emit(build); } @@ -7726,6 +7742,70 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // same for String methods. It also uses a hidden struct type to define them. Self->ValueType = TypeStringStruct; } + else if (Self->IsDynamicArray()) + { + if (MethodName == NAME_Size) + { + FxExpression *x = new FxMemberIdentifier(Self, NAME_Size, ScriptPosition); // todo: obfuscate the name to prevent direct access. + Self = nullptr; + delete this; + return x->Resolve(ctx); + } + else + { + auto elementType = static_cast(Self->ValueType)->ElementType; + Self->ValueType = static_cast(Self->ValueType)->BackingType; + // this requires some added type checks for the passed types. + for (auto &a : ArgList) + { + a = a->Resolve(ctx); + if (a == nullptr) + { + delete this; + return nullptr; + } + if (a->IsDynamicArray()) + { + // Copy and Move must turn their parameter into a pointer to the backing struct type. + auto backingtype = static_cast(a->ValueType)->BackingType; + if (elementType != static_cast(a->ValueType)->ElementType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + bool writable; + if (!a->RequestAddress(ctx, &writable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference array variable"); + delete this; + return nullptr; + } + a->ValueType = NewPointer(backingtype); + + // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable) + { + auto member = static_cast(Self); + auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); + member->membervar = newfield; + } + } + else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + // the only case which must be checked up front is for pointer arrays receiving a new element. + // Since there is only one native backing class it uses a neutral void pointer as its argument, + // meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here. + if (a->ValueType != elementType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), elementType->DescriptiveName()); + delete this; + return nullptr; + } + } + } + } + } else if (Self->IsArray()) { if (MethodName == NAME_Size) @@ -7748,19 +7828,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else { // Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator. - if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_GlobalVariable) { - auto member = static_cast(Self); - auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer. - member->membervar = newfield; - Self = nullptr; - delete this; - member->ValueType = TypeUInt32; - return member; - } - else if (Self->ExprType == EFX_GlobalVariable) - { - auto member = static_cast(Self); + auto member = static_cast(Self); auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer. member->membervar = newfield; Self = nullptr; @@ -7793,7 +7863,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return x->Resolve(ctx); } - if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) @@ -8791,7 +8861,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) op.Free(build); } ExpEmit to(build, REGT_POINTER); - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); return to; } @@ -8863,7 +8933,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) build->Emit(OP_LKP, to.RegNum, op.RegNum); op = to; } - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return to; } @@ -10600,8 +10670,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) case REGT_POINTER: { - bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC)); break; } case REGT_STRING: @@ -10741,7 +10810,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) { TArray cvalues; for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); - StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC); break; } } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/backend/codegen.h similarity index 98% rename from src/scripting/codegeneration/codegen.h rename to src/scripting/backend/codegen.h index 69ad192f5..abbcbd54e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/backend/codegen.h @@ -294,6 +294,7 @@ enum EFxType EFX_StrLen, EFX_ColorLiteral, EFX_GetDefaultByType, + EFX_FontCast, EFX_COUNT }; @@ -332,6 +333,7 @@ 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)); } bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form. + bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } virtual ExpEmit Emit(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build); @@ -488,6 +490,13 @@ public: isresolved = true; } + FxConstant(FFont *state, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = state; + ValueType = value.Type = TypeFont; + isresolved = true; + } + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = nullptr; @@ -664,6 +673,18 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxFontCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxFontCast(FxExpression *x); + ~FxFontCast(); + FxExpression *Resolve(FCompileContext&); +}; + + //========================================================================== // // FxTypeCast @@ -1293,19 +1314,30 @@ public: }; +//========================================================================== +// +// FxMemberBase +// +//========================================================================== + +class FxMemberBase : public FxExpression +{ +public: + PField *membervar; + bool AddressRequested = false; + bool AddressWritable = true; + FxMemberBase(EFxType type, PField *f, const FScriptPosition &p); +}; + //========================================================================== // // FxGlobalVariaböe // //========================================================================== -class FxGlobalVariable : public FxExpression +class FxGlobalVariable : public FxMemberBase { public: - PField *membervar; - bool AddressRequested; - bool AddressWritable; - FxGlobalVariable(PField*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); @@ -1322,19 +1354,17 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; + //========================================================================== // // FxClassMember // //========================================================================== -class FxStructMember : public FxExpression +class FxStructMember : public FxMemberBase { public: FxExpression *classx; - PField *membervar; - bool AddressRequested; - bool AddressWritable; FxStructMember(FxExpression*, PField*, const FScriptPosition&); ~FxStructMember(); @@ -1382,16 +1412,11 @@ public: // //========================================================================== -class FxStackVariable : public FxExpression +class FxStackVariable : public FxMemberBase { public: - PField *membervar; - bool AddressRequested; - bool AddressWritable; - FxStackVariable(PType *type, int offset, const FScriptPosition&); ~FxStackVariable(); - void ReplaceField(PField *newfield); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp similarity index 99% rename from src/scripting/codegeneration/dynarrays.cpp rename to src/scripting/backend/dynarrays.cpp index 05e18a3ca..0152c6520 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/backend/dynarrays.cpp @@ -1,10 +1,10 @@ /* ** dynarray.cpp ** -** Compiler backend / code generation for dynamic arrays +** internal data types for dynamic arrays ** **--------------------------------------------------------------------------- -** Copyright 2016 Christoph Oelckers +** Copyright 2016-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp similarity index 99% rename from src/scripting/vm/vmbuilder.cpp rename to src/scripting/backend/vmbuilder.cpp index 19fe81c32..74f845248 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -32,7 +32,7 @@ */ #include "vmbuilder.h" -#include "codegeneration/codegen.h" +#include "codegen.h" #include "info.h" #include "m_argv.h" #include "thingdef.h" diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/backend/vmbuilder.h similarity index 100% rename from src/scripting/vm/vmbuilder.h rename to src/scripting/backend/vmbuilder.h diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/backend/vmdisasm.cpp similarity index 100% rename from src/scripting/vm/vmdisasm.cpp rename to src/scripting/backend/vmdisasm.cpp diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 5861138d6..50e8f9c6a 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -47,7 +47,7 @@ #include "decallib.h" #include "i_system.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "r_data/r_translate.h" // TYPES ------------------------------------------------------------------- @@ -541,7 +541,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - static_cast(bag.Info)->PickupMsg = sc.String; + bag.Info->PickupMsg = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 2b0866dd8..6757a2382 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -49,7 +49,7 @@ #include "thingdef.h" #include "p_lnspec.h" #include "doomstat.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" FRandom pr_exrandom ("EX_Random"); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 505585937..23ffc48e8 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -49,7 +49,7 @@ #include "v_palette.h" #include "doomerrors.h" #include "i_system.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "w_wad.h" #include "v_video.h" #include "version.h" @@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns) } try { - info->Finalize(bag.statedef); + GetDefaultByType(info)->Finalize(bag.statedef); } catch (CRecoverableError &err) { diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 8e08fc038..63269eeeb 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -53,10 +53,10 @@ #include "s_sound.h" #include "i_system.h" #include "colormatcher.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "version.h" #include "templates.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" //========================================================================== //*** diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp new file mode 100644 index 000000000..b6adb33e7 --- /dev/null +++ b/src/scripting/symbols.cpp @@ -0,0 +1,406 @@ +/* +** symbols.cpp +** Implements the symbol types and symbol table +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2006-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "dobject.h" +#include "i_system.h" + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FNamespaceManager Namespaces; + +// Symbol tables ------------------------------------------------------------ + +IMPLEMENT_CLASS(PTypeBase, true, false); +IMPLEMENT_CLASS(PSymbol, true, false); +IMPLEMENT_CLASS(PSymbolConst, false, false); +IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); +IMPLEMENT_CLASS(PSymbolConstString, false, false); +IMPLEMENT_CLASS(PSymbolTreeNode, false, false) +IMPLEMENT_CLASS(PSymbolType, false, false) +IMPLEMENT_CLASS(PSymbolVMFunction, false, false) +IMPLEMENT_CLASS(PFunction, false, false) +IMPLEMENT_CLASS(PNamespace, false, true) + +IMPLEMENT_POINTERS_START(PNamespace) +IMPLEMENT_POINTER(Parent) +IMPLEMENT_POINTERS_END + + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolConstString::PSymbolConstString(FName name, const FString &str) + : PSymbolConst(name, TypeString), Str(str) +{ +} + +//========================================================================== +// +// PFunction :: AddVariant +// +// Adds a new variant for this function. Does not check if a matching +// variant already exists. +// +//========================================================================== + +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) +{ + Variant variant; + + // I do not think we really want to deal with overloading here... + assert(Variants.Size() == 0); + + variant.Flags = flags; + variant.UseFlags = useflags; + variant.Proto = proto; + variant.ArgFlags = std::move(argflags); + variant.ArgNames = std::move(argnames); + variant.Implementation = impl; + if (impl != nullptr) impl->Proto = proto; + + // SelfClass can differ from OwningClass, but this is variant-dependent. + // Unlike the owner there can be cases where different variants can have different SelfClasses. + // (Of course only if this ever gets enabled...) + if (flags & VARF_Method) + { + assert(proto->ArgumentTypes.Size() > 0); + auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); + assert(selftypeptr != nullptr); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); + assert(variant.SelfClass != nullptr); + } + else + { + variant.SelfClass = nullptr; + } + + return Variants.Push(variant); +} + +//========================================================================== +// +// +// +//========================================================================== + +int PFunction::GetImplicitArgs() +{ + if (Variants[0].Flags & VARF_Action) return 3; + else if (Variants[0].Flags & VARF_Method) return 1; + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolTable::PSymbolTable() +: ParentSymbolTable(nullptr) +{ +} + +PSymbolTable::PSymbolTable(PSymbolTable *parent) +: ParentSymbolTable(parent) +{ +} + +PSymbolTable::~PSymbolTable () +{ + ReleaseSymbols(); +} + +//========================================================================== +// +// this must explicitly delete all content because the symbols have +// been released from the GC. +// +//========================================================================== + +void PSymbolTable::ReleaseSymbols() +{ + auto it = GetIterator(); + MapType::Pair *pair; + while (it.NextPair(pair)) + { + delete pair->Value; + } + Symbols.Clear(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::SetParentTable (PSymbolTable *parent) +{ + ParentSymbolTable = parent; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbol(symname, searchparents); + } + return value != nullptr ? *value : nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr) + { + if (ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbolInTable(symname, symtable); + } + symtable = nullptr; + return nullptr; + } + symtable = this; + return *value; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) +{ + // Symbols that already exist are not inserted. + if (Symbols.CheckKey(sym->SymbolName) != nullptr) + { + return nullptr; + } + Symbols.Insert(sym->SymbolName, sym); + sym->Release(); // no more GC, please! + return sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::RemoveSymbol(PSymbol *sym) +{ + auto mysym = Symbols.CheckKey(sym->SymbolName); + if (mysym == nullptr || *mysym != sym) return; + Symbols.Remove(sym->SymbolName); + delete sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::ReplaceSymbol(PSymbol *newsym) +{ + // If a symbol with a matching name exists, take its place and return it. + PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); + if (symslot != nullptr) + { + PSymbol *oldsym = *symslot; + delete oldsym; + *symslot = newsym; + } + // Else, just insert normally and return nullptr since there was no + // symbol to replace. + newsym->Release(); // no more GC, please! + Symbols.Insert(newsym->SymbolName, newsym); +} + +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace::PNamespace(int filenum, PNamespace *parent) +{ + Parent = parent; + if (parent) Symbols.SetParentTable(&parent->Symbols); + FileNum = filenum; +} + +//========================================================================== +// +// +// +//========================================================================== + +FNamespaceManager::FNamespaceManager() +{ + GlobalNamespace = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace *FNamespaceManager::NewNamespace(int filenum) +{ + PNamespace *parent = nullptr; + // The parent will be the last namespace with this or a lower filenum. + // This ensures that DECORATE won't see the symbols of later files. + for (int i = AllNamespaces.Size() - 1; i >= 0; i--) + { + if (AllNamespaces[i]->FileNum <= filenum) + { + parent = AllNamespaces[i]; + break; + } + } + auto newns = new PNamespace(filenum, parent); + AllNamespaces.Push(newns); + return newns; +} + +//========================================================================== +// +// +// +//========================================================================== + +size_t FNamespaceManager::MarkSymbols() +{ + for (auto ns : AllNamespaces) + { + GC::Mark(ns); + } + return AllNamespaces.Size(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FNamespaceManager::ReleaseSymbols() +{ + RemoveSymbols(); + GlobalNamespace = nullptr; + AllNamespaces.Clear(); +} + +//========================================================================== +// +// removes all symbols from the symbol tables. +// After running the compiler these are not needed anymore. +// Only the namespaces themselves are kept because the type table references them. +// +//========================================================================== + +int FNamespaceManager::RemoveSymbols() +{ + int count = 0; + for (auto ns : AllNamespaces) + { + count += ns->Symbols.Symbols.CountUsed(); + ns->Symbols.ReleaseSymbols(); + } + return count; +} + +//========================================================================== +// +// Clean out all compiler-only data from the symbol tables +// +//========================================================================== + +void RemoveUnusedSymbols() +{ + // Global symbols are not needed anymore after running the compiler. + int count = Namespaces.RemoveSymbols(); + + // We do not need any non-field and non-function symbols in structs and classes anymore. + // struct/class fields and functions are still needed so that the game can access the script data, + // but all the rest serves no purpose anymore and can be entirely removed. + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) + { + if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) + { + auto it = ty->Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) + { + ty->Symbols.RemoveSymbol(pair->Value); + count++; + } + } + } + } + } + DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); +} diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h new file mode 100644 index 000000000..3c9d1f8f3 --- /dev/null +++ b/src/scripting/symbols.h @@ -0,0 +1,272 @@ +// Note: This must not be included by anything but dobject.h! +#pragma once + +#ifndef __DOBJECT_H__ +#error You must #include "dobject.h" to get symbols.h +#endif + + +class VMFunction; +class PType; +class PPrototype; +struct ZCC_TreeNode; +class PStruct; + +// Symbol information ------------------------------------------------------- + +class PTypeBase : public DObject +{ + DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) + +public: +}; + +class PSymbol : public DObject +{ + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); +public: + FName SymbolName; + +protected: + PSymbol(FName name) { SymbolName = name; } +}; + +// A VM function ------------------------------------------------------------ + +class PSymbolVMFunction : public PSymbol +{ + DECLARE_CLASS(PSymbolVMFunction, PSymbol); +public: + VMFunction *Function; + + PSymbolVMFunction(FName name) : PSymbol(name) {} + PSymbolVMFunction() : PSymbol(NAME_None) {} +}; + +// A symbol for a type ------------------------------------------------------ + +class PSymbolType : public PSymbol +{ + DECLARE_CLASS(PSymbolType, PSymbol); +public: + PType *Type; + + PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} + PSymbolType() : PSymbol(NAME_None) {} +}; + +// A symbol for a compiler tree node ---------------------------------------- + +class PSymbolTreeNode : public PSymbol +{ + DECLARE_CLASS(PSymbolTreeNode, PSymbol); +public: + struct ZCC_TreeNode *Node; + + PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} + PSymbolTreeNode() : PSymbol(NAME_None) {} +}; + +// Struct/class fields ------------------------------------------------------ + +// A PField describes a symbol that takes up physical space in the struct. +class PField : public PSymbol +{ + DECLARE_CLASS(PField, PSymbol); + HAS_OBJECT_POINTERS +public: + PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0); + + size_t Offset; + PType *Type; + uint32_t Flags; + int BitValue; +protected: + PField(); +}; + +// Properties ------------------------------------------------------ + +// For setting properties in class defaults. +class PProperty : public PSymbol +{ + DECLARE_CLASS(PProperty, PSymbol); +public: + PProperty(FName name, TArray &variables); + + TArray Variables; + +protected: + PProperty(); +}; + +class PPropFlag : public PSymbol +{ + DECLARE_CLASS(PPropFlag, PSymbol); +public: + PPropFlag(FName name, PField *offset, int bitval); + + PField *Offset; + int bitval; + +protected: + PPropFlag(); +}; + +// A constant value --------------------------------------------------------- + +class PSymbolConst : public PSymbol +{ + DECLARE_CLASS(PSymbolConst, PSymbol); +public: + PType *ValueType; + + PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} + PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} +}; + +// A constant numeric value ------------------------------------------------- + +class PSymbolConstNumeric : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); +public: + union + { + int Value; + double Float; + void *Pad; + }; + + PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} + PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} + PSymbolConstNumeric() {} +}; + +// A constant string value -------------------------------------------------- + +class PSymbolConstString : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstString, PSymbolConst); +public: + FString Str; + + PSymbolConstString(FName name, const FString &str); + PSymbolConstString() {} +}; + + +// A function for the VM -------------------------------------------------- + +// TBD: Should we really support overloading? +class PFunction : public PSymbol +{ + DECLARE_CLASS(PFunction, PSymbol); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes + TArray ArgNames; // we need the names to access them later when the function gets compiled. + uint32_t Flags; + int UseFlags; + PStruct *SelfClass; + }; + TArray Variants; + PStruct *OwningClass = nullptr; + + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); + int GetImplicitArgs(); + + PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} +}; + +// A symbol table ----------------------------------------------------------- + +struct PSymbolTable +{ + PSymbolTable(); + PSymbolTable(PSymbolTable *parent); + ~PSymbolTable(); + + // Sets the table to use for searches if this one doesn't contain the + // requested symbol. + void SetParentTable (PSymbolTable *parent); + PSymbolTable *GetParentTable() const + { + return ParentSymbolTable; + } + + // Finds a symbol in the table, optionally searching parent tables + // as well. + PSymbol *FindSymbol (FName symname, bool searchparents) const; + + // Like FindSymbol with searchparents set true, but also returns the + // specific symbol table the symbol was found in. + PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); + + + // Places the symbol in the table and returns a pointer to it or NULL if + // a symbol with the same name is already in the table. This symbol is + // not copied and will be freed when the symbol table is destroyed. + PSymbol *AddSymbol (PSymbol *sym); + + // Similar to AddSymbol but always succeeds. Returns the symbol that used + // to be in the table with this name, if any. + void ReplaceSymbol(PSymbol *sym); + + void RemoveSymbol(PSymbol *sym); + + // Frees all symbols from this table. + void ReleaseSymbols(); + + typedef TMap MapType; + + MapType::Iterator GetIterator() + { + return MapType::Iterator(Symbols); + } + +private: + + PSymbolTable *ParentSymbolTable; + MapType Symbols; + + friend class DObject; + friend struct FNamespaceManager; +}; + +// Namespaces -------------------------------------------------- + +class PNamespace : public PTypeBase +{ + DECLARE_CLASS(PNamespace, PTypeBase) + HAS_OBJECT_POINTERS; + +public: + PSymbolTable Symbols; + PNamespace *Parent; + int FileNum; // This is for blocking DECORATE access to later files. + + PNamespace() {} + PNamespace(int filenum, PNamespace *parent); +}; + +struct FNamespaceManager +{ + PNamespace *GlobalNamespace; + TArray AllNamespaces; + + FNamespaceManager(); + PNamespace *NewNamespace(int filenum); + size_t MarkSymbols(); + void ReleaseSymbols(); + int RemoveSymbols(); +}; + +extern FNamespaceManager Namespaces; + + diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 6776e70e8..a43c741ce 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -60,9 +60,9 @@ #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "a_sharedglobal.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "stats.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -246,7 +246,7 @@ static void CheckForUnsafeStates(PClassActor *obj) TMap checked; ENamedName *test; - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. test = weaponstates; @@ -336,11 +336,11 @@ static void CheckStates(PClassActor *obj) CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites"); - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites"); } - else if (obj->IsDescendantOf(PClass::FindActor(NAME_CustomInventory))) + else if (obj->IsDescendantOf(NAME_CustomInventory)) { CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); } @@ -396,8 +396,9 @@ void LoadActors() { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; - DObject::StaticPointerSubstitution(ti, nullptr); - PClassActor::AllActorClasses.Delete(i); + // the class must be rendered harmless so that it won't cause problems. + ti->ParentClass = RUNTIME_CLASS(AActor); + ti->Size = sizeof(AActor); } else { diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 37c247cbe..5558ffe3f 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state); // Extra info maintained while defining an actor. // //========================================================================== -class DDropItem; +struct FDropItem; struct Baggage { @@ -126,7 +126,7 @@ struct Baggage int Lumpnum; FStateDefinitions statedef; - DDropItem *DropItemList; + FDropItem *DropItemList; FScriptPosition ScriptPosition; }; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9c36f0e49..97f6ae10b 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1136,4 +1136,40 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret); (*self) += s; return 0; -} \ No newline at end of file +} + +DEFINE_ACTION_FUNCTION(FStringStruct, Mid) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(pos); + PARAM_UINT(len); + FString s = self->Mid(pos, len); + ACTION_RETURN_STRING(s); +} + +DEFINE_ACTION_FUNCTION(FStringStruct, Len) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_INT((int)self->Len()); +} + +// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. +DEFINE_ACTION_FUNCTION(FStringStruct, CharAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + int slen = (int)self->Len(); + if (pos < 0 || pos >= slen) + ACTION_RETURN_STRING(""); + ACTION_RETURN_STRING(FString((*self)[pos])); +} + +DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + int slen = (int)self->Len(); + if (pos < 0 || pos >= slen) + ACTION_RETURN_INT(0); + ACTION_RETURN_INT((*self)[pos]); +} diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 682300147..50b81310c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -66,9 +66,10 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" +#include "d_player.h" //========================================================================== // @@ -97,7 +98,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); + return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); } static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { @@ -560,7 +561,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) return; } - memcpy ((void *)defaults, (void *)GetDefault(), sizeof(AActor)); + *defaults = *GetDefault(); ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } @@ -920,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = type; di->Probability = 255; @@ -938,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor) //========================================================================== DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) { - static_cast(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) - static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1713,12 +1713,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) { - static_cast(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) - static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1734,31 +1734,47 @@ DEFINE_CLASS_PROPERTY(amount, I, Inventory) //========================================================================== // //========================================================================== -DEFINE_CLASS_PROPERTY(icon, S, Inventory) +static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) { - PROP_STRING_PARM(i, 0); - if (i == NULL || i[0] == '\0') { - defaults->Icon.SetNull(); + icon.SetNull(); } else { - defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); - if (!defaults->Icon.isValid()) + icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); + if (!icon.isValid()) { // Don't print warnings if the item is for another game or if this is a shareware IWAD. // Strife's teaser doesn't contain all the icon graphics of the full game. - if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) && + if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars()); + "Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars()); } } } } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(icon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->Icon, bag, i); +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(althudicon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->AltHUDIcon, bag, i); +} + //========================================================================== // //========================================================================== @@ -1801,8 +1817,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->PickupMsg = str; + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->PickupMsg = str; } //========================================================================== @@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->GiveQuest = i; + defaults->GiveQuest = i; } //========================================================================== @@ -2065,8 +2080,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotNumber = i; + defaults->SlotNumber = i; } //========================================================================== @@ -2075,8 +2089,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotPriority = int(i*65536); + defaults->SlotPriority = int(i*65536); } //========================================================================== @@ -2098,9 +2111,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) int alpha; PalEntry *pBlendColor; - bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)); + bool isgiver = info->IsDescendantOf(NAME_PowerupGiver); - if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver) + if (info->IsDescendantOf(NAME_Powerup) || isgiver) { pBlendColor = &defaults->ColorVar(NAME_BlendColor); } @@ -2150,7 +2163,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) { PalEntry BlendColor; - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n"); return; @@ -2185,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n"); return; @@ -2200,7 +2213,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n"); return; @@ -2216,7 +2229,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory) { PROP_STRING_PARM(str, 0); - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n"); return; @@ -2263,8 +2276,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->DisplayName = str; + info->DisplayName = str; } //========================================================================== @@ -2276,8 +2288,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->SoundClass = tmp; + defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None; } //========================================================================== @@ -2288,21 +2299,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) PROP_STRING_PARM(str, 0); FString tmp = str; - tmp.ToUpper(); - bool valid = (tmp.Len() == 3 && - (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && - (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && - (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) - ); - if (!valid) + if (tmp.Len() == 0) defaults->Face = NAME_None; + else { - bag.ScriptPosition.Message(MSG_OPTERROR, - "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", - tmp.GetChars(), info->TypeName.GetChars ()); + tmp.ToUpper(); + bool valid = (tmp.Len() == 3 && + (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && + (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && + (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) + ); + if (!valid) + { + bag.ScriptPosition.Message(MSG_OPTERROR, + "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", + tmp.GetChars(), info->TypeName.GetChars()); + } + defaults->Face = tmp; } - - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->Face = tmp; } //========================================================================== @@ -2316,9 +2329,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swapvalues (start, end); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorRangeStart = start; - static_cast(info)->ColorRangeEnd = end; + defaults->ColorRangeStart = start; + defaults->ColorRangeEnd = end; } //========================================================================== @@ -2373,8 +2385,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2400,8 +2411,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2418,8 +2428,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Remove(setnum); + FPlayerColorSet color; + memset(&color, 0, sizeof(color)); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2653,8 +2664,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->PainFlashes.Insert(type, color); + PainFlashes.Push(std::make_tuple(info, type, color)); } } @@ -2674,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = str; di->Probability = 255; @@ -2686,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -2695,8 +2704,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->InvulMode = str; + defaults->InvulMode = str; } //========================================================================== @@ -2705,8 +2713,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->HealingRadiusType = str; + defaults->HealingRadiusType = str; } //========================================================================== @@ -2714,11 +2721,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); for (int i = 0; i < 5; i++) { PROP_DOUBLE_PARM(val, i); - static_cast(info)->HexenArmor[i] = val; + defaults->HexenArmor[i] = val; } } @@ -2727,9 +2733,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PROP_STRING_PARM(val, 0); - static_cast(info)->Portrait = val; + defaults->Portrait = val; } //========================================================================== @@ -2739,7 +2744,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss { PROP_INT_PARM(slot, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); if (slot < 0 || slot > 9) { I_Error("Slot must be between 0 and 9."); @@ -2753,7 +2757,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - static_cast(info)->Slot[slot] = &weapons[1]; + defaults->Slot[slot] = weapons.IsEmpty()? NAME_None : FName(weapons); } } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 1a5c10b4e..36619ef5b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -6,6 +6,9 @@ #include "vectors.h" #include "cmdlib.h" #include "doomerrors.h" +#include "memarena.h" + +extern FMemArena ClassDataAllocator; #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 @@ -693,10 +696,8 @@ do_double: if (inexact) } }; -class VMFunction : public DObject +class VMFunction { - DECLARE_ABSTRACT_CLASS(VMFunction, DObject); - HAS_OBJECT_POINTERS; public: bool Native; bool Final = false; // cannot be overridden @@ -709,7 +710,29 @@ public: class PPrototype *Proto; - VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} + VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) + { + AllFunctions.Push(this); + } + virtual ~VMFunction() {} + + void *operator new(size_t size) + { + return ClassDataAllocator.Alloc(size); + } + + void operator delete(void *block) {} + void operator delete[](void *block) {} + static void DeleteAll() + { + for (auto f : AllFunctions) + { + f->~VMFunction(); + } + AllFunctions.Clear(); + } + static TArray AllFunctions; +protected: }; // VM frame layout: @@ -838,11 +861,9 @@ struct FStatementInfo class VMScriptFunction : public VMFunction { - DECLARE_CLASS(VMScriptFunction, VMFunction); public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); - size_t PropagateMark(); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } @@ -910,7 +931,6 @@ private: class VMNativeFunction : public VMFunction { - DECLARE_CLASS(VMNativeFunction, VMFunction); public: typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); @@ -997,6 +1017,7 @@ void NullParam(const char *varname); // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; #define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; #define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; @@ -1040,6 +1061,7 @@ void NullParam(const char *varname); #define PARAM_PROLOGUE int paramnum = -1; #define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x) #define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) #define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) #define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 38dbbc411..b9f8e81ca 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -347,6 +347,17 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(void **)ptr = reg.a[B]; NEXTOP; + OP(SO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; + OP(SO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; OP(SV2): ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index c44fbb2ea..d5eaed5bd 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -42,14 +42,9 @@ cycle_t VMCycles[10]; int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -IMPLEMENT_CLASS(VMFunction, true, true) -IMPLEMENT_POINTERS_START(VMFunction) - IMPLEMENT_POINTER(Proto) -IMPLEMENT_POINTERS_END +TArray VMFunction::AllFunctions; -IMPLEMENT_CLASS(VMScriptFunction, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { @@ -87,7 +82,6 @@ VMScriptFunction::~VMScriptFunction() KonstS[i].~FString(); } } - M_Free(Code); } } @@ -100,7 +94,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535); - void *mem = M_Malloc(numops * sizeof(VMOP) + + void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + @@ -166,24 +160,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko NumKonstA = numkonsta; } -size_t VMScriptFunction::PropagateMark() -{ - if (KonstA != NULL) - { - FVoidObj *konsta = KonstA; - VM_UBYTE *atag = KonstATags(); - for (int count = NumKonstA; count > 0; --count) - { - if (*atag++ == ATAG_OBJECT) - { - GC::Mark(konsta->o); - } - konsta++; - } - } - return NumKonstA * sizeof(void *) + Super::PropagateMark(); -} - void VMScriptFunction::InitExtra(void *addr) { char *caddr = (char*)addr; diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3fc3d7643..7128f1e43 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string xx(SS_R, ss, RPRSRI, NOP, 0, 0), xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types +xx(SO_R, sp, RPRPRI, NOP, 0, 0), xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 610e7554d..4972e1344 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -48,7 +48,7 @@ #include "p_lnspec.h" #include "i_system.h" #include "gdtoa.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "version.h" static int GetIntConst(FxExpression *ex, FCompileContext &ctx) @@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n case AST_DynArrayType: if (allowarraytypes) { - Error(field, "%s: Dynamic array types not implemented yet", name.GetChars()); auto atype = static_cast(ztype); - retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false)); + auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); + if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) + { + Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + } + else + { + retval = NewDynArray(ftype); + } break; } break; @@ -2440,19 +2447,6 @@ void ZCCCompiler::CompileStates() continue; } - // Same here, hack in the DVMObject as they weren't in the list originally - // TODO: process them in a non hackish way obviously - if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false) - { - auto vmtype = static_cast(c->Type()->ParentClass); - if (vmtype->StateList == nullptr) - { - FStateDefinitions vmstates; - vmstates.MakeStateDefines(dyn_cast(vmtype->ParentClass)); - vmtype->Finalize(vmstates); - } - } - FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; statedef.MakeStateDefines(dyn_cast(c->Type()->ParentClass)); @@ -2651,7 +2645,7 @@ void ZCCCompiler::CompileStates() } try { - static_cast(c->Type())->Finalize(statedef); + GetDefaultByType(c->Type())->Finalize(statedef); } catch (CRecoverableError &err) { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index a14443b7d..dc5fea565 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -2,7 +2,7 @@ #define ZCC_COMPILE_H #include -#include "codegeneration/codegen.h" +#include "backend/codegen.h" struct Baggage; struct FPropertyInfo; diff --git a/src/serializer.cpp b/src/serializer.cpp index 6d7a6ef7c..a577056af 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -2187,17 +2187,17 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon { if (arc.isWriting()) { - const char *n = font->GetName(); - return arc.StringPtr(key, n); + FName n = font->GetName(); + return arc(key, n); } else { - const char *n; - arc.StringPtr(key, n); + FName n; + arc(key, n); font = V_GetFont(n); if (font == nullptr) { - Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n); + Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n.GetChars()); font = SmallFont; } return arc; diff --git a/src/serializer.h b/src/serializer.h index e4dc8f226..4f0d90cec 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -246,11 +246,6 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); -template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, PClassPlayerPawn *&clst, PClassPlayerPawn **def) -{ - return Serialize(arc, key, (PClassActor *&)clst, (PClassActor **)def); -} - FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) { diff --git a/src/v_blend.cpp b/src/v_blend.cpp index ffc16cd5c..41e6fe7ff 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } PalEntry painFlash = CPlayer->mo->DamageFade; - CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); + CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) { diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 1a2e39434..723db6917 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -124,12 +124,12 @@ static int PalFromRGB(uint32 rgb) void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...) { - va_list tags; - va_start(tags, tags_first); + Va_List tags; + va_start(tags.list, tags_first); DrawParms parms; bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false); - va_end(tags); + va_end(tags.list); if (!res) { return; @@ -137,7 +137,7 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, .. DrawTextureParms(img, parms); } -static int ListGetInt(VMVa_List &tags); +int ListGetInt(VMVa_List &tags); void DCanvas::DrawTexture(FTexture *img, double x, double y, VMVa_List &args) { @@ -452,37 +452,37 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double return false; } -static void ListEnd(va_list &tags) +static void ListEnd(Va_List &tags) { - va_end(tags); + va_end(tags.list); } -static int ListGetInt(va_list &tags) +static int ListGetInt(Va_List &tags) { - return va_arg(tags, int); + return va_arg(tags.list, int); } -static inline double ListGetDouble(va_list &tags) +static inline double ListGetDouble(Va_List &tags) { - return va_arg(tags, double); + return va_arg(tags.list, double); } // These two options are only being used by the D3D version of the HUD weapon drawer, they serve no purpose anywhere else. -static inline FSpecialColormap * ListGetSpecialColormap(va_list &tags) +static inline FSpecialColormap * ListGetSpecialColormap(Va_List &tags) { - return va_arg(tags, FSpecialColormap *); + return va_arg(tags.list, FSpecialColormap *); } -static inline FColormapStyle * ListGetColormapStyle(va_list &tags) +static inline FColormapStyle * ListGetColormapStyle(Va_List &tags) { - return va_arg(tags, FColormapStyle *); + return va_arg(tags.list, FColormapStyle *); } static void ListEnd(VMVa_List &tags) { } -static int ListGetInt(VMVa_List &tags) +int ListGetInt(VMVa_List &tags) { if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_INT) { @@ -941,7 +941,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, } // explicitly instantiate both versions for v_text.cpp. -template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, va_list& tags, DrawParms *parms, bool fortext) const; +template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, Va_List& tags, DrawParms *parms, bool fortext) const; template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, VMVa_List& tags, DrawParms *parms, bool fortext) const; void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, diff --git a/src/v_font.cpp b/src/v_font.cpp index 2854be8c2..00d3b10f7 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -94,6 +94,7 @@ The FON2 header is followed by variable length data: #include "r_data/r_translate.h" #include "colormatcher.h" #include "v_palette.h" +#include "v_text.h" // MACROS ------------------------------------------------------------------ @@ -340,6 +341,14 @@ FFont *V_GetFont(const char *name) return font; } +DEFINE_ACTION_FUNCTION(FFont, GetFont) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + ACTION_RETURN_POINTER(V_GetFont(name.GetChars())); +} + + //========================================================================== // // FFont :: FFont @@ -366,7 +375,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, LastChar = first + count - 1; FontHeight = 0; GlobalKerning = false; - Name = copystring (name); + FontName = name; Next = FirstFont; FirstFont = this; Cursor = '_'; @@ -478,11 +487,6 @@ FFont::~FFont () delete[] PatchRemap; PatchRemap = NULL; } - if (Name) - { - delete[] Name; - Name = NULL; - } FFont **prev = &FirstFont; FFont *font = *prev; @@ -508,27 +512,26 @@ FFont::~FFont () // //========================================================================== -FFont *FFont::FindFont (const char *name) +FFont *FFont::FindFont (FName name) { - if (name == NULL) + if (name == NAME_None) { - return NULL; + return nullptr; } FFont *font = FirstFont; - while (font != NULL) + while (font != nullptr) { - if (stricmp (font->Name, name) == 0) - break; + if (font->FontName == name) return font; font = font->Next; } - return font; + return nullptr; } DEFINE_ACTION_FUNCTION(FFont, FindFont) { PARAM_PROLOGUE; - PARAM_STRING(name); + PARAM_NAME(name); ACTION_RETURN_POINTER(FFont::FindFont(name)); } @@ -843,6 +846,65 @@ int FFont::GetCharWidth (int code) const return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove; } +DEFINE_ACTION_FUNCTION(FFont, GetCharWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_INT(self->GetCharWidth(code)); +} + +//========================================================================== +// +// Find string width using this font +// +//========================================================================== + +int FFont::StringWidth(const BYTE *string) const +{ + int w = 0; + int maxw = 0; + + while (*string) + { + if (*string == TEXTCOLOR_ESCAPE) + { + ++string; + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (*string == '\n') + { + if (w > maxw) + maxw = w; + w = 0; + ++string; + } + else + { + w += GetCharWidth(*string++) + GlobalKerning; + } + } + + return MAX(maxw, w); +} + +DEFINE_ACTION_FUNCTION(FFont, StringWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + ACTION_RETURN_INT(self->StringWidth(str)); +} + //========================================================================== // // FFont :: LoadTranslations @@ -935,7 +997,7 @@ FFont::FFont (int lump) Lump = lump; Chars = NULL; PatchRemap = NULL; - Name = NULL; + FontName = NAME_None; Cursor = '_'; } @@ -951,7 +1013,7 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) { assert(lump >= 0); - Name = copystring (name); + FontName = name; FMemLump data1 = Wads.ReadLump (lump); const BYTE *data = (const BYTE *)data1.GetMem(); @@ -1189,7 +1251,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) if (destSize < 0) { i += FirstChar; - I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, Name); + I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars()); } } @@ -1491,7 +1553,7 @@ FSinglePicFont::FSinglePicFont(const char *picname) : FTexture *pic = TexMan[picnum]; - Name = copystring(picname); + FontName = picname; FontHeight = pic->GetScaledHeight(); SpaceWidth = pic->GetScaledWidth(); GlobalKerning = 0; @@ -1903,7 +1965,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l memcpy(this->notranslate, notranslate, 256*sizeof(bool)); - Name = copystring(name); + FontName = name; Chars = new CharData[count]; charlumps = new FTexture*[count]; PatchRemap = new BYTE[256]; @@ -2490,6 +2552,13 @@ EColorRange V_FindFontColor (FName name) return CR_UNTRANSLATED; } +DEFINE_ACTION_FUNCTION(FFont, FindFontColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_NAME(code); + ACTION_RETURN_INT((int)V_FindFontColor(code)); +} + //========================================================================== // // V_LogColorFromColorRange @@ -2664,12 +2733,3 @@ void V_ClearFonts() SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL; } -void V_RetranslateFonts() -{ - FFont *font = FFont::FirstFont; - while(font) - { - font->LoadTranslations(); - font = font->Next; - } -} diff --git a/src/v_font.h b/src/v_font.h index b31c51471..4c78b3007 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -88,9 +88,9 @@ public: int GetDefaultKerning () const { return GlobalKerning; } virtual void LoadTranslations(); void Preload() const; - const char *GetName() const { return Name; } + FName GetName() const { return FontName; } - static FFont *FindFont (const char *fontname); + static FFont *FindFont(FName fontname); static void StaticPreloadFonts(); // Return width of string in pixels (unscaled) @@ -127,14 +127,13 @@ protected: BYTE *PatchRemap; int Lump; - char *Name; + FName FontName; FFont *Next; static FFont *FirstFont; friend struct FontsDeleter; friend void V_ClearFonts(); - friend void V_RetranslateFonts(); }; @@ -147,6 +146,5 @@ PalEntry V_LogColorFromColorRange (EColorRange range); EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor); FFont *V_GetFont(const char *); void V_InitFontColors(); -void V_RetranslateFonts(); #endif //__V_FONT_H__ diff --git a/src/v_text.cpp b/src/v_text.cpp index 3fcac5541..8b612e83c 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -47,11 +47,16 @@ #include "doomstat.h" #include "templates.h" +int ListGetInt(VMVa_List &tags); + +//========================================================================== // // DrawChar // // Write a single character using the given font // +//========================================================================== + void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...) { if (font == NULL) @@ -66,10 +71,10 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch if (NULL != (pic = font->GetChar (character, &dummy))) { DrawParms parms; - va_list tags; - va_start(tags, tag_first); + Va_List tags; + va_start(tags.list, tag_first); bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false); - va_end(tags); + va_end(tags.list); if (!res) { return; @@ -79,37 +84,61 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch } } +void DCanvas::DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args) +{ + if (font == NULL) + return; + + if (normalcolor >= NumTextColors) + normalcolor = CR_UNTRANSLATED; + + FTexture *pic; + int dummy; + + if (NULL != (pic = font->GetChar(character, &dummy))) + { + DrawParms parms; + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(pic, x, y, tag, args, &parms, false); + if (!res) return; + parms.remap = font->GetColorTranslation((EColorRange)normalcolor); + DrawTextureParms(pic, parms); + } +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawChar) +{ + PARAM_PROLOGUE; + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(chr); + + VMVa_List args = { param + 5, 0, numparam - 5 }; + screen->DrawChar(font, cr, x, y, chr, args); + return 0; +} + +//========================================================================== // // DrawText // // Write a string using the given font // -void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...) +//========================================================================== + +void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms) { int w; const BYTE *ch; int c; - int cx; - int cy; + double cx; + double cy; int boldcolor; FRemapTable *range; int kerning; FTexture *pic; - DrawParms parms; - - va_list tags; - - if (font == NULL || string == NULL) - return; - - va_start(tags, tag_first); - bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); - va_end(tags); - if (!res) - { - return; - } - if (parms.celly == 0) parms.celly = font->GetHeight() + 1; parms.celly *= parms.scaley; @@ -118,15 +147,15 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s normalcolor = CR_UNTRANSLATED; boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1; - range = font->GetColorTranslation ((EColorRange)normalcolor); + range = font->GetColorTranslation((EColorRange)normalcolor); - kerning = font->GetDefaultKerning (); + kerning = font->GetDefaultKerning(); ch = (const BYTE *)string; cx = x; cy = y; - + while ((const char *)ch - string < parms.maxstrlen) { c = *ch++; @@ -135,14 +164,14 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s if (c == TEXTCOLOR_ESCAPE) { - EColorRange newcolor = V_ParseFontColor (ch, normalcolor, boldcolor); + EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor); if (newcolor != CR_UNDEFINED) { - range = font->GetColorTranslation (newcolor); + range = font->GetColorTranslation(newcolor); } continue; } - + if (c == '\n') { cx = x; @@ -150,7 +179,7 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s continue; } - if (NULL != (pic = font->GetChar (c, &w))) + if (NULL != (pic = font->GetChar(c, &w))) { parms.remap = range; SetTextureParms(&parms, pic, cx, cy); @@ -166,52 +195,61 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s } } - -// -// Find string width using this font -// -int FFont::StringWidth (const BYTE *string) const +void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...) { - int w = 0; - int maxw = 0; - - while (*string) + Va_List tags; + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + va_start(tags.list, tag_first); + bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); + va_end(tags.list); + if (!res) { - if (*string == TEXTCOLOR_ESCAPE) - { - ++string; - if (*string == '[') - { - while (*string != '\0' && *string != ']') - { - ++string; - } - } - if (*string != '\0') - { - ++string; - } - continue; - } - else if (*string == '\n') - { - if (w > maxw) - maxw = w; - w = 0; - ++string; - } - else - { - w += GetCharWidth (*string++) + GlobalKerning; - } + return; } - - return MAX (maxw, w); + DrawTextCommon(font, normalcolor, x, y, string, parms); } +void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args) +{ + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(nullptr, 0, 0, tag, args, &parms, true); + if (!res) + { + return; + } + DrawTextCommon(font, normalcolor, x, y, string, parms); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawText) +{ + PARAM_PROLOGUE; + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_STRING(chr); + + VMVa_List args = { param + 5, 0, numparam - 5 }; + screen->DrawText(font, cr, x, y, chr, args); + return 0; +} + + +//========================================================================== // // Break long lines of text into multiple lines no longer than maxwidth pixels // +//========================================================================== + static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor) { if (!linecolor.IsEmpty()) @@ -223,20 +261,19 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B line->Width = font->StringWidth (line->Text); } -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor) +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor, unsigned int *count) { - FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) + TArray Lines(128); const BYTE *space = NULL, *start = string; - size_t i, ii; int c, w, nw; FString lastcolor, linecolor; bool lastWasSpace = false; int kerning = font->GetDefaultKerning (); - i = w = 0; + w = 0; - while ( (c = *string++) && i < countof(lines) ) + while ( (c = *string++) ) { if (c == TEXTCOLOR_ESCAPE) { @@ -283,14 +320,14 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool if (!space) space = string - 1; - breakit (&lines[i], font, start, space, linecolor); + auto index = Lines.Reserve(1); + breakit (&Lines[index], font, start, space, linecolor); if (c == '\n' && !preservecolor) { lastcolor = ""; // Why, oh why, did I do it like this? } linecolor = lastcolor; - i++; w = 0; lastWasSpace = false; start = space; @@ -312,7 +349,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool } // String here is pointing one character after the '\0' - if (i < countof(lines) && --string - start >= 1) + if (--string - start >= 1) { const BYTE *s = start; @@ -321,20 +358,25 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool // If there is any non-white space in the remainder of the string, add it. if (!isspace (*s++)) { - breakit (&lines[i++], font, start, string, linecolor); + auto i = Lines.Reserve(1); + breakit (&Lines[i], font, start, string, linecolor); break; } } } // Make a copy of the broken lines and return them - FBrokenLines *broken = new FBrokenLines[i+1]; + FBrokenLines *broken = new FBrokenLines[Lines.Size() + 1]; - for (ii = 0; ii < i; ++ii) + for (unsigned ii = 0; ii < Lines.Size(); ++ii) { - broken[ii] = lines[ii]; + broken[ii] = Lines[ii]; + } + broken[Lines.Size()].Width = -1; + if (count != nullptr) + { + *count = Lines.Size(); } - broken[ii].Width = -1; return broken; } @@ -346,3 +388,56 @@ void V_FreeBrokenLines (FBrokenLines *lines) delete[] lines; } } + +class DBrokenLines : public DObject +{ + DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) + +public: + FBrokenLines *mBroken; + unsigned int mCount; + + DBrokenLines(FBrokenLines *broken, unsigned int count) + { + mBroken = broken; + mCount = count; + } + + void OnDestroy() override + { + V_FreeBrokenLines(mBroken); + } +}; + +IMPLEMENT_CLASS(DBrokenLines, true, false); + +DEFINE_ACTION_FUNCTION(DBrokenLines, Count) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + ACTION_RETURN_INT(self->mCount); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_INT((unsigned)index >= self->mCount? -1 : self->mBroken[index].Width); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_STRING((unsigned)index >= self->mCount? -1 : self->mBroken[index].Text); +} + +DEFINE_ACTION_FUNCTION(FFont, BreakLines) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(text); + PARAM_INT(maxwidth); + + unsigned int count; + FBrokenLines *broken = V_BreakLines(self, maxwidth, text, true, &count); + ACTION_RETURN_OBJECT(new DBrokenLines(broken, count)); +} diff --git a/src/v_text.h b/src/v_text.h index 3baf62af7..bd24be405 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -75,11 +75,11 @@ struct FBrokenLines #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false); +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false, unsigned int *count = nullptr); void V_FreeBrokenLines (FBrokenLines *lines); -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); } -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor, count); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor, count); } #endif //__V_TEXT_H__ diff --git a/src/v_video.cpp b/src/v_video.cpp index 3a00df8e2..d6d8b6b9e 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1397,7 +1397,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real cy1 = MAX(cheight / designheight, 1); cx2 = MAX(realwidth / designwidth, 1); cy2 = MAX(realheight / designheight, 1); - if (abs(cx1 - cy1) <= abs(cx2 - cy2)) + if (abs(cx1 - cy1) <= abs(cx2 - cy2) || cx1 >= 4) { // e.g. 640x360 looks better with this. *cleanx = cx1; *cleany = cy1; diff --git a/src/v_video.h b/src/v_video.h index 18bb310e1..a2586d5a7 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -177,6 +177,11 @@ struct DrawParms bool virtBottom; }; +struct Va_List +{ + va_list list; +}; + struct VMVa_List { VMValue *args; @@ -269,8 +274,10 @@ public: #undef DrawText // See WinUser.h for the definition of DrawText as a macro #endif // 2D Text drawing - void DrawText (FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...); - void DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...); + void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...); + void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args); + void DrawChar(FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...); + void DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args); protected: BYTE *Buffer; @@ -279,6 +286,8 @@ protected: int Pitch; int LockCount; + void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms); + bool ClipBox (int &left, int &top, int &width, int &height, const BYTE *&src, const int srcpitch) const; void DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags) = delete; virtual void DrawTextureParms(FTexture *img, DrawParms &parms); diff --git a/src/zstring.h b/src/zstring.h index c696f7fd6..c58fb111a 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -449,4 +449,14 @@ template<> struct THashTraits // Compares two keys, returning zero if they are the same. int Compare(const FString &left, const FString &right) { return left.Compare(right); } }; + +class FStringNoInit +{ + char mem[sizeof(FString)]; + operator FString&() + { + return *reinterpret_cast(&mem); + } +}; + #endif diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index bdc1ce3ae..4d567d3ca 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1417,6 +1417,9 @@ TXT_KILLED_ORACLE = "You've Killed The Oracle!"; TXT_KILLED_MACIL = "You Killed Macil!"; TXT_KILLED_LOREMASTER = "You've Killed the Loremaster!"; +TXT_YOUFOOL = "You Fool! You've set off the alarm."; +TXT_YOUREDEAD = "You're dead! You set off the alarm."; + // Strife pickup messages TXT_METALARMOR = "You picked up the Metal Armor."; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 24afe68e9..ceda20bd8 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -498,6 +498,7 @@ class Actor : Thinker native native bool UsePuzzleItem(int PuzzleItemType); native float AccuracyFactor(); native bool MorphMonster (Class spawntype, int duration, int style, Class enter_flash, Class exit_flash); + action native void SetCamera(Actor cam, bool revert = false); // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b84d72a51..5ba744a8e 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -28,10 +28,80 @@ struct TexMan ShortNameOnly = 16, DontCreate = 32 }; + + enum ETexReplaceFlags + { + NOT_BOTTOM = 1, + NOT_MIDDLE = 2, + NOT_TOP = 4, + NOT_FLOOR = 8, + NOT_CEILING = 16, + NOT_WALL = 7, + NOT_FLAT = 24 + }; native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny); + native static void ReplaceTextures(String from, String to, int flags); } +enum DrawTextureTags +{ + TAG_USER = (1<<30), + DTA_Base = TAG_USER + 5000, + DTA_DestWidth, // width of area to draw to + DTA_DestHeight, // height of area to draw to + DTA_Alpha, // alpha value for translucency + DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers) + DTA_TranslationIndex, // translation table to recolor the source + DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor + DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac + DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen + DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets + DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position + DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead + DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) + DTA_ShadowColor, // color of shadow + DTA_ShadowAlpha, // alpha of shadow + DTA_Shadow, // set shadow color and alphas to defaults + DTA_VirtualWidth, // pretend the canvas is this wide + DTA_VirtualHeight, // pretend the canvas is this tall + DTA_TopOffset, // override texture's top offset + DTA_LeftOffset, // override texture's left offset + DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle + DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle + DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) + DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) + DTA_ClipTop, // don't draw anything above this row (on dest, not source) + DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) + DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) + DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) + DTA_Masked, // true(default)=use masks from texture, false=ignore masks + DTA_HUDRules, // use fullscreen HUD rules to position and size textures + DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter + DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 + DTA_RenderStyle, // same as render style for actors + DTA_ColorOverlay, // DWORD: ARGB to overlay on top of image; limited to black for software + DTA_Internal1, + DTA_Internal2, + DTA_Internal3, + DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) + + // floating point duplicates of some of the above: + DTA_DestWidthF, + DTA_DestHeightF, + DTA_TopOffsetF, + DTA_LeftOffsetF, + DTA_VirtualWidthF, + DTA_VirtualHeightF, + DTA_WindowLeftF, + DTA_WindowRightF, + + // For DrawText calls only: + DTA_TextLen, // stop after this many characters, even if \0 not hit + DTA_CellX, // horizontal size of character cell + DTA_CellY, // vertical size of character cell +}; + struct Screen native { enum EColorRange @@ -66,17 +136,33 @@ struct Screen native native static int GetWidth(); native static int GetHeight(); native static void DrawHUDTexture(TextureID tex, double x, double y); + native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); + native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); + native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); + +} + +class BrokenLines : Object native +{ + native int Count(); + native int StringWidth(int line); + native String StringAt(int line); } struct Font native { - native static Font FindFont(String name); + native int GetCharWidth(int code); + native int StringWidth(String code); + native static int FindFontColor(Name color); + native static Font FindFont(Name fontname); + native static Font GetFont(Name fontname); + native static BrokenLines BreakLines(String text, int maxlen); } struct Console native { native static void HideConsole(); - native static void MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. + native static void MidPrint(Font fontname, string textlabel, bool bold = false); } struct DamageTypeDefinition native @@ -182,7 +268,7 @@ class BlockThingsIterator : Object native native bool Next(); } -class DropItem : Object native +struct DropItem native { native readonly DropItem Next; native readonly name Name; @@ -343,9 +429,14 @@ enum EPickStart // Although String is a builtin type, this is a convenient way to attach methods to it. struct StringStruct native { - native void Replace(String pattern, String replacement); native static vararg String Format(String fmt, ...); - native vararg void AppendFormat(String fmt, ...); + native vararg void AppendFormat(String fmt, ...); + + native void Replace(String pattern, String replacement); + native String Mid(int pos = 0, int len = 2147483647); + native int Len(); + native String CharAt(int pos); + native int CharCodeAt(int pos); } class Floor : Thinker native diff --git a/wadsrc/static/zscript/compatibility.txt b/wadsrc/static/zscript/compatibility.txt index 752de8016..1ae88ab85 100644 --- a/wadsrc/static/zscript/compatibility.txt +++ b/wadsrc/static/zscript/compatibility.txt @@ -9,7 +9,9 @@ extend class Object deprecated static void C_MidPrint(string fontname, string textlabel, bool bold = false) // deprecated for 2.4.x { - return Console.MidPrint(fontname, textlabel, bold); + let f = Font.GetFont(fontname); + if (f == null) return; + return Console.MidPrint(f, textlabel, bold); } } diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index da915f170..28b20cdd5 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -24,7 +24,7 @@ class Inventory : Actor native native bool bCreateCopyMoved; native bool bInitEffectFailed; native meta String PickupMsg; - native meta int GiveQuest; + native /*meta*/ int GiveQuest; Default { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 5634c4c49..c1fbf4384 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -43,6 +43,8 @@ class Weapon : StateProvider native Weapon.BobSpeed 1.0; Weapon.BobRangeX 1.0; Weapon.BobRangeY 1.0; + Weapon.SlotNumber -1; + Weapon.SlotPriority 32767; +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; } @@ -250,7 +252,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // // If you can't see the weapon when it's active, then you can't pick it up. // @@ -275,7 +277,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // //=========================================================================== @@ -291,7 +293,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Use + // Weapon :: Use // // Make the player switch to self weapon. // @@ -322,7 +324,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Destroy + // Weapon :: Destroy // //=========================================================================== @@ -345,7 +347,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: HandlePickup + // Weapon :: HandlePickup // // Try to leach ammo from the weapon if you have it already. // @@ -370,7 +372,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: PickupForAmmo + // Weapon :: PickupForAmmo // // The player already has self weapon, so try to pick it up for ammo. // @@ -409,7 +411,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateCopy + // Weapon :: CreateCopy // //=========================================================================== @@ -426,7 +428,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateTossable + // Weapon :: CreateTossable // // A weapon that's tossed out should contain no ammo, so you can't cheat // by dropping it and then picking it back up. @@ -462,7 +464,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AttachToOwner + // Weapon :: AttachToOwner // //=========================================================================== @@ -489,7 +491,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddAmmo + // Weapon :: AddAmmo // // Give some ammo to the owner, even if it's just 0. // @@ -534,7 +536,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddExistingAmmo + // Weapon :: AddExistingAmmo // // Give the owner some more ammo he already has. // @@ -561,7 +563,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddWeapon + // Weapon :: AddWeapon // // Give the owner a weapon if they don't have it already. // @@ -586,7 +588,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: ShouldStay + // Weapon :: ShouldStay // //=========================================================================== @@ -604,7 +606,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: EndPowerUp + // Weapon :: EndPowerUp // // The Tome of Power just expired. // diff --git a/wadsrc/static/zscript/shared/fastprojectile.txt b/wadsrc/static/zscript/shared/fastprojectile.txt index fd877bd83..657c4680e 100644 --- a/wadsrc/static/zscript/shared/fastprojectile.txt +++ b/wadsrc/static/zscript/shared/fastprojectile.txt @@ -156,7 +156,7 @@ class FastProjectile : Actor ExplodeMissile (NULL, NULL); return; } - if (frac != (0, 0, 0) && ripcount <= 0) + if (!(frac.xy ~== (0, 0)) && ripcount <= 0) { ripcount = count >> 3; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 0a7798ace..dc1d1ba1d 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -9,17 +9,16 @@ class PlayerPawn : Actor native native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvSel; // selected inventory item native meta String DisplayName; // Display name (used in menus, etc.) - native meta String SoundClass; // Sound class - native meta String Face; // Doom status bar face (when used) - native meta String Portrait; - native meta String Slot[10]; - native meta Name InvulMode; - native meta Name HealingRadiusType; - native meta double HexenArmor[5]; - native meta uint8 ColorRangeStart; // Skin color range - native meta uint8 ColorRangeEnd; - //FPlayerColorSetMap ColorSets; - //PainFlashList PainFlashes; + + native /*meta*/ Name SoundClass; // Sound class + native /*meta*/ Name Face; // Doom status bar face (when used) + native /*meta*/ Name Portrait; + native /*meta*/ Name Slot[10]; + native /*meta*/ Name InvulMode; + native /*meta*/ Name HealingRadiusType; + native /*meta*/ double HexenArmor[5]; + native /*meta*/ uint8 ColorRangeStart; // Skin color range + native /*meta*/ uint8 ColorRangeEnd; // [GRB] Player class properties native double JumpZ; diff --git a/wadsrc/static/zscript/strife/strifeitems.txt b/wadsrc/static/zscript/strife/strifeitems.txt index 970478cae..4c7311b56 100644 --- a/wadsrc/static/zscript/strife/strifeitems.txt +++ b/wadsrc/static/zscript/strife/strifeitems.txt @@ -632,7 +632,7 @@ class RaiseAlarm : DummyStrifeItem dropper.target.SoundAlert(dropper.target); if (dropper.target.CheckLocalView(consoleplayer)) { - A_Log("You Fool! You've set off the alarm."); + Console.MidPrint(SmallFont, "$TXT_YOUFOOL"); } } Destroy (); @@ -672,7 +672,7 @@ class CloseDoor222 : DummyStrifeItem { if (dropper.target.CheckLocalView(consoleplayer)) { - A_Log("You're dead! You set off the alarm."); + Console.MidPrint(SmallFont, "$TXT_YOUREDEAD"); } dropper.target.SoundAlert(dropper.target); }