TasSkillPicker

Introduction


TasSkillSetPicker is a custom UI system for Warcraft 3 V1.31 or higher in Lua.
Players pick a set of Skills of a given pool in a custom UI.

Details


The choices in the pool are either numbers -> object Editor objects or Lua tables.
Choices can be searched & filtered by categories. Categories can be freely chosen. You can have up to 32 categories.
A Set of choices is 1 to 12.
One Player can not pick the same choice twice.
Choices can have enforced categories or reject some.
Other players can see your choices, you can tell the system to not show it (show only allies or nobody).
One can clear the current choice pool and fill it again.
All players use the same pool at a given time.
The system works also for itemCodes & unitCodes, if one does some small modifications.

There are 3 Buttons for the user. Random, Accept & Free.
With the Random button one choice is randomed, it can be repeated until the player likes it, the button also jumps to the next choice-Slot.
The Accept Button disables all 3 buttons for this player, fills not chosen slots with random ones and calls the function TasSkillSetPicker.PlayerDone here one can decide what to do with the chosen skillset, the function is found at top of the system code.
FreeButton does nothing on default, it can be hidden with a setup. In the setup you could choose what it does needs Lua scripting.

The demo map contains TasHeroLearnEx which allows to train the chosen abilities, it is not required but without you need to solve the skill learning.

The Setup from the Lua script. There are 2 setups one at the top of the System code, more about the general rules. And one in some other script to setup the choices & categories.
You should look at the functions this.AllowPlayer & this.PlayerDone and fit them to your maps need.
Lua:
--[[ TasSkillSetPicker V1.2 by Tasyen

TasSkillSetPicker.DefineCategory(icon, text) -> number categoryValue
    make a new category
    categories need to be made before the UI is created.

TasSkillSetPicker.Add(spellCode, category)
    add an new Spell as option with category.
    i Suggest to store categories in variables and add them
    TasSkillSetPicker.Add('AHhb', 1 + 2)
    spellCode can be a Table expects some Keys {Icon = img, Text = bigText, Name = smallText}
    you can add after the ui was created or before.
    this can be used to set the category of already added choices

TasSkillSetPicker.LockCategory(buttonIndex, category)
    the skill selected at buttonIndex needs to have this category, it can have other categories aswell.
    buttonIndex starts with 1

TasSkillSetPicker.BanCategory(buttonIndex, category)
    the skill selected at buttonIndex can not have this category.

TasSkillSetPicker.PlayerAccept(player)
    finish player, fills unset slots with randoms

TasSkillSetPicker.ForcePickNow()
    all players PLAYER_SLOT_STATE_PLAYING are forced to accept now, if they did not already.

TasSkillSetPicker.ResetPlayer([player])
    players choosen data is removed and can use ui again
    no player = all players

TasSkillSetPicker.ShowOtherPlayerBars([show, player])

TasSkillSetPicker.ClearData()
    remove all choseable options.

requires
GetPlayerColorTexture
TasButtonList V14 or higher
TasWindow
TasFrameList
TasFrameAction

optional
TasAbilityData (ToolTipGenInfo = true)
]]
do
    
    local this = {}
    this.Show = true -- Show on Creation
    this.TocPath = "war3mapImported\\TasSkillSetPicker.toc"
    this.BarSlotCount = 6 -- The amount of Skills a Player picks & Buttons in one Bar. Expects 1 to 12. 6 are one Row, 12 are 2 Rows. You could choose more but more rows was not coded and therefore will look bad. Dont change this value after creation
    this.ParentFunc = function() return BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
    this.PosX = 0.77 
    this.PosY = 0.55
    this.SizeX = 0.51 -- total Size with Bars & editor
    this.SizeY = 0.37
    this.Pos = FRAMEPOINT_TOPRIGHT
    this.ToolTipGenInfo   = true -- (true) Add generic spell Fields to the displayed tooltip text (only for number choices). requires GetGenericSpellData
    this.ShowBars         = true -- preview other player builts (false) makes the UI smaller
    this.ShowEnemy        = true -- can look into enemy builts false/true?
    this.Localize         = true -- try to throw texts in to GetLocalizedString
    
    -- These are images displayed over a category button that mets the conditions. Only one of them is displayed at once, or none of them.
    -- They are displayed with reduced Alpha
    this.FilterNotAllowed = "ui/widgets/battlenet/chaticons/bnet-squelch"  -- TasSkillSetPicker.BanCategory
    this.FilterNotUsed    = "textures/black32" -- user does not search by this category
    this.FilterEnforced   = "ui/widgets/glues/gluescreen-checkbox-check" -- TasSkillSetPicker.LockCategory


    -- accept/random/show Button

    -- a button that allows the user to show a hidden TasSkillSetPicker
    this.ShowButtonShow = true
    this.ShowButtonParentFunc = function() return BlzGetFrameByName("InsideMainPanel", 0) end
    this.ShowButtonText = "Skill Picker" --tries Localizing
    this.ShowButtonPosX = 0.1
    this.ShowButtonPosY = 0.55
    
    -- Inside a SkillBar what to display for no/0 skill?
    -- not used in table mode
    this.NoSkillIcon = "replaceabletextures/commandbuttons/btntemp"
    this.NoSkillTooltip = "No Skill"

    -- accept/random Button
    this.ControlButtonSizeX = 0.085 
    this.ControlButtonSizeY = 0.03
    this.RandomButtonText   = "RANDOM" --tries Localizing
    this.AcceptButtonText   = "ACCEPT" --tries Localizing
    this.RandomButtonTooltip   = "Randomize the current Slot" --tries Localizing
    this.AcceptButtonTooltip   = "Finish selection & Fills unused slots" --tries Localizing
    this.FreeButtonText    = "" --tries Localizing
    this.FreeButtonTooltip   = "" --tries Localizing
    this.FreeButtonShow   = false --show the free button which function you need to code  function this.ActionButtonFree(frame, player)

    this.EditorBarTitle   = "SkillSet Editor"
    this.EditorBarIcon    = "replaceabletextures/commandbuttons/btnengineeringupgrade"
    this.SearchBarTooltip = "Search in Ability Name & Text, Ignores Case"

    this.AllowPlayer = function(player)
        -- this should be edited for your maps need.
        -- used by ForcePickNow & to consider if this player is added to the other players view
        -- return false to reject a player
        if GetPlayerSlotState(player) ~= PLAYER_SLOT_STATE_PLAYING then return false end
        return true
    end
    this.DoLocalize = function(text) if this.Localize then return GetLocalizedString(text) else return text end end
    this.PlayerDone = function(player, spellArray)
        -- this function happens when a player finished the picking

        this.PlayerHasDone[player] = true -- remember this player finished
        this.EnableControl(player, false)

        -- what to do with the choice
        TasHeroLearnEx.HeroData[player] = spellArray
    end

    function this.ActionButtonFree(frame, player)
        -- What happens when the Free button is pressed
        print("Free Button")
    end
    
    -- how to display a choice in the list and its tooltip?
    function this.ActionSpellListDraw(frameObject, data)
        if not data then data = 0 end
        if type(data) == "number" then
            if data == 0 then
                BlzFrameSetTexture(frameObject.Icon, this.NoSkillIcon, 0, false)
                BlzFrameSetTexture(frameObject.IconPush, this.NoSkillIcon, 0, false)
                BlzFrameSetTexture(frameObject.IconOff, this.NoSkillIcon, 0, false)
                BlzFrameSetText(frameObject.Text, this.NoSkillTooltip)
                BlzFrameSetTexture(frameObject.ToolTipFrameIcon, this.NoSkillIcon, 0, false)
                BlzFrameSetText(frameObject.ToolTipFrameName, this.NoSkillTooltip)
                BlzFrameSetText(frameObject.ToolTipFrameText, "")
            else
                BlzFrameSetTexture(frameObject.Icon, BlzGetAbilityIcon(data), 0, false)
                BlzFrameSetTexture(frameObject.IconPush, BlzGetAbilityIcon(data), 0, false)
                BlzFrameSetTexture(frameObject.IconOff, BlzGetAbilityIcon(data), 0, false)
                BlzFrameSetText(frameObject.Text, GetObjectName(data))
                BlzFrameSetTexture(frameObject.ToolTipFrameIcon, BlzGetAbilityIcon(data), 0, false)
                BlzFrameSetText(frameObject.ToolTipFrameName, GetObjectName(data))
                --BlzFrameSetText(frameObject.ToolTipFrameText, BlzGetAbilityResearchExtendedTooltip(data, 0))
                if this.ToolTipGenInfo and data > 0 then
                    BlzFrameSetText(frameObject.ToolTipFrameText, BlzGetAbilityResearchExtendedTooltip(data, 0).. TasAbilityData.GetGenericFields(data))
                else
                    BlzFrameSetText(frameObject.ToolTipFrameText, BlzGetAbilityResearchExtendedTooltip(data, 0))
                end
            end
        elseif type(data) == "table" then
            BlzFrameSetTexture(frameObject.Icon, data.Icon, 0, false)
            BlzFrameSetTexture(frameObject.IconPush, data.Icon, 0, false)
            BlzFrameSetTexture(frameObject.IconOff, data.Icon, 0, false)
            BlzFrameSetText(frameObject.Text, data.Text)
            BlzFrameSetTexture(frameObject.ToolTipFrameIcon, data.Icon, 0, false)
            BlzFrameSetText(frameObject.ToolTipFrameName, data.Name)
            BlzFrameSetText(frameObject.ToolTipFrameText, data.Text)
        end
    end
    -- how to search
    function this.ActionSpellListSearch(data, text, buttonListObject)
        if not text or text == "" then return true end
        text = string.lower(text)
        if type(data) == "number" then
            if string.find(string.lower(GetObjectName(data)), text, 1, true) then return true end
            if string.find(string.lower(BlzGetAbilityTooltip(data, 0)), text, 1, true) then return true end
            if string.find(string.lower(BlzGetAbilityResearchTooltip(data, 0)), text, 1, true) then return true end
            if string.find(string.lower(BlzGetAbilityExtendedTooltip(data, 0)), text, 1, true) then return true end
            if string.find(string.lower(BlzGetAbilityResearchExtendedTooltip(data, 0)), text, 1, true) then return true end
        elseif type(data) == "table" then
            if string.find(string.lower(data.Name), text, 1, true) then return true end
            if string.find(string.lower(data.Text), text, 1, true) then return true end
        end
        return false
    end


An example minimal DataSetup. It adds the wanted choice options and categories and starts the ui creation.
Lua:
do
    local AutoRun = false --(true) will create Itself at 0s, (false) you need to TasSkillSetPickerConfig
    function TasSkillSetPickerConfig()
xpcall(function()

ClearSelection() -- In V1.31.1 this performs bad when an unit is selected

    local catPassive = TasSkillSetPicker.DefineCategory("ReplaceableTextures/PassiveButtons/PASBTNStatUp.tga", "Passive")
    local catDamage = TasSkillSetPicker.DefineCategory("ReplaceableTextures/CommandButtons/BTNSteelMelee", "Offensive")
    local catUlti = TasSkillSetPicker.DefineCategory("ReplaceableTextures/CommandButtons/BTNAvatar", "Ultimate")

    TasSkillSetPicker.BanCategory(1, catUlti) -- ultimateSkill not allowed here
    TasSkillSetPicker.BanCategory(2, catUlti)
    TasSkillSetPicker.BanCategory(3, catUlti)
    TasSkillSetPicker.BanCategory(4, catUlti)
    TasSkillSetPicker.LockCategory(5, catUlti) -- only ultimateSkill allowed here
    TasSkillSetPicker.LockCategory(6, catUlti)

    TasSkillSetPicker.Add('AHhb', catHeal + catDamage)
    TasSkillSetPicker.Add('AHab', catAura + catMana)
    

    TasSkillSetPicker.Init()
    local counter = 120
    TimerStart(CreateTimer(), 1, true, function()
        counter = counter - 1
        BlzFrameSetText(TasSkillSetPicker.Window.WindowHead, "SkillPicker "..counter)
        if counter <= 0 then
            TasSkillSetPicker.ForcePickNow()
BlzFrameSetVisible(TasSkillSetPicker.Window.WindowHead, false)
            PauseTimer(GetExpiredTimer())
            DestroyTimer(GetExpiredTimer())
        end
    end)
end, print)
    end

    if AutoRun then
        if OnInit then -- Total Initialization v5.2.0.1 by Bribe
            OnInit.final(TasSkillSetPickerConfig)
        else -- without
            local real = MarkGameStarted
            function MarkGameStarted()
                real()
                TasSkillSetPickerConfig()
            end
        end
    end
end

How to install


Requiers Warcraft 3 1.31+ or higher
Map in Lua Mode
They must be in the map script
TasWindow
TasButtonList
TasFrameList
GetPlayerColorTexture
TasFrameAction
TasSkillSetPicker

optional features
TasAbilityData
TasHeroLearnEx

This needs to be imported in import/asset manager
war3mapImported\TasSkillSetPicker.fdf
war3mapImported\TasButtonList.fdf
war3mapImported\TasSkillSetPicker.toc
war3mapImported\TasButtonList.toc
WHEN USING THE EXPORT ALL BUTTON, IT CAN HAPPEN THAT THE CONTENT OF FDF & TOC FILES SWAP



ChangeLog


V1.2 no skill icon/Tooltip
V1.1 More comments, can stop localize, hide UI by button
V1a Fixed a bug with CastTime display
V1 First Release​
Previews
Contents

TasSkillPicker (Map)

Reviews
Antares
Everything seems to be working. Quite a nice system. You probably want to use it such that you force categories for each picked skill so that no hotkeys overlap. Approved
Finished looking through everything. Here are my comments:
  • The annotations for optional parameters is usually with an ?, instead of [], so it should be TasSkillSetPicker.ResetPlayer(player?), for example.
  • I don't know how I feel about the forced localization of strings. This could lead to a weird mix of translated and english words. I would at least make that an option that can be disabled in the config.
  • When I click the button to show the Skill Picker, it cannot be hidden again.
  • I think you should disable the normal hero abilities in the test map to avoid confusion with using your own skill learning system.
  • this.FilterNotAllowed / this.FilterNotUsed / this.FilterEnforced: This does not state that it is an overlay texture. You should clarify this.
  • this.BarSlotCount = 6 -- button in one Bar 1 to 12, dont change after creation The value can be between 1 and 12? Use full sentences please. This also seems to be the amount of skills that a player picks, so that should definitely be in its description.
  • Lua:
    TasSkillSetPicker.ActionButtonAccept(frame, player)
        finish player, use nil for frame, 
        fills unset slots with randoms
    If this is done because of the argument order in an internal function, you should create a wrapper that calls the public function which just uses one argument.
  • The EditorBarTooltip is kinda weird. I looked in-game to see where that is displayed and I only found it by accident. Not a great place to put a tooltip, but I also don't have a better suggestion where to put it.
  • Is there a way to change the unassigned icon and tooltip from Sammy and Tooltip missing?

The ability tooltips are quite nice and the search field is pretty pog. I need to steal that :prazz:.
 
Updated to V1.1

show button also can hide the Skill Picker

Demo Map Heroes now have a Fake Learn Skill and the default Learn UI is not shown.

Wrote comments above the filter Textures setup

API function PlayerAccept(player) replaces ActionButtonAccept(frame, player)

Added this.Localize = true & this.DoLocalize. TasSkillSetPicker & TasAbilityData each has an own set

The annotations for optional parameters is usually with an ?, instead of [], so it should be TasSkillSetPicker.ResetPlayer(player?), for example.
Lua.org uses [].

Is there a way to change the unassigned icon and tooltip from Sammy and Tooltip missing?
Tooltip Text no, Icon fdf ;)
 
Top