ZScrpt Hud Question

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
Xtyfe
Posts: 1470
Joined: Fri Dec 14, 2007 6:29 pm
Operating System: Windows 10/8.1/8/201x 64-bit
Graphics Processor: nVidia with Vulkan support

ZScrpt Hud Question

Post by Xtyfe »

I made an attempt to learn a bit about zscript hud creation. I created a lean and minimalist hud based on code from gzdoom.pk3. Everything is mostly where it want it, but the one thing I can't quite figure out is key display.

I have been able to move where the keys will display, but how they display is another matter. I want them to populate under and from the middle of another string called "Keys". So far, I have only been able to make them populate this area from either the left or right of where I'd like for them to go. What can I do to achieve what I need?

[imgur]https://imgur.com/LvJxqXc[/imgur] What it looks like with just one key.
[imgur]https://imgur.com/GugsJfB[/imgur] What it looks like with all keys

The code

Code: Select all

   protected void DrawFullScreenStuff ()
   {
      DrawTexture(GetMugShot(5, MugShot.ANIMATEDGODMODE|Mugshot.XDEATHFACE), (110, -17), DI_ITEM_CENTER);
      
      DrawString(mConsoleFont, "Health", (64, -30), DI_TEXT_ALIGN_CENTER);
      DrawString(mHUDFont, FormatNumber(CPlayer.health, 1, 4), (64, -20), DI_TEXT_ALIGN_CENTER);
      
      DrawString(mConsoleFont, "Keys", (-64, -60), DI_TEXT_ALIGN_CENTER);
      DrawFullscreenKeys();
      
      DrawString(mConsoleFont, "Armor", (64, -60), DI_TEXT_ALIGN_CENTER);
      let armor = CPlayer.mo.FindInventory("BasicArmor");
      if (armor != null && armor.Amount > 0)
      {
         DrawString(mHUDFont, FormatNumber(armor.Amount, 1, 4), (64, -50), DI_TEXT_ALIGN_CENTER);
      }
      else
      {
         DrawString(mHUDFont, FormatNumber(0, 1), (64, -50), DI_TEXT_ALIGN_CENTER);
      }
      
      DrawString(mConsoleFont, "Ammo", (-64, -30), DI_TEXT_ALIGN_CENTER);
      Inventory ammotype1;
      ammotype1 = GetCurrentAmmo();
      if (ammotype1 != null)
      {
         DrawString(mHUDFont, FormatNumber(ammotype1.Amount, 1, 4), (-64, -20), DI_TEXT_ALIGN_CENTER);
      }
      else
      {
         DrawString(mHUDFont, FormatNumber(0, 1), (-64, -20), DI_TEXT_ALIGN_CENTER);
      }
      
      if (!isInventoryBarVisible() && !Level.NoInventoryBar && CPlayer.mo.InvSel != null)
      {
         DrawInventoryIcon(CPlayer.mo.InvSel, (-110, -14), DI_DIMDEPLETED|DI_ITEM_CENTER);
         if (CPlayer.mo.InvSel.Amount > 1)
         {
            DrawString(mAmountFont, FormatNumber(CPlayer.mo.InvSel.Amount), (-102, -2-mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_CENTER, Font.CR_GOLD);
         }
      }
      
      if (isInventoryBarVisible())
      {
         DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, HX_SHADOW);
      }
   }
   
   protected virtual void DrawFullscreenKeys()
   {
      // Draw the keys. This does not use a special draw function like SBARINFO because the specifics will be different for each mod
      // so it's easier to copy or reimplement the following piece of code instead of trying to write a complicated all-encompassing solution.
      Vector2 keypos = (-86, -39);
      int rowc = 0;
      double roww = 0;
      for(let i = CPlayer.mo.Inv; i != null; i = i.Inv)
      {
         if (i is "Key" && i.Icon.IsValid())
         {
            DrawTexture(i.Icon, keypos, DI_ITEM_CENTER);
            Vector2 size = TexMan.GetScaledSize(i.Icon);
            keypos.Y += size.Y + 2;
            roww = max(roww, size.X);
            if (++rowc == 1)
            {
               keypos.Y = -39;
               keypos.X += roww + 2;
               roww = 0;
               rowc = 0;
            }
         }
      }
   }
User avatar
Blue Shadow
Posts: 4901
Joined: Sun Nov 14, 2010 12:59 am
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: ATI/AMD (Modern GZDoom)

Re: ZScrpt Hud Question

Post by Blue Shadow »

The key thing here (pun unintended) is to use AdjustPosition():

Code: Select all

Vector2, int AdjustPosition(Vector2 position, int flags, double width, double height)

position is where you want the keys bar to be drawn (below the "Keys" label, centered, in your case).
flags is for alignment. If you want the bar to be drawn centered, you pass DI_ITEM_CENTER.
width is the width of the bar. This depends on how many keys the player currently possess, as well as their icon's width, and the gap between each icon.
height is the height of the bar. You probably want this to be the same as the icon with the biggest height.

The function returns the position and flags after adjustment, so you can start drawing the icons (from left to right).

Here's some code:
Spoiler:

Note that the above code doesn't handle multiple rows of keys; it draws all the keys in a single row.
User avatar
Xtyfe
Posts: 1470
Joined: Fri Dec 14, 2007 6:29 pm
Operating System: Windows 10/8.1/8/201x 64-bit
Graphics Processor: nVidia with Vulkan support

Re: ZScrpt Hud Question

Post by Xtyfe »

Thank you so much for your help. I had no idea there was a function that did all the calculations itself. This worked exactly the way I had hoped.
User avatar
Xtyfe
Posts: 1470
Joined: Fri Dec 14, 2007 6:29 pm
Operating System: Windows 10/8.1/8/201x 64-bit
Graphics Processor: nVidia with Vulkan support

Re: ZScrpt Hud Question

Post by Xtyfe »

Blue Shadow wrote:The key thing here (pun unintended) is to use AdjustPosition():

Code: Select all

Vector2, int AdjustPosition(Vector2 position, int flags, double width, double height

position is where you want the keys bar to be drawn (below the "Keys" label, centered, in your case).
flags is for alignment. If you want the bar to be drawn centered, you pass DI_ITEM_CENTER.
width is the width of the bar. This depends on how many keys the player currently possess, as well as their icon's width, and the gap between each icon.
height is the height of the bar. You probably want this to be the same as the icon with the biggest height.

The function returns the position and flags after adjustment, so you can start drawing the icons (from left to right).

Here's some code:
Spoiler:

Note that the above code doesn't handle multiple rows of keys; it draws all the keys in a single row.


So I took your suggestion and tried to apply it to powerup timers

I settled on overriding the DrawPowerup function to do this. I want the text for the timer to be centered on the powerup icon, regardless of how many digits are display (up to 3 since they are additive)

I don't think I've done this right, but I'm not quite certain what the issue might be.

Here the code

Code: Select all

override void DrawPowerups ()
   {
      Vector2 pos = (-20, POWERUPICONSIZE * 5 / 4); int flags;
      [pos, flags] = AdjustPosition((pos.x, pos.y - 34), DI_TEXT_ALIGN_CENTER, (8, 8));
      double maxpos = screen.GetWidth() / 2;
      for (let iitem = CPlayer.mo.Inv; iitem != NULL; iitem = iitem.Inv)
      {
         let item = Powerup(iitem);
         if (item != null)
         {
            let icon = item.GetPowerupIcon();
            if (icon.IsValid() && !item.IsBlinking())
            {
            
               // Get the amount of seconds left (tics / ticrate).
               int secondsLeft = int(Ceil(double(item.EffectTics) / GameTicRate));
               
               // Each icon gets a 32x32 block.
               DrawTexture(icon, pos, DI_SCREEN_RIGHT_TOP, 1.0, (POWERUPICONSIZE, POWERUPICONSIZE));
               DrawString(mSmallFont, FormatNumber(secondsLeft, 3), pos, flags, Font.CR_GREY);
               pos.x -= POWERUPICONSIZE;
               if (pos.x < -maxpos)
               {
                  pos.x = -20;
                  pos.y += POWERUPICONSIZE * 3 / 2;
               }
            }
         }
      }
   }
User avatar
Blue Shadow
Posts: 4901
Joined: Sun Nov 14, 2010 12:59 am
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: ATI/AMD (Modern GZDoom)

Re: ZScrpt Hud Question

Post by Blue Shadow »

A couple of errors I see in the code:
  • The width and height aren't supposed to be passed as a Vector2 to AdjustPosition. They're a separate argument each.
  • You want to pass DI_ITEM_CENTER, not DI_TEXT_ALIGN_CENTER. It's the bar you're trying to position, not the stuff in it.

Return to “Scripting”