Damage reduction 0% tooltip

Do you think Ai had some clue?

JASS:
library ArmorTooltipUI initializer InitArmorTooltip
    globals
        private unit array at_LastSel
 
        private framehandle at_TooltipBox   = null
        private framehandle at_TooltipText  = null
        private framehandle at_ArmorIcon    = null
        private framehandle at_OverlayBtn   = null // intercepts mouse so default tooltip won't show
 
        private trigger at_SelectTrg = null
        private trigger at_HoverTrg  = null
 
        private string array at_TypeName
    endglobals
 
    // ---------- helpers ----------
    private function RoundInt takes real r returns integer
        if r >= 0.0 then
            return R2I(r + 0.5)
        endif
        return R2I(r - 0.5)
    endfunction
 
    private function ArmorReductionPercent takes real armor returns real
        local real a
        local real p
        set a = armor
        if a >= 0.0 then
            set p = (0.06 * a) / (1.0 + 0.06 * a)
        else
            set a = -a
            set p = - (0.06 * a) / (1.0 + 0.06 * a)
        endif
        return p * 100.0
    endfunction
 
    private function ArmorTypeToName takes defensetype dt returns string
        if dt == DEFENSE_TYPE_NONE   then
            return at_TypeName[0]
        elseif dt == DEFENSE_TYPE_LIGHT  then
            return at_TypeName[1]
        elseif dt == DEFENSE_TYPE_MEDIUM then
            return at_TypeName[2]
        elseif dt == DEFENSE_TYPE_LARGE  then
            return at_TypeName[3]
        elseif dt == DEFENSE_TYPE_FORT   then
            return at_TypeName[4]
        elseif dt == DEFENSE_TYPE_HERO   then
            return at_TypeName[5]
        elseif dt == DEFENSE_TYPE_DIVINE then
            return at_TypeName[6]
        endif
        return "Armor"
    endfunction
 
    private function BuildTooltipText takes unit u returns string
        local real armor
        local integer armorI
        local integer defTypeI
        local string typeName
        local real red
        local string s
 
        set armor  = BlzGetUnitArmor(u)
        set armorI = RoundInt(armor)
        set defTypeI = BlzGetUnitIntegerField(u, UNIT_IF_DEFENSE_TYPE)
        set typeName = ArmorTypeToName(ConvertDefenseType(defTypeI))
        set red = ArmorReductionPercent(armor)
 
        set s = ""
        set s = s + "|cffffcc00Armor:|r " + I2S(armorI) + " (" + R2S(armor) + ")\n"
        set s = s + "|cffffcc00Type:|r " + typeName + "\n"
        set s = s + "|cffffcc00Damage Reduction:|r " + I2S(RoundInt(red)) + "%"
 
        return s
    endfunction
 
    // ---------- selection tracking ----------
    private function OnSelected takes nothing returns nothing
        local integer pid
        local unit u
        set pid = GetPlayerId(GetTriggerPlayer())
        set u   = GetTriggerUnit()
        set at_LastSel[pid] = u
    endfunction
 
    // ---------- UI ----------
    private function FindArmorIcon takes nothing returns framehandle
        local framehandle f
        // Try common names across patches/skins
        set f = BlzGetFrameByName("SimpleInfoPanelIconArmorType", 0)
        if f != null then
            return f
        endif
        set f = BlzGetFrameByName("InfoPanelIconArmor", 0)
        if f != null then
            return f
        endif
        set f = BlzGetFrameByName("SimpleInfoPanelIconArmor", 0)
        return f
    endfunction
 
    private function CreateTooltipFrames takes nothing returns nothing
        local framehandle parent
 
        set parent = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
 
        // Use stock tooltip container so z-order & skin look correct
        set at_TooltipBox = BlzCreateFrame("Tooltip", parent, 0, 0)
        call BlzFrameSetSize(at_TooltipBox, 0.24, 0.12)
        call BlzFrameSetVisible(at_TooltipBox, false)
 
        set at_TooltipText = BlzCreateFrameByType("TEXT", "ArmorTipText", at_TooltipBox, "", 0)
        call BlzFrameSetPoint(at_TooltipText, FRAMEPOINT_TOPLEFT,     at_TooltipBox, FRAMEPOINT_TOPLEFT,     0.010, -0.010)
        call BlzFrameSetPoint(at_TooltipText, FRAMEPOINT_BOTTOMRIGHT, at_TooltipBox, FRAMEPOINT_BOTTOMRIGHT, -0.010,  0.010)
        call BlzFrameSetEnable(at_TooltipText, false)
        call BlzFrameSetTextAlignment(at_TooltipText, TEXT_JUSTIFY_LEFT, TEXT_JUSTIFY_TOP)
        call BlzFrameSetText(at_TooltipText, "Armor…")
    endfunction
 
    private function RefreshTooltipText takes nothing returns nothing
        local player lp
        local integer pid
        local unit u
        local string txt
 
        set lp  = GetLocalPlayer()
        set pid = GetPlayerId(lp)
        set u   = at_LastSel[pid]
 
        if u != null then
            set txt = BuildTooltipText(u)
        else
            set txt = "|cffffcc00Armor666:|r —\n|cffffcc00Type:|r —\n|cffffcc00Damage Reduction:|r —"
        endif
 
        if GetLocalPlayer() == lp then
            call BlzFrameSetText(at_TooltipText, txt)
        endif
    endfunction
 
    private function MakeOverlay takes nothing returns nothing
        local framehandle parent
        local trigger enter
        local trigger leave
 
        if at_ArmorIcon == null then
            return
        endif
 
        set parent = BlzFrameGetParent(at_ArmorIcon)
 
        // Transparent button overlay on top of the armor icon
        set at_OverlayBtn = BlzCreateFrameByType("BUTTON", "ArmorOverlay", parent, "", 0)
        call BlzFrameSetLevel(at_OverlayBtn, 10) // above icon
        call BlzFrameClearAllPoints(at_OverlayBtn)
        // Anchor overlay exactly to the icon (two corners is enough)
        call BlzFrameSetPoint(at_OverlayBtn, FRAMEPOINT_TOPLEFT,     at_ArmorIcon, FRAMEPOINT_TOPLEFT,     0.0, 0.0)
        call BlzFrameSetPoint(at_OverlayBtn, FRAMEPOINT_BOTTOMRIGHT, at_ArmorIcon, FRAMEPOINT_BOTTOMRIGHT, 0.0, 0.0)
        call BlzFrameSetVisible(at_OverlayBtn, true)
 
        // Position our tooltip relative to the overlay
        call BlzFrameClearAllPoints(at_TooltipBox)
        call BlzFrameSetPoint(at_TooltipBox, FRAMEPOINT_BOTTOMLEFT, at_OverlayBtn, FRAMEPOINT_TOPRIGHT, 0.006, 0.006)
        call BlzFrameSetTooltip(at_OverlayBtn, at_TooltipBox)
 
        // Refresh text when hovered
        set enter = CreateTrigger()
        call BlzTriggerRegisterFrameEvent(enter, at_OverlayBtn, FRAMEEVENT_MOUSE_ENTER)
        call TriggerAddAction(enter, function RefreshTooltipText)
 
        set leave = CreateTrigger()
        call BlzTriggerRegisterFrameEvent(leave, at_OverlayBtn, FRAMEEVENT_MOUSE_LEAVE)
        call TriggerAddAction(leave, function RefreshTooltipText) // optional
    endfunction
 
 
 
    // Retry until the info panel exists, then build overlay
    private function TryInitUI takes nothing returns nothing
        local timer t
 
        if at_TooltipBox == null then
            call CreateTooltipFrames()
        endif
 
        if at_ArmorIcon == null then
            set at_ArmorIcon = FindArmorIcon()
        endif
 
        if at_ArmorIcon != null and at_OverlayBtn == null then
            call MakeOverlay()
        endif
 
        if at_OverlayBtn == null then
            set t = CreateTimer()
            call TimerStart(t, 0.10, false, function TryInitUI)
        endif
    endfunction
 
    // ---------- core init ----------
    private function InitCore takes nothing returns nothing
        local integer i
        set i = 0
 
        set at_TypeName[0] = "None"
        set at_TypeName[1] = "Light"
        set at_TypeName[2] = "Medium"
        set at_TypeName[3] = "Large"     // your build
        set at_TypeName[4] = "Fortified"
        set at_TypeName[5] = "Hero"
        set at_TypeName[6] = "Divine"
 
        set at_SelectTrg = CreateTrigger()
        loop
            exitwhen i >= bj_MAX_PLAYERS
            call TriggerRegisterPlayerUnitEvent(at_SelectTrg, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
            set i = i + 1
        endloop
        call TriggerAddAction(at_SelectTrg, function OnSelected)
    endfunction
 
    // ---------- self-init ----------
    private function InitArmorTooltip takes nothing returns nothing
        call InitCore()
        // tiny delay so Simple Info Panel frames exist
        call TimerStart(CreateTimer(), 0.03, false, function TryInitUI)
    endfunction
 
    endlibrary
 
Please don't spam, I just saw your post from 6 minutes ago.

Anyway, did that code work? It's an easy thing to test yourself.

It looks fairly correct, although I imagine the AI will have a hard time finding the correct names for the different frames. It also assumes a lot, and this game often requires workarounds and hacks to get things working the way you'd expect them to.

For example, in this function it's testing out three different frame names because it's unsure, or I suppose it could be for backwards compatibility:
vJASS:
    // ---------- UI ----------
    private function FindArmorIcon takes nothing returns framehandle
        local framehandle f
        // Try common names across patches/skins
        set f = BlzGetFrameByName("SimpleInfoPanelIconArmorType", 0)
        if f != null then
            return f
        endif
        set f = BlzGetFrameByName("InfoPanelIconArmor", 0)
        if f != null then
            return f
        endif
        set f = BlzGetFrameByName("SimpleInfoPanelIconArmor", 0)
        return f
    endfunction
Best to just figure out what the frame is actually called and use that. @Tasyen
 
Last edited:
Sorry, I really have no idea how to help. The only thing I can add the conversation (and I'm not sure if it even addresses the question) is that <Xxxx,Xxxx> stuff in tooltips for custom abilities doesn't always work and you may need to just harcode it and put in the actual values instead.

I really have no idea about how to achieve such things with custom frames or whatever.
 
I've tried it. No... It's just like its not there. Normal tooltip is shown
Okay, this is the best I can come up with, I've never modified these particular frames before:
vJASS:
    function EnterFrame takes nothing returns nothing
        call BJDebugMsg("Enter")
    endfunction

    function LeaveFrame takes nothing returns nothing
        call BJDebugMsg("Leave")
    endfunction

    function Test takes nothing returns nothing
        local framehandle btn
        local framehandle icon
        local framehandle newParent = BlzCreateFrameByType("SIMPLEFRAME", "", BlzGetFrameByName("ConsoleUI", 0), "", 0)
        local trigger e = CreateTrigger()
        local trigger l = CreateTrigger()

        // Similar UI elements
        //call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconDamage",0), newParent)
        //call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconDamage",1), newParent)
        //call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconRank",3), newParent)
        //call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconFood",4), newParent)
        //call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconGold",5), newParent)

        // Create a new armor button + icon
        set btn = BlzCreateSimpleFrame("UpperButtonBarButtonTemplate", BlzGetFrameByName("ConsoleUI", 0), 0)
        set icon  = BlzCreateFrameByType("SIMPLESTATUSBAR", "name", btn, "", 0)
        call BlzFrameSetValue(icon, 100)
        call BlzFrameSetAllPoints(icon, btn)
        call BlzFrameSetSize(btn, 0.03, 0.03)
        call BlzFrameSetSize(icon, 0.03, 0.03)
        call BlzFrameSetTexture(icon, BlzGetAbilityIcon('Hpal'), 0, true)
        call BlzFrameSetPoint(btn, FRAMEPOINT_LEFT, BlzGetFrameByName("SimpleInfoPanelIconArmor",2), FRAMEPOINT_LEFT, 0.0025, 0.0)
        call BlzFrameSetEnable(icon, false)

        // Register mouse events
        call BlzTriggerRegisterFrameEvent(e, btn, FRAMEEVENT_MOUSE_ENTER)
        call TriggerAddAction(e, function EnterFrame)
        call BlzTriggerRegisterFrameEvent(l, btn, FRAMEEVENT_MOUSE_LEAVE)
        call TriggerAddAction(l, function LeaveFrame)

        // Hide armor icon
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconArmor",2), newParent)
        call BlzFrameSetEnable(BlzGetFrameByName("SimpleInfoPanelIconArmor",2), false)
        call BlzFrameSetVisible(newParent, false)
    endfunction
But there's a few issues. The main issue is that the UI layers prevent your mouse from being detected over the button, so EnterFrame and LeaveFrame never run. I've tried many different Parents for the button but nothing seems to work. Maybe you can get the AI to fix this. After that you'll need to come up with a good way of showing the button while a unit is selected and hiding it while none are selected. This will be tricky to get right and have it working for each Player.

There's always other resources you can use:
 
Last edited:
1757970771264.png


I've copypasted folder from here

but instead of unit stats i see a blank black area...
No icons no text.

Can you help me?..
 
Back
Top