• Check out the results of the Techtree Contest #19!
  • Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

Unit Info Panels

This bundle is marked as pending. It has not been reviewed by a staff member yet.

Introduction

Unit Info Panels is an UI-Frame Resource, extending the default warcraft 3 UI. It upgrades the single Unit selection Frame into a Book with Pages. This only includes the normal view when the unit is not training, nor transporting.

Has a Lua and (v)jass version.
Requires Warcraft 3 V1.31 or higher.

Features

One can add additional custom Pages, showing other infos about the current Unit.
The pages also can contain interactive UI.
Each player can only see one page at the same time, that page doesn't have to be the same for them.
The current seen Page can be changed using up and down Buttons.
Includes a Framework to setup a Tooltiptext.
Probably one also don't want any unit be able to have access to all Pages. Therefore they can have a conditionfunction which prevents switching to it under such unwanted circumstances.
Supports using non-SimpleFrames you have to use SetUnitInfoPanelFrame, these non simpleframes don't become children of the UnitInfoPanels.

How to install


First you have to export and import the 2 Files in the demo map (using the export all Files function can bug in older Editor Versions).

war3mapImported\UnitInfoPanels.fdf
war3mapImported\UnitInfoPanels.toc
Now you copy UnitInfoPanels (trigger editor) into your map
Done.

Lua

(v)jass


Lua API
Code:
AddUnitInfoPanel(frame, update[, condition])
    frame is the containerPanel, update a function(unit) that runs every updateTick, condition is a function(unit) that returns true or false it is used to prevent rotating to this panel.
AddUnitInfoPanelEx(update, condition)
    wrapper for AddUnitInfoPanel, it creates and returns a new frame

SetUnitInfoPanelFrame(frame)
    makes a non SimpleFrame share visibility with the last Added InfoPanel, supports only one Frame per InfoPanel
SetUnitInfoPanelFrameEx()
    wrapper SetUnitInfoPanelFrame creates and returns a new empty Frame

UnitInfoPanelAddTooltipListener(frame, code)
    detects if this frame is visible if it is call the given function which should return a text which is the now wanted tooltipText.

UnitInfoCreateCustomInfo(parent, label, texture, tooltipCode)
    return createContext, infoFrame, iconFrame, labelFrame, textFrame
UnitInfoGetUnit([player])
    returns & recacls the current selected Unit
    without a player it will use the local player.
 
function UnitInfoPanelSetPage(newPage, updateWanted)
    ignores conditions, newPage can be "+" or "-" or a frame

local AutoRun = true -- (false) call InitUnitInfoPanels()
Bounty Panel example in Lua. It creates 2 custom Unit Infos that display the gold and Lumber bounty on kill. This Panel can only be changed to when the owner of the current selected Unit gives bounty.
Lua:
-- Shows how much gold and Lumber bounty one gets when slaying an unit
do
    local realFunction = InitUnitInfoPanels
    local lumberText, goldText, parent
    local createContext, infoFrame, iconFrame, labelFrame, textFrame
    local function Init()
        -- create a new Unit Info Panel, this panel can only be shown when the current selected unit's owner gives bounty
        parent = AddUnitInfoPanelEx(function(unit)
            local min, max
            min = BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_NUMBER_OF_DICE) + BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_BASE)
            max = BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_NUMBER_OF_DICE) *BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_SIDES_PER_DIE) + BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_BASE)
            BlzFrameSetText(goldText, min.." - "..max)
            min = BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_NUMBER_OF_DICE) + BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_BASE)
            max = BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_NUMBER_OF_DICE) *BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_SIDES_PER_DIE) + BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_BASE)
            BlzFrameSetText(lumberText, min.." - "..max)
        end,
        function(unit) return IsPlayerFlagSetBJ(PLAYER_STATE_GIVES_BOUNTY, GetOwningPlayer(unit)) end)
        -- define locals
        
        -- create a new custom Info and load all created frames into the locals
        createContext, infoFrame, iconFrame, labelFrame, textFrame = UnitInfoCreateCustomInfo(parent, " Gold:", "UI\\Widgets\\ToolTips\\Human\\ToolTipGoldIcon", function(unit)
        -- this function returns the text shown inside the tooltip when this UnitInfo is mouse hovered.
            local min, max
            min = BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_NUMBER_OF_DICE) + BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_BASE)
            max = BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_NUMBER_OF_DICE) *BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_SIDES_PER_DIE) + BlzGetUnitIntegerField(unit, UNIT_IF_GOLD_BOUNTY_AWARDED_BASE)
            return "Bounty Gold: "..min.." - "..max
            .."\nWhen an unit owned by you kills this unit, you gain this amount of Gold.\nOnly unallied unit give bounty."
        end)
        local prevIcon = iconFrame
        goldText = textFrame
        BlzFrameSetPoint(iconFrame, FRAMEPOINT_TOPLEFT, BlzGetFrameByName("SimpleHeroLevelBar", 0), FRAMEPOINT_BOTTOMLEFT, 0, -0.001)

        -- 2. Custom Info
        createContext, infoFrame, iconFrame, labelFrame, textFrame = UnitInfoCreateCustomInfo(parent, " Lumber:", "UI\\Widgets\\ToolTips\\Human\\ToolTipLumberIcon", function(unit)
            local min, max
            min = BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_NUMBER_OF_DICE) + BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_BASE)
            max = BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_NUMBER_OF_DICE) *BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_SIDES_PER_DIE) + BlzGetUnitIntegerField(unit, UNIT_IF_LUMBER_BOUNTY_AWARDED_BASE)
            return "Bounty Lumber: "..min.." - "..max
            .."\nWhen an unit owned by you kills this unit, you gain this amount of Lumber.\nOnly unallied unit give bounty."
        end)
        lumberText = textFrame
        BlzFrameSetPoint(iconFrame, FRAMEPOINT_TOPLEFT, prevIcon, FRAMEPOINT_TOPLEFT, 0.095, 0)
        prevIcon = nil
    end
    function InitUnitInfoPanels()
        realFunction()
        Init()
        if FrameLoaderAdd then FrameLoaderAdd(Init) end
    end
end

The (v)jass API.
Code:
UnitInfoGetUnit(player p) -> unit
    returns & recacls the current selected Unit, unneeded in given actionfunctions
AddUnitInfoPanel(framehandle frame, code update, code condition)
    frame is the containerPanel, update a function() that runs every updateTick, condition is a function() that returns true or false it is used to prevent rotating to this panel.
    it is suggested to use UnitInfoUnit inside this functions
AddUnitInfoPanelEx(code update, code condition) -> framehandle
    wrapper for AddUnitInfoPanel, it creates and returns a new frame
SetUnitInfoPanelFrame(framehandle frame)
    makes a non SimpleFrame share visibility with the last Added InfoPanel, supports only one Frame per InfoPanel
SetUnitInfoPanelFrameEx() -> framehandle
    wrapper SetUnitInfoPanelFrame creates and returns a new empty Frame
UnitInfoPanelAddTooltipListener(framehandle frame, code func)
    detects if this frame is visible if it is call the given function which is expected to set string UnitInfoTooltipText to the now wanted tooltipText.
UnitInfoCreateCustomInfo(framehandle parent, string label, string texture, code tooltipCode) -> integer
    returns createContext
    you can get the frames over globals UnitInfoInfoFrame, UnitInfoIconFrame, UnitInfoLabelFrame, UnitInfoTextFrame
UnitInfoPanelSetPage(integer newPage)
    ignores conditions, using 0 will change to next page and -1 previous page
UnitInfoPanelSetPageByFrame(framehandle newPage, boolean updateWanted)
    searches the index of newPage and calls UnitInfoPanelSetPage when found
A vjass Demo contained by the Demo Map. It shows 8 abilities the current selected Unit got. (Lua also got that, but what use would it have to show the same example twice, on this page).

The demo Panels share a set of functions which you could copy paste, but change the content of this functions to fit you wanted Pages.
This would be private function condition, private function update, private function At0s, private function init_function.
init_function is the default vjass helper init, it starts a timer so At0s runs as soon the game started.
At0s creates the page and setups it.
condition is a simple function that tells, if one can change to this page. Beaware that this runs async.
update is called every update Tick by the main System, you use this if the displayed infos change based on the current situation.
tooltipAction is called when in the main system's update Tick the tooltip detector is hovered. Beaware that this runs async and every update Tick as long as hovered.
JASS:
library SkillPanel initializer init_function requires UnitInfoPanels
// Creates an UnitInfopanel showing the last 8 abilities the unit got, ignoring abilities having no tooltip.
// Ignores abilities without a Tooltip: When BlzGetAbilityStringLevelField returns "Tool tip missing!" or "" or " "
    globals
        private framehandle array Icon
        private framehandle array Text
        private framehandle array Button
        private framehandle array ToolTip
        private integer buttonCount = 8
        private integer array SkillIndex
        private framehandle parent
        private trigger buttonTrigger = CreateTrigger()  
    endglobals

    private function buttonAction takes nothing returns nothing
        // request currently used unit of the clicking player
        local integer i = buttonCount
        local framehandle frame = BlzGetTriggerFrame()
        call UnitInfoGetUnit(GetTriggerPlayer())
        // get the clicked buttonIndex

        // find the used Button
    call BJDebugMsg("Skill Panel")
        loop
            exitwhen i == 0
            if frame == Button[i] then
                call BJDebugMsg(GetPlayerName(GetTriggerPlayer()) + " Clicked: " + I2S(i) + " "+ GetUnitName(UnitInfoUnit))
                exitwhen true
            endif
            set i = i - 1
        endloop
        set frame = null
    endfunction

    private function tooltipAction takes nothing returns nothing
    // the tooltip function is async do not create or destroy here
        local integer i = buttonCount
        local ability abi
        // find the active tooltip
        loop
            exitwhen i == 0
            if UnitInfoTooltipFrame == ToolTip[i] then
                set abi = BlzGetUnitAbilityByIndex(UnitInfoUnit, SkillIndex[i])
                if BlzGetAbilityBooleanField(abi, ABILITY_BF_HERO_ABILITY) then
                    set UnitInfoTooltipText = BlzGetAbilityStringLevelField(abi, ABILITY_SLF_TOOLTIP_LEARN, 0) + "\n" + BlzGetAbilityStringLevelField(abi, ABILITY_SLF_TOOLTIP_LEARN_EXTENDED, 0)
                else
                    set UnitInfoTooltipText = BlzGetAbilityStringLevelField(abi, ABILITY_SLF_TOOLTIP_NORMAL, 0) + "\n" + BlzGetAbilityStringLevelField(abi, ABILITY_SLF_TOOLTIP_NORMAL_EXTENDED, 0)
                endif
                exitwhen true
            endif
            set i = i - 1
        endloop
        set abi = null
    endfunction

    private function condition takes nothing returns boolean
        return IsUnitOwnedByPlayer(UnitInfoUnit, Player(PLAYER_NEUTRAL_AGGRESSIVE))
    endfunction

    private function abiFilter takes ability abi, string text returns boolean
        if BlzGetAbilityBooleanField(abi, ABILITY_BF_ITEM_ABILITY) then
            return false
        endif
        if text == "Tool tip missing!" or text == "" or text == " " then
            return false
        endif
        return true
    endfunction
 
    private function update takes nothing returns nothing
        local ability abi
        local integer buttonIndex = 1
        local integer abiIndex = 0
        local string text
        loop
            exitwhen buttonIndex > buttonCount
            set abi = BlzGetUnitAbilityByIndex(UnitInfoUnit, abiIndex)
            if abi != null then
                set text = BlzGetAbilityStringLevelField(abi, ABILITY_SLF_TOOLTIP_NORMAL, 0)
                if abiFilter(abi, text) then
                    set SkillIndex[buttonIndex] = abiIndex
                    call BlzFrameSetVisible(Button[buttonIndex], true)
                    call BlzFrameSetTexture(Icon[buttonIndex], BlzGetAbilityStringLevelField(abi, ABILITY_SLF_ICON_NORMAL, 0), 0, false)
                    call BlzFrameSetText(Text[buttonIndex], text)
                    set buttonIndex = buttonIndex + 1
                endif
                set abiIndex = abiIndex + 1
            else
                call BlzFrameSetVisible(Button[buttonIndex], false)
                set buttonIndex = buttonIndex + 1
            endif
        endloop
    endfunction
    private function At0s takes nothing returns nothing
        local integer i = buttonCount
        set parent = BlzCreateSimpleFrame("CustomUnitInfoPanel2x4", BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0), 0)
        call AddUnitInfoPanel(parent, function update, function condition)  
   
        loop
            exitwhen i == 0
            set Button[i] = BlzGetFrameByName("CustomUnitInfoButton" + I2S(i), 0)
            set ToolTip[i] = BlzCreateFrameByType("SIMPLEFRAME", "", Button[i], "", 0)
            set Icon[i] = BlzGetFrameByName("CustomUnitInfoButtonIcon" + I2S(i), 0)
            set Text[i] = BlzGetFrameByName("CustomUnitInfoButtonText" + I2S(i), 0)
            call BlzTriggerRegisterFrameEvent(buttonTrigger, Button[i], FRAMEEVENT_CONTROL_CLICK)
            call BlzFrameSetTooltip(Button[i], ToolTip[i])
            call BlzFrameSetVisible(ToolTip[i], false)

            call UnitInfoPanelAddTooltipListener(ToolTip[i], function tooltipAction)
            set i = i - 1
        endloop
 
    endfunction
    private function init_function takes nothing returns nothing
        call TimerStart(CreateTimer(), 0, false, function At0s)
        call TriggerAddAction(buttonTrigger, function buttonAction)
        call FrameLoaderAdd(function At0s)
    endfunction
endlibrary


ChangeLog

4e) (Lua only)
can manual Init the system
BuffBar fix (reforged)​
4d) (Lua only) Improved demo 4x3 UnitInfoPanel
V4b&c) (Lua only) Save&Load Fix
V4a)
Added a safty check for Panel finding​

V4)
added wantedPage Feature
Changes current viewn Page if the condition fails
Hides the current non-SimpelFrame when another selection Type is changed to (Group, trainer etc)
(Lua) Fixed the down Button
(vjass) runs only the active update instead of all of them
SkillPanel, seperated the ability filter into an own function, on-default now blocks any ability with the item skill Flag
UnitInfoPanelSetPage has now a second argument to support the new wantedIndex feature.
UnitInfoPanelSetPage can evoke nextPanel PrevPanel with 0/-1 or in Lua "+" "-"
UnitInfoPanelSetPage increased lower limit to 1.
(Lua) UnitInfoPanelSetPage now can be called with a frame instead of a number
(vjass) added UnitInfoPanelSetPageByFrame finds the used index and swaps the page
The whole UnitInfo can now be a next Panel Button
Remove various initial values in the globals block​
V3)
Hides the Page Buttons when no other page can be selected.
Changed default Condtions for Skillpanel & CustomStat.​
V2)
fixed Load&Save Bug
Checks and Forces Panel Condition inside the update tick​
Previews
Contents

Unit Info Panels V4bc VJass (Map)

Unit Info Panels V4fa (Map)

Back
Top