• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

How can I know the order my heros will appear in the hero bar?

Level 24
Joined
Jun 26, 2020
Messages
1,928
Hello, in my map I constantly add and remove heros to each player, and also hide them, but for that I need to change their owners, the problem is everytime I do that the heros could change the order they appear in the UI Hero Bar at the top left, this wasn't too much an issue until now that I need to now what of my heros ocupy those slot, do you know how can I do that?
 
Level 24
Joined
Jun 26, 2020
Messages
1,928
I tried this priority thing (Changing the real field with scripts), and it didn't work, but I noticed that when I change owner one of my hero and then I return it to the original owner, it always goes to the last place on the top left buttons order, no matter if I put the priority in order ascendant or descendant (at least with this I can know for sure the order of my heros ¯\_(ツ)/¯).
 
Level 24
Joined
Jun 26, 2020
Messages
1,928
Honestly I don't know how consistent is the rule of "Depends on the order the heroes have been created on the map for the player", when I change owner of them sometimes they appear in the last place, and sometimes appears in the first place, I'm running out of ideas, maybe adding an event when the heros buttons are clicked and see what unit is selected, but it seems that I can't add that event to that buttons.
 
Last edited:
Level 24
Joined
Jun 26, 2020
Messages
1,928
Can the boolean field something display hero icon be set to false and true during the game to maybe refresh the order?
Changing that boolean field doesn't do anything (thanks Blizzard).
It only restores the visibility of the hero icon if it was hidden from the beginning and I change the owner of the hero, but never hides it again.
 
Level 24
Joined
Jun 26, 2020
Messages
1,928
Have you double checked if there was anything going on like maybe the handle ID of the heroes would align with the order?

It probably does not align, and I do not know. But I thought it might be another idea to check
Nah, it doesn't and it shouldn't, because in that case the order should never change since the handle IDs never change.
 
Level 24
Joined
Jun 26, 2020
Messages
1,928
FINALLY I GOT IT, I know a way to know in what order the heros buttons are positioned.

Before explaining it I wanna explain why I chose this method, what I tried is getting something differentiable from the hero buttons, but I couldn't, I tried the hero hp or mana bars values, the number that appears in the skill points, but the game doesn't let me, but something that I can get is if the glow that appears when a hero has skill points to expend is visible:
1731703064658.png

And luckily this is manipulable since I can add and subtract them, but I only care if the hero has more than 0, and also luckily the visibility changes instantly when I modify the skill points.

So now the answer is obvious, but the method I will show only works for 0 to 3 heros, probably someone else could think in a more general method:

For 0 and 1, its easy, if 0 just do nothing, if 1 then that only 1 has the 0 index.

For 2 I can just make 1st of them have more than 0 skill points and then check if the glow with index 0 is visible, if yes then the 1st have the 0 index and the 2nd has the 1 index, otherwise the 1st have the 1 index and the 2nd has the 0 index.

For 3 probably you could ask what can I do if I only have 2 states and I need to compare 3 values, the answer is easy, I can just make the 3rd hero not have more than 0 skill points and then check what glow is not visible and then assign that index to the 3rd hero, and then apply the process for just 2 heros for the other 2 heros with the rest of indices.
Lua:
---@async
---Returns a table with indices from 0 to 2 with their respective hero if it exists, based on the hero button positions
---@param p player
---@return table<0|1|2, unit>
function GetHeroButtonPos(p)
    local orders = {} ---@type table<0|1|2, unit>

    local heros = {} ---@type unit[]
    ForUnitsOfPlayer(p, function (u)
        if IsUnitType(u, UNIT_TYPE_HERO) then
            table.insert(heros, u)
        end
    end)

    -- To prevent crashes
    for i = 0, #heros - 1 do
        if BlzFrameGetChildrenCount(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, i)) < 3 then
            return orders
        end
    end

    if #heros == 1 then -- The only 1
        orders[0] = heros[1]
    elseif #heros > 1 then
        local prevSkillPoints = __jarray(0) ---@type table<unit, integer>
        for i = 1, #heros do
            prevSkillPoints[heros[i]] = GetHeroSkillPoints(heros[i])
            UnitModifySkillPoints(heros[i], -prevSkillPoints[heros[i]])
        end

        if #heros == 2 then -- Check who has it visible or not
            UnitModifySkillPoints(heros[1], 1)

            if BlzFrameIsVisible(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0), 2)) then
                orders[0] = heros[1]
                orders[1] = heros[2]
            else
                orders[0] = heros[2]
                orders[1] = heros[1]
            end

            UnitModifySkillPoints(heros[1], -1)
        elseif #heros == 3 then -- Make visible 2 and check who is the other one
            local indices = {0, 1, 2}

            UnitModifySkillPoints(heros[1], 1)
            UnitModifySkillPoints(heros[2], 1)

            local noVisible = -1

            for i = 0, 2 do
                if not BlzFrameIsVisible(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, i), 2)) then
                    noVisible = i
                end
            end

            orders[noVisible] = heros[3]

            for i = 3, 1, -1 do
                if indices[i] == noVisible then
                    table.remove(indices, i)
                    break
                end
            end

            -- Now repeat the same process of 2 with the rest of them
            UnitModifySkillPoints(heros[2], -1)

            local visible = -1

            for i = 1, 2 do
                if not BlzFrameIsVisible(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, indices[i]), 2)) then
                    noVisible = indices[i]
                else
                    visible = indices[i]
                end
            end

            orders[visible] = heros[1]
            orders[noVisible] = heros[2]

            UnitModifySkillPoints(heros[1], -1)
        end

        for i = 1, #heros do
            UnitModifySkillPoints(heros[i], prevSkillPoints[heros[i]])
        end
    end

    return orders
end
The problem with this is that the visibility is not synced between players, so in case of multiplayer it would be necessary use this library: [Lua] - GetSyncedData
And do this:
Lua:
-- I do this in this way because the function locally calls the passed function and has functions that can't be called locally
local orders = GetHeroButtonPos(Player(0))
local syncedOrders = GetSyncedData(Player(0), function ()
    return orders
end)
for i = 0, 2 do
    if syncedOrders[i] then
        print(GetHeroProperName(orders[i]))
    end
end
 
I'd assume the game displays it by players and of a player it just loops player units until a none hero is found. It probably stores the allies in a LinkedList. Self, ally 1, ally2 .... I think i was able to change the displayed allies by reAlly them.

As mentioned earlier SetReservedLocalHeroButtons(int) is upperlimit for own heroes

GroupEnumUnitsOfPlayer(group, player, nil)
BlzGroupUnitAt(group, 0 to x) until not hero

or it might be by hero creation order for allies.
maybe it is also different in fixed Team games.
 
Last edited:
Level 24
Joined
Jun 26, 2020
Messages
1,928
I'd assume the game displays it by players and of a player it just loops player units until a none hero is found. It probably stores the allies in a LinkedList. Self, ally 1, ally2 .... I think i was able to change the displayed allies by reAlly them.

As mentioned earlier SetReservedLocalHeroButtons(int) is upperlimit for own heroes

GroupEnumUnitsOfPlayer(group, player, nil)
BlzGroupUnitAt(group, 0 to x) until not hero

or it might be by hero creation order for allies.
maybe it is also different in fixed Team games.
Your message gave an idea, I tested more and it seems that if in the map there are at least 1 hero of mine and no neutral heros from other players then I change them the owner and revert it back to mine the hero they always appear in the bottom of the hero bar no matter what.

But if there are pre-placed heros of another player or I add it manually while running the game for whatever reason things are different and more complicated and I wasn't able to find a pattern, but I think that I found a deterministic way to know the order of my heros, I just have to make all the heros in the map mine and then change the owner of that hero to passive and then to mine and then revert back all the rest of heros and then I always will know they will appear at the bottom.

The only problem with that is changing owner interrumpts the current order of the unit.
 
Top