mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-26 05:41:39 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
# 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:
commit
cf06a6ae91
107 changed files with 2717 additions and 2216 deletions
|
@ -622,7 +622,7 @@ file( GLOB HEADER_FILES
|
||||||
sound/*.h
|
sound/*.h
|
||||||
textures/*.h
|
textures/*.h
|
||||||
scripting/*.h
|
scripting/*.h
|
||||||
scripting/codegeneration/*.h
|
scripting/backend/*.h
|
||||||
scripting/decorate/*.h
|
scripting/decorate/*.h
|
||||||
scripting/zscript/*.h
|
scripting/zscript/*.h
|
||||||
scripting/vm/*.h
|
scripting/vm/*.h
|
||||||
|
@ -1016,17 +1016,18 @@ set (PCH_SOURCES
|
||||||
r_data/voxels.cpp
|
r_data/voxels.cpp
|
||||||
r_data/renderstyle.cpp
|
r_data/renderstyle.cpp
|
||||||
r_data/r_interpolate.cpp
|
r_data/r_interpolate.cpp
|
||||||
|
scripting/symbols.cpp
|
||||||
scripting/thingdef.cpp
|
scripting/thingdef.cpp
|
||||||
scripting/thingdef_data.cpp
|
scripting/thingdef_data.cpp
|
||||||
scripting/thingdef_properties.cpp
|
scripting/thingdef_properties.cpp
|
||||||
scripting/codegeneration/codegen.cpp
|
scripting/backend/codegen.cpp
|
||||||
scripting/codegeneration/dynarrays.cpp
|
scripting/backend/dynarrays.cpp
|
||||||
|
scripting/backend/vmbuilder.cpp
|
||||||
|
scripting/backend/vmdisasm.cpp
|
||||||
scripting/decorate/olddecorations.cpp
|
scripting/decorate/olddecorations.cpp
|
||||||
scripting/decorate/thingdef_exp.cpp
|
scripting/decorate/thingdef_exp.cpp
|
||||||
scripting/decorate/thingdef_parse.cpp
|
scripting/decorate/thingdef_parse.cpp
|
||||||
scripting/decorate/thingdef_states.cpp
|
scripting/decorate/thingdef_states.cpp
|
||||||
scripting/vm/vmbuilder.cpp
|
|
||||||
scripting/vm/vmdisasm.cpp
|
|
||||||
scripting/vm/vmexec.cpp
|
scripting/vm/vmexec.cpp
|
||||||
scripting/vm/vmframe.cpp
|
scripting/vm/vmframe.cpp
|
||||||
scripting/zscript/ast.cpp
|
scripting/zscript/ast.cpp
|
||||||
|
@ -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\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+")
|
||||||
source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
|
source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
|
||||||
source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
|
source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
|
||||||
source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+")
|
source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+")
|
||||||
source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
|
source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
|
||||||
source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+")
|
source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+")
|
||||||
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
|
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
|
||||||
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
|
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
|
||||||
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")
|
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")
|
||||||
|
|
16
src/actor.h
16
src/actor.h
|
@ -573,12 +573,9 @@ struct FLinkContext
|
||||||
msecnode_t *render_list = nullptr;
|
msecnode_t *render_list = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DDropItem : public DObject
|
struct FDropItem
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(DDropItem, DObject)
|
FDropItem *Next;
|
||||||
HAS_OBJECT_POINTERS
|
|
||||||
public:
|
|
||||||
DDropItem *Next;
|
|
||||||
FName Name;
|
FName Name;
|
||||||
int Probability;
|
int Probability;
|
||||||
int Amount;
|
int Amount;
|
||||||
|
@ -597,6 +594,7 @@ public:
|
||||||
AActor &operator= (const AActor &other);
|
AActor &operator= (const AActor &other);
|
||||||
~AActor ();
|
~AActor ();
|
||||||
|
|
||||||
|
virtual void Finalize(FStateDefinitions &statedef);
|
||||||
virtual void OnDestroy() override;
|
virtual void OnDestroy() override;
|
||||||
virtual void Serialize(FSerializer &arc) override;
|
virtual void Serialize(FSerializer &arc) override;
|
||||||
virtual void PostSerialize() override;
|
virtual void PostSerialize() override;
|
||||||
|
@ -610,7 +608,7 @@ public:
|
||||||
return (AActor *)(this->GetClass()->Defaults);
|
return (AActor *)(this->GetClass()->Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
DDropItem *GetDropItems() const;
|
FDropItem *GetDropItems() const;
|
||||||
|
|
||||||
// Return true if the monster should use a missile attack, false for melee
|
// Return true if the monster should use a missile attack, false for melee
|
||||||
bool SuggestMissileAttack (double dist);
|
bool SuggestMissileAttack (double dist);
|
||||||
|
@ -699,7 +697,7 @@ public:
|
||||||
|
|
||||||
// Give an item to the actor and pick it up.
|
// Give an item to the actor and pick it up.
|
||||||
// Returns true if the item pickup succeeded.
|
// Returns true if the item pickup succeeded.
|
||||||
bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false);
|
bool GiveInventory (PClassActor *type, int amount, bool givecheat = false);
|
||||||
|
|
||||||
// Removes the item from the inventory list.
|
// Removes the item from the inventory list.
|
||||||
virtual void RemoveInventory (AInventory *item);
|
virtual void RemoveInventory (AInventory *item);
|
||||||
|
@ -736,7 +734,7 @@ public:
|
||||||
AInventory *FirstInv ();
|
AInventory *FirstInv ();
|
||||||
|
|
||||||
// Tries to give the actor some ammo.
|
// Tries to give the actor some ammo.
|
||||||
bool GiveAmmo (PClassInventory *type, int amount);
|
bool GiveAmmo (PClassActor *type, int amount);
|
||||||
|
|
||||||
// Destroys all the inventory the actor is holding.
|
// Destroys all the inventory the actor is holding.
|
||||||
void DestroyAllInventory ();
|
void DestroyAllInventory ();
|
||||||
|
@ -973,7 +971,7 @@ public:
|
||||||
{
|
{
|
||||||
SetOrigin(Pos() + vel, true);
|
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)
|
void SetOrigin(const DVector3 & npos, bool moving)
|
||||||
{
|
{
|
||||||
SetOrigin(npos.X, npos.Y, npos.Z, moving);
|
SetOrigin(npos.X, npos.Y, npos.Z, moving);
|
||||||
|
|
|
@ -2858,7 +2858,7 @@ void AM_drawThings ()
|
||||||
// Find the key's own color.
|
// Find the key's own color.
|
||||||
// Only works correctly if single-key locks have lower numbers than any-key locks.
|
// Only works correctly if single-key locks have lower numbers than any-key locks.
|
||||||
// That is the case for all default keys, however.
|
// That is the case for all default keys, however.
|
||||||
if (t->IsKindOf(PClass::FindActor(NAME_Key)))
|
if (t->IsKindOf(NAME_Key))
|
||||||
{
|
{
|
||||||
if (G_SkillProperty(SKILLP_EasyKey))
|
if (G_SkillProperty(SKILLP_EasyKey))
|
||||||
{
|
{
|
||||||
|
|
|
@ -263,7 +263,7 @@ void InitBotStuff()
|
||||||
for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++)
|
for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++)
|
||||||
{
|
{
|
||||||
const PClass *cls = PClass::FindClass(botinits[i].type);
|
const PClass *cls = PClass::FindClass(botinits[i].type);
|
||||||
if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (cls != NULL && cls->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
AWeapon *w = (AWeapon*)GetDefaultByType(cls);
|
AWeapon *w = (AWeapon*)GetDefaultByType(cls);
|
||||||
if (w != NULL)
|
if (w != NULL)
|
||||||
|
|
|
@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item)
|
||||||
//if(pos && !bglobal.thingvis[pos->id][item->id]) continue;
|
//if(pos && !bglobal.thingvis[pos->id][item->id]) continue;
|
||||||
// if (item->IsKindOf (RUNTIME_CLASS(AArtifact)))
|
// if (item->IsKindOf (RUNTIME_CLASS(AArtifact)))
|
||||||
// return; // don't know how to use artifacts
|
// return; // don't know how to use artifacts
|
||||||
if (item->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
if (item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
// FIXME
|
// FIXME
|
||||||
AWeapon *heldWeapon;
|
AWeapon *heldWeapon;
|
||||||
|
|
|
@ -1210,7 +1210,7 @@ static void PrintSecretString(const char *string, bool thislevel)
|
||||||
{
|
{
|
||||||
while ((actor = it.Next()))
|
while ((actor = it.Next()))
|
||||||
{
|
{
|
||||||
if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue;
|
if (!actor->IsKindOf("SecretTrigger")) continue;
|
||||||
foundone = true;
|
foundone = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1752,11 +1752,10 @@ void C_MidPrintBold (FFont *font, const char *msg)
|
||||||
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
|
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_STRING(font);
|
PARAM_POINTER_NOT_NULL(fnt, FFont);
|
||||||
PARAM_STRING(text);
|
PARAM_STRING(text);
|
||||||
PARAM_BOOL_DEF(bold);
|
PARAM_BOOL_DEF(bold);
|
||||||
|
|
||||||
FFont *fnt = FFont::FindFont(font);
|
|
||||||
const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars();
|
const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars();
|
||||||
if (!bold) C_MidPrint(fnt, txt);
|
if (!bold) C_MidPrint(fnt, txt);
|
||||||
else C_MidPrintBold(fnt, txt);
|
else C_MidPrintBold(fnt, txt);
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
#include "vmbuilder.h"
|
#include "backend/vmbuilder.h"
|
||||||
|
|
||||||
// [SO] Just the way Randy said to do it :)
|
// [SO] Just the way Randy said to do it :)
|
||||||
// [RH] Made this CVAR_SERVERINFO
|
// [RH] Made this CVAR_SERVERINFO
|
||||||
|
@ -1658,7 +1658,7 @@ static int PatchWeapon (int weapNum)
|
||||||
{
|
{
|
||||||
val = 5;
|
val = 5;
|
||||||
}
|
}
|
||||||
info->AmmoType1 = (PClassInventory*)AmmoNames[val];
|
info->AmmoType1 = AmmoNames[val];
|
||||||
if (info->AmmoType1 != NULL)
|
if (info->AmmoType1 != NULL)
|
||||||
{
|
{
|
||||||
info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2;
|
info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2;
|
||||||
|
@ -1983,7 +1983,7 @@ static int PatchMisc (int dummy)
|
||||||
player->health = deh.StartHealth;
|
player->health = deh.StartHealth;
|
||||||
|
|
||||||
// Hm... I'm not sure that this is the right way to change this info...
|
// Hm... I'm not sure that this is the right way to change this info...
|
||||||
DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems;
|
FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems;
|
||||||
while (di != NULL)
|
while (di != NULL)
|
||||||
{
|
{
|
||||||
if (di->Name == NAME_Clip)
|
if (di->Name == NAME_Clip)
|
||||||
|
@ -2916,7 +2916,7 @@ static bool LoadDehSupp ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto cls = PClass::FindActor(sc.String);
|
auto cls = PClass::FindActor(sc.String);
|
||||||
if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo)))
|
if (cls == NULL || !cls->IsDescendantOf(NAME_Ammo))
|
||||||
{
|
{
|
||||||
sc.ScriptError("Unknown ammo type '%s'", sc.String);
|
sc.ScriptError("Unknown ammo type '%s'", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -2934,7 +2934,7 @@ static bool LoadDehSupp ()
|
||||||
{
|
{
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
PClass *cls = PClass::FindClass(sc.String);
|
PClass *cls = PClass::FindClass(sc.String);
|
||||||
if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (cls == NULL || !cls->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
sc.ScriptError("Unknown weapon type '%s'", sc.String);
|
sc.ScriptError("Unknown weapon type '%s'", sc.String);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2468,6 +2468,9 @@ void D_DoomMain (void)
|
||||||
TexMan.Init();
|
TexMan.Init();
|
||||||
C_InitConback();
|
C_InitConback();
|
||||||
|
|
||||||
|
StartScreen->Progress();
|
||||||
|
V_InitFonts();
|
||||||
|
|
||||||
// [CW] Parse any TEAMINFO lumps.
|
// [CW] Parse any TEAMINFO lumps.
|
||||||
if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n");
|
if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n");
|
||||||
TeamLibrary.ParseTeamInfo ();
|
TeamLibrary.ParseTeamInfo ();
|
||||||
|
@ -2705,6 +2708,8 @@ void D_DoomMain (void)
|
||||||
|
|
||||||
// delete all data that cannot be left until reinitialization
|
// delete all data that cannot be left until reinitialization
|
||||||
V_ClearFonts(); // must clear global font pointers
|
V_ClearFonts(); // must clear global font pointers
|
||||||
|
ColorSets.Clear();
|
||||||
|
PainFlashes.Clear();
|
||||||
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
|
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
|
||||||
gameinfo.~gameinfo_t();
|
gameinfo.~gameinfo_t();
|
||||||
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
||||||
|
@ -2715,7 +2720,7 @@ void D_DoomMain (void)
|
||||||
|
|
||||||
GC::FullGC(); // clean up before taking down the object list.
|
GC::FullGC(); // clean up before taking down the object list.
|
||||||
|
|
||||||
// Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions.
|
// Delete the reference to the VM functions here which were deleted and will be recreated after the restart.
|
||||||
FAutoSegIterator probe(ARegHead, ARegTail);
|
FAutoSegIterator probe(ARegHead, ARegTail);
|
||||||
while (*++probe != NULL)
|
while (*++probe != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2540,7 +2540,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
case DEM_MORPHEX:
|
case DEM_MORPHEX:
|
||||||
{
|
{
|
||||||
s = ReadString (stream);
|
s = ReadString (stream);
|
||||||
const char *msg = cht_Morph (players + player, dyn_cast<PClassPlayerPawn>(PClass::FindClass (s)), false);
|
const char *msg = cht_Morph (players + player, PClass::FindActor (s), false);
|
||||||
if (player == consoleplayer)
|
if (player == consoleplayer)
|
||||||
{
|
{
|
||||||
Printf ("%s\n", *msg != '\0' ? msg : "Morph failed.");
|
Printf ("%s\n", *msg != '\0' ? msg : "Morph failed.");
|
||||||
|
@ -2639,7 +2639,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
}
|
}
|
||||||
for(i = 0; i < count; ++i)
|
for(i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
PClassWeapon *wpn = Net_ReadWeapon(stream);
|
PClassActor *wpn = Net_ReadWeapon(stream);
|
||||||
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
|
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2648,7 +2648,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
case DEM_ADDSLOT:
|
case DEM_ADDSLOT:
|
||||||
{
|
{
|
||||||
int slot = ReadByte(stream);
|
int slot = ReadByte(stream);
|
||||||
PClassWeapon *wpn = Net_ReadWeapon(stream);
|
PClassActor *wpn = Net_ReadWeapon(stream);
|
||||||
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
|
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2656,7 +2656,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
case DEM_ADDSLOTDEFAULT:
|
case DEM_ADDSLOTDEFAULT:
|
||||||
{
|
{
|
||||||
int slot = ReadByte(stream);
|
int slot = ReadByte(stream);
|
||||||
PClassWeapon *wpn = Net_ReadWeapon(stream);
|
PClassActor *wpn = Net_ReadWeapon(stream);
|
||||||
players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer);
|
players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i)
|
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i)
|
||||||
{
|
{
|
||||||
PClassPlayerPawn *type = PlayerClasses[i].Type;
|
auto type = PlayerClasses[i].Type;
|
||||||
|
|
||||||
if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0)
|
if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0)
|
||||||
{
|
{
|
||||||
|
@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet
|
||||||
|
|
||||||
if (players[player].mo != NULL)
|
if (players[player].mo != NULL)
|
||||||
{
|
{
|
||||||
colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet());
|
colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet());
|
||||||
}
|
}
|
||||||
if (colorset != NULL)
|
if (colorset != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,39 +67,17 @@ struct FPlayerColorSet
|
||||||
ExtraRange Extra[6];
|
ExtraRange Extra[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
|
typedef TArray<std::tuple<PClass*, FName, PalEntry>> PainFlashList;
|
||||||
typedef TMap<FName, PalEntry> PainFlashList;
|
typedef TArray<std::tuple<PClass*, int, FPlayerColorSet>> ColorSetList;
|
||||||
|
|
||||||
class PClassPlayerPawn : public PClassActor
|
extern PainFlashList PainFlashes;
|
||||||
{
|
extern ColorSetList ColorSets;
|
||||||
DECLARE_CLASS(PClassPlayerPawn, PClassActor);
|
|
||||||
protected:
|
|
||||||
public:
|
|
||||||
PClassPlayerPawn();
|
|
||||||
virtual void DeriveData(PClass *newclass);
|
|
||||||
void EnumColorSets(TArray<int> *out);
|
|
||||||
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
|
|
||||||
void SetPainFlash(FName type, PalEntry color);
|
|
||||||
bool GetPainFlash(FName type, PalEntry *color) const;
|
|
||||||
|
|
||||||
FString DisplayName; // Display name (used in menus, etc.)
|
FString GetPrintableDisplayName(PClassActor *cls);
|
||||||
FString SoundClass; // Sound class
|
|
||||||
FString Face; // Doom status bar face (when used)
|
|
||||||
FString Portrait;
|
|
||||||
FString Slot[10];
|
|
||||||
FName InvulMode;
|
|
||||||
FName HealingRadiusType;
|
|
||||||
double HexenArmor[5];
|
|
||||||
BYTE ColorRangeStart; // Skin color range
|
|
||||||
BYTE ColorRangeEnd;
|
|
||||||
FPlayerColorSetMap ColorSets;
|
|
||||||
PainFlashList PainFlashes;
|
|
||||||
};
|
|
||||||
FString GetPrintableDisplayName(PClassPlayerPawn *cls);
|
|
||||||
|
|
||||||
class APlayerPawn : public AActor
|
class APlayerPawn : public AActor
|
||||||
{
|
{
|
||||||
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
|
DECLARE_CLASS(APlayerPawn, AActor)
|
||||||
HAS_OBJECT_POINTERS
|
HAS_OBJECT_POINTERS
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -120,9 +98,9 @@ public:
|
||||||
void TweakSpeeds (double &forwardmove, double &sidemove);
|
void TweakSpeeds (double &forwardmove, double &sidemove);
|
||||||
void MorphPlayerThink ();
|
void MorphPlayerThink ();
|
||||||
void ActivateMorphWeapon ();
|
void ActivateMorphWeapon ();
|
||||||
AWeapon *PickNewWeapon (PClassInventory *ammotype);
|
AWeapon *PickNewWeapon (PClassActor *ammotype);
|
||||||
AWeapon *BestWeapon (PClassInventory *ammotype);
|
AWeapon *BestWeapon (PClassActor *ammotype);
|
||||||
void CheckWeaponSwitch(PClassInventory *ammotype);
|
void CheckWeaponSwitch(PClassActor *ammotype);
|
||||||
void GiveDeathmatchInventory ();
|
void GiveDeathmatchInventory ();
|
||||||
void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
|
void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
|
||||||
|
|
||||||
|
@ -177,6 +155,17 @@ public:
|
||||||
// [SP] ViewBob Multiplier
|
// [SP] ViewBob Multiplier
|
||||||
double ViewBob;
|
double ViewBob;
|
||||||
|
|
||||||
|
// Former class properties that were moved into the object to get rid of the meta class.
|
||||||
|
FName SoundClass; // Sound class
|
||||||
|
FName Face; // Doom status bar face (when used)
|
||||||
|
FName Portrait;
|
||||||
|
FName Slot[10];
|
||||||
|
FName InvulMode;
|
||||||
|
FName HealingRadiusType;
|
||||||
|
double HexenArmor[5];
|
||||||
|
BYTE ColorRangeStart; // Skin color range
|
||||||
|
BYTE ColorRangeEnd;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -273,7 +262,7 @@ public:
|
||||||
|
|
||||||
bool CheckSkin (int skin);
|
bool CheckSkin (int skin);
|
||||||
|
|
||||||
PClassPlayerPawn *Type;
|
PClassActor *Type;
|
||||||
DWORD Flags;
|
DWORD Flags;
|
||||||
TArray<int> Skins;
|
TArray<int> Skins;
|
||||||
};
|
};
|
||||||
|
@ -345,7 +334,7 @@ struct userinfo_t : TMap<FName,FBaseCVar *>
|
||||||
{
|
{
|
||||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
|
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
|
||||||
}
|
}
|
||||||
PClassPlayerPawn *GetPlayerClassType() const
|
PClassActor *GetPlayerClassType() const
|
||||||
{
|
{
|
||||||
return PlayerClasses[GetPlayerClassNum()].Type;
|
return PlayerClasses[GetPlayerClassNum()].Type;
|
||||||
}
|
}
|
||||||
|
@ -403,7 +392,7 @@ public:
|
||||||
|
|
||||||
userinfo_t userinfo; // [RH] who is this?
|
userinfo_t userinfo; // [RH] who is this?
|
||||||
|
|
||||||
PClassPlayerPawn *cls; // class of associated PlayerPawn
|
PClassActor *cls; // class of associated PlayerPawn
|
||||||
|
|
||||||
float DesiredFOV; // desired field of vision
|
float DesiredFOV; // desired field of vision
|
||||||
float FOV; // current field of vision
|
float FOV; // current field of vision
|
||||||
|
@ -461,7 +450,7 @@ public:
|
||||||
short fixedcolormap; // can be set to REDCOLORMAP, etc.
|
short fixedcolormap; // can be set to REDCOLORMAP, etc.
|
||||||
short fixedlightlevel;
|
short fixedlightlevel;
|
||||||
int morphTics; // player is a chicken/pig if > 0
|
int morphTics; // player is a chicken/pig if > 0
|
||||||
PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
|
PClassActor *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
|
||||||
int MorphStyle; // which effects to apply for this player instance when morphed
|
int MorphStyle; // which effects to apply for this player instance when morphed
|
||||||
PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer)
|
PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer)
|
||||||
TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing
|
TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing
|
||||||
|
@ -540,12 +529,16 @@ public:
|
||||||
// Make sure that a state is properly set after calling this unless
|
// Make sure that a state is properly set after calling this unless
|
||||||
// you are 100% sure the context already implies the layer exists.
|
// you are 100% sure the context already implies the layer exists.
|
||||||
DPSprite *GetPSprite(PSPLayers layer);
|
DPSprite *GetPSprite(PSPLayers layer);
|
||||||
|
|
||||||
|
bool GetPainFlash(FName type, PalEntry *color) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bookkeeping on players - state.
|
// Bookkeeping on players - state.
|
||||||
extern player_t players[MAXPLAYERS];
|
extern player_t players[MAXPLAYERS];
|
||||||
|
|
||||||
void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale);
|
void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale);
|
||||||
|
void EnumColorSets(PClassActor *pc, TArray<int> *out);
|
||||||
|
FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum);
|
||||||
|
|
||||||
inline void AActor::SetFriendPlayer(player_t *player)
|
inline void AActor::SetFriendPlayer(player_t *player)
|
||||||
{
|
{
|
||||||
|
|
109
src/dobject.cpp
109
src/dobject.cpp
|
@ -301,42 +301,17 @@ DObject::~DObject ()
|
||||||
PClass *type = GetClass();
|
PClass *type = GetClass();
|
||||||
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
|
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
|
||||||
{
|
{
|
||||||
DObject **probe;
|
if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released)))
|
||||||
|
|
||||||
if (!(ObjectFlags & OF_YesReallyDelete))
|
|
||||||
{
|
{
|
||||||
Printf("Warning: '%s' is freed outside the GC process.\n",
|
Printf("Warning: '%s' is freed outside the GC process.\n",
|
||||||
type != NULL ? type->TypeName.GetChars() : "==some object==");
|
type != NULL ? type->TypeName.GetChars() : "==some object==");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all pointers that reference this object and NULL them.
|
if (!(ObjectFlags & OF_Released))
|
||||||
StaticPointerSubstitution(this, NULL);
|
|
||||||
|
|
||||||
// Now unlink this object from the GC list.
|
|
||||||
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
|
|
||||||
{
|
{
|
||||||
if (*probe == this)
|
// Find all pointers that reference this object and NULL them.
|
||||||
{
|
StaticPointerSubstitution(this, NULL);
|
||||||
*probe = ObjNext;
|
Release();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||||
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 info->Size;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -427,6 +454,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
{
|
||||||
|
if (p == old)
|
||||||
|
{
|
||||||
|
p = notOld;
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offsets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,11 +93,6 @@ enum
|
||||||
{
|
{
|
||||||
CLASSREG_PClass,
|
CLASSREG_PClass,
|
||||||
CLASSREG_PClassActor,
|
CLASSREG_PClassActor,
|
||||||
CLASSREG_PClassInventory,
|
|
||||||
CLASSREG_PClassWeapon,
|
|
||||||
CLASSREG_PClassPlayerPawn,
|
|
||||||
CLASSREG_PClassType,
|
|
||||||
CLASSREG_PClassClass,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClassReg
|
struct ClassReg
|
||||||
|
@ -208,6 +203,7 @@ enum EObjectFlags
|
||||||
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
|
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
|
||||||
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
|
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
|
||||||
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
||||||
|
OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T> class TObjPtr;
|
template<class T> class TObjPtr;
|
||||||
|
@ -460,6 +456,7 @@ public:
|
||||||
virtual ~DObject ();
|
virtual ~DObject ();
|
||||||
|
|
||||||
inline bool IsKindOf (const PClass *base) const;
|
inline bool IsKindOf (const PClass *base) const;
|
||||||
|
inline bool IsKindOf(FName base) const;
|
||||||
inline bool IsA (const PClass *type) const;
|
inline bool IsA (const PClass *type) const;
|
||||||
|
|
||||||
void SerializeUserVars(FSerializer &arc);
|
void SerializeUserVars(FSerializer &arc);
|
||||||
|
@ -470,6 +467,9 @@ public:
|
||||||
Class = NULL;
|
Class = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Releases the object from the GC, letting the caller care of any maintenance.
|
||||||
|
void Release();
|
||||||
|
|
||||||
// For catching Serialize functions in derived classes
|
// For catching Serialize functions in derived classes
|
||||||
// that don't call their base class.
|
// that don't call their base class.
|
||||||
void CheckIfSerialized () const;
|
void CheckIfSerialized () const;
|
||||||
|
@ -606,6 +606,7 @@ static inline void GC::WriteBarrier(DObject *pointed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "symbols.h"
|
||||||
#include "dobjtype.h"
|
#include "dobjtype.h"
|
||||||
|
|
||||||
inline bool DObject::IsKindOf (const PClass *base) const
|
inline bool DObject::IsKindOf (const PClass *base) const
|
||||||
|
@ -613,6 +614,11 @@ inline bool DObject::IsKindOf (const PClass *base) const
|
||||||
return base->IsAncestorOf (GetClass ());
|
return base->IsAncestorOf (GetClass ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool DObject::IsKindOf(FName base) const
|
||||||
|
{
|
||||||
|
return GetClass()->IsDescendantOf(base);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool DObject::IsA (const PClass *type) const
|
inline bool DObject::IsA (const PClass *type) const
|
||||||
{
|
{
|
||||||
return (type == GetClass());
|
return (type == GetClass());
|
||||||
|
|
|
@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
|
||||||
|
|
||||||
curr->Destroy();
|
curr->Destroy();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
if (curr->IsKindOf(RUNTIME_CLASS(PSymbol)))
|
||||||
|
Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast<PSymbol*>(curr)->SymbolName.GetChars());
|
||||||
|
else if (curr->IsKindOf(RUNTIME_CLASS(PType)))
|
||||||
|
Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast<PType*>(curr)->DescriptiveName());
|
||||||
|
else
|
||||||
|
Printf("Collecting %s\n", curr->GetClass()->TypeName.GetChars());
|
||||||
|
*/
|
||||||
curr->ObjectFlags |= OF_Cleanup;
|
curr->ObjectFlags |= OF_Cleanup;
|
||||||
delete curr;
|
delete curr;
|
||||||
finalized++;
|
finalized++;
|
||||||
|
@ -277,7 +285,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
|
||||||
void Mark(DObject **obj)
|
void Mark(DObject **obj)
|
||||||
{
|
{
|
||||||
DObject *lobj = *obj;
|
DObject *lobj = *obj;
|
||||||
if (lobj != NULL)
|
|
||||||
|
assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released));
|
||||||
|
if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released))
|
||||||
{
|
{
|
||||||
if (lobj->ObjectFlags & OF_EuthanizeMe)
|
if (lobj->ObjectFlags & OF_EuthanizeMe)
|
||||||
{
|
{
|
||||||
|
@ -361,23 +371,6 @@ static void MarkRoot()
|
||||||
}
|
}
|
||||||
Mark(SectorMarker);
|
Mark(SectorMarker);
|
||||||
Mark(interpolator.Head);
|
Mark(interpolator.Head);
|
||||||
// Mark action functions
|
|
||||||
if (!FinalGC)
|
|
||||||
{
|
|
||||||
FAutoSegIterator probe(ARegHead, ARegTail);
|
|
||||||
|
|
||||||
while (*++probe != NULL)
|
|
||||||
{
|
|
||||||
AFuncDesc *afunc = (AFuncDesc *)*probe;
|
|
||||||
Mark(*(afunc->VMPointer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Mark types
|
|
||||||
TypeTable.Mark();
|
|
||||||
for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i)
|
|
||||||
{
|
|
||||||
Mark(PClass::AllClasses[i]);
|
|
||||||
}
|
|
||||||
// Mark global symbols
|
// Mark global symbols
|
||||||
Namespaces.MarkSymbols();
|
Namespaces.MarkSymbols();
|
||||||
// Mark bot stuff.
|
// Mark bot stuff.
|
||||||
|
@ -458,8 +451,8 @@ static size_t SingleStep()
|
||||||
{ // Nothing more to sweep?
|
{ // Nothing more to sweep?
|
||||||
State = GCS_Finalize;
|
State = GCS_Finalize;
|
||||||
}
|
}
|
||||||
assert(old >= AllocBytes);
|
//assert(old >= AllocBytes);
|
||||||
Estimate -= old - AllocBytes;
|
Estimate -= MAX<size_t>(0, old - AllocBytes);
|
||||||
return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST;
|
return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,9 +552,12 @@ void FullGC()
|
||||||
|
|
||||||
void Barrier(DObject *pointing, DObject *pointed)
|
void Barrier(DObject *pointing, DObject *pointed)
|
||||||
{
|
{
|
||||||
|
assert(pointed->GetClass() < (void*)0x1000000000000000);
|
||||||
assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead()));
|
assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead()));
|
||||||
assert(pointed->IsWhite() && !pointed->IsDead());
|
assert(pointed->IsWhite() && !pointed->IsDead());
|
||||||
assert(State != GCS_Finalize && State != GCS_Pause);
|
assert(State != GCS_Finalize && State != GCS_Pause);
|
||||||
|
assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong.
|
||||||
|
if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects.
|
||||||
// The invariant only needs to be maintained in the propagate state.
|
// The invariant only needs to be maintained in the propagate state.
|
||||||
if (State == GCS_Propagate)
|
if (State == GCS_Propagate)
|
||||||
{
|
{
|
||||||
|
@ -776,7 +772,7 @@ CCMD(gc)
|
||||||
{
|
{
|
||||||
if (argv.argc() == 1)
|
if (argv.argc() == 1)
|
||||||
{
|
{
|
||||||
Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n");
|
Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stricmp(argv[1], "stop") == 0)
|
if (stricmp(argv[1], "stop") == 0)
|
||||||
|
@ -791,6 +787,12 @@ CCMD(gc)
|
||||||
{
|
{
|
||||||
GC::FullGC();
|
GC::FullGC();
|
||||||
}
|
}
|
||||||
|
else if (stricmp(argv[1], "count") == 0)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++);
|
||||||
|
Printf("%d active objects counted\n", cnt);
|
||||||
|
}
|
||||||
else if (stricmp(argv[1], "pause") == 0)
|
else if (stricmp(argv[1], "pause") == 0)
|
||||||
{
|
{
|
||||||
if (argv.argc() == 2)
|
if (argv.argc() == 2)
|
||||||
|
@ -814,3 +816,4 @@ CCMD(gc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1075
src/dobjtype.cpp
1075
src/dobjtype.cpp
File diff suppressed because it is too large
Load diff
370
src/dobjtype.h
370
src/dobjtype.h
|
@ -6,6 +6,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||||
|
class PStruct;
|
||||||
|
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
@ -38,36 +39,6 @@ enum
|
||||||
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
||||||
};
|
};
|
||||||
|
|
||||||
// Symbol information -------------------------------------------------------
|
|
||||||
|
|
||||||
class PTypeBase : public DObject
|
|
||||||
{
|
|
||||||
DECLARE_ABSTRACT_CLASS(PTypeBase, DObject)
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual FString QualifiedName() const
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PSymbol : public PTypeBase
|
|
||||||
{
|
|
||||||
DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase);
|
|
||||||
public:
|
|
||||||
virtual ~PSymbol();
|
|
||||||
|
|
||||||
virtual FString QualifiedName() const
|
|
||||||
{
|
|
||||||
return SymbolName.GetChars();
|
|
||||||
}
|
|
||||||
|
|
||||||
FName SymbolName;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
PSymbol(FName name) { SymbolName = name; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// An action function -------------------------------------------------------
|
// An action function -------------------------------------------------------
|
||||||
|
|
||||||
struct FState;
|
struct FState;
|
||||||
|
@ -78,101 +49,6 @@ struct VMReturn;
|
||||||
class VMFunction;
|
class VMFunction;
|
||||||
struct FNamespaceManager;
|
struct FNamespaceManager;
|
||||||
|
|
||||||
// A VM function ------------------------------------------------------------
|
|
||||||
|
|
||||||
class PSymbolVMFunction : public PSymbol
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolVMFunction, PSymbol);
|
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
|
||||||
VMFunction *Function;
|
|
||||||
|
|
||||||
PSymbolVMFunction(FName name) : PSymbol(name) {}
|
|
||||||
PSymbolVMFunction() : PSymbol(NAME_None) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A symbol for a type ------------------------------------------------------
|
|
||||||
|
|
||||||
class PSymbolType : public PSymbol
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolType, PSymbol);
|
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
|
||||||
class PType *Type;
|
|
||||||
|
|
||||||
PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {}
|
|
||||||
PSymbolType() : PSymbol(NAME_None) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A symbol table -----------------------------------------------------------
|
|
||||||
|
|
||||||
struct PSymbolTable
|
|
||||||
{
|
|
||||||
PSymbolTable();
|
|
||||||
PSymbolTable(PSymbolTable *parent);
|
|
||||||
~PSymbolTable();
|
|
||||||
|
|
||||||
size_t MarkSymbols();
|
|
||||||
|
|
||||||
// Sets the table to use for searches if this one doesn't contain the
|
|
||||||
// requested symbol.
|
|
||||||
void SetParentTable (PSymbolTable *parent);
|
|
||||||
PSymbolTable *GetParentTable() const
|
|
||||||
{
|
|
||||||
return ParentSymbolTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finds a symbol in the table, optionally searching parent tables
|
|
||||||
// as well.
|
|
||||||
PSymbol *FindSymbol (FName symname, bool searchparents) const;
|
|
||||||
|
|
||||||
// Like FindSymbol with searchparents set true, but also returns the
|
|
||||||
// specific symbol table the symbol was found in.
|
|
||||||
PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable);
|
|
||||||
|
|
||||||
|
|
||||||
// Places the symbol in the table and returns a pointer to it or NULL if
|
|
||||||
// a symbol with the same name is already in the table. This symbol is
|
|
||||||
// not copied and will be freed when the symbol table is destroyed.
|
|
||||||
PSymbol *AddSymbol (PSymbol *sym);
|
|
||||||
|
|
||||||
// Similar to AddSymbol but always succeeds. Returns the symbol that used
|
|
||||||
// to be in the table with this name, if any.
|
|
||||||
PSymbol *ReplaceSymbol(PSymbol *sym);
|
|
||||||
|
|
||||||
void RemoveSymbol(PSymbol *sym);
|
|
||||||
|
|
||||||
// Frees all symbols from this table.
|
|
||||||
void ReleaseSymbols();
|
|
||||||
|
|
||||||
typedef TMap<FName, PSymbol *> MapType;
|
|
||||||
|
|
||||||
MapType::Iterator GetIterator()
|
|
||||||
{
|
|
||||||
return MapType::Iterator(Symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
PSymbolTable *ParentSymbolTable;
|
|
||||||
MapType Symbols;
|
|
||||||
|
|
||||||
friend class DObject;
|
|
||||||
friend struct FNamespaceManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A symbol for a compiler tree node ----------------------------------------
|
|
||||||
|
|
||||||
class PSymbolTreeNode : public PSymbol
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolTreeNode, PSymbol);
|
|
||||||
public:
|
|
||||||
struct ZCC_TreeNode *Node;
|
|
||||||
|
|
||||||
PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {}
|
|
||||||
PSymbolTreeNode() : PSymbol(NAME_None) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Basic information shared by all types ------------------------------------
|
// Basic information shared by all types ------------------------------------
|
||||||
|
|
||||||
// Only one copy of a type is ever instantiated at one time.
|
// Only one copy of a type is ever instantiated at one time.
|
||||||
|
@ -198,22 +74,13 @@ public:
|
||||||
// Prototype *+ *+
|
// Prototype *+ *+
|
||||||
|
|
||||||
struct ZCC_ExprConstant;
|
struct ZCC_ExprConstant;
|
||||||
class PClassType;
|
|
||||||
class PType : public PTypeBase
|
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)
|
DECLARE_ABSTRACT_CLASS(PType, PTypeBase)
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
protected:
|
protected:
|
||||||
enum { MetaClassNum = CLASSREG_PClassType };
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef PClassType MetaClass;
|
PClass *TypeTableType; // The type to use for hashing into the type table
|
||||||
MetaClass *GetClass() const;
|
|
||||||
|
|
||||||
unsigned int Size; // this type's size
|
unsigned int Size; // this type's size
|
||||||
unsigned int Align; // this type's preferred alignment
|
unsigned int Align; // this type's preferred alignment
|
||||||
PType *HashNext; // next type in this type table
|
PType *HashNext; // next type in this type table
|
||||||
|
@ -246,6 +113,7 @@ public:
|
||||||
// object is destroyed.
|
// object is destroyed.
|
||||||
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const;
|
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 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)
|
// Initialize the value, if needed (e.g. strings)
|
||||||
virtual void InitializeValue(void *addr, const void *def) const;
|
virtual void InitializeValue(void *addr, const void *def) const;
|
||||||
|
@ -302,8 +170,6 @@ public:
|
||||||
|
|
||||||
const char *DescriptiveName() const;
|
const char *DescriptiveName() const;
|
||||||
|
|
||||||
size_t PropagateMark();
|
|
||||||
|
|
||||||
static void StaticInit();
|
static void StaticInit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -341,7 +207,6 @@ class PCompoundType : public PType
|
||||||
class PNamedType : public PCompoundType
|
class PNamedType : public PCompoundType
|
||||||
{
|
{
|
||||||
DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType);
|
DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PTypeBase *Outer; // object this type is contained within
|
PTypeBase *Outer; // object this type is contained within
|
||||||
FName TypeName; // this type's name
|
FName TypeName; // this type's name
|
||||||
|
@ -355,7 +220,6 @@ public:
|
||||||
|
|
||||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||||
virtual FString QualifiedName() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic types --------------------------------------------------------------
|
// Basic types --------------------------------------------------------------
|
||||||
|
@ -498,7 +362,6 @@ public:
|
||||||
class PPointer : public PBasicType
|
class PPointer : public PBasicType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PPointer, PBasicType);
|
DECLARE_CLASS(PPointer, PBasicType);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PPointer();
|
PPointer();
|
||||||
PPointer(PType *pointsat, bool isconst = false);
|
PPointer(PType *pointsat, bool isconst = false);
|
||||||
|
@ -531,9 +394,8 @@ public:
|
||||||
class PClassPointer : public PPointer
|
class PClassPointer : public PPointer
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PClassPointer, PPointer);
|
DECLARE_CLASS(PClassPointer, PPointer);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PClassPointer(class PClass *restrict);
|
PClassPointer(class PClass *restrict = nullptr);
|
||||||
|
|
||||||
class PClass *ClassRestriction;
|
class PClass *ClassRestriction;
|
||||||
|
|
||||||
|
@ -541,54 +403,6 @@ public:
|
||||||
|
|
||||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||||
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 -----------------------------------------------------------
|
// Compound types -----------------------------------------------------------
|
||||||
|
@ -596,7 +410,6 @@ protected:
|
||||||
class PEnum : public PInt
|
class PEnum : public PInt
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PEnum, PInt);
|
DECLARE_CLASS(PEnum, PInt);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PEnum(FName name, PTypeBase *outer);
|
PEnum(FName name, PTypeBase *outer);
|
||||||
|
|
||||||
|
@ -609,7 +422,6 @@ protected:
|
||||||
class PArray : public PCompoundType
|
class PArray : public PCompoundType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PArray, PCompoundType);
|
DECLARE_CLASS(PArray, PCompoundType);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PArray(PType *etype, unsigned int ecount);
|
PArray(PType *etype, unsigned int ecount);
|
||||||
|
|
||||||
|
@ -633,7 +445,6 @@ protected:
|
||||||
class PResizableArray : public PArray
|
class PResizableArray : public PArray
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PResizableArray, PArray);
|
DECLARE_CLASS(PResizableArray, PArray);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PResizableArray(PType *etype);
|
PResizableArray(PType *etype);
|
||||||
|
|
||||||
|
@ -647,14 +458,22 @@ protected:
|
||||||
class PDynArray : public PCompoundType
|
class PDynArray : public PCompoundType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PDynArray, PCompoundType);
|
DECLARE_CLASS(PDynArray, PCompoundType);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PDynArray(PType *etype);
|
PDynArray(PType *etype, PStruct *backing);
|
||||||
|
|
||||||
PType *ElementType;
|
PType *ElementType;
|
||||||
|
PStruct *BackingType;
|
||||||
|
|
||||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||||
|
|
||||||
|
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:
|
protected:
|
||||||
PDynArray();
|
PDynArray();
|
||||||
};
|
};
|
||||||
|
@ -662,7 +481,6 @@ protected:
|
||||||
class PMap : public PCompoundType
|
class PMap : public PCompoundType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PMap, PCompoundType);
|
DECLARE_CLASS(PMap, PCompoundType);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
PMap(PType *keytype, PType *valtype);
|
PMap(PType *keytype, PType *valtype);
|
||||||
|
|
||||||
|
@ -691,8 +509,6 @@ public:
|
||||||
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
|
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
|
||||||
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
|
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
|
||||||
|
|
||||||
size_t PropagateMark();
|
|
||||||
|
|
||||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
|
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
|
||||||
|
@ -729,36 +545,6 @@ protected:
|
||||||
PPrototype();
|
PPrototype();
|
||||||
};
|
};
|
||||||
|
|
||||||
// TBD: Should we really support overloading?
|
|
||||||
class PFunction : public PSymbol
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PFunction, PSymbol);
|
|
||||||
public:
|
|
||||||
struct Variant
|
|
||||||
{
|
|
||||||
PPrototype *Proto;
|
|
||||||
VMFunction *Implementation;
|
|
||||||
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
|
|
||||||
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
|
|
||||||
uint32_t Flags;
|
|
||||||
int UseFlags;
|
|
||||||
PStruct *SelfClass;
|
|
||||||
};
|
|
||||||
TArray<Variant> Variants;
|
|
||||||
PStruct *OwningClass = nullptr;
|
|
||||||
|
|
||||||
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags);
|
|
||||||
int GetImplicitArgs()
|
|
||||||
{
|
|
||||||
if (Variants[0].Flags & VARF_Action) return 3;
|
|
||||||
else if (Variants[0].Flags & VARF_Method) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t PropagateMark();
|
|
||||||
|
|
||||||
PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Meta-info for every class derived from DObject ---------------------------
|
// Meta-info for every class derived from DObject ---------------------------
|
||||||
|
|
||||||
|
@ -767,22 +553,16 @@ enum
|
||||||
TentativeClass = UINT_MAX,
|
TentativeClass = UINT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
class PClassClass;
|
|
||||||
class PClass : public PNativeStruct
|
class PClass : public PNativeStruct
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PClass, PNativeStruct);
|
DECLARE_CLASS(PClass, PNativeStruct);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
protected:
|
protected:
|
||||||
// We unravel _WITH_META here just as we did for PType.
|
// We unravel _WITH_META here just as we did for PType.
|
||||||
enum { MetaClassNum = CLASSREG_PClassClass };
|
|
||||||
TArray<FTypeAndOffset> SpecialInits;
|
TArray<FTypeAndOffset> SpecialInits;
|
||||||
void Derive(PClass *newclass, FName name);
|
void Derive(PClass *newclass, FName name);
|
||||||
void InitializeSpecials(void *addr, void *defaults) const;
|
void InitializeSpecials(void *addr, void *defaults) const;
|
||||||
void SetSuper();
|
void SetSuper();
|
||||||
public:
|
public:
|
||||||
typedef PClassClass MetaClass;
|
|
||||||
MetaClass *GetClass() const;
|
|
||||||
|
|
||||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||||
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
||||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||||
|
@ -799,6 +579,7 @@ public:
|
||||||
PClass *ParentClass; // the class this class derives from
|
PClass *ParentClass; // the class this class derives from
|
||||||
const size_t *Pointers; // object pointers defined by this class *only*
|
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 *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;
|
BYTE *Defaults;
|
||||||
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
||||||
bool bExported; // This type has been declared in a script
|
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;
|
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||||
void InitializeActorInfo();
|
void InitializeActorInfo();
|
||||||
void BuildFlatPointers();
|
void BuildFlatPointers();
|
||||||
|
void BuildArrayPointers();
|
||||||
void DestroySpecials(void *addr) const;
|
void DestroySpecials(void *addr) const;
|
||||||
const PClass *NativeClass() const;
|
const PClass *NativeClass() const;
|
||||||
|
|
||||||
|
@ -830,11 +612,24 @@ public:
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsDescendantOf(const PClass *ti) const
|
inline bool IsDescendantOf(const PClass *ti) const
|
||||||
{
|
{
|
||||||
return ti->IsAncestorOf(this);
|
return ti->IsAncestorOf(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool IsDescendantOf(FName ti) const
|
||||||
|
{
|
||||||
|
auto me = this;
|
||||||
|
while (me)
|
||||||
|
{
|
||||||
|
if (me->TypeName == ti)
|
||||||
|
return true;
|
||||||
|
me = me->ParentClass;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Find a type, given its name.
|
// Find a type, given its name.
|
||||||
const PClass *FindParentClass(FName name) const;
|
const PClass *FindParentClass(FName name) const;
|
||||||
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
|
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
|
||||||
|
@ -858,34 +653,6 @@ public:
|
||||||
static bool bVMOperational;
|
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 --------------------------------------------------------------
|
// Type tables --------------------------------------------------------------
|
||||||
|
|
||||||
struct FTypeTable
|
struct FTypeTable
|
||||||
|
@ -895,10 +662,8 @@ struct FTypeTable
|
||||||
PType *TypeHash[HASH_SIZE];
|
PType *TypeHash[HASH_SIZE];
|
||||||
|
|
||||||
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
|
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
|
||||||
void ReplaceType(PType *newtype, PType *oldtype, size_t bucket);
|
|
||||||
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
|
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
|
||||||
void AddType(PType *type);
|
void AddType(PType *type);
|
||||||
void Mark();
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
|
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
|
||||||
|
@ -940,86 +705,11 @@ extern PStruct *TypeVector3;
|
||||||
extern PStruct *TypeColorStruct;
|
extern PStruct *TypeColorStruct;
|
||||||
extern PStruct *TypeStringStruct;
|
extern PStruct *TypeStringStruct;
|
||||||
extern PStatePointer *TypeState;
|
extern PStatePointer *TypeState;
|
||||||
|
extern PPointer *TypeFont;
|
||||||
extern PStateLabel *TypeStateLabel;
|
extern PStateLabel *TypeStateLabel;
|
||||||
extern PPointer *TypeNullPtr;
|
extern PPointer *TypeNullPtr;
|
||||||
extern PPointer *TypeVoidPtr;
|
extern PPointer *TypeVoidPtr;
|
||||||
|
|
||||||
// A constant value ---------------------------------------------------------
|
|
||||||
|
|
||||||
class PSymbolConst : public PSymbol
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolConst, PSymbol);
|
|
||||||
public:
|
|
||||||
PType *ValueType;
|
|
||||||
|
|
||||||
PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {}
|
|
||||||
PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A constant numeric value -------------------------------------------------
|
|
||||||
|
|
||||||
class PSymbolConstNumeric : public PSymbolConst
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst);
|
|
||||||
public:
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int Value;
|
|
||||||
double Float;
|
|
||||||
void *Pad;
|
|
||||||
};
|
|
||||||
|
|
||||||
PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {}
|
|
||||||
PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {}
|
|
||||||
PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {}
|
|
||||||
PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {}
|
|
||||||
PSymbolConstNumeric() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A constant string value --------------------------------------------------
|
|
||||||
|
|
||||||
class PSymbolConstString : public PSymbolConst
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PSymbolConstString, PSymbolConst);
|
|
||||||
public:
|
|
||||||
FString Str;
|
|
||||||
|
|
||||||
PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
|
||||||
PSymbolConstString() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Namespaces --------------------------------------------------
|
|
||||||
|
|
||||||
class PNamespace : public PTypeBase
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PNamespace, PTypeBase)
|
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PSymbolTable Symbols;
|
|
||||||
PNamespace *Parent;
|
|
||||||
int FileNum; // This is for blocking DECORATE access to later files.
|
|
||||||
|
|
||||||
PNamespace() {}
|
|
||||||
PNamespace(int filenum, PNamespace *parent);
|
|
||||||
size_t PropagateMark();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FNamespaceManager
|
|
||||||
{
|
|
||||||
PNamespace *GlobalNamespace;
|
|
||||||
TArray<PNamespace *> AllNamespaces;
|
|
||||||
|
|
||||||
FNamespaceManager();
|
|
||||||
PNamespace *NewNamespace(int filenum);
|
|
||||||
size_t MarkSymbols();
|
|
||||||
void ReleaseSymbols();
|
|
||||||
int RemoveSymbols();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern FNamespaceManager Namespaces;
|
|
||||||
|
|
||||||
|
|
||||||
// Enumerations for serializing types in an archive -------------------------
|
// Enumerations for serializing types in an archive -------------------------
|
||||||
|
|
||||||
inline bool &DObject::BoolVar(FName field)
|
inline bool &DObject::BoolVar(FName field)
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <tuple>
|
||||||
|
#include <algorithm>
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "name.h"
|
#include "name.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
|
@ -156,12 +158,9 @@ struct PalEntry
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class PClassInventory;
|
|
||||||
|
|
||||||
class FTextureID
|
class FTextureID
|
||||||
{
|
{
|
||||||
friend class FTextureManager;
|
friend class FTextureManager;
|
||||||
friend FTextureID GetHUDIcon(PClassInventory *cls);
|
|
||||||
friend void R_InitSpriteDefs();
|
friend void R_InitSpriteDefs();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum)
|
||||||
// Doom index is only supported for the 4 original ammo types
|
// Doom index is only supported for the 4 original ammo types
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
static PClassInventory * T_GetAmmo(const svalue_t &t)
|
static PClassActor * T_GetAmmo(const svalue_t &t)
|
||||||
{
|
{
|
||||||
const char * p;
|
const char * p;
|
||||||
|
|
||||||
|
@ -361,8 +361,8 @@ static PClassInventory * T_GetAmmo(const svalue_t &t)
|
||||||
}
|
}
|
||||||
p=DefAmmo[ammonum];
|
p=DefAmmo[ammonum];
|
||||||
}
|
}
|
||||||
PClassInventory * am=dyn_cast<PClassInventory>(PClass::FindActor(p));
|
auto am = PClass::FindActor(p);
|
||||||
if (am == NULL)
|
if (am == NULL || !am->IsKindOf(PClass::FindClass(NAME_Ammo)))
|
||||||
{
|
{
|
||||||
script_error("unknown ammo type : %s", p);
|
script_error("unknown ammo type : %s", p);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2434,8 +2434,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount)
|
||||||
{
|
{
|
||||||
type = "BasicArmorPickup";
|
type = "BasicArmorPickup";
|
||||||
}
|
}
|
||||||
PClassInventory * info = dyn_cast<PClassInventory>(PClass::FindActor (type));
|
auto info = PClass::FindActor (type);
|
||||||
if (info == NULL)
|
if (info == NULL || !info->IsKindOf(RUNTIME_CLASS(AInventory)))
|
||||||
{
|
{
|
||||||
Printf ("Unknown inventory item: %s\n", type);
|
Printf ("Unknown inventory item: %s\n", type);
|
||||||
return;
|
return;
|
||||||
|
@ -2564,7 +2564,7 @@ void FParser::SF_PlayerKeys(void)
|
||||||
void FParser::SF_PlayerAmmo(void)
|
void FParser::SF_PlayerAmmo(void)
|
||||||
{
|
{
|
||||||
int playernum, amount;
|
int playernum, amount;
|
||||||
PClassInventory * ammotype;
|
PClassActor * ammotype;
|
||||||
|
|
||||||
if (CheckArgs(2))
|
if (CheckArgs(2))
|
||||||
{
|
{
|
||||||
|
@ -2600,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void)
|
||||||
void FParser::SF_MaxPlayerAmmo()
|
void FParser::SF_MaxPlayerAmmo()
|
||||||
{
|
{
|
||||||
int playernum, amount;
|
int playernum, amount;
|
||||||
PClassInventory * ammotype;
|
PClassActor * ammotype;
|
||||||
|
|
||||||
if (CheckArgs(2))
|
if (CheckArgs(2))
|
||||||
{
|
{
|
||||||
|
@ -2629,7 +2629,7 @@ void FParser::SF_MaxPlayerAmmo()
|
||||||
|
|
||||||
for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory)
|
for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory)
|
||||||
{
|
{
|
||||||
if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem)))
|
if (item->IsKindOf(NAME_BackpackItem))
|
||||||
{
|
{
|
||||||
if (t_argc>=4) amount = intvalue(t_argv[3]);
|
if (t_argc>=4) amount = intvalue(t_argv[3]);
|
||||||
else amount*=2;
|
else amount*=2;
|
||||||
|
@ -2675,8 +2675,8 @@ void FParser::SF_PlayerWeapon()
|
||||||
script_error("weaponnum out of range! %d\n", weaponnum);
|
script_error("weaponnum out of range! %d\n", weaponnum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PClassWeapon * ti = static_cast<PClassWeapon *>(PClass::FindActor(WeaponNames[weaponnum]));
|
auto ti = PClass::FindActor(WeaponNames[weaponnum]);
|
||||||
if (!ti)
|
if (!ti || !ti->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
script_error("incompatibility in playerweapon %d\n", weaponnum);
|
script_error("incompatibility in playerweapon %d\n", weaponnum);
|
||||||
return;
|
return;
|
||||||
|
@ -2686,7 +2686,7 @@ void FParser::SF_PlayerWeapon()
|
||||||
{
|
{
|
||||||
AActor * wp = players[playernum].mo->FindInventory(ti);
|
AActor * wp = players[playernum].mo->FindInventory(ti);
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
t_return.value.i = wp!=NULL;;
|
t_return.value.i = wp!=NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2712,7 +2712,7 @@ void FParser::SF_PlayerWeapon()
|
||||||
{
|
{
|
||||||
if (!wp)
|
if (!wp)
|
||||||
{
|
{
|
||||||
AWeapon * pw=players[playernum].PendingWeapon;
|
auto pw=players[playernum].PendingWeapon;
|
||||||
players[playernum].mo->GiveInventoryType(ti);
|
players[playernum].mo->GiveInventoryType(ti);
|
||||||
players[playernum].PendingWeapon=pw;
|
players[playernum].PendingWeapon=pw;
|
||||||
}
|
}
|
||||||
|
@ -2756,8 +2756,8 @@ void FParser::SF_PlayerSelectedWeapon()
|
||||||
script_error("weaponnum out of range! %d\n", weaponnum);
|
script_error("weaponnum out of range! %d\n", weaponnum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PClassWeapon * ti = static_cast<PClassWeapon *>(PClass::FindActor(WeaponNames[weaponnum]));
|
auto ti = PClass::FindActor(WeaponNames[weaponnum]);
|
||||||
if (!ti)
|
if (!ti || !ti->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
script_error("incompatibility in playerweapon %d\n", weaponnum);
|
script_error("incompatibility in playerweapon %d\n", weaponnum);
|
||||||
return;
|
return;
|
||||||
|
@ -2862,7 +2862,7 @@ void FParser::SF_SetWeapon()
|
||||||
{
|
{
|
||||||
AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1])));
|
AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1])));
|
||||||
|
|
||||||
if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
if (item == NULL || !item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else if (players[playernum].ReadyWeapon == item)
|
else if (players[playernum].ReadyWeapon == item)
|
||||||
|
@ -2874,7 +2874,7 @@ void FParser::SF_SetWeapon()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AWeapon *weap = static_cast<AWeapon *> (item);
|
auto weap = static_cast<AWeapon *> (item);
|
||||||
|
|
||||||
if (weap->CheckAmmo (AWeapon::EitherFire, false))
|
if (weap->CheckAmmo (AWeapon::EitherFire, false))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1362,7 +1362,7 @@ void G_PlayerReborn (int player)
|
||||||
BYTE currclass;
|
BYTE currclass;
|
||||||
userinfo_t userinfo; // [RH] Save userinfo
|
userinfo_t userinfo; // [RH] Save userinfo
|
||||||
APlayerPawn *actor;
|
APlayerPawn *actor;
|
||||||
PClassPlayerPawn *cls;
|
PClassActor *cls;
|
||||||
FString log;
|
FString log;
|
||||||
DBot *Bot; //Added by MC:
|
DBot *Bot; //Added by MC:
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc)
|
||||||
keygroup->anykeylist.Push (k);
|
keygroup->anykeylist.Push (k);
|
||||||
|
|
||||||
//... but only keys get key numbers!
|
//... but only keys get key numbers!
|
||||||
if (mi->IsDescendantOf(PClass::FindActor(NAME_Key)))
|
if (mi->IsDescendantOf(NAME_Key))
|
||||||
{
|
{
|
||||||
if (!ignorekey &&
|
if (!ignorekey &&
|
||||||
GetDefaultByType(mi)->special1 == 0)
|
GetDefaultByType(mi)->special1 == 0)
|
||||||
|
|
|
@ -25,58 +25,10 @@
|
||||||
|
|
||||||
EXTERN_CVAR(Bool, sv_unlimited_pickup)
|
EXTERN_CVAR(Bool, sv_unlimited_pickup)
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PClassInventory, false, false)
|
void AInventory::Finalize(FStateDefinitions &statedef)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Super::Finalize(statedef);
|
Super::Finalize(statedef);
|
||||||
((AActor*)Defaults)->flags |= MF_SPECIAL;
|
flags |= MF_SPECIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_CLASS(AInventory, false, true)
|
IMPLEMENT_CLASS(AInventory, false, true)
|
||||||
|
@ -98,8 +50,8 @@ DEFINE_FIELD(AInventory, DropTime)
|
||||||
DEFINE_FIELD(AInventory, SpawnPointClass)
|
DEFINE_FIELD(AInventory, SpawnPointClass)
|
||||||
DEFINE_FIELD(AInventory, PickupFlash)
|
DEFINE_FIELD(AInventory, PickupFlash)
|
||||||
DEFINE_FIELD(AInventory, PickupSound)
|
DEFINE_FIELD(AInventory, PickupSound)
|
||||||
DEFINE_FIELD(PClassInventory, PickupMsg)
|
DEFINE_FIELD(AInventory, GiveQuest)
|
||||||
DEFINE_FIELD(PClassInventory, GiveQuest)
|
DEFINE_FIELD(PClassActor, PickupMsg)
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
|
@ -163,7 +115,8 @@ void AInventory::Serialize(FSerializer &arc)
|
||||||
("icon", Icon, def->Icon)
|
("icon", Icon, def->Icon)
|
||||||
("pickupsound", PickupSound, def->PickupSound)
|
("pickupsound", PickupSound, def->PickupSound)
|
||||||
("spawnpointclass", SpawnPointClass, def->SpawnPointClass)
|
("spawnpointclass", SpawnPointClass, def->SpawnPointClass)
|
||||||
("droptime", DropTime, def->DropTime);
|
("droptime", DropTime, def->DropTime)
|
||||||
|
("givequest", GiveQuest, def->GiveQuest);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -548,7 +501,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CanPickup)
|
||||||
if (!toucher)
|
if (!toucher)
|
||||||
ACTION_RETURN_BOOL(false);
|
ACTION_RETURN_BOOL(false);
|
||||||
|
|
||||||
PClassInventory *ai = self->GetClass();
|
auto ai = self->GetClass();
|
||||||
// Is the item restricted to certain player classes?
|
// Is the item restricted to certain player classes?
|
||||||
if (ai->RestrictedToPlayerClass.Size() != 0)
|
if (ai->RestrictedToPlayerClass.Size() != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
class player_t;
|
class player_t;
|
||||||
class FConfigFile;
|
class FConfigFile;
|
||||||
class PClassPlayerPawn;
|
|
||||||
struct visstyle_t;
|
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
|
class AInventory : public AActor
|
||||||
{
|
{
|
||||||
DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory)
|
DECLARE_CLASS(AInventory, AActor)
|
||||||
HAS_OBJECT_POINTERS
|
HAS_OBJECT_POINTERS
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual void Finalize(FStateDefinitions &statedef) override;
|
||||||
virtual void Serialize(FSerializer &arc) override;
|
virtual void Serialize(FSerializer &arc) override;
|
||||||
virtual void MarkPrecacheSounds() const override;
|
virtual void MarkPrecacheSounds() const override;
|
||||||
virtual void OnDestroy() override;
|
virtual void OnDestroy() override;
|
||||||
|
@ -103,6 +87,8 @@ public:
|
||||||
FTextureID Icon; // Icon to show on status bar or HUD
|
FTextureID Icon; // Icon to show on status bar or HUD
|
||||||
int DropTime; // Countdown after dropping
|
int DropTime; // Countdown after dropping
|
||||||
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
|
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
|
||||||
|
int GiveQuest; // Optionally give one of the quest items.
|
||||||
|
FTextureID AltHUDIcon;
|
||||||
|
|
||||||
DWORD ItemFlags;
|
DWORD ItemFlags;
|
||||||
PClassActor *PickupFlash; // actor to spawn as pickup flash
|
PClassActor *PickupFlash; // actor to spawn as pickup flash
|
||||||
|
|
|
@ -64,9 +64,6 @@ IMPLEMENT_POINTERS_START(AWeapon)
|
||||||
IMPLEMENT_POINTER(Ammo1)
|
IMPLEMENT_POINTER(Ammo1)
|
||||||
IMPLEMENT_POINTER(Ammo2)
|
IMPLEMENT_POINTER(Ammo2)
|
||||||
IMPLEMENT_POINTER(SisterWeapon)
|
IMPLEMENT_POINTER(SisterWeapon)
|
||||||
IMPLEMENT_POINTER(AmmoType1)
|
|
||||||
IMPLEMENT_POINTER(AmmoType2)
|
|
||||||
IMPLEMENT_POINTER(SisterWeaponType)
|
|
||||||
IMPLEMENT_POINTERS_END
|
IMPLEMENT_POINTERS_END
|
||||||
|
|
||||||
DEFINE_FIELD(AWeapon, WeaponFlags)
|
DEFINE_FIELD(AWeapon, WeaponFlags)
|
||||||
|
@ -113,55 +110,25 @@ FString WeaponSection;
|
||||||
TArray<FString> KeyConfWeapons;
|
TArray<FString> KeyConfWeapons;
|
||||||
FWeaponSlots *PlayingKeyConf;
|
FWeaponSlots *PlayingKeyConf;
|
||||||
|
|
||||||
TArray<PClassWeapon *> Weapons_ntoh;
|
TArray<PClassActor *> Weapons_ntoh;
|
||||||
TMap<PClassWeapon *, int> Weapons_hton;
|
TMap<PClassActor *, int> Weapons_hton;
|
||||||
|
|
||||||
static int ntoh_cmp(const void *a, const void *b);
|
static int ntoh_cmp(const void *a, const void *b);
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PClassWeapon, false, false)
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
PClassWeapon::PClassWeapon()
|
void AWeapon::Finalize(FStateDefinitions &statedef)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Super::Finalize(statedef);
|
Super::Finalize(statedef);
|
||||||
FState *ready = FindState(NAME_Ready);
|
FState *ready = FindState(NAME_Ready);
|
||||||
FState *select = FindState(NAME_Select);
|
FState *select = FindState(NAME_Select);
|
||||||
FState *deselect = FindState(NAME_Deselect);
|
FState *deselect = FindState(NAME_Deselect);
|
||||||
FState *fire = FindState(NAME_Fire);
|
FState *fire = FindState(NAME_Fire);
|
||||||
|
auto TypeName = GetClass()->TypeName;
|
||||||
|
|
||||||
// Consider any weapon without any valid state abstract and don't output a warning
|
// 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.
|
// 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);
|
bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false);
|
||||||
if (!gotSome && autoSwitch)
|
if (!gotSome && autoSwitch)
|
||||||
{
|
{
|
||||||
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (NULL);
|
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (nullptr);
|
||||||
}
|
}
|
||||||
return gotSome;
|
return gotSome;
|
||||||
}
|
}
|
||||||
|
@ -281,10 +248,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0;
|
count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0;
|
||||||
count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0;
|
count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0;
|
||||||
|
|
||||||
if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL))
|
if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr))
|
||||||
{
|
{
|
||||||
lAmmoUse1 = 0;
|
lAmmoUse1 = 0;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +273,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am
|
||||||
{
|
{
|
||||||
enoughmask = 1 << altFire;
|
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
|
{ // If this weapon has no alternate fire, then there is never enough ammo for it
|
||||||
enough &= 1;
|
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
|
// out of ammo, pick a weapon to change to
|
||||||
if (autoSwitch)
|
if (autoSwitch)
|
||||||
{
|
{
|
||||||
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (NULL);
|
barrier_cast<APlayerPawn *>(Owner)->PickNewWeapon (nullptr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -352,7 +319,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
|
||||||
}
|
}
|
||||||
if (!altFire)
|
if (!altFire)
|
||||||
{
|
{
|
||||||
if (Ammo1 != NULL)
|
if (Ammo1 != nullptr)
|
||||||
{
|
{
|
||||||
if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO))
|
if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO))
|
||||||
{
|
{
|
||||||
|
@ -363,25 +330,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
|
||||||
Ammo1->Amount -= AmmoUse1;
|
Ammo1->Amount -= AmmoUse1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL)
|
if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr)
|
||||||
{
|
{
|
||||||
Ammo2->Amount -= AmmoUse2;
|
Ammo2->Amount -= AmmoUse2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Ammo2 != NULL)
|
if (Ammo2 != nullptr)
|
||||||
{
|
{
|
||||||
Ammo2->Amount -= AmmoUse2;
|
Ammo2->Amount -= AmmoUse2;
|
||||||
}
|
}
|
||||||
if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL)
|
if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr)
|
||||||
{
|
{
|
||||||
Ammo1->Amount -= AmmoUse1;
|
Ammo1->Amount -= AmmoUse1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Ammo1 != NULL && Ammo1->Amount < 0)
|
if (Ammo1 != nullptr && Ammo1->Amount < 0)
|
||||||
Ammo1->Amount = 0;
|
Ammo1->Amount = 0;
|
||||||
if (Ammo2 != NULL && Ammo2->Amount < 0)
|
if (Ammo2 != nullptr && Ammo2->Amount < 0)
|
||||||
Ammo2->Amount = 0;
|
Ammo2->Amount = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -546,19 +513,19 @@ FState *AWeapon::GetStateForButtonName (FName button)
|
||||||
|
|
||||||
bool FWeaponSlot::AddWeapon(const char *type)
|
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;
|
unsigned int i;
|
||||||
|
|
||||||
if (type == NULL)
|
if (type == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!type->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (!type->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars());
|
Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars());
|
||||||
return false;
|
return false;
|
||||||
|
@ -594,10 +561,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear)
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
tok = strtok(buff, " ");
|
tok = strtok(buff, " ");
|
||||||
while (tok != NULL)
|
while (tok != nullptr)
|
||||||
{
|
{
|
||||||
AddWeapon(tok);
|
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;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -641,22 +608,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (player->mo == NULL)
|
if (player->mo == nullptr)
|
||||||
{
|
{
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// Does this slot even have any weapons?
|
// Does this slot even have any weapons?
|
||||||
if (Weapons.Size() == 0)
|
if (Weapons.Size() == 0)
|
||||||
{
|
{
|
||||||
return player->ReadyWeapon;
|
return player->ReadyWeapon;
|
||||||
}
|
}
|
||||||
if (player->ReadyWeapon != NULL)
|
if (player->ReadyWeapon != nullptr)
|
||||||
{
|
{
|
||||||
for (i = 0; (unsigned)i < Weapons.Size(); i++)
|
for (i = 0; (unsigned)i < Weapons.Size(); i++)
|
||||||
{
|
{
|
||||||
if (Weapons[i].Type == player->ReadyWeapon->GetClass() ||
|
if (Weapons[i].Type == player->ReadyWeapon->GetClass() ||
|
||||||
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
|
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||||
player->ReadyWeapon->SisterWeapon != NULL &&
|
player->ReadyWeapon->SisterWeapon != nullptr &&
|
||||||
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type))
|
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type))
|
||||||
{
|
{
|
||||||
for (j = (i == 0 ? Weapons.Size() - 1 : i - 1);
|
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));
|
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))
|
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));
|
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))
|
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
|
||||||
{
|
{
|
||||||
|
@ -736,7 +703,7 @@ void FWeaponSlot::Sort()
|
||||||
for (i = 1; i < (int)Weapons.Size(); ++i)
|
for (i = 1; i < (int)Weapons.Size(); ++i)
|
||||||
{
|
{
|
||||||
int pos = Weapons[i].Position;
|
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)
|
for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j)
|
||||||
{
|
{
|
||||||
Weapons[j + 1] = Weapons[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;
|
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;
|
int i, j;
|
||||||
|
|
||||||
|
@ -819,8 +786,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const
|
||||||
j = Slots[i].LocateWeapon(type);
|
j = Slots[i].LocateWeapon(type);
|
||||||
if (j >= 0)
|
if (j >= 0)
|
||||||
{
|
{
|
||||||
if (slot != NULL) *slot = i;
|
if (slot != nullptr) *slot = i;
|
||||||
if (index != NULL) *index = j;
|
if (index != nullptr) *index = j;
|
||||||
return true;
|
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);
|
return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index);
|
||||||
}
|
}
|
||||||
else if (player->ReadyWeapon != NULL)
|
else if (player->ReadyWeapon != nullptr)
|
||||||
{
|
{
|
||||||
AWeapon *weap = player->ReadyWeapon;
|
AWeapon *weap = player->ReadyWeapon;
|
||||||
if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index))
|
if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index))
|
||||||
{
|
{
|
||||||
// If the current weapon wasn't found and is powered up,
|
// If the current weapon wasn't found and is powered up,
|
||||||
// look for its non-powered up version.
|
// 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);
|
return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index);
|
||||||
}
|
}
|
||||||
|
@ -893,16 +860,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
|
||||||
int startslot, startindex;
|
int startslot, startindex;
|
||||||
int slotschecked = 0;
|
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 slot;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
if (player->ReadyWeapon == NULL)
|
if (player->ReadyWeapon == nullptr)
|
||||||
{
|
{
|
||||||
startslot = NUM_WEAPON_SLOTS - 1;
|
startslot = NUM_WEAPON_SLOTS - 1;
|
||||||
startindex = Slots[startslot].Size() - 1;
|
startindex = Slots[startslot].Size() - 1;
|
||||||
|
@ -921,9 +888,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
|
||||||
slot = 0;
|
slot = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PClassWeapon *type = Slots[slot].GetWeapon(index);
|
PClassActor *type = Slots[slot].GetWeapon(index);
|
||||||
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
|
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;
|
return weap;
|
||||||
}
|
}
|
||||||
|
@ -948,16 +915,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
|
||||||
int startslot, startindex;
|
int startslot, startindex;
|
||||||
int slotschecked = 0;
|
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 slot;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
if (player->ReadyWeapon == NULL)
|
if (player->ReadyWeapon == nullptr)
|
||||||
{
|
{
|
||||||
startslot = 0;
|
startslot = 0;
|
||||||
startindex = 0;
|
startindex = 0;
|
||||||
|
@ -976,9 +943,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
|
||||||
}
|
}
|
||||||
index = Slots[slot].Size() - 1;
|
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));
|
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;
|
return weap;
|
||||||
}
|
}
|
||||||
|
@ -1010,23 +977,23 @@ void FWeaponSlots::AddExtraWeapons()
|
||||||
// Append extra weapons to the slots.
|
// Append extra weapons to the slots.
|
||||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
PClassWeapon *acls = static_cast<PClassWeapon *>(cls);
|
auto weapdef = ((AWeapon*)GetDefaultByType(cls));
|
||||||
if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) &&
|
if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) &&
|
||||||
acls->Replacement == NULL && // Replaced weapons don't get slotted.
|
cls->Replacement == nullptr && // Replaced weapons don't get slotted.
|
||||||
!(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) &&
|
!(weapdef->WeaponFlags & WIF_POWERED_UP) &&
|
||||||
!LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present.
|
!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)
|
if ((unsigned)slot < NUM_WEAPON_SLOTS)
|
||||||
{
|
{
|
||||||
FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority };
|
FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority };
|
||||||
Slots[slot].Weapons.Push(info);
|
Slots[slot].Weapons.Push(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,8 +1030,8 @@ void FWeaponSlots::SetFromGameInfo()
|
||||||
{
|
{
|
||||||
for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++)
|
for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++)
|
||||||
{
|
{
|
||||||
PClassWeapon *cls = dyn_cast<PClassWeapon>(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j]));
|
PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]);
|
||||||
if (cls == NULL)
|
if (cls == nullptr)
|
||||||
{
|
{
|
||||||
Printf("Unknown weapon class '%s' found in default weapon slot assignments\n",
|
Printf("Unknown weapon class '%s' found in default weapon slot assignments\n",
|
||||||
gameinfo.DefaultWeaponSlots[i][j].GetChars());
|
gameinfo.DefaultWeaponSlots[i][j].GetChars());
|
||||||
|
@ -1088,7 +1055,7 @@ void FWeaponSlots::SetFromGameInfo()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FWeaponSlots::StandardSetup(PClassPlayerPawn *type)
|
void FWeaponSlots::StandardSetup(PClassActor *type)
|
||||||
{
|
{
|
||||||
SetFromPlayer(type);
|
SetFromPlayer(type);
|
||||||
AddExtraWeapons();
|
AddExtraWeapons();
|
||||||
|
@ -1181,14 +1148,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type)
|
void FWeaponSlots::SetFromPlayer(PClassActor *type)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot;
|
||||||
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
|
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
|
||||||
{
|
{
|
||||||
if (!type->Slot[i].IsEmpty())
|
if (Slot[i] != NAME_None)
|
||||||
{
|
{
|
||||||
Slots[i].AddWeaponList(type->Slot[i], false);
|
Slots[i].AddWeaponList(Slot[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1260,7 +1228,7 @@ CCMD (setslot)
|
||||||
if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
|
if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
|
||||||
{
|
{
|
||||||
Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n");
|
Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n");
|
||||||
if (players[consoleplayer].mo != NULL)
|
if (players[consoleplayer].mo != nullptr)
|
||||||
{
|
{
|
||||||
FString config(GameConfig->GetConfigPath(false));
|
FString config(GameConfig->GetConfigPath(false));
|
||||||
Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE
|
Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE
|
||||||
|
@ -1279,7 +1247,7 @@ CCMD (setslot)
|
||||||
{
|
{
|
||||||
KeyConfWeapons.Push(argv.args());
|
KeyConfWeapons.Push(argv.args());
|
||||||
}
|
}
|
||||||
else if (PlayingKeyConf != NULL)
|
else if (PlayingKeyConf != nullptr)
|
||||||
{
|
{
|
||||||
PlayingKeyConf->Slots[slot].Clear();
|
PlayingKeyConf->Slots[slot].Clear();
|
||||||
for (int i = 2; i < argv.argc(); ++i)
|
for (int i = 2; i < argv.argc(); ++i)
|
||||||
|
@ -1299,7 +1267,7 @@ CCMD (setslot)
|
||||||
Net_WriteByte(argv.argc()-2);
|
Net_WriteByte(argv.argc()-2);
|
||||||
for (int i = 2; i < argv.argc(); i++)
|
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);
|
Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot);
|
||||||
}
|
}
|
||||||
|
@ -1328,8 +1296,8 @@ CCMD (addslot)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PClassWeapon *type= dyn_cast<PClassWeapon>(PClass::FindClass(argv[2]));
|
PClassActor *type= dyn_cast<PClassActor>(PClass::FindClass(argv[2]));
|
||||||
if (type == NULL)
|
if (type == nullptr)
|
||||||
{
|
{
|
||||||
Printf("%s is not a weapon\n", argv[2]);
|
Printf("%s is not a weapon\n", argv[2]);
|
||||||
return;
|
return;
|
||||||
|
@ -1339,7 +1307,7 @@ CCMD (addslot)
|
||||||
{
|
{
|
||||||
KeyConfWeapons.Push(argv.args());
|
KeyConfWeapons.Push(argv.args());
|
||||||
}
|
}
|
||||||
else if (PlayingKeyConf != NULL)
|
else if (PlayingKeyConf != nullptr)
|
||||||
{
|
{
|
||||||
PlayingKeyConf->AddSlot(int(slot), type, false);
|
PlayingKeyConf->AddSlot(int(slot), type, false);
|
||||||
}
|
}
|
||||||
|
@ -1370,9 +1338,9 @@ CCMD (weaponsection)
|
||||||
// CCMD addslotdefault
|
// 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))
|
switch (AddDefaultWeapon(slot, type))
|
||||||
{
|
{
|
||||||
|
@ -1395,7 +1363,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback)
|
||||||
|
|
||||||
CCMD (addslotdefault)
|
CCMD (addslotdefault)
|
||||||
{
|
{
|
||||||
PClassWeapon *type;
|
PClassActor *type;
|
||||||
unsigned int slot;
|
unsigned int slot;
|
||||||
|
|
||||||
if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
|
if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
|
||||||
|
@ -1404,8 +1372,8 @@ CCMD (addslotdefault)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = dyn_cast<PClassWeapon>(PClass::FindClass(argv[2]));
|
type = dyn_cast<PClassActor>(PClass::FindClass(argv[2]));
|
||||||
if (type == NULL)
|
if (type == nullptr)
|
||||||
{
|
{
|
||||||
Printf ("%s is not a weapon\n", argv[2]);
|
Printf ("%s is not a weapon\n", argv[2]);
|
||||||
return;
|
return;
|
||||||
|
@ -1415,7 +1383,7 @@ CCMD (addslotdefault)
|
||||||
{
|
{
|
||||||
KeyConfWeapons.Push(argv.args());
|
KeyConfWeapons.Push(argv.args());
|
||||||
}
|
}
|
||||||
else if (PlayingKeyConf != NULL)
|
else if (PlayingKeyConf != nullptr)
|
||||||
{
|
{
|
||||||
PlayingKeyConf->AddSlotDefault(int(slot), type, false);
|
PlayingKeyConf->AddSlotDefault(int(slot), type, false);
|
||||||
}
|
}
|
||||||
|
@ -1443,7 +1411,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots)
|
||||||
FString cmd(KeyConfWeapons[i]);
|
FString cmd(KeyConfWeapons[i]);
|
||||||
AddCommandString(cmd.LockBuffer());
|
AddCommandString(cmd.LockBuffer());
|
||||||
}
|
}
|
||||||
PlayingKeyConf = NULL;
|
PlayingKeyConf = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -1460,20 +1428,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots)
|
||||||
void P_SetupWeapons_ntohton()
|
void P_SetupWeapons_ntohton()
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
PClassWeapon *cls;
|
PClassActor *cls;
|
||||||
|
|
||||||
Weapons_ntoh.Clear();
|
Weapons_ntoh.Clear();
|
||||||
Weapons_hton.Clear();
|
Weapons_hton.Clear();
|
||||||
|
|
||||||
cls = NULL;
|
cls = nullptr;
|
||||||
Weapons_ntoh.Push(cls); // Index 0 is always NULL.
|
Weapons_ntoh.Push(cls); // Index 0 is always nullptr.
|
||||||
for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||||
{
|
{
|
||||||
PClassActor *cls = PClassActor::AllActorClasses[i];
|
PClassActor *cls = PClassActor::AllActorClasses[i];
|
||||||
|
|
||||||
if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (cls->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
Weapons_ntoh.Push(static_cast<PClassWeapon *>(cls));
|
Weapons_ntoh.Push(static_cast<PClassActor *>(cls));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp);
|
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)
|
static int ntoh_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
PClassWeapon *c1 = *(PClassWeapon **)a;
|
PClassActor *c1 = *(PClassActor **)a;
|
||||||
PClassWeapon *c2 = *(PClassWeapon **)b;
|
PClassActor *c2 = *(PClassActor **)b;
|
||||||
int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2;
|
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;
|
int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2;
|
||||||
if (g1 != g2)
|
if (g1 != g2)
|
||||||
|
@ -1540,24 +1508,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo)
|
||||||
void P_ReadDemoWeaponsChunk(BYTE **demo)
|
void P_ReadDemoWeaponsChunk(BYTE **demo)
|
||||||
{
|
{
|
||||||
int count, i;
|
int count, i;
|
||||||
PClassWeapon *type;
|
PClassActor *type;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
count = ReadWord(demo);
|
count = ReadWord(demo);
|
||||||
Weapons_ntoh.Resize(count);
|
Weapons_ntoh.Resize(count);
|
||||||
Weapons_hton.Clear(count);
|
Weapons_hton.Clear(count);
|
||||||
|
|
||||||
Weapons_ntoh[0] = type = NULL;
|
Weapons_ntoh[0] = type = nullptr;
|
||||||
Weapons_hton[type] = 0;
|
Weapons_hton[type] = 0;
|
||||||
|
|
||||||
for (i = 1; i < count; ++i)
|
for (i = 1; i < count; ++i)
|
||||||
{
|
{
|
||||||
s = ReadStringConst(demo);
|
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,
|
// If a demo was recorded with a weapon that is no longer present,
|
||||||
// should we report it?
|
// should we report it?
|
||||||
Weapons_ntoh[i] = type;
|
Weapons_ntoh[i] = type;
|
||||||
if (type != NULL)
|
if (type != nullptr)
|
||||||
{
|
{
|
||||||
Weapons_hton[type] = i;
|
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;
|
int index, *index_p;
|
||||||
|
|
||||||
index_p = Weapons_hton.CheckKey(type);
|
index_p = Weapons_hton.CheckKey(type);
|
||||||
if (index_p == NULL)
|
if (index_p == nullptr)
|
||||||
{
|
{
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
@ -1602,7 +1570,7 @@ void Net_WriteWeapon(PClassWeapon *type)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
PClassWeapon *Net_ReadWeapon(BYTE **stream)
|
PClassActor *Net_ReadWeapon(BYTE **stream)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
@ -1613,7 +1581,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream)
|
||||||
}
|
}
|
||||||
if ((unsigned)index >= Weapons_ntoh.Size())
|
if ((unsigned)index >= Weapons_ntoh.Size())
|
||||||
{
|
{
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Weapons_ntoh[index];
|
return Weapons_ntoh[index];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "a_pickups.h"
|
#include "a_pickups.h"
|
||||||
class PClassWeapon;
|
class PClassActor;
|
||||||
class AWeapon;
|
class AWeapon;
|
||||||
|
|
||||||
class FWeaponSlot
|
class FWeaponSlot
|
||||||
|
@ -12,13 +12,13 @@ public:
|
||||||
FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; }
|
FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; }
|
||||||
void Clear() { Weapons.Clear(); }
|
void Clear() { Weapons.Clear(); }
|
||||||
bool AddWeapon (const char *type);
|
bool AddWeapon (const char *type);
|
||||||
bool AddWeapon (PClassWeapon *type);
|
bool AddWeapon (PClassActor *type);
|
||||||
void AddWeaponList (const char *list, bool clear);
|
void AddWeaponList (const char *list, bool clear);
|
||||||
AWeapon *PickWeapon (player_t *player, bool checkammo = false);
|
AWeapon *PickWeapon (player_t *player, bool checkammo = false);
|
||||||
int Size () const { return (int)Weapons.Size(); }
|
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())
|
if ((unsigned)index < Weapons.Size())
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ public:
|
||||||
private:
|
private:
|
||||||
struct WeaponInfo
|
struct WeaponInfo
|
||||||
{
|
{
|
||||||
PClassWeapon *Type;
|
PClassActor *Type;
|
||||||
int Position;
|
int Position;
|
||||||
};
|
};
|
||||||
void SetInitialPositions();
|
void SetInitialPositions();
|
||||||
|
@ -61,59 +61,45 @@ struct FWeaponSlots
|
||||||
AWeapon *PickPrevWeapon (player_t *player);
|
AWeapon *PickPrevWeapon (player_t *player);
|
||||||
|
|
||||||
void Clear ();
|
void Clear ();
|
||||||
bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index);
|
bool LocateWeapon (PClassActor *type, int *const slot, int *const index);
|
||||||
ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type);
|
ESlotDef AddDefaultWeapon (int slot, PClassActor *type);
|
||||||
void AddExtraWeapons();
|
void AddExtraWeapons();
|
||||||
void SetFromGameInfo();
|
void SetFromGameInfo();
|
||||||
void SetFromPlayer(PClassPlayerPawn *type);
|
void SetFromPlayer(PClassActor *type);
|
||||||
void StandardSetup(PClassPlayerPawn *type);
|
void StandardSetup(PClassActor *type);
|
||||||
void LocalSetup(PClassActor *type);
|
void LocalSetup(PClassActor *type);
|
||||||
void SendDifferences(int playernum, const FWeaponSlots &other);
|
void SendDifferences(int playernum, const FWeaponSlots &other);
|
||||||
int RestoreSlots (FConfigFile *config, const char *section);
|
int RestoreSlots (FConfigFile *config, const char *section);
|
||||||
void PrintSettings();
|
void PrintSettings();
|
||||||
|
|
||||||
void AddSlot(int slot, PClassWeapon *type, bool feedback);
|
void AddSlot(int slot, PClassActor *type, bool feedback);
|
||||||
void AddSlotDefault(int slot, PClassWeapon *type, bool feedback);
|
void AddSlotDefault(int slot, PClassActor *type, bool feedback);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void P_PlaybackKeyConfWeapons(FWeaponSlots *slots);
|
void P_PlaybackKeyConfWeapons(FWeaponSlots *slots);
|
||||||
void Net_WriteWeapon(PClassWeapon *type);
|
void Net_WriteWeapon(PClassActor *type);
|
||||||
PClassWeapon *Net_ReadWeapon(BYTE **stream);
|
PClassActor *Net_ReadWeapon(BYTE **stream);
|
||||||
|
|
||||||
void P_SetupWeapons_ntohton();
|
void P_SetupWeapons_ntohton();
|
||||||
void P_WriteDemoWeaponsChunk(BYTE **demo);
|
void P_WriteDemoWeaponsChunk(BYTE **demo);
|
||||||
void P_ReadDemoWeaponsChunk(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
|
class AWeapon : public AStateProvider
|
||||||
{
|
{
|
||||||
DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon)
|
DECLARE_CLASS(AWeapon, AStateProvider)
|
||||||
HAS_OBJECT_POINTERS
|
HAS_OBJECT_POINTERS
|
||||||
public:
|
public:
|
||||||
DWORD WeaponFlags;
|
DWORD WeaponFlags;
|
||||||
PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
|
PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
|
||||||
int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
|
int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
|
||||||
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
|
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
|
||||||
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
|
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
|
||||||
int Kickback;
|
int Kickback;
|
||||||
float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double)
|
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
|
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 *ProjectileType; // Projectile used by primary attack
|
||||||
PClassActor *AltProjectileType; // Projectile used by alternate attack
|
PClassActor *AltProjectileType; // Projectile used by alternate attack
|
||||||
int SelectionOrder; // Lower-numbered weapons get picked first
|
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)
|
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 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.
|
float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
|
||||||
|
int SlotNumber;
|
||||||
|
int SlotPriority;
|
||||||
|
|
||||||
// In-inventory instance variables
|
// In-inventory instance variables
|
||||||
TObjPtr<AInventory> Ammo1, Ammo2;
|
TObjPtr<AInventory> Ammo1, Ammo2;
|
||||||
|
@ -135,7 +123,8 @@ public:
|
||||||
|
|
||||||
virtual void MarkPrecacheSounds() const;
|
virtual void MarkPrecacheSounds() const;
|
||||||
|
|
||||||
virtual void Serialize(FSerializer &arc) override;
|
void Finalize(FStateDefinitions &statedef) override;
|
||||||
|
void Serialize(FSerializer &arc) override;
|
||||||
|
|
||||||
void PostMorphWeapon();
|
void PostMorphWeapon();
|
||||||
|
|
||||||
|
|
|
@ -20,3 +20,4 @@
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
|
@ -42,7 +42,7 @@ void A_Unblock(AActor *self, bool drop)
|
||||||
// If the actor has attached metadata for items to drop, drop those.
|
// If the actor has attached metadata for items to drop, drop those.
|
||||||
if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
|
if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
|
||||||
{
|
{
|
||||||
DDropItem *di = self->GetDropItems();
|
auto di = self->GetDropItems();
|
||||||
|
|
||||||
if (di != NULL)
|
if (di != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ void InitAllPowerupEffects(AInventory *item);
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash)
|
bool P_MorphPlayer (player_t *activator, player_t *p, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash)
|
||||||
{
|
{
|
||||||
AInventory *item;
|
AInventory *item;
|
||||||
APlayerPawn *morphed;
|
APlayerPawn *morphed;
|
||||||
|
@ -290,8 +290,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
||||||
// and for the original DOOM status bar.
|
// and for the original DOOM status bar.
|
||||||
if (player == &players[consoleplayer])
|
if (player == &players[consoleplayer])
|
||||||
{
|
{
|
||||||
FString face = pmo->GetClass()->Face;
|
FName face = pmo->Face;
|
||||||
if (face.IsNotEmpty() && strcmp(face, "None") != 0)
|
if (face != NAME_None)
|
||||||
{
|
{
|
||||||
// Assume root-level base skin to begin with
|
// Assume root-level base skin to begin with
|
||||||
size_t skinindex = 0;
|
size_t skinindex = 0;
|
||||||
|
@ -337,7 +337,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
||||||
if (correctweapon)
|
if (correctweapon)
|
||||||
{ // Better "lose morphed weapon" semantics
|
{ // Better "lose morphed weapon" semantics
|
||||||
PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon);
|
PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon);
|
||||||
if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (morphweapon != nullptr && morphweapon->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon));
|
AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon));
|
||||||
if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon))
|
if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon))
|
||||||
|
@ -367,7 +367,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
||||||
if (hxarmor != nullptr)
|
if (hxarmor != nullptr)
|
||||||
{
|
{
|
||||||
double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
|
double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
Slots[4] = mo->GetClass()->HexenArmor[0];
|
Slots[4] = mo->HexenArmor[0];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class AActor;
|
||||||
class player_t;
|
class player_t;
|
||||||
class AMorphedMonster;
|
class AMorphedMonster;
|
||||||
|
|
||||||
bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0,
|
bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0,
|
||||||
PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL);
|
PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL);
|
||||||
bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false);
|
bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false);
|
||||||
bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0,
|
bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0,
|
||||||
|
|
|
@ -122,16 +122,6 @@ static int statspace;
|
||||||
DVector2 AM_GetPosition();
|
DVector2 AM_GetPosition();
|
||||||
int active_con_scaletext();
|
int active_con_scaletext();
|
||||||
|
|
||||||
FTextureID GetHUDIcon(PClassInventory *cls)
|
|
||||||
{
|
|
||||||
return cls->AltHUDIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetHUDIcon(PClassInventory *cls, FTextureID tex)
|
|
||||||
{
|
|
||||||
cls->AltHUDIcon = tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Draws an image into a box with its bottom center at the bottom
|
// Draws an image into a box with its bottom center at the bottom
|
||||||
|
@ -437,7 +427,7 @@ static void SetKeyTypes()
|
||||||
static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv)
|
static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv)
|
||||||
{
|
{
|
||||||
FTextureID icon = FNullTextureID();
|
FTextureID icon = FNullTextureID();
|
||||||
FTextureID AltIcon = GetHUDIcon(inv->GetClass());
|
FTextureID AltIcon = inv->AltHUDIcon;
|
||||||
|
|
||||||
if (!AltIcon.Exists()) return;
|
if (!AltIcon.Exists()) return;
|
||||||
|
|
||||||
|
@ -516,27 +506,27 @@ static int DrawKeys(player_t * CPlayer, int x, int y)
|
||||||
// Drawing Ammo
|
// Drawing Ammo
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
static TArray<PClassInventory *> orderedammos;
|
static TArray<PClassActor *> orderedammos;
|
||||||
|
|
||||||
static void AddAmmoToList(AWeapon * weapdef)
|
static void AddAmmoToList(AWeapon * weapdef)
|
||||||
{
|
{
|
||||||
|
|
||||||
for(int i=0; i<2;i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2;
|
auto ti = i == 0 ? weapdef->AmmoType1 : weapdef->AmmoType2;
|
||||||
if (ti)
|
if (ti)
|
||||||
{
|
{
|
||||||
auto ammodef=(AInventory*)GetDefaultByType(ti);
|
auto ammodef = (AInventory*)GetDefaultByType(ti);
|
||||||
|
|
||||||
if (ammodef && !(ammodef->ItemFlags&IF_INVBAR))
|
if (ammodef && !(ammodef->ItemFlags&IF_INVBAR))
|
||||||
{
|
{
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
|
||||||
for(j=0;j<orderedammos.Size();j++)
|
for (j = 0; j < orderedammos.Size(); j++)
|
||||||
{
|
{
|
||||||
if (ti == orderedammos[j]) break;
|
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
|
// Now check for the remaining weapons that are in the inventory but not in the weapon slots
|
||||||
for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory)
|
for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory)
|
||||||
{
|
{
|
||||||
if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
if (inv->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
AddAmmoToList((AWeapon*)inv);
|
AddAmmoToList((AWeapon*)inv);
|
||||||
}
|
}
|
||||||
|
@ -646,11 +636,11 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
|
||||||
for(i=orderedammos.Size()-1;i>=0;i--)
|
for(i=orderedammos.Size()-1;i>=0;i--)
|
||||||
{
|
{
|
||||||
|
|
||||||
PClassInventory * type = orderedammos[i];
|
auto type = orderedammos[i];
|
||||||
auto ammoitem = CPlayer->mo->FindInventory(type);
|
auto ammoitem = CPlayer->mo->FindInventory(type);
|
||||||
|
|
||||||
auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
|
auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
|
||||||
FTextureID AltIcon = GetHUDIcon(type);
|
FTextureID AltIcon = inv->AltHUDIcon;
|
||||||
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
|
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
|
||||||
if (!icon.isValid()) continue;
|
if (!icon.isValid()) continue;
|
||||||
|
|
||||||
|
@ -682,7 +672,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO
|
FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO
|
||||||
{
|
{
|
||||||
FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass());
|
FTextureID picnum, AltIcon = item->AltHUDIcon;
|
||||||
FState * state=NULL, *ReadyState;
|
FState * state=NULL, *ReadyState;
|
||||||
|
|
||||||
picnum.SetNull();
|
picnum.SetNull();
|
||||||
|
@ -713,7 +703,7 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no spawn state - now try the ready state if it's weapon
|
// no spawn state - now try the ready state if it's weapon
|
||||||
else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0)
|
else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0)
|
||||||
{
|
{
|
||||||
state = ReadyState;
|
state = ReadyState;
|
||||||
}
|
}
|
||||||
|
@ -767,7 +757,7 @@ static void DrawWeapons(player_t *CPlayer, int x, int y)
|
||||||
// First draw all weapons in the inventory that are not assigned to a weapon slot
|
// First draw all weapons in the inventory that are not assigned to a weapon slot
|
||||||
for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory)
|
for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory)
|
||||||
{
|
{
|
||||||
if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) &&
|
if (inv->IsKindOf(NAME_Weapon) &&
|
||||||
!CPlayer->weapons.LocateWeapon(static_cast<AWeapon*>(inv)->GetClass(), NULL, NULL))
|
!CPlayer->weapons.LocateWeapon(static_cast<AWeapon*>(inv)->GetClass(), NULL, NULL))
|
||||||
{
|
{
|
||||||
DrawOneWeapon(CPlayer, x, y, static_cast<AWeapon*>(inv));
|
DrawOneWeapon(CPlayer, x, y, static_cast<AWeapon*>(inv));
|
||||||
|
@ -816,7 +806,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y)
|
||||||
{
|
{
|
||||||
if (rover->Amount>0)
|
if (rover->Amount>0)
|
||||||
{
|
{
|
||||||
FTextureID AltIcon = GetHUDIcon(rover->GetClass());
|
FTextureID AltIcon = rover->AltHUDIcon;
|
||||||
|
|
||||||
if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) )
|
if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) )
|
||||||
{
|
{
|
||||||
|
@ -1285,7 +1275,7 @@ void HUD_InitHud()
|
||||||
}
|
}
|
||||||
else tex.SetInvalid();
|
else tex.SetInvalid();
|
||||||
|
|
||||||
if (ti) SetHUDIcon(static_cast<PClassInventory*>(ti), tex);
|
if (ti) ((AInventory*)GetDefaultByType(ti))->AltHUDIcon = tex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu
|
||||||
if (CurrentState != NULL)
|
if (CurrentState != NULL)
|
||||||
{
|
{
|
||||||
int skin = player->userinfo.GetSkin();
|
int skin = player->userinfo.GetSkin();
|
||||||
const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? player->MorphedPlayerClass->Face.GetChars() : skins[skin].face);
|
const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face);
|
||||||
return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle);
|
return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -148,7 +148,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
|
||||||
{
|
{
|
||||||
type = INVENTORYICON;
|
type = INVENTORYICON;
|
||||||
const PClass* item = PClass::FindClass(sc.String);
|
const PClass* item = PClass::FindClass(sc.String);
|
||||||
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory
|
if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
||||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||||
{
|
{
|
||||||
PClassActor *cls = PClassActor::AllActorClasses[i];
|
PClassActor *cls = PClassActor::AllActorClasses[i];
|
||||||
if (cls->IsDescendantOf(PClass::FindActor(NAME_Key)))
|
if (cls->IsDescendantOf(NAME_Key))
|
||||||
{
|
{
|
||||||
auto key = GetDefaultByType(cls);
|
auto key = GetDefaultByType(cls);
|
||||||
if (key->special1 == keynum)
|
if (key->special1 == keynum)
|
||||||
|
@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
||||||
{
|
{
|
||||||
inventoryItem[0] = sc.String;
|
inventoryItem[0] = sc.String;
|
||||||
const PClass* item = PClass::FindClass(sc.String);
|
const PClass* item = PClass::FindClass(sc.String);
|
||||||
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory
|
if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
inventoryItem[1] = sc.String;
|
inventoryItem[1] = sc.String;
|
||||||
const PClass* item = PClass::FindClass(sc.String);
|
const PClass* item = PClass::FindClass(sc.String);
|
||||||
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory
|
if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -556,7 +556,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
||||||
|
|
||||||
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
||||||
{
|
{
|
||||||
if(item->IsKindOf(PClass::FindActor(NAME_Key)))
|
if(item->IsKindOf(NAME_Key))
|
||||||
{
|
{
|
||||||
int keynum = item->special1;
|
int keynum = item->special1;
|
||||||
if(keynum)
|
if(keynum)
|
||||||
|
@ -1078,7 +1078,7 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
inventoryItem = PClass::FindActor(sc.String);
|
inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
if(inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||||
inventoryItem = PClass::FindActor(NAME_Ammo);
|
inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||||
|
@ -1094,7 +1094,7 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
inventoryItem = PClass::FindActor(sc.String);
|
inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||||
inventoryItem = PClass::FindActor(NAME_Ammo);
|
inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||||
|
@ -1160,7 +1160,7 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
inventoryItem = PClass::FindActor(sc.String);
|
inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem))
|
if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||||
inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||||
|
@ -1203,7 +1203,7 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
if(value == INVENTORY)
|
if(value == INVENTORY)
|
||||||
{
|
{
|
||||||
inventoryItem = PClass::FindActor(sc.String);
|
inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Inventory))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
inventoryItem = RUNTIME_CLASS(AInventory);
|
inventoryItem = RUNTIME_CLASS(AInventory);
|
||||||
|
@ -1476,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
num = 0;
|
num = 0;
|
||||||
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
||||||
{
|
{
|
||||||
if(item->IsKindOf(PClass::FindActor(NAME_Key)))
|
if(item->IsKindOf(NAME_Key))
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2431,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand
|
||||||
int rowWidth = 0;
|
int rowWidth = 0;
|
||||||
for(unsigned int i = 0;i < number+keyOffset;i++)
|
for(unsigned int i = 0;i < number+keyOffset;i++)
|
||||||
{
|
{
|
||||||
while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key)))
|
while(!item->Icon.isValid() || !item->IsKindOf(NAME_Key))
|
||||||
{
|
{
|
||||||
item = item->Inventory;
|
item = item->Inventory;
|
||||||
if(item == NULL)
|
if(item == NULL)
|
||||||
|
@ -2632,7 +2632,7 @@ class CommandDrawBar : public SBarInfoCommand
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
type = AMMO;
|
type = AMMO;
|
||||||
data.inventoryItem = PClass::FindActor(sc.String);
|
data.inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo
|
if (data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||||
data.inventoryItem = PClass::FindActor(NAME_Ammo);
|
data.inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||||
|
@ -2660,7 +2660,7 @@ class CommandDrawBar : public SBarInfoCommand
|
||||||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
data.inventoryItem = PClass::FindActor(sc.String);
|
data.inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem))
|
if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||||
data.inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
data.inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||||
|
@ -2672,7 +2672,7 @@ class CommandDrawBar : public SBarInfoCommand
|
||||||
{
|
{
|
||||||
type = INVENTORY;
|
type = INVENTORY;
|
||||||
data.inventoryItem = PClass::FindActor(sc.String);
|
data.inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem))
|
if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
data.inventoryItem = RUNTIME_CLASS(AInventory);
|
data.inventoryItem = RUNTIME_CLASS(AInventory);
|
||||||
|
@ -2894,7 +2894,7 @@ class CommandDrawBar : public SBarInfoCommand
|
||||||
if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference
|
if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference
|
||||||
{
|
{
|
||||||
data.inventoryItem = PClass::FindActor(sc.String);
|
data.inventoryItem = PClass::FindActor(sc.String);
|
||||||
if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory
|
if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) //must be a kind of inventory
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
data.inventoryItem = RUNTIME_CLASS(AInventory);
|
data.inventoryItem = RUNTIME_CLASS(AInventory);
|
||||||
|
@ -2977,7 +2977,7 @@ class CommandIsSelected : public SBarInfoNegatableFlowControl
|
||||||
for(int i = 0;i < 2;i++)
|
for(int i = 0;i < 2;i++)
|
||||||
{
|
{
|
||||||
weapon[i] = PClass::FindClass(sc.String);
|
weapon[i] = PClass::FindClass(sc.String);
|
||||||
if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i]))
|
if(weapon[i] == NULL || !weapon[i]->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of weapon.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of weapon.", sc.String);
|
||||||
weapon[i] = RUNTIME_CLASS(AWeapon);
|
weapon[i] = RUNTIME_CLASS(AWeapon);
|
||||||
|
@ -3130,7 +3130,7 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
|
||||||
if(!sc.CheckToken(TK_StringConst))
|
if(!sc.CheckToken(TK_StringConst))
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
weapon = PClass::FindClass(sc.String);
|
weapon = PClass::FindClass(sc.String);
|
||||||
if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon
|
if (weapon == NULL || !weapon->IsDescendantOf(NAME_Weapon)) //must be a weapon
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("%s is not a kind of weapon.", sc.String);
|
sc.ScriptMessage("%s is not a kind of weapon.", sc.String);
|
||||||
weapon = RUNTIME_CLASS(AWeapon);
|
weapon = RUNTIME_CLASS(AWeapon);
|
||||||
|
@ -3317,7 +3317,7 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl
|
||||||
for(int i = 0;i < 2;i++)
|
for(int i = 0;i < 2;i++)
|
||||||
{
|
{
|
||||||
ammo[i] = PClass::FindClass(sc.String);
|
ammo[i] = PClass::FindClass(sc.String);
|
||||||
if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo
|
if(ammo[i] == NULL || !ammo[i]->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||||
ammo[i] = PClass::FindActor(NAME_Ammo);
|
ammo[i] = PClass::FindActor(NAME_Ammo);
|
||||||
|
@ -3400,7 +3400,7 @@ class CommandInInventory : public SBarInfoNegatableFlowControl
|
||||||
for(int i = 0;i < 2;i++)
|
for(int i = 0;i < 2;i++)
|
||||||
{
|
{
|
||||||
item[i] = PClass::FindActor(sc.String);
|
item[i] = PClass::FindActor(sc.String);
|
||||||
if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i]))
|
if (item[i] == NULL || !item[i]->IsDescendantOf(NAME_Inventory)) //must be a kind of ammo
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||||
item[i] = RUNTIME_CLASS(AInventory);
|
item[i] = RUNTIME_CLASS(AInventory);
|
||||||
|
|
|
@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox();
|
||||||
inline PClassActor * GetRealType(PClassActor * ti)
|
inline PClassActor * GetRealType(PClassActor * ti)
|
||||||
{
|
{
|
||||||
PClassActor *rep = ti->GetReplacement(false);
|
PClassActor *rep = ti->GetReplacement(false);
|
||||||
if (rep != ti && rep != NULL && rep->IsDescendantOf(PClass::FindActor(NAME_DehackedPickup)))
|
if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup))
|
||||||
{
|
{
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
|
@ -787,6 +787,10 @@ void gl_InitModels()
|
||||||
map[c]=1;
|
map[c]=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (sc.Compare("dontcullbackfaces"))
|
||||||
|
{
|
||||||
|
smf.flags |= MDL_DONTCULLBACKFACES;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("Unrecognized string \"%s\"", sc.String);
|
sc.ScriptMessage("Unrecognized string \"%s\"", sc.String);
|
||||||
|
@ -949,8 +953,9 @@ void gl_RenderModel(GLSprite * spr)
|
||||||
gl_RenderState.EnableTexture(true);
|
gl_RenderState.EnableTexture(true);
|
||||||
// [BB] In case the model should be rendered translucent, do back face culling.
|
// [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.
|
// 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.
|
// 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);
|
glEnable(GL_CULL_FACE);
|
||||||
glFrontFace(GL_CW);
|
glFrontFace(GL_CW);
|
||||||
|
@ -1012,6 +1017,9 @@ void gl_RenderModel(GLSprite * spr)
|
||||||
// Model space => World space
|
// Model space => World space
|
||||||
gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y );
|
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)
|
if (spr->actor->renderflags & RF_INTERPOLATEANGLES)
|
||||||
{
|
{
|
||||||
// [Nash] use interpolated angles
|
// [Nash] use interpolated angles
|
||||||
|
|
|
@ -370,6 +370,7 @@ enum
|
||||||
MDL_USEACTORPITCH = 32,
|
MDL_USEACTORPITCH = 32,
|
||||||
MDL_USEACTORROLL = 64,
|
MDL_USEACTORROLL = 64,
|
||||||
MDL_BADROTATION = 128,
|
MDL_BADROTATION = 128,
|
||||||
|
MDL_DONTCULLBACKFACES = 256,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FSpriteModelFrame
|
struct FSpriteModelFrame
|
||||||
|
|
|
@ -866,6 +866,14 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
|
||||||
// This should be done after postprocessing, not before.
|
// This should be done after postprocessing, not before.
|
||||||
mBuffers->BindCurrentFB();
|
mBuffers->BindCurrentFB();
|
||||||
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
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);
|
DrawBlend(lviewsector);
|
||||||
}
|
}
|
||||||
mDrawingScene2D = false;
|
mDrawingScene2D = false;
|
||||||
|
|
74
src/info.cpp
74
src/info.cpp
|
@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
|
||||||
const char *callinfo = "";
|
const char *callinfo = "";
|
||||||
if (info != nullptr && info->mStateType == STATE_Psprite)
|
if (info != nullptr && info->mStateType == STATE_Psprite)
|
||||||
{
|
{
|
||||||
if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon ";
|
if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon ";
|
||||||
else callinfo = "overlay ";
|
else callinfo = "overlay ";
|
||||||
}
|
}
|
||||||
err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars());
|
err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars());
|
||||||
|
@ -176,11 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex)
|
||||||
ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false));
|
ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PClassActor, false, true)
|
IMPLEMENT_CLASS(PClassActor, false, false)
|
||||||
|
|
||||||
IMPLEMENT_POINTERS_START(PClassActor)
|
|
||||||
IMPLEMENT_POINTER(DropItems)
|
|
||||||
IMPLEMENT_POINTERS_END
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -349,32 +345,12 @@ void PClassActor::DeriveData(PClass *newclass)
|
||||||
*newa->PainChances = *PainChances;
|
*newa->PainChances = *PainChances;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// Inventory stuff
|
||||||
|
newa->PickupMsg = PickupMsg;
|
||||||
|
newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass;
|
||||||
|
newa->RestrictedToPlayerClass = RestrictedToPlayerClass;
|
||||||
|
|
||||||
//==========================================================================
|
newa->DisplayName = DisplayName;
|
||||||
//
|
|
||||||
// PClassActor :: PropagateMark
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
size_t PClassActor::PropagateMark()
|
|
||||||
{
|
|
||||||
// Mark state functions
|
|
||||||
for (int i = 0; i < NumOwnedStates; ++i)
|
|
||||||
{
|
|
||||||
if (OwnedStates[i].ActionFunc != NULL)
|
|
||||||
{
|
|
||||||
GC::Mark(OwnedStates[i].ActionFunc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Mark damage function
|
|
||||||
if (Defaults != NULL)
|
|
||||||
{
|
|
||||||
GC::Mark(((AActor *)Defaults)->DamageFunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// marked += ActorInfo->NumOwnedStates * sizeof(FState);
|
|
||||||
return Super::PropagateMark();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -414,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void PClassActor::SetDropItems(DDropItem *drops)
|
void PClassActor::SetDropItems(FDropItem *drops)
|
||||||
{
|
{
|
||||||
DropItems = drops;
|
DropItems = drops;
|
||||||
GC::WriteBarrier(this, DropItems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
try
|
||||||
{
|
{
|
||||||
statedef.FinishStates(this, defaults);
|
statedef.FinishStates(GetClass(), defaults);
|
||||||
}
|
}
|
||||||
catch (CRecoverableError &)
|
catch (CRecoverableError &)
|
||||||
{
|
{
|
||||||
statedef.MakeStateDefines(NULL);
|
statedef.MakeStateDefines(NULL);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
statedef.InstallStates(this, defaults);
|
statedef.InstallStates(GetClass(), defaults);
|
||||||
statedef.MakeStateDefines(NULL);
|
statedef.MakeStateDefines(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,10 +634,33 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass)
|
||||||
{
|
{
|
||||||
if (VisibleToPlayerClass[i] == oldclass)
|
if (VisibleToPlayerClass[i] == oldclass)
|
||||||
{
|
{
|
||||||
VisibleToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
|
VisibleToPlayerClass[i] = static_cast<PClassActor*>(newclass);
|
||||||
changed++;
|
changed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++)
|
||||||
|
{
|
||||||
|
if (ForbiddenToPlayerClass[i] == oldclass)
|
||||||
|
{
|
||||||
|
ForbiddenToPlayerClass[i] = static_cast<PClassActor*>(newclass);
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++)
|
||||||
|
{
|
||||||
|
if (RestrictedToPlayerClass[i] == oldclass)
|
||||||
|
{
|
||||||
|
RestrictedToPlayerClass[i] = static_cast<PClassActor*>(newclass);
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AInventory *def = dyn_cast<AInventory>((AActor*)Defaults);
|
||||||
|
if (def != NULL)
|
||||||
|
{
|
||||||
|
if (def->PickupFlash == oldclass) def->PickupFlash = static_cast<PClassActor *>(newclass);
|
||||||
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/info.h
20
src/info.h
|
@ -234,13 +234,11 @@ private:
|
||||||
static DamageTypeDefinition *Get(FName type);
|
static DamageTypeDefinition *Get(FName type);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DDropItem;
|
struct FDropItem;
|
||||||
class PClassPlayerPawn;
|
|
||||||
|
|
||||||
class PClassActor : public PClass
|
class PClassActor : public PClass
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PClassActor, PClass);
|
DECLARE_CLASS(PClassActor, PClass);
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
protected:
|
protected:
|
||||||
public:
|
public:
|
||||||
static void StaticInit ();
|
static void StaticInit ();
|
||||||
|
@ -256,10 +254,8 @@ public:
|
||||||
void RegisterIDs();
|
void RegisterIDs();
|
||||||
void SetDamageFactor(FName type, double factor);
|
void SetDamageFactor(FName type, double factor);
|
||||||
void SetPainChance(FName type, int chance);
|
void SetPainChance(FName type, int chance);
|
||||||
size_t PropagateMark();
|
|
||||||
bool SetReplacement(FName replaceName);
|
bool SetReplacement(FName replaceName);
|
||||||
void SetDropItems(DDropItem *drops);
|
void SetDropItems(FDropItem *drops);
|
||||||
virtual void Finalize(FStateDefinitions &statedef);
|
|
||||||
|
|
||||||
FState *FindState(int numnames, FName *names, bool exact=false) const;
|
FState *FindState(int numnames, FName *names, bool exact=false) const;
|
||||||
FState *FindStateByString(const char *name, bool exact=false);
|
FState *FindStateByString(const char *name, bool exact=false);
|
||||||
|
@ -289,7 +285,7 @@ public:
|
||||||
DmgFactors *DamageFactors;
|
DmgFactors *DamageFactors;
|
||||||
PainChanceList *PainChances;
|
PainChanceList *PainChances;
|
||||||
|
|
||||||
TArray<PClassPlayerPawn *> VisibleToPlayerClass;
|
TArray<PClassActor *> VisibleToPlayerClass;
|
||||||
|
|
||||||
FString Obituary; // Player was killed by this actor
|
FString Obituary; // Player was killed by this actor
|
||||||
FString HitObituary; // Player was killed by this actor in melee
|
FString HitObituary; // Player was killed by this actor in melee
|
||||||
|
@ -306,7 +302,7 @@ public:
|
||||||
FName BloodType2; // Bloopsplatter replacement type
|
FName BloodType2; // Bloopsplatter replacement type
|
||||||
FName BloodType3; // AxeBlood replacement type
|
FName BloodType3; // AxeBlood replacement type
|
||||||
|
|
||||||
DDropItem *DropItems;
|
FDropItem *DropItems;
|
||||||
FString SourceLumpName;
|
FString SourceLumpName;
|
||||||
FIntCVar *distancecheck;
|
FIntCVar *distancecheck;
|
||||||
|
|
||||||
|
@ -319,6 +315,14 @@ public:
|
||||||
FName MissileName;
|
FName MissileName;
|
||||||
double MissileHeight;
|
double MissileHeight;
|
||||||
|
|
||||||
|
// These are only valid for inventory items.
|
||||||
|
FString PickupMsg;
|
||||||
|
TArray<PClassActor *> RestrictedToPlayerClass;
|
||||||
|
TArray<PClassActor *> ForbiddenToPlayerClass;
|
||||||
|
|
||||||
|
// This is from PClassPlayerPawn
|
||||||
|
FString DisplayName;
|
||||||
|
|
||||||
// For those times when being able to scan every kind of actor is convenient
|
// For those times when being able to scan every kind of actor is convenient
|
||||||
static TArray<PClassActor *> AllActorClasses;
|
static TArray<PClassActor *> AllActorClasses;
|
||||||
};
|
};
|
||||||
|
|
|
@ -171,7 +171,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHT_MORPH:
|
case CHT_MORPH:
|
||||||
msg = cht_Morph (player, static_cast<PClassPlayerPawn *>(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true);
|
msg = cht_Morph (player, PClass::FindActor (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHT_NOTARGET:
|
case CHT_NOTARGET:
|
||||||
|
@ -318,7 +318,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
case CHT_RESSURECT:
|
case CHT_RESSURECT:
|
||||||
if (player->playerstate != PST_LIVE && player->mo != nullptr)
|
if (player->playerstate != PST_LIVE && player->mo != nullptr)
|
||||||
{
|
{
|
||||||
if (player->mo->IsKindOf(PClass::FindActor("PlayerChunk")))
|
if (player->mo->IsKindOf("PlayerChunk"))
|
||||||
{
|
{
|
||||||
Printf("Unable to resurrect. Player is no longer connected to its body.\n");
|
Printf("Unable to resurrect. Player is no longer connected to its body.\n");
|
||||||
}
|
}
|
||||||
|
@ -422,7 +422,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
{
|
{
|
||||||
lastinvp = invp;
|
lastinvp = invp;
|
||||||
invp = &(*invp)->Inventory;
|
invp = &(*invp)->Inventory;
|
||||||
if (item->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
if (item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
AWeapon *weap = static_cast<AWeapon *> (item);
|
AWeapon *weap = static_cast<AWeapon *> (item);
|
||||||
if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) ||
|
if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) ||
|
||||||
|
@ -549,13 +549,13 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg);
|
Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo)
|
const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo)
|
||||||
{
|
{
|
||||||
if (player->mo == NULL)
|
if (player->mo == NULL)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
PClassPlayerPawn *oldclass = player->mo->GetClass();
|
auto oldclass = player->mo->GetClass();
|
||||||
|
|
||||||
// Set the standard morph style for the current game
|
// Set the standard morph style for the current game
|
||||||
int style = MORPH_UNDOBYTOMEOFPOWER;
|
int style = MORPH_UNDOBYTOMEOFPOWER;
|
||||||
|
|
|
@ -30,12 +30,12 @@
|
||||||
|
|
||||||
// [RH] Functions that actually perform the cheating
|
// [RH] Functions that actually perform the cheating
|
||||||
class player_t;
|
class player_t;
|
||||||
class PClassPlayerPawn;
|
class PClassActor;
|
||||||
|
|
||||||
void cht_DoCheat (player_t *player, int cheat);
|
void cht_DoCheat (player_t *player, int cheat);
|
||||||
void cht_Give (player_t *player, const char *item, int amount=1);
|
void cht_Give (player_t *player, const char *item, int amount=1);
|
||||||
void cht_Take (player_t *player, const char *item, int amount=1);
|
void cht_Take (player_t *player, const char *item, int amount=1);
|
||||||
void cht_Suicide (player_t *player);
|
void cht_Suicide (player_t *player);
|
||||||
const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo);
|
const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks()
|
||||||
FreeBlockChain(FreeBlocks);
|
FreeBlockChain(FreeBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FMemArena :: DumpInfo
|
||||||
|
//
|
||||||
|
// Prints some info about this arena
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FMemArena::DumpInfo()
|
||||||
|
{
|
||||||
|
size_t allocated = 0;
|
||||||
|
size_t used = 0;
|
||||||
|
for (auto block = TopBlock; block != NULL; block = block->NextBlock)
|
||||||
|
{
|
||||||
|
allocated += BlockSize;
|
||||||
|
used += BlockSize - ((char*)block->Limit - (char*)block->Avail);
|
||||||
|
}
|
||||||
|
Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FMemArena :: FreeBlockChain
|
// FMemArena :: FreeBlockChain
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
void *Alloc(size_t size);
|
void *Alloc(size_t size);
|
||||||
void FreeAll();
|
void FreeAll();
|
||||||
void FreeAllBlocks();
|
void FreeAllBlocks();
|
||||||
|
void DumpInfo();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct Block;
|
struct Block;
|
||||||
|
|
|
@ -435,7 +435,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation()
|
||||||
if (mPlayerClass != NULL)
|
if (mPlayerClass != NULL)
|
||||||
{
|
{
|
||||||
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0]));
|
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0]));
|
||||||
R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset),
|
R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset),
|
||||||
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
|
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,11 +557,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString portrait = mPlayerClass->Type->Portrait;
|
FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait;
|
||||||
|
|
||||||
if (portrait.IsNotEmpty() && !mNoportrait)
|
if (portrait != NAME_None && !mNoportrait)
|
||||||
{
|
{
|
||||||
FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch);
|
FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch);
|
||||||
if (texid.isValid())
|
if (texid.isValid())
|
||||||
{
|
{
|
||||||
FTexture *tex = TexMan(texid);
|
FTexture *tex = TexMan(texid);
|
||||||
|
|
|
@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation()
|
||||||
if (PlayerClass != NULL)
|
if (PlayerClass != NULL)
|
||||||
{
|
{
|
||||||
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0]));
|
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0]));
|
||||||
R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset),
|
R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset),
|
||||||
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
|
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets()
|
||||||
if (li != NULL)
|
if (li != NULL)
|
||||||
{
|
{
|
||||||
int sel = 0;
|
int sel = 0;
|
||||||
PlayerClass->Type->EnumColorSets(&PlayerColorSets);
|
EnumColorSets(PlayerClass->Type, &PlayerColorSets);
|
||||||
li->SetString(0, "Custom");
|
li->SetString(0, "Custom");
|
||||||
for(unsigned i=0;i<PlayerColorSets.Size(); i++)
|
for(unsigned i=0;i<PlayerColorSets.Size(); i++)
|
||||||
{
|
{
|
||||||
FPlayerColorSet *colorset = PlayerClass->Type->GetColorSet(PlayerColorSets[i]);
|
FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]);
|
||||||
li->SetString(i+1, colorset->Name);
|
li->SetString(i+1, colorset->Name);
|
||||||
}
|
}
|
||||||
int mycolorset = players[consoleplayer].userinfo.GetColorSet();
|
int mycolorset = players[consoleplayer].userinfo.GetColorSet();
|
||||||
|
@ -899,7 +899,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li)
|
||||||
players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1);
|
players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1);
|
||||||
PickPlayerClass();
|
PickPlayerClass();
|
||||||
|
|
||||||
cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->DisplayName.GetChars());
|
cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(PlayerClass->Type).GetChars());
|
||||||
|
|
||||||
UpdateSkins();
|
UpdateSkins();
|
||||||
UpdateColorsets();
|
UpdateColorsets();
|
||||||
|
|
|
@ -821,6 +821,8 @@ xx(DamageFunction)
|
||||||
xx(Length)
|
xx(Length)
|
||||||
xx(Unit)
|
xx(Unit)
|
||||||
xx(Size)
|
xx(Size)
|
||||||
|
xx(Copy)
|
||||||
|
xx(Move)
|
||||||
xx(Voidptr)
|
xx(Voidptr)
|
||||||
xx(StateLabel)
|
xx(StateLabel)
|
||||||
xx(SpriteID)
|
xx(SpriteID)
|
||||||
|
|
|
@ -858,7 +858,8 @@ void P_Spawn3DFloors (void)
|
||||||
{
|
{
|
||||||
case ExtraFloor_LightOnly:
|
case ExtraFloor_LightOnly:
|
||||||
if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0;
|
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;
|
break;
|
||||||
|
|
||||||
case Sector_Set3DFloor:
|
case Sector_Set3DFloor:
|
||||||
|
@ -877,7 +878,8 @@ void P_Spawn3DFloors (void)
|
||||||
line.args[4]=0;
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -114,13 +114,6 @@ FRandom pr_acs ("ACS");
|
||||||
#define HUDMSG_VISIBILITY_MASK (0x00070000)
|
#define HUDMSG_VISIBILITY_MASK (0x00070000)
|
||||||
// See HUDMSG visibility enumerations in sbar.h
|
// 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
|
// LineAttack flags
|
||||||
#define FHF_NORANDOMPUFFZ 1
|
#define FHF_NORANDOMPUFFZ 1
|
||||||
#define FHF_NOIMPACTDECAL 2
|
#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)
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||||
{
|
{
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
players[i].mo->GiveInventory(static_cast<PClassInventory *>(info), amount);
|
players[i].mo->GiveInventory(info, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
activator->GiveInventory(static_cast<PClassInventory *>(info), amount);
|
activator->GiveInventory(info, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force)
|
||||||
{
|
{
|
||||||
PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type));
|
PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type));
|
||||||
|
@ -5716,7 +5668,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
||||||
if (argCount >= 2)
|
if (argCount >= 2)
|
||||||
{
|
{
|
||||||
PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1]));
|
PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1]));
|
||||||
if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup)))
|
if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup))
|
||||||
{
|
{
|
||||||
Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1]));
|
Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1]));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -8352,9 +8304,14 @@ scriptwait:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_REPLACETEXTURES:
|
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;
|
sp -= 3;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PCD_SETLINEBLOCKING:
|
case PCD_SETLINEBLOCKING:
|
||||||
{
|
{
|
||||||
|
@ -9042,7 +8999,7 @@ scriptwait:
|
||||||
AInventory *item = activator->FindInventory (dyn_cast<PClassActor>(
|
AInventory *item = activator->FindInventory (dyn_cast<PClassActor>(
|
||||||
PClass::FindClass (FBehavior::StaticLookupString (STACK(1)))));
|
PClass::FindClass (FBehavior::StaticLookupString (STACK(1)))));
|
||||||
|
|
||||||
if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
if (item == NULL || !item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
STACK(1) = 0;
|
STACK(1) = 0;
|
||||||
}
|
}
|
||||||
|
@ -9110,7 +9067,7 @@ scriptwait:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine")))
|
if (activator != nullptr && activator->IsKindOf("ScriptedMarine"))
|
||||||
{
|
{
|
||||||
SetMarineSprite(activator, type);
|
SetMarineSprite(activator, type);
|
||||||
}
|
}
|
||||||
|
@ -9491,7 +9448,7 @@ scriptwait:
|
||||||
{
|
{
|
||||||
int tag = STACK(7);
|
int tag = STACK(7);
|
||||||
FName playerclass_name = FBehavior::StaticLookupString(STACK(6));
|
FName playerclass_name = FBehavior::StaticLookupString(STACK(6));
|
||||||
PClassPlayerPawn *playerclass = dyn_cast<PClassPlayerPawn>(PClass::FindClass (playerclass_name));
|
auto playerclass = PClass::FindActor (playerclass_name);
|
||||||
FName monsterclass_name = FBehavior::StaticLookupString(STACK(5));
|
FName monsterclass_name = FBehavior::StaticLookupString(STACK(5));
|
||||||
PClassActor *monsterclass = PClass::FindActor(monsterclass_name);
|
PClassActor *monsterclass = PClass::FindActor(monsterclass_name);
|
||||||
int duration = STACK(4);
|
int duration = STACK(4);
|
||||||
|
|
|
@ -913,7 +913,6 @@ protected:
|
||||||
static void ChangeFlat (int tag, int name, bool floorOrCeiling);
|
static void ChangeFlat (int tag, int name, bool floorOrCeiling);
|
||||||
static int CountPlayers ();
|
static int CountPlayers ();
|
||||||
static void SetLineTexture (int lineid, int side, int position, int name);
|
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, 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 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);
|
static bool DoCheckActorTexture(int tid, AActor *activator, int string, bool floor);
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "math/cmath.h"
|
#include "math/cmath.h"
|
||||||
#include "g_levellocals.h"
|
#include "g_levellocals.h"
|
||||||
|
#include "r_utility.h"
|
||||||
|
|
||||||
AActor *SingleActorFromTID(int tid, AActor *defactor);
|
AActor *SingleActorFromTID(int tid, AActor *defactor);
|
||||||
|
|
||||||
|
@ -2386,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (item->IsKindOf(PClass::FindActor(NAME_Health)))
|
if (item->IsKindOf(NAME_Health))
|
||||||
{
|
{
|
||||||
item->Amount *= amount;
|
item->Amount *= amount;
|
||||||
}
|
}
|
||||||
|
@ -3122,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon)
|
||||||
|
|
||||||
AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls));
|
AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls));
|
||||||
|
|
||||||
if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
if (self->player->ReadyWeapon != weaponitem)
|
if (self->player->ReadyWeapon != weaponitem)
|
||||||
{
|
{
|
||||||
|
@ -5011,7 +5012,7 @@ enum T_Flags
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
|
DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
|
||||||
{
|
{
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
PARAM_ACTION_PROLOGUE(AActor);
|
||||||
PARAM_STATE_DEF (teleport_state)
|
PARAM_STATE_ACTION_DEF (teleport_state)
|
||||||
PARAM_CLASS_DEF (target_type, ASpecialSpot)
|
PARAM_CLASS_DEF (target_type, ASpecialSpot)
|
||||||
PARAM_CLASS_DEF (fog_type, AActor)
|
PARAM_CLASS_DEF (fog_type, AActor)
|
||||||
PARAM_INT_DEF (flags)
|
PARAM_INT_DEF (flags)
|
||||||
|
@ -5448,7 +5449,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp)
|
||||||
PARAM_FLOAT_DEF(zofs)
|
PARAM_FLOAT_DEF(zofs)
|
||||||
PARAM_ANGLE_DEF(angle)
|
PARAM_ANGLE_DEF(angle)
|
||||||
PARAM_INT_DEF(flags)
|
PARAM_INT_DEF(flags)
|
||||||
PARAM_STATE_DEF(success_state)
|
PARAM_STATE_ACTION_DEF(success_state)
|
||||||
PARAM_FLOAT_DEF(heightoffset)
|
PARAM_FLOAT_DEF(heightoffset)
|
||||||
PARAM_FLOAT_DEF(radiusoffset)
|
PARAM_FLOAT_DEF(radiusoffset)
|
||||||
PARAM_ANGLE_DEF(pitch)
|
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))
|
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
|
||||||
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
||||||
AInventory *gift = static_cast<AInventory *>(Spawn(item));
|
AInventory *gift = static_cast<AInventory *>(Spawn(item));
|
||||||
if (gift->IsKindOf(PClass::FindActor(NAME_Health)))
|
if (gift->IsKindOf(NAME_Health))
|
||||||
{
|
{
|
||||||
gift->Amount *= amount;
|
gift->Amount *= amount;
|
||||||
}
|
}
|
||||||
|
@ -6913,3 +6914,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetSize)
|
||||||
|
|
||||||
ACTION_RETURN_BOOL(true);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
|
||||||
node->ItemCheck.Resize(3);
|
node->ItemCheck.Resize(3);
|
||||||
for (j = 0; j < 3; ++j)
|
for (j = 0; j < 3; ++j)
|
||||||
{
|
{
|
||||||
node->ItemCheck[j].Item = dyn_cast<PClassInventory>(GetStrifeType(speech.ItemCheck[j]));
|
auto inv = GetStrifeType(speech.ItemCheck[j]);
|
||||||
|
if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr;
|
||||||
|
node->ItemCheck[j].Item = inv;
|
||||||
node->ItemCheck[j].Amount = -1;
|
node->ItemCheck[j].Amount = -1;
|
||||||
}
|
}
|
||||||
node->ItemCheckNode = speech.Link;
|
node->ItemCheckNode = speech.Link;
|
||||||
|
@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
|
||||||
reply->ItemCheck.Resize(3);
|
reply->ItemCheck.Resize(3);
|
||||||
for (k = 0; k < 3; ++k)
|
for (k = 0; k < 3; ++k)
|
||||||
{
|
{
|
||||||
reply->ItemCheck[k].Item = dyn_cast<PClassInventory>(GetStrifeType(rsp->Item[k]));
|
auto inv = GetStrifeType(rsp->Item[k]);
|
||||||
|
if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr;
|
||||||
|
reply->ItemCheck[k].Item = inv;
|
||||||
reply->ItemCheck[k].Amount = rsp->Count[k];
|
reply->ItemCheck[k].Amount = rsp->Count[k];
|
||||||
}
|
}
|
||||||
reply->ItemCheckRequire.Clear();
|
reply->ItemCheckRequire.Clear();
|
||||||
|
@ -1331,7 +1335,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (reply->GiveType->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
if (player->mo->FindInventory(reply->GiveType) != NULL)
|
if (player->mo->FindInventory(reply->GiveType) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1357,7 +1361,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter")))
|
if (reply->GiveType->IsDescendantOf("SlideshowStarter"))
|
||||||
gameaction = ga_slideshow;
|
gameaction = ga_slideshow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct FBrokenLines;
|
||||||
|
|
||||||
struct FStrifeDialogueItemCheck
|
struct FStrifeDialogueItemCheck
|
||||||
{
|
{
|
||||||
PClassInventory *Item;
|
PClassActor *Item;
|
||||||
int Amount;
|
int Amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3227,7 +3227,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
|
||||||
|
|
||||||
if (dropamount > 0)
|
if (dropamount > 0)
|
||||||
{
|
{
|
||||||
if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo)))
|
if (flagmask != 0 && inv->IsKindOf(NAME_Ammo))
|
||||||
{
|
{
|
||||||
inv->Amount = int(dropamount * dropammofactor);
|
inv->Amount = int(dropamount * dropammofactor);
|
||||||
inv->ItemFlags |= IF_IGNORESKILL;
|
inv->ItemFlags |= IF_IGNORESKILL;
|
||||||
|
@ -3253,7 +3253,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
|
||||||
inv->FloatVar("AmmoFactor") = dropammofactor;
|
inv->FloatVar("AmmoFactor") = dropammofactor;
|
||||||
inv->ItemFlags |= flagmask;
|
inv->ItemFlags |= flagmask;
|
||||||
}
|
}
|
||||||
else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
else if (inv->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
// The same goes for ammo from a weapon.
|
// The same goes for ammo from a weapon.
|
||||||
static_cast<AWeapon *>(inv)->AmmoGive1 = int(static_cast<AWeapon *>(inv)->AmmoGive1 * dropammofactor);
|
static_cast<AWeapon *>(inv)->AmmoGive1 = int(static_cast<AWeapon *>(inv)->AmmoGive1 * dropammofactor);
|
||||||
|
|
|
@ -442,4 +442,15 @@ enum EDmgFlags
|
||||||
//
|
//
|
||||||
bool P_AlignFlat (int linenum, int side, int fc);
|
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__
|
#endif // __P_LOCAL__
|
||||||
|
|
|
@ -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;
|
bool result = true;
|
||||||
|
|
||||||
|
if (type == nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
|
||||||
|
|
||||||
AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL;
|
AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL;
|
||||||
bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true;
|
bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true;
|
||||||
|
|
||||||
|
@ -904,7 +906,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
|
||||||
// and infinite ammo is on
|
// and infinite ammo is on
|
||||||
if (notakeinfinite &&
|
if (notakeinfinite &&
|
||||||
((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) &&
|
((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) &&
|
||||||
item->IsKindOf(PClass::FindActor(NAME_Ammo)))
|
item->IsKindOf(NAME_Ammo))
|
||||||
{
|
{
|
||||||
// Nothing to do here, except maybe res = false;? Would it make sense?
|
// Nothing to do here, except maybe res = false;? Would it make sense?
|
||||||
result = false;
|
result = false;
|
||||||
|
@ -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 != NULL)
|
||||||
{
|
{
|
||||||
|
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
|
||||||
|
|
||||||
AInventory *item = static_cast<AInventory *>(Spawn (type));
|
AInventory *item = static_cast<AInventory *>(Spawn (type));
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
|
@ -1543,7 +1547,7 @@ bool AActor::IsVisibleToPlayer() const
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i)
|
for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i)
|
||||||
{
|
{
|
||||||
PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i];
|
auto cls = GetClass()->VisibleToPlayerClass[i];
|
||||||
if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls))
|
if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls))
|
||||||
{
|
{
|
||||||
visible = true;
|
visible = true;
|
||||||
|
@ -3197,6 +3201,7 @@ void P_NightmareRespawn (AActor *mobj)
|
||||||
|
|
||||||
// spawn it
|
// spawn it
|
||||||
mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true);
|
mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true);
|
||||||
|
mo->health = mobj->SpawnHealth();
|
||||||
|
|
||||||
if (z == ONFLOORZ)
|
if (z == ONFLOORZ)
|
||||||
{
|
{
|
||||||
|
@ -7488,7 +7493,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DDropItem *AActor::GetDropItems() const
|
FDropItem *AActor::GetDropItems() const
|
||||||
{
|
{
|
||||||
return GetClass()->DropItems;
|
return GetClass()->DropItems;
|
||||||
}
|
}
|
||||||
|
@ -8096,16 +8101,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors)
|
||||||
//
|
//
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_CLASS(DDropItem, false, true)
|
DEFINE_FIELD(FDropItem, Next)
|
||||||
|
DEFINE_FIELD(FDropItem, Name)
|
||||||
IMPLEMENT_POINTERS_START(DDropItem)
|
DEFINE_FIELD(FDropItem, Probability)
|
||||||
IMPLEMENT_POINTER(Next)
|
DEFINE_FIELD(FDropItem, Amount)
|
||||||
IMPLEMENT_POINTERS_END
|
|
||||||
|
|
||||||
DEFINE_FIELD(DDropItem, Next)
|
|
||||||
DEFINE_FIELD(DDropItem, Name)
|
|
||||||
DEFINE_FIELD(DDropItem, Probability)
|
|
||||||
DEFINE_FIELD(DDropItem, Amount)
|
|
||||||
|
|
||||||
void PrintMiscActorInfo(AActor *query)
|
void PrintMiscActorInfo(AActor *query)
|
||||||
{
|
{
|
||||||
|
|
|
@ -166,7 +166,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id)
|
||||||
if (Next && Next->ID == ID && ID != 0)
|
if (Next && Next->ID == ID && ID != 0)
|
||||||
Next->Destroy(); // Replace it.
|
Next->Destroy(); // Replace it.
|
||||||
|
|
||||||
if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
|
if (Caller->IsKindOf(NAME_Weapon) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
|
||||||
Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST);
|
Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ void DPSprite::SetState(FState *newstate, bool pending)
|
||||||
}
|
}
|
||||||
else if (!(newstate->UseFlags & SUF_WEAPON))
|
else if (!(newstate->UseFlags & SUF_WEAPON))
|
||||||
{
|
{
|
||||||
if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
if (Caller->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
auto so = FState::StaticFindStateOwner(newstate);
|
auto so = FState::StaticFindStateOwner(newstate);
|
||||||
Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates));
|
Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates));
|
||||||
|
@ -1333,7 +1333,7 @@ void player_t::TickPSprites()
|
||||||
// or if it's from an inventory item that the player no longer owns.
|
// or if it's from an inventory item that the player no longer owns.
|
||||||
if ((pspr->Caller == nullptr ||
|
if ((pspr->Caller == nullptr ||
|
||||||
(pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast<AInventory *>(pspr->Caller)->Owner != pspr->Owner->mo) ||
|
(pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast<AInventory *>(pspr->Caller)->Owner != pspr->Owner->mo) ||
|
||||||
(pspr->Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && pspr->Caller != pspr->Owner->ReadyWeapon)))
|
(pspr->Caller->IsKindOf(NAME_Weapon) && pspr->Caller != pspr->Owner->ReadyWeapon)))
|
||||||
{
|
{
|
||||||
pspr->Destroy();
|
pspr->Destroy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2121,6 +2121,63 @@ bool P_AlignFlat (int linenum, int side, int fc)
|
||||||
return true;
|
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
|
// P_BuildPolyBSP
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ public:
|
||||||
{
|
{
|
||||||
ld->alpha = 0.75;
|
ld->alpha = 0.75;
|
||||||
}
|
}
|
||||||
if (strifetrans2 && ld->alpha == OPAQUE)
|
if (strifetrans2 && ld->alpha == 1.)
|
||||||
{
|
{
|
||||||
ld->alpha = 0.25;
|
ld->alpha = 0.25;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,21 +57,23 @@ class USDFParser : public UDMFParserBase
|
||||||
|
|
||||||
PClassActor *CheckActorType(const char *key)
|
PClassActor *CheckActorType(const char *key)
|
||||||
{
|
{
|
||||||
|
PClassActor *type = nullptr;
|
||||||
if (namespace_bits == St)
|
if (namespace_bits == St)
|
||||||
{
|
{
|
||||||
return GetStrifeType(CheckInt(key));
|
type = GetStrifeType(CheckInt(key));
|
||||||
}
|
}
|
||||||
else if (namespace_bits == Zd)
|
else if (namespace_bits == Zd)
|
||||||
{
|
{
|
||||||
PClassActor *cls = PClass::FindActor(CheckString(key));
|
PClassActor *cls = PClass::FindActor(CheckString(key));
|
||||||
if (cls == NULL)
|
if (cls == nullptr)
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("Unknown actor class '%s'", key);
|
sc.ScriptMessage("Unknown actor class '%s'", key);
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return cls;
|
type = cls;
|
||||||
}
|
}
|
||||||
return NULL;
|
if (type && type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return type;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -92,7 +94,7 @@ class USDFParser : public UDMFParserBase
|
||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
case NAME_Item:
|
case NAME_Item:
|
||||||
check.Item = dyn_cast<PClassInventory>(CheckActorType(key));
|
check.Item = CheckActorType(key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAME_Amount:
|
case NAME_Amount:
|
||||||
|
@ -266,7 +268,7 @@ class USDFParser : public UDMFParserBase
|
||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
case NAME_Item:
|
case NAME_Item:
|
||||||
check.Item = dyn_cast<PClassInventory>(CheckActorType(key));
|
check.Item = CheckActorType(key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAME_Count:
|
case NAME_Count:
|
||||||
|
|
183
src/p_user.cpp
183
src/p_user.cpp
|
@ -85,6 +85,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
|
||||||
P_PredictionLerpReset();
|
P_PredictionLerpReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorSetList ColorSets;
|
||||||
|
PainFlashList PainFlashes;
|
||||||
|
|
||||||
struct PredictPos
|
struct PredictPos
|
||||||
{
|
{
|
||||||
int gametic;
|
int gametic;
|
||||||
|
@ -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.
|
// Fixme; This needs a decent way to access the string table without creating a mess.
|
||||||
// [RH] ????
|
// [RH] ????
|
||||||
|
@ -165,7 +168,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name)
|
||||||
Printf("Invalid player class '%s'\n", name);
|
Printf("Invalid player class '%s'\n", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (static_cast<PClassPlayerPawn *>(ti)->DisplayName.IsEmpty())
|
else if (ti->DisplayName.IsEmpty())
|
||||||
{
|
{
|
||||||
Printf ("Missing displayname for player class '%s'\n", name);
|
Printf ("Missing displayname for player class '%s'\n", name);
|
||||||
return false;
|
return false;
|
||||||
|
@ -184,7 +187,7 @@ void SetupPlayerClasses ()
|
||||||
if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i]))
|
if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i]))
|
||||||
{
|
{
|
||||||
newclass.Flags = 0;
|
newclass.Flags = 0;
|
||||||
newclass.Type = static_cast<PClassPlayerPawn *>(cls);
|
newclass.Type = cls;
|
||||||
if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU))
|
if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU))
|
||||||
{
|
{
|
||||||
newclass.Flags |= PCF_NOMENU;
|
newclass.Flags |= PCF_NOMENU;
|
||||||
|
@ -212,7 +215,7 @@ CCMD (addplayerclass)
|
||||||
{
|
{
|
||||||
FPlayerClass newclass;
|
FPlayerClass newclass;
|
||||||
|
|
||||||
newclass.Type = static_cast<PClassPlayerPawn *>(ti);
|
newclass.Type = ti;
|
||||||
newclass.Flags = 0;
|
newclass.Flags = 0;
|
||||||
|
|
||||||
int arg = 2;
|
int arg = 2;
|
||||||
|
@ -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)
|
static int intcmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return *(const int *)a - *(const int *)b;
|
return *(const int *)a - *(const int *)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
|
void EnumColorSets(PClassActor *cls, TArray<int> *out)
|
||||||
{
|
{
|
||||||
out->Clear();
|
TArray<int> deleteds;
|
||||||
FPlayerColorSetMap::Iterator it(ColorSets);
|
|
||||||
FPlayerColorSetMap::Pair *pair;
|
|
||||||
|
|
||||||
while (it.NextPair(pair))
|
out->Clear();
|
||||||
|
for (int i = ColorSets.Size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
out->Push(pair->Key);
|
if (std::get<0>(ColorSets[i])->IsAncestorOf(cls))
|
||||||
|
{
|
||||||
|
int v = std::get<1>(ColorSets[i]);
|
||||||
|
if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size())
|
||||||
|
{
|
||||||
|
if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v);
|
||||||
|
else out->Push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
|
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
for (int i = ColorSets.Size() - 1; i >= 0; i--)
|
||||||
|
|
||||||
while (info != NULL)
|
|
||||||
{
|
{
|
||||||
const PalEntry *flash = info->PainFlashes.CheckKey(type);
|
if (std::get<1>(ColorSets[i]) == setnum &&
|
||||||
if (flash != NULL)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
// Try parent class
|
|
||||||
info = dyn_cast<PClassPlayerPawn>(info->ParentClass);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -661,7 +658,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true)
|
||||||
IMPLEMENT_POINTERS_START(APlayerPawn)
|
IMPLEMENT_POINTERS_START(APlayerPawn)
|
||||||
IMPLEMENT_POINTER(InvFirst)
|
IMPLEMENT_POINTER(InvFirst)
|
||||||
IMPLEMENT_POINTER(InvSel)
|
IMPLEMENT_POINTER(InvSel)
|
||||||
IMPLEMENT_POINTER(FlechetteType)
|
|
||||||
IMPLEMENT_POINTERS_END
|
IMPLEMENT_POINTERS_END
|
||||||
|
|
||||||
void APlayerPawn::Serialize(FSerializer &arc)
|
void APlayerPawn::Serialize(FSerializer &arc)
|
||||||
|
@ -953,7 +949,7 @@ bool APlayerPawn::UseInventory (AInventory *item)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
|
AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype)
|
||||||
{
|
{
|
||||||
AWeapon *bestMatch = NULL;
|
AWeapon *bestMatch = NULL;
|
||||||
int bestOrder = INT_MAX;
|
int bestOrder = INT_MAX;
|
||||||
|
@ -964,7 +960,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
|
||||||
// Find the best weapon the player has.
|
// Find the best weapon the player has.
|
||||||
for (item = Inventory; item != NULL; item = item->Inventory)
|
for (item = Inventory; item != NULL; item = item->Inventory)
|
||||||
{
|
{
|
||||||
if (!item->IsKindOf (RUNTIME_CLASS(AWeapon)))
|
if (!item->IsKindOf(NAME_Weapon))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
weap = static_cast<AWeapon *> (item);
|
weap = static_cast<AWeapon *> (item);
|
||||||
|
@ -1015,7 +1011,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype)
|
AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype)
|
||||||
{
|
{
|
||||||
AWeapon *best = BestWeapon (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() &&
|
if (!player->userinfo.GetNeverSwitch() &&
|
||||||
player->PendingWeapon == WP_NOCHANGE &&
|
player->PendingWeapon == WP_NOCHANGE &&
|
||||||
|
@ -1062,7 +1058,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype)
|
||||||
DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch)
|
DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(APlayerPawn);
|
PARAM_SELF_PROLOGUE(APlayerPawn);
|
||||||
PARAM_OBJECT(ammotype, PClassInventory);
|
PARAM_OBJECT(ammotype, PClassActor);
|
||||||
self->CheckWeaponSwitch(ammotype);
|
self->CheckWeaponSwitch(ammotype);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1137,29 +1133,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
|
||||||
|
|
||||||
if ((dmflags & DF_COOP_LOSE_KEYS) &&
|
if ((dmflags & DF_COOP_LOSE_KEYS) &&
|
||||||
defitem == NULL &&
|
defitem == NULL &&
|
||||||
item->IsKindOf(PClass::FindActor(NAME_Key)))
|
item->IsKindOf(NAME_Key))
|
||||||
{
|
{
|
||||||
item->Destroy();
|
item->Destroy();
|
||||||
}
|
}
|
||||||
else if ((dmflags & DF_COOP_LOSE_WEAPONS) &&
|
else if ((dmflags & DF_COOP_LOSE_WEAPONS) &&
|
||||||
defitem == NULL &&
|
defitem == NULL &&
|
||||||
item->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
item->Destroy();
|
item->Destroy();
|
||||||
}
|
}
|
||||||
else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
|
else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
|
||||||
item->IsKindOf(PClass::FindActor(NAME_Armor)))
|
item->IsKindOf(NAME_Armor))
|
||||||
{
|
{
|
||||||
if (defitem == NULL)
|
if (defitem == NULL)
|
||||||
{
|
{
|
||||||
item->Destroy();
|
item->Destroy();
|
||||||
}
|
}
|
||||||
else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor)))
|
else if (item->IsKindOf(NAME_BasicArmor))
|
||||||
{
|
{
|
||||||
item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
|
item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
|
||||||
item->Amount = defitem->Amount;
|
item->Amount = defitem->Amount;
|
||||||
}
|
}
|
||||||
else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor)))
|
else if (item->IsKindOf(NAME_HexenArmor))
|
||||||
{
|
{
|
||||||
double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
|
double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
|
||||||
double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
|
double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
|
||||||
|
@ -1168,12 +1164,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
|
||||||
}
|
}
|
||||||
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
|
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
|
||||||
defitem == NULL &&
|
defitem == NULL &&
|
||||||
item->IsKindOf(PClass::FindActor(NAME_PowerupGiver)))
|
item->IsKindOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
item->Destroy();
|
item->Destroy();
|
||||||
}
|
}
|
||||||
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
|
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
|
||||||
item->IsKindOf(PClass::FindActor(NAME_Ammo)))
|
item->IsKindOf(NAME_Ammo))
|
||||||
{
|
{
|
||||||
if (defitem == NULL)
|
if (defitem == NULL)
|
||||||
{
|
{
|
||||||
|
@ -1230,8 +1226,8 @@ const char *APlayerPawn::GetSoundClass() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// [GRB]
|
// [GRB]
|
||||||
PClassPlayerPawn *pclass = GetClass();
|
auto pclass = GetClass();
|
||||||
return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player";
|
return SoundClass != NAME_None? SoundClass.GetChars() : "player";
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -1368,16 +1364,16 @@ void APlayerPawn::GiveDefaultInventory ()
|
||||||
// HexenArmor must always be the first item in the inventory because
|
// HexenArmor must always be the first item in the inventory because
|
||||||
// it provides player class based protection that should not affect
|
// it provides player class based protection that should not affect
|
||||||
// any other protection item.
|
// any other protection item.
|
||||||
PClassPlayerPawn *myclass = GetClass();
|
auto myclass = GetClass();
|
||||||
GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
|
GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
|
||||||
auto harmor = FindInventory(NAME_HexenArmor);
|
auto harmor = FindInventory(NAME_HexenArmor);
|
||||||
|
|
||||||
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
|
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
|
||||||
Slots[4] = myclass->HexenArmor[0];
|
Slots[4] = HexenArmor[0];
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
SlotsIncrement[i] = myclass->HexenArmor[i + 1];
|
SlotsIncrement[i] = HexenArmor[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// BasicArmor must come right after that. It should not affect any
|
// BasicArmor must come right after that. It should not affect any
|
||||||
|
@ -1388,7 +1384,7 @@ void APlayerPawn::GiveDefaultInventory ()
|
||||||
AddInventory (barmor);
|
AddInventory (barmor);
|
||||||
|
|
||||||
// Now add the items from the DECORATE definition
|
// Now add the items from the DECORATE definition
|
||||||
DDropItem *di = GetDropItems();
|
auto di = GetDropItems();
|
||||||
|
|
||||||
while (di)
|
while (di)
|
||||||
{
|
{
|
||||||
|
@ -1413,7 +1409,7 @@ void APlayerPawn::GiveDefaultInventory ()
|
||||||
item = static_cast<AInventory *>(Spawn(ti));
|
item = static_cast<AInventory *>(Spawn(ti));
|
||||||
item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here
|
item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here
|
||||||
item->Amount = di->Amount;
|
item->Amount = di->Amount;
|
||||||
if (item->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
if (item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
// To allow better control any weapon is emptied of
|
// To allow better control any weapon is emptied of
|
||||||
// ammo before being given to the player.
|
// ammo before being given to the player.
|
||||||
|
@ -1433,7 +1429,7 @@ void APlayerPawn::GiveDefaultInventory ()
|
||||||
item = NULL;
|
item = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) &&
|
if (item != NULL && item->IsKindOf(NAME_Weapon) &&
|
||||||
static_cast<AWeapon*>(item)->CheckAmmo(AWeapon::EitherFire, false))
|
static_cast<AWeapon*>(item)->CheckAmmo(AWeapon::EitherFire, false))
|
||||||
{
|
{
|
||||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item);
|
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item);
|
||||||
|
@ -1518,7 +1514,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
|
||||||
AInventory *item;
|
AInventory *item;
|
||||||
|
|
||||||
// kgDROP - start - modified copy from a_action.cpp
|
// kgDROP - start - modified copy from a_action.cpp
|
||||||
DDropItem *di = weap->GetDropItems();
|
auto di = weap->GetDropItems();
|
||||||
|
|
||||||
if (di != NULL)
|
if (di != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1537,7 +1533,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
|
||||||
weap->SpawnState != ::GetDefault<AActor>()->SpawnState)
|
weap->SpawnState != ::GetDefault<AActor>()->SpawnState)
|
||||||
{
|
{
|
||||||
item = P_DropItem (this, weap->GetClass(), -1, 256);
|
item = P_DropItem (this, weap->GetClass(), -1, 256);
|
||||||
if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)))
|
if (item != NULL && item->IsKindOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
if (weap->AmmoGive1 && weap->Ammo1)
|
if (weap->AmmoGive1 && weap->Ammo1)
|
||||||
{
|
{
|
||||||
|
@ -1710,9 +1706,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop)
|
||||||
player_t *player;
|
player_t *player;
|
||||||
|
|
||||||
// [GRB] Parameterized version
|
// [GRB] Parameterized version
|
||||||
if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk")))
|
if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk"))
|
||||||
{
|
{
|
||||||
spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull"));
|
spawntype = PClass::FindActor("BloodySkull");
|
||||||
if (spawntype == NULL)
|
if (spawntype == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3249,18 +3245,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade)
|
||||||
DEFINE_FIELD(APlayerPawn, ViewBob)
|
DEFINE_FIELD(APlayerPawn, ViewBob)
|
||||||
DEFINE_FIELD(APlayerPawn, FullHeight)
|
DEFINE_FIELD(APlayerPawn, FullHeight)
|
||||||
|
|
||||||
DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType)
|
DEFINE_FIELD(APlayerPawn, HealingRadiusType)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, DisplayName)
|
DEFINE_FIELD(APlayerPawn, SoundClass)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, SoundClass)
|
DEFINE_FIELD(APlayerPawn, Face)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, Face)
|
DEFINE_FIELD(APlayerPawn, Portrait)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, Portrait)
|
DEFINE_FIELD(APlayerPawn, Slot)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, Slot)
|
DEFINE_FIELD(APlayerPawn, InvulMode)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, InvulMode)
|
DEFINE_FIELD(APlayerPawn, HexenArmor)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, HexenArmor)
|
DEFINE_FIELD(APlayerPawn, ColorRangeStart)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart)
|
DEFINE_FIELD(APlayerPawn, ColorRangeEnd)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd)
|
|
||||||
DEFINE_FIELD(PClassPlayerPawn, ColorSets)
|
DEFINE_FIELD(PClassActor, DisplayName)
|
||||||
DEFINE_FIELD(PClassPlayerPawn, PainFlashes)
|
|
||||||
|
|
||||||
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
|
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
|
||||||
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)
|
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)
|
||||||
|
|
|
@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor)
|
||||||
unsigned i = level.sectorPortals.Reserve(1);
|
unsigned i = level.sectorPortals.Reserve(1);
|
||||||
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
|
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
|
||||||
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
|
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
|
||||||
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY;
|
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY;
|
||||||
level.sectorPortals[i].mSkybox = actor;
|
level.sectorPortals[i].mSkybox = actor;
|
||||||
level.sectorPortals[i].mDestination = actor->Sector;
|
level.sectorPortals[i].mDestination = actor->Sector;
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha)
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case STYLEALPHA_Zero: return 0;
|
case STYLEALPHA_Zero: return 0;
|
||||||
case STYLEALPHA_One: return OPAQUE;
|
case STYLEALPHA_One: return 1.;
|
||||||
case STYLEALPHA_Src: return alpha;
|
case STYLEALPHA_Src: return alpha;
|
||||||
case STYLEALPHA_InvSrc: return 1. - alpha;
|
case STYLEALPHA_InvSrc: return 1. - alpha;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
|
|
|
@ -44,10 +44,6 @@
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
OPAQUE = 65536,
|
OPAQUE = 65536,
|
||||||
TRANSLUC25 = (OPAQUE / 4),
|
|
||||||
TRANSLUC33 = (OPAQUE / 3),
|
|
||||||
TRANSLUC66 = ((OPAQUE * 2) / 3),
|
|
||||||
TRANSLUC75 = ((OPAQUE * 3) / 4),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Legacy render styles
|
// Legacy render styles
|
||||||
|
|
|
@ -517,7 +517,7 @@ void R_InitSkins (void)
|
||||||
int lastlump;
|
int lastlump;
|
||||||
int aliasid;
|
int aliasid;
|
||||||
bool remove;
|
bool remove;
|
||||||
PClassPlayerPawn *basetype, *transtype;
|
PClassActor *basetype, *transtype;
|
||||||
|
|
||||||
key[sizeof(key)-1] = 0;
|
key[sizeof(key)-1] = 0;
|
||||||
i = PlayerClasses.Size () - 1;
|
i = PlayerClasses.Size () - 1;
|
||||||
|
@ -602,11 +602,11 @@ void R_InitSkins (void)
|
||||||
else if (0 == stricmp (key, "game"))
|
else if (0 == stricmp (key, "game"))
|
||||||
{
|
{
|
||||||
if (gameinfo.gametype == GAME_Heretic)
|
if (gameinfo.gametype == GAME_Heretic)
|
||||||
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer));
|
basetype = PClass::FindActor(NAME_HereticPlayer);
|
||||||
else if (gameinfo.gametype == GAME_Strife)
|
else if (gameinfo.gametype == GAME_Strife)
|
||||||
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_StrifePlayer));
|
basetype = PClass::FindActor(NAME_StrifePlayer);
|
||||||
else
|
else
|
||||||
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer));
|
basetype = PClass::FindActor(NAME_DoomPlayer);
|
||||||
|
|
||||||
transtype = basetype;
|
transtype = basetype;
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ void R_InitSkins (void)
|
||||||
{
|
{
|
||||||
if (gameinfo.gametype & GAME_DoomChex)
|
if (gameinfo.gametype & GAME_DoomChex)
|
||||||
{
|
{
|
||||||
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer));
|
transtype = PClass::FindActor(NAME_HereticPlayer);
|
||||||
skins[i].othergame = true;
|
skins[i].othergame = true;
|
||||||
}
|
}
|
||||||
else if (gameinfo.gametype != GAME_Heretic)
|
else if (gameinfo.gametype != GAME_Heretic)
|
||||||
|
@ -633,7 +633,7 @@ void R_InitSkins (void)
|
||||||
{
|
{
|
||||||
if (gameinfo.gametype == GAME_Heretic)
|
if (gameinfo.gametype == GAME_Heretic)
|
||||||
{
|
{
|
||||||
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer));
|
transtype = PClass::FindActor(NAME_DoomPlayer);
|
||||||
skins[i].othergame = true;
|
skins[i].othergame = true;
|
||||||
}
|
}
|
||||||
else if (!(gameinfo.gametype & GAME_DoomChex))
|
else if (!(gameinfo.gametype & GAME_DoomChex))
|
||||||
|
@ -709,12 +709,12 @@ void R_InitSkins (void)
|
||||||
{
|
{
|
||||||
if (gameinfo.gametype & GAME_DoomChex)
|
if (gameinfo.gametype & GAME_DoomChex)
|
||||||
{
|
{
|
||||||
basetype = transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer));
|
basetype = transtype = PClass::FindActor(NAME_DoomPlayer);
|
||||||
}
|
}
|
||||||
else if (gameinfo.gametype == GAME_Heretic)
|
else if (gameinfo.gametype == GAME_Heretic)
|
||||||
{
|
{
|
||||||
basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer));
|
basetype = PClass::FindActor(NAME_HereticPlayer);
|
||||||
transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer));
|
transtype = PClass::FindActor(NAME_DoomPlayer);
|
||||||
skins[i].othergame = true;
|
skins[i].othergame = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -725,18 +725,22 @@ void R_InitSkins (void)
|
||||||
|
|
||||||
if (!remove)
|
if (!remove)
|
||||||
{
|
{
|
||||||
skins[i].range0start = transtype->ColorRangeStart;
|
auto transdef = ((APlayerPawn*)GetDefaultByType(transtype));
|
||||||
skins[i].range0end = transtype->ColorRangeEnd;
|
auto basedef = ((APlayerPawn*)GetDefaultByType(basetype));
|
||||||
|
|
||||||
|
skins[i].range0start = transdef->ColorRangeStart;
|
||||||
|
skins[i].range0end = transdef->ColorRangeEnd;
|
||||||
|
|
||||||
remove = true;
|
remove = true;
|
||||||
for (j = 0; j < (int)PlayerClasses.Size (); j++)
|
for (j = 0; j < (int)PlayerClasses.Size (); j++)
|
||||||
{
|
{
|
||||||
PClassPlayerPawn *type = PlayerClasses[j].Type;
|
auto type = PlayerClasses[j].Type;
|
||||||
|
auto type_def = ((APlayerPawn*)GetDefaultByType(type));
|
||||||
|
|
||||||
if (type->IsDescendantOf (basetype) &&
|
if (type->IsDescendantOf (basetype) &&
|
||||||
GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite &&
|
GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite &&
|
||||||
type->ColorRangeStart == basetype->ColorRangeStart &&
|
type_def->ColorRangeStart == basedef->ColorRangeStart &&
|
||||||
type->ColorRangeEnd == basetype->ColorRangeEnd)
|
type_def->ColorRangeEnd == basedef->ColorRangeEnd)
|
||||||
{
|
{
|
||||||
PlayerClasses[j].Skins.Push ((int)i);
|
PlayerClasses[j].Skins.Push ((int)i);
|
||||||
remove = false;
|
remove = false;
|
||||||
|
@ -935,10 +939,10 @@ void R_InitSprites ()
|
||||||
memset (skins, 0, sizeof(*skins) * numskins);
|
memset (skins, 0, sizeof(*skins) * numskins);
|
||||||
for (i = 0; i < numskins; i++)
|
for (i = 0; i < numskins; i++)
|
||||||
{ // Assume Doom skin by default
|
{ // Assume Doom skin by default
|
||||||
PClassPlayerPawn *type = PlayerClasses[0].Type;
|
auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type));
|
||||||
skins[i].range0start = type->ColorRangeStart;
|
skins[i].range0start = type->ColorRangeStart;
|
||||||
skins[i].range0end = type->ColorRangeEnd;
|
skins[i].range0end = type->ColorRangeEnd;
|
||||||
skins[i].Scale = GetDefaultByType (type)->Scale;
|
skins[i].Scale = type->Scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_InitSpriteDefs ();
|
R_InitSpriteDefs ();
|
||||||
|
@ -950,11 +954,10 @@ void R_InitSprites ()
|
||||||
// [GRB] Each player class has its own base skin
|
// [GRB] Each player class has its own base skin
|
||||||
for (i = 0; i < PlayerClasses.Size (); i++)
|
for (i = 0; i < PlayerClasses.Size (); i++)
|
||||||
{
|
{
|
||||||
PClassPlayerPawn *basetype = PlayerClasses[i].Type;
|
auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type));
|
||||||
FString classface = basetype->Face;
|
|
||||||
|
|
||||||
strcpy (skins[i].name, "Base");
|
strcpy (skins[i].name, "Base");
|
||||||
if (classface.IsEmpty() || strcmp(classface, "None") == 0)
|
if (basetype->Face == NAME_None)
|
||||||
{
|
{
|
||||||
skins[i].face[0] = 'S';
|
skins[i].face[0] = 'S';
|
||||||
skins[i].face[1] = 'T';
|
skins[i].face[1] = 'T';
|
||||||
|
@ -963,12 +966,12 @@ void R_InitSprites ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy(skins[i].face, classface);
|
strcpy(skins[i].face, basetype->Face);
|
||||||
}
|
}
|
||||||
skins[i].range0start = basetype->ColorRangeStart;
|
skins[i].range0start = basetype->ColorRangeStart;
|
||||||
skins[i].range0end = basetype->ColorRangeEnd;
|
skins[i].range0end = basetype->ColorRangeEnd;
|
||||||
skins[i].Scale = GetDefaultByType (basetype)->Scale;
|
skins[i].Scale = basetype->Scale;
|
||||||
skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite;
|
skins[i].sprite = basetype->SpawnState->sprite;
|
||||||
skins[i].namespc = ns_global;
|
skins[i].namespc = ns_global;
|
||||||
|
|
||||||
PlayerClasses[i].Skins.Push (i);
|
PlayerClasses[i].Skins.Push (i);
|
||||||
|
|
|
@ -338,8 +338,6 @@ void R_Init ()
|
||||||
{
|
{
|
||||||
atterm (R_Shutdown);
|
atterm (R_Shutdown);
|
||||||
|
|
||||||
StartScreen->Progress();
|
|
||||||
V_InitFonts();
|
|
||||||
StartScreen->Progress();
|
StartScreen->Progress();
|
||||||
// Colormap init moved back to InitPalette()
|
// Colormap init moved back to InitPalette()
|
||||||
//R_InitColormaps ();
|
//R_InitColormaps ();
|
||||||
|
|
|
@ -716,6 +716,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector,
|
||||||
{
|
{
|
||||||
case SOURCE_None:
|
case SOURCE_None:
|
||||||
default:
|
default:
|
||||||
|
pos->Zero();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_Actor:
|
case SOURCE_Actor:
|
||||||
|
|
|
@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
tag = ATAG_STATE;
|
tag = ATAG_STATE;
|
||||||
}
|
}
|
||||||
else if (value.Type->GetLoadOp() == OP_LO)
|
else if (value.Type->GetLoadOp() != OP_LP)
|
||||||
{
|
{
|
||||||
tag = ATAG_OBJECT;
|
tag = ATAG_OBJECT;
|
||||||
}
|
}
|
||||||
|
@ -1420,6 +1420,76 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build)
|
||||||
return to;
|
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
|
// generic type cast operator
|
||||||
|
@ -1649,6 +1719,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
goto basereturn;
|
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.
|
// todo: pointers to class objects.
|
||||||
// All other types are only compatible to themselves and have already been handled above by the equality check.
|
// 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.
|
// 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);
|
ob.Free(build);
|
||||||
ExpEmit meta(build, REGT_POINTER);
|
ExpEmit meta(build, REGT_POINTER);
|
||||||
build->Emit(OP_META, meta.RegNum, ob.RegNum);
|
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;
|
return meta;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6290,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
|
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)
|
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()
|
FxStackVariable::~FxStackVariable()
|
||||||
{
|
{
|
||||||
// Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap.
|
|
||||||
membervar->ObjectFlags |= OF_YesReallyDelete;
|
membervar->ObjectFlags |= OF_YesReallyDelete;
|
||||||
delete membervar;
|
delete membervar;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void FxStackVariable::ReplaceField(PField *newfield)
|
|
||||||
{
|
|
||||||
membervar->ObjectFlags |= OF_YesReallyDelete;
|
|
||||||
delete membervar;
|
|
||||||
membervar = newfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -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)
|
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
||||||
: FxExpression(EFX_StructMember, pos)
|
: FxMemberBase(EFX_StructMember, mem, pos)
|
||||||
{
|
{
|
||||||
classx = x;
|
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)))
|
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 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.
|
// PFields are garbage collected so this will be automatically taken care of later.
|
||||||
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||||
newfield->BitValue = membervar->BitValue;
|
newfield->BitValue = membervar->BitValue;
|
||||||
static_cast<FxStructMember *>(classx)->membervar = newfield;
|
static_cast<FxMemberBase *>(classx)->membervar = newfield;
|
||||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
|
||||||
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);
|
|
||||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||||
auto x = classx->Resolve(ctx);
|
auto x = classx->Resolve(ctx);
|
||||||
classx = nullptr;
|
classx = nullptr;
|
||||||
|
@ -6868,33 +6907,41 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PArray *arraytype = dyn_cast<PArray>(Array->ValueType);
|
PArray *arraytype = nullptr;
|
||||||
if (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.
|
PDynArray *darraytype = static_cast<PDynArray*>(Array->ValueType);
|
||||||
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
|
elementtype = darraytype->ElementType;
|
||||||
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
|
Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged.
|
||||||
{
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
arraytype = static_cast<PArray*>(ptype->PointedType);
|
|
||||||
arrayispointer = true;
|
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 (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 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;
|
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
|
||||||
SizeAddr = parentfield->Offset + parentfield->Type->Align;
|
SizeAddr = parentfield->Offset + sizeof(void*);
|
||||||
}
|
|
||||||
else if (Array->ExprType == EFX_GlobalVariable)
|
|
||||||
{
|
|
||||||
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
|
|
||||||
SizeAddr = parentfield->Offset + parentfield->Type->Align;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -6903,54 +6950,32 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
||||||
return nullptr;
|
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();
|
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");
|
ScriptPosition.Message(MSG_ERROR, "Array index out of bounds");
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
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.
|
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
|
||||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
|
// 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);
|
||||||
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
|
static_cast<FxMemberBase *>(Array)->membervar = newfield;
|
||||||
// PFields are garbage collected so this will be automatically taken care of later.
|
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||||
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
|
auto x = Array->Resolve(ctx);
|
||||||
static_cast<FxStructMember *>(Array)->membervar = newfield;
|
Array = nullptr;
|
||||||
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
return x;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueType = arraytype->ElementType;
|
ValueType = elementtype;
|
||||||
if (!Array->RequestAddress(ctx, &AddressWritable))
|
if (!Array->RequestAddress(ctx, &AddressWritable))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array.");
|
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));
|
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
|
||||||
|
|
||||||
auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
|
auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
|
||||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
|
static_cast<FxMemberBase *>(Array)->membervar = f;
|
||||||
{
|
static_cast<FxMemberBase *>(Array)->AddressRequested = false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array->ValueType = TypeUInt32;
|
Array->ValueType = TypeUInt32;
|
||||||
bound = Array->Emit(build);
|
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.
|
// same for String methods. It also uses a hidden struct type to define them.
|
||||||
Self->ValueType = TypeStringStruct;
|
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())
|
else if (Self->IsArray())
|
||||||
{
|
{
|
||||||
if (MethodName == NAME_Size)
|
if (MethodName == NAME_Size)
|
||||||
|
@ -7748,19 +7828,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
else
|
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.
|
// 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 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;
|
|
||||||
delete this;
|
|
||||||
member->ValueType = TypeUInt32;
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
else if (Self->ExprType == EFX_GlobalVariable)
|
|
||||||
{
|
|
||||||
auto member = static_cast<FxGlobalVariable*>(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.
|
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;
|
member->membervar = newfield;
|
||||||
Self = nullptr;
|
Self = nullptr;
|
||||||
|
@ -7793,7 +7863,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
return x->Resolve(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;
|
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
|
||||||
if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)))
|
if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||||
|
@ -8791,7 +8861,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
||||||
op.Free(build);
|
op.Free(build);
|
||||||
}
|
}
|
||||||
ExpEmit to(build, REGT_POINTER);
|
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;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8863,7 +8933,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build)
|
||||||
build->Emit(OP_LKP, to.RegNum, op.RegNum);
|
build->Emit(OP_LKP, to.RegNum, op.RegNum);
|
||||||
op = to;
|
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;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10600,8 +10670,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
||||||
|
|
||||||
case REGT_POINTER:
|
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(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC));
|
||||||
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REGT_STRING:
|
case REGT_STRING:
|
||||||
|
@ -10741,7 +10810,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
TArray<void*> cvalues;
|
TArray<void*> cvalues;
|
||||||
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetPointer());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -294,6 +294,7 @@ enum EFxType
|
||||||
EFX_StrLen,
|
EFX_StrLen,
|
||||||
EFX_ColorLiteral,
|
EFX_ColorLiteral,
|
||||||
EFX_GetDefaultByType,
|
EFX_GetDefaultByType,
|
||||||
|
EFX_FontCast,
|
||||||
EFX_COUNT
|
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 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 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 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);
|
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
void EmitStatement(VMFunctionBuilder *build);
|
void EmitStatement(VMFunctionBuilder *build);
|
||||||
|
@ -488,6 +490,13 @@ public:
|
||||||
isresolved = true;
|
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)
|
FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
||||||
{
|
{
|
||||||
value.pointer = nullptr;
|
value.pointer = nullptr;
|
||||||
|
@ -664,6 +673,18 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FxFontCast : public FxExpression
|
||||||
|
{
|
||||||
|
FxExpression *basex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FxFontCast(FxExpression *x);
|
||||||
|
~FxFontCast();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxTypeCast
|
// 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
|
// FxGlobalVariaböe
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
class FxGlobalVariable : public FxExpression
|
class FxGlobalVariable : public FxMemberBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PField *membervar;
|
|
||||||
bool AddressRequested;
|
|
||||||
bool AddressWritable;
|
|
||||||
|
|
||||||
FxGlobalVariable(PField*, const FScriptPosition&);
|
FxGlobalVariable(PField*, const FScriptPosition&);
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
bool RequestAddress(FCompileContext &ctx, bool *writable);
|
bool RequestAddress(FCompileContext &ctx, bool *writable);
|
||||||
|
@ -1322,19 +1354,17 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxClassMember
|
// FxClassMember
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
class FxStructMember : public FxExpression
|
class FxStructMember : public FxMemberBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FxExpression *classx;
|
FxExpression *classx;
|
||||||
PField *membervar;
|
|
||||||
bool AddressRequested;
|
|
||||||
bool AddressWritable;
|
|
||||||
|
|
||||||
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
|
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
|
||||||
~FxStructMember();
|
~FxStructMember();
|
||||||
|
@ -1382,16 +1412,11 @@ public:
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
class FxStackVariable : public FxExpression
|
class FxStackVariable : public FxMemberBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PField *membervar;
|
|
||||||
bool AddressRequested;
|
|
||||||
bool AddressWritable;
|
|
||||||
|
|
||||||
FxStackVariable(PType *type, int offset, const FScriptPosition&);
|
FxStackVariable(PType *type, int offset, const FScriptPosition&);
|
||||||
~FxStackVariable();
|
~FxStackVariable();
|
||||||
void ReplaceField(PField *newfield);
|
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
bool RequestAddress(FCompileContext &ctx, bool *writable);
|
bool RequestAddress(FCompileContext &ctx, bool *writable);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
** dynarray.cpp
|
** dynarray.cpp
|
||||||
**
|
**
|
||||||
** Compiler backend / code generation for dynamic arrays
|
** internal data types for dynamic arrays
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 2016 Christoph Oelckers
|
** Copyright 2016-2017 Christoph Oelckers
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** Redistribution and use in source and binary forms, with or without
|
|
@ -32,7 +32,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vmbuilder.h"
|
#include "vmbuilder.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "codegen.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
|
@ -47,7 +47,7 @@
|
||||||
#include "decallib.h"
|
#include "decallib.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
#include "r_data/r_translate.h"
|
#include "r_data/r_translate.h"
|
||||||
|
|
||||||
// TYPES -------------------------------------------------------------------
|
// TYPES -------------------------------------------------------------------
|
||||||
|
@ -541,7 +541,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
||||||
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
||||||
{
|
{
|
||||||
sc.MustGetString ();
|
sc.MustGetString ();
|
||||||
static_cast<PClassInventory *>(bag.Info)->PickupMsg = sc.String;
|
bag.Info->PickupMsg = sc.String;
|
||||||
}
|
}
|
||||||
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
|
|
||||||
FRandom pr_exrandom ("EX_Random");
|
FRandom pr_exrandom ("EX_Random");
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
#include "doomerrors.h"
|
#include "doomerrors.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns)
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info->Finalize(bag.statedef);
|
GetDefaultByType(info)->Finalize(bag.statedef);
|
||||||
}
|
}
|
||||||
catch (CRecoverableError &err)
|
catch (CRecoverableError &err)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,10 +53,10 @@
|
||||||
#include "s_sound.h"
|
#include "s_sound.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "colormatcher.h"
|
#include "colormatcher.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "vmbuilder.h"
|
#include "backend/vmbuilder.h"
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//***
|
//***
|
||||||
|
|
406
src/scripting/symbols.cpp
Normal file
406
src/scripting/symbols.cpp
Normal 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
272
src/scripting/symbols.h
Normal 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;
|
||||||
|
|
||||||
|
|
|
@ -60,9 +60,9 @@
|
||||||
#include "p_conversation.h"
|
#include "p_conversation.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
#include "vmbuilder.h"
|
#include "backend/vmbuilder.h"
|
||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
@ -246,7 +246,7 @@ static void CheckForUnsafeStates(PClassActor *obj)
|
||||||
TMap<FState *, bool> checked;
|
TMap<FState *, bool> checked;
|
||||||
ENamedName *test;
|
ENamedName *test;
|
||||||
|
|
||||||
if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (obj->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables.
|
if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables.
|
||||||
test = weaponstates;
|
test = weaponstates;
|
||||||
|
@ -336,11 +336,11 @@ static void CheckStates(PClassActor *obj)
|
||||||
|
|
||||||
CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites");
|
CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites");
|
||||||
|
|
||||||
if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (obj->IsDescendantOf(NAME_Weapon))
|
||||||
{
|
{
|
||||||
CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites");
|
CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites");
|
||||||
}
|
}
|
||||||
else if (obj->IsDescendantOf(PClass::FindActor(NAME_CustomInventory)))
|
else if (obj->IsDescendantOf(NAME_CustomInventory))
|
||||||
{
|
{
|
||||||
CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain");
|
CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain");
|
||||||
}
|
}
|
||||||
|
@ -396,8 +396,9 @@ void LoadActors()
|
||||||
{
|
{
|
||||||
Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
|
Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
|
||||||
FScriptPosition::WarnCounter++;
|
FScriptPosition::WarnCounter++;
|
||||||
DObject::StaticPointerSubstitution(ti, nullptr);
|
// the class must be rendered harmless so that it won't cause problems.
|
||||||
PClassActor::AllActorClasses.Delete(i);
|
ti->ParentClass = RUNTIME_CLASS(AActor);
|
||||||
|
ti->Size = sizeof(AActor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state);
|
||||||
// Extra info maintained while defining an actor.
|
// Extra info maintained while defining an actor.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
class DDropItem;
|
struct FDropItem;
|
||||||
|
|
||||||
struct Baggage
|
struct Baggage
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ struct Baggage
|
||||||
int Lumpnum;
|
int Lumpnum;
|
||||||
FStateDefinitions statedef;
|
FStateDefinitions statedef;
|
||||||
|
|
||||||
DDropItem *DropItemList;
|
FDropItem *DropItemList;
|
||||||
|
|
||||||
FScriptPosition ScriptPosition;
|
FScriptPosition ScriptPosition;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1136,4 +1136,40 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
|
||||||
FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret);
|
FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret);
|
||||||
(*self) += s;
|
(*self) += s;
|
||||||
return 0;
|
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]);
|
||||||
|
}
|
||||||
|
|
|
@ -66,9 +66,10 @@
|
||||||
#include "teaminfo.h"
|
#include "teaminfo.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
#include "vmbuilder.h"
|
#include "backend/vmbuilder.h"
|
||||||
#include "a_keys.h"
|
#include "a_keys.h"
|
||||||
#include "g_levellocals.h"
|
#include "g_levellocals.h"
|
||||||
|
#include "d_player.h"
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -97,7 +98,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool
|
||||||
}
|
}
|
||||||
static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
|
static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
|
||||||
{
|
{
|
||||||
return static_cast<PClassInventory *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional));
|
return static_cast<AInventory::MetaClass *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional));
|
||||||
}
|
}
|
||||||
static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
|
static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
|
||||||
{
|
{
|
||||||
|
@ -560,7 +561,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy ((void *)defaults, (void *)GetDefault<AActor>(), sizeof(AActor));
|
*defaults = *GetDefault<AActor>();
|
||||||
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
|
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
|
||||||
bag.DropItemList = NULL;
|
bag.DropItemList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DDropItem *di = new DDropItem;
|
FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
|
||||||
|
|
||||||
di->Name = type;
|
di->Name = type;
|
||||||
di->Probability = 255;
|
di->Probability = 255;
|
||||||
|
@ -938,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor)
|
||||||
}
|
}
|
||||||
di->Next = bag.DropItemList;
|
di->Next = bag.DropItemList;
|
||||||
bag.DropItemList = di;
|
bag.DropItemList = di;
|
||||||
GC::WriteBarrier(di);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
|
DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
|
||||||
{
|
{
|
||||||
static_cast<PClassInventory*>(info)->RestrictedToPlayerClass.Clear();
|
static_cast<PClassActor*>(info)->RestrictedToPlayerClass.Clear();
|
||||||
for(int i = 0;i < PROP_PARM_COUNT;++i)
|
for(int i = 0;i < PROP_PARM_COUNT;++i)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(n, i);
|
PROP_STRING_PARM(n, i);
|
||||||
if (*n != 0)
|
if (*n != 0)
|
||||||
static_cast<PClassInventory*>(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n));
|
static_cast<PClassActor*>(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1713,12 +1713,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
|
DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
|
||||||
{
|
{
|
||||||
static_cast<PClassInventory*>(info)->ForbiddenToPlayerClass.Clear();
|
static_cast<PClassActor*>(info)->ForbiddenToPlayerClass.Clear();
|
||||||
for(int i = 0;i < PROP_PARM_COUNT;++i)
|
for(int i = 0;i < PROP_PARM_COUNT;++i)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(n, i);
|
PROP_STRING_PARM(n, i);
|
||||||
if (*n != 0)
|
if (*n != 0)
|
||||||
static_cast<PClassInventory*>(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n));
|
static_cast<PClassActor*>(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1734,31 +1734,47 @@ DEFINE_CLASS_PROPERTY(amount, I, Inventory)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY(icon, S, Inventory)
|
static void SetIcon(FTextureID &icon, Baggage &bag, const char *i)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(i, 0);
|
|
||||||
|
|
||||||
if (i == NULL || i[0] == '\0')
|
if (i == NULL || i[0] == '\0')
|
||||||
{
|
{
|
||||||
defaults->Icon.SetNull();
|
icon.SetNull();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
|
icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch);
|
||||||
if (!defaults->Icon.isValid())
|
if (!icon.isValid())
|
||||||
{
|
{
|
||||||
// Don't print warnings if the item is for another game or if this is a shareware IWAD.
|
// Don't print warnings if the item is for another game or if this is a shareware IWAD.
|
||||||
// Strife's teaser doesn't contain all the icon graphics of the full game.
|
// Strife's teaser doesn't contain all the icon graphics of the full game.
|
||||||
if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) &&
|
if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) &&
|
||||||
!(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
|
!(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
|
||||||
{
|
{
|
||||||
bag.ScriptPosition.Message(MSG_WARNING,
|
bag.ScriptPosition.Message(MSG_WARNING,
|
||||||
"Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars());
|
"Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_CLASS_PROPERTY(icon, S, Inventory)
|
||||||
|
{
|
||||||
|
PROP_STRING_PARM(i, 0);
|
||||||
|
SetIcon(defaults->Icon, bag, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_CLASS_PROPERTY(althudicon, S, Inventory)
|
||||||
|
{
|
||||||
|
PROP_STRING_PARM(i, 0);
|
||||||
|
SetIcon(defaults->AltHUDIcon, bag, i);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1801,8 +1817,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
|
||||||
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
|
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory)));
|
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||||
static_cast<PClassInventory *>(info)->PickupMsg = str;
|
static_cast<PClassActor *>(info)->PickupMsg = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
|
||||||
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
|
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
|
||||||
{
|
{
|
||||||
PROP_INT_PARM(i, 0);
|
PROP_INT_PARM(i, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory)));
|
defaults->GiveQuest = i;
|
||||||
static_cast<PClassInventory *>(info)->GiveQuest = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2065,8 +2080,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon)
|
||||||
DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
|
DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
|
||||||
{
|
{
|
||||||
PROP_INT_PARM(i, 0);
|
PROP_INT_PARM(i, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon)));
|
defaults->SlotNumber = i;
|
||||||
static_cast<PClassWeapon *>(info)->SlotNumber = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2075,8 +2089,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
|
||||||
DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
|
DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
|
||||||
{
|
{
|
||||||
PROP_DOUBLE_PARM(i, 0);
|
PROP_DOUBLE_PARM(i, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon)));
|
defaults->SlotPriority = int(i*65536);
|
||||||
static_cast<PClassWeapon *>(info)->SlotPriority = int(i*65536);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2098,9 +2111,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
|
||||||
|
|
||||||
int alpha;
|
int alpha;
|
||||||
PalEntry *pBlendColor;
|
PalEntry *pBlendColor;
|
||||||
bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver));
|
bool isgiver = info->IsDescendantOf(NAME_PowerupGiver);
|
||||||
|
|
||||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver)
|
if (info->IsDescendantOf(NAME_Powerup) || isgiver)
|
||||||
{
|
{
|
||||||
pBlendColor = &defaults->ColorVar(NAME_BlendColor);
|
pBlendColor = &defaults->ColorVar(NAME_BlendColor);
|
||||||
}
|
}
|
||||||
|
@ -2150,7 +2163,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
|
||||||
{
|
{
|
||||||
PalEntry BlendColor;
|
PalEntry BlendColor;
|
||||||
|
|
||||||
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
|
I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
|
||||||
return;
|
return;
|
||||||
|
@ -2185,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
|
DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
|
||||||
{
|
{
|
||||||
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n");
|
I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n");
|
||||||
return;
|
return;
|
||||||
|
@ -2200,7 +2213,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory)
|
DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory)
|
||||||
{
|
{
|
||||||
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n");
|
I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n");
|
||||||
return;
|
return;
|
||||||
|
@ -2216,7 +2229,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
|
|
||||||
if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver))
|
||||||
{
|
{
|
||||||
I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n");
|
I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n");
|
||||||
return;
|
return;
|
||||||
|
@ -2263,8 +2276,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
|
DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
info->DisplayName = str;
|
||||||
static_cast<PClassPlayerPawn *>(info)->DisplayName = str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2276,8 +2288,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn)
|
||||||
|
|
||||||
FString tmp = str;
|
FString tmp = str;
|
||||||
tmp.ReplaceChars (' ', '_');
|
tmp.ReplaceChars (' ', '_');
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None;
|
||||||
static_cast<PClassPlayerPawn *>(info)->SoundClass = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2288,21 +2299,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
FString tmp = str;
|
FString tmp = str;
|
||||||
|
|
||||||
tmp.ToUpper();
|
if (tmp.Len() == 0) defaults->Face = NAME_None;
|
||||||
bool valid = (tmp.Len() == 3 &&
|
else
|
||||||
(((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,
|
tmp.ToUpper();
|
||||||
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
|
bool valid = (tmp.Len() == 3 &&
|
||||||
tmp.GetChars(), info->TypeName.GetChars ());
|
(((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)
|
if (start > end)
|
||||||
swapvalues (start, end);
|
swapvalues (start, end);
|
||||||
|
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
defaults->ColorRangeStart = start;
|
||||||
static_cast<PClassPlayerPawn *>(info)->ColorRangeStart = start;
|
defaults->ColorRangeEnd = end;
|
||||||
static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2373,8 +2385,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
ColorSets.Push(std::make_tuple(info, setnum, color));
|
||||||
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2400,8 +2411,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
|
||||||
}
|
}
|
||||||
else if (color.Lump >= 0)
|
else if (color.Lump >= 0)
|
||||||
{
|
{
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
ColorSets.Push(std::make_tuple(info, setnum, color));
|
||||||
static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2418,8 +2428,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
FPlayerColorSet color;
|
||||||
static_cast<PClassPlayerPawn *>(info)->ColorSets.Remove(setnum);
|
memset(&color, 0, sizeof(color));
|
||||||
|
ColorSets.Push(std::make_tuple(info, setnum, color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2653,8 +2664,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn)
|
||||||
PROP_STRING_PARM(type, 3);
|
PROP_STRING_PARM(type, 3);
|
||||||
|
|
||||||
color.a = BYTE(255 * clamp<double>(a, 0.f, 1.f));
|
color.a = BYTE(255 * clamp<double>(a, 0.f, 1.f));
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
PainFlashes.Push(std::make_tuple(info, type, color));
|
||||||
static_cast<PClassPlayerPawn *>(info)->PainFlashes.Insert(type, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2674,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
|
||||||
bag.DropItemList = NULL;
|
bag.DropItemList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DDropItem *di = new DDropItem;
|
FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem));
|
||||||
|
|
||||||
di->Name = str;
|
di->Name = str;
|
||||||
di->Probability = 255;
|
di->Probability = 255;
|
||||||
|
@ -2686,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
|
||||||
}
|
}
|
||||||
di->Next = bag.DropItemList;
|
di->Next = bag.DropItemList;
|
||||||
bag.DropItemList = di;
|
bag.DropItemList = di;
|
||||||
GC::WriteBarrier(di);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2695,8 +2704,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
|
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
defaults->InvulMode = str;
|
||||||
static_cast<PClassPlayerPawn *>(info)->InvulMode = str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2705,8 +2713,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
|
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
|
||||||
{
|
{
|
||||||
PROP_STRING_PARM(str, 0);
|
PROP_STRING_PARM(str, 0);
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
defaults->HealingRadiusType = str;
|
||||||
static_cast<PClassPlayerPawn *>(info)->HealingRadiusType = str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2714,11 +2721,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
|
DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
|
||||||
{
|
{
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
PROP_DOUBLE_PARM(val, i);
|
PROP_DOUBLE_PARM(val, i);
|
||||||
static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val;
|
defaults->HexenArmor[i] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2727,9 +2733,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
|
DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
|
||||||
{
|
{
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
|
||||||
PROP_STRING_PARM(val, 0);
|
PROP_STRING_PARM(val, 0);
|
||||||
static_cast<PClassPlayerPawn *>(info)->Portrait = val;
|
defaults->Portrait = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -2739,7 +2744,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
|
||||||
{
|
{
|
||||||
PROP_INT_PARM(slot, 0);
|
PROP_INT_PARM(slot, 0);
|
||||||
|
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
|
|
||||||
if (slot < 0 || slot > 9)
|
if (slot < 0 || slot > 9)
|
||||||
{
|
{
|
||||||
I_Error("Slot must be between 0 and 9.");
|
I_Error("Slot must be between 0 and 9.");
|
||||||
|
@ -2753,7 +2757,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
|
||||||
PROP_STRING_PARM(str, i);
|
PROP_STRING_PARM(str, i);
|
||||||
weapons << ' ' << str;
|
weapons << ' ' << str;
|
||||||
}
|
}
|
||||||
static_cast<PClassPlayerPawn *>(info)->Slot[slot] = &weapons[1];
|
defaults->Slot[slot] = weapons.IsEmpty()? NAME_None : FName(weapons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#include "vectors.h"
|
#include "vectors.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
#include "doomerrors.h"
|
#include "doomerrors.h"
|
||||||
|
#include "memarena.h"
|
||||||
|
|
||||||
|
extern FMemArena ClassDataAllocator;
|
||||||
|
|
||||||
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
|
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
|
||||||
#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function
|
#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function
|
||||||
|
@ -693,10 +696,8 @@ do_double: if (inexact)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class VMFunction : public DObject
|
class VMFunction
|
||||||
{
|
{
|
||||||
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
|
|
||||||
HAS_OBJECT_POINTERS;
|
|
||||||
public:
|
public:
|
||||||
bool Native;
|
bool Native;
|
||||||
bool Final = false; // cannot be overridden
|
bool Final = false; // cannot be overridden
|
||||||
|
@ -709,7 +710,29 @@ public:
|
||||||
|
|
||||||
class PPrototype *Proto;
|
class PPrototype *Proto;
|
||||||
|
|
||||||
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {}
|
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL)
|
||||||
|
{
|
||||||
|
AllFunctions.Push(this);
|
||||||
|
}
|
||||||
|
virtual ~VMFunction() {}
|
||||||
|
|
||||||
|
void *operator new(size_t size)
|
||||||
|
{
|
||||||
|
return ClassDataAllocator.Alloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *block) {}
|
||||||
|
void operator delete[](void *block) {}
|
||||||
|
static void DeleteAll()
|
||||||
|
{
|
||||||
|
for (auto f : AllFunctions)
|
||||||
|
{
|
||||||
|
f->~VMFunction();
|
||||||
|
}
|
||||||
|
AllFunctions.Clear();
|
||||||
|
}
|
||||||
|
static TArray<VMFunction *> AllFunctions;
|
||||||
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
// VM frame layout:
|
// VM frame layout:
|
||||||
|
@ -838,11 +861,9 @@ struct FStatementInfo
|
||||||
|
|
||||||
class VMScriptFunction : public VMFunction
|
class VMScriptFunction : public VMFunction
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(VMScriptFunction, VMFunction);
|
|
||||||
public:
|
public:
|
||||||
VMScriptFunction(FName name=NAME_None);
|
VMScriptFunction(FName name=NAME_None);
|
||||||
~VMScriptFunction();
|
~VMScriptFunction();
|
||||||
size_t PropagateMark();
|
|
||||||
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
|
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
|
||||||
|
|
||||||
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
||||||
|
@ -910,7 +931,6 @@ private:
|
||||||
|
|
||||||
class VMNativeFunction : public VMFunction
|
class VMNativeFunction : public VMFunction
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(VMNativeFunction, VMFunction);
|
|
||||||
public:
|
public:
|
||||||
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
|
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
|
||||||
|
|
||||||
|
@ -997,6 +1017,7 @@ void NullParam(const char *varname);
|
||||||
|
|
||||||
// For required parameters.
|
// 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_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_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_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;
|
#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_PROLOGUE int paramnum = -1;
|
||||||
|
|
||||||
#define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x)
|
#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_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x)
|
||||||
#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x)
|
#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x)
|
||||||
#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x)
|
#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x)
|
||||||
|
|
|
@ -347,6 +347,17 @@ begin:
|
||||||
GETADDR(PA,RC,X_WRITE_NIL);
|
GETADDR(PA,RC,X_WRITE_NIL);
|
||||||
*(void **)ptr = reg.a[B];
|
*(void **)ptr = reg.a[B];
|
||||||
NEXTOP;
|
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):
|
OP(SV2):
|
||||||
ASSERTA(a); ASSERTF(B+1); ASSERTKD(C);
|
ASSERTA(a); ASSERTF(B+1); ASSERTKD(C);
|
||||||
GETADDR(PA,KC,X_WRITE_NIL);
|
GETADDR(PA,KC,X_WRITE_NIL);
|
||||||
|
|
|
@ -42,14 +42,9 @@ cycle_t VMCycles[10];
|
||||||
int VMCalls[10];
|
int VMCalls[10];
|
||||||
|
|
||||||
IMPLEMENT_CLASS(VMException, false, false)
|
IMPLEMENT_CLASS(VMException, false, false)
|
||||||
IMPLEMENT_CLASS(VMFunction, true, true)
|
|
||||||
|
|
||||||
IMPLEMENT_POINTERS_START(VMFunction)
|
TArray<VMFunction *> VMFunction::AllFunctions;
|
||||||
IMPLEMENT_POINTER(Proto)
|
|
||||||
IMPLEMENT_POINTERS_END
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(VMScriptFunction, false, false)
|
|
||||||
IMPLEMENT_CLASS(VMNativeFunction, false, false)
|
|
||||||
|
|
||||||
VMScriptFunction::VMScriptFunction(FName name)
|
VMScriptFunction::VMScriptFunction(FName name)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +82,6 @@ VMScriptFunction::~VMScriptFunction()
|
||||||
KonstS[i].~FString();
|
KonstS[i].~FString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
M_Free(Code);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +94,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
|
||||||
assert(numkonsts >= 0 && numkonsts <= 65535);
|
assert(numkonsts >= 0 && numkonsts <= 65535);
|
||||||
assert(numkonsta >= 0 && numkonsta <= 65535);
|
assert(numkonsta >= 0 && numkonsta <= 65535);
|
||||||
assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
|
assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
|
||||||
void *mem = M_Malloc(numops * sizeof(VMOP) +
|
void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) +
|
||||||
numkonstd * sizeof(int) +
|
numkonstd * sizeof(int) +
|
||||||
numkonstf * sizeof(double) +
|
numkonstf * sizeof(double) +
|
||||||
numkonsts * sizeof(FString) +
|
numkonsts * sizeof(FString) +
|
||||||
|
@ -166,24 +160,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
|
||||||
NumKonstA = numkonsta;
|
NumKonstA = numkonsta;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VMScriptFunction::PropagateMark()
|
|
||||||
{
|
|
||||||
if (KonstA != NULL)
|
|
||||||
{
|
|
||||||
FVoidObj *konsta = KonstA;
|
|
||||||
VM_UBYTE *atag = KonstATags();
|
|
||||||
for (int count = NumKonstA; count > 0; --count)
|
|
||||||
{
|
|
||||||
if (*atag++ == ATAG_OBJECT)
|
|
||||||
{
|
|
||||||
GC::Mark(konsta->o);
|
|
||||||
}
|
|
||||||
konsta++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NumKonstA * sizeof(void *) + Super::PropagateMark();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VMScriptFunction::InitExtra(void *addr)
|
void VMScriptFunction::InitExtra(void *addr)
|
||||||
{
|
{
|
||||||
char *caddr = (char*)addr;
|
char *caddr = (char*)addr;
|
||||||
|
|
|
@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string
|
||||||
xx(SS_R, ss, RPRSRI, NOP, 0, 0),
|
xx(SS_R, ss, RPRSRI, NOP, 0, 0),
|
||||||
xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
|
xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
|
||||||
xx(SP_R, sp, RPRPRI, NOP, 0, 0),
|
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, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2
|
||||||
xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
|
xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
|
||||||
xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3
|
xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "gdtoa.h"
|
#include "gdtoa.h"
|
||||||
#include "vmbuilder.h"
|
#include "backend/vmbuilder.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
|
static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
|
||||||
|
@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
|
||||||
case AST_DynArrayType:
|
case AST_DynArrayType:
|
||||||
if (allowarraytypes)
|
if (allowarraytypes)
|
||||||
{
|
{
|
||||||
Error(field, "%s: Dynamic array types not implemented yet", name.GetChars());
|
|
||||||
auto atype = static_cast<ZCC_DynArrayType *>(ztype);
|
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;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2440,19 +2447,6 @@ void ZCCCompiler::CompileStates()
|
||||||
continue;
|
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.
|
FString statename; // The state builder wants the label as one complete string, not separated into tokens.
|
||||||
FStateDefinitions statedef;
|
FStateDefinitions statedef;
|
||||||
statedef.MakeStateDefines(dyn_cast<PClassActor>(c->Type()->ParentClass));
|
statedef.MakeStateDefines(dyn_cast<PClassActor>(c->Type()->ParentClass));
|
||||||
|
@ -2651,7 +2645,7 @@ void ZCCCompiler::CompileStates()
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
static_cast<PClassActor *>(c->Type())->Finalize(statedef);
|
GetDefaultByType(c->Type())->Finalize(statedef);
|
||||||
}
|
}
|
||||||
catch (CRecoverableError &err)
|
catch (CRecoverableError &err)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define ZCC_COMPILE_H
|
#define ZCC_COMPILE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "codegeneration/codegen.h"
|
#include "backend/codegen.h"
|
||||||
|
|
||||||
struct Baggage;
|
struct Baggage;
|
||||||
struct FPropertyInfo;
|
struct FPropertyInfo;
|
||||||
|
|
|
@ -2187,17 +2187,17 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
|
||||||
{
|
{
|
||||||
if (arc.isWriting())
|
if (arc.isWriting())
|
||||||
{
|
{
|
||||||
const char *n = font->GetName();
|
FName n = font->GetName();
|
||||||
return arc.StringPtr(key, n);
|
return arc(key, n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char *n;
|
FName n;
|
||||||
arc.StringPtr(key, n);
|
arc(key, n);
|
||||||
font = V_GetFont(n);
|
font = V_GetFont(n);
|
||||||
if (font == nullptr)
|
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;
|
font = SmallFont;
|
||||||
}
|
}
|
||||||
return arc;
|
return arc;
|
||||||
|
|
|
@ -246,11 +246,6 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat
|
||||||
template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def);
|
template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def);
|
||||||
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def);
|
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def);
|
||||||
|
|
||||||
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, PClassPlayerPawn *&clst, PClassPlayerPawn **def)
|
|
||||||
{
|
|
||||||
return Serialize(arc, key, (PClassActor *&)clst, (PClassActor **)def);
|
|
||||||
}
|
|
||||||
|
|
||||||
FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode);
|
FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode);
|
||||||
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def)
|
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def)
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
|
||||||
}
|
}
|
||||||
|
|
||||||
PalEntry painFlash = CPlayer->mo->DamageFade;
|
PalEntry painFlash = CPlayer->mo->DamageFade;
|
||||||
CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash);
|
CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash);
|
||||||
|
|
||||||
if (painFlash.a != 0)
|
if (painFlash.a != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -124,12 +124,12 @@ static int PalFromRGB(uint32 rgb)
|
||||||
|
|
||||||
void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...)
|
void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...)
|
||||||
{
|
{
|
||||||
va_list tags;
|
Va_List tags;
|
||||||
va_start(tags, tags_first);
|
va_start(tags.list, tags_first);
|
||||||
DrawParms parms;
|
DrawParms parms;
|
||||||
|
|
||||||
bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false);
|
bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false);
|
||||||
va_end(tags);
|
va_end(tags.list);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -137,7 +137,7 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ..
|
||||||
DrawTextureParms(img, parms);
|
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)
|
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;
|
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.
|
// 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 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)
|
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.
|
// 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;
|
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,
|
void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h,
|
||||||
|
|
116
src/v_font.cpp
116
src/v_font.cpp
|
@ -94,6 +94,7 @@ The FON2 header is followed by variable length data:
|
||||||
#include "r_data/r_translate.h"
|
#include "r_data/r_translate.h"
|
||||||
#include "colormatcher.h"
|
#include "colormatcher.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
|
#include "v_text.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -340,6 +341,14 @@ FFont *V_GetFont(const char *name)
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FFont, GetFont)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_NAME(name);
|
||||||
|
ACTION_RETURN_POINTER(V_GetFont(name.GetChars()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FFont :: FFont
|
// FFont :: FFont
|
||||||
|
@ -366,7 +375,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
|
||||||
LastChar = first + count - 1;
|
LastChar = first + count - 1;
|
||||||
FontHeight = 0;
|
FontHeight = 0;
|
||||||
GlobalKerning = false;
|
GlobalKerning = false;
|
||||||
Name = copystring (name);
|
FontName = name;
|
||||||
Next = FirstFont;
|
Next = FirstFont;
|
||||||
FirstFont = this;
|
FirstFont = this;
|
||||||
Cursor = '_';
|
Cursor = '_';
|
||||||
|
@ -478,11 +487,6 @@ FFont::~FFont ()
|
||||||
delete[] PatchRemap;
|
delete[] PatchRemap;
|
||||||
PatchRemap = NULL;
|
PatchRemap = NULL;
|
||||||
}
|
}
|
||||||
if (Name)
|
|
||||||
{
|
|
||||||
delete[] Name;
|
|
||||||
Name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FFont **prev = &FirstFont;
|
FFont **prev = &FirstFont;
|
||||||
FFont *font = *prev;
|
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;
|
FFont *font = FirstFont;
|
||||||
|
|
||||||
while (font != NULL)
|
while (font != nullptr)
|
||||||
{
|
{
|
||||||
if (stricmp (font->Name, name) == 0)
|
if (font->FontName == name) return font;
|
||||||
break;
|
|
||||||
font = font->Next;
|
font = font->Next;
|
||||||
}
|
}
|
||||||
return font;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(FFont, FindFont)
|
DEFINE_ACTION_FUNCTION(FFont, FindFont)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_STRING(name);
|
PARAM_NAME(name);
|
||||||
ACTION_RETURN_POINTER(FFont::FindFont(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;
|
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
|
// FFont :: LoadTranslations
|
||||||
|
@ -935,7 +997,7 @@ FFont::FFont (int lump)
|
||||||
Lump = lump;
|
Lump = lump;
|
||||||
Chars = NULL;
|
Chars = NULL;
|
||||||
PatchRemap = NULL;
|
PatchRemap = NULL;
|
||||||
Name = NULL;
|
FontName = NAME_None;
|
||||||
Cursor = '_';
|
Cursor = '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,7 +1013,7 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
|
||||||
{
|
{
|
||||||
assert(lump >= 0);
|
assert(lump >= 0);
|
||||||
|
|
||||||
Name = copystring (name);
|
FontName = name;
|
||||||
|
|
||||||
FMemLump data1 = Wads.ReadLump (lump);
|
FMemLump data1 = Wads.ReadLump (lump);
|
||||||
const BYTE *data = (const BYTE *)data1.GetMem();
|
const BYTE *data = (const BYTE *)data1.GetMem();
|
||||||
|
@ -1189,7 +1251,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
|
||||||
if (destSize < 0)
|
if (destSize < 0)
|
||||||
{
|
{
|
||||||
i += FirstChar;
|
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];
|
FTexture *pic = TexMan[picnum];
|
||||||
|
|
||||||
Name = copystring(picname);
|
FontName = picname;
|
||||||
FontHeight = pic->GetScaledHeight();
|
FontHeight = pic->GetScaledHeight();
|
||||||
SpaceWidth = pic->GetScaledWidth();
|
SpaceWidth = pic->GetScaledWidth();
|
||||||
GlobalKerning = 0;
|
GlobalKerning = 0;
|
||||||
|
@ -1903,7 +1965,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
|
||||||
|
|
||||||
memcpy(this->notranslate, notranslate, 256*sizeof(bool));
|
memcpy(this->notranslate, notranslate, 256*sizeof(bool));
|
||||||
|
|
||||||
Name = copystring(name);
|
FontName = name;
|
||||||
Chars = new CharData[count];
|
Chars = new CharData[count];
|
||||||
charlumps = new FTexture*[count];
|
charlumps = new FTexture*[count];
|
||||||
PatchRemap = new BYTE[256];
|
PatchRemap = new BYTE[256];
|
||||||
|
@ -2490,6 +2552,13 @@ EColorRange V_FindFontColor (FName name)
|
||||||
return CR_UNTRANSLATED;
|
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
|
// V_LogColorFromColorRange
|
||||||
|
@ -2664,12 +2733,3 @@ void V_ClearFonts()
|
||||||
SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL;
|
SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void V_RetranslateFonts()
|
|
||||||
{
|
|
||||||
FFont *font = FFont::FirstFont;
|
|
||||||
while(font)
|
|
||||||
{
|
|
||||||
font->LoadTranslations();
|
|
||||||
font = font->Next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -88,9 +88,9 @@ public:
|
||||||
int GetDefaultKerning () const { return GlobalKerning; }
|
int GetDefaultKerning () const { return GlobalKerning; }
|
||||||
virtual void LoadTranslations();
|
virtual void LoadTranslations();
|
||||||
void Preload() const;
|
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();
|
static void StaticPreloadFonts();
|
||||||
|
|
||||||
// Return width of string in pixels (unscaled)
|
// Return width of string in pixels (unscaled)
|
||||||
|
@ -127,14 +127,13 @@ protected:
|
||||||
BYTE *PatchRemap;
|
BYTE *PatchRemap;
|
||||||
|
|
||||||
int Lump;
|
int Lump;
|
||||||
char *Name;
|
FName FontName;
|
||||||
FFont *Next;
|
FFont *Next;
|
||||||
|
|
||||||
static FFont *FirstFont;
|
static FFont *FirstFont;
|
||||||
friend struct FontsDeleter;
|
friend struct FontsDeleter;
|
||||||
|
|
||||||
friend void V_ClearFonts();
|
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);
|
EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor);
|
||||||
FFont *V_GetFont(const char *);
|
FFont *V_GetFont(const char *);
|
||||||
void V_InitFontColors();
|
void V_InitFontColors();
|
||||||
void V_RetranslateFonts();
|
|
||||||
|
|
||||||
#endif //__V_FONT_H__
|
#endif //__V_FONT_H__
|
||||||
|
|
253
src/v_text.cpp
253
src/v_text.cpp
|
@ -47,11 +47,16 @@
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
|
|
||||||
|
int ListGetInt(VMVa_List &tags);
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// DrawChar
|
// DrawChar
|
||||||
//
|
//
|
||||||
// Write a single character using the given font
|
// Write a single character using the given font
|
||||||
//
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...)
|
void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...)
|
||||||
{
|
{
|
||||||
if (font == NULL)
|
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)))
|
if (NULL != (pic = font->GetChar (character, &dummy)))
|
||||||
{
|
{
|
||||||
DrawParms parms;
|
DrawParms parms;
|
||||||
va_list tags;
|
Va_List tags;
|
||||||
va_start(tags, tag_first);
|
va_start(tags.list, tag_first);
|
||||||
bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false);
|
bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false);
|
||||||
va_end(tags);
|
va_end(tags.list);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
return;
|
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
|
// DrawText
|
||||||
//
|
//
|
||||||
// Write a string using the given font
|
// 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;
|
int w;
|
||||||
const BYTE *ch;
|
const BYTE *ch;
|
||||||
int c;
|
int c;
|
||||||
int cx;
|
double cx;
|
||||||
int cy;
|
double cy;
|
||||||
int boldcolor;
|
int boldcolor;
|
||||||
FRemapTable *range;
|
FRemapTable *range;
|
||||||
int kerning;
|
int kerning;
|
||||||
FTexture *pic;
|
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;
|
if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
|
||||||
parms.celly *= parms.scaley;
|
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;
|
normalcolor = CR_UNTRANSLATED;
|
||||||
boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1;
|
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;
|
ch = (const BYTE *)string;
|
||||||
cx = x;
|
cx = x;
|
||||||
cy = y;
|
cy = y;
|
||||||
|
|
||||||
|
|
||||||
while ((const char *)ch - string < parms.maxstrlen)
|
while ((const char *)ch - string < parms.maxstrlen)
|
||||||
{
|
{
|
||||||
c = *ch++;
|
c = *ch++;
|
||||||
|
@ -135,14 +164,14 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
|
||||||
|
|
||||||
if (c == TEXTCOLOR_ESCAPE)
|
if (c == TEXTCOLOR_ESCAPE)
|
||||||
{
|
{
|
||||||
EColorRange newcolor = V_ParseFontColor (ch, normalcolor, boldcolor);
|
EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor);
|
||||||
if (newcolor != CR_UNDEFINED)
|
if (newcolor != CR_UNDEFINED)
|
||||||
{
|
{
|
||||||
range = font->GetColorTranslation (newcolor);
|
range = font->GetColorTranslation(newcolor);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
cx = x;
|
cx = x;
|
||||||
|
@ -150,7 +179,7 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != (pic = font->GetChar (c, &w)))
|
if (NULL != (pic = font->GetChar(c, &w)))
|
||||||
{
|
{
|
||||||
parms.remap = range;
|
parms.remap = range;
|
||||||
SetTextureParms(&parms, pic, cx, cy);
|
SetTextureParms(&parms, pic, cx, cy);
|
||||||
|
@ -166,52 +195,61 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...)
|
||||||
//
|
|
||||||
// Find string width using this font
|
|
||||||
//
|
|
||||||
int FFont::StringWidth (const BYTE *string) const
|
|
||||||
{
|
{
|
||||||
int w = 0;
|
Va_List tags;
|
||||||
int maxw = 0;
|
DrawParms parms;
|
||||||
|
|
||||||
while (*string)
|
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)
|
return;
|
||||||
{
|
|
||||||
++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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
DrawTextCommon(font, normalcolor, x, y, string, parms);
|
||||||
return MAX (maxw, w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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)
|
static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor)
|
||||||
{
|
{
|
||||||
if (!linecolor.IsEmpty())
|
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);
|
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;
|
const BYTE *space = NULL, *start = string;
|
||||||
size_t i, ii;
|
|
||||||
int c, w, nw;
|
int c, w, nw;
|
||||||
FString lastcolor, linecolor;
|
FString lastcolor, linecolor;
|
||||||
bool lastWasSpace = false;
|
bool lastWasSpace = false;
|
||||||
int kerning = font->GetDefaultKerning ();
|
int kerning = font->GetDefaultKerning ();
|
||||||
|
|
||||||
i = w = 0;
|
w = 0;
|
||||||
|
|
||||||
while ( (c = *string++) && i < countof(lines) )
|
while ( (c = *string++) )
|
||||||
{
|
{
|
||||||
if (c == TEXTCOLOR_ESCAPE)
|
if (c == TEXTCOLOR_ESCAPE)
|
||||||
{
|
{
|
||||||
|
@ -283,14 +320,14 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool
|
||||||
if (!space)
|
if (!space)
|
||||||
space = string - 1;
|
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)
|
if (c == '\n' && !preservecolor)
|
||||||
{
|
{
|
||||||
lastcolor = ""; // Why, oh why, did I do it like this?
|
lastcolor = ""; // Why, oh why, did I do it like this?
|
||||||
}
|
}
|
||||||
linecolor = lastcolor;
|
linecolor = lastcolor;
|
||||||
|
|
||||||
i++;
|
|
||||||
w = 0;
|
w = 0;
|
||||||
lastWasSpace = false;
|
lastWasSpace = false;
|
||||||
start = space;
|
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'
|
// String here is pointing one character after the '\0'
|
||||||
if (i < countof(lines) && --string - start >= 1)
|
if (--string - start >= 1)
|
||||||
{
|
{
|
||||||
const BYTE *s = start;
|
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 there is any non-white space in the remainder of the string, add it.
|
||||||
if (!isspace (*s++))
|
if (!isspace (*s++))
|
||||||
{
|
{
|
||||||
breakit (&lines[i++], font, start, string, linecolor);
|
auto i = Lines.Reserve(1);
|
||||||
|
breakit (&Lines[i], font, start, string, linecolor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a copy of the broken lines and return them
|
// 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;
|
return broken;
|
||||||
}
|
}
|
||||||
|
@ -346,3 +388,56 @@ void V_FreeBrokenLines (FBrokenLines *lines)
|
||||||
delete[] 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));
|
||||||
|
}
|
||||||
|
|
10
src/v_text.h
10
src/v_text.h
|
@ -75,11 +75,11 @@ struct FBrokenLines
|
||||||
#define TEXTCOLOR_CHAT "\034*"
|
#define TEXTCOLOR_CHAT "\034*"
|
||||||
#define TEXTCOLOR_TEAMCHAT "\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);
|
void V_FreeBrokenLines (FBrokenLines *lines);
|
||||||
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false)
|
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); }
|
{ return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor, count); }
|
||||||
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false)
|
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); }
|
{ return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor, count); }
|
||||||
|
|
||||||
#endif //__V_TEXT_H__
|
#endif //__V_TEXT_H__
|
||||||
|
|
|
@ -1397,7 +1397,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real
|
||||||
cy1 = MAX(cheight / designheight, 1);
|
cy1 = MAX(cheight / designheight, 1);
|
||||||
cx2 = MAX(realwidth / designwidth, 1);
|
cx2 = MAX(realwidth / designwidth, 1);
|
||||||
cy2 = MAX(realheight / designheight, 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.
|
{ // e.g. 640x360 looks better with this.
|
||||||
*cleanx = cx1;
|
*cleanx = cx1;
|
||||||
*cleany = cy1;
|
*cleany = cy1;
|
||||||
|
|
|
@ -177,6 +177,11 @@ struct DrawParms
|
||||||
bool virtBottom;
|
bool virtBottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Va_List
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
};
|
||||||
|
|
||||||
struct VMVa_List
|
struct VMVa_List
|
||||||
{
|
{
|
||||||
VMValue *args;
|
VMValue *args;
|
||||||
|
@ -269,8 +274,10 @@ public:
|
||||||
#undef DrawText // See WinUser.h for the definition of DrawText as a macro
|
#undef DrawText // See WinUser.h for the definition of DrawText as a macro
|
||||||
#endif
|
#endif
|
||||||
// 2D Text drawing
|
// 2D Text drawing
|
||||||
void DrawText (FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...);
|
void DrawText(FFont *font, int normalcolor, double x, double 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, 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:
|
protected:
|
||||||
BYTE *Buffer;
|
BYTE *Buffer;
|
||||||
|
@ -279,6 +286,8 @@ protected:
|
||||||
int Pitch;
|
int Pitch;
|
||||||
int LockCount;
|
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;
|
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;
|
void DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags) = delete;
|
||||||
virtual void DrawTextureParms(FTexture *img, DrawParms &parms);
|
virtual void DrawTextureParms(FTexture *img, DrawParms &parms);
|
||||||
|
|
|
@ -449,4 +449,14 @@ template<> struct THashTraits<FString>
|
||||||
// Compares two keys, returning zero if they are the same.
|
// Compares two keys, returning zero if they are the same.
|
||||||
int Compare(const FString &left, const FString &right) { return left.Compare(right); }
|
int Compare(const FString &left, const FString &right) { return left.Compare(right); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FStringNoInit
|
||||||
|
{
|
||||||
|
char mem[sizeof(FString)];
|
||||||
|
operator FString&()
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<FString*>(&mem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1417,6 +1417,9 @@ TXT_KILLED_ORACLE = "You've Killed The Oracle!";
|
||||||
TXT_KILLED_MACIL = "You Killed Macil!";
|
TXT_KILLED_MACIL = "You Killed Macil!";
|
||||||
TXT_KILLED_LOREMASTER = "You've Killed the Loremaster!";
|
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
|
// Strife pickup messages
|
||||||
|
|
||||||
TXT_METALARMOR = "You picked up the Metal Armor.";
|
TXT_METALARMOR = "You picked up the Metal Armor.";
|
||||||
|
|
|
@ -498,6 +498,7 @@ class Actor : Thinker native
|
||||||
native bool UsePuzzleItem(int PuzzleItemType);
|
native bool UsePuzzleItem(int PuzzleItemType);
|
||||||
native float AccuracyFactor();
|
native float AccuracyFactor();
|
||||||
native bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash);
|
native bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash);
|
||||||
|
action native void SetCamera(Actor cam, bool revert = false);
|
||||||
|
|
||||||
// DECORATE compatible functions
|
// DECORATE compatible functions
|
||||||
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
|
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue