# Conflicts:
#	src/oplsynth/fmopl.cpp
#	src/oplsynth/mlopl.cpp
#	src/oplsynth/mlopl_io.cpp
#	src/oplsynth/music_opl_mididevice.cpp
#	src/oplsynth/music_opldumper_mididevice.cpp
#	src/oplsynth/muslib.h
#	src/r_draw.cpp
This commit is contained in:
nashmuhandes 2017-02-09 19:18:18 +08:00
commit cf06a6ae91
107 changed files with 2717 additions and 2216 deletions

View file

@ -622,7 +622,7 @@ file( GLOB HEADER_FILES
sound/*.h
textures/*.h
scripting/*.h
scripting/codegeneration/*.h
scripting/backend/*.h
scripting/decorate/*.h
scripting/zscript/*.h
scripting/vm/*.h
@ -1016,17 +1016,18 @@ set (PCH_SOURCES
r_data/voxels.cpp
r_data/renderstyle.cpp
r_data/r_interpolate.cpp
scripting/symbols.cpp
scripting/thingdef.cpp
scripting/thingdef_data.cpp
scripting/thingdef_properties.cpp
scripting/codegeneration/codegen.cpp
scripting/codegeneration/dynarrays.cpp
scripting/backend/codegen.cpp
scripting/backend/dynarrays.cpp
scripting/backend/vmbuilder.cpp
scripting/backend/vmdisasm.cpp
scripting/decorate/olddecorations.cpp
scripting/decorate/thingdef_exp.cpp
scripting/decorate/thingdef_parse.cpp
scripting/decorate/thingdef_states.cpp
scripting/vm/vmbuilder.cpp
scripting/vm/vmdisasm.cpp
scripting/vm/vmexec.cpp
scripting/vm/vmframe.cpp
scripting/zscript/ast.cpp
@ -1206,9 +1207,9 @@ source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE
source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+")
source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+")
source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+")
source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+")
source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+")
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")

View file

@ -573,12 +573,9 @@ struct FLinkContext
msecnode_t *render_list = nullptr;
};
class DDropItem : public DObject
struct FDropItem
{
DECLARE_CLASS(DDropItem, DObject)
HAS_OBJECT_POINTERS
public:
DDropItem *Next;
FDropItem *Next;
FName Name;
int Probability;
int Amount;
@ -597,6 +594,7 @@ public:
AActor &operator= (const AActor &other);
~AActor ();
virtual void Finalize(FStateDefinitions &statedef);
virtual void OnDestroy() override;
virtual void Serialize(FSerializer &arc) override;
virtual void PostSerialize() override;
@ -610,7 +608,7 @@ public:
return (AActor *)(this->GetClass()->Defaults);
}
DDropItem *GetDropItems() const;
FDropItem *GetDropItems() const;
// Return true if the monster should use a missile attack, false for melee
bool SuggestMissileAttack (double dist);
@ -699,7 +697,7 @@ public:
// Give an item to the actor and pick it up.
// Returns true if the item pickup succeeded.
bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false);
bool GiveInventory (PClassActor *type, int amount, bool givecheat = false);
// Removes the item from the inventory list.
virtual void RemoveInventory (AInventory *item);
@ -736,7 +734,7 @@ public:
AInventory *FirstInv ();
// Tries to give the actor some ammo.
bool GiveAmmo (PClassInventory *type, int amount);
bool GiveAmmo (PClassActor *type, int amount);
// Destroys all the inventory the actor is holding.
void DestroyAllInventory ();
@ -973,7 +971,7 @@ public:
{
SetOrigin(Pos() + vel, true);
}
void SetOrigin(double x, double y, double z, bool moving);
virtual void SetOrigin(double x, double y, double z, bool moving);
void SetOrigin(const DVector3 & npos, bool moving)
{
SetOrigin(npos.X, npos.Y, npos.Z, moving);

View file

@ -2858,7 +2858,7 @@ void AM_drawThings ()
// Find the key's own color.
// Only works correctly if single-key locks have lower numbers than any-key locks.
// That is the case for all default keys, however.
if (t->IsKindOf(PClass::FindActor(NAME_Key)))
if (t->IsKindOf(NAME_Key))
{
if (G_SkillProperty(SKILLP_EasyKey))
{

View file

@ -263,7 +263,7 @@ void InitBotStuff()
for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++)
{
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);
if (w != NULL)

View file

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

View file

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

View file

@ -1752,11 +1752,10 @@ void C_MidPrintBold (FFont *font, const char *msg)
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
{
PARAM_PROLOGUE;
PARAM_STRING(font);
PARAM_POINTER_NOT_NULL(fnt, FFont);
PARAM_STRING(text);
PARAM_BOOL_DEF(bold);
FFont *fnt = FFont::FindFont(font);
const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars();
if (!bold) C_MidPrint(fnt, txt);
else C_MidPrintBold(fnt, txt);

View file

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

View file

@ -2468,6 +2468,9 @@ void D_DoomMain (void)
TexMan.Init();
C_InitConback();
StartScreen->Progress();
V_InitFonts();
// [CW] Parse any TEAMINFO lumps.
if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n");
TeamLibrary.ParseTeamInfo ();
@ -2705,6 +2708,8 @@ void D_DoomMain (void)
// delete all data that cannot be left until reinitialization
V_ClearFonts(); // must clear global font pointers
ColorSets.Clear();
PainFlashes.Clear();
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
gameinfo.~gameinfo_t();
new (&gameinfo) gameinfo_t; // Reset gameinfo
@ -2715,7 +2720,7 @@ void D_DoomMain (void)
GC::FullGC(); // clean up before taking down the object list.
// Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions.
// Delete the reference to the VM functions here which were deleted and will be recreated after the restart.
FAutoSegIterator probe(ARegHead, ARegTail);
while (*++probe != NULL)
{

View file

@ -2540,7 +2540,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
case DEM_MORPHEX:
{
s = ReadString (stream);
const char *msg = cht_Morph (players + player, dyn_cast<PClassPlayerPawn>(PClass::FindClass (s)), false);
const char *msg = cht_Morph (players + player, PClass::FindActor (s), false);
if (player == consoleplayer)
{
Printf ("%s\n", *msg != '\0' ? msg : "Morph failed.");
@ -2639,7 +2639,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
}
for(i = 0; i < count; ++i)
{
PClassWeapon *wpn = Net_ReadWeapon(stream);
PClassActor *wpn = Net_ReadWeapon(stream);
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
}
}
@ -2648,7 +2648,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
case DEM_ADDSLOT:
{
int slot = ReadByte(stream);
PClassWeapon *wpn = Net_ReadWeapon(stream);
PClassActor *wpn = Net_ReadWeapon(stream);
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
}
break;
@ -2656,7 +2656,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
case DEM_ADDSLOTDEFAULT:
{
int slot = ReadByte(stream);
PClassWeapon *wpn = Net_ReadWeapon(stream);
PClassActor *wpn = Net_ReadWeapon(stream);
players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer);
}
break;

View file

@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname)
{
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i)
{
PClassPlayerPawn *type = PlayerClasses[i].Type;
auto type = PlayerClasses[i].Type;
if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0)
{
@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet
if (players[player].mo != NULL)
{
colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet());
colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet());
}
if (colorset != NULL)
{

View file

@ -67,39 +67,17 @@ struct FPlayerColorSet
ExtraRange Extra[6];
};
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
typedef TMap<FName, PalEntry> PainFlashList;
typedef TArray<std::tuple<PClass*, FName, PalEntry>> PainFlashList;
typedef TArray<std::tuple<PClass*, int, FPlayerColorSet>> ColorSetList;
class PClassPlayerPawn : public PClassActor
{
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;
extern PainFlashList PainFlashes;
extern ColorSetList ColorSets;
FString DisplayName; // Display name (used in menus, etc.)
FString SoundClass; // Sound class
FString Face; // Doom status bar face (when used)
FString Portrait;
FString Slot[10];
FName InvulMode;
FName HealingRadiusType;
double HexenArmor[5];
BYTE ColorRangeStart; // Skin color range
BYTE ColorRangeEnd;
FPlayerColorSetMap ColorSets;
PainFlashList PainFlashes;
};
FString GetPrintableDisplayName(PClassPlayerPawn *cls);
FString GetPrintableDisplayName(PClassActor *cls);
class APlayerPawn : public AActor
{
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
DECLARE_CLASS(APlayerPawn, AActor)
HAS_OBJECT_POINTERS
public:
@ -120,9 +98,9 @@ public:
void TweakSpeeds (double &forwardmove, double &sidemove);
void MorphPlayerThink ();
void ActivateMorphWeapon ();
AWeapon *PickNewWeapon (PClassInventory *ammotype);
AWeapon *BestWeapon (PClassInventory *ammotype);
void CheckWeaponSwitch(PClassInventory *ammotype);
AWeapon *PickNewWeapon (PClassActor *ammotype);
AWeapon *BestWeapon (PClassActor *ammotype);
void CheckWeaponSwitch(PClassActor *ammotype);
void GiveDeathmatchInventory ();
void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
@ -177,6 +155,17 @@ public:
// [SP] ViewBob Multiplier
double ViewBob;
// Former class properties that were moved into the object to get rid of the meta class.
FName SoundClass; // Sound class
FName Face; // Doom status bar face (when used)
FName Portrait;
FName Slot[10];
FName InvulMode;
FName HealingRadiusType;
double HexenArmor[5];
BYTE ColorRangeStart; // Skin color range
BYTE ColorRangeEnd;
};
//
@ -273,7 +262,7 @@ public:
bool CheckSkin (int skin);
PClassPlayerPawn *Type;
PClassActor *Type;
DWORD Flags;
TArray<int> Skins;
};
@ -345,7 +334,7 @@ struct userinfo_t : TMap<FName,FBaseCVar *>
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
}
PClassPlayerPawn *GetPlayerClassType() const
PClassActor *GetPlayerClassType() const
{
return PlayerClasses[GetPlayerClassNum()].Type;
}
@ -403,7 +392,7 @@ public:
userinfo_t userinfo; // [RH] who is this?
PClassPlayerPawn *cls; // class of associated PlayerPawn
PClassActor *cls; // class of associated PlayerPawn
float DesiredFOV; // desired field of vision
float FOV; // current field of vision
@ -461,7 +450,7 @@ public:
short fixedcolormap; // can be set to REDCOLORMAP, etc.
short fixedlightlevel;
int morphTics; // player is a chicken/pig if > 0
PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
PClassActor *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
int MorphStyle; // which effects to apply for this player instance when morphed
PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer)
TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing
@ -540,12 +529,16 @@ public:
// Make sure that a state is properly set after calling this unless
// you are 100% sure the context already implies the layer exists.
DPSprite *GetPSprite(PSPLayers layer);
bool GetPainFlash(FName type, PalEntry *color) const;
};
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale);
void EnumColorSets(PClassActor *pc, TArray<int> *out);
FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum);
inline void AActor::SetFriendPlayer(player_t *player)
{

View file

@ -301,42 +301,17 @@ DObject::~DObject ()
PClass *type = GetClass();
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
{
DObject **probe;
if (!(ObjectFlags & OF_YesReallyDelete))
if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released)))
{
Printf("Warning: '%s' is freed outside the GC process.\n",
type != NULL ? type->TypeName.GetChars() : "==some object==");
}
// Find all pointers that reference this object and NULL them.
StaticPointerSubstitution(this, NULL);
// Now unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
if (!(ObjectFlags & OF_Released))
{
if (*probe == this)
{
*probe = ObjNext;
if (&ObjNext == GC::SweepPos)
{
GC::SweepPos = probe;
}
break;
}
}
// If it's gray, also unlink it from the gray list.
if (this->IsGray())
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
{
if (*probe == this)
{
*probe = GCNext;
break;
}
}
// Find all pointers that reference this object and NULL them.
StaticPointerSubstitution(this, NULL);
Release();
}
}
@ -347,6 +322,41 @@ DObject::~DObject ()
}
}
void DObject::Release()
{
DObject **probe;
// Unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{
if (*probe == this)
{
*probe = ObjNext;
if (&ObjNext == GC::SweepPos)
{
GC::SweepPos = probe;
}
break;
}
}
// If it's gray, also unlink it from the gray list.
if (this->IsGray())
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
{
if (*probe == this)
{
*probe = GCNext;
break;
}
}
}
ObjNext = nullptr;
GCNext = nullptr;
ObjectFlags |= OF_Released;
}
//==========================================================================
//
//
@ -397,6 +407,23 @@ size_t DObject::PropagateMark()
GC::Mark((DObject **)((BYTE *)this + *offsets));
offsets++;
}
offsets = info->ArrayPointers;
if (offsets == NULL)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
}
while (*offsets != ~(size_t)0)
{
auto aray = (TArray<DObject*>*)((BYTE *)this + *offsets);
for (auto &p : *aray)
{
GC::Mark(&p);
}
offsets++;
}
return info->Size;
}
return 0;
@ -427,6 +454,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
}
offsets++;
}
offsets = info->ArrayPointers;
if (offsets == NULL)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
}
while (*offsets != ~(size_t)0)
{
auto aray = (TArray<DObject*>*)((BYTE *)this + *offsets);
for (auto &p : *aray)
{
if (p == old)
{
p = notOld;
changed++;
}
}
offsets++;
}
return changed;
}

View file

@ -93,11 +93,6 @@ enum
{
CLASSREG_PClass,
CLASSREG_PClassActor,
CLASSREG_PClassInventory,
CLASSREG_PClassWeapon,
CLASSREG_PClassPlayerPawn,
CLASSREG_PClassType,
CLASSREG_PClassClass,
};
struct ClassReg
@ -208,6 +203,7 @@ enum EObjectFlags
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function
};
template<class T> class TObjPtr;
@ -460,6 +456,7 @@ public:
virtual ~DObject ();
inline bool IsKindOf (const PClass *base) const;
inline bool IsKindOf(FName base) const;
inline bool IsA (const PClass *type) const;
void SerializeUserVars(FSerializer &arc);
@ -470,6 +467,9 @@ public:
Class = NULL;
}
// Releases the object from the GC, letting the caller care of any maintenance.
void Release();
// For catching Serialize functions in derived classes
// that don't call their base class.
void CheckIfSerialized () const;
@ -606,6 +606,7 @@ static inline void GC::WriteBarrier(DObject *pointed)
}
}
#include "symbols.h"
#include "dobjtype.h"
inline bool DObject::IsKindOf (const PClass *base) const
@ -613,6 +614,11 @@ inline bool DObject::IsKindOf (const PClass *base) const
return base->IsAncestorOf (GetClass ());
}
inline bool DObject::IsKindOf(FName base) const
{
return GetClass()->IsDescendantOf(base);
}
inline bool DObject::IsA (const PClass *type) const
{
return (type == GetClass());

View file

@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
curr->Destroy();
}
/*
if (curr->IsKindOf(RUNTIME_CLASS(PSymbol)))
Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast<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;
delete curr;
finalized++;
@ -277,7 +285,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
void Mark(DObject **obj)
{
DObject *lobj = *obj;
if (lobj != NULL)
assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released));
if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released))
{
if (lobj->ObjectFlags & OF_EuthanizeMe)
{
@ -361,23 +371,6 @@ static void MarkRoot()
}
Mark(SectorMarker);
Mark(interpolator.Head);
// Mark action functions
if (!FinalGC)
{
FAutoSegIterator probe(ARegHead, ARegTail);
while (*++probe != NULL)
{
AFuncDesc *afunc = (AFuncDesc *)*probe;
Mark(*(afunc->VMPointer));
}
}
// Mark types
TypeTable.Mark();
for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i)
{
Mark(PClass::AllClasses[i]);
}
// Mark global symbols
Namespaces.MarkSymbols();
// Mark bot stuff.
@ -458,8 +451,8 @@ static size_t SingleStep()
{ // Nothing more to sweep?
State = GCS_Finalize;
}
assert(old >= AllocBytes);
Estimate -= old - AllocBytes;
//assert(old >= AllocBytes);
Estimate -= MAX<size_t>(0, old - AllocBytes);
return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST;
}
@ -559,9 +552,12 @@ void FullGC()
void Barrier(DObject *pointing, DObject *pointed)
{
assert(pointed->GetClass() < (void*)0x1000000000000000);
assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead()));
assert(pointed->IsWhite() && !pointed->IsDead());
assert(State != GCS_Finalize && State != GCS_Pause);
assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong.
if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects.
// The invariant only needs to be maintained in the propagate state.
if (State == GCS_Propagate)
{
@ -776,7 +772,7 @@ CCMD(gc)
{
if (argv.argc() == 1)
{
Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n");
Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n");
return;
}
if (stricmp(argv[1], "stop") == 0)
@ -791,6 +787,12 @@ CCMD(gc)
{
GC::FullGC();
}
else if (stricmp(argv[1], "count") == 0)
{
int cnt = 0;
for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++);
Printf("%d active objects counted\n", cnt);
}
else if (stricmp(argv[1], "pause") == 0)
{
if (argv.argc() == 2)
@ -814,3 +816,4 @@ CCMD(gc)
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@
#endif
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
class PStruct;
#include "vm.h"
@ -38,36 +39,6 @@ enum
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
};
// Symbol information -------------------------------------------------------
class PTypeBase : public DObject
{
DECLARE_ABSTRACT_CLASS(PTypeBase, DObject)
public:
virtual FString QualifiedName() const
{
return "";
}
};
class PSymbol : public PTypeBase
{
DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase);
public:
virtual ~PSymbol();
virtual FString QualifiedName() const
{
return SymbolName.GetChars();
}
FName SymbolName;
protected:
PSymbol(FName name) { SymbolName = name; }
};
// An action function -------------------------------------------------------
struct FState;
@ -78,101 +49,6 @@ struct VMReturn;
class VMFunction;
struct FNamespaceManager;
// A VM function ------------------------------------------------------------
class PSymbolVMFunction : public PSymbol
{
DECLARE_CLASS(PSymbolVMFunction, PSymbol);
HAS_OBJECT_POINTERS;
public:
VMFunction *Function;
PSymbolVMFunction(FName name) : PSymbol(name) {}
PSymbolVMFunction() : PSymbol(NAME_None) {}
};
// A symbol for a type ------------------------------------------------------
class PSymbolType : public PSymbol
{
DECLARE_CLASS(PSymbolType, PSymbol);
HAS_OBJECT_POINTERS;
public:
class PType *Type;
PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {}
PSymbolType() : PSymbol(NAME_None) {}
};
// A symbol table -----------------------------------------------------------
struct PSymbolTable
{
PSymbolTable();
PSymbolTable(PSymbolTable *parent);
~PSymbolTable();
size_t MarkSymbols();
// Sets the table to use for searches if this one doesn't contain the
// requested symbol.
void SetParentTable (PSymbolTable *parent);
PSymbolTable *GetParentTable() const
{
return ParentSymbolTable;
}
// Finds a symbol in the table, optionally searching parent tables
// as well.
PSymbol *FindSymbol (FName symname, bool searchparents) const;
// Like FindSymbol with searchparents set true, but also returns the
// specific symbol table the symbol was found in.
PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable);
// Places the symbol in the table and returns a pointer to it or NULL if
// a symbol with the same name is already in the table. This symbol is
// not copied and will be freed when the symbol table is destroyed.
PSymbol *AddSymbol (PSymbol *sym);
// Similar to AddSymbol but always succeeds. Returns the symbol that used
// to be in the table with this name, if any.
PSymbol *ReplaceSymbol(PSymbol *sym);
void RemoveSymbol(PSymbol *sym);
// Frees all symbols from this table.
void ReleaseSymbols();
typedef TMap<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 ------------------------------------
// Only one copy of a type is ever instantiated at one time.
@ -198,22 +74,13 @@ public:
// Prototype *+ *+
struct ZCC_ExprConstant;
class PClassType;
class PType : public PTypeBase
{
//DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType);
// We need to unravel the _WITH_META macro, since PClassType isn't defined yet,
// and we can't define it until we've defined PClass. But we can't define that
// without defining PType.
DECLARE_ABSTRACT_CLASS(PType, PTypeBase)
HAS_OBJECT_POINTERS;
protected:
enum { MetaClassNum = CLASSREG_PClassType };
public:
typedef PClassType MetaClass;
MetaClass *GetClass() const;
PClass *TypeTableType; // The type to use for hashing into the type table
unsigned int Size; // this type's size
unsigned int Align; // this type's preferred alignment
PType *HashNext; // next type in this type table
@ -246,6 +113,7 @@ public:
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const;
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
@ -302,8 +170,6 @@ public:
const char *DescriptiveName() const;
size_t PropagateMark();
static void StaticInit();
};
@ -341,7 +207,6 @@ class PCompoundType : public PType
class PNamedType : public PCompoundType
{
DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType);
HAS_OBJECT_POINTERS;
public:
PTypeBase *Outer; // object this type is contained within
FName TypeName; // this type's name
@ -355,7 +220,6 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
virtual FString QualifiedName() const;
};
// Basic types --------------------------------------------------------------
@ -498,7 +362,6 @@ public:
class PPointer : public PBasicType
{
DECLARE_CLASS(PPointer, PBasicType);
HAS_OBJECT_POINTERS;
public:
PPointer();
PPointer(PType *pointsat, bool isconst = false);
@ -531,9 +394,8 @@ public:
class PClassPointer : public PPointer
{
DECLARE_CLASS(PClassPointer, PPointer);
HAS_OBJECT_POINTERS;
public:
PClassPointer(class PClass *restrict);
PClassPointer(class PClass *restrict = nullptr);
class PClass *ClassRestriction;
@ -541,54 +403,6 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
PClassPointer();
};
// Struct/class fields ------------------------------------------------------
// A PField describes a symbol that takes up physical space in the struct.
class PField : public PSymbol
{
DECLARE_CLASS(PField, PSymbol);
HAS_OBJECT_POINTERS
public:
PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0);
size_t Offset;
PType *Type;
DWORD Flags;
int BitValue;
protected:
PField();
};
// Struct/class fields ------------------------------------------------------
// A PField describes a symbol that takes up physical space in the struct.
class PProperty : public PSymbol
{
DECLARE_CLASS(PProperty, PSymbol);
public:
PProperty(FName name, TArray<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 -----------------------------------------------------------
@ -596,7 +410,6 @@ protected:
class PEnum : public PInt
{
DECLARE_CLASS(PEnum, PInt);
HAS_OBJECT_POINTERS;
public:
PEnum(FName name, PTypeBase *outer);
@ -609,7 +422,6 @@ protected:
class PArray : public PCompoundType
{
DECLARE_CLASS(PArray, PCompoundType);
HAS_OBJECT_POINTERS;
public:
PArray(PType *etype, unsigned int ecount);
@ -633,7 +445,6 @@ protected:
class PResizableArray : public PArray
{
DECLARE_CLASS(PResizableArray, PArray);
HAS_OBJECT_POINTERS;
public:
PResizableArray(PType *etype);
@ -647,14 +458,22 @@ protected:
class PDynArray : public PCompoundType
{
DECLARE_CLASS(PDynArray, PCompoundType);
HAS_OBJECT_POINTERS;
public:
PDynArray(PType *etype);
PDynArray(PType *etype, PStruct *backing);
PType *ElementType;
PStruct *BackingType;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const override;
protected:
PDynArray();
};
@ -662,7 +481,6 @@ protected:
class PMap : public PCompoundType
{
DECLARE_CLASS(PMap, PCompoundType);
HAS_OBJECT_POINTERS;
public:
PMap(PType *keytype, PType *valtype);
@ -691,8 +509,6 @@ public:
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
size_t PropagateMark();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
@ -729,36 +545,6 @@ protected:
PPrototype();
};
// TBD: Should we really support overloading?
class PFunction : public PSymbol
{
DECLARE_CLASS(PFunction, PSymbol);
public:
struct Variant
{
PPrototype *Proto;
VMFunction *Implementation;
TArray<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 ---------------------------
@ -767,22 +553,16 @@ enum
TentativeClass = UINT_MAX,
};
class PClassClass;
class PClass : public PNativeStruct
{
DECLARE_CLASS(PClass, PNativeStruct);
HAS_OBJECT_POINTERS;
protected:
// We unravel _WITH_META here just as we did for PType.
enum { MetaClassNum = CLASSREG_PClassClass };
TArray<FTypeAndOffset> SpecialInits;
void Derive(PClass *newclass, FName name);
void InitializeSpecials(void *addr, void *defaults) const;
void SetSuper();
public:
typedef PClassClass MetaClass;
MetaClass *GetClass() const;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
void WriteAllFields(FSerializer &ar, const void *addr) const;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
@ -799,6 +579,7 @@ public:
PClass *ParentClass; // the class this class derives from
const size_t *Pointers; // object pointers defined by this class *only*
const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default
const size_t *ArrayPointers; // dynamic arrays containing object pointers.
BYTE *Defaults;
bool bRuntimeClass; // class was defined at run-time, not compile-time
bool bExported; // This type has been declared in a script
@ -816,6 +597,7 @@ public:
PField *AddField(FName name, PType *type, DWORD flags=0) override;
void InitializeActorInfo();
void BuildFlatPointers();
void BuildArrayPointers();
void DestroySpecials(void *addr) const;
const PClass *NativeClass() const;
@ -830,11 +612,24 @@ public:
}
return false;
}
inline bool IsDescendantOf(const PClass *ti) const
{
return ti->IsAncestorOf(this);
}
inline bool IsDescendantOf(FName ti) const
{
auto me = this;
while (me)
{
if (me->TypeName == ti)
return true;
me = me->ParentClass;
}
return false;
}
// Find a type, given its name.
const PClass *FindParentClass(FName name) const;
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
@ -858,34 +653,6 @@ public:
static bool bVMOperational;
};
class PClassType : public PClass
{
DECLARE_CLASS(PClassType, PClass);
protected:
public:
PClassType();
virtual void DeriveData(PClass *newclass);
PClass *TypeTableType; // The type to use for hashing into the type table
};
inline PType::MetaClass *PType::GetClass() const
{
return static_cast<MetaClass *>(DObject::GetClass());
}
class PClassClass : public PClassType
{
DECLARE_CLASS(PClassClass, PClassType);
public:
PClassClass();
};
inline PClass::MetaClass *PClass::GetClass() const
{
return static_cast<MetaClass *>(DObject::GetClass());
}
// Type tables --------------------------------------------------------------
struct FTypeTable
@ -895,10 +662,8 @@ struct FTypeTable
PType *TypeHash[HASH_SIZE];
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
void ReplaceType(PType *newtype, PType *oldtype, size_t bucket);
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
void AddType(PType *type);
void Mark();
void Clear();
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
@ -940,86 +705,11 @@ extern PStruct *TypeVector3;
extern PStruct *TypeColorStruct;
extern PStruct *TypeStringStruct;
extern PStatePointer *TypeState;
extern PPointer *TypeFont;
extern PStateLabel *TypeStateLabel;
extern PPointer *TypeNullPtr;
extern PPointer *TypeVoidPtr;
// A constant value ---------------------------------------------------------
class PSymbolConst : public PSymbol
{
DECLARE_CLASS(PSymbolConst, PSymbol);
public:
PType *ValueType;
PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {}
PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {}
};
// A constant numeric value -------------------------------------------------
class PSymbolConstNumeric : public PSymbolConst
{
DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst);
public:
union
{
int Value;
double Float;
void *Pad;
};
PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {}
PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {}
PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {}
PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {}
PSymbolConstNumeric() {}
};
// A constant string value --------------------------------------------------
class PSymbolConstString : public PSymbolConst
{
DECLARE_CLASS(PSymbolConstString, PSymbolConst);
public:
FString Str;
PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {}
PSymbolConstString() {}
};
// Namespaces --------------------------------------------------
class PNamespace : public PTypeBase
{
DECLARE_CLASS(PNamespace, PTypeBase)
HAS_OBJECT_POINTERS;
public:
PSymbolTable Symbols;
PNamespace *Parent;
int FileNum; // This is for blocking DECORATE access to later files.
PNamespace() {}
PNamespace(int filenum, PNamespace *parent);
size_t PropagateMark();
};
struct FNamespaceManager
{
PNamespace *GlobalNamespace;
TArray<PNamespace *> AllNamespaces;
FNamespaceManager();
PNamespace *NewNamespace(int filenum);
size_t MarkSymbols();
void ReleaseSymbols();
int RemoveSymbols();
};
extern FNamespaceManager Namespaces;
// Enumerations for serializing types in an archive -------------------------
inline bool &DObject::BoolVar(FName field)

View file

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

View file

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

View file

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

View file

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

View file

@ -25,58 +25,10 @@
EXTERN_CVAR(Bool, sv_unlimited_pickup)
IMPLEMENT_CLASS(PClassInventory, false, false)
PClassInventory::PClassInventory()
{
GiveQuest = 0;
AltHUDIcon.SetNull();
}
void PClassInventory::DeriveData(PClass *newclass)
{
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory)));
Super::DeriveData(newclass);
PClassInventory *newc = static_cast<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 PClassInventory::Finalize(FStateDefinitions &statedef)
void AInventory::Finalize(FStateDefinitions &statedef)
{
Super::Finalize(statedef);
((AActor*)Defaults)->flags |= MF_SPECIAL;
flags |= MF_SPECIAL;
}
IMPLEMENT_CLASS(AInventory, false, true)
@ -98,8 +50,8 @@ DEFINE_FIELD(AInventory, DropTime)
DEFINE_FIELD(AInventory, SpawnPointClass)
DEFINE_FIELD(AInventory, PickupFlash)
DEFINE_FIELD(AInventory, PickupSound)
DEFINE_FIELD(PClassInventory, PickupMsg)
DEFINE_FIELD(PClassInventory, GiveQuest)
DEFINE_FIELD(AInventory, GiveQuest)
DEFINE_FIELD(PClassActor, PickupMsg)
//===========================================================================
//
@ -163,7 +115,8 @@ void AInventory::Serialize(FSerializer &arc)
("icon", Icon, def->Icon)
("pickupsound", PickupSound, def->PickupSound)
("spawnpointclass", SpawnPointClass, def->SpawnPointClass)
("droptime", DropTime, def->DropTime);
("droptime", DropTime, def->DropTime)
("givequest", GiveQuest, def->GiveQuest);
}
//===========================================================================
@ -548,7 +501,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CanPickup)
if (!toucher)
ACTION_RETURN_BOOL(false);
PClassInventory *ai = self->GetClass();
auto ai = self->GetClass();
// Is the item restricted to certain player classes?
if (ai->RestrictedToPlayerClass.Size() != 0)
{

View file

@ -9,7 +9,6 @@
class player_t;
class FConfigFile;
class PClassPlayerPawn;
struct visstyle_t;
/************************************************************************/
@ -50,28 +49,13 @@ enum
};
class PClassInventory : public PClassActor
{
DECLARE_CLASS(PClassInventory, PClassActor)
public:
PClassInventory();
virtual void DeriveData(PClass *newclass);
virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass);
void Finalize(FStateDefinitions &statedef);
FString PickupMsg;
int GiveQuest; // Optionally give one of the quest items.
FTextureID AltHUDIcon;
TArray<PClassPlayerPawn *> RestrictedToPlayerClass;
TArray<PClassPlayerPawn *> ForbiddenToPlayerClass;
};
class AInventory : public AActor
{
DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory)
DECLARE_CLASS(AInventory, AActor)
HAS_OBJECT_POINTERS
public:
virtual void Finalize(FStateDefinitions &statedef) override;
virtual void Serialize(FSerializer &arc) override;
virtual void MarkPrecacheSounds() const override;
virtual void OnDestroy() override;
@ -103,6 +87,8 @@ public:
FTextureID Icon; // Icon to show on status bar or HUD
int DropTime; // Countdown after dropping
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
int GiveQuest; // Optionally give one of the quest items.
FTextureID AltHUDIcon;
DWORD ItemFlags;
PClassActor *PickupFlash; // actor to spawn as pickup flash

View file

@ -64,9 +64,6 @@ IMPLEMENT_POINTERS_START(AWeapon)
IMPLEMENT_POINTER(Ammo1)
IMPLEMENT_POINTER(Ammo2)
IMPLEMENT_POINTER(SisterWeapon)
IMPLEMENT_POINTER(AmmoType1)
IMPLEMENT_POINTER(AmmoType2)
IMPLEMENT_POINTER(SisterWeaponType)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(AWeapon, WeaponFlags)
@ -113,55 +110,25 @@ FString WeaponSection;
TArray<FString> KeyConfWeapons;
FWeaponSlots *PlayingKeyConf;
TArray<PClassWeapon *> Weapons_ntoh;
TMap<PClassWeapon *, int> Weapons_hton;
TArray<PClassActor *> Weapons_ntoh;
TMap<PClassActor *, int> Weapons_hton;
static int ntoh_cmp(const void *a, const void *b);
IMPLEMENT_CLASS(PClassWeapon, false, false)
//===========================================================================
//
//
//
//===========================================================================
PClassWeapon::PClassWeapon()
{
SlotNumber = -1;
SlotPriority = INT_MAX;
}
//===========================================================================
//
//
//
//===========================================================================
void PClassWeapon::DeriveData(PClass *newclass)
{
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon)));
Super::DeriveData(newclass);
PClassWeapon *newc = static_cast<PClassWeapon *>(newclass);
newc->SlotNumber = SlotNumber;
newc->SlotPriority = SlotPriority;
}
//===========================================================================
//
//
//
//===========================================================================
void PClassWeapon::Finalize(FStateDefinitions &statedef)
void AWeapon::Finalize(FStateDefinitions &statedef)
{
Super::Finalize(statedef);
FState *ready = FindState(NAME_Ready);
FState *select = FindState(NAME_Select);
FState *deselect = FindState(NAME_Deselect);
FState *fire = FindState(NAME_Fire);
auto TypeName = GetClass()->TypeName;
// Consider any weapon without any valid state abstract and don't output a warning
// This is for creating base classes for weapon groups that only set up some properties.
@ -272,7 +239,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false);
if (!gotSome && autoSwitch)
{
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (NULL);
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (nullptr);
}
return gotSome;
}
@ -281,10 +248,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
{
return true;
}
count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0;
count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0;
count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0;
count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0;
if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL))
if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr))
{
lAmmoUse1 = 0;
}
@ -306,7 +273,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
{
enoughmask = 1 << altFire;
}
if (altFire && FindState(NAME_AltFire) == NULL)
if (altFire && FindState(NAME_AltFire) == nullptr)
{ // If this weapon has no alternate fire, then there is never enough ammo for it
enough &= 1;
}
@ -317,7 +284,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
// out of ammo, pick a weapon to change to
if (autoSwitch)
{
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (NULL);
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (nullptr);
}
return false;
}
@ -352,7 +319,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
}
if (!altFire)
{
if (Ammo1 != NULL)
if (Ammo1 != nullptr)
{
if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO))
{
@ -363,25 +330,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
Ammo1->Amount -= AmmoUse1;
}
}
if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL)
if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr)
{
Ammo2->Amount -= AmmoUse2;
}
}
else
{
if (Ammo2 != NULL)
if (Ammo2 != nullptr)
{
Ammo2->Amount -= AmmoUse2;
}
if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL)
if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr)
{
Ammo1->Amount -= AmmoUse1;
}
}
if (Ammo1 != NULL && Ammo1->Amount < 0)
if (Ammo1 != nullptr && Ammo1->Amount < 0)
Ammo1->Amount = 0;
if (Ammo2 != NULL && Ammo2->Amount < 0)
if (Ammo2 != nullptr && Ammo2->Amount < 0)
Ammo2->Amount = 0;
}
return true;
@ -546,19 +513,19 @@ FState *AWeapon::GetStateForButtonName (FName button)
bool FWeaponSlot::AddWeapon(const char *type)
{
return AddWeapon(static_cast<PClassWeapon *>(PClass::FindClass(type)));
return AddWeapon(static_cast<PClassActor *>(PClass::FindClass(type)));
}
bool FWeaponSlot::AddWeapon(PClassWeapon *type)
bool FWeaponSlot::AddWeapon(PClassActor *type)
{
unsigned int i;
if (type == NULL)
if (type == nullptr)
{
return false;
}
if (!type->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
if (!type->IsDescendantOf(NAME_Weapon))
{
Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars());
return false;
@ -594,10 +561,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear)
Clear();
}
tok = strtok(buff, " ");
while (tok != NULL)
while (tok != nullptr)
{
AddWeapon(tok);
tok = strtok(NULL, " ");
tok = strtok(nullptr, " ");
}
}
@ -610,7 +577,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear)
//
//===========================================================================
int FWeaponSlot::LocateWeapon(PClassWeapon *type)
int FWeaponSlot::LocateWeapon(PClassActor *type)
{
unsigned int i;
@ -641,22 +608,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{
int i, j;
if (player->mo == NULL)
if (player->mo == nullptr)
{
return NULL;
return nullptr;
}
// Does this slot even have any weapons?
if (Weapons.Size() == 0)
{
return player->ReadyWeapon;
}
if (player->ReadyWeapon != NULL)
if (player->ReadyWeapon != nullptr)
{
for (i = 0; (unsigned)i < Weapons.Size(); i++)
{
if (Weapons[i].Type == player->ReadyWeapon->GetClass() ||
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
player->ReadyWeapon->SisterWeapon != NULL &&
player->ReadyWeapon->SisterWeapon != nullptr &&
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type))
{
for (j = (i == 0 ? Weapons.Size() - 1 : i - 1);
@ -665,7 +632,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[j].Type));
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{
@ -680,7 +647,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[i].Type));
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{
@ -736,7 +703,7 @@ void FWeaponSlot::Sort()
for (i = 1; i < (int)Weapons.Size(); ++i)
{
int pos = Weapons[i].Position;
PClassWeapon *type = Weapons[i].Type;
PClassActor *type = Weapons[i].Type;
for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j)
{
Weapons[j + 1] = Weapons[j];
@ -785,7 +752,7 @@ void FWeaponSlots::Clear()
//
//===========================================================================
ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type)
ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type)
{
int currSlot, index;
@ -810,7 +777,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type)
//
//===========================================================================
bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index)
bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index)
{
int i, j;
@ -819,8 +786,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const
j = Slots[i].LocateWeapon(type);
if (j >= 0)
{
if (slot != NULL) *slot = i;
if (index != NULL) *index = j;
if (slot != nullptr) *slot = i;
if (index != nullptr) *index = j;
return true;
}
}
@ -857,14 +824,14 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index)
{
return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index);
}
else if (player->ReadyWeapon != NULL)
else if (player->ReadyWeapon != nullptr)
{
AWeapon *weap = player->ReadyWeapon;
if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index))
{
// If the current weapon wasn't found and is powered up,
// look for its non-powered up version.
if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL)
if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr)
{
return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index);
}
@ -893,16 +860,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
int startslot, startindex;
int slotschecked = 0;
if (player->mo == NULL)
if (player->mo == nullptr)
{
return NULL;
return nullptr;
}
if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex))
if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex))
{
int slot;
int index;
if (player->ReadyWeapon == NULL)
if (player->ReadyWeapon == nullptr)
{
startslot = NUM_WEAPON_SLOTS - 1;
startindex = Slots[startslot].Size() - 1;
@ -921,9 +888,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
slot = 0;
}
}
PClassWeapon *type = Slots[slot].GetWeapon(index);
PClassActor *type = Slots[slot].GetWeapon(index);
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false))
if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
@ -948,16 +915,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
int startslot, startindex;
int slotschecked = 0;
if (player->mo == NULL)
if (player->mo == nullptr)
{
return NULL;
return nullptr;
}
if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex))
if (player->ReadyWeapon == nullptr || FindMostRecentWeapon (player, &startslot, &startindex))
{
int slot;
int index;
if (player->ReadyWeapon == NULL)
if (player->ReadyWeapon == nullptr)
{
startslot = 0;
startindex = 0;
@ -976,9 +943,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
}
index = Slots[slot].Size() - 1;
}
PClassWeapon *type = Slots[slot].GetWeapon(index);
PClassActor *type = Slots[slot].GetWeapon(index);
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false))
if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
@ -1010,23 +977,23 @@ void FWeaponSlots::AddExtraWeapons()
// Append extra weapons to the slots.
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
PClass *cls = PClassActor::AllActorClasses[i];
PClassActor *cls = PClassActor::AllActorClasses[i];
if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
if (!cls->IsDescendantOf(NAME_Weapon))
{
continue;
}
PClassWeapon *acls = static_cast<PClassWeapon *>(cls);
if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) &&
acls->Replacement == NULL && // Replaced weapons don't get slotted.
!(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) &&
!LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present.
auto weapdef = ((AWeapon*)GetDefaultByType(cls));
if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) &&
cls->Replacement == nullptr && // Replaced weapons don't get slotted.
!(weapdef->WeaponFlags & WIF_POWERED_UP) &&
!LocateWeapon(cls, nullptr, nullptr) // Don't duplicate it if it's already present.
)
{
int slot = acls->SlotNumber;
int slot = weapdef->SlotNumber;
if ((unsigned)slot < NUM_WEAPON_SLOTS)
{
FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority };
FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority };
Slots[slot].Weapons.Push(info);
}
}
@ -1063,8 +1030,8 @@ void FWeaponSlots::SetFromGameInfo()
{
for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++)
{
PClassWeapon *cls = dyn_cast<PClassWeapon>(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j]));
if (cls == NULL)
PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]);
if (cls == nullptr)
{
Printf("Unknown weapon class '%s' found in default weapon slot assignments\n",
gameinfo.DefaultWeaponSlots[i][j].GetChars());
@ -1088,7 +1055,7 @@ void FWeaponSlots::SetFromGameInfo()
//
//===========================================================================
void FWeaponSlots::StandardSetup(PClassPlayerPawn *type)
void FWeaponSlots::StandardSetup(PClassActor *type)
{
SetFromPlayer(type);
AddExtraWeapons();
@ -1181,14 +1148,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other)
//
//===========================================================================
void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type)
void FWeaponSlots::SetFromPlayer(PClassActor *type)
{
Clear();
auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot;
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
if (!type->Slot[i].IsEmpty())
if (Slot[i] != NAME_None)
{
Slots[i].AddWeaponList(type->Slot[i], false);
Slots[i].AddWeaponList(Slot[i], false);
}
}
}
@ -1260,7 +1228,7 @@ CCMD (setslot)
if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
{
Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n");
if (players[consoleplayer].mo != NULL)
if (players[consoleplayer].mo != nullptr)
{
FString config(GameConfig->GetConfigPath(false));
Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE
@ -1279,7 +1247,7 @@ CCMD (setslot)
{
KeyConfWeapons.Push(argv.args());
}
else if (PlayingKeyConf != NULL)
else if (PlayingKeyConf != nullptr)
{
PlayingKeyConf->Slots[slot].Clear();
for (int i = 2; i < argv.argc(); ++i)
@ -1299,7 +1267,7 @@ CCMD (setslot)
Net_WriteByte(argv.argc()-2);
for (int i = 2; i < argv.argc(); i++)
{
Net_WriteWeapon(dyn_cast<PClassWeapon>(PClass::FindClass(argv[i])));
Net_WriteWeapon(dyn_cast<PClassActor>(PClass::FindClass(argv[i])));
}
}
}
@ -1310,9 +1278,9 @@ CCMD (setslot)
//
//===========================================================================
void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback)
void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback)
{
if (type != NULL && !Slots[slot].AddWeapon(type) && feedback)
if (type != nullptr && !Slots[slot].AddWeapon(type) && feedback)
{
Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot);
}
@ -1328,8 +1296,8 @@ CCMD (addslot)
return;
}
PClassWeapon *type= dyn_cast<PClassWeapon>(PClass::FindClass(argv[2]));
if (type == NULL)
PClassActor *type= dyn_cast<PClassActor>(PClass::FindClass(argv[2]));
if (type == nullptr)
{
Printf("%s is not a weapon\n", argv[2]);
return;
@ -1339,7 +1307,7 @@ CCMD (addslot)
{
KeyConfWeapons.Push(argv.args());
}
else if (PlayingKeyConf != NULL)
else if (PlayingKeyConf != nullptr)
{
PlayingKeyConf->AddSlot(int(slot), type, false);
}
@ -1370,9 +1338,9 @@ CCMD (weaponsection)
// CCMD addslotdefault
//
//===========================================================================
void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback)
void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback)
{
if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
if (type != nullptr && type->IsDescendantOf(NAME_Weapon))
{
switch (AddDefaultWeapon(slot, type))
{
@ -1395,7 +1363,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback)
CCMD (addslotdefault)
{
PClassWeapon *type;
PClassActor *type;
unsigned int slot;
if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
@ -1404,8 +1372,8 @@ CCMD (addslotdefault)
return;
}
type = dyn_cast<PClassWeapon>(PClass::FindClass(argv[2]));
if (type == NULL)
type = dyn_cast<PClassActor>(PClass::FindClass(argv[2]));
if (type == nullptr)
{
Printf ("%s is not a weapon\n", argv[2]);
return;
@ -1415,7 +1383,7 @@ CCMD (addslotdefault)
{
KeyConfWeapons.Push(argv.args());
}
else if (PlayingKeyConf != NULL)
else if (PlayingKeyConf != nullptr)
{
PlayingKeyConf->AddSlotDefault(int(slot), type, false);
}
@ -1443,7 +1411,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots)
FString cmd(KeyConfWeapons[i]);
AddCommandString(cmd.LockBuffer());
}
PlayingKeyConf = NULL;
PlayingKeyConf = nullptr;
}
//===========================================================================
@ -1460,20 +1428,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots)
void P_SetupWeapons_ntohton()
{
unsigned int i;
PClassWeapon *cls;
PClassActor *cls;
Weapons_ntoh.Clear();
Weapons_hton.Clear();
cls = NULL;
Weapons_ntoh.Push(cls); // Index 0 is always NULL.
cls = nullptr;
Weapons_ntoh.Push(cls); // Index 0 is always nullptr.
for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
PClassActor *cls = PClassActor::AllActorClasses[i];
if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
if (cls->IsDescendantOf(NAME_Weapon))
{
Weapons_ntoh.Push(static_cast<PClassWeapon *>(cls));
Weapons_ntoh.Push(static_cast<PClassActor *>(cls));
}
}
qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp);
@ -1499,8 +1467,8 @@ void P_SetupWeapons_ntohton()
static int ntoh_cmp(const void *a, const void *b)
{
PClassWeapon *c1 = *(PClassWeapon **)a;
PClassWeapon *c2 = *(PClassWeapon **)b;
PClassActor *c1 = *(PClassActor **)a;
PClassActor *c2 = *(PClassActor **)b;
int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2;
int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2;
if (g1 != g2)
@ -1540,24 +1508,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo)
void P_ReadDemoWeaponsChunk(BYTE **demo)
{
int count, i;
PClassWeapon *type;
PClassActor *type;
const char *s;
count = ReadWord(demo);
Weapons_ntoh.Resize(count);
Weapons_hton.Clear(count);
Weapons_ntoh[0] = type = NULL;
Weapons_ntoh[0] = type = nullptr;
Weapons_hton[type] = 0;
for (i = 1; i < count; ++i)
{
s = ReadStringConst(demo);
type = dyn_cast<PClassWeapon>(PClass::FindClass(s));
type = dyn_cast<PClassActor>(PClass::FindClass(s));
// If a demo was recorded with a weapon that is no longer present,
// should we report it?
Weapons_ntoh[i] = type;
if (type != NULL)
if (type != nullptr)
{
Weapons_hton[type] = i;
}
@ -1570,12 +1538,12 @@ void P_ReadDemoWeaponsChunk(BYTE **demo)
//
//===========================================================================
void Net_WriteWeapon(PClassWeapon *type)
void Net_WriteWeapon(PClassActor *type)
{
int index, *index_p;
index_p = Weapons_hton.CheckKey(type);
if (index_p == NULL)
if (index_p == nullptr)
{
index = 0;
}
@ -1602,7 +1570,7 @@ void Net_WriteWeapon(PClassWeapon *type)
//
//===========================================================================
PClassWeapon *Net_ReadWeapon(BYTE **stream)
PClassActor *Net_ReadWeapon(BYTE **stream)
{
int index;
@ -1613,7 +1581,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream)
}
if ((unsigned)index >= Weapons_ntoh.Size())
{
return NULL;
return nullptr;
}
return Weapons_ntoh[index];
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "a_pickups.h"
class PClassWeapon;
class PClassActor;
class AWeapon;
class FWeaponSlot
@ -12,13 +12,13 @@ public:
FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; }
void Clear() { Weapons.Clear(); }
bool AddWeapon (const char *type);
bool AddWeapon (PClassWeapon *type);
bool AddWeapon (PClassActor *type);
void AddWeaponList (const char *list, bool clear);
AWeapon *PickWeapon (player_t *player, bool checkammo = false);
int Size () const { return (int)Weapons.Size(); }
int LocateWeapon (PClassWeapon *type);
int LocateWeapon (PClassActor *type);
inline PClassWeapon *GetWeapon (int index) const
inline PClassActor *GetWeapon (int index) const
{
if ((unsigned)index < Weapons.Size())
{
@ -35,7 +35,7 @@ public:
private:
struct WeaponInfo
{
PClassWeapon *Type;
PClassActor *Type;
int Position;
};
void SetInitialPositions();
@ -61,59 +61,45 @@ struct FWeaponSlots
AWeapon *PickPrevWeapon (player_t *player);
void Clear ();
bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index);
ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type);
bool LocateWeapon (PClassActor *type, int *const slot, int *const index);
ESlotDef AddDefaultWeapon (int slot, PClassActor *type);
void AddExtraWeapons();
void SetFromGameInfo();
void SetFromPlayer(PClassPlayerPawn *type);
void StandardSetup(PClassPlayerPawn *type);
void SetFromPlayer(PClassActor *type);
void StandardSetup(PClassActor *type);
void LocalSetup(PClassActor *type);
void SendDifferences(int playernum, const FWeaponSlots &other);
int RestoreSlots (FConfigFile *config, const char *section);
void PrintSettings();
void AddSlot(int slot, PClassWeapon *type, bool feedback);
void AddSlotDefault(int slot, PClassWeapon *type, bool feedback);
void AddSlot(int slot, PClassActor *type, bool feedback);
void AddSlotDefault(int slot, PClassActor *type, bool feedback);
};
void P_PlaybackKeyConfWeapons(FWeaponSlots *slots);
void Net_WriteWeapon(PClassWeapon *type);
PClassWeapon *Net_ReadWeapon(BYTE **stream);
void Net_WriteWeapon(PClassActor *type);
PClassActor *Net_ReadWeapon(BYTE **stream);
void P_SetupWeapons_ntohton();
void P_WriteDemoWeaponsChunk(BYTE **demo);
void P_ReadDemoWeaponsChunk(BYTE **demo);
// A weapon is just that.
class PClassWeapon : public PClassInventory
{
DECLARE_CLASS(PClassWeapon, PClassInventory);
protected:
virtual void DeriveData(PClass *newclass);
public:
PClassWeapon();
void Finalize(FStateDefinitions &statedef);
int SlotNumber;
int SlotPriority;
};
class AWeapon : public AStateProvider
{
DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon)
DECLARE_CLASS(AWeapon, AStateProvider)
HAS_OBJECT_POINTERS
public:
DWORD WeaponFlags;
PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
int Kickback;
float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double)
FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle
PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one
PClassActor *SisterWeaponType; // Another weapon to pick up with this one
PClassActor *ProjectileType; // Projectile used by primary attack
PClassActor *AltProjectileType; // Projectile used by alternate attack
int SelectionOrder; // Lower-numbered weapons get picked first
@ -123,6 +109,8 @@ public:
int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double)
float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs.
float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
int SlotNumber;
int SlotPriority;
// In-inventory instance variables
TObjPtr<AInventory> Ammo1, Ammo2;
@ -135,7 +123,8 @@ public:
virtual void MarkPrecacheSounds() const;
virtual void Serialize(FSerializer &arc) override;
void Finalize(FStateDefinitions &statedef) override;
void Serialize(FSerializer &arc) override;
void PostMorphWeapon();

View file

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

View file

@ -35,7 +35,7 @@ class AActor;
class player_t;
class AMorphedMonster;
bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0,
bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0,
PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL);
bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false);
bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0,

View file

@ -122,16 +122,6 @@ static int statspace;
DVector2 AM_GetPosition();
int active_con_scaletext();
FTextureID GetHUDIcon(PClassInventory *cls)
{
return cls->AltHUDIcon;
}
void SetHUDIcon(PClassInventory *cls, FTextureID tex)
{
cls->AltHUDIcon = tex;
}
//---------------------------------------------------------------------------
//
// Draws an image into a box with its bottom center at the bottom
@ -437,7 +427,7 @@ static void SetKeyTypes()
static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv)
{
FTextureID icon = FNullTextureID();
FTextureID AltIcon = GetHUDIcon(inv->GetClass());
FTextureID AltIcon = inv->AltHUDIcon;
if (!AltIcon.Exists()) return;
@ -516,27 +506,27 @@ static int DrawKeys(player_t * CPlayer, int x, int y)
// Drawing Ammo
//
//---------------------------------------------------------------------------
static TArray<PClassInventory *> orderedammos;
static TArray<PClassActor *> orderedammos;
static void AddAmmoToList(AWeapon * weapdef)
{
for(int i=0; i<2;i++)
for (int i = 0; i < 2; i++)
{
PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2;
auto ti = i == 0 ? weapdef->AmmoType1 : weapdef->AmmoType2;
if (ti)
{
auto ammodef=(AInventory*)GetDefaultByType(ti);
auto ammodef = (AInventory*)GetDefaultByType(ti);
if (ammodef && !(ammodef->ItemFlags&IF_INVBAR))
{
unsigned int j;
for(j=0;j<orderedammos.Size();j++)
for (j = 0; j < orderedammos.Size(); j++)
{
if (ti == orderedammos[j]) break;
}
if (j==orderedammos.Size()) orderedammos.Push(ti);
if (j == orderedammos.Size()) orderedammos.Push(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
for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory)
{
if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (inv->IsKindOf(NAME_Weapon))
{
AddAmmoToList((AWeapon*)inv);
}
@ -646,11 +636,11 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
for(i=orderedammos.Size()-1;i>=0;i--)
{
PClassInventory * type = orderedammos[i];
auto type = orderedammos[i];
auto ammoitem = CPlayer->mo->FindInventory(type);
auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
FTextureID AltIcon = GetHUDIcon(type);
FTextureID AltIcon = inv->AltHUDIcon;
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
if (!icon.isValid()) continue;
@ -682,7 +672,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
//---------------------------------------------------------------------------
FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO
{
FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass());
FTextureID picnum, AltIcon = item->AltHUDIcon;
FState * state=NULL, *ReadyState;
picnum.SetNull();
@ -713,7 +703,7 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL
}
}
// no spawn state - now try the ready state if it's weapon
else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0)
else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0)
{
state = ReadyState;
}
@ -767,7 +757,7 @@ static void DrawWeapons(player_t *CPlayer, int x, int y)
// First draw all weapons in the inventory that are not assigned to a weapon slot
for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory)
{
if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) &&
if (inv->IsKindOf(NAME_Weapon) &&
!CPlayer->weapons.LocateWeapon(static_cast<AWeapon*>(inv)->GetClass(), NULL, NULL))
{
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)
{
FTextureID AltIcon = GetHUDIcon(rover->GetClass());
FTextureID AltIcon = rover->AltHUDIcon;
if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) )
{
@ -1285,7 +1275,7 @@ void HUD_InitHud()
}
else tex.SetInvalid();
if (ti) SetHUDIcon(static_cast<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)
{
int skin = player->userinfo.GetSkin();
const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? player->MorphedPlayerClass->Face.GetChars() : skins[skin].face);
const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face);
return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle);
}
return NULL;

View file

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

View file

@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox();
inline PClassActor * GetRealType(PClassActor * ti)
{
PClassActor *rep = ti->GetReplacement(false);
if (rep != ti && rep != NULL && rep->IsDescendantOf(PClass::FindActor(NAME_DehackedPickup)))
if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup))
{
return rep;
}

View file

@ -787,6 +787,10 @@ void gl_InitModels()
map[c]=1;
}
}
else if (sc.Compare("dontcullbackfaces"))
{
smf.flags |= MDL_DONTCULLBACKFACES;
}
else
{
sc.ScriptMessage("Unrecognized string \"%s\"", sc.String);
@ -949,8 +953,9 @@ void gl_RenderModel(GLSprite * spr)
gl_RenderState.EnableTexture(true);
// [BB] In case the model should be rendered translucent, do back face culling.
// This solves a few of the problems caused by the lack of depth sorting.
// [Nash] Don't do back face culling if explicitly specified in MODELDEF
// TO-DO: Implement proper depth sorting.
if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
if (!(spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
{
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
@ -1012,6 +1017,9 @@ void gl_RenderModel(GLSprite * spr)
// Model space => World space
gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y );
// [Nash] take SpriteRotation into account
angle += spr->actor->SpriteRotation.Degrees;
if (spr->actor->renderflags & RF_INTERPOLATEANGLES)
{
// [Nash] use interpolated angles

View file

@ -370,6 +370,7 @@ enum
MDL_USEACTORPITCH = 32,
MDL_USEACTORROLL = 64,
MDL_BADROTATION = 128,
MDL_DONTCULLBACKFACES = 256,
};
struct FSpriteModelFrame

View file

@ -866,6 +866,14 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
// This should be done after postprocessing, not before.
mBuffers->BindCurrentFB();
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
if (!toscreen)
{
gl_RenderState.mViewMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.ortho(mScreenViewport.left, mScreenViewport.width, mScreenViewport.height, mScreenViewport.top, -1.0f, 1.0f);
gl_RenderState.ApplyMatrices();
}
DrawBlend(lviewsector);
}
mDrawingScene2D = false;

View file

@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
const char *callinfo = "";
if (info != nullptr && info->mStateType == STATE_Psprite)
{
if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon ";
if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon ";
else callinfo = "overlay ";
}
err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars());
@ -176,11 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex)
ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false));
}
IMPLEMENT_CLASS(PClassActor, false, true)
IMPLEMENT_POINTERS_START(PClassActor)
IMPLEMENT_POINTER(DropItems)
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(PClassActor, false, false)
//==========================================================================
//
@ -349,32 +345,12 @@ void PClassActor::DeriveData(PClass *newclass)
*newa->PainChances = *PainChances;
}
}
// Inventory stuff
newa->PickupMsg = PickupMsg;
newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass;
newa->RestrictedToPlayerClass = RestrictedToPlayerClass;
//==========================================================================
//
// PClassActor :: PropagateMark
//
//==========================================================================
size_t PClassActor::PropagateMark()
{
// Mark state functions
for (int i = 0; i < NumOwnedStates; ++i)
{
if (OwnedStates[i].ActionFunc != NULL)
{
GC::Mark(OwnedStates[i].ActionFunc);
}
}
// Mark damage function
if (Defaults != NULL)
{
GC::Mark(((AActor *)Defaults)->DamageFunc);
}
// marked += ActorInfo->NumOwnedStates * sizeof(FState);
return Super::PropagateMark();
newa->DisplayName = DisplayName;
}
//==========================================================================
@ -414,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName)
//
//==========================================================================
void PClassActor::SetDropItems(DDropItem *drops)
void PClassActor::SetDropItems(FDropItem *drops)
{
DropItems = drops;
GC::WriteBarrier(this, DropItems);
}
@ -429,20 +404,20 @@ void PClassActor::SetDropItems(DDropItem *drops)
//
//==========================================================================
void PClassActor::Finalize(FStateDefinitions &statedef)
void AActor::Finalize(FStateDefinitions &statedef)
{
AActor *defaults = (AActor*)Defaults;
AActor *defaults = this;
try
{
statedef.FinishStates(this, defaults);
statedef.FinishStates(GetClass(), defaults);
}
catch (CRecoverableError &)
{
statedef.MakeStateDefines(NULL);
throw;
}
statedef.InstallStates(this, defaults);
statedef.InstallStates(GetClass(), defaults);
statedef.MakeStateDefines(NULL);
}
@ -659,10 +634,33 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass)
{
if (VisibleToPlayerClass[i] == oldclass)
{
VisibleToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
VisibleToPlayerClass[i] = static_cast<PClassActor*>(newclass);
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;
}

View file

@ -234,13 +234,11 @@ private:
static DamageTypeDefinition *Get(FName type);
};
class DDropItem;
class PClassPlayerPawn;
struct FDropItem;
class PClassActor : public PClass
{
DECLARE_CLASS(PClassActor, PClass);
HAS_OBJECT_POINTERS;
protected:
public:
static void StaticInit ();
@ -256,10 +254,8 @@ public:
void RegisterIDs();
void SetDamageFactor(FName type, double factor);
void SetPainChance(FName type, int chance);
size_t PropagateMark();
bool SetReplacement(FName replaceName);
void SetDropItems(DDropItem *drops);
virtual void Finalize(FStateDefinitions &statedef);
void SetDropItems(FDropItem *drops);
FState *FindState(int numnames, FName *names, bool exact=false) const;
FState *FindStateByString(const char *name, bool exact=false);
@ -289,7 +285,7 @@ public:
DmgFactors *DamageFactors;
PainChanceList *PainChances;
TArray<PClassPlayerPawn *> VisibleToPlayerClass;
TArray<PClassActor *> VisibleToPlayerClass;
FString Obituary; // Player was killed by this actor
FString HitObituary; // Player was killed by this actor in melee
@ -306,7 +302,7 @@ public:
FName BloodType2; // Bloopsplatter replacement type
FName BloodType3; // AxeBlood replacement type
DDropItem *DropItems;
FDropItem *DropItems;
FString SourceLumpName;
FIntCVar *distancecheck;
@ -319,6 +315,14 @@ public:
FName MissileName;
double MissileHeight;
// These are only valid for inventory items.
FString PickupMsg;
TArray<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
static TArray<PClassActor *> AllActorClasses;
};

View file

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

View file

@ -30,12 +30,12 @@
// [RH] Functions that actually perform the cheating
class player_t;
class PClassPlayerPawn;
class PClassActor;
void cht_DoCheat (player_t *player, int cheat);
void cht_Give (player_t *player, const char *item, int amount=1);
void cht_Take (player_t *player, const char *item, int amount=1);
void cht_Suicide (player_t *player);
const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo);
const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo);
#endif

View file

@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks()
FreeBlockChain(FreeBlocks);
}
//==========================================================================
//
// FMemArena :: DumpInfo
//
// Prints some info about this arena
//
//==========================================================================
void FMemArena::DumpInfo()
{
size_t allocated = 0;
size_t used = 0;
for (auto block = TopBlock; block != NULL; block = block->NextBlock)
{
allocated += BlockSize;
used += BlockSize - ((char*)block->Limit - (char*)block->Avail);
}
Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used);
}
//==========================================================================
//
// FMemArena :: FreeBlockChain

View file

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

View file

@ -435,7 +435,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation()
if (mPlayerClass != NULL)
{
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0]));
R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset),
R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
}
}
@ -557,11 +557,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected)
return;
}
FString portrait = mPlayerClass->Type->Portrait;
FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait;
if (portrait.IsNotEmpty() && !mNoportrait)
if (portrait != NAME_None && !mNoportrait)
{
FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch);
FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch);
if (texid.isValid())
{
FTexture *tex = TexMan(texid);

View file

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

View file

@ -821,6 +821,8 @@ xx(DamageFunction)
xx(Length)
xx(Unit)
xx(Size)
xx(Copy)
xx(Move)
xx(Voidptr)
xx(StateLabel)
xx(SpriteID)

View file

@ -858,7 +858,8 @@ void P_Spawn3DFloors (void)
{
case ExtraFloor_LightOnly:
if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0;
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
if (line.args[0] != 0)
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
break;
case Sector_Set3DFloor:
@ -877,7 +878,8 @@ void P_Spawn3DFloors (void)
line.args[4]=0;
}
}
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
if (line.args[0] != 0)
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
break;
default:

View file

@ -114,13 +114,6 @@ FRandom pr_acs ("ACS");
#define HUDMSG_VISIBILITY_MASK (0x00070000)
// See HUDMSG visibility enumerations in sbar.h
// Flags for ReplaceTextures
#define NOT_BOTTOM 1
#define NOT_MIDDLE 2
#define NOT_TOP 4
#define NOT_FLOOR 8
#define NOT_CEILING 16
// LineAttack flags
#define FHF_NORANDOMPUFFZ 1
#define FHF_NOIMPACTDECAL 2
@ -1193,12 +1186,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount)
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i])
players[i].mo->GiveInventory(static_cast<PClassInventory *>(info), amount);
players[i].mo->GiveInventory(info, amount);
}
}
else
{
activator->GiveInventory(static_cast<PClassInventory *>(info), amount);
activator->GiveInventory(info, amount);
}
}
@ -3322,47 +3315,6 @@ void DLevelScript::SetLineTexture (int lineid, int side, int position, int name)
}
}
void DLevelScript::ReplaceTextures (int fromnamei, int tonamei, int flags)
{
const char *fromname = FBehavior::StaticLookupString (fromnamei);
const char *toname = FBehavior::StaticLookupString (tonamei);
FTextureID picnum1, picnum2;
if (fromname == NULL)
return;
if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0)
{
picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
for (auto &side : level.sides)
{
for(int j=0;j<3;j++)
{
static BYTE bits[]={NOT_TOP, NOT_MIDDLE, NOT_BOTTOM};
if (!(flags & bits[j]) && side.GetTexture(j) == picnum1)
{
side.SetTexture(j, picnum2);
}
}
}
}
if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0)
{
picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
for (auto &sec : level.sectors)
{
if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1)
sec.SetTexture(sector_t::floor, picnum2);
if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1)
sec.SetTexture(sector_t::ceiling, picnum2);
}
}
}
int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force)
{
PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type));
@ -5716,7 +5668,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
if (argCount >= 2)
{
PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1]));
if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup)))
if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup))
{
Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1]));
return 0;
@ -8352,9 +8304,14 @@ scriptwait:
break;
case PCD_REPLACETEXTURES:
ReplaceTextures (STACK(3), STACK(2), STACK(1));
{
const char *fromname = FBehavior::StaticLookupString(STACK(3));
const char *toname = FBehavior::StaticLookupString(STACK(2));
P_ReplaceTextures(fromname, toname, STACK(1));
sp -= 3;
break;
}
case PCD_SETLINEBLOCKING:
{
@ -9042,7 +8999,7 @@ scriptwait:
AInventory *item = activator->FindInventory (dyn_cast<PClassActor>(
PClass::FindClass (FBehavior::StaticLookupString (STACK(1)))));
if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon)))
if (item == NULL || !item->IsKindOf(NAME_Weapon))
{
STACK(1) = 0;
}
@ -9110,7 +9067,7 @@ scriptwait:
}
else
{
if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine")))
if (activator != nullptr && activator->IsKindOf("ScriptedMarine"))
{
SetMarineSprite(activator, type);
}
@ -9491,7 +9448,7 @@ scriptwait:
{
int tag = STACK(7);
FName playerclass_name = FBehavior::StaticLookupString(STACK(6));
PClassPlayerPawn *playerclass = dyn_cast<PClassPlayerPawn>(PClass::FindClass (playerclass_name));
auto playerclass = PClass::FindActor (playerclass_name);
FName monsterclass_name = FBehavior::StaticLookupString(STACK(5));
PClassActor *monsterclass = PClass::FindActor(monsterclass_name);
int duration = STACK(4);

View file

@ -913,7 +913,6 @@ protected:
static void ChangeFlat (int tag, int name, bool floorOrCeiling);
static int CountPlayers ();
static void SetLineTexture (int lineid, int side, int position, int name);
static void ReplaceTextures (int fromname, int toname, int flags);
static int DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force);
static int DoSpawn(int type, int x, int y, int z, int tid, int angle, bool force);
static bool DoCheckActorTexture(int tid, AActor *activator, int string, bool floor);

View file

@ -79,6 +79,7 @@
#include "thingdef.h"
#include "math/cmath.h"
#include "g_levellocals.h"
#include "r_utility.h"
AActor *SingleActorFromTID(int tid, AActor *defactor);
@ -2386,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS)
{
return false;
}
if (item->IsKindOf(PClass::FindActor(NAME_Health)))
if (item->IsKindOf(NAME_Health))
{
item->Amount *= amount;
}
@ -3122,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon)
AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls));
if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon))
{
if (self->player->ReadyWeapon != weaponitem)
{
@ -5011,7 +5012,7 @@ enum T_Flags
DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_STATE_DEF (teleport_state)
PARAM_STATE_ACTION_DEF (teleport_state)
PARAM_CLASS_DEF (target_type, ASpecialSpot)
PARAM_CLASS_DEF (fog_type, AActor)
PARAM_INT_DEF (flags)
@ -5448,7 +5449,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp)
PARAM_FLOAT_DEF(zofs)
PARAM_ANGLE_DEF(angle)
PARAM_INT_DEF(flags)
PARAM_STATE_DEF(success_state)
PARAM_STATE_ACTION_DEF(success_state)
PARAM_FLOAT_DEF(heightoffset)
PARAM_FLOAT_DEF(radiusoffset)
PARAM_ANGLE_DEF(pitch)
@ -5667,7 +5668,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
AInventory *gift = static_cast<AInventory *>(Spawn(item));
if (gift->IsKindOf(PClass::FindActor(NAME_Health)))
if (gift->IsKindOf(NAME_Health))
{
gift->Amount *= amount;
}
@ -6913,3 +6914,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetSize)
ACTION_RETURN_BOOL(true);
}
DEFINE_ACTION_FUNCTION(AActor, SetCamera)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_OBJECT(cam, AActor);
PARAM_BOOL_DEF(revert);
if (self->player == nullptr || self->player->mo != self) return 0;
if (cam == nullptr)
{
cam = self;
revert = false;
}
AActor *oldcamera = self->player->camera;
self->player->camera = cam;
if (revert) self->player->cheats |= CF_REVERTPLEASE;
if (oldcamera != cam)
{
R_ClearPastViewer(cam);
}
return 0;
}

View file

@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
node->ItemCheck.Resize(3);
for (j = 0; j < 3; ++j)
{
node->ItemCheck[j].Item = dyn_cast<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->ItemCheckNode = speech.Link;
@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheck.Resize(3);
for (k = 0; k < 3; ++k)
{
reply->ItemCheck[k].Item = dyn_cast<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->ItemCheckRequire.Clear();
@ -1331,7 +1335,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
{
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
if (reply->GiveType->IsDescendantOf(NAME_Weapon))
{
if (player->mo->FindInventory(reply->GiveType) != NULL)
{
@ -1357,7 +1361,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
}
}
if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter")))
if (reply->GiveType->IsDescendantOf("SlideshowStarter"))
gameaction = ga_slideshow;
}
else

View file

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

View file

@ -3227,7 +3227,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
if (dropamount > 0)
{
if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo)))
if (flagmask != 0 && inv->IsKindOf(NAME_Ammo))
{
inv->Amount = int(dropamount * dropammofactor);
inv->ItemFlags |= IF_IGNORESKILL;
@ -3253,7 +3253,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
inv->FloatVar("AmmoFactor") = dropammofactor;
inv->ItemFlags |= flagmask;
}
else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon)))
else if (inv->IsKindOf(NAME_Weapon))
{
// The same goes for ammo from a weapon.
static_cast<AWeapon *>(inv)->AmmoGive1 = int(static_cast<AWeapon *>(inv)->AmmoGive1 * dropammofactor);

View file

@ -442,4 +442,15 @@ enum EDmgFlags
//
bool P_AlignFlat (int linenum, int side, int fc);
enum ETexReplaceFlags
{
NOT_BOTTOM = 1,
NOT_MIDDLE = 2,
NOT_TOP = 4,
NOT_FLOOR = 8,
NOT_CEILING = 16
};
void P_ReplaceTextures(const char *fromname, const char *toname, int flags);
#endif // __P_LOCAL__

View file

@ -768,10 +768,12 @@ DEFINE_ACTION_FUNCTION(AActor, AddInventory)
//
//============================================================================
bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat)
bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat)
{
bool result = true;
if (type == nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL;
bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true;
@ -904,7 +906,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
// and infinite ammo is on
if (notakeinfinite &&
((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) &&
item->IsKindOf(PClass::FindActor(NAME_Ammo)))
item->IsKindOf(NAME_Ammo))
{
// Nothing to do here, except maybe res = false;? Would it make sense?
result = false;
@ -1147,10 +1149,12 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType)
//
//============================================================================
bool AActor::GiveAmmo (PClassInventory *type, int amount)
bool AActor::GiveAmmo (PClassActor *type, int amount)
{
if (type != NULL)
{
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
AInventory *item = static_cast<AInventory *>(Spawn (type));
if (item)
{
@ -1543,7 +1547,7 @@ bool AActor::IsVisibleToPlayer() const
bool visible = false;
for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i)
{
PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i];
auto cls = GetClass()->VisibleToPlayerClass[i];
if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls))
{
visible = true;
@ -3197,6 +3201,7 @@ void P_NightmareRespawn (AActor *mobj)
// spawn it
mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true);
mo->health = mobj->SpawnHealth();
if (z == ONFLOORZ)
{
@ -7488,7 +7493,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight)
}
DDropItem *AActor::GetDropItems() const
FDropItem *AActor::GetDropItems() const
{
return GetClass()->DropItems;
}
@ -8096,16 +8101,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors)
//
//----------------------------------------------------------------------------
IMPLEMENT_CLASS(DDropItem, false, true)
IMPLEMENT_POINTERS_START(DDropItem)
IMPLEMENT_POINTER(Next)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(DDropItem, Next)
DEFINE_FIELD(DDropItem, Name)
DEFINE_FIELD(DDropItem, Probability)
DEFINE_FIELD(DDropItem, Amount)
DEFINE_FIELD(FDropItem, Next)
DEFINE_FIELD(FDropItem, Name)
DEFINE_FIELD(FDropItem, Probability)
DEFINE_FIELD(FDropItem, Amount)
void PrintMiscActorInfo(AActor *query)
{

View file

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

View file

@ -2121,6 +2121,63 @@ bool P_AlignFlat (int linenum, int side, int fc)
return true;
}
//==========================================================================
//
// P_ReplaceTextures
//
//==========================================================================
void P_ReplaceTextures(const char *fromname, const char *toname, int flags)
{
FTextureID picnum1, picnum2;
if (fromname == nullptr)
return;
if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0)
{
picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
for (auto &side : level.sides)
{
for (int j = 0; j<3; j++)
{
static uint8_t bits[] = { NOT_TOP, NOT_MIDDLE, NOT_BOTTOM };
if (!(flags & bits[j]) && side.GetTexture(j) == picnum1)
{
side.SetTexture(j, picnum2);
}
}
}
}
if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0)
{
picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
for (auto &sec : level.sectors)
{
if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1)
sec.SetTexture(sector_t::floor, picnum2);
if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1)
sec.SetTexture(sector_t::ceiling, picnum2);
}
}
}
DEFINE_ACTION_FUNCTION(_TexMan, ReplaceTextures)
{
PARAM_PROLOGUE;
PARAM_STRING(from);
PARAM_STRING(to);
PARAM_INT(flags);
P_ReplaceTextures(from, to, flags);
return 0;
}
//==========================================================================
//
// P_BuildPolyBSP

View file

@ -1097,7 +1097,7 @@ public:
{
ld->alpha = 0.75;
}
if (strifetrans2 && ld->alpha == OPAQUE)
if (strifetrans2 && ld->alpha == 1.)
{
ld->alpha = 0.25;
}

View file

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

View file

@ -85,6 +85,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
P_PredictionLerpReset();
}
ColorSetList ColorSets;
PainFlashList PainFlashes;
struct PredictPos
{
int gametic;
@ -146,7 +149,7 @@ bool FPlayerClass::CheckSkin (int skin)
//
//===========================================================================
FString GetPrintableDisplayName(PClassPlayerPawn *cls)
FString GetPrintableDisplayName(PClassActor *cls)
{
// Fixme; This needs a decent way to access the string table without creating a mess.
// [RH] ????
@ -165,7 +168,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name)
Printf("Invalid player class '%s'\n", name);
return false;
}
else if (static_cast<PClassPlayerPawn *>(ti)->DisplayName.IsEmpty())
else if (ti->DisplayName.IsEmpty())
{
Printf ("Missing displayname for player class '%s'\n", name);
return false;
@ -184,7 +187,7 @@ void SetupPlayerClasses ()
if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i]))
{
newclass.Flags = 0;
newclass.Type = static_cast<PClassPlayerPawn *>(cls);
newclass.Type = cls;
if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU))
{
newclass.Flags |= PCF_NOMENU;
@ -212,7 +215,7 @@ CCMD (addplayerclass)
{
FPlayerClass newclass;
newclass.Type = static_cast<PClassPlayerPawn *>(ti);
newclass.Type = ti;
newclass.Flags = 0;
int arg = 2;
@ -535,61 +538,34 @@ int player_t::GetSpawnClass()
//===========================================================================
//
// PClassPlayerPawn
// EnumColorsets
//
// Only used by the menu so it doesn't really matter that it's a bit
// inefficient.
//
//===========================================================================
IMPLEMENT_CLASS(PClassPlayerPawn, false, false)
PClassPlayerPawn::PClassPlayerPawn()
{
for (size_t i = 0; i < countof(HexenArmor); ++i)
{
HexenArmor[i] = 0;
}
ColorRangeStart = 0;
ColorRangeEnd = 0;
}
void PClassPlayerPawn::DeriveData(PClass *newclass)
{
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
Super::DeriveData(newclass);
PClassPlayerPawn *newp = static_cast<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)
{
return *(const int *)a - *(const int *)b;
}
void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
void EnumColorSets(PClassActor *cls, TArray<int> *out)
{
out->Clear();
FPlayerColorSetMap::Iterator it(ColorSets);
FPlayerColorSetMap::Pair *pair;
TArray<int> deleteds;
while (it.NextPair(pair))
out->Clear();
for (int i = ColorSets.Size() - 1; i >= 0; i--)
{
out->Push(pair->Key);
if (std::get<0>(ColorSets[i])->IsAncestorOf(cls))
{
int v = std::get<1>(ColorSets[i]);
if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size())
{
if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v);
else out->Push(v);
}
}
}
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
}
@ -599,20 +575,41 @@ void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
//
//==========================================================================
bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const
FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum)
{
const PClassPlayerPawn *info = this;
while (info != NULL)
for (int i = ColorSets.Size() - 1; i >= 0; i--)
{
const PalEntry *flash = info->PainFlashes.CheckKey(type);
if (flash != NULL)
if (std::get<1>(ColorSets[i]) == setnum &&
std::get<0>(ColorSets[i])->IsAncestorOf(cls))
{
*color = *flash;
auto c = &std::get<2>(ColorSets[i]);
return c->Name != NAME_None ? c : nullptr;
}
}
return nullptr;
}
//==========================================================================
//
//
//==========================================================================
bool player_t::GetPainFlash(FName type, PalEntry *color) const
{
PClass *info = mo->GetClass();
// go backwards through the list and return the first item with a
// matching damage type for an ancestor of our class.
// This will always return the best fit because any parent class
// must be processed before its children.
for (int i = PainFlashes.Size() - 1; i >= 0; i--)
{
if (std::get<1>(PainFlashes[i]) == type &&
std::get<0>(PainFlashes[i])->IsAncestorOf(info))
{
*color = std::get<2>(PainFlashes[i]);
return true;
}
// Try parent class
info = dyn_cast<PClassPlayerPawn>(info->ParentClass);
}
return false;
}
@ -661,7 +658,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true)
IMPLEMENT_POINTERS_START(APlayerPawn)
IMPLEMENT_POINTER(InvFirst)
IMPLEMENT_POINTER(InvSel)
IMPLEMENT_POINTER(FlechetteType)
IMPLEMENT_POINTERS_END
void APlayerPawn::Serialize(FSerializer &arc)
@ -953,7 +949,7 @@ bool APlayerPawn::UseInventory (AInventory *item)
//
//===========================================================================
AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype)
{
AWeapon *bestMatch = NULL;
int bestOrder = INT_MAX;
@ -964,7 +960,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
// Find the best weapon the player has.
for (item = Inventory; item != NULL; item = item->Inventory)
{
if (!item->IsKindOf (RUNTIME_CLASS(AWeapon)))
if (!item->IsKindOf(NAME_Weapon))
continue;
weap = static_cast<AWeapon *> (item);
@ -1015,7 +1011,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
//
//===========================================================================
AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype)
AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype)
{
AWeapon *best = BestWeapon (ammotype);
@ -1043,7 +1039,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype)
//
//===========================================================================
void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype)
void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype)
{
if (!player->userinfo.GetNeverSwitch() &&
player->PendingWeapon == WP_NOCHANGE &&
@ -1062,7 +1058,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype)
DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch)
{
PARAM_SELF_PROLOGUE(APlayerPawn);
PARAM_OBJECT(ammotype, PClassInventory);
PARAM_OBJECT(ammotype, PClassActor);
self->CheckWeaponSwitch(ammotype);
return 0;
}
@ -1137,29 +1133,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
if ((dmflags & DF_COOP_LOSE_KEYS) &&
defitem == NULL &&
item->IsKindOf(PClass::FindActor(NAME_Key)))
item->IsKindOf(NAME_Key))
{
item->Destroy();
}
else if ((dmflags & DF_COOP_LOSE_WEAPONS) &&
defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AWeapon)))
item->IsKindOf(NAME_Weapon))
{
item->Destroy();
}
else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
item->IsKindOf(PClass::FindActor(NAME_Armor)))
item->IsKindOf(NAME_Armor))
{
if (defitem == NULL)
{
item->Destroy();
}
else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor)))
else if (item->IsKindOf(NAME_BasicArmor))
{
item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
item->Amount = defitem->Amount;
}
else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor)))
else if (item->IsKindOf(NAME_HexenArmor))
{
double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
@ -1168,12 +1164,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
}
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
defitem == NULL &&
item->IsKindOf(PClass::FindActor(NAME_PowerupGiver)))
item->IsKindOf(NAME_PowerupGiver))
{
item->Destroy();
}
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
item->IsKindOf(PClass::FindActor(NAME_Ammo)))
item->IsKindOf(NAME_Ammo))
{
if (defitem == NULL)
{
@ -1230,8 +1226,8 @@ const char *APlayerPawn::GetSoundClass() const
}
// [GRB]
PClassPlayerPawn *pclass = GetClass();
return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player";
auto pclass = GetClass();
return SoundClass != NAME_None? SoundClass.GetChars() : "player";
}
//===========================================================================
@ -1368,16 +1364,16 @@ void APlayerPawn::GiveDefaultInventory ()
// HexenArmor must always be the first item in the inventory because
// it provides player class based protection that should not affect
// any other protection item.
PClassPlayerPawn *myclass = GetClass();
auto myclass = GetClass();
GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
auto harmor = FindInventory(NAME_HexenArmor);
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
Slots[4] = myclass->HexenArmor[0];
Slots[4] = HexenArmor[0];
for (int i = 0; i < 4; ++i)
{
SlotsIncrement[i] = myclass->HexenArmor[i + 1];
SlotsIncrement[i] = HexenArmor[i + 1];
}
// BasicArmor must come right after that. It should not affect any
@ -1388,7 +1384,7 @@ void APlayerPawn::GiveDefaultInventory ()
AddInventory (barmor);
// Now add the items from the DECORATE definition
DDropItem *di = GetDropItems();
auto di = GetDropItems();
while (di)
{
@ -1413,7 +1409,7 @@ void APlayerPawn::GiveDefaultInventory ()
item = static_cast<AInventory *>(Spawn(ti));
item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here
item->Amount = di->Amount;
if (item->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (item->IsKindOf(NAME_Weapon))
{
// To allow better control any weapon is emptied of
// ammo before being given to the player.
@ -1433,7 +1429,7 @@ void APlayerPawn::GiveDefaultInventory ()
item = NULL;
}
}
if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) &&
if (item != NULL && item->IsKindOf(NAME_Weapon) &&
static_cast<AWeapon*>(item)->CheckAmmo(AWeapon::EitherFire, false))
{
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item);
@ -1518,7 +1514,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
AInventory *item;
// kgDROP - start - modified copy from a_action.cpp
DDropItem *di = weap->GetDropItems();
auto di = weap->GetDropItems();
if (di != NULL)
{
@ -1537,7 +1533,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
weap->SpawnState != ::GetDefault<AActor>()->SpawnState)
{
item = P_DropItem (this, weap->GetClass(), -1, 256);
if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)))
if (item != NULL && item->IsKindOf(NAME_Weapon))
{
if (weap->AmmoGive1 && weap->Ammo1)
{
@ -1710,9 +1706,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop)
player_t *player;
// [GRB] Parameterized version
if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk")))
if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk"))
{
spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull"));
spawntype = PClass::FindActor("BloodySkull");
if (spawntype == NULL)
return 0;
}
@ -3249,18 +3245,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade)
DEFINE_FIELD(APlayerPawn, ViewBob)
DEFINE_FIELD(APlayerPawn, FullHeight)
DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType)
DEFINE_FIELD(PClassPlayerPawn, DisplayName)
DEFINE_FIELD(PClassPlayerPawn, SoundClass)
DEFINE_FIELD(PClassPlayerPawn, Face)
DEFINE_FIELD(PClassPlayerPawn, Portrait)
DEFINE_FIELD(PClassPlayerPawn, Slot)
DEFINE_FIELD(PClassPlayerPawn, InvulMode)
DEFINE_FIELD(PClassPlayerPawn, HexenArmor)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd)
DEFINE_FIELD(PClassPlayerPawn, ColorSets)
DEFINE_FIELD(PClassPlayerPawn, PainFlashes)
DEFINE_FIELD(APlayerPawn, HealingRadiusType)
DEFINE_FIELD(APlayerPawn, SoundClass)
DEFINE_FIELD(APlayerPawn, Face)
DEFINE_FIELD(APlayerPawn, Portrait)
DEFINE_FIELD(APlayerPawn, Slot)
DEFINE_FIELD(APlayerPawn, InvulMode)
DEFINE_FIELD(APlayerPawn, HexenArmor)
DEFINE_FIELD(APlayerPawn, ColorRangeStart)
DEFINE_FIELD(APlayerPawn, ColorRangeEnd)
DEFINE_FIELD(PClassActor, DisplayName)
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)

View file

@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor)
unsigned i = level.sectorPortals.Reserve(1);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY;
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY;
level.sectorPortals[i].mSkybox = actor;
level.sectorPortals[i].mDestination = actor->Sector;
return i;

View file

@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha)
switch (type)
{
case STYLEALPHA_Zero: return 0;
case STYLEALPHA_One: return OPAQUE;
case STYLEALPHA_One: return 1.;
case STYLEALPHA_Src: return alpha;
case STYLEALPHA_InvSrc: return 1. - alpha;
default: return 0;

View file

@ -44,10 +44,6 @@
enum
{
OPAQUE = 65536,
TRANSLUC25 = (OPAQUE / 4),
TRANSLUC33 = (OPAQUE / 3),
TRANSLUC66 = ((OPAQUE * 2) / 3),
TRANSLUC75 = ((OPAQUE * 3) / 4),
};
// Legacy render styles

View file

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

View file

@ -338,8 +338,6 @@ void R_Init ()
{
atterm (R_Shutdown);
StartScreen->Progress();
V_InitFonts();
StartScreen->Progress();
// Colormap init moved back to InitPalette()
//R_InitColormaps ();

View file

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

View file

@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
{
tag = ATAG_STATE;
}
else if (value.Type->GetLoadOp() == OP_LO)
else if (value.Type->GetLoadOp() != OP_LP)
{
tag = ATAG_OBJECT;
}
@ -1420,6 +1420,76 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build)
return to;
}
//==========================================================================
//
//
//
//==========================================================================
FxFontCast::FxFontCast(FxExpression *x)
: FxExpression(EFX_FontCast, x->ScriptPosition)
{
basex = x;
ValueType = TypeSound;
}
//==========================================================================
//
//
//
//==========================================================================
FxFontCast::~FxFontCast()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxFontCast::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
if (basex->ValueType == TypeFont)
{
FxExpression *x = basex;
basex = nullptr;
delete this;
return x;
}
// This intentionally does not convert non-constants.
// The sole reason for this cast is to allow passing both font pointers and string constants to printing functions and have the font names checked at compile time.
else if ((basex->ValueType == TypeString || basex->ValueType == TypeName) && basex->isConstant())
{
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FFont *font = V_GetFont(constval.GetString());
// Font must exist. Most internal functions working with fonts do not like null pointers.
// If checking is needed scripts will have to call Font.GetFont themselves.
if (font == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Unknown font '%s'", constval.GetString().GetChars());
delete this;
return nullptr;
}
FxExpression *x = new FxConstant(font, ScriptPosition);
delete this;
return x;
}
else
{
ScriptPosition.Message(MSG_ERROR, "Cannot convert to font");
delete this;
return nullptr;
}
}
//==========================================================================
//
// generic type cast operator
@ -1649,6 +1719,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
{
goto basereturn;
}
else if (ValueType == TypeFont)
{
FxExpression *x = new FxFontCast(basex);
x = x->Resolve(ctx);
basex = nullptr;
delete this;
return x;
}
// todo: pointers to class objects.
// All other types are only compatible to themselves and have already been handled above by the equality check.
// Anything that falls through here is not compatible and must print an error.
@ -6278,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
ob.Free(build);
ExpEmit meta(build, REGT_POINTER);
build->Emit(OP_META, meta.RegNum, ob.RegNum);
build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
return meta;
}
@ -6290,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
//==========================================================================
FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
: FxExpression(EFX_GlobalVariable, pos)
: FxMemberBase(EFX_GlobalVariable, mem, pos)
{
membervar = mem;
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
}
//==========================================================================
@ -6470,11 +6545,8 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
//==========================================================================
FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos)
: FxExpression(EFX_StackVariable, pos)
: FxMemberBase(EFX_StackVariable, new PField(NAME_None, type, 0, offset), pos)
{
membervar = new PField(NAME_None, type, 0, offset);
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
}
//==========================================================================
@ -6486,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition
FxStackVariable::~FxStackVariable()
{
// Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap.
membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar;
}
//==========================================================================
//
//
//==========================================================================
void FxStackVariable::ReplaceField(PField *newfield)
{
membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar;
membervar = newfield;
}
//==========================================================================
//
//
@ -6573,14 +6632,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build)
//
//
//==========================================================================
FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p)
:FxExpression(type, p), membervar(f)
{
}
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
: FxExpression(EFX_StructMember, pos)
: FxMemberBase(EFX_StructMember, mem, pos)
{
classx = x;
membervar = mem;
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
}
//==========================================================================
@ -6652,35 +6713,13 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)))
{
// if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember)
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStructMember *>(classx)->membervar;
auto parentfield = static_cast<FxMemberBase *>(classx)->membervar;
// PFields are garbage collected so this will be automatically taken care of later.
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue;
static_cast<FxStructMember *>(classx)->membervar = newfield;
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = classx->Resolve(ctx);
classx = nullptr;
return x;
}
else if (classx->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(classx)->membervar;
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue;
static_cast<FxGlobalVariable *>(classx)->membervar = newfield;
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = classx->Resolve(ctx);
classx = nullptr;
return x;
}
else if (classx->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStackVariable *>(classx)->membervar;
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue;
static_cast<FxStackVariable *>(classx)->ReplaceField(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.
auto x = classx->Resolve(ctx);
classx = nullptr;
@ -6868,33 +6907,41 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
return nullptr;
}
PArray *arraytype = dyn_cast<PArray>(Array->ValueType);
if (arraytype == nullptr)
PArray *arraytype = nullptr;
PType *elementtype = nullptr;
if (Array->IsDynamicArray())
{
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
{
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
delete this;
return nullptr;
}
arraytype = static_cast<PArray*>(ptype->PointedType);
PDynArray *darraytype = static_cast<PDynArray*>(Array->ValueType);
elementtype = darraytype->ElementType;
Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged.
arrayispointer = true;
}
else
{
arraytype = dyn_cast<PArray>(Array->ValueType);
if (arraytype == nullptr)
{
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
{
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
delete this;
return nullptr;
}
arraytype = static_cast<PArray*>(ptype->PointedType);
arrayispointer = true;
}
elementtype = arraytype->ElementType;
}
if (Array->IsResizableArray())
{
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
SizeAddr = parentfield->Offset + parentfield->Type->Align;
}
else if (Array->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
SizeAddr = parentfield->Offset + parentfield->Type->Align;
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
SizeAddr = parentfield->Offset + sizeof(void*);
}
else
{
@ -6903,54 +6950,32 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
return nullptr;
}
}
else if (index->isConstant())
// constant indices can only be resolved at compile time for statically sized arrays.
else if (index->isConstant() && arraytype != nullptr && !arrayispointer)
{
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
if (indexval >= arraytype->ElementCount && !Array->IsResizableArray())
if (indexval >= arraytype->ElementCount)
{
ScriptPosition.Message(MSG_ERROR, "Array index out of bounds");
delete this;
return nullptr;
}
if (!arrayispointer)
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
{
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
{
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
// PFields are garbage collected so this will be automatically taken care of later.
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxStructMember *>(Array)->membervar = newfield;
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
else if (Array->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxGlobalVariable *>(Array)->membervar = newfield;
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
else if (Array->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStackVariable *>(Array)->membervar;
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxStackVariable *>(Array)->ReplaceField(newfield);
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
// PFields are garbage collected so this will be automatically taken care of later.
auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxMemberBase *>(Array)->membervar = newfield;
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
}
ValueType = arraytype->ElementType;
ValueType = elementtype;
if (!Array->RequestAddress(ctx, &AddressWritable))
{
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array.");
@ -6989,17 +7014,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
{
static_cast<FxStructMember *>(Array)->membervar = f;
static_cast<FxStructMember *>(Array)->AddressRequested = false;
}
else if (Array->ExprType == EFX_GlobalVariable)
{
static_cast<FxGlobalVariable *>(Array)->membervar = f;
static_cast<FxGlobalVariable *>(Array)->AddressRequested = false;
}
static_cast<FxMemberBase *>(Array)->membervar = f;
static_cast<FxMemberBase *>(Array)->AddressRequested = false;
Array->ValueType = TypeUInt32;
bound = Array->Emit(build);
}
@ -7726,6 +7742,70 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
// same for String methods. It also uses a hidden struct type to define them.
Self->ValueType = TypeStringStruct;
}
else if (Self->IsDynamicArray())
{
if (MethodName == NAME_Size)
{
FxExpression *x = new FxMemberIdentifier(Self, NAME_Size, ScriptPosition); // todo: obfuscate the name to prevent direct access.
Self = nullptr;
delete this;
return x->Resolve(ctx);
}
else
{
auto elementType = static_cast<PDynArray*>(Self->ValueType)->ElementType;
Self->ValueType = static_cast<PDynArray*>(Self->ValueType)->BackingType;
// this requires some added type checks for the passed types.
for (auto &a : ArgList)
{
a = a->Resolve(ctx);
if (a == nullptr)
{
delete this;
return nullptr;
}
if (a->IsDynamicArray())
{
// Copy and Move must turn their parameter into a pointer to the backing struct type.
auto backingtype = static_cast<PDynArray*>(a->ValueType)->BackingType;
if (elementType != static_cast<PDynArray*>(a->ValueType)->ElementType)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
delete this;
return nullptr;
}
bool writable;
if (!a->RequestAddress(ctx, &writable))
{
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array variable");
delete this;
return nullptr;
}
a->ValueType = NewPointer(backingtype);
// Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.)
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable)
{
auto member = static_cast<FxMemberBase*>(Self);
auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset);
member->membervar = newfield;
}
}
else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
{
// the only case which must be checked up front is for pointer arrays receiving a new element.
// Since there is only one native backing class it uses a neutral void pointer as its argument,
// meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here.
if (a->ValueType != elementType)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), elementType->DescriptiveName());
delete this;
return nullptr;
}
}
}
}
}
else if (Self->IsArray())
{
if (MethodName == NAME_Size)
@ -7748,19 +7828,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
else
{
// Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator.
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember)
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_GlobalVariable)
{
auto member = static_cast<FxStructMember*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield;
Self = nullptr;
delete this;
member->ValueType = TypeUInt32;
return member;
}
else if (Self->ExprType == EFX_GlobalVariable)
{
auto member = static_cast<FxGlobalVariable*>(Self);
auto member = static_cast<FxMemberBase*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield;
Self = nullptr;
@ -7793,7 +7863,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
return x->Resolve(ctx);
}
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)))
@ -8791,7 +8861,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
op.Free(build);
}
ExpEmit to(build, REGT_POINTER);
build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
return to;
}
@ -8863,7 +8933,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build)
build->Emit(OP_LKP, to.RegNum, op.RegNum);
op = to;
}
build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
return to;
}
@ -10600,8 +10670,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
case REGT_POINTER:
{
bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)));
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC));
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC));
break;
}
case REGT_STRING:
@ -10741,7 +10810,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build)
{
TArray<void*> cvalues;
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetPointer());
StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC);
StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC);
break;
}
}

View file

@ -294,6 +294,7 @@ enum EFxType
EFX_StrLen,
EFX_ColorLiteral,
EFX_GetDefaultByType,
EFX_FontCast,
EFX_COUNT
};
@ -332,6 +333,7 @@ public:
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form.
bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); }
virtual ExpEmit Emit(VMFunctionBuilder *build);
void EmitStatement(VMFunctionBuilder *build);
@ -488,6 +490,13 @@ public:
isresolved = true;
}
FxConstant(FFont *state, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
{
value.pointer = state;
ValueType = value.Type = TypeFont;
isresolved = true;
}
FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
{
value.pointer = nullptr;
@ -664,6 +673,18 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
class FxFontCast : public FxExpression
{
FxExpression *basex;
public:
FxFontCast(FxExpression *x);
~FxFontCast();
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// FxTypeCast
@ -1293,19 +1314,30 @@ public:
};
//==========================================================================
//
// FxMemberBase
//
//==========================================================================
class FxMemberBase : public FxExpression
{
public:
PField *membervar;
bool AddressRequested = false;
bool AddressWritable = true;
FxMemberBase(EFxType type, PField *f, const FScriptPosition &p);
};
//==========================================================================
//
// FxGlobalVariaböe
//
//==========================================================================
class FxGlobalVariable : public FxExpression
class FxGlobalVariable : public FxMemberBase
{
public:
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxGlobalVariable(PField*, const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable);
@ -1322,19 +1354,17 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxClassMember
//
//==========================================================================
class FxStructMember : public FxExpression
class FxStructMember : public FxMemberBase
{
public:
FxExpression *classx;
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
~FxStructMember();
@ -1382,16 +1412,11 @@ public:
//
//==========================================================================
class FxStackVariable : public FxExpression
class FxStackVariable : public FxMemberBase
{
public:
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxStackVariable(PType *type, int offset, const FScriptPosition&);
~FxStackVariable();
void ReplaceField(PField *newfield);
FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable);
ExpEmit Emit(VMFunctionBuilder *build);

View file

@ -1,10 +1,10 @@
/*
** dynarray.cpp
**
** Compiler backend / code generation for dynamic arrays
** internal data types for dynamic arrays
**
**---------------------------------------------------------------------------
** Copyright 2016 Christoph Oelckers
** Copyright 2016-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without

View file

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

View file

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

View file

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

View file

@ -49,7 +49,7 @@
#include "v_palette.h"
#include "doomerrors.h"
#include "i_system.h"
#include "codegeneration/codegen.h"
#include "backend/codegen.h"
#include "w_wad.h"
#include "v_video.h"
#include "version.h"
@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns)
}
try
{
info->Finalize(bag.statedef);
GetDefaultByType(info)->Finalize(bag.statedef);
}
catch (CRecoverableError &err)
{

View file

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

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

View file

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

View file

@ -1136,4 +1136,40 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret);
(*self) += s;
return 0;
}
}
DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_UINT(pos);
PARAM_UINT(len);
FString s = self->Mid(pos, len);
ACTION_RETURN_STRING(s);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_INT((int)self->Len());
}
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
DEFINE_ACTION_FUNCTION(FStringStruct, CharAt)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(pos);
int slen = (int)self->Len();
if (pos < 0 || pos >= slen)
ACTION_RETURN_STRING("");
ACTION_RETURN_STRING(FString((*self)[pos]));
}
DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(pos);
int slen = (int)self->Len();
if (pos < 0 || pos >= slen)
ACTION_RETURN_INT(0);
ACTION_RETURN_INT((*self)[pos]);
}

View file

@ -66,9 +66,10 @@
#include "teaminfo.h"
#include "v_video.h"
#include "r_data/colormaps.h"
#include "vmbuilder.h"
#include "backend/vmbuilder.h"
#include "a_keys.h"
#include "g_levellocals.h"
#include "d_player.h"
//==========================================================================
//
@ -97,7 +98,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool
}
static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
{
return static_cast<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)
{
@ -560,7 +561,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
return;
}
memcpy ((void *)defaults, (void *)GetDefault<AActor>(), sizeof(AActor));
*defaults = *GetDefault<AActor>();
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
}
@ -920,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
bag.DropItemList = NULL;
}
DDropItem *di = new DDropItem;
FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
di->Name = type;
di->Probability = 255;
@ -938,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
}
di->Next = bag.DropItemList;
bag.DropItemList = di;
GC::WriteBarrier(di);
}
//==========================================================================
@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor)
//==========================================================================
DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
{
static_cast<PClassInventory*>(info)->RestrictedToPlayerClass.Clear();
static_cast<PClassActor*>(info)->RestrictedToPlayerClass.Clear();
for(int i = 0;i < PROP_PARM_COUNT;++i)
{
PROP_STRING_PARM(n, i);
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)
{
static_cast<PClassInventory*>(info)->ForbiddenToPlayerClass.Clear();
static_cast<PClassActor*>(info)->ForbiddenToPlayerClass.Clear();
for(int i = 0;i < PROP_PARM_COUNT;++i)
{
PROP_STRING_PARM(n, i);
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')
{
defaults->Icon.SetNull();
icon.SetNull();
}
else
{
defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
if (!defaults->Icon.isValid())
icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
if (!icon.isValid())
{
// Don't print warnings if the item is for another game or if this is a shareware IWAD.
// Strife's teaser doesn't contain all the icon graphics of the full game.
if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) &&
if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) &&
!(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
{
bag.ScriptPosition.Message(MSG_WARNING,
"Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars());
"Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars());
}
}
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(icon, S, Inventory)
{
PROP_STRING_PARM(i, 0);
SetIcon(defaults->Icon, bag, i);
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(althudicon, S, Inventory)
{
PROP_STRING_PARM(i, 0);
SetIcon(defaults->AltHUDIcon, bag, i);
}
//==========================================================================
//
//==========================================================================
@ -1801,8 +1817,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory)));
static_cast<PClassInventory *>(info)->PickupMsg = str;
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->PickupMsg = str;
}
//==========================================================================
@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
{
PROP_INT_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory)));
static_cast<PClassInventory *>(info)->GiveQuest = i;
defaults->GiveQuest = i;
}
//==========================================================================
@ -2065,8 +2080,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon)
DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
{
PROP_INT_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon)));
static_cast<PClassWeapon *>(info)->SlotNumber = i;
defaults->SlotNumber = i;
}
//==========================================================================
@ -2075,8 +2089,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
{
PROP_DOUBLE_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon)));
static_cast<PClassWeapon *>(info)->SlotPriority = int(i*65536);
defaults->SlotPriority = int(i*65536);
}
//==========================================================================
@ -2098,9 +2111,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
int alpha;
PalEntry *pBlendColor;
bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver));
bool isgiver = info->IsDescendantOf(NAME_PowerupGiver);
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver)
if (info->IsDescendantOf(NAME_Powerup) || isgiver)
{
pBlendColor = &defaults->ColorVar(NAME_BlendColor);
}
@ -2150,7 +2163,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
{
PalEntry BlendColor;
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
{
I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
return;
@ -2185,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
{
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
{
I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n");
return;
@ -2200,7 +2213,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory)
{
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
{
I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n");
return;
@ -2216,7 +2229,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
{
PROP_STRING_PARM(str, 0);
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
{
I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n");
return;
@ -2263,8 +2276,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->DisplayName = str;
info->DisplayName = str;
}
//==========================================================================
@ -2276,8 +2288,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn)
FString tmp = str;
tmp.ReplaceChars (' ', '_');
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->SoundClass = tmp;
defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None;
}
//==========================================================================
@ -2288,21 +2299,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
PROP_STRING_PARM(str, 0);
FString tmp = str;
tmp.ToUpper();
bool valid = (tmp.Len() == 3 &&
(((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) &&
(((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) &&
(((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9')))
);
if (!valid)
if (tmp.Len() == 0) defaults->Face = NAME_None;
else
{
bag.ScriptPosition.Message(MSG_OPTERROR,
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
tmp.GetChars(), info->TypeName.GetChars ());
tmp.ToUpper();
bool valid = (tmp.Len() == 3 &&
(((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) &&
(((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) &&
(((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9')))
);
if (!valid)
{
bag.ScriptPosition.Message(MSG_OPTERROR,
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
tmp.GetChars(), info->TypeName.GetChars());
}
defaults->Face = tmp;
}
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->Face = tmp;
}
//==========================================================================
@ -2316,9 +2329,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn)
if (start > end)
swapvalues (start, end);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->ColorRangeStart = start;
static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end;
defaults->ColorRangeStart = start;
defaults->ColorRangeEnd = end;
}
//==========================================================================
@ -2373,8 +2385,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl
}
else
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
ColorSets.Push(std::make_tuple(info, setnum, color));
}
}
@ -2400,8 +2411,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
}
else if (color.Lump >= 0)
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
ColorSets.Push(std::make_tuple(info, setnum, color));
}
}
@ -2418,8 +2428,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
}
else
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->ColorSets.Remove(setnum);
FPlayerColorSet color;
memset(&color, 0, sizeof(color));
ColorSets.Push(std::make_tuple(info, setnum, color));
}
}
@ -2653,8 +2664,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn)
PROP_STRING_PARM(type, 3);
color.a = BYTE(255 * clamp<double>(a, 0.f, 1.f));
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->PainFlashes.Insert(type, color);
PainFlashes.Push(std::make_tuple(info, type, color));
}
}
@ -2674,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
bag.DropItemList = NULL;
}
DDropItem *di = new DDropItem;
FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
di->Name = str;
di->Probability = 255;
@ -2686,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
}
di->Next = bag.DropItemList;
bag.DropItemList = di;
GC::WriteBarrier(di);
}
//==========================================================================
@ -2695,8 +2704,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->InvulMode = str;
defaults->InvulMode = str;
}
//==========================================================================
@ -2705,8 +2713,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->HealingRadiusType = str;
defaults->HealingRadiusType = str;
}
//==========================================================================
@ -2714,11 +2721,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
for (int i = 0; i < 5; i++)
{
PROP_DOUBLE_PARM(val, i);
static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val;
defaults->HexenArmor[i] = val;
}
}
@ -2727,9 +2733,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
PROP_STRING_PARM(val, 0);
static_cast<PClassPlayerPawn *>(info)->Portrait = val;
defaults->Portrait = val;
}
//==========================================================================
@ -2739,7 +2744,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
{
PROP_INT_PARM(slot, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
if (slot < 0 || slot > 9)
{
I_Error("Slot must be between 0 and 9.");
@ -2753,7 +2757,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
PROP_STRING_PARM(str, i);
weapons << ' ' << str;
}
static_cast<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 "cmdlib.h"
#include "doomerrors.h"
#include "memarena.h"
extern FMemArena ClassDataAllocator;
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function
@ -693,10 +696,8 @@ do_double: if (inexact)
}
};
class VMFunction : public DObject
class VMFunction
{
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
HAS_OBJECT_POINTERS;
public:
bool Native;
bool Final = false; // cannot be overridden
@ -709,7 +710,29 @@ public:
class PPrototype *Proto;
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {}
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL)
{
AllFunctions.Push(this);
}
virtual ~VMFunction() {}
void *operator new(size_t size)
{
return ClassDataAllocator.Alloc(size);
}
void operator delete(void *block) {}
void operator delete[](void *block) {}
static void DeleteAll()
{
for (auto f : AllFunctions)
{
f->~VMFunction();
}
AllFunctions.Clear();
}
static TArray<VMFunction *> AllFunctions;
protected:
};
// VM frame layout:
@ -838,11 +861,9 @@ struct FStatementInfo
class VMScriptFunction : public VMFunction
{
DECLARE_CLASS(VMScriptFunction, VMFunction);
public:
VMScriptFunction(FName name=NAME_None);
~VMScriptFunction();
size_t PropagateMark();
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
@ -910,7 +931,6 @@ private:
class VMNativeFunction : public VMFunction
{
DECLARE_CLASS(VMNativeFunction, VMFunction);
public:
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
@ -997,6 +1017,7 @@ void NullParam(const char *varname);
// For required parameters.
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i;
#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i;
#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i);
#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i;
@ -1040,6 +1061,7 @@ void NullParam(const char *varname);
#define PARAM_PROLOGUE int paramnum = -1;
#define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x)
#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x)
#define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x)
#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x)
#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x)

View file

@ -347,6 +347,17 @@ begin:
GETADDR(PA,RC,X_WRITE_NIL);
*(void **)ptr = reg.a[B];
NEXTOP;
OP(SO):
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
GETADDR(PA,KC,X_WRITE_NIL);
*(void **)ptr = reg.a[B];
GC::WriteBarrier((DObject*)*(void **)ptr);
NEXTOP;
OP(SO_R):
ASSERTA(a); ASSERTA(B); ASSERTD(C);
GETADDR(PA,RC,X_WRITE_NIL);
GC::WriteBarrier((DObject*)*(void **)ptr);
NEXTOP;
OP(SV2):
ASSERTA(a); ASSERTF(B+1); ASSERTKD(C);
GETADDR(PA,KC,X_WRITE_NIL);

View file

@ -42,14 +42,9 @@ cycle_t VMCycles[10];
int VMCalls[10];
IMPLEMENT_CLASS(VMException, false, false)
IMPLEMENT_CLASS(VMFunction, true, true)
IMPLEMENT_POINTERS_START(VMFunction)
IMPLEMENT_POINTER(Proto)
IMPLEMENT_POINTERS_END
TArray<VMFunction *> VMFunction::AllFunctions;
IMPLEMENT_CLASS(VMScriptFunction, false, false)
IMPLEMENT_CLASS(VMNativeFunction, false, false)
VMScriptFunction::VMScriptFunction(FName name)
{
@ -87,7 +82,6 @@ VMScriptFunction::~VMScriptFunction()
KonstS[i].~FString();
}
}
M_Free(Code);
}
}
@ -100,7 +94,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
assert(numkonsts >= 0 && numkonsts <= 65535);
assert(numkonsta >= 0 && numkonsta <= 65535);
assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
void *mem = M_Malloc(numops * sizeof(VMOP) +
void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) +
numkonstd * sizeof(int) +
numkonstf * sizeof(double) +
numkonsts * sizeof(FString) +
@ -166,24 +160,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
NumKonstA = numkonsta;
}
size_t VMScriptFunction::PropagateMark()
{
if (KonstA != NULL)
{
FVoidObj *konsta = KonstA;
VM_UBYTE *atag = KonstATags();
for (int count = NumKonstA; count > 0; --count)
{
if (*atag++ == ATAG_OBJECT)
{
GC::Mark(konsta->o);
}
konsta++;
}
}
return NumKonstA * sizeof(void *) + Super::PropagateMark();
}
void VMScriptFunction::InitExtra(void *addr)
{
char *caddr = (char*)addr;

View file

@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string
xx(SS_R, ss, RPRSRI, NOP, 0, 0),
xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
xx(SP_R, sp, RPRPRI, NOP, 0, 0),
xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types
xx(SO_R, sp, RPRPRI, NOP, 0, 0),
xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2
xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3

View file

@ -48,7 +48,7 @@
#include "p_lnspec.h"
#include "i_system.h"
#include "gdtoa.h"
#include "vmbuilder.h"
#include "backend/vmbuilder.h"
#include "version.h"
static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
case AST_DynArrayType:
if (allowarraytypes)
{
Error(field, "%s: Dynamic array types not implemented yet", name.GetChars());
auto atype = static_cast<ZCC_DynArrayType *>(ztype);
retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false));
auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true);
if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1)
{
Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName());
}
else
{
retval = NewDynArray(ftype);
}
break;
}
break;
@ -2440,19 +2447,6 @@ void ZCCCompiler::CompileStates()
continue;
}
// Same here, hack in the DVMObject as they weren't in the list originally
// TODO: process them in a non hackish way obviously
if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false)
{
auto vmtype = static_cast<PClassActor *>(c->Type()->ParentClass);
if (vmtype->StateList == nullptr)
{
FStateDefinitions vmstates;
vmstates.MakeStateDefines(dyn_cast<PClassActor>(vmtype->ParentClass));
vmtype->Finalize(vmstates);
}
}
FString statename; // The state builder wants the label as one complete string, not separated into tokens.
FStateDefinitions statedef;
statedef.MakeStateDefines(dyn_cast<PClassActor>(c->Type()->ParentClass));
@ -2651,7 +2645,7 @@ void ZCCCompiler::CompileStates()
}
try
{
static_cast<PClassActor *>(c->Type())->Finalize(statedef);
GetDefaultByType(c->Type())->Finalize(statedef);
}
catch (CRecoverableError &err)
{

View file

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

View file

@ -2187,17 +2187,17 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
{
if (arc.isWriting())
{
const char *n = font->GetName();
return arc.StringPtr(key, n);
FName n = font->GetName();
return arc(key, n);
}
else
{
const char *n;
arc.StringPtr(key, n);
FName n;
arc(key, n);
font = V_GetFont(n);
if (font == nullptr)
{
Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n);
Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n.GetChars());
font = SmallFont;
}
return arc;

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, FFont *&font, FFont **def);
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, PClassPlayerPawn *&clst, PClassPlayerPawn **def)
{
return Serialize(arc, key, (PClassActor *&)clst, (PClassActor **)def);
}
FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode);
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def)
{

View file

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

View file

@ -124,12 +124,12 @@ static int PalFromRGB(uint32 rgb)
void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...)
{
va_list tags;
va_start(tags, tags_first);
Va_List tags;
va_start(tags.list, tags_first);
DrawParms parms;
bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false);
va_end(tags);
va_end(tags.list);
if (!res)
{
return;
@ -137,7 +137,7 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ..
DrawTextureParms(img, parms);
}
static int ListGetInt(VMVa_List &tags);
int ListGetInt(VMVa_List &tags);
void DCanvas::DrawTexture(FTexture *img, double x, double y, VMVa_List &args)
{
@ -452,37 +452,37 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double
return false;
}
static void ListEnd(va_list &tags)
static void ListEnd(Va_List &tags)
{
va_end(tags);
va_end(tags.list);
}
static int ListGetInt(va_list &tags)
static int ListGetInt(Va_List &tags)
{
return va_arg(tags, int);
return va_arg(tags.list, int);
}
static inline double ListGetDouble(va_list &tags)
static inline double ListGetDouble(Va_List &tags)
{
return va_arg(tags, double);
return va_arg(tags.list, double);
}
// These two options are only being used by the D3D version of the HUD weapon drawer, they serve no purpose anywhere else.
static inline FSpecialColormap * ListGetSpecialColormap(va_list &tags)
static inline FSpecialColormap * ListGetSpecialColormap(Va_List &tags)
{
return va_arg(tags, FSpecialColormap *);
return va_arg(tags.list, FSpecialColormap *);
}
static inline FColormapStyle * ListGetColormapStyle(va_list &tags)
static inline FColormapStyle * ListGetColormapStyle(Va_List &tags)
{
return va_arg(tags, FColormapStyle *);
return va_arg(tags.list, FColormapStyle *);
}
static void ListEnd(VMVa_List &tags)
{
}
static int ListGetInt(VMVa_List &tags)
int ListGetInt(VMVa_List &tags)
{
if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_INT)
{
@ -941,7 +941,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag,
}
// explicitly instantiate both versions for v_text.cpp.
template bool DCanvas::ParseDrawTextureTags<va_list>(FTexture *img, double x, double y, DWORD tag, va_list& tags, DrawParms *parms, bool fortext) const;
template bool DCanvas::ParseDrawTextureTags<Va_List>(FTexture *img, double x, double y, DWORD tag, Va_List& tags, DrawParms *parms, bool fortext) const;
template bool DCanvas::ParseDrawTextureTags<VMVa_List>(FTexture *img, double x, double y, DWORD tag, VMVa_List& tags, DrawParms *parms, bool fortext) const;
void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h,

View file

@ -94,6 +94,7 @@ The FON2 header is followed by variable length data:
#include "r_data/r_translate.h"
#include "colormatcher.h"
#include "v_palette.h"
#include "v_text.h"
// MACROS ------------------------------------------------------------------
@ -340,6 +341,14 @@ FFont *V_GetFont(const char *name)
return font;
}
DEFINE_ACTION_FUNCTION(FFont, GetFont)
{
PARAM_PROLOGUE;
PARAM_NAME(name);
ACTION_RETURN_POINTER(V_GetFont(name.GetChars()));
}
//==========================================================================
//
// FFont :: FFont
@ -366,7 +375,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
LastChar = first + count - 1;
FontHeight = 0;
GlobalKerning = false;
Name = copystring (name);
FontName = name;
Next = FirstFont;
FirstFont = this;
Cursor = '_';
@ -478,11 +487,6 @@ FFont::~FFont ()
delete[] PatchRemap;
PatchRemap = NULL;
}
if (Name)
{
delete[] Name;
Name = NULL;
}
FFont **prev = &FirstFont;
FFont *font = *prev;
@ -508,27 +512,26 @@ FFont::~FFont ()
//
//==========================================================================
FFont *FFont::FindFont (const char *name)
FFont *FFont::FindFont (FName name)
{
if (name == NULL)
if (name == NAME_None)
{
return NULL;
return nullptr;
}
FFont *font = FirstFont;
while (font != NULL)
while (font != nullptr)
{
if (stricmp (font->Name, name) == 0)
break;
if (font->FontName == name) return font;
font = font->Next;
}
return font;
return nullptr;
}
DEFINE_ACTION_FUNCTION(FFont, FindFont)
{
PARAM_PROLOGUE;
PARAM_STRING(name);
PARAM_NAME(name);
ACTION_RETURN_POINTER(FFont::FindFont(name));
}
@ -843,6 +846,65 @@ int FFont::GetCharWidth (int code) const
return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove;
}
DEFINE_ACTION_FUNCTION(FFont, GetCharWidth)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_INT(code);
ACTION_RETURN_INT(self->GetCharWidth(code));
}
//==========================================================================
//
// Find string width using this font
//
//==========================================================================
int FFont::StringWidth(const BYTE *string) const
{
int w = 0;
int maxw = 0;
while (*string)
{
if (*string == TEXTCOLOR_ESCAPE)
{
++string;
if (*string == '[')
{
while (*string != '\0' && *string != ']')
{
++string;
}
}
if (*string != '\0')
{
++string;
}
continue;
}
else if (*string == '\n')
{
if (w > maxw)
maxw = w;
w = 0;
++string;
}
else
{
w += GetCharWidth(*string++) + GlobalKerning;
}
}
return MAX(maxw, w);
}
DEFINE_ACTION_FUNCTION(FFont, StringWidth)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_STRING(str);
ACTION_RETURN_INT(self->StringWidth(str));
}
//==========================================================================
//
// FFont :: LoadTranslations
@ -935,7 +997,7 @@ FFont::FFont (int lump)
Lump = lump;
Chars = NULL;
PatchRemap = NULL;
Name = NULL;
FontName = NAME_None;
Cursor = '_';
}
@ -951,7 +1013,7 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
{
assert(lump >= 0);
Name = copystring (name);
FontName = name;
FMemLump data1 = Wads.ReadLump (lump);
const BYTE *data = (const BYTE *)data1.GetMem();
@ -1189,7 +1251,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
if (destSize < 0)
{
i += FirstChar;
I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, Name);
I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars());
}
}
@ -1491,7 +1553,7 @@ FSinglePicFont::FSinglePicFont(const char *picname) :
FTexture *pic = TexMan[picnum];
Name = copystring(picname);
FontName = picname;
FontHeight = pic->GetScaledHeight();
SpaceWidth = pic->GetScaledWidth();
GlobalKerning = 0;
@ -1903,7 +1965,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
memcpy(this->notranslate, notranslate, 256*sizeof(bool));
Name = copystring(name);
FontName = name;
Chars = new CharData[count];
charlumps = new FTexture*[count];
PatchRemap = new BYTE[256];
@ -2490,6 +2552,13 @@ EColorRange V_FindFontColor (FName name)
return CR_UNTRANSLATED;
}
DEFINE_ACTION_FUNCTION(FFont, FindFontColor)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_NAME(code);
ACTION_RETURN_INT((int)V_FindFontColor(code));
}
//==========================================================================
//
// V_LogColorFromColorRange
@ -2664,12 +2733,3 @@ void V_ClearFonts()
SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL;
}
void V_RetranslateFonts()
{
FFont *font = FFont::FirstFont;
while(font)
{
font->LoadTranslations();
font = font->Next;
}
}

View file

@ -88,9 +88,9 @@ public:
int GetDefaultKerning () const { return GlobalKerning; }
virtual void LoadTranslations();
void Preload() const;
const char *GetName() const { return Name; }
FName GetName() const { return FontName; }
static FFont *FindFont (const char *fontname);
static FFont *FindFont(FName fontname);
static void StaticPreloadFonts();
// Return width of string in pixels (unscaled)
@ -127,14 +127,13 @@ protected:
BYTE *PatchRemap;
int Lump;
char *Name;
FName FontName;
FFont *Next;
static FFont *FirstFont;
friend struct FontsDeleter;
friend void V_ClearFonts();
friend void V_RetranslateFonts();
};
@ -147,6 +146,5 @@ PalEntry V_LogColorFromColorRange (EColorRange range);
EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor);
FFont *V_GetFont(const char *);
void V_InitFontColors();
void V_RetranslateFonts();
#endif //__V_FONT_H__

View file

@ -47,11 +47,16 @@
#include "doomstat.h"
#include "templates.h"
int ListGetInt(VMVa_List &tags);
//==========================================================================
//
// DrawChar
//
// Write a single character using the given font
//
//==========================================================================
void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...)
{
if (font == NULL)
@ -66,10 +71,10 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch
if (NULL != (pic = font->GetChar (character, &dummy)))
{
DrawParms parms;
va_list tags;
va_start(tags, tag_first);
Va_List tags;
va_start(tags.list, tag_first);
bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false);
va_end(tags);
va_end(tags.list);
if (!res)
{
return;
@ -79,37 +84,61 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch
}
}
void DCanvas::DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args)
{
if (font == NULL)
return;
if (normalcolor >= NumTextColors)
normalcolor = CR_UNTRANSLATED;
FTexture *pic;
int dummy;
if (NULL != (pic = font->GetChar(character, &dummy)))
{
DrawParms parms;
uint32_t tag = ListGetInt(args);
bool res = ParseDrawTextureTags(pic, x, y, tag, args, &parms, false);
if (!res) return;
parms.remap = font->GetColorTranslation((EColorRange)normalcolor);
DrawTextureParms(pic, parms);
}
}
DEFINE_ACTION_FUNCTION(_Screen, DrawChar)
{
PARAM_PROLOGUE;
PARAM_POINTER(font, FFont);
PARAM_INT(cr);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_INT(chr);
VMVa_List args = { param + 5, 0, numparam - 5 };
screen->DrawChar(font, cr, x, y, chr, args);
return 0;
}
//==========================================================================
//
// DrawText
//
// Write a string using the given font
//
void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...)
//==========================================================================
void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms)
{
int w;
const BYTE *ch;
int c;
int cx;
int cy;
double cx;
double cy;
int boldcolor;
FRemapTable *range;
int kerning;
FTexture *pic;
DrawParms parms;
va_list tags;
if (font == NULL || string == NULL)
return;
va_start(tags, tag_first);
bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true);
va_end(tags);
if (!res)
{
return;
}
if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
parms.celly *= parms.scaley;
@ -118,15 +147,15 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
normalcolor = CR_UNTRANSLATED;
boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1;
range = font->GetColorTranslation ((EColorRange)normalcolor);
range = font->GetColorTranslation((EColorRange)normalcolor);
kerning = font->GetDefaultKerning ();
kerning = font->GetDefaultKerning();
ch = (const BYTE *)string;
cx = x;
cy = y;
while ((const char *)ch - string < parms.maxstrlen)
{
c = *ch++;
@ -135,14 +164,14 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
if (c == TEXTCOLOR_ESCAPE)
{
EColorRange newcolor = V_ParseFontColor (ch, normalcolor, boldcolor);
EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor);
if (newcolor != CR_UNDEFINED)
{
range = font->GetColorTranslation (newcolor);
range = font->GetColorTranslation(newcolor);
}
continue;
}
if (c == '\n')
{
cx = x;
@ -150,7 +179,7 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
continue;
}
if (NULL != (pic = font->GetChar (c, &w)))
if (NULL != (pic = font->GetChar(c, &w)))
{
parms.remap = range;
SetTextureParms(&parms, pic, cx, cy);
@ -166,52 +195,61 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
}
}
//
// Find string width using this font
//
int FFont::StringWidth (const BYTE *string) const
void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...)
{
int w = 0;
int maxw = 0;
while (*string)
Va_List tags;
DrawParms parms;
if (font == NULL || string == NULL)
return;
va_start(tags.list, tag_first);
bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true);
va_end(tags.list);
if (!res)
{
if (*string == TEXTCOLOR_ESCAPE)
{
++string;
if (*string == '[')
{
while (*string != '\0' && *string != ']')
{
++string;
}
}
if (*string != '\0')
{
++string;
}
continue;
}
else if (*string == '\n')
{
if (w > maxw)
maxw = w;
w = 0;
++string;
}
else
{
w += GetCharWidth (*string++) + GlobalKerning;
}
return;
}
return MAX (maxw, w);
DrawTextCommon(font, normalcolor, x, y, string, parms);
}
void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args)
{
DrawParms parms;
if (font == NULL || string == NULL)
return;
uint32_t tag = ListGetInt(args);
bool res = ParseDrawTextureTags(nullptr, 0, 0, tag, args, &parms, true);
if (!res)
{
return;
}
DrawTextCommon(font, normalcolor, x, y, string, parms);
}
DEFINE_ACTION_FUNCTION(_Screen, DrawText)
{
PARAM_PROLOGUE;
PARAM_POINTER(font, FFont);
PARAM_INT(cr);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_STRING(chr);
VMVa_List args = { param + 5, 0, numparam - 5 };
screen->DrawText(font, cr, x, y, chr, args);
return 0;
}
//==========================================================================
//
// Break long lines of text into multiple lines no longer than maxwidth pixels
//
//==========================================================================
static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor)
{
if (!linecolor.IsEmpty())
@ -223,20 +261,19 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B
line->Width = font->StringWidth (line->Text);
}
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor)
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor, unsigned int *count)
{
FBrokenLines lines[128]; // Support up to 128 lines (should be plenty)
TArray<FBrokenLines> Lines(128);
const BYTE *space = NULL, *start = string;
size_t i, ii;
int c, w, nw;
FString lastcolor, linecolor;
bool lastWasSpace = false;
int kerning = font->GetDefaultKerning ();
i = w = 0;
w = 0;
while ( (c = *string++) && i < countof(lines) )
while ( (c = *string++) )
{
if (c == TEXTCOLOR_ESCAPE)
{
@ -283,14 +320,14 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool
if (!space)
space = string - 1;
breakit (&lines[i], font, start, space, linecolor);
auto index = Lines.Reserve(1);
breakit (&Lines[index], font, start, space, linecolor);
if (c == '\n' && !preservecolor)
{
lastcolor = ""; // Why, oh why, did I do it like this?
}
linecolor = lastcolor;
i++;
w = 0;
lastWasSpace = false;
start = space;
@ -312,7 +349,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool
}
// String here is pointing one character after the '\0'
if (i < countof(lines) && --string - start >= 1)
if (--string - start >= 1)
{
const BYTE *s = start;
@ -321,20 +358,25 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool
// If there is any non-white space in the remainder of the string, add it.
if (!isspace (*s++))
{
breakit (&lines[i++], font, start, string, linecolor);
auto i = Lines.Reserve(1);
breakit (&Lines[i], font, start, string, linecolor);
break;
}
}
}
// Make a copy of the broken lines and return them
FBrokenLines *broken = new FBrokenLines[i+1];
FBrokenLines *broken = new FBrokenLines[Lines.Size() + 1];
for (ii = 0; ii < i; ++ii)
for (unsigned ii = 0; ii < Lines.Size(); ++ii)
{
broken[ii] = lines[ii];
broken[ii] = Lines[ii];
}
broken[Lines.Size()].Width = -1;
if (count != nullptr)
{
*count = Lines.Size();
}
broken[ii].Width = -1;
return broken;
}
@ -346,3 +388,56 @@ void V_FreeBrokenLines (FBrokenLines *lines)
delete[] lines;
}
}
class DBrokenLines : public DObject
{
DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject)
public:
FBrokenLines *mBroken;
unsigned int mCount;
DBrokenLines(FBrokenLines *broken, unsigned int count)
{
mBroken = broken;
mCount = count;
}
void OnDestroy() override
{
V_FreeBrokenLines(mBroken);
}
};
IMPLEMENT_CLASS(DBrokenLines, true, false);
DEFINE_ACTION_FUNCTION(DBrokenLines, Count)
{
PARAM_SELF_PROLOGUE(DBrokenLines);
ACTION_RETURN_INT(self->mCount);
}
DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth)
{
PARAM_SELF_PROLOGUE(DBrokenLines);
PARAM_INT(index);
ACTION_RETURN_INT((unsigned)index >= self->mCount? -1 : self->mBroken[index].Width);
}
DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt)
{
PARAM_SELF_PROLOGUE(DBrokenLines);
PARAM_INT(index);
ACTION_RETURN_STRING((unsigned)index >= self->mCount? -1 : self->mBroken[index].Text);
}
DEFINE_ACTION_FUNCTION(FFont, BreakLines)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_STRING(text);
PARAM_INT(maxwidth);
unsigned int count;
FBrokenLines *broken = V_BreakLines(self, maxwidth, text, true, &count);
ACTION_RETURN_OBJECT(new DBrokenLines(broken, count));
}

View file

@ -75,11 +75,11 @@ struct FBrokenLines
#define TEXTCOLOR_CHAT "\034*"
#define TEXTCOLOR_TEAMCHAT "\034!"
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false);
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false, unsigned int *count = nullptr);
void V_FreeBrokenLines (FBrokenLines *lines);
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false)
{ return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); }
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false)
{ return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor); }
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false, unsigned int *count = nullptr)
{ return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor, count); }
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr)
{ return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor, count); }
#endif //__V_TEXT_H__

View file

@ -1397,7 +1397,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real
cy1 = MAX(cheight / designheight, 1);
cx2 = MAX(realwidth / designwidth, 1);
cy2 = MAX(realheight / designheight, 1);
if (abs(cx1 - cy1) <= abs(cx2 - cy2))
if (abs(cx1 - cy1) <= abs(cx2 - cy2) || cx1 >= 4)
{ // e.g. 640x360 looks better with this.
*cleanx = cx1;
*cleany = cy1;

View file

@ -177,6 +177,11 @@ struct DrawParms
bool virtBottom;
};
struct Va_List
{
va_list list;
};
struct VMVa_List
{
VMValue *args;
@ -269,8 +274,10 @@ public:
#undef DrawText // See WinUser.h for the definition of DrawText as a macro
#endif
// 2D Text drawing
void DrawText (FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...);
void DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...);
void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...);
void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args);
void DrawChar(FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...);
void DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args);
protected:
BYTE *Buffer;
@ -279,6 +286,8 @@ protected:
int Pitch;
int LockCount;
void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms);
bool ClipBox (int &left, int &top, int &width, int &height, const BYTE *&src, const int srcpitch) const;
void DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags) = delete;
virtual void DrawTextureParms(FTexture *img, DrawParms &parms);

View file

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

View file

@ -1417,6 +1417,9 @@ TXT_KILLED_ORACLE = "You've Killed The Oracle!";
TXT_KILLED_MACIL = "You Killed Macil!";
TXT_KILLED_LOREMASTER = "You've Killed the Loremaster!";
TXT_YOUFOOL = "You Fool! You've set off the alarm.";
TXT_YOUREDEAD = "You're dead! You set off the alarm.";
// Strife pickup messages
TXT_METALARMOR = "You picked up the Metal Armor.";

View file

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

Some files were not shown because too many files have changed in this diff Show more