You need a "zscriptified" status bars. ZScript is a thing but a very low-documented one, so you will need to experiment. Basically what you need is to override functions that draw things, then call the original ones to draw all, and after that add something on top of it (e.g. draw special mugshot if player have Invuln sphere).A_D_M_E_R_A_L wrote:2. I'd LOVE to do that (grin face while Invul is active) but I don't know HOW. If there is a way to do it, I want to know how to do it ASAP.
As an example I've found this post by AFADoomer a few years back:
Here's a (very ugly) status bar that is stripped down to bare minimals and heavily commented... Not sure if that will help or not.
I didn't include keys on here, since there's no key bar equivalent in ZScript - you have to manually check for the keys and draw them yourself (see ugliness here), but this at least mostly documents the core functions that Vaecrius mentioned in the previous post, plus some.
Code: Select all
version "2.5"
class NewStatusBar : BaseStatusBar
{
// Unlike SBARINFO, fonts can't be directly referenced by name.
// You'll need to declare them here, then initialize them in Init() below
HUDFont mHUDFont;
HUDFont mIndexFont;
HUDFont mAmountFont;
// This is necessary if you want to use the Inventory Bar
InventoryBarState diparms;
// You need a DynamicValueInterpolator for any value that you want to have interpolated
// This includes both bar values and any numbers that you want to "count to"
// instead of having the value immediately change over
DynamicValueInterpolator mHealthInterpolator;
// Declare any other variables you might end up needing here
// What happens when this bar is initialized?
override void Init()
{
// Run the parent status bar's Init() function
// It's generally a good idea to call the super class's function whenever you
// are overriding a function, in case some critical code is executed by the
// parent class - unless you know specifically that you want to completely
// replace the parent class's function instead
Super.Init();
SetSize(32, 320, 200); // This sets the pixel height of the status bar and the base resolution
// Initialize the fonts - there's actually a wiki page on this part:
// https://zdoom.org/wiki/Classes:HUDFont
Font fnt = "HUDFONT_DOOM";
mHUDFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true, 1, 1);
fnt = "INDEXFONT_DOOM";
mIndexFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true);
mAmountFont = HUDFont.Create("INDEXFONT");
// Initialize the inventory bar
diparms = InventoryBarState.Create();
// Initialize the interpolation variables
// Parameters:
// Starting Value
// Change Factor (I'm not 100% sure what this does)
// Minimum change step size (don't increment by less than this amount each Update() call)
// Maximum change step size (don't increment by more than this amount each Update() call)
//
// These are the values used by:
// Hexen's health bar: 0, 0.25, 1, 8
// Hexen's chain health bar: 0, 0.25, 1, 6
mHealthInterpolator = DynamicValueInterpolator.Create(0, 0.25, 1, 8);
}
// What happens when a new game begins
override void NewGame ()
{
// Run the parent status bar's NewGame() function
Super.NewGame();
// Reset any interpolators that you declared
// void Reset(int value)
// Parameter: Desired value that you want to set the value to immediately
mHealthInterpolator.Reset(0); // Reset sets the current value directly, so this sets the value to 0
}
// What needs to run every tick
override void Tick()
{
// Run the parent status bar's Tick() function
Super.Tick();
// Update the value of the interpolators
// void Update(int destvalue)
// Parameter: Desired end-state value of the interpolator
// This is what sets the interpolator's value. It uses the min/max step size variables that we created
// interpolator with in Init(), so must be called repeatedly to set the correct value (so, if we start
// at 0, and Update to 100, and max step size is 8, each Update call will increment the value up by 8
// until the value reaches 100... 8, 16, 24, 32, ... 96, 100)
mHealthInterpolator.Update(CPlayer.health); // Set the interpolator's value to this player's health
}
// Draw the status bar
// The default status bars use some logic here to call different functions based on whether the bar is normal
// or full-screen. Since you don't actually want to use anything but a fullscreen HUD, you can get rid of the
// checks here and jsut do the drawing here instead of calling another function
override void Draw (int state, double TicFrac)
{
// Run the parent status bar's Draw() function
Super.Draw (state, TicFrac);
BeginHUD(); // You'd use BeginStatusBar(); if you wanted a traditional bar instead of fullscreen
// Draw the hud elements
// The x, y coordinates are all in Vector2 format, which for editing purposes means that they are enclosed
// in their own set of parenthesis... Screen coordinates of x=5, y=10 is written as "(5, 10)"
//
// Positioning flags are mostly self-explanatory; a list can be seen here: https://github.com/coelckers/gzdoom/blob/master/wadsrc/static/zscript/statusbar/statusbar.txt#L159
// Flags that start with DI_SCREEN set the relative position of the coordinates you pass - so (0, -15) and
// DI_SCREEN_CENTER_BOTTOM will position your element at screen center, 15 pixels from the bottom
//
// Flags that start with DI_ITEM set the positioning point of the element, essentially by overriding the
// sprite/graphic's image offsets. DI_ITEM_LEFT_TOP will position the item with it's top left corner at
// the coordinates you provide, and DI_ITEM_OFFSETS will use the item's offset values
// Only draw if there's no automap active
if (!automapactive)
{
// Draw an image
// native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1));
// Parameters:
// Texture name as a string
// The desired coordinates of the image
// Positioning flags (DI_*)
// Alpha of the image (0.0 - 1.0)
// Vector2 box = (-1, -1) (Don't know what this does...)
// Scale as a Vector2 (so, half sized would be: (0.5, 0.5) )
//
// NOTES:
// There is also a DrawTexture function that uses the exact same parameters, except it takes an texture ID
// instead of the string name of the texture - it's used when drawing the MugShot below
//
// There is also a DrawInventoryIcon function with the same parameters except that it takes an inventory item
// instead of the texture name - used for ammo and inventory icon drawing below
DrawImage("STBAR", (0, 168), DI_ITEM_OFFSETS, 1.0, (-1, -1), (1, 1));
// Draw a text string
// 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);
// Parameters:
// Font variable name, as declared in Init()
// The string you want to print. To print a variable that is a number value (like DrawNumber in SBARINFO), use FormatNumber(yourvariable)
// Position where you want the string printed
// Positioning flags
// The font color translation that you want to use
// Alpha of the string
// Width that the string can be before it begins to wrap
// Spacing between the lines in the string when it wraps or has a newline character in it
DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (90, 171), DI_TEXT_ALIGN_RIGHT|DI_NOSHADOW);
DrawString(mHUDFont, "This is a normal string...", (221, 171), DI_TEXT_ALIGN_RIGHT|DI_NOSHADOW);
// Draw a bar
// void DrawBar(String ongfx, String offgfx, double curval, double maxval, Vector2 position, int border, int vertical, int flags = 0)
// Parameters:
// The top layer graphic of the bar that is incrementally drawn based on the variable value
// The bottom/background graphic of the bar
// The current value of the bar - usually your interpolated variable
// The maximum value of the bar
// Bar position
// "Border" - I think only really used by Hexen?
// Bar direction flags - SHADER_HORZ, SHADER_VERT, or SHADER_REVERSE - https://github.com/coelckers/gzdoom/blob/master/wadsrc/static/zscript/statusbar/statusbar.txt#L261
// Positioning Flags
//
// Note the use of GetValue() on the health interpolator here.
DrawBar("SOULA0", "PINVA0", mHealthInterpolator.GetValue(), CPlayer.mo.GetMaxHealth(true), (36, 160), 0, SHADER_HORZ, DI_ITEM_OFFSETS);
// Draw current ammo amounts
Ammo ammo1, ammo2;
int ammocount1, ammocount2;
[ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo();
if (ammo1) { DrawString(mAmountFont, FormatNumber(ammocount1, 3), (225, 171), DI_TEXT_ALIGN_RIGHT); }
if (ammo2) { DrawString(mAmountFont, FormatNumber(ammocount2, 3), (225, 185), DI_TEXT_ALIGN_RIGHT); }
//Ammo Icons
DrawInventoryIcon(ammo1, (231, 170), DI_ITEM_OFFSETS);
DrawInventoryIcon(ammo2, (231, 184), DI_ITEM_OFFSETS);
// Draw armor amount
let armor = CPlayer.mo.FindInventory("BasicArmor");
if (armor != null && armor.Amount > 0)
{
DrawInventoryIcon(armor, (4, 184), DI_ITEM_OFFSETS);
DrawString(mHUDFont, FormatNumber(GetArmorAmount(), 3), (52, 185), DI_TEXT_ALIGN_RIGHT);
DrawString(mHUDFont, "%", (65, 185), DI_TEXT_ALIGN_RIGHT);
}
// Draw the mugshot
// Uses DrawTexture to draw the mugshot image, as retrieved by GetMugShot
// native TextureID GetMugshot(int accuracy, int stateflags=MugShot.STANDARD, String default_face = "STF");
// (I haven't looked into these parameters at all - I assume the "STF" one changes the mugshot image base, though)
DrawTexture(GetMugShot(5), (143, 168), DI_ITEM_OFFSETS);
// Draw the currently selected inventory item
// void DrawInventoryIcon(Inventory item, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.))
// Parameters:
// Inventory item name - CPlayer.mo.InvSel is the current inventroy selected by the player
// All other parameters are the same as DrawImage
//
// A major difference from SBARINFO is that you have to manually draw the inventory amount
if (CPlayer.mo.InvSel != null) // If there's an inventory item selected...
{
double x = 160;
double y = 198;
DrawInventoryIcon(CPlayer.mo.InvSel, (x, y));
if (CPlayer.mo.InvSel.Amount > 1) // If you have more than one, draw the amount number as a string
{
DrawString(mAmountFont, FormatNumber(CPlayer.mo.InvSel.Amount), (x + 15, y-mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD);
}
}
// Draw the inventory bar
if (isInventoryBarVisible()) // If it should be visible...
{
// void DrawInventoryBar(InventoryBarState parms, Vector2 position, int numfields, int flags = 0, double bgalpha = 1.)
// Parameters:
// The InventoryBarState variable that you declared and initialized above
// The desired coordinates of the bar
// The number of inventory items to show in the bar at one time
// Positioning flags
// Alpha of the background for the inventory bar (0.0 to 1.0)
DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, 0.5);
}
// Other useful functions:
// bool CheckInventory(class<Inventory> item, int amount = 1)
// bool CheckHealth(int Amount, bool percentage = false)
// bool isInvulnerable()
// bool isInventoryBarVisible()
// bool CheckWeaponSelected(class<Weapon> weap, bool checksister = true)
// bool CheckDisplayName(String displayname)
// String FormatNumber(int number, int minsize = 0, int maxsize = 0, int format = 0, String prefix = "")
}
}
}
Hope this will help at least a little.