WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   3 Questions (https://www.wowinterface.com/forums/showthread.php?t=46850)

laukond 07-23-13 10:49 AM

3 Questions
 
http://i.imgur.com/zI9jLCR.jpg

1.
How do I change the value for health to be shortened?
For example, in the screenshot my health is 113k and my target is 2482.
How do I change it so it shortens from 999 and up?

2.
As seen on the screenshot the texture on the EXP bar is thicker on the bottom of it compared to the top.
Can I either make it as thin as on the top side or simply remove the border completely?

ravagernl 07-23-13 01:34 PM

Can you provide some info about what UI this is, and/or if you are writing some addon yourself, please provide code to look at :)

laukond 07-23-13 01:37 PM

Quote:

Originally Posted by ravagernl (Post 281408)
Can you provide some info about what UI this is, and/or if you are writing some addon yourself, please provide code to look at :)

It's blizzard UI with lots of zzzz:SetAlpha(0);

As for the health text I use this code currently:
Code:

        hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function()
        PlayerFrameHealthBar.TextString:SetText(AbbreviateLargeNumbers(UnitHealth("player")))
        PlayerFrameManaBar.TextString:SetText(AbbreviateLargeNumbers(UnitMana("player")))
                -- PlayerFrameAlternateManaBar.TextString:SetText(AbbreviateLargeNumbers(UnitPower("player")))
               
        TargetFrameHealthBar.TextString:SetText(AbbreviateLargeNumbers(UnitHealth("target")))
        TargetFrameManaBar.TextString:SetText(AbbreviateLargeNumbers(UnitMana("target")))

        FocusFrameHealthBar.TextString:SetText(AbbreviateLargeNumbers(UnitHealth("focus")))
        FocusFrameManaBar.TextString:SetText(AbbreviateLargeNumbers(UnitMana("focus")))
               
               
        end)


Rainrider 07-23-13 04:31 PM

1. You will have to write your own AbbreviateLargeNumbers function for it.
lua Code:
  1. local SiValue = function(val)
  2.     if (val >= 1e6) then
  3.         return ("%.1fm"):format(val / 1e6)
  4.     elseif (val >= 1e3) then
  5.         return ("%.1fk"):format(val / 1e3)
  6.     else
  7.         return val
  8.     end
  9. end
would be a simple example without using blizzard's separators.

2. I'm not sure what's the texture shown there, but it might be these:
MainMenuXPBarTextureLeftCap
MainMenuXPBarTextureRightCap
MainMenuXPBarTextureMid
(Those are global names)
If so, you could use MainMenuXPBarTextureLeftCap:SetTexture(nil) and so on or play with SetTexCoords to make the border suit your needs. You might have to hook MainMenuExpBar_SetWidth as well.

Apart from that, when you use hooksecurefunc, your hook will be called with the same arguments as the function you hook to. In the case of TextStatusBar_UpdateTextStringWithValues those are:
statusFrame - StatusBar - the status bar the text is being changed on (i.e. PlayerFrameHealthBar)
textString - FontString - the text being changed (i.e. PlayerFrameHealthBar.TextString)
value - number - the current value of the statusbar (probably the same as the return of UnitHealth("player") +/- some negligible lag, if the func is being called for the player)
valueMin - number - the min value of the statusbar (probably 0)
valueMax - number - the max value of the statusbar (probably the same as the return of UnitMaxHealth("player") +/- some negligible lag, if the func is being called for the player)

By using those you could spare yourself some global look-ups and only update when there is need to and not all player, target and focus every time TextStatusBar_UpdateTextStringWithValues has been called.

Edit: By the way, what is the third question? :)

Phanx 07-23-13 10:56 PM

Quote:

Originally Posted by Rainrider (Post 281415)
lua Code:
  1. local SiValue = function(val)
  2.     if (val >= 1e6) then
  3.         return ("%.1fm"):format(val / 1e6)
  4.     elseif (val >= 1e3) then
  5.         return ("%.1fk"):format(val / 1e3)
  6.     else
  7.         return val
  8.     end
  9. end
would be a simple example without using blizzard's separators.

Just FYI, ("%d"):format(5) is slower than format("%d", 5) even if you don't upvalue format. If you do upvalue the global format, then format("%d", 5) is faster by a huge margin.

The only time you should use slower method syntax is if you're chaining a lot of operations together and want to keep it more human-readable, eg. ("blah blah %d blah"):format(5):upper():sub(8):gsub("a", "x")

Even small differences in speed can really add up in code that's run often, like inside a function that's formatting text every time a unit's health changes.

Rainrider 07-24-13 05:18 PM

Oh, thank you, Phanx. Is there a good resource for all this stuff? I always suck at efficiency.

laukond 07-24-13 05:29 PM

How do I use the code you wrote?
I'm pretty new to Lua.

Phanx 07-24-13 07:45 PM

1. Go to http://addon.bool.no/

2. Copy this code and paste it in the box on that page:
Code:

hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function(statusBar, fontString, value, valueMin, valueMax)
        local str, val
        if value >= 1e10 then
                -- Shorten 10,000,000,000+ like 12b
                str, val = "%.0fb", value / 1e9
        elseif value >= 1e9 then
                -- Shorten 1,000,000,000+ like 8.3b
                str, val = "%.1fb", value / 1e9
        elseif value >= 1e7 then
                -- Shorten 10,000,000+ like 14m
                str, val = "%.1fm", value / 1e6
        elseif value >= 1e6 then
                -- Shorten 1,000,000+ like 7.4m
                str, val = "%.2fm", value / 1e6
        elseif value >= 1e5 then
                -- Shorten 100,000+ like 84k
                str, val = "%.0fk", value / 1e3
        elseif value >= 1e3 then
                -- Shorten 1,000+ like 2.5k
                str, val = "%.1fk", value / 1e3
        else
                -- Don't shorten under 1,000
                str, val = "%d", value
        end
        fontString:SetFormattedText(str, val)
end)

3. Download the resulting addon and install it like any other addon.

You can remove the comments in the above code if you want to keep it shorter. If you only want to see whole numbers (eg. 157k or 12m) and never decimals (eg. 12.8m or 13.4k) use this code instead:

Code:

hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function(statusBar, fontString, value, valueMin, valueMax)
        local str, val
        if value >= 1e9 then
                -- 1,000,000,000+ like 8b
                str, val = "%.0fb", value / 1e9
        elseif value >= 1e6 then
                -- 1,000,000+ like 14m
                str, val = "%.0fm", value / 1e6
        elseif value >= 1e3 then
                -- 1,000+ like 2k
                str, val = "%.0fk", value / 1e3
        else
                -- Don't shorten numbers under 1,000
                str, val = "%d", value
        end
        fontString:SetFormattedText(str, val)
end)

Also, in this case there's no need to call string.format directly anyway, since it's even more efficient to use the fontstring's SetFormattedText method and offload the string processing into C code.

Phanx 07-24-13 07:47 PM

Quote:

Originally Posted by Rainrider (Post 281519)
Oh, thank you, Phanx. Is there a good resource for all this stuff? I always suck at efficiency.

Not really. I've thought about putting one together, I'm not really sure how you'd organize a collection of random Lua tips, or whether anyone would really bother reading an unorganized list of tips. The best way to do it might be just compiling a list of links to forum threads with good explanations.

laukond 07-24-13 08:45 PM

Quote:

18x hbitUI\hbitUI.lua:585: attempt to compare number with nil
hbitUI\hbitUI.lua:585: in function <hbitUI\hbitUI.lua:583>
<in C code>
FrameXML\TextStatusBar.lua:37: in function "TextStatusBar_UpdateTextString"
FrameXML\ReputationFrame.lua:424: in function "ReputationWatchBar_Update"
<string>:"*:OnEvent":6: in function <string>:"*:OnEvent":1

Locals:
(*temporary) = <func> =[C]:-1
= <func> @FrameXML\TextStatusBar.lua:41
= <func> @..\hbitUI.lua:583
I get this error in what is line 3 of your code with absvalue.

Phanx 07-24-13 10:34 PM

Fixed; I'd copied the code from my unitframes addon, but forgot to change that variable name.

laukond 07-24-13 10:50 PM

It works, thanks you very much :-D
Sometimes I raid, and then percentage hp is very useful. So I thought of making a slashcommand: /pct to turn on percentage hp, since this can't be done in the interface options because this code disregards those settings. So current hp is default and when /pct is run it will run for the session only (until /reload etc.)
Is this possible to do?

Phanx 07-25-13 01:53 PM

1. Add this line to your addon's TOC file:

Code:

## SavedVariables: MyCustomTextFormat
2. Modify your addon's Lua code like so:

Code:

MyCustomTextFormat = "VALUE"

hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function(statusBar, fontString, value, valueMin, valueMax)
        local str, val
        if MyCustomTextFormat == "PERCENT" then
                -- Show the value as a percent
                str, val = "%.0f%%", value / valueMax * 100
        elseif value >= 1e10 then
                -- Shorten 10,000,000,000+ like 12b
                str, val = "%.0fb", value / 1e9
        elseif value >= 1e9 then
                -- Shorten 1,000,000,000+ like 8.3b
                str, val = "%.1fb", value / 1e9
        elseif value >= 1e7 then
                -- Shorten 10,000,000+ like 14m
                str, val = "%.1fm", value / 1e6
        elseif value >= 1e6 then
                -- Shorten 1,000,000+ like 7.4m
                str, val = "%.2fm", value / 1e6
        elseif value >= 1e5 then
                -- Shorten 100,000+ like 84k
                str, val = "%.0fk", value / 1e3
        elseif value >= 1e3 then
                -- Shorten 1,000+ like 2.5k
                str, val = "%.1fk", value / 1e3
        else
                -- Don't shorten under 1,000
                str, val = "%d", value
        end
        fontString:SetFormattedText(str, val)
end)

SLASH_CUSTOMSHORTTEXT1 = "/pct"
SlashCmdList.CUSTOMSHORTTEXT = function()
        MyCustomTextFormat = MyCustomTextFormat == "VALUE" and "PERCENT" or "VALUE"
        print("Short text now showing", strlower(MyCustomTextFormat))
end

If you don't want it to remember your preference between reloads or logouts, just skip Step 1.

laukond 07-25-13 02:08 PM

Thank you Phanx you're very helpful :)
Can you make it update the values when you run the command somehow? Else you need to /rl, lose health, or gain health for it to update with your new setting (at least for your own frame).

semlar 07-25-13 02:51 PM

I would just modify it to use the setting from the interface by checking if GetCVar("statusTextDisplay") is "PERCENT", "NUMERIC" or "BOTH".

Phanx 07-25-13 09:01 PM

Here's a version that will use your CVar setting instead, as suggested by Semlar. I also converted the growing if-else chain into an easier-to-maintain indexed table loop:

Code:

local shorts = {
        { 1e10, 1e9, "%.0fb" }, --  10b+ as  12b
        {  1e9, 1e9, "%.1fb" }, --  1b+ as 8.3b
        {  1e7, 1e6, "%.0fm" }, --  10m+ as  14m
        {  1e6, 1e6, "%.1fm" }, --  1m+ as 7.4m
        {  1e5, 1e3, "%.0fk" }, -- 100k+ as 840k
        {  1e3, 1e3, "%.1fk" }, --  1k+ as 2.5k
        {    0,  1,    "%d" }, -- < 1k  as  974
}
for i = 1, #shorts do
        shorts[i][4] = shorts[i][3] .. " (%.0f%%)"
end

hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function(statusBar, fontString, value, valueMin, valueMax)
        local style = GetCVar("statusTextDisplay")
        if style == "PERCENT" then
                return fontString:SetFormattedText("%.0f%%", value / valueMax * 100)
        end
        for i = 1, #shorts do
                local t = shorts[i]
                if value >= t[1] then
                        return style == "BOTH"
                                and fontString:SetFormattedText(t[4], value / t[2], value / valueMax * 100)
                                or  fontString:SetFormattedText(t[3], value / t[2])
                end
        end
end)


laukond 07-26-13 06:35 AM

I changed a little bit:

Code:

local shorts = {
        { 1e10, 1e9, "%.0fb" }, --  10b+ as  12b
        {  1e9, 1e9, "%.1fb" }, --  1b+ as 8.3b
        {  1e7, 1e6, "%.0fm" }, --  10m+ as  14m
        {  1e6, 1e6, "%.1fm" }, --  1m+ as 7.4m
        {  1e5, 1e3, "%.0fk" }, -- 100k+ as 840k
        {  1e3, 1e3, "%.1fk" }, --  1k+ as 2.5k
        {    0,  1,    "%d" }, -- < 1k  as  974
}
for i = 1, #shorts do
        shorts[i][4] = shorts[i][3] .. " (%.0f%%)"
end

local style = GetCVar("statusTextDisplay")

hooksecurefunc("TextStatusBar_UpdateTextStringWithValues", function(statusBar, fontString, value, valueMin, valueMax)
        if style == "PERCENT" then
                return fontString:SetFormattedText("%.0f%%", value / valueMax * 100)
        end
        for i = 1, #shorts do
                local t = shorts[i]
                if value >= t[1] then
                        return style == "BOTH"
                                and fontString:SetFormattedText(t[4], value / t[2], value / valueMax * 100)
                                or  fontString:SetFormattedText(t[3], value / t[2])
                end
        end
end)

SLASH_HP1 = "/hp"
SlashCmdList.HP = function()
        if style == "NUMERIC" then
                SetCVar("statusTextDisplay", "PERCENT")
                print("You are now displaying percentage health.")
        elseif style == "PERCENT" then
                SetCVar("statusTextDisplay", "NUMERIC")
                print("You are now displaying numeric health.")
        else
                print("You are displaying both current and percentage health.")
        end
end

I moved the local style = GetCVar("statusTextDisplay") out so I can use it in the main code and the slash command, and I tried to make a slash command that doesn't work as intended.

I can't get the SetCVar to work, it doesn't change the CVar.
It displays numeric health when it is set to BOTH I don't know if this is intentional, since I do not understand what this line:

Code:

if value >= t[1] then
Specifically the t[1] which really is shorts[1], I'm guessing it will show both if the target has more than 10 billion health because that is the first line of the shorts array?

I also tried changing:

Code:

{  1e9, 1e9, "%.1fb" }, --  1b+ as 8.3b
To:
Code:

{  1e9, 1e9, "% . 1fb" }, --  1b+ as 8 . 3b
To make it a little easier to read, but it doesn't work that way.

Also, in my country we use comma, I know of :gsub('%.', ',') but can it be used here?

Rainrider 07-26-13 08:15 AM

t[1] equals shorts[i][1] (i.e. 1e10, 1e9 and so on) where i is the running index in the for loop. The meaning is to compare your current health value with t[1] so you don't end with 0.9k instead of 900.

SetFormattedText works just like lua's own format which in turn is based of C's printf. http://www.cplusplus.com/reference/cstdio/printf/ is a good reference. In order to produce language dependant output, you'll have to use gsub I believe

Something like that should work:
Code:

fontString:SetText(format(t[3], value/t[2]):gsub("%.", " , "))
(this would also add spaces before and after the decimal seperator)

As for your slash command:
The upvalue style is initialized when the file is first processed by the game. It takes the value of statusTextDisplay at this time and does not change later. You either have to call GetCVar("statusTextDisplay") in your slash command function or reassign style after calling SetCVar("statusTextDisplay", "whatever")

laukond 07-26-13 01:44 PM

Okay it is more readable now and the CVar actually does change.
I still have the problem from earlier though: By changing the CVar this way the frames do not update in order to reflect the new change, so you have to re-target, lose/gain hp, etc.

If I do change it through the Interface menu it does update.


Edit: I am onto something!
Code:

/click InterfaceOptionsStatusTextPanelDisplayDropDownButton
/click DropDownList1Button2

In-game changes it to percentage now I'm trying to find out how to do it in Lua.

Edit2: It works!

Code:

SLASH_HP1 = "/hp"
SlashCmdList.HP = function()
        local style = GetCVar("statusTextDisplay")
        if style == "NUMERIC" then
                InterfaceOptionsStatusTextPanelDisplayDropDownButton:Click();
                DropDownList1Button2:Click();
                print("You are now displaying percentage health.")
        elseif style == "PERCENT" then
                InterfaceOptionsStatusTextPanelDisplayDropDownButton:Click();
                DropDownList1Button1:Click();
                print("You are now displaying numeric health.")
        else
                print("You are displaying both current and percentage health.")
        end
end


Rainrider 07-26-13 07:50 PM

The reason for this behavior is that Blizzard updates the status texts when CVAR_UPDATE fires. This event does not (always?) fire when using SetCVar, unless you provide a third argument, typically your addon name. You could skip the
Code:

InterfaceOptionsStatusTextPanelDisplayDropDownButton:Click();
DropDownList1Button2:Click();

part and just use SetCVar calls instead:
Code:

SetCVar("statusTextDisplay", "whatever_value_you_need", "HP")
This will trigger TextStatusBar_OnEvent which will call TextStatusBar_UpdateTextString, which will call TextStatusBar_UpdateTextStringWithValues, which will trigger your hook and alter the display.


All times are GMT -6. The time now is 10:02 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI