mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 23:32:02 +00:00
a112b29c43
- finished work on the Doom status bar. I also took the opportunity to fix the layout of the inventory bar which is a bit broken in SBARINFO. - tuned the selection rules for deciding what creates the status bar, so that the most recent definition that can be found is chosen.
841 lines
25 KiB
Text
841 lines
25 KiB
Text
|
|
struct MugShot
|
|
{
|
|
enum StateFlags
|
|
{
|
|
STANDARD = 0x0,
|
|
|
|
XDEATHFACE = 0x1,
|
|
ANIMATEDGODMODE = 0x2,
|
|
DISABLEGRIN = 0x4,
|
|
DISABLEOUCH = 0x8,
|
|
DISABLEPAIN = 0x10,
|
|
DISABLERAMPAGE = 0x20,
|
|
CUSTOM = 0x40,
|
|
}
|
|
}
|
|
|
|
class HUDFont native ui
|
|
{
|
|
native Font mFont;
|
|
native static HUDFont Create(Font fnt, int spacing = 0, bool monospaced = false, int shadowx = 0, int shadowy = 0);
|
|
}
|
|
|
|
class InventoryBarState ui
|
|
{
|
|
TextureID box;
|
|
TextureID selector;
|
|
Vector2 boxsize;
|
|
Vector2 innersize;
|
|
int boxframesize;
|
|
|
|
TextureID left;
|
|
TextureID right;
|
|
Vector2 arrowoffset;
|
|
|
|
double itemalpha;
|
|
|
|
HUDFont amountfont;
|
|
int cr;
|
|
int flags;
|
|
|
|
// The default settings here are what SBARINFO is using.
|
|
static InventoryBarState Create(HUDFont indexfont = null, int cr = Font.CR_UNTRANSLATED, double itemalpha = 1.,
|
|
String boxgfx = "ARTIBOX", String selgfx = "SELECTBO", int fsize = 2,
|
|
String leftgfx = "INVGEML1", String rightgfx = "INVGEMR1", Vector2 arrowoffs = (0, 0), int flags = 0)
|
|
{
|
|
let me = new ("InventoryBarState");
|
|
me.itemalpha = itemalpha;
|
|
me.box = TexMan.CheckForTexture(boxgfx, TexMan.TYPE_MiscPatch);
|
|
me.selector = TexMan.CheckForTexture(selgfx, TexMan.TYPE_MiscPatch);
|
|
me.boxframesize = fsize;
|
|
if (me.box.IsValid() || me.selector.IsValid()) me.boxsize = TexMan.GetScaledSize(me.box.IsValid()? me.box : me.selector);
|
|
else me.boxsize = (32., 32.);
|
|
me.innersize = me.boxsize - (2.*fsize, 2.*fsize);
|
|
me.left = TexMan.CheckForTexture(leftgfx, TexMan.TYPE_MiscPatch);
|
|
me.right = TexMan.CheckForTexture(rightgfx, TexMan.TYPE_MiscPatch);
|
|
me.arrowoffset = arrowoffs;
|
|
me.arrowoffset.Y += me.boxsize.Y/2; // default is centered to the side of the box.
|
|
if (indexfont == null)
|
|
{
|
|
me.amountfont = HUDFont.Create("INDEXFONT");
|
|
if (cr == Font.CR_UNTRANSLATED) cr = Font.CR_GOLD;
|
|
}
|
|
else me.amountfont = indexfont;
|
|
me.cr = cr;
|
|
me.flags = flags;
|
|
return me;
|
|
}
|
|
}
|
|
|
|
|
|
class BaseStatusBar native ui
|
|
{
|
|
enum EPop
|
|
{
|
|
POP_NoChange = -1,
|
|
POP_None,
|
|
POP_Log,
|
|
POP_Keys,
|
|
POP_Status
|
|
}
|
|
|
|
// Status face stuff
|
|
enum EMug
|
|
{
|
|
ST_NUMPAINFACES = 5,
|
|
ST_NUMSTRAIGHTFACES = 3,
|
|
ST_NUMTURNFACES = 2,
|
|
ST_NUMSPECIALFACES = 3,
|
|
ST_NUMEXTRAFACES = 2,
|
|
ST_FACESTRIDE = ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES,
|
|
ST_NUMFACES = ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES,
|
|
|
|
ST_TURNOFFSET = ST_NUMSTRAIGHTFACES,
|
|
ST_OUCHOFFSET = ST_TURNOFFSET + ST_NUMTURNFACES,
|
|
ST_EVILGRINOFFSET = ST_OUCHOFFSET + 1,
|
|
ST_RAMPAGEOFFSET = ST_EVILGRINOFFSET + 1,
|
|
ST_GODFACE = ST_NUMPAINFACES*ST_FACESTRIDE,
|
|
ST_DEADFACE = ST_GODFACE + 1
|
|
}
|
|
|
|
enum EHudState
|
|
{
|
|
HUD_StatusBar,
|
|
HUD_Fullscreen,
|
|
HUD_None,
|
|
|
|
HUD_AltHud // Used for passing through popups to the alt hud
|
|
}
|
|
|
|
enum DI_Flags
|
|
{
|
|
DI_SKIPICON = 0x1,
|
|
DI_SKIPALTICON = 0x2,
|
|
DI_SKIPSPAWN = 0x4,
|
|
DI_SKIPREADY = 0x8,
|
|
DI_ALTICONFIRST = 0x10,
|
|
DI_TRANSLATABLE = 0x20,
|
|
DI_FORCESCALE = 0x40,
|
|
DI_DIM = 0x80,
|
|
DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar.
|
|
DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar.
|
|
DI_DIMDEPLETED = 0x400,
|
|
DI_DONTANIMATE = 0x800, // do not animate the texture
|
|
// These 2 flags are only used by SBARINFO
|
|
DI_DRAWINBOX = 0x1000, // Set when either width or height is not zero
|
|
DI_ALTERNATEONFAIL = 0x2000,
|
|
|
|
DI_SCREEN_AUTO = 0, // decide based on given offsets.
|
|
DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect
|
|
|
|
DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN,
|
|
|
|
DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN,
|
|
DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN,
|
|
|
|
DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP|DI_SCREEN_LEFT,
|
|
DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP|DI_SCREEN_RIGHT,
|
|
DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_LEFT,
|
|
DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_RIGHT,
|
|
DI_SCREEN_CENTER = DI_SCREEN_VCENTER|DI_SCREEN_HCENTER,
|
|
DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_HCENTER,
|
|
DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET|DI_SCREEN_VOFFSET,
|
|
|
|
DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment.
|
|
|
|
DI_ITEM_TOP = 0x80000,
|
|
DI_ITEM_VCENTER = 0x100000,
|
|
DI_ITEM_BOTTOM = 0, // this is the default vertical alignment
|
|
DI_ITEM_VOFFSET = 0x180000,
|
|
DI_ITEM_VMASK = 0x180000,
|
|
|
|
DI_ITEM_LEFT = 0x200000,
|
|
DI_ITEM_HCENTER = 0, // this is the deafault horizontal alignment
|
|
DI_ITEM_RIGHT = 0x400000,
|
|
DI_ITEM_HOFFSET = 0x600000,
|
|
DI_ITEM_HMASK = 0x600000,
|
|
|
|
DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT,
|
|
DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT,
|
|
DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT,
|
|
DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT,
|
|
DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER,
|
|
DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER,
|
|
DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET,
|
|
|
|
DI_TEXT_ALIGN_LEFT = 0,
|
|
DI_TEXT_ALIGN_RIGHT = 0x800000,
|
|
DI_TEXT_ALIGN_CENTER = 0x1000000,
|
|
|
|
DI_ALPHAMAPPED = 0x2000000,
|
|
DI_NOSHADOW = 0x4000000,
|
|
DI_ALWAYSSHOWCOUNTERS = 0x8000000,
|
|
};
|
|
|
|
enum IconType
|
|
{
|
|
ITYPE_PLAYERICON = 1000,
|
|
ITYPE_AMMO1,
|
|
ITYPE_AMMO2,
|
|
ITYPE_ARMOR,
|
|
ITYPE_WEAPON,
|
|
ITYPE_SIGIL,
|
|
ITYPE_WEAPONSLOT,
|
|
ITYPE_SELECTEDINVENTORY,
|
|
}
|
|
|
|
enum HexArmorType
|
|
{
|
|
HEXENARMOR_ARMOR,
|
|
HEXENARMOR_SHIELD,
|
|
HEXENARMOR_HELM,
|
|
HEXENARMOR_AMULET,
|
|
};
|
|
|
|
enum AmmoModes
|
|
{
|
|
AMMO_PRIMARY,
|
|
AMMO_SECONDARY,
|
|
AMMO_ANY,
|
|
AMMO_BOTH
|
|
};
|
|
|
|
enum EHudDraw
|
|
{
|
|
HUD_Normal,
|
|
HUD_HorizCenter
|
|
}
|
|
|
|
enum ENumFlags
|
|
{
|
|
FNF_FILLZEROS,
|
|
FNF_WHENNOTZERO,
|
|
}
|
|
|
|
const XHAIRSHRINKSIZE =(1./18);
|
|
const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE);
|
|
const POWERUPICONSIZE = 32;
|
|
|
|
|
|
native int ST_X, ST_Y;
|
|
native int RelTop;
|
|
native int HorizontalResolution, VerticalResolution;
|
|
native bool Scaled;
|
|
native bool Centering;
|
|
native bool FixedOrigin;
|
|
native bool CompleteBorder;
|
|
native double CrosshairSize;
|
|
native double Displacement;
|
|
native PlayerInfo CPlayer;
|
|
native bool ShowLog;
|
|
native Vector2 defaultScale; // factor for fully scaled fullscreen display.
|
|
|
|
// These are block properties for the drawers. A child class can set them to have a block of items use the same settings.
|
|
native double Alpha;
|
|
native Vector2 drawOffset; // can be set by subclasses to offset drawing operations
|
|
native double drawClip[4]; // defines a clipping rectangle (not used yet)
|
|
native bool fullscreenOffsets; // current screen is displayed with fullscreen behavior.
|
|
|
|
|
|
native void SetSize(int height, int vwidth, int vheight);
|
|
native Vector2 GetHUDScale();
|
|
native void BeginStatusBar(int resW, int resH, int relTop, bool completeborder = false, bool forceScaled = false);
|
|
native void BeginHUD(int resW, int resH, double Alpha, bool forcescaled = false);
|
|
|
|
virtual void Init() {}
|
|
|
|
native virtual void SetScaled(bool scale, bool force = false);
|
|
native virtual void Tick ();
|
|
native virtual void Draw (int state, double TicFrac);
|
|
native virtual void ScreenSizeChanged ();
|
|
native virtual clearscope void ReceivedWeapon (Weapon weapn);
|
|
native virtual clearscope void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false);
|
|
|
|
virtual void FlashItem (class<Inventory> itemtype) {}
|
|
virtual void AttachToPlayer (PlayerInfo player) { CPlayer = player; }
|
|
virtual void FlashCrosshair () { CrosshairSize = XHAIRPICKUPSIZE; }
|
|
virtual void NewGame () {}
|
|
virtual void ShowPop (int popnum) { ShowLog = (popnum == POP_Log && !ShowLog); }
|
|
virtual bool MustDrawLog(int state) { return true; }
|
|
|
|
native void RefreshBackground () const;
|
|
native TextureID GetMugshot(int accuracy, int stateflags=MugShot.STANDARD, String default_face = "STF");
|
|
|
|
// These functions are kept native solely for performance reasons. They get called repeatedly and can drag down performance easily if they get too slow.
|
|
native Inventory ValidateInvFirst (int numVisible) const;
|
|
native static TextureID, bool GetInventoryIcon(Inventory item, int flags);
|
|
native void DrawTexture(TextureID texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1));
|
|
native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1));
|
|
native void DrawString(HUDFont font, String string, Vector2 pos, int flags = 0, int translation = Font.CR_UNTRANSLATED, double Alpha = 1., int wrapwidth = -1, int linespacing = 4);
|
|
native static String FormatNumber(int number, int minsize = 0, int maxsize = 0, int format = 0, String prefix = "");
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// DBaseStatusBar :: GetCurrentAmmo
|
|
//
|
|
// Returns the types and amounts of ammo used by the current weapon. If the
|
|
// weapon only uses one type of ammo, it is always returned as ammo1.
|
|
//
|
|
//============================================================================
|
|
|
|
Inventory, Inventory, int, int GetCurrentAmmo () const
|
|
{
|
|
Ammo ammo1, ammo2;
|
|
if (CPlayer.ReadyWeapon != NULL)
|
|
{
|
|
ammo1 = CPlayer.ReadyWeapon.Ammo1;
|
|
ammo2 = CPlayer.ReadyWeapon.Ammo2;
|
|
if (ammo1 == NULL)
|
|
{
|
|
ammo1 = ammo2;
|
|
ammo2 = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ammo1 = ammo2 = NULL;
|
|
}
|
|
let ammocount1 = ammo1 != NULL ? ammo1.Amount : 0;
|
|
let ammocount2 = ammo2 != NULL ? ammo2.Amount : 0;
|
|
return ammo1, ammo2, ammocount1, ammocount2;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// Get an icon
|
|
//
|
|
//============================================================================
|
|
|
|
TextureID, Vector2 GetIcon(Inventory item, int flags, bool showdepleted = true)
|
|
{
|
|
TextureID icon;
|
|
Vector2 scale = (1,1);
|
|
icon.SetInvalid();
|
|
if (item != null)
|
|
{
|
|
bool applyscale;
|
|
[icon, applyscale] = GetInventoryIcon(item, flags);
|
|
|
|
if (item.Amount == 0 && !showdepleted) return icon, scale;
|
|
|
|
if (applyscale)
|
|
scale = item.Scale;
|
|
}
|
|
return icon, scale;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// Convenience functions to retrieve item tags
|
|
//
|
|
//============================================================================
|
|
|
|
String GetAmmoTag(bool secondary = false)
|
|
{
|
|
let w = CPlayer.ReadyWeapon;
|
|
if (w == null) return "";
|
|
let ammo = secondary? w.ammo2 : w.ammo1;
|
|
return ammo.GetTag();
|
|
}
|
|
|
|
String GetWeaponTag()
|
|
{
|
|
let w = CPlayer.ReadyWeapon;
|
|
if (w == null) return "";
|
|
return w.GetTag();
|
|
}
|
|
|
|
String GetSelectedInventoryTag()
|
|
{
|
|
let w = CPlayer.mo.InvSel;
|
|
if (w == null) return "";
|
|
return w.GetTag();
|
|
}
|
|
|
|
// These cannot be done in ZScript.
|
|
native String GetGlobalACSString(int index);
|
|
native String GetGlobalACSArrayString(int arrayno, int index);
|
|
native int GetGlobalACSValue(int index);
|
|
native int GetGlobalACSArrayValue(int arrayno, int index);
|
|
|
|
//============================================================================
|
|
//
|
|
// Convenience functions to retrieve some numbers
|
|
//
|
|
//============================================================================
|
|
|
|
int GetArmorAmount()
|
|
{
|
|
let armor = CPlayer.mo.FindInventory("BasicArmor");
|
|
return armor? armor.Amount : 0;
|
|
}
|
|
|
|
int, int GetAmount(class<Inventory> item)
|
|
{
|
|
let it = CPlayer.mo.FindInventory(item);
|
|
int ret1 = it? it.Amount : GetDefaultByType(item).Amount;
|
|
int ret2 = it? it.MaxAmount : GetDefaultByType(item).MaxAmount;
|
|
return ret1, ret2;
|
|
}
|
|
|
|
int GetMaxAmount(class<Inventory> item)
|
|
{
|
|
let it = CPlayer.mo.FindInventory(item);
|
|
return it? it.MaxAmount : GetDefaultByType(item).MaxAmount;
|
|
}
|
|
|
|
int GetArmorSavePercent()
|
|
{
|
|
double add = 0;
|
|
let harmor = HexenArmor(CPlayer.mo.FindInventory("HexenArmor"));
|
|
if(harmor != NULL)
|
|
{
|
|
add = harmor.Slots[0] + harmor.Slots[1] + harmor.Slots[2] + harmor.Slots[3] + harmor.Slots[4];
|
|
}
|
|
//Hexen counts basic armor also so we should too.
|
|
let armor = BasicArmor(CPlayer.mo.FindInventory("BasicArmor"));
|
|
if(armor != NULL)
|
|
{
|
|
add += armor.SavePercent * 100;
|
|
}
|
|
return int(add);
|
|
}
|
|
|
|
// Note that this retrieves the value in tics, not seconds like the equivalent SBARINFO function.
|
|
// The idea is to let the caller decide what to do with it instead of destroying accuracy here.
|
|
int GetAirTime()
|
|
{
|
|
if(CPlayer.mo.waterlevel < 3)
|
|
return level.airsupply;
|
|
else
|
|
return max(CPlayer.air_finished - level.time, 0);
|
|
}
|
|
|
|
int GetSelectedInventoryAmount()
|
|
{
|
|
if(CPlayer.mo.InvSel != NULL) return CPlayer.mo.InvSel.Amount;
|
|
return 0;
|
|
}
|
|
|
|
int GetKeyCount()
|
|
{
|
|
int num = 0;
|
|
for(Inventory item = CPlayer.mo.Inv;item != NULL;item = item.Inv)
|
|
{
|
|
if(item is "Key") num++;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// various checker functions, based on SBARINFOs condition nodes.
|
|
//
|
|
//============================================================================
|
|
|
|
//============================================================================
|
|
//
|
|
// checks ammo use of current weapon
|
|
//
|
|
//============================================================================
|
|
|
|
bool WeaponUsesAmmo(int ValidModes)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
let w = CPlayer.ReadyWeapon;
|
|
if (w == null) return false;
|
|
bool usesammo1 = w.AmmoType1 != NULL;
|
|
bool usesammo2 = w.AmmoType2 != NULL;
|
|
|
|
if (ValidModes == AMMO_PRIMARY) return usesammo1;
|
|
if (ValidModes == AMMO_SECONDARY) return usesammo2;
|
|
if (ValidModes == AMMO_ANY) return (usesammo1 || usesammo2);
|
|
if (ValidModes == AMMO_BOTH) return (usesammo1 && usesammo2);
|
|
return false;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if inventory bar is visible
|
|
//
|
|
//============================================================================
|
|
|
|
bool isInventoryBarVisible()
|
|
{
|
|
if (CPlayer == null) return false;
|
|
return (CPlayer.inventorytics <= 0 || level.NoInventoryBar);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if aspect ratio is in a given range
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckAspectRatio(double min, double max)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
double aspect = screen.GetAspectRatio();
|
|
return (aspect >= min && aspect < max);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if weapon is selected.
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckWeaponSelected(class<Weapon> weap, bool checksister = true)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
let w = CPlayer.ReadyWeapon;
|
|
if (w == null) return false;
|
|
if (w.GetClass() == weap) return true;
|
|
if (checksister && w.SisterWeapon != null && w.SisterWeapon.GetClass() == weap) return true;
|
|
return false;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player has the given display name
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckDiplayName(String displayname)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
return displayname == PlayerPawn.GetPrintableDisplayName(CPlayer.mo.GetClass());
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player has the given weapon piece
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckWeaponPiece(class<Weapon> weap, int piecenum)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
for(let inv = CPlayer.mo.Inv; inv != NULL; inv = inv.Inv)
|
|
{
|
|
let wh = WeaponHolder(inv);
|
|
if (wh != null && wh.PieceWeapon == weap)
|
|
{
|
|
return (!!(wh.PieceMask & (1 << (PieceNum-1))));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player has the given weapon piece
|
|
//
|
|
//============================================================================
|
|
|
|
bool WeaponUsesAmmoType(class<Ammo> ammotype)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
let w = CPlayer.ReadyWeapon;
|
|
if (w == NULL) return false;
|
|
return w.AmmoType1 == ammotype || w.AmmoType2 == ammotype;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player has the required health
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckHealth(int Amount, bool percentage = false)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
|
|
int phealth = percentage ? CPlayer.mo.health * 100 / CPlayer.mo.GetMaxHealth() : CPlayer.mo.health;
|
|
return (phealth >= Amount);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player is invulnerable
|
|
//
|
|
//============================================================================
|
|
|
|
bool isInvulnerable()
|
|
{
|
|
if (CPlayer == null) return false;
|
|
return ((CPlayer.mo.bInvulnerable) || (CPlayer.cheats & (CF_GODMODE | CF_GODMODE2)));
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// checks if player owns enough of the item
|
|
//
|
|
//============================================================================
|
|
|
|
bool CheckInventory(class<Inventory> item, int amount = 1)
|
|
{
|
|
if (CPlayer == null) return false;
|
|
|
|
let it = CPlayer.mo.FindInventory(item);
|
|
return it != null && it.Amount >= amount;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// DrawPowerups
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
virtual void DrawPowerups ()
|
|
{
|
|
// The AltHUD specific adjustments have been removed here, because the AltHUD uses its own variant of this function
|
|
// that can obey AltHUD rules - which this cannot.
|
|
Vector2 pos = (-20, POWERUPICONSIZE * 5 / 4);
|
|
double maxpos = screen.GetWidth() / 2;
|
|
for (let item = CPlayer.mo.Inv; item != NULL; item = item.Inv)
|
|
{
|
|
let icon = item.GetPowerupIcon();
|
|
if (icon.IsValid())
|
|
{
|
|
// Each icon gets a 32x32 block.
|
|
DrawTexture(icon, pos, DI_SCREEN_RIGHT_TOP, 1.0, (POWERUPICONSIZE, POWERUPICONSIZE));
|
|
pos.x -= POWERUPICONSIZE;
|
|
if (pos.x < -maxpos)
|
|
{
|
|
pos.x = -20;
|
|
pos.y += POWERUPICONSIZE * 3 / 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// draw stuff
|
|
//
|
|
//============================================================================
|
|
|
|
int GetTranslation() const
|
|
{
|
|
if(gameinfo.gametype & GAME_Raven)
|
|
return Translation.MakeID(TRANSLATION_PlayersExtra, CPlayer.mo.PlayerNumber());
|
|
else
|
|
return Translation.MakeID(TRANSLATION_Players, CPlayer.mo.PlayerNumber());
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
//
|
|
//
|
|
//============================================================================
|
|
|
|
void DrawHexenArmor(int armortype, String image, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.))
|
|
{
|
|
let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor"));
|
|
if (harmor != NULL)
|
|
{
|
|
let slotval = harmor.Slots[armorType];
|
|
let slotincr = harmor.SlotsIncrement[armorType];
|
|
|
|
if (slotval > 0 && slotincr > 0)
|
|
{
|
|
//combine the alpha values
|
|
alpha *= MIN(1., slotval / slotincr);
|
|
}
|
|
else return;
|
|
}
|
|
DrawImage(image, pos, flags, alpha, boxsize, scale);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
//
|
|
//
|
|
//============================================================================
|
|
|
|
void DrawInventoryIcon(Inventory item, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.))
|
|
{
|
|
TextureID texture;
|
|
Vector2 applyscale;
|
|
[texture, applyscale] = GetIcon(item, flags, false);
|
|
if (texture.IsValid())
|
|
{
|
|
if ((flags & DI_DIMDEPLETED) && item.Amount <= 0) flags |= DI_DIM;
|
|
applyscale.X *= scale.X;
|
|
applyscale.Y *= scale.Y;
|
|
DrawTexture(texture, pos, flags, alpha, boxsize, applyscale);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// DrawInventoryBar
|
|
//
|
|
// This function needs too many parameters, so most have been offloaded to
|
|
// a struct to keep code readable and allow initialization somewhere outside
|
|
// the actual drawing code.
|
|
//
|
|
//============================================================================
|
|
|
|
// Except for the placement information this gets all info from the struct that gets passed in.
|
|
void DrawInventoryBar(InventoryBarState parms, Vector2 position, int numfields, int flags = 0, double bgalpha = 1.)
|
|
{
|
|
double width = parms.boxsize.X * numfields;
|
|
|
|
// This must be done here, before altered coordinates get sent to the draw functions.
|
|
if (!(flags & DI_SCREEN_MANUAL_ALIGN))
|
|
{
|
|
if (position.x < 0) flags |= DI_SCREEN_RIGHT;
|
|
else flags |= DI_SCREEN_LEFT;
|
|
if (position.y < 0) flags |= DI_SCREEN_BOTTOM;
|
|
else flags |= DI_SCREEN_TOP;
|
|
}
|
|
|
|
// placement by offset is not supported because the inventory bar is a composite.
|
|
switch (flags & DI_ITEM_HMASK)
|
|
{
|
|
case DI_ITEM_HCENTER: position.x -= width / 2; break;
|
|
case DI_ITEM_RIGHT: position.x -= width; break;
|
|
}
|
|
|
|
switch (flags & DI_ITEM_VMASK)
|
|
{
|
|
case DI_ITEM_VCENTER: position.y -= parms.boxsize.Y / 2; break;
|
|
case DI_ITEM_BOTTOM: position.y -= parms.boxsize.Y; break;
|
|
}
|
|
|
|
// clear all alignment flags so that the following code only passed on the rest
|
|
flags &= ~(DI_ITEM_VMASK|DI_ITEM_HMASK);
|
|
|
|
CPlayer.mo.InvFirst = ValidateInvFirst(numfields);
|
|
if (CPlayer.mo.InvFirst == null) return; // Player has no listed inventory items.
|
|
|
|
Vector2 boxsize = parms.boxsize;
|
|
// First draw all the boxes
|
|
for(int i = 0; i < numfields; i++)
|
|
{
|
|
DrawTexture(parms.box, position + (boxsize.X * i, 0), flags | DI_ITEM_LEFT_TOP, bgalpha);
|
|
}
|
|
|
|
// now the items and the rest
|
|
|
|
Vector2 itempos = position + (boxsize.X / 2, boxsize.Y - parms.boxframesize);
|
|
Vector2 textpos = position + boxsize - (parms.boxframesize*2, parms.boxframesize + parms.amountfont.mFont.GetHeight());
|
|
|
|
int i = 0;
|
|
Inventory item;
|
|
for(item = CPlayer.mo.InvFirst; item != NULL && i < numfields; item = item.NextInv())
|
|
{
|
|
if ((parms.flags & DI_DRAWCURSORFIRST) && item == CPlayer.mo.InvSel) DrawTexture(parms.selector, position + (boxsize.X * i, 0), flags | DI_ITEM_LEFT_TOP);
|
|
DrawInventoryIcon(item, itempos + (boxsize.X * i, 0), flags | DI_ITEM_CENTER_BOTTOM );
|
|
if (!(parms.flags & DI_DRAWCURSORFIRST) && item == CPlayer.mo.InvSel) DrawTexture(parms.selector, position + (boxsize.X * i, 0), flags | DI_ITEM_LEFT_TOP);
|
|
|
|
if (parms.amountfont != null && (item.Amount > 1 || (parms.flags & DI_ALWAYSSHOWCOUNTERS)))
|
|
{
|
|
DrawString(parms.amountfont, FormatNumber(item.Amount, 0, 5), textpos + (boxsize.X * i, 0), flags | DI_TEXT_ALIGN_RIGHT, parms.cr, parms.itemalpha);
|
|
}
|
|
i++;
|
|
}
|
|
// Is there something to the left?
|
|
if (CPlayer.mo.FirstInv() != CPlayer.mo.InvFirst)
|
|
{
|
|
DrawTexture(parms.left, position + (-parms.arrowoffset.X, parms.arrowoffset.Y), flags | DI_ITEM_RIGHT|DI_ITEM_VCENTER);
|
|
}
|
|
// Is there something to the right?
|
|
if (item != NULL)
|
|
{
|
|
DrawTexture(parms.right, position + parms.arrowoffset + (width, 0), flags | DI_ITEM_LEFT|DI_ITEM_VCENTER);
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// a generic value interpolator for status bar elements that can change
|
|
// gradually to their new value.
|
|
//
|
|
//============================================================================
|
|
|
|
class LinearValueInterpolator : Object
|
|
{
|
|
int mCurrentValue;
|
|
int mMaxChange;
|
|
|
|
static LinearValueInterpolator Create(int startval, int maxchange)
|
|
{
|
|
let v = new("LinearValueInterpolator");
|
|
v.mCurrentValue = startval;
|
|
v.mMaxChange = maxchange;
|
|
return v;
|
|
}
|
|
|
|
// This must be called peroiodically in the status bar's Tick function.
|
|
// Do not call this in the Draw function because that may skip some frames!
|
|
void Update(int destvalue)
|
|
{
|
|
if (mCurrentValue > destvalue)
|
|
{
|
|
mCurrentValue = max(destvalue, mCurrentValue - mMaxChange);
|
|
}
|
|
else
|
|
{
|
|
mCurrentValue = min(destvalue, mCurrentValue + mMaxChange);
|
|
}
|
|
}
|
|
|
|
// This must be called in the draw function to retrieve the value for output.
|
|
int GetValue()
|
|
{
|
|
return mCurrentValue;
|
|
}
|
|
}
|
|
|
|
class DynamicValueInterpolator : Object
|
|
{
|
|
int mCurrentValue;
|
|
int mMinChange;
|
|
double mChangeFactor;
|
|
|
|
|
|
static DynamicValueInterpolator Create(int startval, double changefactor, int minchange)
|
|
{
|
|
let v = new("DynamicValueInterpolator");
|
|
v.mCurrentValue = startval;
|
|
v.mMinChange = minchange;
|
|
v.mChangeFactor = changefactor;
|
|
return v;
|
|
}
|
|
|
|
// This must be called peroiodically in the status bar's Tick function.
|
|
// Do not call this in the Draw function because that may skip some frames!
|
|
void Update(int destvalue)
|
|
{
|
|
int diff = int(max(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange));
|
|
if (mCurrentValue > destvalue)
|
|
{
|
|
mCurrentValue = max(destvalue, mCurrentValue - diff);
|
|
}
|
|
else
|
|
{
|
|
mCurrentValue = min(destvalue, mCurrentValue + diff);
|
|
}
|
|
}
|
|
|
|
// This must be called in the draw function to retrieve the value for output.
|
|
int GetValue()
|
|
{
|
|
return mCurrentValue;
|
|
}
|
|
}
|
|
|