• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

HeroSelector

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

Introduction


HeroSelector is a Frame-UI System to pick a hero. Provides a vjass and Lua version. It features Random, Picking, Baning, unique/limited Picks, Random-Only "Picks", Swap, simple Pick Requirement, Categories. Picking/Banning can be enabled or disabled for a subgroup of Players at a wanted moment. The baned heroes can be baned instantly or wait until the next Picking.
A Pick Requirement enables a Hero only for a Player, a TeamNr, a force, a Race or for a TechLevel/UnitCode-count. But each option can have only one requirement. The button is still visible for all Players.

Category can be clicked to have Heros not having that category being displayed less visible. One should use power 2 numbers when Setting/adding categories to selection Options. All added Options get on Default the category melee or ranged or None if the can't attack on default.

The Selection pool is displayed in one page in rows and cols the amount of cols and rows can be changed inside HeroSelectors Setup which is at the top of HeroSelector after the API comments. The space between 2 rows and 2 Buttons can be changed as well as the button size.

HeroSelector Trigger Files


A short overview of the Trigger Editor files
HeroSelectors features are split into 3/(4 jass) Trigger Editor Files.
HeroSelector is the main one the big box with the hero icons and categories.
Teamviewer manages the herocards that show current preview.
HeroInfo shows the info for the current selected preview.
Each of them has a setup part at the top (globals vjass + some functions)

(vjass) HeroSelectorAction is the place for manual (v)jass writers to change the default behaviour of HeroSelectorEvents and the initial selectable options setup

How to use the Selection grid?


Each hero can only be once in the grid. When using HeroSelector.addUnit it will add a new slot. There are HeroSelector.ButtonColCount*HeroSelector.ButtonRowCount slots.
3 rows with 4 cols would result into:

Code:
01,  02,  03,  04,
05,  06,  07,  08,
09,  10,  11,  12,

When you want to leave fields in the grid empty use HeroSelector.addUnit(0) or HeroSelector.addUnit().
There is a GUI setup which works with indexes, not set indexes will be empty fields.

Hook into


Offers 4 functions one can hook into to add custom Code without having to touch the System Code. By doing that one can add extra Features. Like shown with TeamView and HeroInfo which are not part of the core System but in the same folder. Although this functions have in this upload some content which I think is useful to have. They are below HeroSelector Setup.
Lua:
function HeroSelector.unitCreated(player, unit, isRandom)
--    this function is called when an unit is picked, add here you actions that have to be done for the picked unit
function HeroSelector.buttonSelected(player, unitCode)
--    this function is called when an player selects an button, this is not the picking.
function HeroSelector.unitBaned(player, unitCode)
--    this function is called when a player bans an unitCode.
function HeroSelector.initHeroes()
--    this function will be called before anything is created, when not using GUI to setup data you could add the selectable heroes here.
function HeroSelector.repick(unit[, player])
-- if you hook/overwritte this, make sure you run it.

How to Install:


You map has to be in Lua-Mode (Lua mode).
jass requires vjass enabled
Export and Import
war3mapImported\HeroSelector.fdf
war3mapImported\HeroSelector.toc
war3mapImported\HeroSelectorBan.mdx
WHEN USING THE EXPORT ALL BUTTON, IT CAN HAPPEN THAT THE CONTENT OF the fdf and toc FILES SWAP
Copy the trigger Folder "HeroSelector" into your map.

API:


Lua:
--[[
HeroSelector V1.8b by Tasyen

A UI System to pick a Hero/UnitCode also supports ban and requirments
]]
HeroSelector = {}
HeroSelector.TocPath                = "war3mapImported\\HeroSelector.toc" --ex/import also "HeroSelector.fdf"
--Box
HeroSelector.BoxFrameName           = "HeroSelectorRaceBox" --this is the background box being created
HeroSelector.BoxPosX                = 0.3
HeroSelector.BoxPosY                = 0.4
HeroSelector.BoxPosPoint            = FRAMEPOINT_CENTER
HeroSelector.AutoShow               = true --(true) shows the box and the Selection at 0.0 for all players
HeroSelector.AutoCreate             = true --(true) create itself when gameStarted. (false) you need to HeroSelector.initHeroes() HeroSelector.initFrames()
--Unique Picks
HeroSelector.UnitCount              = 999 --each hero is in total allowed to be picked this amount of times (includes random, repicking allows a hero again).
HeroSelector.UnitCountPerTeam       = 1 --Each Team is allowed to pick this amount of each unitType
HeroSelector.ToManyTooltip          = "OUTOFSTOCKTOOLTIP"
-- HeroSelector.PickAbleHeroes is a Way to define pickable Units without touching HeroSelector.initHeroes
-- pickable options expects one string like "Hamg,Hmkg,Hpal,Hblm". It can contain 0 to have empty slots "Hamg,0,Hpal,0,Hblm"
-- all melee heroes "Hamg,Hmkg,Hpal,Hblm,Obla,Ofar,Otch,Oshd,Udea,Ulic,Udre,Ucrl,Edem,Ekee,Emoo,Ewar,Nngs,Nbrn,Npbm,Nplh,Nbst,Nfir,Ntin,Nalc"
HeroSelector.PickAbleHeroes         = ""
HeroSelector.EnableGUICode          = true  -- enables the gui parser and throwing the picked event. if you don't use either you should set this to false.
--Ban
HeroSelector.DelayBanUntilPick      = false --(true) baning will not be applied instantly, instead it is applied when HeroSelector.enablePick is called the next time.
--Category
HeroSelector.CategoryData = {
    --Icon path, tooltip Text (tries to localize), HeroCdes "Hmkg,Hpal"
    {"ReplaceableTextures\\CommandButtons\\BTNSteelMelee", "MELEE"},                 --1, automatic detected when adding an unit
    {"ReplaceableTextures\\CommandButtons\\BTNHumanMissileUpOne", "Ranged"},         --2, automatic detected when adding an unit
    {"ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower", "STRENGTH"},    --4
    {"ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility", "AGILITY"},        --8
    {"ReplaceableTextures\\CommandButtons\\BTNMantleOfIntelligence", "INTELLECT"},   --16
}
HeroSelector.CategoryAffectRandom   = true  --(false) random will not care about selected category
HeroSelector.CategoryMultiSelect    = false --(false) deselect other category when selecting one, (true) can selected multiple categories and all heroes having any of them are not filtered.
HeroSelector.CategorySize           = 0.02  --the size of the Category Button
HeroSelector.CategorySpaceX         = 0.0008 --space between 2 category Buttons, it is meant to need only one line of Categoryy Buttons.
HeroSelector.CategoryFilteredAlpha  = 45     -- Alpha value of Heroes being filtered by unselected categories
HeroSelector.CategoryAutoDetect     = true  -- try to set category of added options automatic
HeroSelector.CategoryAutoDetectHero = true  -- (heavy performance wise) create and remove added Heroes to setup the Category for the primary Attribute Str(4) Agi(8) Int(16)

--Indicator
HeroSelector.IndicatorPathPick      = "UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdl" --this model is used by the indicator during picking
HeroSelector.IndicatorPathBan       = "war3mapImported\\HeroSelectorBan.mdl" --this model is used by the indicator during baning
--Grid
HeroSelector.SpaceBetweenX          = 0.008 --space between 2 buttons in one row
HeroSelector.SpaceBetweenY          = 0.008 --space between 2 rows
HeroSelector.ButtonColCount         = 4 --amount of buttons in one row
HeroSelector.ButtonRowCount         = 4 --amount of rows
HeroSelector.ChainedButtons         = true --(true) connect to the previous button/ or row, (false) have a offset to the box topLeft in this moving a button has no effect on other buttons.
--Button
HeroSelector.ButtonSize             = 0.036 --size of each button
HeroSelector.ButtonBlendAll         = false --(true) when a hero icon uses transparenzy
HeroSelector.EmptyButtonPath        = "UI\\Widgets\\EscMenu\\Human\\blank-background.blp"
HeroSelector.HideEmptyButtons       = true
--Ban Button
HeroSelector.BanButtonTextPrefix    = "|cffcf2084" --Prefix Text for the Ban Button
HeroSelector.BanButtonText          = "CHAT_ACTION_BAN" --tries to get a Localized String
HeroSelector.BanButtonSizeX         = 0.085
HeroSelector.BanButtonSizeY         = 0.03
HeroSelector.BanTooltip             = "DISALLOWED"
HeroSelector.BanIgnoreRequirment    = true -- (true) Ban is not restricted by Requirments
--BanDone Button
HeroSelector.BanDoneButtonTextPrefix    = "|cffcf2084" --Prefix Text for the Ban Button
HeroSelector.BanDoneButtonText          = "QUESTACCEPT" --tries to get a Localized String
HeroSelector.BanDoneButtonSizeX         = 0.085
HeroSelector.BanDoneButtonSizeY         = 0.03
HeroSelector.BanDoneButtonIsShown       = false --show this button in the Ban Phase
--Accept Button
HeroSelector.AcceptButtonTextPrefix = ""
HeroSelector.AcceptButtonText       = "ACCEPT"
HeroSelector.AcceptButtonSizeX      = 0.085
HeroSelector.AcceptButtonSizeY      = 0.03
HeroSelector.AcceptButtonIsShown    = true --show this button in the Pick Phase
--Random Button
HeroSelector.RandomButtonTextPrefix = ""
HeroSelector.RandomButtonText       = "RANDOM" --tries Localizing
HeroSelector.RandomButtonSizeX      = 0.085
HeroSelector.RandomButtonSizeY      = 0.03
HeroSelector.RandomButtonIsShown    = true --show this button in the Pick Phase
HeroSelector.RandomButtonPick       = false --(true) pressing the random button will pick the option. (false) pressing the random button will select a button, random only heroes can not be selected, but that does not matter. This weak random and randomonly should not be combined.
--Repick Button
HeroSelector.RepickButtonTextPrefix = ""
HeroSelector.RepickButtonText       = "REPICK" --tries Localizing
HeroSelector.RepickButtonTextLimit  = "Repick (#)" --tries Localizing # is the variable for the remaining
HeroSelector.RepickButtonSizeX      = 0.085
HeroSelector.RepickButtonSizeY      = 0.03
HeroSelector.RepickButtonIsShown    = true --show this button in the Pick Phase
HeroSelector.RepickMax              = 0 -- when bigger than 0 only that amount of Repicks is allowed
--ShowButton
HeroSelector.ShowButtonTextPrefix = ""
HeroSelector.ShowButtonText       = "PICK-HERO" --tries Localizing
HeroSelector.ShowButtonSizeX      = 0.085
HeroSelector.ShowButtonSizeY      = 0.03
HeroSelector.ShowButtonIsShown    = false --show this button 
HeroSelector.ShowButtonX          = 0.42
HeroSelector.ShowButtonY          = 0.58
HeroSelector.ShowButtonPoint      = FRAMEPOINT_TOPLEFT
HeroSelector.ShowButtonParent     = function() return BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
--Tooltip
HeroSelector.TooltipPrefix          = "|cffffcc00"
HeroSelector.TooltipOffsetX         = 0
HeroSelector.TooltipOffsetY         = 0
HeroSelector.TooltipPoint           = FRAMEPOINT_BOTTOM --pos the Tooltip with which Point
HeroSelector.TooltipRelativePoint   = FRAMEPOINT_TOP --pos the Tooltip to which Point of the Relative
HeroSelector.TooltipRelativIsBox    = false          --(true) use the box as anchor, (false) use the button as anchor
HeroSelector.TooltipRequires        = "QUESTCOMPONENTS"
HeroSelector.TooltipRequires2       = {
    [RACE_HUMAN] = "HUMAN"
    ,[RACE_ORC] = "ORC"
    ,[RACE_UNDEAD] = "UNDEAD"
    ,[RACE_NIGHTELF] = "NIGHT_ELF"
    ,[PLAYER_STATE_RESOURCE_HERO_TOKENS] = "HERO TOCKEN"
}


--Border
HeroSelector.BorderSize = {}
HeroSelector.BorderSize[RACE_HUMAN]     = 0.029 --border size seen by Race Human, this is needed cause the borders are different in size.
HeroSelector.BorderSize[RACE_ORC]       = 0.029
HeroSelector.BorderSize[RACE_UNDEAD]    = 0.035
HeroSelector.BorderSize[RACE_NIGHTELF]  = 0.035
HeroSelector.BorderSize[RACE_DEMON]     = 0.024


--This runs before the box is created with that the system has the needed data right when it is needed.
--you can add units somewhere else but it is done after the box was created you have to use the update function to update the textures of shown buttons
function HeroSelector.initHeroes()
    --create categories setuped in config
    local categories = HeroSelector.CategoryData
    HeroSelector.Category = {}
    for index, value in ipairs(categories) do
       HeroSelector.addCategory(value[1], value[2])
    end

    --read GUI, when the variable exist
    if HeroSelector.EnableGUICode and udg_HeroSelectorUnitCode then
        local index = 1
        --add from index 1 all random only heroes
        while udg_HeroSelectorRandomOnly[index] ~= 0 do
            HeroSelector.addUnit(udg_HeroSelectorRandomOnly[index], true)
            index = index + 1
        end

        --copy the setuped field
        for index = 1, HeroSelector.ButtonColCount*HeroSelector.ButtonRowCount,1 do
            HeroSelector.addUnit(udg_HeroSelectorUnitCode[index])
            if udg_HeroSelectorCategory and udg_HeroSelectorCategory[index] ~= 0 then
                HeroSelector.addUnitCategory(udg_HeroSelectorUnitCode[index], udg_HeroSelectorCategory[index])
            end
        end

        --kill the tables
        udg_HeroSelectorUnitCode = nil
        udg_HeroSelectorRandomOnly = nil
        udg_HeroSelectorCategory = nil
    end

    --adding further units when using the GUI Array does not make much sense, except you would add rows.

    if HeroSelector.PickAbleHeroes and (type(HeroSelector.PickAbleHeroes) =="string" and string.len( HeroSelector.PickAbleHeroes ) >= 4 ) then HeroSelector.addUnit(HeroSelector.PickAbleHeroes) end

    local iCat = 1
    for index, value in ipairs(categories) do
        if value[3] then
            HeroSelector.addUnitCategory(value[3], iCat)
        end
        iCat=iCat*2
    end

    --skip further demo code
    if true then return end


    HeroSelector.addUnit("Hgam", true, 0) --antonidas is an only random Hero that can only be randomed by team 0 (for users 1).
    HeroSelector.addUnit("Eevi", true, 1) --evil Illidan is an only random Hero that can only be randomed by team 1 (for users 2).
    
    --Adds requirments
    --when you have a ban phase it might be better to add the requirments after the ban phase is over, otherwise one can only ban own options.
    --paladin requires having 5 footman, Archmage a Hero Tocken other human heroes can only picked by human-Race, as nightelf only for Nightelf
    HeroSelector.setUnitReq('Hpal', {FourCC('hfoo'), 5})
    HeroSelector.setUnitReq('Hamg', PLAYER_STATE_RESOURCE_HERO_TOKENS)
    HeroSelector.setUnitReq('Hblm', RACE_HUMAN)
    HeroSelector.setUnitReq('Hmkg', RACE_HUMAN)
    --HeroSelector.setUnitReq('Ofar', RACE_ORC)
    --HeroSelector.setUnitReq('Oshd', RACE_ORC)
    --HeroSelector.setUnitReq('Otch', RACE_ORC)
    --HeroSelector.setUnitReq('Obla', RACE_ORC)
    HeroSelector.setUnitReq('Emoo', RACE_NIGHTELF)
    HeroSelector.setUnitReq('Edem', RACE_NIGHTELF)
    HeroSelector.setUnitReq('Ekee', RACE_NIGHTELF)
    HeroSelector.setUnitReq('Ewar', RACE_NIGHTELF)
    --HeroSelector.setUnitReq('Udea', RACE_UNDEAD)
    --HeroSelector.setUnitReq('Ulic', RACE_UNDEAD)
    --HeroSelector.setUnitReq('Udre', RACE_UNDEAD)
    --HeroSelector.setUnitReq('Ucrl', RACE_UNDEAD)
    --[[
    local categoryMelee = 1 --autodetected
    local categoryRanged = 2 --autodetected
    local categoryStr = 4
    local categoryAgi = 8
    local categoryInt = 16
    HeroSelector.addUnitCategory('Hpal', categoryStr)
    HeroSelector.addUnitCategory('Hamg', categoryInt)
    HeroSelector.addUnitCategory('Hblm', categoryInt)
    HeroSelector.addUnitCategory('Hmkg', categoryStr)
    HeroSelector.addUnitCategory('Ofar', categoryInt)
    HeroSelector.addUnitCategory('Oshd', categoryAgi)
    HeroSelector.addUnitCategory('Otch', categoryAgi)
    HeroSelector.addUnitCategory('Obla', categoryAgi)
    HeroSelector.addUnitCategory('Emoo', categoryAgi)
    HeroSelector.addUnitCategory('Edem', categoryAgi)
    HeroSelector.addUnitCategory('Ekee', categoryInt)
    HeroSelector.addUnitCategory('Ewar', categoryAgi)
    HeroSelector.addUnitCategory('Udea', categoryStr)
    HeroSelector.addUnitCategory('Ulic', categoryInt)
    HeroSelector.addUnitCategory('Udre', categoryStr)
    HeroSelector.addUnitCategory('Ucrl', categoryStr)

    HeroSelector.setUnitCategory('Hgam', categoryInt + categoryRanged)
    HeroSelector.setUnitCategory("Eevi", categoryAgi + categoryMelee)
    --]]
    
    --[[
    HeroSelector.addUnit('Hpal') --add paladin as selectable Hero
    HeroSelector.addUnit('Hamg')
    HeroSelector.addUnit('Hblm')
    HeroSelector.addUnit('Hmkg')
    HeroSelector.addUnit("Obla", true) --this unit can only be randomed
    HeroSelector.addUnit("Ofar")
    HeroSelector.addUnit("Otch", 1) --this unit can only be randomed
    HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    HeroSelector.addUnit() 
    HeroSelector.addUnit("Oshd")
    HeroSelector.addUnit("Edem")
    HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    HeroSelector.addUnit() 
    HeroSelector.addUnit("Ekee")
    HeroSelector.addUnit("Emoo")
    HeroSelector.addUnit("Ewar",true)
    HeroSelector.addUnit("Udea")
    HeroSelector.addUnit("Ulic")
    HeroSelector.addUnit("Udre")
    HeroSelector.addUnit("Ucrl",1)
    --]]
end

function HeroSelector.autoDetectCategory(unitCode)
    if HeroSelector.CategoryAutoDetect then
        if IsUnitIdType(unitCode, UNIT_TYPE_MELEE_ATTACKER) then
            HeroSelector.UnitData[unitCode].Category = 1
        elseif IsUnitIdType(unitCode, UNIT_TYPE_RANGED_ATTACKER) then
            HeroSelector.UnitData[unitCode].Category = 2
        end
        if HeroSelector.CategoryAutoDetectHero and IsUnitIdType(unitCode, UNIT_TYPE_HERO) then
            local unit = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), unitCode, 0, 0, 270)
            local primaryAttribute = BlzGetUnitIntegerField(unit, UNIT_IF_PRIMARY_ATTRIBUTE)
            RemoveUnit(unit)
            if ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_STR then
                HeroSelector.UnitData[unitCode].Category = HeroSelector.UnitData[unitCode].Category + 4
            elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_AGI then
                HeroSelector.UnitData[unitCode].Category = HeroSelector.UnitData[unitCode].Category + 8
            elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_INT then 
                HeroSelector.UnitData[unitCode].Category = HeroSelector.UnitData[unitCode].Category + 16
            end
        end
    end
end

--what happens to the unit beeing picked, player is the one having pressed the button
function HeroSelector.unitCreated(player, unitCode, isRandom)
    bj_lastCreatedUnit = CreateUnit(player, unitCode, GetPlayerStartLocationX(player), GetPlayerStartLocationY(player), 0)
    local unit = bj_lastCreatedUnit
    HeroSelector.PickedUnit[player] = unit
    if isRandom then
        --randomed
    else
        --picked
    end

    if player == Player(1) then
                
    end

    PanCameraToTimedForPlayer(player, GetUnitX(unit), GetUnitY(unit),0)
    SelectUnitForPlayerSingle(unit, player)
    HeroSelector.enablePick(false, player) --only one pick for this player

    if HeroSelector.EnableGUICode then
        globals.udg_HeroSelectorEvent = 0
        globals.udg_HeroSelectorEvent = 1.0
    end
    --print(GetPlayerName(player),"picks",GetUnitName(unit))
end

--happens when the banButton is pressed, player is the one having pressed the button
function HeroSelector.unitBaned(player, unitCode)
    HeroSelector.enableBan(false, player) --only one ban
    --print(GetPlayerName(player),"bans",GetObjectName(unitCode))
end

function HeroSelector.buttonSelected(player, unitCode)
    --player who pressed the button
    --unitCode the unitCode selected
    --this is not picked.

    --print(GetPlayerName(player),"selects",GetObjectName(unitCode))
end

function HeroSelector.repick(unit, player)
    
    if not unit then return end

    UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, unit) --this is done to undo metamorph
    local unitCode = GetUnitTypeId(unit)
    if unitCode == 0 then return end

    HeroSelector.counterChangeUnitCode(unitCode, -1, player)

    if not player then
        player = GetOwningPlayer(unit)
    end
    HeroSelector.PickedUnit[player] = nil
    HeroSelector.show(true, player)
    HeroSelector.enablePick(true, player)
    RemoveUnit(unit)
end

function HeroSelector.actionBanDoneButton(frame, player)
    -- HeroSelector.enablePick(true) -> on click finish the Ban Phase and start pick Phase
    HeroSelector.enablePick(true)
end

function HeroSelector.actionShowButton(frame, player)
    if GetLocalPlayer() == player then BlzFrameSetVisible(HeroSelector.Box, not BlzFrameIsVisible(HeroSelector.Box)) end
end

--[[
This functions are found directly below the config and belong to the config.
They also can be hooked but you might lose the default. Could do it like it is done in TeamViewer create a Backup of the current then overwrite it and call the backup in the replacement.

function HeroSelector.unitCreated(player, unitCode, isRandom)
    this function is called when an unit is picked, add here you actions that have to be done for the picked unit

function HeroSelector.buttonSelected(player, unitCode)
    this function is called when an player selects an button, this is not the picking.

function HeroSelector.unitBaned(player, unitCode)
    this function is called when a player bans an unitCode.

function HeroSelector.actionBanDoneButton(frame, player)
    this function happens when the banDone Button is clicked

function HeroSelector.repick(unit[, player])
    if player is skiped unit owner sees the selection
    this will remove the unit from the game.
    Adds thie unitcode of the unit to the randompool

function HeroSelector.autoDetectCategory(unitCode)
    this called on every unit added. It is a good place for simple automatic categorizes, on default it categorizes melee as 1 and ranged as 2.

function HeroSelector.initHeroes()
    this function will be called before anything is created, when not using GUI to setup data you could add the selectable heroes here.
------
How use the Selection grid?
Each hero can only be once in the grid. When using HeroSelector.addUnit it will add a new slot. There are HeroSelector.ButtonColCount*HeroSelector.ButtonRowCount slots.
3 rows with 4 cols would result into:
01 02 03 04
05 06 07 08
09 10 11 12

When you want to leave fields in the grid empty use HeroSelector.addUnit(0) or HeroSelector.addUnit().
There is a GUI setup which works with indexes, not set indexes will be empty fields.
------
function HeroSelector.setUnitReq(unitCode, who)
    adds an requirement: can be a player, a force, a teamNumber, a race, a table {techcode, level}, playerState (need to have 1 of it, mostly useful for PLAYER_STATE_RESOURCE_HERO_TOKENS), skip who or nil will remove an requirment.
    unitCode can be a number or a string 'Hpal' or 'Hpal,Ofar,Ulic'
    Only when the local player fullfills than he can click the button.
    calling this will not update the selected buttonIndex of players nor does this update the clickability.
    To update the clickability when setting requirments after the Box was created use HeroSelector.update() and deselect indexes
    won't work when the unitCode wasn't added yet.
    
function HeroSelector.addUnit([unitCode, onlyRandom, requirement])
    unitCode can be a number or a string 'Hpal' or 'Hpal,Ofar,Ulic,0,Obla'
    can be called without arguments to hava a empty slot calling it with 0 has the same effect
    requirement works like who in HeroSelector.setUnitReq.

function HeroSelector.setUnitCategory(unitCode, category)
    unitCode can be a number or a string 'Hpal' or 'Hpal,Ofar,Ulic'
    sets the category of an added Option.
    Category should be a power 2 number. 1 2 4 8 16 32 ....

function HeroSelector.addUnitCategory(unitCode, category)
    unitCode can be a number or a string 'Hpal' or 'Hpal,Ofar,Ulic'
    Keeps previous setings untouched

function HeroSelector.addCategory(icon, text)
    icon is the enabled image, text is the tooltip text.

function HeroSelector.clearUnitData()
    removes all current UnitData this includes limit-counters, requirements, categories.

function HeroSelector.show(flag, [who])
    Shows/Hides HeroSelector to who
    flag = true show it, false = hide it
    who can be a player, a force, a teamNumber, a race or nothing = anyone
    teamNumbers are the warcraft 3 given teamNumbers starting with 0 for team 1.
    the force is expected to be kept alive

function HeroSelector.setFrameText(frame, text[, who])
    uses BlzFrameSetText onto frame when the local player is included in who by the rules of function HeroSelector.includesPlayer
function HeroSelector.setTitleText(text[, who])
    wrapper HeroSelector.setFrameText
function HeroSelector.setBanButtonText(text[, who])
    wrapper HeroSelector.setFrameText
function HeroSelector.setAcceptButtonText(text[, who])
    wrapper HeroSelector.setFrameText

function HeroSelector.enablePick(flag[, who])
    enable/disable the accept/random button also makes them visible for that players and hides the ban Button.
    
function HeroSelector.enableBan(flag[, who])
    enable/disable the ban button also makes accept/random invisible for that players and shows the ban Button.

function HeroSelector.forceRandom([who])
    wrapper for doRandom for player

function HeroSelector.forcePick([who])
    forces to pick what currently is selected, if that fails doRandom

function HeroSelector.buttonRequirementDone(unitCode, player)

function HeroSelector.deselectButtons([buttonIndex])
    deselect selected buttons for all players with 0 or nil
    when an index is given only this specific buttonIndex

function HeroSelector.update()
    reDo possible selection, textures and enability for all heroButtons.

function HeroSelector.getDisabledIcon(icon)
    ReplaceableTextures\CommandButtons\BTNHeroPaladin.tga -> ReplaceableTextures\CommandButtonsDisabled\DISBTNHeroPaladin.tga

function HeroSelector.showFrame(frame, flag[, who])
    Set the visibility of frame to flag when who includes the local player by the rules of function HeroSelector.includesPlayer

function HeroSelector.includesPlayer(who, player)
    does player include who?
    return true, if yes.
    return false otherwise
    who can be a number(GetPlayerTeam), a race(GetPlayerRace), a player, a force(BlzForceHasPlayer) or
    nil => true    

function HeroSelector.counterChangeUnitCode(unitCode, add, player)
    increases/decreases the counter for picks of unitCode for the player's team.
    This can allow/disallow picking this unit for that team.

function HeroSelector.rollOption(player, includeRandomOnly, excludedIndex, category)
    get an random Unitcode from the added options
    returns an unitcode or nil when none could be found
--]]


JASS:
library HeroSelector initializer init_function requires optional FrameLoader
//HeroSelector V1.7
//API
//=====
//HeroSelectorForcePick()
//HeroSelectorForcePickPlayer(player p)
//HeroSelectorForcePickRace(race r)
//HeroSelectorForcePickTeam(integer teamNr)

//HeroSelectorForceRandom()
//HeroSelectorForceRandomRace(race r)
//HeroSelectorForceRandomTeam(integer teamNr)

//HeroSelectorDoPick(player p)
//HeroSelectorDoRandom(player p)

//HeroSelectorShow(boolean flag)
//HeroSelectorShowForce(boolean flag, force f)
//HeroSelectorShowRace(boolean flag, race r)
//HeroSelectorShowPlayer(boolean flag, player p)
//HeroSelectorShowTeam(boolean flag, integer teamNr)

//HeroSelectorEnableBan(boolean flag)
//HeroSelectorEnableBanRace
//HeroSelectorEnableBanTeam
//HeroSelectorEnableBanPlayer
//HeroSelectorEnableBanForce

//HeroSelectorEnablePick(boolean flag)
//HeroSelectorEnablePickForce
//HeroSelectorEnablePickPlayer
//HeroSelectorEnablePickTeam
//HeroSelectorEnablePickRace

//HeroSelectorRollOption(player p, boolean includeRandomOnly, integer exculdedIndex, integer category) returns integer
//HeroSelectorCounterChangeUnitCode(integer unitCode, integer add, player p)
//HeroSelectorEnableButtonIndex(integer unitCode, integer buttonIndex)
//HeroSelectorDisableButtonIndex(integer buttonIndex, integer teamNr)
//HeroSelectorButtonRequirementDone(integer unitCode, player p) returns boolean
//HeroSelectorDeselectButton(integer buttonIndex)

//HeroSelectorAddUnit(integer unitCode, boolean onlyRandom)
//HeroSelectorAddUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitReqPlayer(integer unitCode, player p)
//HeroSelectorSetUnitReqRace(integer unitCode, race r)
//HeroSelectorSetUnitReqForce(integer unitCode, force f)
//HeroSelectorSetUnitReqTeam(integer unitCode, integer teamNr)
//HeroSelectorSetUnitReqTechLevel(integer unitCode, integer techCode, integer techLevel)

//HeroSelectorSetFrameText(framehandle frame, string text)
//HeroSelectorSetFrameTextPlayer
//HeroSelectorSetFrameTextForce
//HeroSelectorSetFrameTextTeam
//HeroSelectorSetFrameTextRace

//HeroSelectorSetTitleText(string text)
//HeroSelectorSetTitleTextRace
//HeroSelectorSetTitleTextPlayer
//HeroSelectorSetTitleTextForce
//HeroSelectorSetTitleTextTeam

//HeroSelectorSetBanButtonText
//HeroSelectorSetBanButtonTextPlayer
//HeroSelectorSetBanButtonTextRace
//HeroSelectorSetBanButtonTextForce
//HeroSelectorSetBanButtonTextTeam

//HeroSelectorSetRandomButtonText
//HeroSelectorSetRandomButtonTextPlayer
//HeroSelectorSetRandomButtonTextForce
//HeroSelectorSetRandomButtonTextTeam
//HeroSelectorSetRandomButtonTextRace

//HeroSelectorSetAcceptButtonText
//HeroSelectorSetAcceptButtonTextPlayer
//HeroSelectorSetAcceptButtonTextForce
//HeroSelectorSetAcceptButtonTextTeam
//HeroSelectorSetAcceptButtonTextRace

//HeroSelectorAddCategory(string icon, string text) //should only be used before the category Buttons are created

//HeroSelectorGetDisabledIcon(string iconPath)

//HeroSelectorUpdate()

//=====

    
    globals
        //Setup
        private string TocPath            = "war3mapImported\\HeroSelector.toc" //ex/import also "HeroSelector.fdf"
        //Box
        private string BoxFrameName            = "HeroSelectorRaceBox" //this is the background box being created
        private real BoxPosX                   = 0.3
        private real BoxPosY                   = 0.4
        private framepointtype BoxPosPoint     = FRAMEPOINT_CENTER
        private boolean AutoShow               = true //(true) shows the box and the Selection at 0.0 for all players
        //Unique Picks
        public integer UnitCount              = 2 //each hero is in total allowed to be picked this amount of times (includes random, repicking allows a hero again).
        public integer UnitCountPerTeam       = 1 //Each Team is allowed to pick this amount of each unitType
        private string  ToManyTooltip          = "OUTOFSTOCKTOOLTIP"
        //Ban
        private boolean DelayBanUntilPick      = false //(true) baning will not be applied instantly, instead it is applied when HeroSelectorEnablePick is called the next time.
        //Category
        private boolean CategoryAffectRandom   = true  //(false) random will not care about selected category
        private boolean CategoryMultiSelect    = false //(false) deselect other category when selecting one, (true) can selected multiple categories and all heroes having any of them are not filtered.
        private real CategorySize              = 0.02  //the size of the Category Button
        private real CategorySpaceX            = 0.0008 //space between 2 category Buttons, it is meant to need only one line of Categoryy Buttons.
        private integer CategoryFilteredAlpha  = 45     // Alpha value of Heroes being filtered by unselected categories
        private boolean CategoryAutoDetectHero = true // Will create and remove added Heroes to read and setup the Category for the primary Attribute Str(4) Agi(8) Int(16)
            //Icon path, tooltip Text (tries to localize)
        //Indicator
        private framehandle IndicatorSelected
        private framehandle IndicatorSelectedParent
        private string IndicatorPathPick       = "UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdl" //this model is used by the indicator during picking
        private string IndicatorPathBan        = "war3mapImported\\HeroSelectorBan.mdl" //this model is used by the indicator during baning
        //Grid
        private real SpaceBetweenX             = 0.008 //space between 2 buttons in one row
        private real SpaceBetweenY             = 0.008 //space between 2 rows
        private integer ButtonColCount         = 4 //amount of buttons in one row
        private integer ButtonRowCount         = 4 //amount of rows
        
        private boolean ChainedButtons         = true //(true) connect to the previous button/ or row, (false) have a offset to the box topLeft in this moving a button has no effect on other buttons.
        //Button
        private real ButtonSize                = 0.036 //size of each button
        private boolean ButtonBlendAll         = false //(true) when a hero icon uses transparenzy
        private string EmptyButtonPath         = "UI\\Widgets\\EscMenu\\Human\\blank-background.blp"
        private boolean HideEmptyButtons       = true
        //Ban Button
        private string BanButtonTextPrefix     = "|cffcf2084" //Prefix Text for the Ban Button
        private string BanButtonText           = "CHAT_ACTION_BAN" //tries to get a Localized String
        private real BanButtonSizeX            = 0.085
        private real BanButtonSizeY            = 0.03
        private string BanTooltip              = "DISALLOWED"
        private boolean BanIgnoreRequirment    = true // (true) Ban is not restricted by Requirments
        //BanDone Button
        private string BanDoneButtonTextPrefix    = "|cffcf2084" //Prefix Text for the Ban Button
        private string BanDoneButtonText          = "QUESTACCEPT" //tries to get a Localized String
        private real BanDoneButtonSizeX         = 0.085
        private real BanDoneButtonSizeY         = 0.03
        public boolean BanDoneButtonIsShown       = false //show this button in the Ban Phase
        //Accept Button
        private string AcceptButtonTextPrefix       = ""
        private string AcceptButtonText             = "ACCEPT"
        private real AcceptButtonSizeX              = 0.085
        private real AcceptButtonSizeY              = 0.03
        public boolean AcceptButtonIsShown         = true
        //Random Button
        private string RandomButtonTextPrefix       = ""
        private string RandomButtonText             = "RANDOM" //tries Localizing
        private real RandomButtonSizeX              = 0.085
        private real RandomButtonSizeY              = 0.03
        private boolean RandomButtonIsShown         = true
        private boolean RandomButtonPick            = false //(true) pressing the random button will pick the option. (false) pressing the random button will select a button, random only heroes can not be selected, but that does not matter. This weak random and randomonly should not be combined.
        //Repick Button
        private string RepickButtonTextPrefix = ""
        private string RepickButtonText       = "REPICK" //tries Localizing
        private real RepickButtonSizeX      = 0.085
        private real RepickButtonSizeY      = 0.03
        public boolean RepickButtonIsShown    = true //show this button in the Pick Phase
        //Tooltip
        private string TooltipPrefix                  = "|cffffcc00"
        private real TooltipOffsetX                   = 0
        private real TooltipOffsetY                   = 0
        private framepointtype TooltipPoint           = FRAMEPOINT_BOTTOM //pos the Tooltip with which Point
        private framepointtype TooltipRelativePoint   = FRAMEPOINT_TOP //pos the Tooltip to which Point of the Relative
        private boolean TooltipRelativIsBox           = false          //(true) use the box as anchor, (false) use the button as anchor
        private string TooltipRequires                = "QUESTCOMPONENTS"

        //System variables, Do not touch
        public integer HeroButtonCount        = ButtonRowCount*ButtonColCount
        public unit array PickedUnit
        private trigger CategoryClickTrigger   = CreateTrigger()
        private trigger AcceptButtonTrigger  = CreateTrigger()
        private trigger BanButtonTrigger      = CreateTrigger()
        private trigger RandomButtonTrigger  = CreateTrigger()
        private trigger RepickButtonTrigger  = CreateTrigger()
        private trigger BanDoneButtonTrigger  = CreateTrigger()
        
        private framehandle BanButton
        private framehandle AcceptButton
        private framehandle RandomButton
        private framehandle BanDoneButton
        private framehandle RepickButton
        private player array DelayBanPlayer
        private integer array DelayBanUnitCode
        private integer DelayBanCount = 0
        public framehandle array CategoryButton
        public framehandle array CategoryIconFrame
        public framehandle array CategoryIconPushedFrame        
        public framehandle array CategoryTooltipFrame
        public framehandle array CategoryTooltipFrameBox
        public string array CategoryText
        public string array CategoryTexture
        public string array CategoryTextureDisabled
        private integer array CategoryButtonValue
        public integer CategoryButtonCount = 0
        private integer array UsedTeamNr
        private integer UsedTeamNrCount = 0

        private integer ButtonHeroCount = 0        
        private integer array ButtonHeroUnitCode


        private integer array HeroTotalCount
        public integer array HeroCategory
        private integer array HeroRegType
        private player array HeroRegPlayer
        private force array HeroRegForce
        private integer array HeroRegNumber
        private integer array HeroRegNumber2
        private race array HeroRegRace

        private integer HeroCount = 0
        private integer array HeroUnitCode
        private integer array HeroButtonIndex


        public hashtable Hash = InitHashtable()
        framehandle HeroSelectorBox
        private framehandle HeroSelectorBoxSeperator
        private framehandle HeroSelectorBoxTitle

        private integer array HeroButtonUnitCode
        private integer HeroButtonUnitCodeCount = 0
        private framehandle array HeroButtonIcon
        private framehandle array HeroButtonIconPushed        
        private framehandle array HeroButtonIconDisabled
        private framehandle array HeroButtonTooltip
        private framehandle array HeroButtonTooltipBox
        private framehandle array HeroButtonFrame
        private trigger HeroButtonClickTrigger = CreateTrigger()

        private integer array PlayerSelectedButtonIndex
        private integer array PlayerSelectedCategory
        private integer array PlayerLastSelectedCategoryIndex

        private integer LastAction = 0
    endglobals

    private function AutoDetectCategory takes integer unitCode returns integer
        local integer value = 0
        local unit u
        local integer primaryAttribute
        if IsUnitIdType(unitCode, UNIT_TYPE_MELEE_ATTACKER) then
            set value = 1            
        elseif IsUnitIdType(unitCode, UNIT_TYPE_RANGED_ATTACKER) then
            set value = 2
        endif
        if CategoryAutoDetectHero and IsUnitIdType(unitCode, UNIT_TYPE_HERO) then
            set u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), unitCode, 0, 0, 270)
            set primaryAttribute = BlzGetUnitIntegerField(u, UNIT_IF_PRIMARY_ATTRIBUTE)
            call RemoveUnit(u)
            set u = null

            if ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_STR then
                set value = value + 4
            elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_AGI then
                set value = value + 8
            elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_INT then 
                set value = value + 16
            endif
        endif
        return value
    endfunction

    private function GetBorderSize takes nothing returns real
        if GetPlayerRace(GetLocalPlayer()) == RACE_HUMAN then
            return 0.029
        elseif GetPlayerRace(GetLocalPlayer()) == RACE_ORC then
            return 0.029
        elseif GetPlayerRace(GetLocalPlayer()) == RACE_UNDEAD then
            return 0.035
        elseif GetPlayerRace(GetLocalPlayer()) == RACE_NIGHTELF then
            return 0.035
        elseif GetPlayerRace(GetLocalPlayer()) == RACE_DEMON then
            return 0.024
        else 
            return 0.0
        endif
    endfunction



  • HeroSelectorGUI Plus
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Random Only Hero do not take slots --------
      • Set HeroSelectorRandomOnly[1] = Klingenmeister
      • Set HeroSelectorRandomOnly[2] = Tauren-Häuptling
      • Set HeroSelectorRandomOnly[3] = Gruftlord
      • Set HeroSelectorRandomOnly[4] = Wächterin
      • -------- Positions of the UnitCodes taking buttons. --------
      • -------- Can only use upto HeroSelector.ButtonColCount*HeroSelector.ButtonRowCount fields --------
      • -------- The first button start at the top left with index 1. --------
      • -------- Unset fields are autofilled with empty slots. --------
      • Set HeroSelectorUnitCode[2] = Paladin
      • Set HeroSelectorUnitCode[3] = Erzmagier
      • Set HeroSelectorUnitCode[5] = Bergkönig
      • Set HeroSelectorUnitCode[6] = Blutmagier
      • Set HeroSelectorUnitCode[7] = Scharfseher
      • Set HeroSelectorUnitCode[8] = Schattenjäger
      • Set HeroSelectorUnitCode[9] = Dämonenjäger
      • Set HeroSelectorUnitCode[10] = Hüter des Hains
      • Set HeroSelectorUnitCode[11] = Mond-Priesterin
      • Set HeroSelectorUnitCode[12] = Todesritter
      • Set HeroSelectorUnitCode[14] = Lich
      • Set HeroSelectorUnitCode[15] = Schreckenslord
  • Start
    • Events
      • Time - Elapsed game time is 0.10 seconds
    • Conditions
    • Actions
      • Player Group - Pick every player in (All players) and do (Actions)
        • Loop - Actions
          • Unit - Create 1 Circle der Macht for (Picked player) at ((Picked player) start location) facing Default building facing degrees
      • -------- When the autoShowing is off, the HeroSelector has to be shown first --------
      • Custom script: HeroSelector.show(true)
      • -------- Hide picking buttons and show the bann button --------
      • Custom script: HeroSelector.enableBan(true)
  • BaningPhase
    • Events
      • Time - Every 0.75 seconds of game time
    • Conditions
    • Actions
      • -------- Runs 3 times in 4 seconds changes the Title. --------
      • -------- Show Remaining Counts in the Titel --------
      • Set Count = (31 - (Execution count of (This trigger)))
      • Custom script: HeroSelector.setTitleText( "Baning: " .. udg_Count)
      • -------- Time Run up? --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Count Less than or equal to 0
        • Then - Actions
          • -------- Enable Picking --------
          • Custom script: HeroSelector.enablePick(true)
          • -------- Swap Active Trigger (Phase) --------
          • Trigger - Turn off (This trigger)
          • Trigger - Turn on Picking Phase <gen>
          • -------- Update Titel Right Now --------
          • Custom script: HeroSelector.setTitleText( "Picking: ")
        • Else - Actions
  • Picking Phase
    • Events
      • Time - Every 0.75 seconds of game time
    • Conditions
    • Actions
      • -------- Runs 3 times in 4 seconds changes the Title. --------
      • Set Count = (31 - (Execution count of (This trigger)))
      • Custom script: HeroSelector.setTitleText( "Picking: " .. udg_Count)
      • -------- The Time run up? --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Count Less than or equal to 0
        • Then - Actions
          • -------- Pick everyone --------
          • Player Group - Pick every player in (All players) and do (Actions)
            • Loop - Actions
              • Custom script: bj_wantDestroyGroup = true
              • -------- This one has a hero? --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Random unit from (Units owned by (Picked player) matching (((Matching unit) is A Hero) Equal to True))) Equal to No unit
                • Then - Actions
                  • -------- No, force a Pick for him --------
                  • Custom script: HeroSelector.forcePick(GetEnumPlayer())
                • Else - Actions
          • Trigger - Turn off (This trigger)
          • Custom script: HeroSelector.destroy()
        • Else - Actions


Credits (jass):
Nestharus/Bribe

changelog:
1.8b Lua)
Better support for DisabledIcons
Max Repicks Config
AutoCreation on/off
Improved Category Setup
Do/ForceRandom improved
1.8a) Teamviewer Bugfix, Added ShowButton
1.8)
added requirement playerstate
Improved Req Tooltip
Added config Options
1.7)
Add Repick Button
Add Teamviewer.Reset()
Add Teamviewer swap Feature
Add BanDoneButton
TocPath in the setup section.

1.6a) compatible with TasFrameLoader
1.6)
Added TeamViewer Scale
HeroInfo can display Skills.
(Lua)
Various Bugfixes
function HeroSelector.unitCreated takes now the unitCode as arg instead and has to create the unit.
Can now Prevent options from being Randomed (HeroSelector.UnitDataPool[unitCode] = false)
added function HeroSelector.clearUnitData() to clear current UnitData making it easy to fill it with new data.
Added a GUI Real-Variable-Event for the default unitPicked function in which last created unit is the picked unit
1.5c)
Lua: Fixed a nil Pointer when categories were added after the box was already created: using function HeroSelector.addCategory(icon, text)​
1.5b)
Changed Fdf
Added visual Feedback while pushing Hero/Category Buttons
Bann/Random/Accept Button play a clicked sound.[/INDENT]

1.5)
Improved Teamviewer and added a non Teambased one
Improved Tooltips
Disabled Options show the reason (out of stock / not allowed / requirment)
HeroSelector box border became smaller and a seperator was added
Title Text is limited to the HeroSelector box
Banning can now ignore Requirments (on default enable)
The vJass version allowed to select Heroes which were above the Team limit after HeroSelectorUpdate was called[/INDENT]
Requires a new fdf[/INDENT]
1.4)
Supports TechCode Level as req
GUI can setup manual category mods.
Skips example code in InitHeroes right after the GUI Loader[/INDENT]
1.3b) Various fixes for the demo map Triggers
1.3a) Teamviewer showed non-Allies, when one didn't wanted that.
1.3) Autodetects Primary Attribute of heroes, can be disabled
1.2.1 only vJass) Seperated the Action functions from the main Code, the functions are now evoked by a real Event System.
1.2)
RandomButton can now select, if wanted.
Added Category
Increased BorderSize HUMAN, ORC
Some Bugfixes
TeamViewer the TextFrame Button posing was replaced with a Left2Right boolean[/INDENT]
1.1)
Heroes can now have requirements
Replaced how Random works internally.
Added Settings for Random and Accept Button
The HeroButtons can now be created without being bound together.
Renamed: enablePicking, DelayBannUntilPicking
Teamviewer and HeroInfo overlap now HeroSelector.destroy
bug fixes.​
Contents

HeroSelector (Map)

HeroSelector Jass (Map)

Level 18
Joined
Oct 17, 2012
Messages
818
Can one have a unique selection pool per player with this system?

Any plans to add this feature to the system? Is it too much work or just you never intended it to be part of this system?
 
Last edited:

Can one have a unique selection pool per player with this system?
Yes and no.
No, in that is not built in directly.
Yes, with some actions one could mimic that, I think.
Hence, I worte "directly".
What I say now might work or might not, never tested it.

Option 1: You add all heroes into the pool. After the box creation run, hide all Buttons based on wanted Settings (the buttons and the hero index are the same), reason this works is a Player can not press hidden Buttons but still get click Events of other Players. Through you would also have to update the randompools, each Team has an own randompool when an hero is repicked it is readded to all randompools. This option would have the sideeffect that the box becomes bigger and shows alot of empty space, but should have the wanted effect. This Option requires you to know how to use GetLocalPlayer() to hide the Buttons based on the Player values, but you should not change the randompools in a GetLocalPlayer way, that would desync probably as soon that Player presses random. You might also Change the size of the box and the positions of the Buttons. But that requires some skill.

Code:
HeroSelector.HeroButtons[buttonIndex].Frame
HeroSelector.UnitData.Pool[teamNr]

Option 2:
When Players are Picking in turns one could empty and refill the heropool before the Picking including the randompools after that one would call HeroSelector.update() which will update the icons.
Through I did not test that, only thinkered about it, it might also break limited picking.

Option 3: You add fake heroes that Morph when being picked, would still be pickable for all Players, but the Morphing could differ based on the picking Player. To Morph the picked unit you have to overlap or Change the Content of "function HeroSelector.unitCreated(player, unit, isRandom)". This Option could be extened by altering the shown Infos in HeroInfo/Teamviewer and overwritting the Textures on and off Icons of the HeroButtons. The Textures won't Change itself after creation when not calling the update function which reloads the textures based on the connected Hero.
Lua:
--one can get the used buttonIndex of the unitCode as number with
local buttonIndex = HeroSelector.UnitData[unitCode].Index

BlzFrameSetTexture(HeroSelector.HeroButtons[buttonIndex].Icon, BlzGetAbilityIcon(unitCode), 0, HeroSelector.ButtonBlendAll)
BlzFrameSetTexture(HeroSelector.HeroButtons[buttonIndex].IconDisabled, HeroSelector.getDisabledIcon(BlzGetAbilityIcon(unitCode)), 0, HeroSelector.ButtonBlendAll)
Any plans to add this feature to the system? Is it too much work or just you never intended it to be part of this system?
I though about that feature. Would have to swap from a Team wise data layout to a Player wise.
 
Last edited:
Uploaded HeroSelector V1.1.
It brings requirements. Requirements can be given when adding an Hero or afterwards. In a game having a ban Phase, I advise to add the requirement after the ban Phase is over. Otherwise one can ban only own heroes.

One can now choose that Buttons in the grid are not connected to the previous button/row allowing to move them around without moving other Buttons.

The Accept and Random Button gained more Settings.
 
With Box you mean the Background of HeroSelector?
Then: HeroSelector uses on Default the BACKDROP "EscMenuBackdrop" as Background/Box. To create it on uses
JASS:
local framehandle box = BlzCreateFrame(HeroSelector.BoxFrameName, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
call BlzFrameSetAbsPoint(box, FRAMEPOINT_CENTER, 0.4, 0.3)

If you mean HeroSelector:
Then it should Show itself on Default with the setting
HeroSelector.AutoShow = true
otherwise you have to call
HeroSelector.show(true)
 
Level 1
Joined
Nov 1, 2013
Messages
8
How to Install:

You map has to be in Lua-Mode.
Export and Import
war3mapImported\HeroSelector.fdf
war3mapImported\HeroSelector.toc
war3mapImported\HeroSelectorBan.mdx
Copy the trigger Folder "HeroSelector" into your map.

I tested the map and the selector is really awesome, but i tried the method you teached to import and doesn't works, i tested the import in 3 diferent maps, without any alteration in the units or the triggers, i used the jass map version, i don't know whats happening maybe is some kind of unrecognized variable, (i tried test with a map without any another trigger, so the possibility of being a conflict is descosiderable), any suggest of what a should do?
 
Level 1
Joined
Nov 1, 2013
Messages
8
Nothing, normaly the helper send a syntax error and block the inicialization, but in this case he just start the game as normal, but the box is just with the category icons
 
Last edited:
Level 12
Joined
Feb 11, 2008
Messages
809
hi im using the LUA version of this system and ive just been playing around making adjustments and ran across a few very weird things first off,

JASS:
function HeroSelector.autoDetectCategory(unitCode)
    if IsUnitIdType(unitCode, UNIT_TYPE_MELEE_ATTACKER) then
        HeroSelector.UnitData[unitCode].Category = 1
    elseif IsUnitIdType(unitCode, UNIT_TYPE_RANGED_ATTACKER) then
        HeroSelector.UnitData[unitCode].Category = 2
    elseif IsUnitIdType(unitCode, UNIT_IF_STRENGTH) then
        HeroSelector.UnitData[unitCode].Category = 4
        print("STR HERO")
    elseif IsUnitIdType(unitCode, UNIT_IF_AGILITY) then
        HeroSelector.UnitData[unitCode].Category = 8
        print("AGI HERO")
    elseif IsUnitIdType(unitCode, UNIT_IF_INTELLIGENCE) then
        HeroSelector.UnitData[unitCode].Category = 16
        print("INT HERO")
    end
end

does not work as if WC3 cannot detect what the heroes main attributes are yet or maybe im doing something wrong.

Second thing is weird also why are all of these capitalized and then 'Ranged' is not and yet if you capitalize it in game the others are not.

JASS:
table.insert(HeroSelector.Category, {"ReplaceableTextures\\CommandButtons\\BTNSteelMelee", "MELEE"})                 --1, automatic detected when adding an unit
table.insert(HeroSelector.Category, {"ReplaceableTextures\\CommandButtons\\BTNHumanMissileUpOne", "Ranged"})         --2, automatic detected when adding an unit
table.insert(HeroSelector.Category, {"ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower", "STRENGTH"})    --4
table.insert(HeroSelector.Category, {"ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility", "AGILITY"})        --8
table.insert(HeroSelector.Category, {"ReplaceableTextures\\CommandButtons\\BTNMantleOfIntelligence", "INTELLECT"})   --16

and also are you able to set the title text for each individual player instead of everyone at once? if that not would be a great feature.
 
does not work as if WC3 cannot detect what the heroes main attributes are yet or maybe im doing something wrong.
That UNIT_IF is for BlzGetUnitIntegerField. I also don't know of any direct way to get the primary attribute from an unitcode. There is the wayaround: create an unit, read the UnitIntegerField and kill it again. I could built that in.

UNIT_IF_PRIMARY_ATTRIBUTE should be used to get the primary attribute.


Second thing is weird also why are all of these capitalized and then 'Ranged' is not and yet if you capitalize it in game the others are not.
HeroSelector tries to read a localized String (so each player has texts in his language), Blizzards localized Strings are UpperCase only, but there is no RANGED. Hence i just wrote the english "Ranged".

and also are you able to set the title text for each individual player instead of everyone at once? if that not would be a great feature.
Yes, that is built in. function HeroSelector.setTitleText(text[, who]). who can be a player, a force, a teamNumber, a race or nothing = anyone
 
Level 12
Joined
Feb 11, 2008
Messages
809
Yea being able to auto-detect all the categories would be a great addition, also thanks for the information ive always used GUI and some simple JASS but never really any coding such as LUA and im really enjoying it so far.

1 more thing in the example map whenever you choose a hero each game its spawning me at a different players starting area instead of my specific starting area and i can see that this is the section that should be moving the unit to mine

JASS:
SetUnitPosition(unit, GetPlayerStartLocationX(player), GetPlayerStartLocationY(player))

but for some reason it is not returning the correct player each time
 
Updated to version 1.3.0. Added the option to autodetect the primary Hero Attribute: Str, Agi or Int as category, on default enabled. That is achived by creating the hero for neutral extra and using BlzGetUnitIntegerField, then the unit is removed again. That probably will also preload object editor added stuff and models of that heroes when enabled.

HeroSelector.CategoryAutoDetectHero = true

private boolean CategoryAutoDetectHero = true

1 more thing in the example map whenever you choose a hero each game its spawning me at a different players starting area instead of my specific starting area and i can see that this is the section that should be moving the unit to mine



but for some reason it is not returning the correct player each time
Is your Circle at the same spot as your hero is created or is it not the spot set in editor?
When it is not the spot set in Editor forcing fixed starting positions should fix that. Otherwise I did something wrong.
 
Last edited:
Level 12
Joined
Feb 11, 2008
Messages
809
The circle of power is spawning in the same area as the hero but it is at a different players start location each time, how would i check to see if the players have fixed starting positions?, and btw i just using your example map so should be the same as what your seeing.

also nice update man that was fast thanks again for this system.
 
Level 12
Joined
Feb 11, 2008
Messages
809
Found some glitches with Team Viewer plug-in

1. if you set it to false the computer players name is still visible
2. the position of the names/icons are then moved above your accept button instead of staying on the top left

EDIT*

also having issues importing it, everything seems to be functioning except the hero icons are not displaying and i have all the imported models plus i just copy and paste your entire folder with the hero selection, heres screenshots.

Screenshots | HIVE

EDIT2*

also i wanted to show i have units added via this code

JASS:
    HeroSelector.addUnit('Hpal') --add paladin as selectable Hero
    HeroSelector.addUnit('Hamg')
    HeroSelector.addUnit('Hblm')
    HeroSelector.addUnit('Hmkg')
    HeroSelector.addUnit("Obla")
    HeroSelector.addUnit("Ofar")
    HeroSelector.addUnit("Otch")
    --HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    --HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    HeroSelector.addUnit("Oshd")
    HeroSelector.addUnit("Edem")
    --HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    --HeroSelector.addUnit() --this is an empty box. It still takes a slot.
    HeroSelector.addUnit("Ekee")
    HeroSelector.addUnit("Emoo")
    HeroSelector.addUnit("Ewar")
    HeroSelector.addUnit("Udea")
    HeroSelector.addUnit("Ulic")
    HeroSelector.addUnit("Udre")
    HeroSelector.addUnit("Ucrl")

it works on the example map with that code but once i import it into my map it no longer shows hero icons even though they are the same default hero codes.
 
Last edited:
Found some glitches with Team Viewer plug-in

1. if you set it to false the computer players name is still visible
2. the position of the names/icons are then moved above your accept button instead of staying on the top left
Thanks for reporting that bug.

EDIT2*

also i wanted to show i have units added via this code



it works on the example map with that code but once i import it into my map it no longer shows hero icons even though they are the same default hero codes.
Lua Only:
Do you have the GUI arrays in your map and did not use them at all? If they exist HeroSelector fills all button positions with their values, so all shown fields are empty seperators. If you not want the GUI part just remove the whole GUI folder with its variables or remove the lines reading that arrays. Then HeroSelector skips reading the GUI array.
 
Level 12
Joined
Feb 11, 2008
Messages
809
Thanks for reporting that bug.


Lua Only:
Do you have the GUI arrays in your map and did not use them at all? If they exist HeroSelector fills all button positions with their values, so all shown fields are empty seperators. If you not want the GUI part just remove the whole GUI folder with its variables or remove the lines reading that arrays. Then HeroSelector skips reading the GUI array.

yea i didnt even copy the gui folder over and like i said everything i have done i also done the same way on the example map before attempting to import and it worked perfectly fine also noticed that when i exported and then re-imported the files they seemed to change size not sure if that has anything to do with it

Code:
LUA Start
    Events
        Time - Elapsed game time is 0.10 seconds
    Conditions
    Actions
        Custom script:   MapSetup()

this is only GUI in the entire map lol

EDIT*

thanks for the help btw i know its annoying at times but ive tried to figure this one out and cant seem to track down whats causing it to fail when exporting/importing since everything works great before i switch maps.
 
Last edited:
Updated to 1.3a Teamviewer should be fixed. The wrong position was not a bug. That was just bad default setup for the Lua version when enemies are hidden.
yea i didnt even copy the gui folder over and like i said everything i have done i also done the same way on the example map before attempting to import and it worked perfectly fine also noticed that when i exported and then re-imported the files they seemed to change size not sure if that has anything to do with it
There is an folder named GUI inside the HeroSelector system. Do you have that in your map? If yes remove it with the GUI variables.
 
Level 12
Joined
Feb 11, 2008
Messages
809
Updated to 1.3a Teamviewer should be fixed. The wrong position was not a bug. That was just bad default setup for the Lua version when enemies are hidden.

There is an folder named GUI inside the HeroSelector system. Do you have that in your map? If yes remove it with the GUI variables.

Heres 2 maps, the first one is my custom map that the icons are not displaying on and the second one is your example map with my exact same code except its working great, from looking at the hero defense map can you see what is causing it to not display?

Maps | HIVE
 
Level 12
Joined
Feb 11, 2008
Messages
809
For some wierd reasons in your map: the toc and fdf files swaped content. That breaks all custom Frames HeroSelector defines.
The fdf should contain the frame definitions and the toc should be a batch to load fdf files.

that is what i was talking about and all i did was export them and import them into the new map, i figured thats what was causing the issue but still cannot figure out why its changing them

EDIT*

i just tried exporting again and as soon as it exports into the folder the files have changed its such a weird bug

EDIT2*

FOUND THE ISSUE : when exporting all files at once the editor is glitching and removing file properties but when you export them 1 at a time then import 1 at a time this issue does not occur!

might want to put a warning about this in your post seems like exporting all at once is breaking the files for whatever reason.
 
Last edited:
Level 12
Joined
Feb 11, 2008
Messages
809
Still some really weird stuff going on this team viewer i just filled all the slots with some enemy computers and 2 teammate computers and overlapping is still happening plus it doesn't seem to be displaying correctly.

EDIT*

and also for some reason when using an actual player as player 2 set on the same team is not displaying at all when team viewer show non-allies is set to false.

EDIT2*

overlooked that you had stated it was only set up for 2 teams so that solves the overlapping of the computer names so sorry i missed that

but still is glitching when trying to display a real player on team 1 with you choosing heros

also the hero info plugin's extended tooltip display on the right of the icons is not displaying for player 2 when they are a real player they can select the icons and choose a hero just fine but none of the description is displaying.
 

Attachments

  • WC3ScrnShot_122019_210304_01.png
    WC3ScrnShot_122019_210304_01.png
    2.3 MB · Views: 211
Last edited:
You would either modify
function HeroSelectorUnitCreated inside "HeroSelectorAction" to create your starting units based on unit u.
Or use real Event udg_HeroSelectorEvent == 1.0 (HeroSelector Lua does not provide this event)
udg_HeroSelectorEventPlayer
udg_HeroSelectorEventUnit
udg_HeroSelectorEventIsRandom

or create unit enter map events checking for the entering hero.

For the starting units you might reuse something from Blizzard.j
function MeleeStartingUnitsForPlayer takes race whichRace, player whichPlayer, location loc, boolean doHeroes

You can find Blizzard.j in "Documents\Warcraft III\JassHelper" when you have saved/validated a map with world editor at least once with jasshelper enabled.
 
Level 9
Joined
Aug 16, 2019
Messages
66
You would either modify
function HeroSelectorUnitCreated inside "HeroSelectorAction" to create your starting units based on unit u.
Or use real Event udg_HeroSelectorEvent == 1.0 (HeroSelector Lua does not provide this event)
udg_HeroSelectorEventPlayer
udg_HeroSelectorEventUnit
udg_HeroSelectorEventIsRandom

or create unit enter map events checking for the entering hero.

For the starting units you might reuse something from Blizzard.j
function MeleeStartingUnitsForPlayer takes race whichRace, player whichPlayer, location loc, boolean doHeroes

You can find Blizzard.j in "Documents\Warcraft III\JassHelper" when you have saved/validated a map with world editor at least once with jasshelper enabled.
Thank you so much for helping me!
 
Level 9
Joined
Aug 16, 2019
Messages
66
I apologize in advance for bad English
Feedback:
This experience allowed me to make a convenient choice of a non-standard race (in the screenshot (russian) there is one race - Grommash Hellscream [Chieftain of the Warsong Clan]) for my Altered Melee - WarCraft Legends (russian). The additional information (on the right) shows the quote of the hero, as well as the advantages and disadvantages of this race. It looks much more presentable than the choice through the "tavern".
The operating time is very flexible and easily customizable even with poor knowledge of jass functions.

Also in the left corner you can see the operating time "Talents" of the same author.
 

Attachments

  • SelectHero.jpg
    SelectHero.jpg
    178.4 KB · Views: 156
Level 12
Joined
May 16, 2020
Messages
660
Hi Tasyen, I experience some issues with the test map, and there are different issues in both:
  • In the JASS folder version, the window stays open for a few seconds after banning and picking
  • In the "normal" folder version, -ar does nothing
  • In the "normal" folder version, there is no banning phase
  • In both versions -close, -open does nothing
Not sure if I missed something, but really great system from what I saw.
 
Ty for your feedback.
I updated it to 1.3b, updates to the demo triggers.
Close & Show also now need a - infront to be typed in as first letter, further all 6 players in the demo map can use it.
After the picking Phase is over Trigger-Repick is disabled. (Can't pick anymore at that point, hence no repick should be allowed)
In the Lua version increased ban Phase from 0.75s to ~16s.

The demo triggers are quite simple, I haven't added any action in the demo that hides HeroSelector for the picking player. It is "hidden" by its destruction when the Picking Phase is over.
In the Jass version one would add such hiding in HeroSelectorAction function HeroSelectorUnitCreated. You could copy paste the custom line from the Close Trigger when you want that.

You were player red when you tried -ar, only he can use it?
 
Level 12
Joined
May 16, 2020
Messages
660
Thank you! And yes I was player red when chosing -ar, but seems it works in the newest version.

A few more questions though, since I'd love to use this system for my map:
  1. Are all units within "HeroSelectorUnitCode[x]" preloaded? At least that's my guess why there is a delay at the start of the game. I have like 60 heroes in my map...
  2. Why are Demon Hunter, Keeper of the Grove and Priestess of the Moon disabled in the testmap? I didn't find anything that would cause this (I know only GUI though)
  3. In ban/picking phase: Why run every 0.75 instead of 1 second? Is there something wrong with the internal clock?
  4. When clicking the "random" button: Can I make the system automatically pick a hero (and not just choose it)?
  5. When clicking the "accept" button: Is it possible to delay the hero creation until the "picking" phase is over? So essentially picking fast does not have any advantage, since all heroes get created at the same time as soon as the last player picks his hero
And fully support the Item Shop idea :)
 
  1. All added Heroes are created to autocalc the categories. You can stop that by changing a boolean in the Config of HeroSelector.
    • private boolean CategoryAutoDetectHero = true // Will create and remove added Heroes to read and setup the Category for the primary Attribute Str(4) Agi(8) Int(16)
    • -> private boolean CategoryAutoDetectHero = false
  2. They use Requirments set with HeroSelectorSetUnitReqRace in HeroSelectorAction public function InitHeroes. In the Demo map Nightelf and Human Heroes can only be picked by Plaers of their Races.
  3. I personly find 0.75s more fluid, one can just change that if one doesn't like that.
  4. You have to change a value in the config in HeroSelector: private boolean RandomButtonPick = true
  5. That feature was not added. You would have to hide/Pause/Stun the Hero when it is picked until Picking Phase is finished.
You find the Config in the globals block of HeroSelector which is found at the top after the API (the outcommented function Heads.
 
Level 12
Joined
May 16, 2020
Messages
660
Thank you - managed to get it to work :)

As feared though, the preload time with CategoryAutoDetectHero = true is quite long for me. So:
  • Could I somehow hook into the system and define myself (manually) if HeroSelectorUnitCode[1] = Strength, HeroSelectorUnitCode[2] = Intelligence etc.? If not, can I hide the 3 symbols at the top?
  • Out of interest: Why can the game quickly recognize what is "range" and "melee" (this creates zero preload lag for me), but not what is the attribute?

Some more questions which popped up when implementing the system:
  • Can I adjust the font within the right box (where the story, stats etc are)? I see that I can change the TextAreaSizeX/Y, but didn't find anything related to font size.
  • What is the criteria for the icons to go "disabled"? These 3 icons have a BTN and DISBTN icon, but when using it in the system it doesn't work:
  • 1.png
 
Could I somehow hook into the system and define myself (manually) if HeroSelectorUnitCode[1] = Strength, HeroSelectorUnitCode[2] = Intelligence etc.? If not, can I hide the 3 symbols at the top?
The system allows to add/remove categories, hence on can also add categories to heroes. This can only be done in code though. After the heroes were added, use call HeroSelectorAddUnitCategory(integer unitCode, integer category) for example call HeroSelectorAddUnitCategory('Hpal', 4) adds the Str category to paladin. The 4 is a power 2 number, the 2^categoryIndex, might change if you add/remove/reorder them.
If you want to add remove categories you have to remove/add call HeroSelectorAddCategory lines
It is intended to do such things in public function InitHeroes of
HeroSelectorAction.
  • Out of interest: Why can the game quickly recognize what is "range" and "melee" (this creates zero preload lag for me), but not what is the attribute?
Ranged/Melee can be read without creating an unit, using only the unitCode. It uses the functionality which can be found in GUI boolean comparison - Unit - UnitType Class check. Unlike detect Primary attribute that creates the hero and reads the primaray attribute unit field, I haven't found a better way for that.

Can I adjust the font within the right box (where the story, stats etc are)? I see that I can change the TextAreaSizeX/Y, but didn't find anything related to font size.
The code to change Font during game does not work for that type of Text Box. Therefore it can only be changed inside the imported fdf. It is
Frame "TEXTAREA" "HeroSelectorTextArea" in which one would change the number in FrameFont "InfoPanelTextFont", 0.011, "", to choose a different Text-Size.

What is the criteria for the icons to go "disabled"? These 3 icons have a BTN and DISBTN icon, but when using it in the system it doesn't work:
When a category is added one image path is given. This path is used as enabled version out of the enabled version it should autofind the disabled version. The autofinder requires that the 34/35 char is "\". If it fails you either have to change the image path or set the paths yourself. The manual setting has to be done after the category was added.
JASS:
set HeroSelector_CategoryTextureDisabled[index] = iconPath. //index starts with 1.
set HeroSelector_CategoryTextureDisabled[4] = "ReplaceableTextures\\CommandButtons\\BTNInvisibility" // would change the agi disabled Icon to the invis ability icon
set HeroSelector_CategoryTexture[3] = "ReplaceableTextures\\CommandButtons\\BTNFootman" // changes the str enabled icon to Footman icon
 
Level 10
Joined
May 16, 2013
Messages
229
This is really cool but I have a question.
1) Can we add tech requirement for heroes? I saw we can add 4 type of requirements right now. Tech requirements would be really useful.
2) Is function HeroSelectorEnablePickPlayer really works? I tried everything but still players can pick. I'm calling HeroSelectorEnablePickPlayer(false, Player(1)) and I can still pick.
3)Also how can I hide specific players from teamviewer?
 
Last edited:
2) Is function HeroSelectorEnablePickPlayer really works? I tried everything but still players can pick. I'm calling HeroSelectorEnablePickPlayer(false, Player(1)) and I can still pick.
It disables the random and pick button. Player(1) is Blue. You were Blue?
1) Can we add tech requirement for heroes? I saw we can add 4 type of requirements right now. Tech requirements would be really useful.
Techs as req are not supported. Only TeamNr, Player, Race, Force. Kinda created with rpg/moba like in mind in which tech req didn't make much sense, at least I thought so when this was created.
On a short look, It wouldn't be so difficult to add it.
3)Also how can I hide specific players from teamviewer?
The default one can be setuped to show only allies and some pos stuff. One would have to modify Teamviewer or write a custom one to do more.
 
Level 12
Joined
May 16, 2020
Messages
660
The system allows to add/remove categories, hence on can also add categories to heroes. This can only be done in code though. After the heroes were added, use
call HeroSelectorAddUnitCategory(integer unitCode, integer category)
for example
call HeroSelectorAddUnitCategory('Hpal', 4)
adds the Str category to paladin. The 4 is a power 2 number, the 2^categoryIndex, might change if you add/remove/reorder them.
If you want to add remove categories you have to remove/add
call HeroSelectorAddCategory
lines
It is intended to do such things in public function InitHeroes of
HeroSelectorAction.

Mmm maybe I'm doing something wrong. First, I disabled the autodetect:
JASS:
private boolean CategoryAutoDetectHero = false

Then I added the unit ID for a strength unit into a custom script:
2.png


1.png


But in-game, filtering on "Strength" doesn't do anything.

Therefore it can only be changed inside the imported fdf.
What program do you use to open fdf files?


The rest worked - thanks a lot :)
 
Level 10
Joined
May 16, 2013
Messages
229
It disables the random and pick button. Player(1) is Blue. You were Blue?

Techs as req are not supported. Only TeamNr, Player, Race, Force. Kinda created with rpg/moba like in mind in which tech req didn't make much sense, at least I thought so when this was created.
On a short look, It wouldn't be so difficult to add it.

The default one can be setuped to show only allies and some pos stuff. One would have to modify Teamviewer or write a custom one to do more.

Sorry my bad for the first one I guess, well I'm working on something else and tech requirement would be awesome for me. I think it will be cool as another feature.
 
But in-game, filtering on "Strength" doesn't do anything.
That GUI trigger happens before the heroes are added to HeroSelector. It only prepares data. But the manual category modification can only happen after the heroes were added to HeroSelector. I probably add an integer array to GUI to add categories to heroes the same way one can set the heroes.
What program do you use to open fdf files?
Any Texteditor can do that. I use vscode or notepad++.

Edit: Update 1.4)
Supports TechCode Level as req. (Beaware that Heroselector does not update automatically. When after a tech was researched or an unit was trained/killed one has to force an update with an
HeroSelector.update()/HeroSelectorUpdate()
)
GUI can add manual categories (for the Heroes) with an GUI integer array next to the normal Hero setup.
added a return to skip example code in InitHeroes right after the GUI Loader.
 
Last edited:
Updated to 1.5) contains a new fdf.
Teamviewer
Player Face Tooltip Text showed the wrong text in some circumstances
Placed Players into boxes.
Player Names are not playerColored anymore. The playercolor is seen at the top of the box.
Added an Actionfunction when clicking the PlayerHeroButton
supports Playercolors not matching the playerIndex
Calls a function filtering unwanted players out.
Added an alternative Teamviewer without Team focus. (you should only enable one of them)​
Tooltip Texts are now in Boxes, new fdf.
The selected Indicator is now above the Buttons.
Selectable options when disabled shows the reason but only one (Not allowed / out of stock / Requirments).
Reduced the Border Size of the HeroSelectorBox by ~25%.
Added a seperator between the category Buttons and Hero Buttons.
Limited the Title Text to the space above the category Buttons, it supports upto 2 Lines and will not leave the box anymore.
The demo GUI Triggers now use 2 game Strings, instead of custom ones. You can still replace it with anything wanted.
Added a new Config HeroSelector.BanIgnoreRequirment, on default true. When enabled it allows to Ban Selections one does not fullfill the requirments for.
Fixed a Bug in the jass version, HeroSelectorUpdate did not respect the teams pick limit
Lua)
Replaced the self execution by Timer with hooking into MarkGameStarted
Heroselector calls Teamviewer and Heroinfo instead of them executing themself
 
Level 12
Joined
May 16, 2020
Messages
660
Since update 1.5 for some reason I cannot make it work when importing to my map.

I can tell that in the background the code is running (delay because the "switch" to pre-load is set to true), but no windows appear to select anything. Is there any change that would cause this?
 
Level 12
Joined
May 16, 2020
Messages
660
Ahh ok thanks - now it worked.

I'm also trying to re-align the windows with HeroInfo and TeamViewer... but not very successful:

WC3-Scrn-Shot-092620-142015-001.png


Ideally I want the following set-up:
  • Main window in the middle (where is this setting?)
  • HeroInfo window directly at the bottom of the main window (I tried BOTTOMMIDDLE, this should be possible as shown here)
  • TeamViewer windows to be a lot more left / right, as they limit the main window space (I tried TeamPosX[0] = 0.00, but then the window disappears for some reason)
Also, is it possible to change Player 1 (red) and Player 7 (green)'s icon to a custom image, not a questionmark? Or better yet: To remove their image completely and just leave the "name" of these players as title for the teams. These are computer players and so they will never pick.
 

warcraft-3-coord-system-3-jpg.359576

coords-image-56-jpg.325821


Main window in the middle (where is this setting?)
The pos of HeroSelector is set in Heroselector globals
private real BoxPosX = 0.3
private real BoxPosY = 0.4
private framepointtype BoxPosPoint = FRAMEPOINT_CENTER

HeroInfo window directly at the bottom of the main window (I tried BOTTOMMIDDLE, this should be possible as shown here)
private framepointtype TextAreaPoint = FRAMEPOINT_TOPRIGHT //pos the Tooltip with which Point
private framepointtype TextAreaRelativePoint = FRAMEPOINT_BOTTOMRIGHT //pos the Tooltip to which Point of the Relative


TeamViewer windows to be a lot more left / right, as they limit the main window space (I tried TeamPosX[0] = 0.00, but then the window disappears for some reason)
You have to change a line in Teamviewer inside function TeamViewerInit:

set playerParentFrame[playerIndex] = BlzCreateFrame("HeroSelectorTextBox", HeroSelectorBox, 0, createContext)
->
set playerParentFrame[playerIndex] = BlzCreateFrame("HeroSelectorTextBox", BlzGetFrameByName("ConsoleUIBackdrop", 0), 0, createContext)

That change allows them to be placed further left and right, also allows them to exist without HeroSelector.
(BlzGetFrameByName("ConsoleUIBackdrop", 0) is reforged only)


You could prevent Red and Green from taking a Teamviewer slot. That is done in TeamViewer private function AllowPlayer.
JASS:
// (true) allows includes the player in TeamViewer
private function AllowPlayer takes player p returns boolean
    if p == Player(0) then
        return false
    endif
    if p == Player(6) then
        return false
    endif
    return GetPlayerSlotState(p) ==  PLAYER_SLOT_STATE_PLAYING
endfunction
If you want to keep them one could do some frame calls to make the Icon be hidden. One would add that at the end of function TeamViewerInit.
call BlzFrameSetVisible(playerFaceButton[0], false)
call BlzFrameSetVisible(playerFaceButton[6], false)
 
Top