ZScript Status Bar Issues

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

ZScript Status Bar Issues

Post by NeoTerraNova »

EDIT: I said "Menu" and not "Status Bar" - this is what you get for posting when you're up for 18 hours. Sorry, everyone!

Again, as always, I'd like to start off by thanking everyone that stops by to help with this problem.

Now, the problem.

In my last request for help, I was looking to make certain things happen with my Status Bar - a non-uniform list of weapons, as images, showing up in the Status Bar based on what the Player is carrying. I was advised to move to a ZScript Status Bar, and I am. Now, some issues have arisen, and I've only just begun.

-Is it possible to use a larger-than-standard graphic for a status bar? And have it scale properly to the user's screen resolution, so it doesn't look tiny on much larger resolutions? The original Doom one is fairly small - I'd like to use one about 80px tall by 800px wide, so I can show more detail. I've looked through the commented version of the doom_sbar file posted elsewhere, and I can't figure out how to make this enlarged status bar appear properly at the bottom of the screen.

-Is it possible to use two different types of images to represent a currently selected inventory item AND weapon? I ask this, so I can have a larger and more detailed graphic for the currently selected gear, and smaller icons for gear not selected, but held in reserve by the player.

-Is it possible to forcibly scale up the status bar number font, in the code, to match the now-larger status bar, or do I have to manually edit the image files and increase the size of the graphics themselves?

I'll probably have more questions, but these are my biggest roadblocks right now. Thank you again for all those that stop by to help.
User avatar
Player701
 
 
Posts: 1552
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: ZScript Status Bar Issues

Post by Player701 »

NeoTerraNova wrote:Is it possible to use a larger-than-standard graphic for a status bar? And have it scale properly to the user's screen resolution, so it doesn't look tiny on much larger resolutions? The original Doom one is fairly small - I'd like to use one about 80px tall by 800px wide, so I can show more detail. I've looked through the commented version of the doom_sbar file posted elsewhere, and I can't figure out how to make this enlarged status bar appear properly at the bottom of the screen.
Yes. In the original Doom status bar code you'll find the following line in the Init method:

Code: Select all

SetSize(32, 320, 200);
What it does is best explained by this picture (click to enlarge):



Essentially, this creates a virtual canvas of size 320x200 with the height of the actual status bar set to 32. This means that a status bar graphic of size 320x32 will fit in there perfectly. If you want more space for your graphic, increase the first argument (height) and the second argument (width). Note that the third argument plays a certain role in the scaling algorithm - I think (but I'm not entirely sure) that for proper fullscreen scaling you should set it to a value of height / 1.6 so that the 16:10 aspect ratio is preserved. But that part of code is something I haven't played with a lot - in fact, I have never deviated from the standard values at all; if there are other people here who've built elaborate custom HUDs and have more experience with these adjustments, they may be able to provide more information.

NeoTerraNova wrote:-Is it possible to use two different types of images to represent a currently selected inventory item AND weapon? I ask this, so I can have a larger and more detailed graphic for the currently selected gear, and smaller icons for gear not selected, but held in reserve by the player.
I'm sorry, but I didn't quite understand that question. If you want a single icon to represent both a weapon and an item, then the total number of icons will be WxI where W is the number of weapons and I is the number of items. Not very practical, so I suggest you have W icons for your weapons and I icons for your items and draw them somewhere close to each other to represent the currently selected weapon and inventory. Please clarify if you wanted something else, sorry I couldn't get you at first.

NeoTerraNova wrote:-Is it possible to forcibly scale up the status bar number font, in the code, to match the now-larger status bar, or do I have to manually edit the image files and increase the size of the graphics themselves?
Yes. The DrawString method has a scale argument, the last one in the argument list. Since it is a vector2, you can specify x- and y-scale separately, although you don't have to do that if you don't want to (e.g. (2, 2) will scale uniformly by a factor of 2).
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: ZScript Status Bar Issues

Post by NeoTerraNova »

NeoTerraNova wrote:
-Is it possible to use two different types of images to represent a currently selected inventory item AND weapon? I ask this, so I can have a larger and more detailed graphic for the currently selected gear, and smaller icons for gear not selected, but held in reserve by the player.


I'm sorry, but I didn't quite understand that question. If you want a single icon to represent both a weapon and an item, then the total number of icons will be WxI where W is the number of weapons and I is the number of items. Not very practical, so I suggest you have W icons for your weapons and I icons for your items and draw them somewhere close to each other to represent the currently selected weapon and inventory. Please clarify if you wanted something else, sorry I couldn't get you at first.
Sorry for my poor wording - as noted in the edit, I'd been awake far too long, and my writing suffered as a result.

What I'm looking to do is to have two images, each, for Weapons and Items. As in, each Weapon will have a larger graphic for when it's the currently selected weapon, and a smaller graphic to show that it's held in reserve. Thus, if I have a Pistol, Shotgun, and Chaingun, I would have small graphics for each of those three weapons on one part of the Status Bar to show that the Player is carrying them, and a larger graphic on another part of the Status Bar to indicate that this is the currently selected weapon. Since my list of weapons is very large and not "fixed" (the Player is encouraged to discard and pick up weapons regularly), just having a set list of Small Weapon Icons that display at specific coordinates on the Status Bar - like how vanilla Doom does it with the number indicator next to the mugshot - would not work. The same goes for the Inventory Items. So, ideally, I would have: Small Weapon Icon, Large Weapon Icon, Small Item Icon, Large Item Icon.

Thank you for the help so far, though! I'll see what I can do with this knowledge.

Well, I started in on things, and I managed to get my new Status Bar centered at the bottom of the screen. How do I get it to scale up properly with the User's own screen resolution? I tried playing with the internal settings, but it doesn't seem to do anything.
User avatar
Player701
 
 
Posts: 1552
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: ZScript Status Bar Issues

Post by Player701 »

I see. The exact code to implement this will depend on:
  1. where exactly in your status bar you want to show your lists
  2. how you want your lists to be laid out (e.g. just one column or row or a fixed number of them)
  3. what should happen when there's not enough space to draw the rest of the list (e.g. allow overlapping anyway, discard the rest, or cycle through the contents periodically)
To get the current weapon the player is carrying, use CPlayer.ReadyWeapon in your HUD code (note that it may be null if the player does not have a weapon equipped).

To get the current inventory item the player has selected, use CPlayer.InvSel. The following code will cycle through all selectable items:

Code: Select all

for (let ii = CPlayer.mo.FirstInv(); ii != null; ii = ii.NextInv())
{
    // ii is one of the selectable items the player is carrying
}
Now, regarding icons. One way of assigning icons is to set the value of the Icon property for your weapons and items. This way, you can have at least one type of icon available immediately for use (either "small" or "large" but it doesn't matter which ones you choose). To get the icon in your HUD code, you can call GetInventoryIcon, which not only checks for the actual icon but can also provide alternatives in case you've forgotten to set the icon or simply don't have one and want to use the sprite from your item's Spawn state as an icon.

The second type of icon can be implemented with a static method that would check for the name of the item's class and return the corresponding icon:

Code: Select all

private static TextureID GetSpecialIconName(class<Inventory> item)
{
    string iconName;
    
    switch(item.GetClassName())
    {
        case 'Pistol':
            iconName = "MYICON1";
            break;
        case 'Shotgun':
            iconName = "MYICON2";
            break;
        // TODO: Rest of weapons/items here
        default:
            iconName = "";
            break;
    }
   
    return TexMan.CheckForTexture(iconName);
}
Call this whenever you want to draw an icon for a weapon/item, optionally call IsValid() on the returned value to see if the icon actually exists. Use DrawTexture to do the actual drawing.
NeoTerraNova wrote:Well, I started in on things, and I managed to get my new Status Bar centered at the bottom of the screen. How do I get it to scale up properly with the User's own screen resolution? I tried playing with the internal settings, but it doesn't seem to do anything.
The status bar scale depends on the user's HUD scale settings. Forcing it to always scale to the fullscreen resolution is a bad idea. You should implement a fullscreen HUD for that, not a status bar. If your status bar does not scale correctly based on these settings ("HUD Options" -> "Scaling options" -> "Status bar"), then there may be a bug in your implementation, but I won't be able to tell you what's wrong unless I can see your entire code.
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: ZScript Status Bar Issues

Post by NeoTerraNova »

You should implement a fullscreen HUD for that, not a status bar.
Okay, okay, I'm following you. I get the reason why that might be the best approach. What would the difference be between these, from a technical/coding standpoint?
User avatar
Player701
 
 
Posts: 1552
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: ZScript Status Bar Issues

Post by Player701 »

You will find the following code in the ZScript file for the Doom status bar:

Code: Select all

override void Draw (int state, double TicFrac)
{
    Super.Draw (state, TicFrac);

    if (state == HUD_StatusBar)
    {
        BeginStatusBar();
        DrawMainBar (TicFrac);
    }
    else if (state == HUD_Fullscreen)
    {
        BeginHUD();
        DrawFullScreenStuff ();
    }
}
The Draw method is called each time the engine wants to draw the HUD. As you can see here, it checks for the current state of the HUD (status bar vs fullscreen HUD) and then calls either BeginStatusBar() or BeginHUD depending on the result. These methods are used to set up the 2D drawer for the corresponding HUD mode (status bar or fullscreen). You can use similar code for your own HUD, except if you don't want a status bar at all, omit the first if block entirely. This, however, may result in some people not wanting to play your mod because they prefer to play with a status bar instead of a fullscreen HUD. Replace DrawFullScreenStuff() with the code to draw your fullscreen HUD.
NeoTerraNova wrote:How do I get it to scale up properly with the User's own screen resolution?
To do that, you should first know the virtual size of the HUD canvas that is available to you in fullscreen mode:

Code: Select all

Width = SW / HX
Height = SH / HY
where SW, SH are, respectively, the width and heigth of the screen, and HX, HY are the HUD scale factors set up in the HUD options menu. To get the screen width and height, use Screen.GetWidth() and Screen.GetHeight() respectively. In your HUD code, you can call GetHUDScale() to get a vector2 that contains the HUD scale factors.

Code: Select all

let hudScale = GetHUDScale();
double w = Screen.GetWidth() / hudScale.X;
double h = Screen.GetHeight() / hudScale.Y;

// TODO: Do something with w and h...
Now that you have the width and height of the (virtual) screen, you can determine the coordinates for DrawImage or DrawTexture to do the actual drawing. One thing that's left is to scale the image to the screen resolution, for that there's an argument called box that can be used to specify the size of a rectangle the image will be constrained into. Note that by default it won't scale the image out of proportions and/or beyond the original size. Specify the DI_FORCEFILL flag to override this behavior.

Here's a concrete example that draws the STBAR image at the bottom of the screen and makes it fill 10% of the screen's bottom area while ignoring scale. Some further explanation is given below.

Code: Select all

class TestHUD : BaseStatusBar
{
    override void Draw(int state, double TicFrac)
    {
        if (state == HUD_FullScreen)
        {
            BeginHUD();
            
            let hudScale = GetHUDScale();
            double w = Screen.GetWidth() / hudScale.X;
            double h = Screen.GetHeight() / hudScale.Y;
            
            DrawImage("STBAR", (0, 0), DI_SCREEN_LEFT_BOTTOM|DI_ITEM_LEFT_BOTTOM|DI_FORCEFILL, box: (w, h/10));
        }
    }
}
Notes:
  • DI_SCREEN_LEFT_BOTTOM puts the point (0, 0) to the bottom left corner of the screen, positive X and Y values shifting it to the right and up respectively.
  • DI_ITEM_LEFT_BOTTOM puts the bottom left corner of the image at the specified coordinates (in our case (0, 0)).
  • DI_FORCEFILL overrides the scaling algorithm.
  • box: (w, h/10) sets the size of the area where the image will be drawn, and since DI_FORCEFILL is set, it will fill the entire box with the image, ignoring the scale.
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: ZScript Status Bar Issues

Post by NeoTerraNova »

Thank you for all of this. I really appreciate it. Let me see what I can do with this information, and I'll get back to you if I have problems. I actually need to finish the graphics, first - I've been using a rough placeholder to get an idea of what this is going to look like when it's done.

Return to “Scripting”