1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Fill your cup and take your pick among the maps best suited for this year's Hive Cup. The 6th Melee Mapping Contest Poll is up!
    Dismiss Notice
  5. Shoot to thrill, play to kill. Sate your hunger with the 33rd Modeling Contest!
    Dismiss Notice
  6. Do you hear boss music? It's the 17th Mini Mapping Contest!
    Dismiss Notice
  7. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

HeroSelector

Submitted by Tasyen
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", 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 or a Race. 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.

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 (Text):

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.
Code (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:


HeroSelector

Code (Lua):

--[[
HeroSelector V1.5

------
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.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}, skip who or nil will remove an requirment.
    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])
    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)
    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)
    Keeps previous setings untouched

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

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])
function HeroSelector.setTitleText(text[, who])
function HeroSelector.setBanButtonText(text[, who])
function HeroSelector.setAcceptButtonText(text[, who])

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.destroy()
    destroys and nil HeroSelector

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

function HeroSelector.showFrame(frame, flag[, who])
function HeroSelector.includesPlayer(who, player)
function HeroSelector.disableButtonIndex(buttonIndex[, teamNr])
function HeroSelector.enableButtonIndex(unitCode, buttonIndex[, teamNr])
function HeroSelector.counterChangeUnitCode(unitCode, add, player)
function HeroSelector.frameLoseFocus(frame)
function HeroSelector.rollOption(player, includeRandomOnly, exculdedIndex, category)
--]]

HeroSelector = {}

--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
--Unique Picks
HeroSelector.UnitCount              = 2 --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"
--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.Category = {
    --Icon path, tooltip Text (tries to localize)
    {"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.CategoryAutoDetectHero = true  -- Will 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"
--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.13
HeroSelector.BanButtonSizeY         = 0.03
HeroSelector.BanTooltip             = "DISALLOWED"
HeroSelector.BanIgnoreRequirment    = true -- (true) Ban is not restricted by Requirments
--Accept Button
HeroSelector.AcceptButtonTextPrefix = ""
HeroSelector.AcceptButtonText       = "ACCEPT"
HeroSelector.AcceptButtonSizeX      = 0.085
HeroSelector.AcceptButtonSizeY      = 0.03
HeroSelector.AcceptButtonIsShown    = true
HeroSelector.AcceptButtonAnchor     = FRAMEPOINT_BOTTOMRIGHT --places the Accept button with which Point to the bottom, with right he is at the left
--Random Button
HeroSelector.RandomButtonTextPrefix = ""
HeroSelector.RandomButtonText       = "RANDOM" --tries Localizing
HeroSelector.RandomButtonSizeX      = 0.085
HeroSelector.RandomButtonSizeY      = 0.03
HeroSelector.RandomButtonIsShown    = true
HeroSelector.RandomButtonAnchor     = FRAMEPOINT_BOTTOMLEFT
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.
--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"

--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.Category
    HeroSelector.Category = {}
    for index, value in ipairs(categories)
    do
       HeroSelector.addCategory(value[1], value[2])
    end

    --read GUI, when the variable exist
    if 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[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.

    --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.
    --human only work for human, as nightelf only for Nightelf
    HeroSelector.setUnitReq('Hpal', RACE_HUMAN)
    HeroSelector.setUnitReq('Hamg', RACE_HUMAN)
    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() --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",true)
    HeroSelector.addUnit("Udea")
    HeroSelector.addUnit("Ulic")
    HeroSelector.addUnit("Udre")
    HeroSelector.addUnit("Ucrl",1)
    --]]

end

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
    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

--what happens to the unit beeing picked, player is the one having pressed the button
function HeroSelector.unitCreated(player, unit, isRandom)
    bj_lastCreatedUnit = unit
    if isRandom then
        --randomed
    else
        --picked
    end

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

    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
    --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)
    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.show(true, player)
    HeroSelector.enablePick(true, player)
    RemoveUnit(unit)
end
 

HeroSelector Jass API

Code (vJASS):

library HeroSelector
//HeroSelector V1.5
//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
        //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
        private integer UnitCount              = 2 //each hero is in total allowed to be picked this amount of times (includes random, repicking allows a hero again).
        private 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"
        //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.13
        private real BanButtonSizeY            = 0.03
        private string BanTooltip              = "DISALLOWED"
        private boolean BanIgnoreRequirment    = true // (true) Ban is not restricted by Requirments
        //Accept Button
        private string AcceptButtonTextPrefix       = ""
        private string AcceptButtonText             = "ACCEPT"
        private real AcceptButtonSizeX              = 0.085
        private real AcceptButtonSizeY              = 0.03
        private boolean AcceptButtonIsShown         = true
        private framepointtype AcceptButtonAnchor   = FRAMEPOINT_BOTTOMRIGHT //places the Accept button with which Point to the bottom, with right he is at the left
        //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 framepointtype RandomButtonAnchor   = FRAMEPOINT_BOTTOMLEFT
        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.
        //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
        private trigger CategoryClickTrigger   = CreateTrigger()
        private trigger AcceptButtonTrigger  = CreateTrigger()
        private trigger BanButtonTrigger      = CreateTrigger()
        private trigger RandomButtonTrigger  = CreateTrigger()
        private framehandle BanButton
        private framehandle AcceptButton
        private framehandle RandomButton
        private player array DelayBanPlayer
        private integer array DelayBanUnitCode
        private integer DelayBanCount = 0
        public framehandle array CategoryButton
        public framehandle array CategoryIconFrame
        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 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
    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

library HeroSelectorAction initializer Init uses HeroSelector, TeamViewer, HeroInfo
//HeroSelectorAction V1.4.0
 

    //what happens to the unit beeing picked, player is the one having pressed the button
    function HeroSelectorUnitCreated takes nothing returns nothing
        local player p = udg_HeroSelectorEventPlayer
        local integer playerIndex = GetPlayerId(p)
        local unit u = udg_HeroSelectorEventUnit
        local boolean isRandom = udg_HeroSelectorEventIsRandom
        set bj_lastCreatedUnit = u
        if isRandom then
            //randomed
        else
            //picked
        endif

        call SetUnitPosition(u, GetPlayerStartLocationX(p), GetPlayerStartLocationY(p))

        if p == Player(1) then
               
        endif
        call TeamViewerUnitCreated(p, u, isRandom)
        call PanCameraToTimedForPlayer(p, GetUnitX(u), GetUnitY(u),0)
        call SelectUnitForPlayerSingle(u, p)
        call HeroSelectorEnablePickPlayer(false, p) //only one pick for this player

        set p = null
        set u = null
    endfunction

    //happens when the banButton is pressed, player is the one having pressed the button
    function HeroSelectorUnitBaned takes nothing returns nothing
        local player p = udg_HeroSelectorEventPlayer
        local integer playerIndex = GetPlayerId(p)
        local integer unitCode = udg_HeroSelectorEventUnitCode
        call HeroSelectorEnableBanPlayer(false, p) //only one ban

        set p = null
   
    endfunction

    function HeroSelectorButtonSelected takes nothing returns nothing
        //player who pressed the button
        //unitCode the unitCode selected
        //this is not picked.
        local player p = udg_HeroSelectorEventPlayer
        local integer playerIndex = GetPlayerId(p)
        local integer unitCode = udg_HeroSelectorEventUnitCode
        call HeroInfoButtonSelected(p, unitCode)
        call TeamViewerButtonSelected(p, unitCode)

        set p = null
    endfunction

    function HeroSelectorRepick takes unit u returns nothing
        local integer unitCode
        local player p = GetOwningPlayer(u)
        local integer playerIndex = GetPlayerId(p)
        call UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, u) //this is done to undo metamorph
        set unitCode = GetUnitTypeId(u)
        if unitCode == 0 then
            return
        endif

        call HeroSelectorCounterChangeUnitCode(unitCode, -1, p)

        call HeroSelectorShowPlayer(true, p)
        call HeroSelectorEnablePickPlayer(true, p)
        call TeamViewerRepick(u, p)
        call RemoveUnit(u)
    endfunction



//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
    public function InitHeroes takes nothing returns nothing
        //create categories setuped in config
        local integer index
        local integer categoryMelee = 1 //autodetected
        local integer categoryRanged = 2 //autodetected
        local integer categoryStr = 4
        local integer categoryAgi = 8
        local integer categoryInt = 16
        call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSteelMelee", "MELEE")                 //1, automatic detected when adding an unit
        call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNHumanMissileUpOne", "Ranged")         //2, automatic detected when adding an unit
        call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower", "STRENGTH")    //4
        call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility", "AGILITY")        //8
        call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNMantleOfIntelligence", "INTELLECT")   //16

        //read GUI, when the variable exist

        set index = 1
        //add from index 1 all random only heroes
        loop
            exitwhen udg_HeroSelectorRandomOnly[index] == 0
            call HeroSelectorAddUnit(udg_HeroSelectorRandomOnly[index], true)
            set index = index + 1
        endloop

        set index = 1
        //copy the setuped field
        loop
            exitwhen index > HeroSelector_HeroButtonCount
            call HeroSelectorAddUnit(udg_HeroSelectorUnitCode[index], false)
            if udg_HeroSelectorCategory[index] != 0 then
                call HeroSelectorAddUnitCategory(udg_HeroSelectorUnitCode[index], udg_HeroSelectorCategory[index])
            endif
            set index = index + 1
        endloop

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

        call HeroSelectorAddUnit('Hgam', true) //antonidas is an only random Hero that can only be randomed by team 0 (for users 1).
        call HeroSelectorAddUnit('Eevi', true) //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.
        //human only work for human, as nightelf only for Nightelf
        call HeroSelectorSetUnitReqRace('Hpal', RACE_HUMAN)
        call HeroSelectorSetUnitReqTechLevel('Hpal', 'hfoo', 4)
        call HeroSelectorSetUnitReqRace('Hamg', RACE_HUMAN)
        call HeroSelectorSetUnitReqRace('Hblm', RACE_HUMAN)
        call HeroSelectorSetUnitReqRace('Hmkg', RACE_HUMAN)
        //call HeroSelectorSetUnitReqRace('Ofar', RACE_ORC)
        //call HeroSelectorSetUnitReqRace('Oshd', RACE_ORC)
        //call HeroSelectorSetUnitReqRace('Otch', RACE_ORC)
        //call HeroSelectorSetUnitReqRace('Obla', RACE_ORC)
        call HeroSelectorSetUnitReqRace('Emoo', RACE_NIGHTELF)
        call HeroSelectorSetUnitReqRace('Edem', RACE_NIGHTELF)
        call HeroSelectorSetUnitReqRace('Ekee', RACE_NIGHTELF)
        call HeroSelectorSetUnitReqRace('Ewar', RACE_NIGHTELF)
        //call HeroSelectorSetUnitReqRace('Udea', RACE_UNDEAD)
        //call HeroSelectorSetUnitReqRace('Ulic', RACE_UNDEAD)
        //call HeroSelectorSetUnitReqRace('Udre', RACE_UNDEAD)
        //call HeroSelectorSetUnitReqRace('Ucrl', RACE_UNDEAD)
   
        call HeroSelectorAddUnitCategory('Hpal', categoryStr)
        call HeroSelectorAddUnitCategory('Hamg', categoryInt)
        call HeroSelectorAddUnitCategory('Hblm', categoryInt)
        call HeroSelectorAddUnitCategory('Hmkg', categoryStr)
        call HeroSelectorAddUnitCategory('Ofar', categoryInt)
        call HeroSelectorAddUnitCategory('Oshd', categoryAgi)
        call HeroSelectorAddUnitCategory('Otch', categoryStr)
        call HeroSelectorAddUnitCategory('Obla', categoryAgi)
        call HeroSelectorAddUnitCategory('Emoo', categoryAgi)
        call HeroSelectorAddUnitCategory('Edem', categoryAgi)
        call HeroSelectorAddUnitCategory('Ekee', categoryInt)
        call HeroSelectorAddUnitCategory('Ewar', categoryAgi)
        call HeroSelectorAddUnitCategory('Udea', categoryStr)
        call HeroSelectorAddUnitCategory('Ulic', categoryInt)
        call HeroSelectorAddUnitCategory('Udre', categoryStr)
        call HeroSelectorAddUnitCategory('Ucrl', categoryStr)

        call HeroSelectorSetUnitCategory('Hgam', categoryInt + categoryRanged)
        call HeroSelectorSetUnitCategory('Eevi', categoryAgi + categoryMelee)

   
        //call HeroSelectorAddUnit('Hpal', false) //add paladin as selectable Hero
        //call HeroSelectorAddUnit('Hamg', false)
        //call HeroSelectorAddUnit('Hblm', false)
        //call HeroSelectorAddUnit('Hmkg', false)
        //call HeroSelectorAddUnit('Obla', true) //this unit can only be randomed
        //call HeroSelectorAddUnit('Ofar', false)
        //call HeroSelectorAddUnit('Otch', true) //this unit can only be randomed
        //call HeroSelectorAddUnit(0,false) //this is an empty box. It still takes a slot.
        //call HeroSelectorAddUnit(0,false) //this is an empty box. It still takes a slot.
        //call HeroSelectorAddUnit('Oshd', false)
        //call HeroSelectorAddUnit('Edem', false)
        //call HeroSelectorAddUnit(0,false) //this is an empty box. It still takes a slot.
        //call HeroSelectorAddUnit(0,false) //this is an empty box. It still takes a slot.
        //call HeroSelectorAddUnit('Ekee', false)
        //call HeroSelectorAddUnit('Emoo', false)
        //call HeroSelectorAddUnit('Ewar', true)
        //call HeroSelectorAddUnit('Udea', false)
        //call HeroSelectorAddUnit('Ulic', false)
        //call HeroSelectorAddUnit('Udre', false)
        //call HeroSelectorAddUnit('Ucrl', true)

    endfunction

    private function Init takes nothing returns nothing
        local trigger trig
        set trig = CreateTrigger()
        call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 2.0 )
        call TriggerAddAction(trig, function HeroSelectorButtonSelected)

        set trig = CreateTrigger()
        call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 1.0 )
        call TriggerAddAction(trig, function HeroSelectorUnitCreated)

        set trig = CreateTrigger()
        call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 3.0 )
        call TriggerAddAction(trig, function HeroSelectorUnitBaned)
    endfunction
endlibrary
 



GUI Examples

  • 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



changelog:
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
Requires a new fdf​
1.4)
Supports TechCode Level as req
GUI can setup manual category mods.
Skips example code in InitHeroes right after the GUI Loader​
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​
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.​
Previews
Contents

HeroSelector (Map)

HeroSelector Jass (Map)

  1. GhostHunter123

    GhostHunter123

    Joined:
    Oct 17, 2012
    Messages:
    479
    Resources:
    1
    Spells:
    1
    Resources:
    1
    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: Sep 4, 2019
  2. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,788
    Resources:
    1
    Spells:
    1
    Resources:
    1
     
  3. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    obsolete since V1.1

    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 (Lua):

    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.
    Code (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)
     
    I though about that feature. Would have to swap from a Team wise data layout to a Player wise.
     
    Last edited: Sep 6, 2019
  4. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    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.
     
  5. Null

    Null

    Joined:
    Dec 3, 2018
    Messages:
    435
    Resources:
    48
    Icons:
    48
    Resources:
    48
    Whats the trigger for making that box ?
     
  6. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    With Box you mean the Background of HeroSelector?
    Then: HeroSelector uses on Default the BACKDROP "EscMenuBackdrop" as Background/Box. To create it on uses
    Code (vJASS):

    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)
     
  7. caioCGD

    caioCGD

    Joined:
    Nov 1, 2013
    Messages:
    4
    Resources:
    0
    Resources:
    0
    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?
     
  8. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    Is your map in Jass mode with jasshelper and vjass enabled? They are required.
     
  9. caioCGD

    caioCGD

    Joined:
    Nov 1, 2013
    Messages:
    4
    Resources:
    0
    Resources:
    0
    [​IMG]

    [​IMG]
     
  10. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    Does nothing happen when starting or is there an error when you try to validate/save the script?

    Edit: didn't see your ingame image. So no hero is shown.
     
  11. caioCGD

    caioCGD

    Joined:
    Nov 1, 2013
    Messages:
    4
    Resources:
    0
    Resources:
    0
    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: Nov 23, 2019
  12. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    You did not import the fdf, toc and model (at least in that map uploaded). Hence it fails to create the Buttons which are defined in the fdf.
     
  13. caioCGD

    caioCGD

    Joined:
    Nov 1, 2013
    Messages:
    4
    Resources:
    0
    Resources:
    0
    Maybe that is the problem:eekani:
    Sorry i'm out of attention in this staff

    +Thanks for the help+ (really awesome code man)
     
    Last edited: Nov 23, 2019
  14. CHA_Owner

    CHA_Owner

    Joined:
    Feb 11, 2008
    Messages:
    808
    Resources:
    2
    Spells:
    2
    Resources:
    2
    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,

    Code (vJASS):
    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.

    Code (vJASS):

    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.
     
  15. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    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.


    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".

    Yes, that is built in.
    function HeroSelector.setTitleText(text[, who])
    . who can be a player, a force, a teamNumber, a race or nothing = anyone
     
  16. CHA_Owner

    CHA_Owner

    Joined:
    Feb 11, 2008
    Messages:
    808
    Resources:
    2
    Spells:
    2
    Resources:
    2
    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

    Code (vJASS):

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


    but for some reason it is not returning the correct player each time
     
  17. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,607
    Resources:
    21
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    4
    JASS:
    1
    Resources:
    21
    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

    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: Dec 12, 2019
  18. CHA_Owner

    CHA_Owner

    Joined:
    Feb 11, 2008
    Messages:
    808
    Resources:
    2
    Spells:
    2
    Resources:
    2
    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.
     
  19. CHA_Owner

    CHA_Owner

    Joined:
    Feb 11, 2008
    Messages:
    808
    Resources:
    2
    Spells:
    2
    Resources:
    2
    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

    Code (vJASS):

        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: Dec 18, 2019