This commit is contained in:
Rachael Alexanderson 2017-02-08 18:42:24 -05:00
commit 5948c7b0da
79 changed files with 1355 additions and 1439 deletions

View file

@ -793,7 +793,7 @@ file( GLOB HEADER_FILES
sound/*.h sound/*.h
textures/*.h textures/*.h
scripting/*.h scripting/*.h
scripting/codegeneration/*.h scripting/backend/*.h
scripting/decorate/*.h scripting/decorate/*.h
scripting/zscript/*.h scripting/zscript/*.h
scripting/vm/*.h scripting/vm/*.h
@ -1271,17 +1271,18 @@ set (PCH_SOURCES
r_data/voxels.cpp r_data/voxels.cpp
r_data/renderstyle.cpp r_data/renderstyle.cpp
r_data/r_interpolate.cpp r_data/r_interpolate.cpp
scripting/symbols.cpp
scripting/thingdef.cpp scripting/thingdef.cpp
scripting/thingdef_data.cpp scripting/thingdef_data.cpp
scripting/thingdef_properties.cpp scripting/thingdef_properties.cpp
scripting/codegeneration/codegen.cpp scripting/backend/codegen.cpp
scripting/codegeneration/dynarrays.cpp scripting/backend/dynarrays.cpp
scripting/backend/vmbuilder.cpp
scripting/backend/vmdisasm.cpp
scripting/decorate/olddecorations.cpp scripting/decorate/olddecorations.cpp
scripting/decorate/thingdef_exp.cpp scripting/decorate/thingdef_exp.cpp
scripting/decorate/thingdef_parse.cpp scripting/decorate/thingdef_parse.cpp
scripting/decorate/thingdef_states.cpp scripting/decorate/thingdef_states.cpp
scripting/vm/vmbuilder.cpp
scripting/vm/vmdisasm.cpp
scripting/vm/vmexec.cpp scripting/vm/vmexec.cpp
scripting/vm/vmframe.cpp scripting/vm/vmframe.cpp
scripting/zscript/ast.cpp scripting/zscript/ast.cpp
@ -1526,9 +1527,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\\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\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") 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\\Decorate frontend" 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\\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\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+") 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\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")

View file

@ -572,12 +572,9 @@ struct FLinkContext
msecnode_t *render_list = nullptr; msecnode_t *render_list = nullptr;
}; };
class DDropItem : public DObject struct FDropItem
{ {
DECLARE_CLASS(DDropItem, DObject) FDropItem *Next;
HAS_OBJECT_POINTERS
public:
DDropItem *Next;
FName Name; FName Name;
int Probability; int Probability;
int Amount; int Amount;
@ -610,7 +607,7 @@ public:
return (AActor *)(this->GetClass()->Defaults); return (AActor *)(this->GetClass()->Defaults);
} }
DDropItem *GetDropItems() const; FDropItem *GetDropItems() const;
// Return true if the monster should use a missile attack, false for melee // Return true if the monster should use a missile attack, false for melee
bool SuggestMissileAttack (double dist); bool SuggestMissileAttack (double dist);
@ -699,7 +696,7 @@ public:
// Give an item to the actor and pick it up. // Give an item to the actor and pick it up.
// Returns true if the item pickup succeeded. // 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. // Removes the item from the inventory list.
virtual void RemoveInventory (AInventory *item); virtual void RemoveInventory (AInventory *item);
@ -736,7 +733,7 @@ public:
AInventory *FirstInv (); AInventory *FirstInv ();
// Tries to give the actor some ammo. // 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. // Destroys all the inventory the actor is holding.
void DestroyAllInventory (); void DestroyAllInventory ();

View file

@ -2857,7 +2857,7 @@ void AM_drawThings ()
// Find the key's own color. // Find the key's own color.
// Only works correctly if single-key locks have lower numbers than any-key locks. // Only works correctly if single-key locks have lower numbers than any-key locks.
// That is the case for all default keys, however. // 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)) if (G_SkillProperty(SKILLP_EasyKey))
{ {

View file

@ -263,7 +263,7 @@ void InitBotStuff()
for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++) for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++)
{ {
const PClass *cls = PClass::FindClass(botinits[i].type); const PClass *cls = PClass::FindClass(botinits[i].type);
if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (cls != NULL && cls->IsDescendantOf(NAME_Weapon))
{ {
AWeapon *w = (AWeapon*)GetDefaultByType(cls); AWeapon *w = (AWeapon*)GetDefaultByType(cls);
if (w != NULL) if (w != NULL)

View file

@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item)
//if(pos && !bglobal.thingvis[pos->id][item->id]) continue; //if(pos && !bglobal.thingvis[pos->id][item->id]) continue;
// if (item->IsKindOf (RUNTIME_CLASS(AArtifact))) // if (item->IsKindOf (RUNTIME_CLASS(AArtifact)))
// return; // don't know how to use artifacts // return; // don't know how to use artifacts
if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) if (item->IsKindOf(NAME_Weapon))
{ {
// FIXME // FIXME
AWeapon *heldWeapon; AWeapon *heldWeapon;

View file

@ -1210,7 +1210,7 @@ static void PrintSecretString(const char *string, bool thislevel)
{ {
while ((actor = it.Next())) while ((actor = it.Next()))
{ {
if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue; if (!actor->IsKindOf("SecretTrigger")) continue;
foundone = true; foundone = true;
break; break;
} }

View file

@ -73,7 +73,7 @@
#include "thingdef.h" #include "thingdef.h"
#include "info.h" #include "info.h"
#include "v_text.h" #include "v_text.h"
#include "vmbuilder.h" #include "backend/vmbuilder.h"
// [SO] Just the way Randy said to do it :) // [SO] Just the way Randy said to do it :)
// [RH] Made this CVAR_SERVERINFO // [RH] Made this CVAR_SERVERINFO
@ -1658,7 +1658,7 @@ static int PatchWeapon (int weapNum)
{ {
val = 5; val = 5;
} }
info->AmmoType1 = (PClassInventory*)AmmoNames[val]; info->AmmoType1 = AmmoNames[val];
if (info->AmmoType1 != NULL) if (info->AmmoType1 != NULL)
{ {
info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2; info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2;
@ -1983,7 +1983,7 @@ static int PatchMisc (int dummy)
player->health = deh.StartHealth; player->health = deh.StartHealth;
// Hm... I'm not sure that this is the right way to change this info... // 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) while (di != NULL)
{ {
if (di->Name == NAME_Clip) if (di->Name == NAME_Clip)
@ -2916,7 +2916,7 @@ static bool LoadDehSupp ()
else else
{ {
auto cls = PClass::FindActor(sc.String); 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); sc.ScriptError("Unknown ammo type '%s'", sc.String);
} }
@ -2934,7 +2934,7 @@ static bool LoadDehSupp ()
{ {
sc.MustGetString(); sc.MustGetString();
PClass *cls = PClass::FindClass(sc.String); 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); sc.ScriptError("Unknown weapon type '%s'", sc.String);
} }

View file

@ -2704,6 +2704,8 @@ void D_DoomMain (void)
// delete all data that cannot be left until reinitialization // delete all data that cannot be left until reinitialization
V_ClearFonts(); // must clear global font pointers V_ClearFonts(); // must clear global font pointers
ColorSets.Clear();
PainFlashes.Clear();
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
gameinfo.~gameinfo_t(); gameinfo.~gameinfo_t();
new (&gameinfo) gameinfo_t; // Reset gameinfo new (&gameinfo) gameinfo_t; // Reset gameinfo
@ -2714,7 +2716,7 @@ void D_DoomMain (void)
GC::FullGC(); // clean up before taking down the object list. 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); FAutoSegIterator probe(ARegHead, ARegTail);
while (*++probe != NULL) while (*++probe != NULL)
{ {

View file

@ -2539,7 +2539,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
case DEM_MORPHEX: case DEM_MORPHEX:
{ {
s = ReadString (stream); s = ReadString (stream);
const char *msg = cht_Morph (players + player, dyn_cast<PClassPlayerPawn>(PClass::FindClass (s)), false); const char *msg = cht_Morph (players + player, PClass::FindActor (s), false);
if (player == consoleplayer) if (player == consoleplayer)
{ {
Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); Printf ("%s\n", *msg != '\0' ? msg : "Morph failed.");

View file

@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname)
{ {
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) 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) 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) if (players[player].mo != NULL)
{ {
colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet());
} }
if (colorset != NULL) if (colorset != NULL)
{ {

View file

@ -66,39 +66,17 @@ struct FPlayerColorSet
ExtraRange Extra[6]; ExtraRange Extra[6];
}; };
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap; typedef TArray<std::tuple<PClass*, FName, PalEntry>> PainFlashList;
typedef TMap<FName, PalEntry> PainFlashList; typedef TArray<std::tuple<PClass*, int, FPlayerColorSet>> ColorSetList;
class PClassPlayerPawn : public PClassActor extern PainFlashList PainFlashes;
{ extern ColorSetList ColorSets;
DECLARE_CLASS(PClassPlayerPawn, PClassActor);
protected:
public:
PClassPlayerPawn();
virtual void DeriveData(PClass *newclass);
void EnumColorSets(TArray<int> *out);
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
void SetPainFlash(FName type, PalEntry color);
bool GetPainFlash(FName type, PalEntry *color) const;
FString DisplayName; // Display name (used in menus, etc.) FString GetPrintableDisplayName(PClassActor *cls);
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);
class APlayerPawn : public AActor class APlayerPawn : public AActor
{ {
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) DECLARE_CLASS(APlayerPawn, AActor)
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
public: public:
@ -119,9 +97,9 @@ public:
void TweakSpeeds (double &forwardmove, double &sidemove); void TweakSpeeds (double &forwardmove, double &sidemove);
void MorphPlayerThink (); void MorphPlayerThink ();
void ActivateMorphWeapon (); void ActivateMorphWeapon ();
AWeapon *PickNewWeapon (PClassInventory *ammotype); AWeapon *PickNewWeapon (PClassActor *ammotype);
AWeapon *BestWeapon (PClassInventory *ammotype); AWeapon *BestWeapon (PClassActor *ammotype);
void CheckWeaponSwitch(PClassInventory *ammotype); void CheckWeaponSwitch(PClassActor *ammotype);
void GiveDeathmatchInventory (); void GiveDeathmatchInventory ();
void FilterCoopRespawnInventory (APlayerPawn *oldplayer); void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
@ -176,6 +154,17 @@ public:
// [SP] ViewBob Multiplier // [SP] ViewBob Multiplier
double ViewBob; 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;
}; };
// //
@ -272,7 +261,7 @@ public:
bool CheckSkin (int skin); bool CheckSkin (int skin);
PClassPlayerPawn *Type; PClassActor *Type;
DWORD Flags; DWORD Flags;
TArray<int> Skins; TArray<int> Skins;
}; };
@ -344,7 +333,7 @@ struct userinfo_t : TMap<FName,FBaseCVar *>
{ {
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass)); return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
} }
PClassPlayerPawn *GetPlayerClassType() const PClassActor *GetPlayerClassType() const
{ {
return PlayerClasses[GetPlayerClassNum()].Type; return PlayerClasses[GetPlayerClassNum()].Type;
} }
@ -402,7 +391,7 @@ public:
userinfo_t userinfo; // [RH] who is this? 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 DesiredFOV; // desired field of vision
float FOV; // current field of vision float FOV; // current field of vision
@ -460,7 +449,7 @@ public:
short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedcolormap; // can be set to REDCOLORMAP, etc.
short fixedlightlevel; short fixedlightlevel;
int morphTics; // player is a chicken/pig if > 0 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 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) PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer)
TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing
@ -539,12 +528,16 @@ public:
// Make sure that a state is properly set after calling this unless // Make sure that a state is properly set after calling this unless
// you are 100% sure the context already implies the layer exists. // you are 100% sure the context already implies the layer exists.
DPSprite *GetPSprite(PSPLayers layer); DPSprite *GetPSprite(PSPLayers layer);
bool GetPainFlash(FName type, PalEntry *color) const;
}; };
// Bookkeeping on players - state. // Bookkeeping on players - state.
extern player_t players[MAXPLAYERS]; extern player_t players[MAXPLAYERS];
void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale); void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale);
void EnumColorSets(PClassActor *pc, TArray<int> *out);
FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum);
inline void AActor::SetFriendPlayer(player_t *player) inline void AActor::SetFriendPlayer(player_t *player)
{ {

View file

@ -301,18 +301,32 @@ DObject::~DObject ()
PClass *type = GetClass(); PClass *type = GetClass();
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
{ {
DObject **probe; if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released)))
if (!(ObjectFlags & OF_YesReallyDelete))
{ {
Printf("Warning: '%s' is freed outside the GC process.\n", Printf("Warning: '%s' is freed outside the GC process.\n",
type != NULL ? type->TypeName.GetChars() : "==some object=="); type != NULL ? type->TypeName.GetChars() : "==some object==");
} }
if (!(ObjectFlags & OF_Released))
{
// Find all pointers that reference this object and NULL them. // Find all pointers that reference this object and NULL them.
StaticPointerSubstitution(this, NULL); StaticPointerSubstitution(this, NULL);
Release();
}
}
// Now unlink this object from the GC list. if (nullptr != type)
{
type->DestroySpecials(this);
}
}
}
void DObject::Release()
{
DObject **probe;
// Unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{ {
if (*probe == this) if (*probe == this)
@ -338,13 +352,9 @@ DObject::~DObject ()
} }
} }
} }
} ObjNext = nullptr;
GCNext = nullptr;
if (nullptr != type) ObjectFlags |= OF_Released;
{
type->DestroySpecials(this);
}
}
} }
//========================================================================== //==========================================================================

View file

@ -93,8 +93,6 @@ enum
{ {
CLASSREG_PClass, CLASSREG_PClass,
CLASSREG_PClassActor, CLASSREG_PClassActor,
CLASSREG_PClassInventory,
CLASSREG_PClassPlayerPawn,
}; };
struct ClassReg struct ClassReg
@ -205,6 +203,7 @@ enum EObjectFlags
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list 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_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 T> class TObjPtr; template<class T> class TObjPtr;
@ -457,6 +456,7 @@ public:
virtual ~DObject (); virtual ~DObject ();
inline bool IsKindOf (const PClass *base) const; inline bool IsKindOf (const PClass *base) const;
inline bool IsKindOf(FName base) const;
inline bool IsA (const PClass *type) const; inline bool IsA (const PClass *type) const;
void SerializeUserVars(FSerializer &arc); void SerializeUserVars(FSerializer &arc);
@ -467,6 +467,9 @@ public:
Class = NULL; Class = NULL;
} }
// Releases the object from the GC, letting the caller care of any maintenance.
void Release();
// For catching Serialize functions in derived classes // For catching Serialize functions in derived classes
// that don't call their base class. // that don't call their base class.
void CheckIfSerialized () const; void CheckIfSerialized () const;
@ -603,6 +606,7 @@ static inline void GC::WriteBarrier(DObject *pointed)
} }
} }
#include "symbols.h"
#include "dobjtype.h" #include "dobjtype.h"
inline bool DObject::IsKindOf (const PClass *base) const inline bool DObject::IsKindOf (const PClass *base) const
@ -610,6 +614,11 @@ inline bool DObject::IsKindOf (const PClass *base) const
return base->IsAncestorOf (GetClass ()); return base->IsAncestorOf (GetClass ());
} }
inline bool DObject::IsKindOf(FName base) const
{
return GetClass()->IsDescendantOf(base);
}
inline bool DObject::IsA (const PClass *type) const inline bool DObject::IsA (const PClass *type) const
{ {
return (type == GetClass()); return (type == GetClass());

View file

@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
curr->Destroy(); curr->Destroy();
} }
/*
if (curr->IsKindOf(RUNTIME_CLASS(PSymbol)))
Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast<PSymbol*>(curr)->SymbolName.GetChars());
else if (curr->IsKindOf(RUNTIME_CLASS(PType)))
Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast<PType*>(curr)->DescriptiveName());
else
Printf("Collecting %s\n", curr->GetClass()->TypeName.GetChars());
*/
curr->ObjectFlags |= OF_Cleanup; curr->ObjectFlags |= OF_Cleanup;
delete curr; delete curr;
finalized++; finalized++;
@ -277,7 +285,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
void Mark(DObject **obj) void Mark(DObject **obj)
{ {
DObject *lobj = *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) if (lobj->ObjectFlags & OF_EuthanizeMe)
{ {
@ -361,23 +371,6 @@ static void MarkRoot()
} }
Mark(SectorMarker); Mark(SectorMarker);
Mark(interpolator.Head); 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 // Mark global symbols
Namespaces.MarkSymbols(); Namespaces.MarkSymbols();
// Mark bot stuff. // Mark bot stuff.
@ -458,8 +451,8 @@ static size_t SingleStep()
{ // Nothing more to sweep? { // Nothing more to sweep?
State = GCS_Finalize; State = GCS_Finalize;
} }
assert(old >= AllocBytes); //assert(old >= AllocBytes);
Estimate -= old - AllocBytes; Estimate -= MAX<size_t>(0, old - AllocBytes);
return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST; return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST;
} }
@ -559,9 +552,12 @@ void FullGC()
void Barrier(DObject *pointing, DObject *pointed) void Barrier(DObject *pointing, DObject *pointed)
{ {
assert(pointed->GetClass() < (void*)0x1000000000000000);
assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead()));
assert(pointed->IsWhite() && !pointed->IsDead()); assert(pointed->IsWhite() && !pointed->IsDead());
assert(State != GCS_Finalize && State != GCS_Pause); 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. // The invariant only needs to be maintained in the propagate state.
if (State == GCS_Propagate) if (State == GCS_Propagate)
{ {
@ -776,7 +772,7 @@ CCMD(gc)
{ {
if (argv.argc() == 1) 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; return;
} }
if (stricmp(argv[1], "stop") == 0) if (stricmp(argv[1], "stop") == 0)
@ -791,6 +787,12 @@ CCMD(gc)
{ {
GC::FullGC(); 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) else if (stricmp(argv[1], "pause") == 0)
{ {
if (argv.argc() == 2) if (argv.argc() == 2)
@ -814,3 +816,4 @@ CCMD(gc)
} }
} }
} }

View file

@ -64,9 +64,7 @@
EXTERN_CVAR(Bool, strictdecorate); EXTERN_CVAR(Bool, strictdecorate);
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
FMemArena ClassDataAllocator(32768); // use this for all static class data that can be released in bulk when the type system is shut down.
FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy.
FNamespaceManager Namespaces;
FTypeTable TypeTable; FTypeTable TypeTable;
TArray<PClass *> PClass::AllClasses; TArray<PClass *> PClass::AllClasses;
@ -153,11 +151,7 @@ void DumpTypeTable()
/* PType ******************************************************************/ /* PType ******************************************************************/
IMPLEMENT_CLASS(PType, true, true) IMPLEMENT_CLASS(PType, true, false)
IMPLEMENT_POINTERS_START(PType)
IMPLEMENT_POINTER(HashNext)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -186,18 +180,6 @@ PType::~PType()
{ {
} }
//==========================================================================
//
// PType :: PropagateMark
//
//==========================================================================
size_t PType::PropagateMark()
{
size_t marked = Symbols.MarkSymbols();
return marked + Super::PropagateMark();
}
//========================================================================== //==========================================================================
// //
// PType :: WriteValue // PType :: WriteValue
@ -458,11 +440,7 @@ IMPLEMENT_CLASS(PCompoundType, true, false)
/* PNamedType *************************************************************/ /* PNamedType *************************************************************/
IMPLEMENT_CLASS(PNamedType, true, true) IMPLEMENT_CLASS(PNamedType, true, false)
IMPLEMENT_POINTERS_START(PNamedType)
IMPLEMENT_POINTER(Outer)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -490,20 +468,6 @@ void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
id2 = TypeName; id2 = TypeName;
} }
//==========================================================================
//
// PNamedType :: QualifiedName
//
//==========================================================================
FString PNamedType::QualifiedName() const
{
FString out;
if (Outer != nullptr) out = Outer->QualifiedName();
out << "::" << TypeName;
return out;
}
/* PInt *******************************************************************/ /* PInt *******************************************************************/
IMPLEMENT_CLASS(PInt, false, false) IMPLEMENT_CLASS(PInt, false, false)
@ -1331,11 +1295,7 @@ PStateLabel::PStateLabel()
/* PPointer ***************************************************************/ /* PPointer ***************************************************************/
IMPLEMENT_CLASS(PPointer, false, true) IMPLEMENT_CLASS(PPointer, false, false)
IMPLEMENT_POINTERS_START(PPointer)
IMPLEMENT_POINTER(PointedType)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -1538,11 +1498,7 @@ bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) cons
/* PClassPointer **********************************************************/ /* PClassPointer **********************************************************/
IMPLEMENT_CLASS(PClassPointer,false, true) IMPLEMENT_CLASS(PClassPointer,false, false)
IMPLEMENT_POINTERS_START(PClassPointer)
IMPLEMENT_POINTER(ClassRestriction)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -1623,11 +1579,7 @@ PClassPointer *NewClassPointer(PClass *restrict)
/* PEnum ******************************************************************/ /* PEnum ******************************************************************/
IMPLEMENT_CLASS(PEnum, false, true) IMPLEMENT_CLASS(PEnum, false, false)
IMPLEMENT_POINTERS_START(PEnum)
IMPLEMENT_POINTER(Outer)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -1679,11 +1631,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer)
/* PArray *****************************************************************/ /* PArray *****************************************************************/
IMPLEMENT_CLASS(PArray, false, true) IMPLEMENT_CLASS(PArray, false, false)
IMPLEMENT_POINTERS_START(PArray)
IMPLEMENT_POINTER(ElementType)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -1916,11 +1864,7 @@ PResizableArray *NewResizableArray(PType *type)
/* PDynArray **************************************************************/ /* PDynArray **************************************************************/
IMPLEMENT_CLASS(PDynArray, false, true) IMPLEMENT_CLASS(PDynArray, false, false)
IMPLEMENT_POINTERS_START(PDynArray)
IMPLEMENT_POINTER(ElementType)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -2056,7 +2000,7 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffs
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special) const void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special) const
{ {
if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ElementType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && static_cast<PPointer*>(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
{ {
// Add to the list of pointer arrays for this class. // Add to the list of pointer arrays for this class.
special->Push(offset); special->Push(offset);
@ -2171,12 +2115,7 @@ PDynArray *NewDynArray(PType *type)
/* PMap *******************************************************************/ /* PMap *******************************************************************/
IMPLEMENT_CLASS(PMap, false, true) IMPLEMENT_CLASS(PMap, false, false)
IMPLEMENT_POINTERS_START(PMap)
IMPLEMENT_POINTER(KeyType)
IMPLEMENT_POINTER(ValueType)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -2428,7 +2367,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags)
if (Symbols.AddSymbol(field) == nullptr) if (Symbols.AddSymbol(field) == nullptr)
{ // name is already in use { // name is already in use
delete field; field->Destroy();
return nullptr; return nullptr;
} }
Fields.Push(field); Fields.Push(field);
@ -2459,18 +2398,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD f
return field; return field;
} }
//==========================================================================
//
// PStruct :: PropagateMark
//
//==========================================================================
size_t PStruct::PropagateMark()
{
GC::MarkArray(Fields);
return Fields.Size() * sizeof(void*) + Super::PropagateMark();
}
//========================================================================== //==========================================================================
// //
// NewStruct // NewStruct
@ -2683,76 +2610,9 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *>
return static_cast<PPrototype *>(proto); return static_cast<PPrototype *>(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<DWORD> &argflags, TArray<FName> &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<PPointer>(proto->ArgumentTypes[0]);
assert(selftypeptr != nullptr);
variant.SelfClass = dyn_cast<PStruct>(selftypeptr->PointedType);
assert(variant.SelfClass != nullptr);
}
else
{
variant.SelfClass = nullptr;
}
return Variants.Push(variant);
}
/* PClass *****************************************************************/ /* PClass *****************************************************************/
IMPLEMENT_CLASS(PClass, false, true) IMPLEMENT_CLASS(PClass, false, false)
IMPLEMENT_POINTERS_START(PClass)
IMPLEMENT_POINTER(ParentClass)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -2947,6 +2807,7 @@ void PClass::StaticShutdown ()
*p = nullptr; *p = nullptr;
} }
FunctionPtrList.Clear(); FunctionPtrList.Clear();
VMFunction::DeleteAll();
// Make a full garbage collection here so that all destroyed but uncollected higher level objects // 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. // that still exist are properly taken down before the low level data is deleted.
@ -2957,18 +2818,10 @@ void PClass::StaticShutdown ()
bVMOperational = false; bVMOperational = false;
// Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts.
bShutdown = true;
TypeTable.Clear(); TypeTable.Clear();
Namespaces.ReleaseSymbols(); Namespaces.ReleaseSymbols();
FlatpointerArena.FreeAllBlocks(); ClassDataAllocator.FreeAllBlocks();
bShutdown = true;
for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i)
{
PClass *type = PClass::AllClasses[i];
PClass::AllClasses[i] = NULL;
type->Destroy();
}
AllClasses.Clear(); AllClasses.Clear();
PClassActor::AllActorClasses.Clear(); PClassActor::AllActorClasses.Clear();
@ -3056,8 +2909,6 @@ PClass *ClassReg::RegisterClass()
{ {
&PClass::RegistrationInfo, &PClass::RegistrationInfo,
&PClassActor::RegistrationInfo, &PClassActor::RegistrationInfo,
&PClassInventory::RegistrationInfo,
&PClassPlayerPawn::RegistrationInfo,
}; };
// Skip classes that have already been registered // Skip classes that have already been registered
@ -3344,45 +3195,28 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
assert(size >= Size); assert(size >= Size);
PClass *type; PClass *type;
bool notnew; bool notnew;
size_t bucket;
PClass *existclass = static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); const PClass *existclass = FindClass(name);
// This is a placeholder so fill it in // 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<PClass*>(existclass);
if (!IsDescendantOf(type->ParentClass))
{ {
if (!IsDescendantOf(existclass->ParentClass)) I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars());
{
I_Error("%s must inherit from %s but doesn't.", name.GetChars(), 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;
}
} }
DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars());
notnew = true; notnew = true;
} }
else else
{ {
// a different class with the same name already exists. Let the calling code deal with this. type = static_cast<PClass *>(GetClass()->CreateNew());
return nullptr;
}
}
else
{
notnew = false; notnew = false;
} }
// Create a new type object of the same type as us. (We may be a derived class of PClass.) type->TypeName = name;
type = static_cast<PClass *>(GetClass()->CreateNew()); type->bRuntimeClass = true;
Derive(type, name); Derive(type, name);
type->Size = size; type->Size = size;
if (size != TentativeClass) if (size != TentativeClass)
@ -3391,22 +3225,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
type->Virtuals = Virtuals; type->Virtuals = Virtuals;
DeriveData(type); DeriveData(type);
} }
else
type->ObjectFlags &= OF_Transient;
if (!notnew) if (!notnew)
{ {
type->InsertIntoHash(); 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<PClassActor*>(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; return type;
} }
@ -3577,7 +3402,7 @@ void PClass::BuildFlatPointers ()
{ } { }
// Concatenate them into a new array // Concatenate them into a new array
size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(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) if (numSuperPointers > 0)
{ {
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
@ -3643,7 +3468,7 @@ void PClass::BuildArrayPointers()
} }
// Concatenate them into a new array // Concatenate them into a new array
size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0) if (numSuperPointers > 0)
{ {
memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers);
@ -3721,31 +3546,6 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si
return nullptr; return nullptr;
} }
//==========================================================================
//
// 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 != nullptr; type_p = &(*type_p)->HashNext)
{
PType *type = *type_p;
if (type == oldtype)
{
newtype->HashNext = type->HashNext;
type->HashNext = nullptr;
*type_p = newtype;
break;
}
}
}
//========================================================================== //==========================================================================
// //
// FTypeTable :: AddType - Fully Parameterized Version // FTypeTable :: AddType - Fully Parameterized Version
@ -3762,7 +3562,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t
type->TypeTableType = metatype; type->TypeTableType = metatype;
type->HashNext = TypeHash[bucket]; type->HashNext = TypeHash[bucket];
TypeHash[bucket] = type; TypeHash[bucket] = type;
GC::WriteBarrier(type); type->Release();
} }
//========================================================================== //==========================================================================
@ -3785,7 +3585,7 @@ void FTypeTable::AddType(PType *type)
type->HashNext = TypeHash[bucket]; type->HashNext = TypeHash[bucket];
TypeHash[bucket] = type; TypeHash[bucket] = type;
GC::WriteBarrier(type); type->Release();
} }
//========================================================================== //==========================================================================
@ -3824,36 +3624,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] != nullptr)
{
GC::Mark(TypeHash[i]);
}
}
}
//========================================================================== //==========================================================================
// //
// FTypeTable :: Clear // FTypeTable :: Clear
// //
// Removes everything from the table. We let the garbage collector worry
// about deleting them.
//
//========================================================================== //==========================================================================
void FTypeTable::Clear() 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)); memset(TypeHash, 0, sizeof(TypeHash));
} }
@ -3863,232 +3650,3 @@ CCMD(typetable)
DumpTypeTable(); 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(nullptr)
{
}
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 == 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);
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 != nullptr)
{
PSymbol *oldsym = *symslot;
*symslot = newsym;
return oldsym;
}
// Else, just insert normally and return nullptr since there was no
// symbol to replace.
Symbols.Insert(newsym->SymbolName, newsym);
return nullptr;
}
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 != 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);
}

View file

@ -39,36 +39,6 @@ enum
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature 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 ------------------------------------------------------- // An action function -------------------------------------------------------
struct FState; struct FState;
@ -79,101 +49,6 @@ struct VMReturn;
class VMFunction; class VMFunction;
struct FNamespaceManager; 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<FName, PSymbol *> 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 ------------------------------------ // Basic information shared by all types ------------------------------------
// Only one copy of a type is ever instantiated at one time. // Only one copy of a type is ever instantiated at one time.
@ -202,7 +77,6 @@ struct ZCC_ExprConstant;
class PType : public PTypeBase class PType : public PTypeBase
{ {
DECLARE_ABSTRACT_CLASS(PType, PTypeBase) DECLARE_ABSTRACT_CLASS(PType, PTypeBase)
HAS_OBJECT_POINTERS;
protected: protected:
public: public:
@ -296,8 +170,6 @@ public:
const char *DescriptiveName() const; const char *DescriptiveName() const;
size_t PropagateMark();
static void StaticInit(); static void StaticInit();
}; };
@ -335,7 +207,6 @@ class PCompoundType : public PType
class PNamedType : public PCompoundType class PNamedType : public PCompoundType
{ {
DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType);
HAS_OBJECT_POINTERS;
public: public:
PTypeBase *Outer; // object this type is contained within PTypeBase *Outer; // object this type is contained within
FName TypeName; // this type's name FName TypeName; // this type's name
@ -349,7 +220,6 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
virtual FString QualifiedName() const;
}; };
// Basic types -------------------------------------------------------------- // Basic types --------------------------------------------------------------
@ -492,7 +362,6 @@ public:
class PPointer : public PBasicType class PPointer : public PBasicType
{ {
DECLARE_CLASS(PPointer, PBasicType); DECLARE_CLASS(PPointer, PBasicType);
HAS_OBJECT_POINTERS;
public: public:
PPointer(); PPointer();
PPointer(PType *pointsat, bool isconst = false); PPointer(PType *pointsat, bool isconst = false);
@ -525,7 +394,6 @@ public:
class PClassPointer : public PPointer class PClassPointer : public PPointer
{ {
DECLARE_CLASS(PClassPointer, PPointer); DECLARE_CLASS(PClassPointer, PPointer);
HAS_OBJECT_POINTERS;
public: public:
PClassPointer(class PClass *restrict = nullptr); PClassPointer(class PClass *restrict = nullptr);
@ -537,58 +405,11 @@ public:
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
}; };
// 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<PField *> &variables);
TArray<PField *> 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 ----------------------------------------------------------- // Compound types -----------------------------------------------------------
class PEnum : public PInt class PEnum : public PInt
{ {
DECLARE_CLASS(PEnum, PInt); DECLARE_CLASS(PEnum, PInt);
HAS_OBJECT_POINTERS;
public: public:
PEnum(FName name, PTypeBase *outer); PEnum(FName name, PTypeBase *outer);
@ -601,7 +422,6 @@ protected:
class PArray : public PCompoundType class PArray : public PCompoundType
{ {
DECLARE_CLASS(PArray, PCompoundType); DECLARE_CLASS(PArray, PCompoundType);
HAS_OBJECT_POINTERS;
public: public:
PArray(PType *etype, unsigned int ecount); PArray(PType *etype, unsigned int ecount);
@ -625,7 +445,6 @@ protected:
class PResizableArray : public PArray class PResizableArray : public PArray
{ {
DECLARE_CLASS(PResizableArray, PArray); DECLARE_CLASS(PResizableArray, PArray);
HAS_OBJECT_POINTERS;
public: public:
PResizableArray(PType *etype); PResizableArray(PType *etype);
@ -639,7 +458,6 @@ protected:
class PDynArray : public PCompoundType class PDynArray : public PCompoundType
{ {
DECLARE_CLASS(PDynArray, PCompoundType); DECLARE_CLASS(PDynArray, PCompoundType);
HAS_OBJECT_POINTERS;
public: public:
PDynArray(PType *etype, PStruct *backing); PDynArray(PType *etype, PStruct *backing);
@ -663,7 +481,6 @@ protected:
class PMap : public PCompoundType class PMap : public PCompoundType
{ {
DECLARE_CLASS(PMap, PCompoundType); DECLARE_CLASS(PMap, PCompoundType);
HAS_OBJECT_POINTERS;
public: public:
PMap(PType *keytype, PType *valtype); PMap(PType *keytype, PType *valtype);
@ -692,8 +509,6 @@ public:
virtual PField *AddField(FName name, PType *type, DWORD flags=0); 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); 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; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override; void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
@ -730,36 +545,6 @@ protected:
PPrototype(); PPrototype();
}; };
// TBD: Should we really support overloading?
class PFunction : public PSymbol
{
DECLARE_CLASS(PFunction, PSymbol);
public:
struct Variant
{
PPrototype *Proto;
VMFunction *Implementation;
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
uint32_t Flags;
int UseFlags;
PStruct *SelfClass;
};
TArray<Variant> Variants;
PStruct *OwningClass = nullptr;
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &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 --------------------------- // Meta-info for every class derived from DObject ---------------------------
@ -771,7 +556,6 @@ enum
class PClass : public PNativeStruct class PClass : public PNativeStruct
{ {
DECLARE_CLASS(PClass, PNativeStruct); DECLARE_CLASS(PClass, PNativeStruct);
HAS_OBJECT_POINTERS;
protected: protected:
// We unravel _WITH_META here just as we did for PType. // We unravel _WITH_META here just as we did for PType.
TArray<FTypeAndOffset> SpecialInits; TArray<FTypeAndOffset> SpecialInits;
@ -828,11 +612,24 @@ public:
} }
return false; return false;
} }
inline bool IsDescendantOf(const PClass *ti) const inline bool IsDescendantOf(const PClass *ti) const
{ {
return ti->IsAncestorOf(this); 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. // Find a type, given its name.
const PClass *FindParentClass(FName name) const; const PClass *FindParentClass(FName name) const;
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); } PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
@ -865,10 +662,8 @@ struct FTypeTable
PType *TypeHash[HASH_SIZE]; PType *TypeHash[HASH_SIZE];
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); 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, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
void AddType(PType *type); void AddType(PType *type);
void Mark();
void Clear(); void Clear();
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
@ -915,82 +710,6 @@ extern PStateLabel *TypeStateLabel;
extern PPointer *TypeNullPtr; extern PPointer *TypeNullPtr;
extern PPointer *TypeVoidPtr; 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<PNamespace *> AllNamespaces;
FNamespaceManager();
PNamespace *NewNamespace(int filenum);
size_t MarkSymbols();
void ReleaseSymbols();
int RemoveSymbols();
};
extern FNamespaceManager Namespaces;
// Enumerations for serializing types in an archive ------------------------- // Enumerations for serializing types in an archive -------------------------
inline bool &DObject::BoolVar(FName field) inline bool &DObject::BoolVar(FName field)

View file

@ -41,6 +41,8 @@
#endif #endif
#include <limits.h> #include <limits.h>
#include <tuple>
#include <algorithm>
#include "tarray.h" #include "tarray.h"
#include "name.h" #include "name.h"
#include "zstring.h" #include "zstring.h"
@ -155,12 +157,9 @@ struct PalEntry
#endif #endif
}; };
class PClassInventory;
class FTextureID class FTextureID
{ {
friend class FTextureManager; friend class FTextureManager;
friend FTextureID GetHUDIcon(PClassInventory *cls);
friend void R_InitSpriteDefs(); friend void R_InitSpriteDefs();
public: public:

View file

@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum)
// Doom index is only supported for the 4 original ammo types // 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; const char * p;
@ -361,8 +361,8 @@ static PClassInventory * T_GetAmmo(const svalue_t &t)
} }
p=DefAmmo[ammonum]; p=DefAmmo[ammonum];
} }
PClassInventory * am=dyn_cast<PClassInventory>(PClass::FindActor(p)); auto am = PClass::FindActor(p);
if (am == NULL) if (am == NULL || !am->IsKindOf(PClass::FindClass(NAME_Ammo)))
{ {
script_error("unknown ammo type : %s", p); script_error("unknown ammo type : %s", p);
return NULL; return NULL;
@ -2434,8 +2434,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount)
{ {
type = "BasicArmorPickup"; type = "BasicArmorPickup";
} }
PClassInventory * info = dyn_cast<PClassInventory>(PClass::FindActor (type)); auto info = PClass::FindActor (type);
if (info == NULL) if (info == NULL || !info->IsKindOf(RUNTIME_CLASS(AInventory)))
{ {
Printf ("Unknown inventory item: %s\n", type); Printf ("Unknown inventory item: %s\n", type);
return; return;
@ -2564,7 +2564,7 @@ void FParser::SF_PlayerKeys(void)
void FParser::SF_PlayerAmmo(void) void FParser::SF_PlayerAmmo(void)
{ {
int playernum, amount; int playernum, amount;
PClassInventory * ammotype; PClassActor * ammotype;
if (CheckArgs(2)) if (CheckArgs(2))
{ {
@ -2600,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void)
void FParser::SF_MaxPlayerAmmo() void FParser::SF_MaxPlayerAmmo()
{ {
int playernum, amount; int playernum, amount;
PClassInventory * ammotype; PClassActor * ammotype;
if (CheckArgs(2)) if (CheckArgs(2))
{ {
@ -2629,7 +2629,7 @@ void FParser::SF_MaxPlayerAmmo()
for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory) 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]); if (t_argc>=4) amount = intvalue(t_argv[3]);
else amount*=2; else amount*=2;
@ -2676,7 +2676,7 @@ void FParser::SF_PlayerWeapon()
return; return;
} }
auto ti = PClass::FindActor(WeaponNames[weaponnum]); auto ti = PClass::FindActor(WeaponNames[weaponnum]);
if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (!ti || !ti->IsDescendantOf(NAME_Weapon))
{ {
script_error("incompatibility in playerweapon %d\n", weaponnum); script_error("incompatibility in playerweapon %d\n", weaponnum);
return; return;
@ -2712,7 +2712,7 @@ void FParser::SF_PlayerWeapon()
{ {
if (!wp) if (!wp)
{ {
AWeapon * pw=players[playernum].PendingWeapon; auto pw=players[playernum].PendingWeapon;
players[playernum].mo->GiveInventoryType(ti); players[playernum].mo->GiveInventoryType(ti);
players[playernum].PendingWeapon=pw; players[playernum].PendingWeapon=pw;
} }
@ -2757,7 +2757,7 @@ void FParser::SF_PlayerSelectedWeapon()
return; return;
} }
auto ti = PClass::FindActor(WeaponNames[weaponnum]); auto ti = PClass::FindActor(WeaponNames[weaponnum]);
if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (!ti || !ti->IsDescendantOf(NAME_Weapon))
{ {
script_error("incompatibility in playerweapon %d\n", weaponnum); script_error("incompatibility in playerweapon %d\n", weaponnum);
return; return;
@ -2862,7 +2862,7 @@ void FParser::SF_SetWeapon()
{ {
AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1]))); 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) else if (players[playernum].ReadyWeapon == item)
@ -2874,7 +2874,7 @@ void FParser::SF_SetWeapon()
} }
else else
{ {
AWeapon *weap = static_cast<AWeapon *> (item); auto weap = static_cast<AWeapon *> (item);
if (weap->CheckAmmo (AWeapon::EitherFire, false)) if (weap->CheckAmmo (AWeapon::EitherFire, false))
{ {

View file

@ -1361,7 +1361,7 @@ void G_PlayerReborn (int player)
BYTE currclass; BYTE currclass;
userinfo_t userinfo; // [RH] Save userinfo userinfo_t userinfo; // [RH] Save userinfo
APlayerPawn *actor; APlayerPawn *actor;
PClassPlayerPawn *cls; PClassActor *cls;
FString log; FString log;
DBot *Bot; //Added by MC: DBot *Bot; //Added by MC:

View file

@ -187,7 +187,7 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc)
keygroup->anykeylist.Push (k); keygroup->anykeylist.Push (k);
//... but only keys get key numbers! //... but only keys get key numbers!
if (mi->IsDescendantOf(PClass::FindActor(NAME_Key))) if (mi->IsDescendantOf(NAME_Key))
{ {
if (!ignorekey && if (!ignorekey &&
GetDefaultByType(mi)->special1 == 0) GetDefaultByType(mi)->special1 == 0)

View file

@ -25,54 +25,6 @@
EXTERN_CVAR(Bool, sv_unlimited_pickup) 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<PClassInventory *>(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<PClassActor *>(newclass);
for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++)
{
if (ForbiddenToPlayerClass[i] == oldclass)
{
ForbiddenToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
changed++;
}
}
for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++)
{
if (RestrictedToPlayerClass[i] == oldclass)
{
RestrictedToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
changed++;
}
}
}
return changed;
}
void AInventory::Finalize(FStateDefinitions &statedef) void AInventory::Finalize(FStateDefinitions &statedef)
{ {
Super::Finalize(statedef); Super::Finalize(statedef);
@ -98,8 +50,8 @@ DEFINE_FIELD(AInventory, DropTime)
DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, SpawnPointClass)
DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupFlash)
DEFINE_FIELD(AInventory, PickupSound) DEFINE_FIELD(AInventory, PickupSound)
DEFINE_FIELD(PClassInventory, PickupMsg) DEFINE_FIELD(AInventory, GiveQuest)
DEFINE_FIELD(PClassInventory, GiveQuest) DEFINE_FIELD(PClassActor, PickupMsg)
//=========================================================================== //===========================================================================
// //
@ -163,7 +115,8 @@ void AInventory::Serialize(FSerializer &arc)
("icon", Icon, def->Icon) ("icon", Icon, def->Icon)
("pickupsound", PickupSound, def->PickupSound) ("pickupsound", PickupSound, def->PickupSound)
("spawnpointclass", SpawnPointClass, def->SpawnPointClass) ("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) if (!toucher)
ACTION_RETURN_BOOL(false); ACTION_RETURN_BOOL(false);
PClassInventory *ai = self->GetClass(); auto ai = self->GetClass();
// Is the item restricted to certain player classes? // Is the item restricted to certain player classes?
if (ai->RestrictedToPlayerClass.Size() != 0) if (ai->RestrictedToPlayerClass.Size() != 0)
{ {

View file

@ -9,7 +9,6 @@
class player_t; class player_t;
class FConfigFile; class FConfigFile;
class PClassPlayerPawn;
struct visstyle_t; struct visstyle_t;
/************************************************************************/ /************************************************************************/
@ -50,25 +49,9 @@ 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<PClassPlayerPawn *> RestrictedToPlayerClass;
TArray<PClassPlayerPawn *> ForbiddenToPlayerClass;
};
class AInventory : public AActor class AInventory : public AActor
{ {
DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) DECLARE_CLASS(AInventory, AActor)
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
public: public:
@ -104,6 +87,8 @@ public:
FTextureID Icon; // Icon to show on status bar or HUD FTextureID Icon; // Icon to show on status bar or HUD
int DropTime; // Countdown after dropping int DropTime; // Countdown after dropping
PClassActor *SpawnPointClass; // For respawning like Heretic's mace PClassActor *SpawnPointClass; // For respawning like Heretic's mace
int GiveQuest; // Optionally give one of the quest items.
FTextureID AltHUDIcon;
DWORD ItemFlags; DWORD ItemFlags;
PClassActor *PickupFlash; // actor to spawn as pickup flash PClassActor *PickupFlash; // actor to spawn as pickup flash

View file

@ -64,9 +64,6 @@ IMPLEMENT_POINTERS_START(AWeapon)
IMPLEMENT_POINTER(Ammo1) IMPLEMENT_POINTER(Ammo1)
IMPLEMENT_POINTER(Ammo2) IMPLEMENT_POINTER(Ammo2)
IMPLEMENT_POINTER(SisterWeapon) IMPLEMENT_POINTER(SisterWeapon)
IMPLEMENT_POINTER(AmmoType1)
IMPLEMENT_POINTER(AmmoType2)
IMPLEMENT_POINTER(SisterWeaponType)
IMPLEMENT_POINTERS_END IMPLEMENT_POINTERS_END
DEFINE_FIELD(AWeapon, WeaponFlags) DEFINE_FIELD(AWeapon, WeaponFlags)
@ -528,7 +525,7 @@ bool FWeaponSlot::AddWeapon(PClassActor *type)
return false; 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()); Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars());
return false; return false;
@ -635,7 +632,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{ {
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[j].Type)); AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[j].Type));
if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{ {
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{ {
@ -650,7 +647,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{ {
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[i].Type)); AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[i].Type));
if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{ {
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{ {
@ -982,7 +979,7 @@ void FWeaponSlots::AddExtraWeapons()
{ {
PClassActor *cls = PClassActor::AllActorClasses[i]; PClassActor *cls = PClassActor::AllActorClasses[i];
if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (!cls->IsDescendantOf(NAME_Weapon))
{ {
continue; continue;
} }
@ -1058,7 +1055,7 @@ void FWeaponSlots::SetFromGameInfo()
// //
//=========================================================================== //===========================================================================
void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) void FWeaponSlots::StandardSetup(PClassActor *type)
{ {
SetFromPlayer(type); SetFromPlayer(type);
AddExtraWeapons(); AddExtraWeapons();
@ -1151,14 +1148,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other)
// //
//=========================================================================== //===========================================================================
void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) void FWeaponSlots::SetFromPlayer(PClassActor *type)
{ {
Clear(); Clear();
auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot;
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) 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);
} }
} }
} }
@ -1342,7 +1340,7 @@ CCMD (weaponsection)
//=========================================================================== //===========================================================================
void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback)
{ {
if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (type != nullptr && type->IsDescendantOf(NAME_Weapon))
{ {
switch (AddDefaultWeapon(slot, type)) switch (AddDefaultWeapon(slot, type))
{ {
@ -1441,7 +1439,7 @@ void P_SetupWeapons_ntohton()
{ {
PClassActor *cls = PClassActor::AllActorClasses[i]; PClassActor *cls = PClassActor::AllActorClasses[i];
if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (cls->IsDescendantOf(NAME_Weapon))
{ {
Weapons_ntoh.Push(static_cast<PClassActor *>(cls)); Weapons_ntoh.Push(static_cast<PClassActor *>(cls));
} }

View file

@ -65,8 +65,8 @@ struct FWeaponSlots
ESlotDef AddDefaultWeapon (int slot, PClassActor *type); ESlotDef AddDefaultWeapon (int slot, PClassActor *type);
void AddExtraWeapons(); void AddExtraWeapons();
void SetFromGameInfo(); void SetFromGameInfo();
void SetFromPlayer(PClassPlayerPawn *type); void SetFromPlayer(PClassActor *type);
void StandardSetup(PClassPlayerPawn *type); void StandardSetup(PClassActor *type);
void LocalSetup(PClassActor *type); void LocalSetup(PClassActor *type);
void SendDifferences(int playernum, const FWeaponSlots &other); void SendDifferences(int playernum, const FWeaponSlots &other);
int RestoreSlots (FConfigFile *config, const char *section); int RestoreSlots (FConfigFile *config, const char *section);
@ -92,7 +92,7 @@ class AWeapon : public AStateProvider
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
public: public:
DWORD WeaponFlags; 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 AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot int AmmoUse1, AmmoUse2; // How much ammo to use with each shot

View file

@ -20,3 +20,4 @@
#include <io.h> #include <io.h>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <tuple>

View file

@ -42,7 +42,7 @@ void A_Unblock(AActor *self, bool drop)
// If the actor has attached metadata for items to drop, drop those. // If the actor has attached metadata for items to drop, drop those.
if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
{ {
DDropItem *di = self->GetDropItems(); auto di = self->GetDropItems();
if (di != NULL) if (di != NULL)
{ {

View file

@ -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; AInventory *item;
APlayerPawn *morphed; APlayerPawn *morphed;
@ -290,8 +290,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
// and for the original DOOM status bar. // and for the original DOOM status bar.
if (player == &players[consoleplayer]) if (player == &players[consoleplayer])
{ {
FString face = pmo->GetClass()->Face; FName face = pmo->Face;
if (face.IsNotEmpty() && strcmp(face, "None") != 0) if (face != NAME_None)
{ {
// Assume root-level base skin to begin with // Assume root-level base skin to begin with
size_t skinindex = 0; size_t skinindex = 0;
@ -337,7 +337,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
if (correctweapon) if (correctweapon)
{ // Better "lose morphed weapon" semantics { // Better "lose morphed weapon" semantics
PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); 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<AWeapon *>(mo->FindInventory (morphweapon)); AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon));
if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon)) if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon))
@ -367,7 +367,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
if (hxarmor != nullptr) if (hxarmor != nullptr)
{ {
double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr); double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
Slots[4] = mo->GetClass()->HexenArmor[0]; Slots[4] = mo->HexenArmor[0];
} }
return true; return true;
} }

View file

@ -35,7 +35,7 @@ class AActor;
class player_t; class player_t;
class AMorphedMonster; 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); 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_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, bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0,

View file

@ -122,16 +122,6 @@ static int statspace;
DVector2 AM_GetPosition(); DVector2 AM_GetPosition();
int active_con_scaletext(); 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 // 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) static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv)
{ {
FTextureID icon = FNullTextureID(); FTextureID icon = FNullTextureID();
FTextureID AltIcon = GetHUDIcon(inv->GetClass()); FTextureID AltIcon = inv->AltHUDIcon;
if (!AltIcon.Exists()) return; if (!AltIcon.Exists()) return;
@ -516,14 +506,14 @@ static int DrawKeys(player_t * CPlayer, int x, int y)
// Drawing Ammo // Drawing Ammo
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static TArray<PClassInventory *> orderedammos; static TArray<PClassActor *> orderedammos;
static void AddAmmoToList(AWeapon * weapdef) 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) if (ti)
{ {
auto ammodef = (AInventory*)GetDefaultByType(ti); auto ammodef = (AInventory*)GetDefaultByType(ti);
@ -612,7 +602,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
// Now check for the remaining weapons that are in the inventory but not in the weapon slots // Now check for the remaining weapons that are in the inventory but not in the weapon slots
for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory)
{ {
if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) if (inv->IsKindOf(NAME_Weapon))
{ {
AddAmmoToList((AWeapon*)inv); 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--) for(i=orderedammos.Size()-1;i>=0;i--)
{ {
PClassInventory * type = orderedammos[i]; auto type = orderedammos[i];
auto ammoitem = CPlayer->mo->FindInventory(type); auto ammoitem = CPlayer->mo->FindInventory(type);
auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]); auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
FTextureID AltIcon = GetHUDIcon(type); FTextureID AltIcon = inv->AltHUDIcon;
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
if (!icon.isValid()) continue; 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 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; FState * state=NULL, *ReadyState;
picnum.SetNull(); 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 // 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; 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 // First draw all weapons in the inventory that are not assigned to a weapon slot
for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) 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<AWeapon*>(inv)->GetClass(), NULL, NULL)) !CPlayer->weapons.LocateWeapon(static_cast<AWeapon*>(inv)->GetClass(), NULL, NULL))
{ {
DrawOneWeapon(CPlayer, x, y, static_cast<AWeapon*>(inv)); DrawOneWeapon(CPlayer, x, y, static_cast<AWeapon*>(inv));
@ -816,7 +806,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y)
{ {
if (rover->Amount>0) if (rover->Amount>0)
{ {
FTextureID AltIcon = GetHUDIcon(rover->GetClass()); FTextureID AltIcon = rover->AltHUDIcon;
if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) ) if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) )
{ {
@ -1285,7 +1275,7 @@ void HUD_InitHud()
} }
else tex.SetInvalid(); else tex.SetInvalid();
if (ti) SetHUDIcon(static_cast<PClassInventory*>(ti), tex); if (ti) ((AInventory*)GetDefaultByType(ti))->AltHUDIcon = tex;
} }
} }
} }

View file

@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu
if (CurrentState != NULL) if (CurrentState != NULL)
{ {
int skin = player->userinfo.GetSkin(); 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 CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle);
} }
return NULL; return NULL;

View file

@ -148,7 +148,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
{ {
type = INVENTORYICON; type = INVENTORYICON;
const PClass* item = PClass::FindClass(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); 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) for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{ {
PClassActor *cls = PClassActor::AllActorClasses[i]; PClassActor *cls = PClassActor::AllActorClasses[i];
if (cls->IsDescendantOf(PClass::FindActor(NAME_Key))) if (cls->IsDescendantOf(NAME_Key))
{ {
auto key = GetDefaultByType(cls); auto key = GetDefaultByType(cls);
if (key->special1 == keynum) if (key->special1 == keynum)
@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
{ {
inventoryItem[0] = sc.String; inventoryItem[0] = sc.String;
const PClass* item = PClass::FindClass(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); sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
} }
@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem[1] = sc.String; inventoryItem[1] = sc.String;
const PClass* item = PClass::FindClass(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); 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) 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; int keynum = item->special1;
if(keynum) if(keynum)
@ -1078,7 +1078,7 @@ class CommandDrawNumber : public CommandDrawString
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
inventoryItem = PClass::FindActor(NAME_Ammo); inventoryItem = PClass::FindActor(NAME_Ammo);
@ -1094,7 +1094,7 @@ class CommandDrawNumber : public CommandDrawString
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
inventoryItem = PClass::FindActor(NAME_Ammo); inventoryItem = PClass::FindActor(NAME_Ammo);
@ -1160,7 +1160,7 @@ class CommandDrawNumber : public CommandDrawString
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
inventoryItem = PClass::FindActor(NAME_PowerupGiver); inventoryItem = PClass::FindActor(NAME_PowerupGiver);
@ -1203,7 +1203,7 @@ class CommandDrawNumber : public CommandDrawString
if(value == INVENTORY) if(value == INVENTORY)
{ {
inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
inventoryItem = RUNTIME_CLASS(AInventory); inventoryItem = RUNTIME_CLASS(AInventory);
@ -1476,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString
num = 0; num = 0;
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) 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++; num++;
} }
break; break;
@ -2431,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand
int rowWidth = 0; int rowWidth = 0;
for(unsigned int i = 0;i < number+keyOffset;i++) 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; item = item->Inventory;
if(item == NULL) if(item == NULL)
@ -2632,7 +2632,7 @@ class CommandDrawBar : public SBarInfoCommand
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
type = AMMO; type = AMMO;
data.inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
data.inventoryItem = PClass::FindActor(NAME_Ammo); data.inventoryItem = PClass::FindActor(NAME_Ammo);
@ -2660,7 +2660,7 @@ class CommandDrawBar : public SBarInfoCommand
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
data.inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
data.inventoryItem = PClass::FindActor(NAME_PowerupGiver); data.inventoryItem = PClass::FindActor(NAME_PowerupGiver);
@ -2672,7 +2672,7 @@ class CommandDrawBar : public SBarInfoCommand
{ {
type = INVENTORY; type = INVENTORY;
data.inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
data.inventoryItem = RUNTIME_CLASS(AInventory); 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 if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference
{ {
data.inventoryItem = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
data.inventoryItem = RUNTIME_CLASS(AInventory); data.inventoryItem = RUNTIME_CLASS(AInventory);
@ -2977,7 +2977,7 @@ class CommandIsSelected : public SBarInfoNegatableFlowControl
for(int i = 0;i < 2;i++) for(int i = 0;i < 2;i++)
{ {
weapon[i] = PClass::FindClass(sc.String); 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); sc.ScriptMessage("'%s' is not a type of weapon.", sc.String);
weapon[i] = RUNTIME_CLASS(AWeapon); weapon[i] = RUNTIME_CLASS(AWeapon);
@ -3130,7 +3130,7 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
if(!sc.CheckToken(TK_StringConst)) if(!sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
weapon = PClass::FindClass(sc.String); 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); sc.ScriptMessage("%s is not a kind of weapon.", sc.String);
weapon = RUNTIME_CLASS(AWeapon); weapon = RUNTIME_CLASS(AWeapon);
@ -3317,7 +3317,7 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl
for(int i = 0;i < 2;i++) for(int i = 0;i < 2;i++)
{ {
ammo[i] = PClass::FindClass(sc.String); 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); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
ammo[i] = PClass::FindActor(NAME_Ammo); ammo[i] = PClass::FindActor(NAME_Ammo);
@ -3400,7 +3400,7 @@ class CommandInInventory : public SBarInfoNegatableFlowControl
for(int i = 0;i < 2;i++) for(int i = 0;i < 2;i++)
{ {
item[i] = PClass::FindActor(sc.String); 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); sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
item[i] = RUNTIME_CLASS(AInventory); item[i] = RUNTIME_CLASS(AInventory);

View file

@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox();
inline PClassActor * GetRealType(PClassActor * ti) inline PClassActor * GetRealType(PClassActor * ti)
{ {
PClassActor *rep = ti->GetReplacement(false); 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; return rep;
} }

View file

@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
const char *callinfo = ""; const char *callinfo = "";
if (info != nullptr && info->mStateType == STATE_Psprite) 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 "; else callinfo = "overlay ";
} }
err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); 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)); ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false));
} }
IMPLEMENT_CLASS(PClassActor, false, true) IMPLEMENT_CLASS(PClassActor, false, false)
IMPLEMENT_POINTERS_START(PClassActor)
IMPLEMENT_POINTER(DropItems)
IMPLEMENT_POINTERS_END
//========================================================================== //==========================================================================
// //
@ -349,32 +345,12 @@ void PClassActor::DeriveData(PClass *newclass)
*newa->PainChances = *PainChances; *newa->PainChances = *PainChances;
} }
} // Inventory stuff
newa->PickupMsg = PickupMsg;
newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass;
newa->RestrictedToPlayerClass = RestrictedToPlayerClass;
//========================================================================== newa->DisplayName = DisplayName;
//
// 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();
} }
//========================================================================== //==========================================================================
@ -414,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName)
// //
//========================================================================== //==========================================================================
void PClassActor::SetDropItems(DDropItem *drops) void PClassActor::SetDropItems(FDropItem *drops)
{ {
DropItems = drops; DropItems = drops;
GC::WriteBarrier(this, DropItems);
} }
@ -659,10 +634,33 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass)
{ {
if (VisibleToPlayerClass[i] == oldclass) if (VisibleToPlayerClass[i] == oldclass)
{ {
VisibleToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass); VisibleToPlayerClass[i] = static_cast<PClassActor*>(newclass);
changed++; changed++;
} }
} }
for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++)
{
if (ForbiddenToPlayerClass[i] == oldclass)
{
ForbiddenToPlayerClass[i] = static_cast<PClassActor*>(newclass);
changed++;
}
}
for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++)
{
if (RestrictedToPlayerClass[i] == oldclass)
{
RestrictedToPlayerClass[i] = static_cast<PClassActor*>(newclass);
changed++;
}
}
AInventory *def = dyn_cast<AInventory>((AActor*)Defaults);
if (def != NULL)
{
if (def->PickupFlash == oldclass) def->PickupFlash = static_cast<PClassActor *>(newclass);
}
return changed; return changed;
} }

View file

@ -234,13 +234,11 @@ private:
static DamageTypeDefinition *Get(FName type); static DamageTypeDefinition *Get(FName type);
}; };
class DDropItem; struct FDropItem;
class PClassPlayerPawn;
class PClassActor : public PClass class PClassActor : public PClass
{ {
DECLARE_CLASS(PClassActor, PClass); DECLARE_CLASS(PClassActor, PClass);
HAS_OBJECT_POINTERS;
protected: protected:
public: public:
static void StaticInit (); static void StaticInit ();
@ -256,9 +254,8 @@ public:
void RegisterIDs(); void RegisterIDs();
void SetDamageFactor(FName type, double factor); void SetDamageFactor(FName type, double factor);
void SetPainChance(FName type, int chance); void SetPainChance(FName type, int chance);
size_t PropagateMark();
bool SetReplacement(FName replaceName); bool SetReplacement(FName replaceName);
void SetDropItems(DDropItem *drops); void SetDropItems(FDropItem *drops);
FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindState(int numnames, FName *names, bool exact=false) const;
FState *FindStateByString(const char *name, bool exact=false); FState *FindStateByString(const char *name, bool exact=false);
@ -288,7 +285,7 @@ public:
DmgFactors *DamageFactors; DmgFactors *DamageFactors;
PainChanceList *PainChances; PainChanceList *PainChances;
TArray<PClassPlayerPawn *> VisibleToPlayerClass; TArray<PClassActor *> VisibleToPlayerClass;
FString Obituary; // Player was killed by this actor FString Obituary; // Player was killed by this actor
FString HitObituary; // Player was killed by this actor in melee FString HitObituary; // Player was killed by this actor in melee
@ -305,7 +302,7 @@ public:
FName BloodType2; // Bloopsplatter replacement type FName BloodType2; // Bloopsplatter replacement type
FName BloodType3; // AxeBlood replacement type FName BloodType3; // AxeBlood replacement type
DDropItem *DropItems; FDropItem *DropItems;
FString SourceLumpName; FString SourceLumpName;
FIntCVar *distancecheck; FIntCVar *distancecheck;
@ -318,6 +315,14 @@ public:
FName MissileName; FName MissileName;
double MissileHeight; double MissileHeight;
// These are only valid for inventory items.
FString PickupMsg;
TArray<PClassActor *> RestrictedToPlayerClass;
TArray<PClassActor *> ForbiddenToPlayerClass;
// This is from PClassPlayerPawn
FString DisplayName;
// For those times when being able to scan every kind of actor is convenient // For those times when being able to scan every kind of actor is convenient
static TArray<PClassActor *> AllActorClasses; static TArray<PClassActor *> AllActorClasses;
}; };

View file

@ -170,7 +170,7 @@ void cht_DoCheat (player_t *player, int cheat)
break; break;
case CHT_MORPH: case CHT_MORPH:
msg = cht_Morph (player, static_cast<PClassPlayerPawn *>(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; break;
case CHT_NOTARGET: case CHT_NOTARGET:
@ -317,7 +317,7 @@ void cht_DoCheat (player_t *player, int cheat)
case CHT_RESSURECT: case CHT_RESSURECT:
if (player->playerstate != PST_LIVE && player->mo != nullptr) 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"); Printf("Unable to resurrect. Player is no longer connected to its body.\n");
} }
@ -421,7 +421,7 @@ void cht_DoCheat (player_t *player, int cheat)
{ {
lastinvp = invp; lastinvp = invp;
invp = &(*invp)->Inventory; invp = &(*invp)->Inventory;
if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) if (item->IsKindOf(NAME_Weapon))
{ {
AWeapon *weap = static_cast<AWeapon *> (item); AWeapon *weap = static_cast<AWeapon *> (item);
if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) ||
@ -548,13 +548,13 @@ void cht_DoCheat (player_t *player, int cheat)
Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); 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) if (player->mo == NULL)
{ {
return ""; return "";
} }
PClassPlayerPawn *oldclass = player->mo->GetClass(); auto oldclass = player->mo->GetClass();
// Set the standard morph style for the current game // Set the standard morph style for the current game
int style = MORPH_UNDOBYTOMEOFPOWER; int style = MORPH_UNDOBYTOMEOFPOWER;

View file

@ -29,12 +29,12 @@
// [RH] Functions that actually perform the cheating // [RH] Functions that actually perform the cheating
class player_t; class player_t;
class PClassPlayerPawn; class PClassActor;
void cht_DoCheat (player_t *player, int cheat); void cht_DoCheat (player_t *player, int cheat);
void cht_Give (player_t *player, const char *item, int amount=1); 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_Take (player_t *player, const char *item, int amount=1);
void cht_Suicide (player_t *player); 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 #endif

View file

@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks()
FreeBlockChain(FreeBlocks); 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 // FMemArena :: FreeBlockChain

View file

@ -46,6 +46,7 @@ public:
void *Alloc(size_t size); void *Alloc(size_t size);
void FreeAll(); void FreeAll();
void FreeAllBlocks(); void FreeAllBlocks();
void DumpInfo();
protected: protected:
struct Block; struct Block;

View file

@ -430,7 +430,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation()
if (mPlayerClass != NULL) if (mPlayerClass != NULL)
{ {
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); 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]); &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
} }
} }
@ -552,11 +552,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected)
return; 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()) if (texid.isValid())
{ {
FTexture *tex = TexMan(texid); FTexture *tex = TexMan(texid);

View file

@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation()
if (PlayerClass != NULL) if (PlayerClass != NULL)
{ {
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); 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]); &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
} }
} }
@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets()
if (li != NULL) if (li != NULL)
{ {
int sel = 0; int sel = 0;
PlayerClass->Type->EnumColorSets(&PlayerColorSets); EnumColorSets(PlayerClass->Type, &PlayerColorSets);
li->SetString(0, "Custom"); li->SetString(0, "Custom");
for(unsigned i=0;i<PlayerColorSets.Size(); i++) for(unsigned i=0;i<PlayerColorSets.Size(); i++)
{ {
FPlayerColorSet *colorset = PlayerClass->Type->GetColorSet(PlayerColorSets[i]); FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]);
li->SetString(i+1, colorset->Name); li->SetString(i+1, colorset->Name);
} }
int mycolorset = players[consoleplayer].userinfo.GetColorSet(); int mycolorset = players[consoleplayer].userinfo.GetColorSet();
@ -899,7 +899,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li)
players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1);
PickPlayerClass(); 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(); UpdateSkins();
UpdateColorsets(); UpdateColorsets();

View file

@ -1193,12 +1193,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount)
for (int i = 0; i < MAXPLAYERS; ++i) for (int i = 0; i < MAXPLAYERS; ++i)
{ {
if (playeringame[i]) if (playeringame[i])
players[i].mo->GiveInventory(static_cast<PClassInventory *>(info), amount); players[i].mo->GiveInventory(info, amount);
} }
} }
else else
{ {
activator->GiveInventory(static_cast<PClassInventory *>(info), amount); activator->GiveInventory(info, amount);
} }
} }
@ -5716,7 +5716,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
if (argCount >= 2) if (argCount >= 2)
{ {
PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1])); 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])); Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1]));
return 0; return 0;
@ -9042,7 +9042,7 @@ scriptwait:
AInventory *item = activator->FindInventory (dyn_cast<PClassActor>( AInventory *item = activator->FindInventory (dyn_cast<PClassActor>(
PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); PClass::FindClass (FBehavior::StaticLookupString (STACK(1)))));
if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) if (item == NULL || !item->IsKindOf(NAME_Weapon))
{ {
STACK(1) = 0; STACK(1) = 0;
} }
@ -9110,7 +9110,7 @@ scriptwait:
} }
else else
{ {
if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) if (activator != nullptr && activator->IsKindOf("ScriptedMarine"))
{ {
SetMarineSprite(activator, type); SetMarineSprite(activator, type);
} }
@ -9491,7 +9491,7 @@ scriptwait:
{ {
int tag = STACK(7); int tag = STACK(7);
FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); FName playerclass_name = FBehavior::StaticLookupString(STACK(6));
PClassPlayerPawn *playerclass = dyn_cast<PClassPlayerPawn>(PClass::FindClass (playerclass_name)); auto playerclass = PClass::FindActor (playerclass_name);
FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5));
PClassActor *monsterclass = PClass::FindActor(monsterclass_name); PClassActor *monsterclass = PClass::FindActor(monsterclass_name);
int duration = STACK(4); int duration = STACK(4);

View file

@ -2387,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS)
{ {
return false; return false;
} }
if (item->IsKindOf(PClass::FindActor(NAME_Health))) if (item->IsKindOf(NAME_Health))
{ {
item->Amount *= amount; item->Amount *= amount;
} }
@ -3123,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon)
AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls)); AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls));
if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon))
{ {
if (self->player->ReadyWeapon != weaponitem) if (self->player->ReadyWeapon != weaponitem)
{ {
@ -5668,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)) 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. { // 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<AInventory *>(Spawn(item)); AInventory *gift = static_cast<AInventory *>(Spawn(item));
if (gift->IsKindOf(PClass::FindActor(NAME_Health))) if (gift->IsKindOf(NAME_Health))
{ {
gift->Amount *= amount; gift->Amount *= amount;
} }
@ -6923,18 +6923,18 @@ DEFINE_ACTION_FUNCTION(AActor, SetCamera)
if (self->player == nullptr || self->player->mo != self) return 0; if (self->player == nullptr || self->player->mo != self) return 0;
if (camera == nullptr) if (cam == nullptr)
{ {
camera = self; cam = self;
revert = false; revert = false;
} }
AActor *oldcamera = self->player->camera; AActor *oldcamera = self->player->camera;
self->player->camera = camera; self->player->camera = cam;
if (revert) self->player->cheats |= CF_REVERTPLEASE; if (revert) self->player->cheats |= CF_REVERTPLEASE;
if (oldcamera != camera) if (oldcamera != cam)
{ {
R_ClearPastViewer(camera); R_ClearPastViewer(cam);
} }
return 0; return 0;
} }

View file

@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
node->ItemCheck.Resize(3); node->ItemCheck.Resize(3);
for (j = 0; j < 3; ++j) for (j = 0; j < 3; ++j)
{ {
node->ItemCheck[j].Item = dyn_cast<PClassInventory>(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->ItemCheck[j].Amount = -1;
} }
node->ItemCheckNode = speech.Link; node->ItemCheckNode = speech.Link;
@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheck.Resize(3); reply->ItemCheck.Resize(3);
for (k = 0; k < 3; ++k) for (k = 0; k < 3; ++k)
{ {
reply->ItemCheck[k].Item = dyn_cast<PClassInventory>(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->ItemCheck[k].Amount = rsp->Count[k];
} }
reply->ItemCheckRequire.Clear(); 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(AInventory)))
{ {
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (reply->GiveType->IsDescendantOf(NAME_Weapon))
{ {
if (player->mo->FindInventory(reply->GiveType) != NULL) 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; gameaction = ga_slideshow;
} }
else else

View file

@ -12,7 +12,7 @@ struct FBrokenLines;
struct FStrifeDialogueItemCheck struct FStrifeDialogueItemCheck
{ {
PClassInventory *Item; PClassActor *Item;
int Amount; int Amount;
}; };

View file

@ -3226,7 +3226,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
if (dropamount > 0) 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->Amount = int(dropamount * dropammofactor);
inv->ItemFlags |= IF_IGNORESKILL; inv->ItemFlags |= IF_IGNORESKILL;
@ -3252,7 +3252,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
inv->FloatVar("AmmoFactor") = dropammofactor; inv->FloatVar("AmmoFactor") = dropammofactor;
inv->ItemFlags |= flagmask; inv->ItemFlags |= flagmask;
} }
else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) else if (inv->IsKindOf(NAME_Weapon))
{ {
// The same goes for ammo from a weapon. // The same goes for ammo from a weapon.
static_cast<AWeapon *>(inv)->AmmoGive1 = int(static_cast<AWeapon *>(inv)->AmmoGive1 * dropammofactor); static_cast<AWeapon *>(inv)->AmmoGive1 = int(static_cast<AWeapon *>(inv)->AmmoGive1 * dropammofactor);

View file

@ -767,10 +767,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; bool result = true;
if (type != nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL; AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL;
bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true; bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true;
@ -903,7 +905,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
// and infinite ammo is on // and infinite ammo is on
if (notakeinfinite && if (notakeinfinite &&
((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && ((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? // Nothing to do here, except maybe res = false;? Would it make sense?
result = false; result = false;
@ -1146,10 +1148,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 != NULL)
{ {
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
AInventory *item = static_cast<AInventory *>(Spawn (type)); AInventory *item = static_cast<AInventory *>(Spawn (type));
if (item) if (item)
{ {
@ -1542,7 +1546,7 @@ bool AActor::IsVisibleToPlayer() const
bool visible = false; bool visible = false;
for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) 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)) if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls))
{ {
visible = true; visible = true;
@ -7488,7 +7492,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight)
} }
DDropItem *AActor::GetDropItems() const FDropItem *AActor::GetDropItems() const
{ {
return GetClass()->DropItems; return GetClass()->DropItems;
} }
@ -8096,16 +8100,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors)
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
IMPLEMENT_CLASS(DDropItem, false, true) DEFINE_FIELD(FDropItem, Next)
DEFINE_FIELD(FDropItem, Name)
IMPLEMENT_POINTERS_START(DDropItem) DEFINE_FIELD(FDropItem, Probability)
IMPLEMENT_POINTER(Next) DEFINE_FIELD(FDropItem, Amount)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(DDropItem, Next)
DEFINE_FIELD(DDropItem, Name)
DEFINE_FIELD(DDropItem, Probability)
DEFINE_FIELD(DDropItem, Amount)
void PrintMiscActorInfo(AActor *query) void PrintMiscActorInfo(AActor *query)
{ {

View file

@ -170,7 +170,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id)
if (Next && Next->ID == ID && ID != 0) if (Next && Next->ID == ID && ID != 0)
Next->Destroy(); // Replace it. 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); Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST);
} }
@ -357,7 +357,7 @@ void DPSprite::SetState(FState *newstate, bool pending)
} }
else if (!(newstate->UseFlags & SUF_WEAPON)) else if (!(newstate->UseFlags & SUF_WEAPON))
{ {
if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) if (Caller->IsKindOf(NAME_Weapon))
{ {
auto so = FState::StaticFindStateOwner(newstate); 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)); Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates));
@ -1399,7 +1399,7 @@ void player_t::TickPSprites()
// or if it's from an inventory item that the player no longer owns. // or if it's from an inventory item that the player no longer owns.
if ((pspr->Caller == nullptr || if ((pspr->Caller == nullptr ||
(pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast<AInventory *>(pspr->Caller)->Owner != pspr->Owner->mo) || (pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast<AInventory *>(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(); pspr->Destroy();
} }

View file

@ -57,21 +57,23 @@ class USDFParser : public UDMFParserBase
PClassActor *CheckActorType(const char *key) PClassActor *CheckActorType(const char *key)
{ {
PClassActor *type = nullptr;
if (namespace_bits == St) if (namespace_bits == St)
{ {
return GetStrifeType(CheckInt(key)); type = GetStrifeType(CheckInt(key));
} }
else if (namespace_bits == Zd) else if (namespace_bits == Zd)
{ {
PClassActor *cls = PClass::FindActor(CheckString(key)); PClassActor *cls = PClass::FindActor(CheckString(key));
if (cls == NULL) if (cls == nullptr)
{ {
sc.ScriptMessage("Unknown actor class '%s'", key); 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) switch(key)
{ {
case NAME_Item: case NAME_Item:
check.Item = dyn_cast<PClassInventory>(CheckActorType(key)); check.Item = CheckActorType(key);
break; break;
case NAME_Amount: case NAME_Amount:
@ -266,7 +268,7 @@ class USDFParser : public UDMFParserBase
switch(key) switch(key)
{ {
case NAME_Item: case NAME_Item:
check.Item = dyn_cast<PClassInventory>(CheckActorType(key)); check.Item = CheckActorType(key);
break; break;
case NAME_Count: case NAME_Count:

View file

@ -84,6 +84,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
P_PredictionLerpReset(); P_PredictionLerpReset();
} }
ColorSetList ColorSets;
PainFlashList PainFlashes;
struct PredictPos struct PredictPos
{ {
int gametic; int gametic;
@ -145,7 +148,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. // Fixme; This needs a decent way to access the string table without creating a mess.
// [RH] ???? // [RH] ????
@ -164,7 +167,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name)
Printf("Invalid player class '%s'\n", name); Printf("Invalid player class '%s'\n", name);
return false; return false;
} }
else if (static_cast<PClassPlayerPawn *>(ti)->DisplayName.IsEmpty()) else if (ti->DisplayName.IsEmpty())
{ {
Printf ("Missing displayname for player class '%s'\n", name); Printf ("Missing displayname for player class '%s'\n", name);
return false; return false;
@ -183,7 +186,7 @@ void SetupPlayerClasses ()
if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i]))
{ {
newclass.Flags = 0; newclass.Flags = 0;
newclass.Type = static_cast<PClassPlayerPawn *>(cls); newclass.Type = cls;
if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU)) if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU))
{ {
newclass.Flags |= PCF_NOMENU; newclass.Flags |= PCF_NOMENU;
@ -211,7 +214,7 @@ CCMD (addplayerclass)
{ {
FPlayerClass newclass; FPlayerClass newclass;
newclass.Type = static_cast<PClassPlayerPawn *>(ti); newclass.Type = ti;
newclass.Flags = 0; newclass.Flags = 0;
int arg = 2; int arg = 2;
@ -534,61 +537,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<PClassPlayerPawn *>(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) static int intcmp(const void *a, const void *b)
{ {
return *(const int *)a - *(const int *)b; return *(const int *)a - *(const int *)b;
} }
void PClassPlayerPawn::EnumColorSets(TArray<int> *out) void EnumColorSets(PClassActor *cls, TArray<int> *out)
{ {
out->Clear(); TArray<int> deleteds;
FPlayerColorSetMap::Iterator it(ColorSets);
FPlayerColorSetMap::Pair *pair;
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); qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
} }
@ -598,20 +574,41 @@ void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
// //
//========================================================================== //==========================================================================
bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum)
{ {
const PClassPlayerPawn *info = this; for (int i = ColorSets.Size() - 1; i >= 0; i--)
{
if (std::get<1>(ColorSets[i]) == setnum &&
std::get<0>(ColorSets[i])->IsAncestorOf(cls))
{
auto c = &std::get<2>(ColorSets[i]);
return c->Name != NAME_None ? c : nullptr;
}
}
return nullptr;
}
while (info != NULL) //==========================================================================
//
//
//==========================================================================
bool player_t::GetPainFlash(FName type, PalEntry *color) const
{ {
const PalEntry *flash = info->PainFlashes.CheckKey(type); PClass *info = mo->GetClass();
if (flash != NULL)
// 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--)
{ {
*color = *flash; if (std::get<1>(PainFlashes[i]) == type &&
std::get<0>(PainFlashes[i])->IsAncestorOf(info))
{
*color = std::get<2>(PainFlashes[i]);
return true; return true;
} }
// Try parent class
info = dyn_cast<PClassPlayerPawn>(info->ParentClass);
} }
return false; return false;
} }
@ -660,7 +657,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true)
IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTERS_START(APlayerPawn)
IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvFirst)
IMPLEMENT_POINTER(InvSel) IMPLEMENT_POINTER(InvSel)
IMPLEMENT_POINTER(FlechetteType)
IMPLEMENT_POINTERS_END IMPLEMENT_POINTERS_END
void APlayerPawn::Serialize(FSerializer &arc) void APlayerPawn::Serialize(FSerializer &arc)
@ -952,7 +948,7 @@ bool APlayerPawn::UseInventory (AInventory *item)
// //
//=========================================================================== //===========================================================================
AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype)
{ {
AWeapon *bestMatch = NULL; AWeapon *bestMatch = NULL;
int bestOrder = INT_MAX; int bestOrder = INT_MAX;
@ -963,7 +959,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
// Find the best weapon the player has. // Find the best weapon the player has.
for (item = Inventory; item != NULL; item = item->Inventory) for (item = Inventory; item != NULL; item = item->Inventory)
{ {
if (!item->IsKindOf (RUNTIME_CLASS(AWeapon))) if (!item->IsKindOf(NAME_Weapon))
continue; continue;
weap = static_cast<AWeapon *> (item); weap = static_cast<AWeapon *> (item);
@ -1014,7 +1010,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
// //
//=========================================================================== //===========================================================================
AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype)
{ {
AWeapon *best = BestWeapon (ammotype); AWeapon *best = BestWeapon (ammotype);
@ -1042,7 +1038,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype)
// //
//=========================================================================== //===========================================================================
void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype)
{ {
if (!player->userinfo.GetNeverSwitch() && if (!player->userinfo.GetNeverSwitch() &&
player->PendingWeapon == WP_NOCHANGE && player->PendingWeapon == WP_NOCHANGE &&
@ -1061,7 +1057,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype)
DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch)
{ {
PARAM_SELF_PROLOGUE(APlayerPawn); PARAM_SELF_PROLOGUE(APlayerPawn);
PARAM_OBJECT(ammotype, PClassInventory); PARAM_OBJECT(ammotype, PClassActor);
self->CheckWeaponSwitch(ammotype); self->CheckWeaponSwitch(ammotype);
return 0; return 0;
} }
@ -1136,29 +1132,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
if ((dmflags & DF_COOP_LOSE_KEYS) && if ((dmflags & DF_COOP_LOSE_KEYS) &&
defitem == NULL && defitem == NULL &&
item->IsKindOf(PClass::FindActor(NAME_Key))) item->IsKindOf(NAME_Key))
{ {
item->Destroy(); item->Destroy();
} }
else if ((dmflags & DF_COOP_LOSE_WEAPONS) && else if ((dmflags & DF_COOP_LOSE_WEAPONS) &&
defitem == NULL && defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AWeapon))) item->IsKindOf(NAME_Weapon))
{ {
item->Destroy(); item->Destroy();
} }
else if ((dmflags & DF_COOP_LOSE_ARMOR) && else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
item->IsKindOf(PClass::FindActor(NAME_Armor))) item->IsKindOf(NAME_Armor))
{ {
if (defitem == NULL) if (defitem == NULL)
{ {
item->Destroy(); 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->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
item->Amount = defitem->Amount; 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 *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr); double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
@ -1167,12 +1163,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
} }
else if ((dmflags & DF_COOP_LOSE_POWERUPS) && else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
defitem == NULL && defitem == NULL &&
item->IsKindOf(PClass::FindActor(NAME_PowerupGiver))) item->IsKindOf(NAME_PowerupGiver))
{ {
item->Destroy(); item->Destroy();
} }
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) && else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
item->IsKindOf(PClass::FindActor(NAME_Ammo))) item->IsKindOf(NAME_Ammo))
{ {
if (defitem == NULL) if (defitem == NULL)
{ {
@ -1229,8 +1225,8 @@ const char *APlayerPawn::GetSoundClass() const
} }
// [GRB] // [GRB]
PClassPlayerPawn *pclass = GetClass(); auto pclass = GetClass();
return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player"; return SoundClass != NAME_None? SoundClass.GetChars() : "player";
} }
//=========================================================================== //===========================================================================
@ -1367,16 +1363,16 @@ void APlayerPawn::GiveDefaultInventory ()
// HexenArmor must always be the first item in the inventory because // HexenArmor must always be the first item in the inventory because
// it provides player class based protection that should not affect // it provides player class based protection that should not affect
// any other protection item. // any other protection item.
PClassPlayerPawn *myclass = GetClass(); auto myclass = GetClass();
GiveInventoryType(PClass::FindActor(NAME_HexenArmor)); GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
auto harmor = FindInventory(NAME_HexenArmor); auto harmor = FindInventory(NAME_HexenArmor);
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, 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) 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 // BasicArmor must come right after that. It should not affect any
@ -1387,7 +1383,7 @@ void APlayerPawn::GiveDefaultInventory ()
AddInventory (barmor); AddInventory (barmor);
// Now add the items from the DECORATE definition // Now add the items from the DECORATE definition
DDropItem *di = GetDropItems(); auto di = GetDropItems();
while (di) while (di)
{ {
@ -1412,7 +1408,7 @@ void APlayerPawn::GiveDefaultInventory ()
item = static_cast<AInventory *>(Spawn(ti)); item = static_cast<AInventory *>(Spawn(ti));
item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here
item->Amount = di->Amount; item->Amount = di->Amount;
if (item->IsKindOf(RUNTIME_CLASS(AWeapon))) if (item->IsKindOf(NAME_Weapon))
{ {
// To allow better control any weapon is emptied of // To allow better control any weapon is emptied of
// ammo before being given to the player. // ammo before being given to the player.
@ -1432,7 +1428,7 @@ void APlayerPawn::GiveDefaultInventory ()
item = NULL; item = NULL;
} }
} }
if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) && if (item != NULL && item->IsKindOf(NAME_Weapon) &&
static_cast<AWeapon*>(item)->CheckAmmo(AWeapon::EitherFire, false)) static_cast<AWeapon*>(item)->CheckAmmo(AWeapon::EitherFire, false))
{ {
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item); player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item);
@ -1517,7 +1513,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
AInventory *item; AInventory *item;
// kgDROP - start - modified copy from a_action.cpp // kgDROP - start - modified copy from a_action.cpp
DDropItem *di = weap->GetDropItems(); auto di = weap->GetDropItems();
if (di != NULL) if (di != NULL)
{ {
@ -1536,7 +1532,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
weap->SpawnState != ::GetDefault<AActor>()->SpawnState) weap->SpawnState != ::GetDefault<AActor>()->SpawnState)
{ {
item = P_DropItem (this, weap->GetClass(), -1, 256); 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) if (weap->AmmoGive1 && weap->Ammo1)
{ {
@ -1709,9 +1705,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop)
player_t *player; player_t *player;
// [GRB] Parameterized version // [GRB] Parameterized version
if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk"))) if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk"))
{ {
spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull")); spawntype = PClass::FindActor("BloodySkull");
if (spawntype == NULL) if (spawntype == NULL)
return 0; return 0;
} }
@ -3249,18 +3245,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade)
DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, ViewBob)
DEFINE_FIELD(APlayerPawn, FullHeight) DEFINE_FIELD(APlayerPawn, FullHeight)
DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) DEFINE_FIELD(APlayerPawn, HealingRadiusType)
DEFINE_FIELD(PClassPlayerPawn, DisplayName) DEFINE_FIELD(APlayerPawn, SoundClass)
DEFINE_FIELD(PClassPlayerPawn, SoundClass) DEFINE_FIELD(APlayerPawn, Face)
DEFINE_FIELD(PClassPlayerPawn, Face) DEFINE_FIELD(APlayerPawn, Portrait)
DEFINE_FIELD(PClassPlayerPawn, Portrait) DEFINE_FIELD(APlayerPawn, Slot)
DEFINE_FIELD(PClassPlayerPawn, Slot) DEFINE_FIELD(APlayerPawn, InvulMode)
DEFINE_FIELD(PClassPlayerPawn, InvulMode) DEFINE_FIELD(APlayerPawn, HexenArmor)
DEFINE_FIELD(PClassPlayerPawn, HexenArmor) DEFINE_FIELD(APlayerPawn, ColorRangeStart)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd)
DEFINE_FIELD(PClassPlayerPawn, ColorSets) DEFINE_FIELD(PClassActor, DisplayName)
DEFINE_FIELD(PClassPlayerPawn, PainFlashes)
DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, mo)
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)

View file

@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor)
unsigned i = level.sectorPortals.Reserve(1); unsigned i = level.sectorPortals.Reserve(1);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; 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].mSkybox = actor;
level.sectorPortals[i].mDestination = actor->Sector; level.sectorPortals[i].mDestination = actor->Sector;
return i; return i;

View file

@ -517,7 +517,7 @@ void R_InitSkins (void)
int lastlump; int lastlump;
int aliasid; int aliasid;
bool remove; bool remove;
PClassPlayerPawn *basetype, *transtype; PClassActor *basetype, *transtype;
key[sizeof(key)-1] = 0; key[sizeof(key)-1] = 0;
i = PlayerClasses.Size () - 1; i = PlayerClasses.Size () - 1;
@ -602,11 +602,11 @@ void R_InitSkins (void)
else if (0 == stricmp (key, "game")) else if (0 == stricmp (key, "game"))
{ {
if (gameinfo.gametype == GAME_Heretic) if (gameinfo.gametype == GAME_Heretic)
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer)); basetype = PClass::FindActor(NAME_HereticPlayer);
else if (gameinfo.gametype == GAME_Strife) else if (gameinfo.gametype == GAME_Strife)
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_StrifePlayer)); basetype = PClass::FindActor(NAME_StrifePlayer);
else else
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); basetype = PClass::FindActor(NAME_DoomPlayer);
transtype = basetype; transtype = basetype;
@ -614,7 +614,7 @@ void R_InitSkins (void)
{ {
if (gameinfo.gametype & GAME_DoomChex) if (gameinfo.gametype & GAME_DoomChex)
{ {
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer)); transtype = PClass::FindActor(NAME_HereticPlayer);
skins[i].othergame = true; skins[i].othergame = true;
} }
else if (gameinfo.gametype != GAME_Heretic) else if (gameinfo.gametype != GAME_Heretic)
@ -633,7 +633,7 @@ void R_InitSkins (void)
{ {
if (gameinfo.gametype == GAME_Heretic) if (gameinfo.gametype == GAME_Heretic)
{ {
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); transtype = PClass::FindActor(NAME_DoomPlayer);
skins[i].othergame = true; skins[i].othergame = true;
} }
else if (!(gameinfo.gametype & GAME_DoomChex)) else if (!(gameinfo.gametype & GAME_DoomChex))
@ -709,12 +709,12 @@ void R_InitSkins (void)
{ {
if (gameinfo.gametype & GAME_DoomChex) if (gameinfo.gametype & GAME_DoomChex)
{ {
basetype = transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); basetype = transtype = PClass::FindActor(NAME_DoomPlayer);
} }
else if (gameinfo.gametype == GAME_Heretic) else if (gameinfo.gametype == GAME_Heretic)
{ {
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer)); basetype = PClass::FindActor(NAME_HereticPlayer);
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); transtype = PClass::FindActor(NAME_DoomPlayer);
skins[i].othergame = true; skins[i].othergame = true;
} }
else else
@ -725,18 +725,22 @@ void R_InitSkins (void)
if (!remove) if (!remove)
{ {
skins[i].range0start = transtype->ColorRangeStart; auto transdef = ((APlayerPawn*)GetDefaultByType(transtype));
skins[i].range0end = transtype->ColorRangeEnd; auto basedef = ((APlayerPawn*)GetDefaultByType(basetype));
skins[i].range0start = transdef->ColorRangeStart;
skins[i].range0end = transdef->ColorRangeEnd;
remove = true; remove = true;
for (j = 0; j < (int)PlayerClasses.Size (); j++) 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) && if (type->IsDescendantOf (basetype) &&
GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite &&
type->ColorRangeStart == basetype->ColorRangeStart && type_def->ColorRangeStart == basedef->ColorRangeStart &&
type->ColorRangeEnd == basetype->ColorRangeEnd) type_def->ColorRangeEnd == basedef->ColorRangeEnd)
{ {
PlayerClasses[j].Skins.Push ((int)i); PlayerClasses[j].Skins.Push ((int)i);
remove = false; remove = false;
@ -935,10 +939,10 @@ void R_InitSprites ()
memset (skins, 0, sizeof(*skins) * numskins); memset (skins, 0, sizeof(*skins) * numskins);
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
{ // Assume Doom skin by default { // Assume Doom skin by default
PClassPlayerPawn *type = PlayerClasses[0].Type; auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type));
skins[i].range0start = type->ColorRangeStart; skins[i].range0start = type->ColorRangeStart;
skins[i].range0end = type->ColorRangeEnd; skins[i].range0end = type->ColorRangeEnd;
skins[i].Scale = GetDefaultByType (type)->Scale; skins[i].Scale = type->Scale;
} }
R_InitSpriteDefs (); R_InitSpriteDefs ();
@ -950,11 +954,10 @@ void R_InitSprites ()
// [GRB] Each player class has its own base skin // [GRB] Each player class has its own base skin
for (i = 0; i < PlayerClasses.Size (); i++) for (i = 0; i < PlayerClasses.Size (); i++)
{ {
PClassPlayerPawn *basetype = PlayerClasses[i].Type; auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type));
FString classface = basetype->Face;
strcpy (skins[i].name, "Base"); 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[0] = 'S';
skins[i].face[1] = 'T'; skins[i].face[1] = 'T';
@ -963,12 +966,12 @@ void R_InitSprites ()
} }
else else
{ {
strcpy(skins[i].face, classface); strcpy(skins[i].face, basetype->Face);
} }
skins[i].range0start = basetype->ColorRangeStart; skins[i].range0start = basetype->ColorRangeStart;
skins[i].range0end = basetype->ColorRangeEnd; skins[i].range0end = basetype->ColorRangeEnd;
skins[i].Scale = GetDefaultByType (basetype)->Scale; skins[i].Scale = basetype->Scale;
skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; skins[i].sprite = basetype->SpawnState->sprite;
skins[i].namespc = ns_global; skins[i].namespc = ns_global;
PlayerClasses[i].Skins.Push (i); PlayerClasses[i].Skins.Push (i);

View file

@ -711,6 +711,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector,
{ {
case SOURCE_None: case SOURCE_None:
default: default:
pos->Zero();
break; break;
case SOURCE_Actor: case SOURCE_Actor:

View file

@ -6558,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition
FxStackVariable::~FxStackVariable() 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; membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar; delete membervar;
} }
//==========================================================================
//
//
//==========================================================================
void FxStackVariable::ReplaceField(PField *newfield)
{
membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar;
membervar = newfield;
}
//========================================================================== //==========================================================================
// //
// //
@ -6730,7 +6717,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
{ {
auto parentfield = static_cast<FxMemberBase *>(classx)->membervar; auto parentfield = static_cast<FxMemberBase *>(classx)->membervar;
// PFields are garbage collected so this will be automatically taken care of later. // 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; newfield->BitValue = membervar->BitValue;
static_cast<FxMemberBase *>(classx)->membervar = newfield; static_cast<FxMemberBase *>(classx)->membervar = newfield;
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.

View file

@ -1417,7 +1417,6 @@ class FxStackVariable : public FxMemberBase
public: public:
FxStackVariable(PType *type, int offset, const FScriptPosition&); FxStackVariable(PType *type, int offset, const FScriptPosition&);
~FxStackVariable(); ~FxStackVariable();
void ReplaceField(PField *newfield);
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable); bool RequestAddress(FCompileContext &ctx, bool *writable);
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);

View file

@ -1,10 +1,10 @@
/* /*
** dynarray.cpp ** 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. ** All rights reserved.
** **
** Redistribution and use in source and binary forms, with or without ** Redistribution and use in source and binary forms, with or without

View file

@ -32,7 +32,7 @@
*/ */
#include "vmbuilder.h" #include "vmbuilder.h"
#include "codegeneration/codegen.h" #include "codegen.h"
#include "info.h" #include "info.h"
#include "m_argv.h" #include "m_argv.h"
#include "thingdef.h" #include "thingdef.h"

View file

@ -47,7 +47,7 @@
#include "decallib.h" #include "decallib.h"
#include "i_system.h" #include "i_system.h"
#include "thingdef.h" #include "thingdef.h"
#include "codegeneration/codegen.h" #include "backend/codegen.h"
#include "r_data/r_translate.h" #include "r_data/r_translate.h"
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
@ -541,7 +541,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
{ {
sc.MustGetString (); sc.MustGetString ();
static_cast<PClassInventory *>(bag.Info)->PickupMsg = sc.String; bag.Info->PickupMsg = sc.String;
} }
else if (def == DEF_Pickup && sc.Compare ("Respawns")) else if (def == DEF_Pickup && sc.Compare ("Respawns"))
{ {

View file

@ -49,7 +49,7 @@
#include "thingdef.h" #include "thingdef.h"
#include "p_lnspec.h" #include "p_lnspec.h"
#include "doomstat.h" #include "doomstat.h"
#include "codegeneration/codegen.h" #include "backend/codegen.h"
FRandom pr_exrandom ("EX_Random"); FRandom pr_exrandom ("EX_Random");

View file

@ -49,7 +49,7 @@
#include "v_palette.h" #include "v_palette.h"
#include "doomerrors.h" #include "doomerrors.h"
#include "i_system.h" #include "i_system.h"
#include "codegeneration/codegen.h" #include "backend/codegen.h"
#include "w_wad.h" #include "w_wad.h"
#include "v_video.h" #include "v_video.h"
#include "version.h" #include "version.h"

View file

@ -53,10 +53,10 @@
#include "s_sound.h" #include "s_sound.h"
#include "i_system.h" #include "i_system.h"
#include "colormatcher.h" #include "colormatcher.h"
#include "codegeneration/codegen.h" #include "backend/codegen.h"
#include "version.h" #include "version.h"
#include "templates.h" #include "templates.h"
#include "vmbuilder.h" #include "backend/vmbuilder.h"
//========================================================================== //==========================================================================
//*** //***

406
src/scripting/symbols.cpp Normal file
View file

@ -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 <float.h>
#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<DWORD> &argflags, TArray<FName> &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<PPointer>(proto->ArgumentTypes[0]);
assert(selftypeptr != nullptr);
variant.SelfClass = dyn_cast<PStruct>(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);
}

272
src/scripting/symbols.h Normal file
View file

@ -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<PField *> &variables);
TArray<PField *> 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<uint32_t> ArgFlags; // Should be the same length as Proto->ArgumentTypes
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
uint32_t Flags;
int UseFlags;
PStruct *SelfClass;
};
TArray<Variant> Variants;
PStruct *OwningClass = nullptr;
unsigned AddVariant(PPrototype *proto, TArray<uint32_t> &argflags, TArray<FName> &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<FName, PSymbol *> 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<PNamespace *> AllNamespaces;
FNamespaceManager();
PNamespace *NewNamespace(int filenum);
size_t MarkSymbols();
void ReleaseSymbols();
int RemoveSymbols();
};
extern FNamespaceManager Namespaces;

View file

@ -60,9 +60,9 @@
#include "p_conversation.h" #include "p_conversation.h"
#include "v_text.h" #include "v_text.h"
#include "thingdef.h" #include "thingdef.h"
#include "codegeneration/codegen.h" #include "backend/codegen.h"
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "vmbuilder.h" #include "backend/vmbuilder.h"
#include "stats.h" #include "stats.h"
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -246,7 +246,7 @@ static void CheckForUnsafeStates(PClassActor *obj)
TMap<FState *, bool> checked; TMap<FState *, bool> checked;
ENamedName *test; 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. if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables.
test = weaponstates; test = weaponstates;
@ -336,11 +336,11 @@ static void CheckStates(PClassActor *obj)
CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites"); 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"); 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"); 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()); Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
FScriptPosition::WarnCounter++; FScriptPosition::WarnCounter++;
DObject::StaticPointerSubstitution(ti, nullptr); // the class must be rendered harmless so that it won't cause problems.
PClassActor::AllActorClasses.Delete(i); ti->ParentClass = RUNTIME_CLASS(AActor);
ti->Size = sizeof(AActor);
} }
else else
{ {

View file

@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state);
// Extra info maintained while defining an actor. // Extra info maintained while defining an actor.
// //
//========================================================================== //==========================================================================
class DDropItem; struct FDropItem;
struct Baggage struct Baggage
{ {
@ -126,7 +126,7 @@ struct Baggage
int Lumpnum; int Lumpnum;
FStateDefinitions statedef; FStateDefinitions statedef;
DDropItem *DropItemList; FDropItem *DropItemList;
FScriptPosition ScriptPosition; FScriptPosition ScriptPosition;
}; };

View file

@ -66,9 +66,10 @@
#include "teaminfo.h" #include "teaminfo.h"
#include "v_video.h" #include "v_video.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "vmbuilder.h" #include "backend/vmbuilder.h"
#include "a_keys.h" #include "a_keys.h"
#include "g_levellocals.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) static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
{ {
return static_cast<PClassInventory *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); return static_cast<AInventory::MetaClass *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional));
} }
static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
{ {
@ -920,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
bag.DropItemList = NULL; bag.DropItemList = NULL;
} }
DDropItem *di = new DDropItem; FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
di->Name = type; di->Name = type;
di->Probability = 255; di->Probability = 255;
@ -938,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
} }
di->Next = bag.DropItemList; di->Next = bag.DropItemList;
bag.DropItemList = di; bag.DropItemList = di;
GC::WriteBarrier(di);
} }
//========================================================================== //==========================================================================
@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
{ {
static_cast<PClassInventory*>(info)->RestrictedToPlayerClass.Clear(); static_cast<PClassActor*>(info)->RestrictedToPlayerClass.Clear();
for(int i = 0;i < PROP_PARM_COUNT;++i) for(int i = 0;i < PROP_PARM_COUNT;++i)
{ {
PROP_STRING_PARM(n, i); PROP_STRING_PARM(n, i);
if (*n != 0) if (*n != 0)
static_cast<PClassInventory*>(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); static_cast<PClassActor*>(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n));
} }
} }
@ -1713,12 +1713,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
{ {
static_cast<PClassInventory*>(info)->ForbiddenToPlayerClass.Clear(); static_cast<PClassActor*>(info)->ForbiddenToPlayerClass.Clear();
for(int i = 0;i < PROP_PARM_COUNT;++i) for(int i = 0;i < PROP_PARM_COUNT;++i)
{ {
PROP_STRING_PARM(n, i); PROP_STRING_PARM(n, i);
if (*n != 0) if (*n != 0)
static_cast<PClassInventory*>(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); static_cast<PClassActor*>(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') if (i == NULL || i[0] == '\0')
{ {
defaults->Icon.SetNull(); icon.SetNull();
} }
else else
{ {
defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
if (!defaults->Icon.isValid()) if (!icon.isValid())
{ {
// Don't print warnings if the item is for another game or if this is a shareware IWAD. // 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. // 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) !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
{ {
bag.ScriptPosition.Message(MSG_WARNING, 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) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassInventory *>(info)->PickupMsg = str; static_cast<PClassActor *>(info)->PickupMsg = str;
} }
//========================================================================== //==========================================================================
@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
DEFINE_CLASS_PROPERTY(givequest, I, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); defaults->GiveQuest = i;
static_cast<PClassInventory *>(info)->GiveQuest = i;
} }
//========================================================================== //==========================================================================
@ -2096,9 +2111,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
int alpha; int alpha;
PalEntry *pBlendColor; 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); pBlendColor = &defaults->ColorVar(NAME_BlendColor);
} }
@ -2148,7 +2163,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
{ {
PalEntry BlendColor; 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"); I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
return; return;
@ -2183,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, 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"); I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n");
return; return;
@ -2198,7 +2213,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, 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"); I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n");
return; return;
@ -2214,7 +2229,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
{ {
PROP_STRING_PARM(str, 0); 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"); I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n");
return; return;
@ -2261,8 +2276,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); info->DisplayName = str;
static_cast<PClassPlayerPawn *>(info)->DisplayName = str;
} }
//========================================================================== //==========================================================================
@ -2274,8 +2288,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn)
FString tmp = str; FString tmp = str;
tmp.ReplaceChars (' ', '_'); tmp.ReplaceChars (' ', '_');
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None;
static_cast<PClassPlayerPawn *>(info)->SoundClass = tmp;
} }
//========================================================================== //==========================================================================
@ -2286,6 +2299,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
FString tmp = str; FString tmp = str;
if (tmp.Len() == 0) defaults->Face = NAME_None;
else
{
tmp.ToUpper(); tmp.ToUpper();
bool valid = (tmp.Len() == 3 && bool valid = (tmp.Len() == 3 &&
(((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) &&
@ -2298,9 +2314,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
tmp.GetChars(), info->TypeName.GetChars()); tmp.GetChars(), info->TypeName.GetChars());
} }
defaults->Face = tmp;
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); }
static_cast<PClassPlayerPawn *>(info)->Face = tmp;
} }
//========================================================================== //==========================================================================
@ -2314,9 +2329,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn)
if (start > end) if (start > end)
swapvalues (start, end); swapvalues (start, end);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); defaults->ColorRangeStart = start;
static_cast<PClassPlayerPawn *>(info)->ColorRangeStart = start; defaults->ColorRangeEnd = end;
static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end;
} }
//========================================================================== //==========================================================================
@ -2371,8 +2385,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl
} }
else else
{ {
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); ColorSets.Push(std::make_tuple(info, setnum, color));
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
} }
} }
@ -2398,8 +2411,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
} }
else if (color.Lump >= 0) else if (color.Lump >= 0)
{ {
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); ColorSets.Push(std::make_tuple(info, setnum, color));
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
} }
} }
@ -2416,8 +2428,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
} }
else else
{ {
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); FPlayerColorSet color;
static_cast<PClassPlayerPawn *>(info)->ColorSets.Remove(setnum); memset(&color, 0, sizeof(color));
ColorSets.Push(std::make_tuple(info, setnum, color));
} }
} }
@ -2651,8 +2664,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn)
PROP_STRING_PARM(type, 3); PROP_STRING_PARM(type, 3);
color.a = BYTE(255 * clamp<double>(a, 0.f, 1.f)); color.a = BYTE(255 * clamp<double>(a, 0.f, 1.f));
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PainFlashes.Push(std::make_tuple(info, type, color));
static_cast<PClassPlayerPawn *>(info)->PainFlashes.Insert(type, color);
} }
} }
@ -2672,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
bag.DropItemList = NULL; bag.DropItemList = NULL;
} }
DDropItem *di = new DDropItem; FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
di->Name = str; di->Name = str;
di->Probability = 255; di->Probability = 255;
@ -2684,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
} }
di->Next = bag.DropItemList; di->Next = bag.DropItemList;
bag.DropItemList = di; bag.DropItemList = di;
GC::WriteBarrier(di);
} }
//========================================================================== //==========================================================================
@ -2693,8 +2704,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); defaults->InvulMode = str;
static_cast<PClassPlayerPawn *>(info)->InvulMode = str;
} }
//========================================================================== //==========================================================================
@ -2703,8 +2713,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); defaults->HealingRadiusType = str;
static_cast<PClassPlayerPawn *>(info)->HealingRadiusType = str;
} }
//========================================================================== //==========================================================================
@ -2712,11 +2721,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
{ {
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
PROP_DOUBLE_PARM(val, i); PROP_DOUBLE_PARM(val, i);
static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val; defaults->HexenArmor[i] = val;
} }
} }
@ -2725,9 +2733,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
{ {
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
PROP_STRING_PARM(val, 0); PROP_STRING_PARM(val, 0);
static_cast<PClassPlayerPawn *>(info)->Portrait = val; defaults->Portrait = val;
} }
//========================================================================== //==========================================================================
@ -2737,7 +2744,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
{ {
PROP_INT_PARM(slot, 0); PROP_INT_PARM(slot, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
if (slot < 0 || slot > 9) if (slot < 0 || slot > 9)
{ {
I_Error("Slot must be between 0 and 9."); I_Error("Slot must be between 0 and 9.");
@ -2751,7 +2757,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
PROP_STRING_PARM(str, i); PROP_STRING_PARM(str, i);
weapons << ' ' << str; weapons << ' ' << str;
} }
static_cast<PClassPlayerPawn *>(info)->Slot[slot] = &weapons[1]; defaults->Slot[slot] = weapons.IsEmpty()? NAME_None : FName(weapons);
} }
} }

View file

@ -6,6 +6,9 @@
#include "vectors.h" #include "vectors.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "doomerrors.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_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 #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: public:
bool Native; bool Native;
bool Final = false; // cannot be overridden bool Final = false; // cannot be overridden
@ -709,7 +710,29 @@ public:
class PPrototype *Proto; 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<VMFunction *> AllFunctions;
protected:
}; };
// VM frame layout: // VM frame layout:
@ -838,11 +861,9 @@ struct FStatementInfo
class VMScriptFunction : public VMFunction class VMScriptFunction : public VMFunction
{ {
DECLARE_CLASS(VMScriptFunction, VMFunction);
public: public:
VMScriptFunction(FName name=NAME_None); VMScriptFunction(FName name=NAME_None);
~VMScriptFunction(); ~VMScriptFunction();
size_t PropagateMark();
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
@ -910,7 +931,6 @@ private:
class VMNativeFunction : public VMFunction class VMNativeFunction : public VMFunction
{ {
DECLARE_CLASS(VMNativeFunction, VMFunction);
public: public:
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret); typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);

View file

@ -42,14 +42,9 @@ cycle_t VMCycles[10];
int VMCalls[10]; int VMCalls[10];
IMPLEMENT_CLASS(VMException, false, false) IMPLEMENT_CLASS(VMException, false, false)
IMPLEMENT_CLASS(VMFunction, true, true)
IMPLEMENT_POINTERS_START(VMFunction) TArray<VMFunction *> VMFunction::AllFunctions;
IMPLEMENT_POINTER(Proto)
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(VMScriptFunction, false, false)
IMPLEMENT_CLASS(VMNativeFunction, false, false)
VMScriptFunction::VMScriptFunction(FName name) VMScriptFunction::VMScriptFunction(FName name)
{ {
@ -87,7 +82,6 @@ VMScriptFunction::~VMScriptFunction()
KonstS[i].~FString(); 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(numkonsts >= 0 && numkonsts <= 65535);
assert(numkonsta >= 0 && numkonsta <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535);
assert(numlinenumbers >= 0 && numlinenumbers <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
void *mem = M_Malloc(numops * sizeof(VMOP) + void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) +
numkonstd * sizeof(int) + numkonstd * sizeof(int) +
numkonstf * sizeof(double) + numkonstf * sizeof(double) +
numkonsts * sizeof(FString) + numkonsts * sizeof(FString) +
@ -166,24 +160,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
NumKonstA = numkonsta; 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) void VMScriptFunction::InitExtra(void *addr)
{ {
char *caddr = (char*)addr; char *caddr = (char*)addr;

View file

@ -48,7 +48,7 @@
#include "p_lnspec.h" #include "p_lnspec.h"
#include "i_system.h" #include "i_system.h"
#include "gdtoa.h" #include "gdtoa.h"
#include "vmbuilder.h" #include "backend/vmbuilder.h"
#include "version.h" #include "version.h"
static int GetIntConst(FxExpression *ex, FCompileContext &ctx) static int GetIntConst(FxExpression *ex, FCompileContext &ctx)

View file

@ -2,7 +2,7 @@
#define ZCC_COMPILE_H #define ZCC_COMPILE_H
#include <memory> #include <memory>
#include "codegeneration/codegen.h" #include "backend/codegen.h"
struct Baggage; struct Baggage;
struct FPropertyInfo; struct FPropertyInfo;

View file

@ -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, char *&pstr, char **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **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); 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) template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def)
{ {

View file

@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
} }
PalEntry painFlash = CPlayer->mo->DamageFade; PalEntry painFlash = CPlayer->mo->DamageFade;
CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash);
if (painFlash.a != 0) if (painFlash.a != 0)
{ {

View file

@ -449,4 +449,14 @@ template<> struct THashTraits<FString>
// Compares two keys, returning zero if they are the same. // Compares two keys, returning zero if they are the same.
int Compare(const FString &left, const FString &right) { return left.Compare(right); } int Compare(const FString &left, const FString &right) { return left.Compare(right); }
}; };
class FStringNoInit
{
char mem[sizeof(FString)];
operator FString&()
{
return *reinterpret_cast<FString*>(&mem);
}
};
#endif #endif

View file

@ -498,7 +498,7 @@ class Actor : Thinker native
native bool UsePuzzleItem(int PuzzleItemType); native bool UsePuzzleItem(int PuzzleItemType);
native float AccuracyFactor(); native float AccuracyFactor();
native bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash); native bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash);
native void SetCamera(Actor cam, bool revert = false); action native void SetCamera(Actor cam, bool revert = false);
// DECORATE compatible functions // DECORATE compatible functions
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT); native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);

View file

@ -256,7 +256,7 @@ class BlockThingsIterator : Object native
native bool Next(); native bool Next();
} }
class DropItem : Object native struct DropItem native
{ {
native readonly DropItem Next; native readonly DropItem Next;
native readonly name Name; native readonly name Name;

View file

@ -24,7 +24,7 @@ class Inventory : Actor native
native bool bCreateCopyMoved; native bool bCreateCopyMoved;
native bool bInitEffectFailed; native bool bInitEffectFailed;
native meta String PickupMsg; native meta String PickupMsg;
native meta int GiveQuest; native /*meta*/ int GiveQuest;
Default Default
{ {

View file

@ -252,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. // If you can't see the weapon when it's active, then you can't pick it up.
// //
@ -277,7 +277,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: TryPickup // Weapon :: TryPickup
// //
//=========================================================================== //===========================================================================
@ -293,7 +293,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: Use // Weapon :: Use
// //
// Make the player switch to self weapon. // Make the player switch to self weapon.
// //
@ -324,7 +324,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: Destroy // Weapon :: Destroy
// //
//=========================================================================== //===========================================================================
@ -347,7 +347,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: HandlePickup // Weapon :: HandlePickup
// //
// Try to leach ammo from the weapon if you have it already. // Try to leach ammo from the weapon if you have it already.
// //
@ -372,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. // The player already has self weapon, so try to pick it up for ammo.
// //
@ -411,7 +411,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: CreateCopy // Weapon :: CreateCopy
// //
//=========================================================================== //===========================================================================
@ -428,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 // A weapon that's tossed out should contain no ammo, so you can't cheat
// by dropping it and then picking it back up. // by dropping it and then picking it back up.
@ -464,7 +464,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: AttachToOwner // Weapon :: AttachToOwner
// //
//=========================================================================== //===========================================================================
@ -491,7 +491,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: AddAmmo // Weapon :: AddAmmo
// //
// Give some ammo to the owner, even if it's just 0. // Give some ammo to the owner, even if it's just 0.
// //
@ -536,7 +536,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: AddExistingAmmo // Weapon :: AddExistingAmmo
// //
// Give the owner some more ammo he already has. // Give the owner some more ammo he already has.
// //
@ -563,7 +563,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: AddWeapon // Weapon :: AddWeapon
// //
// Give the owner a weapon if they don't have it already. // Give the owner a weapon if they don't have it already.
// //
@ -588,7 +588,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: ShouldStay // Weapon :: ShouldStay
// //
//=========================================================================== //===========================================================================
@ -606,7 +606,7 @@ class Weapon : StateProvider native
//=========================================================================== //===========================================================================
// //
// AWeapon :: EndPowerUp // Weapon :: EndPowerUp
// //
// The Tome of Power just expired. // The Tome of Power just expired.
// //

View file

@ -9,17 +9,16 @@ class PlayerPawn : Actor native
native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvFirst; // first inventory item displayed on inventory bar
native Inventory InvSel; // selected inventory item native Inventory InvSel; // selected inventory item
native meta String DisplayName; // Display name (used in menus, etc.) 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*/ Name SoundClass; // Sound class
native meta String Portrait; native /*meta*/ Name Face; // Doom status bar face (when used)
native meta String Slot[10]; native /*meta*/ Name Portrait;
native meta Name InvulMode; native /*meta*/ Name Slot[10];
native meta Name HealingRadiusType; native /*meta*/ Name InvulMode;
native meta double HexenArmor[5]; native /*meta*/ Name HealingRadiusType;
native meta uint8 ColorRangeStart; // Skin color range native /*meta*/ double HexenArmor[5];
native meta uint8 ColorRangeEnd; native /*meta*/ uint8 ColorRangeStart; // Skin color range
//FPlayerColorSetMap ColorSets; native /*meta*/ uint8 ColorRangeEnd;
//PainFlashList PainFlashes;
// [GRB] Player class properties // [GRB] Player class properties
native double JumpZ; native double JumpZ;