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 havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  5. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  6. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  10. 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 in Lua written Frame-UI System to pick a hero. 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.
Export and Import
war3mapImported\HeroSelector.fdf
war3mapImported\HeroSelector.toc
war3mapImported\HeroSelectorBan.mdx
Copy the trigger Folder "HeroSelector" into your map.

API:


HeroSelector

Code (Lua):

--[[
HeroSelector V1.2.0

------
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, 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           = "EscMenuBackdrop" --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
--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 = {}
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
    --Icon path, tooltip Text (tries to localize)
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
--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
--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
--Border
HeroSelector.BorderSize = {}
HeroSelector.BorderSize[RACE_HUMAN]     = 0.025 --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])
        end

        --kill the tables
        udg_HeroSelectorUnitCode = nil
        udg_HeroSelectorRandomOnly = nil
    end
    --adding further units when using the GUI Array does not make much sense, except you would add rows.

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


TeamViewer

Code (Lua):

--TeamViewer 1.2
--Plugin for HeroSelector by Tasyen
--It shows the selection of Teams in groups
--Default setup could be suited for 2 team games

TeamViewer = {}

TeamViewer.ShowNonAllies        = true --show non allies
TeamViewer.UpdateNonAllies      = false --update the image of non allies when the select or pick
--position when TeamViewer.ShowNonAllies = false or when a TeamPos is not set
TeamViewer.TeamPosX             = 0.2
TeamViewer.TeamPosY             = 0.25
TeamViewer.TeamPosGapY          = 0.015
TeamViewer.TeamPosLeft2Right    = true --(true) button is left and text is right, (false) button is right and text ist left
--how big are the Faces
TeamViewer.ButtonSize           = 0.03
TeamViewer.ButtonAlphaSelected  = 150
TeamViewer.ButtonDefaultIcon    = "UI\\Widgets\\EscMenu\\Human\\quest-unknown.blp"
TeamViewer.CategoryButtonSize   = 0.015 --size of the CategoryButtons below an players name
TeamViewer.CategoryButtonGap    = 0.002 -- space between 2 CategoryButtons

--used when ShowNonAllies = true
--warcraft 3 Teams start with 0
TeamViewer.TeamPos = {}
TeamViewer.TeamPos[0] = {}
--abs positions on the screen
TeamViewer.TeamPos[0].X = 0.02
TeamViewer.TeamPos[0].Y = 0.5
TeamViewer.TeamPos[0].GapY = 0.015
TeamViewer.TeamPos[0].Left2Right = true

TeamViewer.TeamPos[1] = {}
TeamViewer.TeamPos[1].X = 0.75
TeamViewer.TeamPos[1].Y = 0.5
TeamViewer.TeamPos[1].Left2Right = false


--player_Color is Copied from TriggerHappy
player_color = {
"ff0303",
"0042ff",
"1ce6b9",
"540081",
"fffc01",
"fe8a0e",
"20c000",
"e55bb0",
"959697",
"7ebff1",
"106246",
"4e2a04",
"9B0000",
"0000C3",
"00EAFF",
"BE00FE",
"EBCD87",
"F8A48B",
"BFFF80",
"DCB9EB",
"282828",
"EBF0FF",
"00781E",
"A46F33"
}

TeamViewer.Frames = {} --this is used to destroy all frames created by TeamViewer.
TeamViewer.HasPicked = {}
TeamViewer.BackupSelected = HeroSelector.buttonSelected
TeamViewer.BackupCreated = HeroSelector.unitCreated
TeamViewer.BackupRepick = HeroSelector.repick
TeamViewer.BackupDestroy = HeroSelector.destroy

function oppositeFramePoint(framepoint)
    if framepoint == FRAMEPOINT_BOTTOM then return FRAMEPOINT_TOP
    elseif framepoint == FRAMEPOINT_TOP then return FRAMEPOINT_BOTTOM
    elseif framepoint == FRAMEPOINT_TOPLEFT then return FRAMEPOINT_BOTTOMRIGHT
    elseif framepoint == FRAMEPOINT_TOPRIGHT then return FRAMEPOINT_BOTTOMLEFT
    elseif framepoint == FRAMEPOINT_LEFT then return FRAMEPOINT_RIGHT
    elseif framepoint == FRAMEPOINT_RIGHT then return FRAMEPOINT_LEFT
    elseif framepoint == FRAMEPOINT_CENTER then return FRAMEPOINT_CENTER
    elseif framepoint == FRAMEPOINT_BOTTOMLEFT then return FRAMEPOINT_TOPRIGHT
    elseif framepoint == FRAMEPOINT_BOTTOMRIGHT then return FRAMEPOINT_TOPLEFT
    else return framepoint
    end
end

function HeroSelector.destroy()
    for key, value in pairs(TeamViewer.Frames)
    do
        BlzDestroyFrame(value)
    end
    TeamViewer.BackupDestroy()
    TeamViewer = nil
end
function TeamViewer.PosFirstFrame(movingFrame, relativFrame, left2Right)
    if left2Right then
        BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPLEFT, relativFrame, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
    else
        BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPRIGHT, relativFrame, FRAMEPOINT_BOTTOMLEFT, 0, 0)
    end
end
function TeamViewer.PosFrame(movingFrame, relativFrame, left2Right)
    if left2Right then
        BlzFrameSetPoint(movingFrame, FRAMEPOINT_LEFT, relativFrame, FRAMEPOINT_RIGHT, TeamViewer.CategoryButtonGap, 0)
    else
        BlzFrameSetPoint(movingFrame, FRAMEPOINT_RIGHT, relativFrame, FRAMEPOINT_LEFT, -TeamViewer.CategoryButtonGap, 0)
    end
end
TimerStart(CreateTimer(),0.25, false, function()
    DestroyTimer(GetExpiredTimer())
    for index= 0, GetBJMaxPlayers() - 1,1 do
        local player = Player(index)
        if GetPlayerSlotState(player) ==  PLAYER_SLOT_STATE_PLAYING then
            local teamNr = GetPlayerTeam(player)
            if not TeamViewer[teamNr] then TeamViewer[teamNr] = {} end
            table.insert(TeamViewer[teamNr], player)
   
            local createContext = 1000 + index
            local button = BlzCreateFrame("HeroSelectorButton", HeroSelector.Box, 0, createContext)
            local textFrame = BlzCreateFrame("HeroSelectorTitle", HeroSelector.Box, 0, createContext) -- do not the buttons child, else it is affected by Alpha change
            local icon = BlzGetFrameByName("HeroSelectorButtonIcon", createContext)
            local iconDisabled = BlzGetFrameByName("HeroSelectorButtonIconDisabled", createContext)
            local tooltip = BlzCreateFrame("HeroSelectorText", button, 0, createContext)
            local left2Right = nil
            if TeamViewer.ShowNonAllies and TeamViewer.TeamPos[teamNr] then
                left2Right = TeamViewer.TeamPos[teamNr].Left2Right
            else
                left2Right = TeamViewer.TeamPosLeft2Right
            end
            BlzFrameSetSize(button, TeamViewer.ButtonSize, TeamViewer.ButtonSize)
            if #TeamViewer[teamNr] == 1 then
                if TeamViewer.ShowNonAllies and TeamViewer.TeamPos[teamNr] then
                    BlzFrameSetAbsPoint(button, FRAMEPOINT_BOTTOMLEFT, TeamViewer.TeamPos[teamNr].X, TeamViewer.TeamPos[teamNr].Y)
                else
                    BlzFrameSetAbsPoint(button,  FRAMEPOINT_BOTTOMLEFT, TeamViewer.TeamPosX, TeamViewer.TeamPosY)
                end
            else
                local prevTeamPlayer = TeamViewer[teamNr][#TeamViewer[teamNr] - 1]

                if TeamViewer.TeamPos[teamNr].GapY then
                    BlzFrameSetPoint(button, FRAMEPOINT_TOPLEFT, TeamViewer[prevTeamPlayer].Button, FRAMEPOINT_BOTTOMLEFT, 0, -TeamViewer.TeamPos[teamNr].GapY)
                else
                    BlzFrameSetPoint(button, FRAMEPOINT_TOPLEFT, TeamViewer[prevTeamPlayer].Button, FRAMEPOINT_BOTTOMLEFT, 0, -TeamViewer.TeamPosGapY)
                end
            end
            TeamViewer.PosFrame(textFrame, button, left2Right)
            if left2Right then
                BlzFrameSetPoint(tooltip, FRAMEPOINT_BOTTOMLEFT, button, FRAMEPOINT_TOPLEFT, 0, 0)
            else
                BlzFrameSetPoint(tooltip, FRAMEPOINT_BOTTOMRIGHT, button, FRAMEPOINT_TOPRIGHT, 0, 0)
            end
            BlzFrameSetText(textFrame, "|cff"..player_color[GetConvertedPlayerId(player)] .. GetPlayerName(player))
            BlzFrameSetTooltip(button, tooltip)
            BlzFrameSetTexture(icon, TeamViewer.ButtonDefaultIcon, 0, true)
            table.insert( TeamViewer.Frames, button)
            table.insert( TeamViewer.Frames, textFrame)
            table.insert( TeamViewer.Frames, icon)
            table.insert( TeamViewer.Frames, iconDisabled)
            table.insert( TeamViewer.Frames, tooltip)

            TeamViewer[player] = {}
            TeamViewer[player].Text = textFrame
            TeamViewer[player].Button = button
            TeamViewer[player].Icon = icon
            TeamViewer[player].IconDisabled = iconDisabled
            TeamViewer[player].Tooltip = tooltip
            TeamViewer[player].Category = {}
            local prevCategoryButton = nil
            --print("Pre HeroSelector.Category")
            for key, value in ipairs(HeroSelector.Category)
            do
                --print("Index",key)
                local categoryButton = {}
                categoryButton.Button = BlzCreateFrameByType("BUTTON", "", HeroSelector.Box, "", 0)
                categoryButton.Icon = BlzCreateFrameByType("BACKDROP", "", categoryButton.Button, "", 0)
                categoryButton.Tooltip = BlzCreateFrame("HeroSelectorText", categoryButton.Button, 0, key)
                BlzFrameSetText(categoryButton.Tooltip, BlzFrameGetText(value.Text))
                BlzFrameSetTooltip(categoryButton.Button, categoryButton.Tooltip)
                BlzFrameSetAllPoints(categoryButton.Icon, categoryButton.Button)
                BlzFrameSetPoint(categoryButton.Tooltip, FRAMEPOINT_BOTTOM, categoryButton.Button, FRAMEPOINT_TOP, 0, 0)
                BlzFrameSetSize(categoryButton.Button, 0.015, 0.015)
                BlzFrameSetTexture(categoryButton.Icon, value.Texture, 0, true)
                BlzFrameSetVisible(categoryButton.Button, false)

                table.insert(TeamViewer[player].Category, categoryButton)
                table.insert(TeamViewer.Frames, categoryButton.Button)
                table.insert(TeamViewer.Frames, categoryButton.Icon)
                table.insert(TeamViewer.Frames, categoryButton.Tooltip)
            end
   

            --When showning only allies, hide non allies
            if not TeamViewer.ShowNonAllies and not IsPlayerAlly(player, GetLocalPlayer()) then
                BlzFrameSetVisible(button, false)
            end
        end
    end
end)

function HeroSelector.buttonSelected(player, unitCode)

    TeamViewer.BackupSelected(player, unitCode)
 
    if not TeamViewer.HasPicked[player] then
        local teamNr = GetPlayerTeam(player)
        if TeamViewer.UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), player) then
            BlzFrameSetText(TeamViewer[player].Tooltip, GetObjectName(unitCode))
            BlzFrameSetTexture(TeamViewer[player].Icon, BlzGetAbilityIcon(unitCode), 0, true)
            BlzFrameSetAlpha(TeamViewer[player].Button, TeamViewer.ButtonAlphaSelected)
            local category = 1
            local prevCategoryButton = nil
            local left2Right = nil
            if TeamViewer.ShowNonAllies and TeamViewer.TeamPos[teamNr] then
                left2Right = TeamViewer.TeamPos[teamNr].Left2Right
            else
                left2Right = TeamViewer.TeamPosLeft2Right
            end
            for key, value in ipairs(HeroSelector.Category)
            do
                local categoryButton = TeamViewer[player].Category[key]
                BlzFrameClearAllPoints(categoryButton.Button)
                if BlzBitAnd(category, HeroSelector.UnitData[unitCode].Category) > 0 then
           
                    BlzFrameSetVisible(categoryButton.Button, true)
           
                    if TeamViewer.ShowNonAllies and TeamViewer.TeamPos[teamNr] then
                        if not prevCategoryButton then
                            TeamViewer.PosFirstFrame(categoryButton.Button, TeamViewer[player].Button, left2Right)
                        else
                            TeamViewer.PosFrame(categoryButton.Button, prevCategoryButton, left2Right)
                        end
                    else
                        if not prevCategoryButton then
                            TeamViewer.PosFirstFrame(categoryButton.Button, TeamViewer[player].Button, left2Right)
                        else
                            TeamViewer.PosFrame(categoryButton.Button, prevCategoryButton, left2Right)
                        end
                    end
           
                    prevCategoryButton = categoryButton.Button
                else
                    BlzFrameSetVisible(categoryButton.Button, false)
                end
                category = category + category        
            end
        end
    end
end

function HeroSelector.unitCreated(player, unit, isRandom)
    TeamViewer.BackupCreated(player, unit, isRandom)
    if not player then player = GetOwningPlayer(unit) end
    if TeamViewer.UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), player) then
        BlzFrameSetTexture(TeamViewer[player].Icon, BlzGetAbilityIcon(GetUnitTypeId(unit)), 0, true)
        BlzFrameSetAlpha(TeamViewer[player].Button, 255)
    end
    TeamViewer.HasPicked[player] = true
end

function HeroSelector.repick(unit, player)
    TeamViewer.BackupRepick(unit, player)
    if not player then player = GetOwningPlayer(unit) end
    if TeamViewer.UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), player) then
        BlzFrameSetTexture(TeamViewer[player].Icon, TeamViewer.ButtonDefaultIcon, 0, true)
        BlzFrameSetAlpha(TeamViewer[player].Button, 255)
    end
    TeamViewer.HasPicked[player] = false
end
 


HeroInfo

Code (Lua):

--HeroInfo 1.1
--Plugin for HeroInfo by Tasyen
--This Creates a TextArea which displays the name and the Extended tooltip of selected units.

HeroInfo = {}
--TextArea
HeroInfo.DescHeroNamePrefix     = "|cffffcc00"   --added before the Units Name
HeroInfo.DescHeroNameSufix      = "|r"           --added after the units Name
HeroInfo.TextAreaSizeX          = 0.2
HeroInfo.TextAreaSizeY          = 0.2
HeroInfo.TextAreaOffsetX        = 0
HeroInfo.TextAreaOffsetY        = 0
HeroInfo.TextAreaPoint          = FRAMEPOINT_TOPLEFT --pos the Tooltip with which Point
HeroInfo.TextAreaRelativePoint  = FRAMEPOINT_TOPRIGHT --pos the Tooltip to which Point of the Relative
HeroInfo.TextAreaRelativeGame   = false --(false) relativ to box, (true) relativ to GameUI
HeroInfo.BackupSelected         = HeroSelector.buttonSelected
HeroInfo.BackupDestroy          = HeroSelector.destroy

function HeroSelector.destroy()
    BlzDestroyFrame(HeroInfo.TextArea)
    HeroInfo.BackupDestroy()
    HeroInfo = nil
end

TimerStart(CreateTimer(),0.25, false, function()
    DestroyTimer(GetExpiredTimer())

    HeroInfo.TextArea = BlzCreateFrame("HeroSelectorTextArea", HeroSelector.Box, 0, 0)
    BlzFrameSetSize(HeroInfo.TextArea , HeroInfo.TextAreaSizeX, HeroInfo.TextAreaSizeY)
    if not HeroInfo.TextAreaRelativeGame then
        BlzFrameSetPoint(HeroInfo.TextArea, HeroInfo.TextAreaPoint, HeroSelector.Box, HeroInfo.TextAreaRelativePoint, HeroInfo.TextAreaOffsetX, HeroInfo.TextAreaOffsetY)
    else
        BlzFrameSetPoint(HeroInfo.TextArea, HeroInfo.TextAreaPoint, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), HeroInfo.TextAreaRelativePoint, HeroInfo.TextAreaOffsetX, HeroInfo.TextAreaOffsetY)
    end
end)

function HeroSelector.buttonSelected(player, unitCode)
    HeroInfo.BackupSelected(player, unitCode)

    if GetLocalPlayer() == player then
        BlzFrameSetText(HeroInfo.TextArea, HeroInfo.DescHeroNamePrefix .. GetObjectName(unitCode).. HeroInfo.DescHeroNameSufix)
        BlzFrameAddText(HeroInfo.TextArea, BlzGetAbilityExtendedTooltip(unitCode,0))
    end
end
 


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.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:
    439
    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:
    2,784
    Resources:
    1
    Spells:
    1
    Resources:
    1
     
  3. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,252
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    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,252
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    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:
    77
    Resources:
    2
    Icons:
    2
    Resources:
    2
    Whats the trigger for making that box ?
     
  6. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,252
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    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)