Antares' Hero Selection v1.5

This bundle is marked as director's cut. It exceeds all expectations and excels in every regard.
RbeQz1.png


Create stunning, cinematic hero selection screens and easily integrate them into your map!

RbeQz1.png



RbeQz1.png


I am putting up all of my resources for free. If you like my work and find these resources useful, please consider buying me a coffee!



Overview

Installation

Change Log

Credits


Overview

This hero selection system allows players to get a full preview of the hero they're about to pick, with a mouse-over tooltip and a preview of their abilities. Heroes are represented as special effects, not as units, allowing for the hero to be shown locally, only to the player selecting it. Heroes can play animations and emotes when they are preselected and/or picked.

There are many additional features, such as All Random, Ban Phase, and Repick. You can set up multiple pages of heroes or enable certain heroes only for specific players or teams. You can define your own callback functions to add functionality that is not possible with the default options.

While the config is quite long, it is only because every part of the presentation can be customized. If you don't like any of the features shown in the showcase map, you can simply disable it. Getting a working system should be relatively easy, although copying all your heroes may be tedious if you have a lot of them.

I recommend using this system in conjunction with Neat Text Messages, which allows you to have more control over where text messages are shown.

Features
  • Supports any number of heroes with multiple pages.
  • Repick, Restart, Ban phase, and All Random.
  • Shared and separate hero selection.
  • Open and concealed hero selection.
  • Different selection screens for each team/player.
  • Different hero rosters for each team/player.

This system is based on the hero selection system used in Particle Party.

Installation

(GUI only) Make sure that in your editor under File -> Preferences, the flag "Automatically create unknown variables when pasting trigger data" is set.
(GUI only) Make sure you have JassHelper and vJASS enabled in the Trigger Editor under JassHelper.

Copy the Hero Selection parent folder from the test map of the respective language into your map. Do the same for Neat Text Messages if you want to use it.

Import
  • HeroSelectionMenu.fdf
  • CustomTooltip.fdf
  • HeroSelectionTemplates.toc
  • GeneralHeroGlow.mdx (optional)

Copy Destructables (optional)
  • Hero No Shadow
  • Hero Shadow
These destructables are used to cast a shadow that only those players previewing a hero can see.


To get started with your setup and customization, follow the steps laid out in the Hero Selection Documentation script file in the Hero Selection folder.

Change Log

Version 1.4
  • Added the BanHeroFromSelectionForPlayer function.

Version 1.3.4
  • Fixed an issue that could cause the game to desync during initialization when a player hasn't focused the Warcraft 3 window.
  • Fixed an issue that caused the hero selection buttons to remain focused after selecting a hero.

Version 1.3.3
  • Fixed a bug that caused the menu to not go into the widescreen area in the vJASS and GUI versions.
  • Fixed a bug that caused the pages to not cycle to a hero on a different page when selected through Suggest Random.

Version 1.3.2
  • Fixed a bug that could cause a desync due hiding/showing ConsoleUIBackdrop locally.
  • Two additional arguments are passed to the HeroSelectionOnPick callback function. These are wasRandomPick and wasRepick.

Version 1.3
  • Improved GUI documentation and import instructions.
  • Enabled hero selection menu and tooltips to be put into the widescreen area. For the menu, this is done by setting MENU_X_LEFT to a negative number. The menu will automatically be adjusted for players who aren't using widescreen monitors.
  • Added the option to add player name texttags over the background heroes. The option in the config is PLAYER_TEXT_TAGS under "Sounds and visuals of background heroes."

Version 1.2
  • Added many page cycle button styles.
  • Added OnRestart callback function.
  • Moved all globals that can be used in callbacks into the callbacks block.
  • Cleaned up code and fixed minor bugs.

Version 1.1
  • Added support for large number of heroes by adding option to setup multiple pages.
  • Split config and callbacks into two files.
  • You no longer need to set the model paths of heroes manually.
  • Tinting colors of heroes will now be shown.
  • Consolidated select and ban buttons into one button.
  • Added option to set the scale of the accept button.
  • Added option to lock top edge of tooltips instead of bottom edge.
  • Cleaned up code and fixed minor bugs.

Credits

Showcase map terrain by illbean.

Trees - Fingolfin
Night Elf Archway - eubz, Stormknight
Fog and Glow - Embercraft
Hero Highlight Effects - Vinz
Music - Nightsong (World of Warcraft)

Thank you to Wrda for the extensive review and all the suggestions!
[/CENTER]
Contents

Antares' Hero Selection v1.5 GUI (Map)

Antares' Hero Selection v1.5 Lua (Map)

Antares' Hero Selection v1.5 vJASS (Map)

Reviews
Wrda
Awarded Director's Cut due to: 1. how the resource outshines others alike and how it exceeds common expectations; 2. supports GUI, vJASS, and LUA; 3. high quality in performance, documentation and configuration. It's a very inspiring resource, full...
It works fine for me. Are you using an older Warcraft 3 version?
Nope I'm using the most current version of wc3. Tho I've seem to figure out the issue. When you download and extract the folder if you copy over the base "Antares Hero Selection v1.3.2 (now with GUI and Lua)" folder to your maps directory, which has a nested "Antares Hero Selection v1.3.2 (now with GUI and Lua)" in it, then Wc3 Seems to think the jass map is corrupted. However if you copy only the subdirectory then it runs fine in Wc3. I have absolutely no idea why this and redownladed and tested it several times just to be sure. Might be something with how wc3 is parsing the file paths. But the map itself appears to be fine.
 
The first folder is a .zip, is it not? Anyway, glad you could fix it! Notify me if there's any problem with the system itself! :psmile:
So I'll be using just the vJASS version going forward as it seems to be the cleanest and the easiest to use.

Am not sure if this is a bug or if I didn't enable something correctly, but when using multiple pages and selecting the random button the game properly picks heroes from any page but does not shift to that page if the hero is on another page, and instead highlights where that hero would be on the current page.

 
Level 2
Joined
May 11, 2021
Messages
2
Hey, this is awesome. Is there any way we could hide or ban certain categories for one team once a member has chosen a hero from that category using GUI? For example, Player 1 from Team 1 chose an agility hero, so now Team 1 can no longer choose any other agility-based hero. Thanks!
 
Hey, this is awesome. Is there any way we could hide or ban certain categories for one team once a member has chosen a hero from that category using GUI? For example, Player 1 from Team 1 chose an agility hero, so now Team 1 can no longer choose any other agility-based hero. Thanks!
It's currently not possible to ban heroes for a specific team, but that's something I could add easily. I'll do that after I get my other resources up-to-date.
 

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
2,010
JASS:
private function InitCrashCheck takes string functionName returns nothing
    static if HERO_SELECTION_ENABLE_DEBUG_MODE then
    local timer crashTimer = CreateTimer()
        call TimerStart(crashTimer, 0.01, false, function CheckForCrash)
        call SaveBoolean(hash, GetHandleId(crashTimer), 0, true)
        call SaveStr(hash, GetHandleId(crashTimer), 1, functionName)
        call SaveTimerHandle(hash, StringHash(functionName), 0, crashTimer)
         set crashTimer = null
        endif
endfunction
i don't understand why you need to save crashTimer with StringHash and this whole line, I don't see you loading it anywhere.


JASS:
private function GetLocZ takes real x, real y returns real
    local location tempLoc = Location(x,y)
    local real z = GetLocationZ(tempLoc)
    call RemoveLocation(tempLoc)
    set tempLoc = null
    return z
endfunction
You can reuse the same location ;)


JASS:
//InitMenu function (...)
        set trig = CreateTrigger()
        call BlzTriggerRegisterFrameEvent( trig , heroBanButton , FRAMEEVENT_CONTROL_CLICK )
        call TriggerAddAction( trig, function BanHero )
       
        //Ability Buttons
        set i = 1
        loop
        exitwhen i > NUMBER_OF_ABILITY_FRAMES
            set heroSelectionAbility[i] = BlzCreateFrameByType("BACKDROP", "heroSelectionAbility_" + I2S(i), heroSelectionMenu, "", 0)
            static if ABILITY_BUTTON_HORIZONTAL_LAYOUT then
                call BlzFrameSetPoint(heroSelectionAbility[i], FRAMEPOINT_TOPLEFT, heroSelectionMenu , FRAMEPOINT_TOPRIGHT, HERO_ABILITY_PREVIEW_BUTTON_X + HERO_ABILITY_PREVIEW_BUTTON_SIZE*(i-1), HERO_ABILITY_PREVIEW_BUTTON_Y)
            else
                call BlzFrameSetPoint(heroSelectionAbility[i], FRAMEPOINT_TOPLEFT, heroSelectionMenu , FRAMEPOINT_TOPRIGHT, HERO_ABILITY_PREVIEW_BUTTON_X, HERO_ABILITY_PREVIEW_BUTTON_Y - HERO_ABILITY_PREVIEW_BUTTON_SIZE*(i-1))
            endif
            call BlzFrameSetSize(heroSelectionAbility[i], HERO_ABILITY_PREVIEW_BUTTON_SIZE, HERO_ABILITY_PREVIEW_BUTTON_SIZE)
            call BlzFrameSetVisible( heroSelectionAbility[i] , false )
           
            set heroSelectionAbilityHover[i] = BlzCreateFrameByType("FRAME" , "heroIconFrameHover" , heroSelectionAbility[i] , "" , 0)
            call BlzFrameSetAllPoints( heroSelectionAbilityHover[i] , heroSelectionAbility[i] )
   
            set heroSelectionAbilityTooltip[i] = BlzCreateFrame("CustomTooltip", heroSelectionAbilityHover[i], 0, 0)
            if TOOLTIP_LOCK_TOP then
                call BlzFrameSetPoint( heroSelectionAbilityTooltip[i] , FRAMEPOINT_TOPLEFT , fullScreenFrame , FRAMEPOINT_BOTTOMLEFT , tooltipLeftXLocal , TOOLTIP_Y )
            else
                call BlzFrameSetPoint( heroSelectionAbilityTooltip[i] , FRAMEPOINT_BOTTOMLEFT , fullScreenFrame , FRAMEPOINT_BOTTOMLEFT , tooltipLeftXLocal , TOOLTIP_Y )
            endif
            call BlzFrameSetTooltip( heroSelectionAbilityHover[i] , heroSelectionAbilityTooltip[i] )
            call BlzFrameSetSize( heroSelectionAbilityTooltip[i] , TOOLTIP_WIDTH , 0.0 )
            set heroSelectionAbilityTooltipTitle[i] = BlzFrameGetChild( heroSelectionAbilityTooltip[i],0)
            set heroSelectionAbilityTooltipText[i] = BlzFrameGetChild( heroSelectionAbilityTooltip[i],1)
           
            set i = i + 1
        endloop
       
        call BlzFrameSetVisible( heroSelectionMenu, false)
        call NoCrash("InitMenu")
    endfunction

Forgot to null trig variable. Same as leaveTrigger.


GUI:
1. Hero Selection Camera

To set up the hero selection camera, edit
FOREGROUND_HERO_X
FOREGROUND_HERO_Y
HERO_SELECTION_ANGLE
Edit where? it's good to mention that's in HeroSelectionConfig.

JASS:
private function DeleteBackgroundHero takes integer P returns nothing
call BlzSetSpecialEffectPosition(backgroundHero[P], GARBAGE_DUMP_X, GARBAGE_DUMP_Y, 0)
    call DeleteBackgroundHero(P)
    static if PLAYER_TEXT_TAGS then
        call DestroyTextTag(backgroundHeroTextTag[P])
    endif
endfunction
Looping and looping and then crashing the thread, as we've talked about.


No issues found on both other than the frames keeping focus of the keyboard, and the disconnection if a player is alt tabbed as you're already aware.

Very cute and fancy hero selection, out of the box. Not so cute the local integer P = GetPlayerId(player) fetish 😁

Waiting on update for those 2 issues, specially the latter.
 
Last edited:
Very cute and fancy hero selection, out of the box. Not so cute the local integer P = GetPlayerId(player) fetish 😁

Waiting on update for those 2 issues, specially the latter.
Thanks for taking the time to read through all this! :plol: Everything you mentioned should be fixed.
 

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
2,010
Lua:
do  LIBRARY_HeroDeclaration = true
(...)
do  LIBRARY_HeroSelectionCallbacks = true
(...)
do  LIBRARY_HeroSelectionConfig = true
(...)
do  LIBRARY_HeroSelection = true
Quite redundant, a remnant of the VJASS conversion to Lua.

if Debug then Debug.endFile() end
Not as important, but you're missing the end line for debug utils report the correct lines if errors arise.

Lua:
---@param whichPlayer player
    ---@param whichHero Hero
    function HeroSelectionOnPick(whichPlayer, whichHero, wasRandomSelect, wasRepick)
        --Here you can insert additional code that is executed when a player picks a hero.
    end
Not a big deal, just a little missing annotation ;)
Since your local function HexToInt(hexString), local function TextColor() ,local function AnimateCaption() are using hex conversions, one can simplify using the follow:
Lua:
---@param sign string|integer
---@return integer
local function hex2Dec(sign)
    return tonumber(tostring(sign), 16)
end

---input 15 returns "f"
---@param dec integer
---@return string
local function dec2HexStr(dec)
    return (string.format('%02x', dec))
end

---input 15 returns "0f"
---@param dec integer
---@return string
local function dec2HexStrEx(dec)
    return (string.format('%x', dec))
end

Lua:
---@param id integer
    ---@return string
    local function GetHeroAbilityName(id)
        local tooltip = BlzGetAbilityTooltip(id, 0) ---@type string
        local length = StringLength(tooltip) ---@type integer
        local delimLength = StringLength(HERO_ABILITY_LEVEL_DELIMITER) ---@type integer
        local j ---@type integer


        if HERO_ABILITY_LEVEL_DELIMITER == nil or HERO_ABILITY_LEVEL_DELIMITER == "" then
            return tooltip
        end


        for i = 1, length - delimLength do
            j = 0
            while not (SubString(tooltip, i+j, i+j+1) ~= SubString(HERO_ABILITY_LEVEL_DELIMITER, j, j+1)) do
                if j == delimLength - 1 then
                    return SubString(tooltip, 0, i)
                end
                j = j + 1
            end
        end
        return tooltip
    end
Replace the loop with:
Lua:
local start = string.find(tooltip, HERO_ABILITY_LEVEL_DELIMITER)
return string.sub(tooltip, 0, start - 1)

Lua:
HeroIconPathOfPlayer[P] = "ReplaceableTextures\\CommandButtons\\" .. HeroList[heroIndex].iconPath
HeroIconPathOfPlayer[Player(P-1)] = HeroIconPathOfPlayer[P]
i don't see the latter one being used anywhere else. Could replace Atan2, Cos, Sin and Deg2Rad with the lua math functions counterpart, not that it will make visible difference nonetheless.

Lua:
heroSelectionAbility[i] = BlzCreateFrameByType("BACKDROP", "heroSelectionAbility_" .. I2S(i), heroSelectionMenu, "", 0)
No need I2S for string concatenation.
Frame stays on focus on click, disabling keyboard input, this is the most important bit.

A unique hero selection system out of the box, which lets you preview the hero, its abilities, and what your allies and enemies have selected, with a lot of flexibility for fine tuning. Lovely.
Only glaring issue is the disabled keyboard input, then it's approved.
 
Smth i didn't catch... Can players select heroes simultaneously?
Can I set 30 sec for all players?
What do you mean with simultaneously? One player picks for multiple players?
You can set a time limit for the hero selection.

Can I configure in a way that Player picks last selected hero when the time runs out? Not just a random hero
If you start the timer with the default option TIME_LIMIT, then each player will choose a random hero as it expires. If you want a different behavior, you can start the timer with StartHeroSelectionTimer instead, which lets you select your own callback function/trigger.
 
>What do you mean with simultaneously? One player picks for multiple players?
Because in reforged it is relatively hard to test multiplayer. I'm not sure if players pick heroes one by one or simultaneously.
As far as i understood they pick simultaneously.

I have a question. Can I use a 2nd step in the menu to pick some game rules? Or artifacts?
 
Because in reforged it is relatively hard to test multiplayer. I'm not sure if players pick heroes one by one or simultaneously.
As far as i understood they pick simultaneously.

I have a question. Can I use a 2nd step in the menu to pick some game rules? Or artifacts?
You can test multiplayer in Reforged by starting one client, logging out at the bottom right, creating a local network game, starting another client, and then joining the network game.

You can have the objects you select in the system represent anything, they don't have to be heroes, but there's currently no way to select multiple objects per player. If you want players to select game rules, you can begin the hero selection so that the camera setup is applied, then show a dialog to players where they can vote, and on the final vote enable the hero selection. How this looks like, you can see in my map Particle Party (the dialog appears only in multiplayer). Also, for dialogs, I can recommend you one of my other resources: Better Dialogs.
 
Level 9
Joined
Nov 18, 2014
Messages
80
Thank you, I will look into ways to enable picking multiple things (without having to rewrite everything). I might want that feature myself at some point.
Hello,

I worked on something to adapt your system with a multiple heroes selection available (based on your v1.3 vJASS).
I'm currently testing if everything is working fine, and might have overlooked some aspects (as I don't use the ban system for example), but it seems to be coherent at the moment.
Not sure it can be used to pick different things (like items), but can probably be adapted for that too with a bit more work.

I'll provide a modified version of the test map when I'll have tested a bit more :grin:
I spotted a couple of errors too as I was doing some tests, and will try to give a list of everything I added and/or corrected.

I won't have much time this week, but should be able to upload soon-ish, if I do not discover something broken in the mean time :hohum:
 
Last edited:
I'll provide a modified version of the test map when I'll have tested a bit more :grin:
I spotted a couple of errors too as I was doing some tests, and will try to give a list of everything I added and/or corrected.

I won't have much time this week, but should be able to upload soon-ish, if I do not discover something broken in the mean time :hohum:
That'd be great! I appreciate it.

I have come up with a solution that should be doable. Maybe you can give me the tl;dr of your approach? Are you achieving it only with the callback functions or did you edit the internals?

My approach:
  • Add a config option to not automatically end hero selection after the last player picks (easy enough).
  • Add a function to clear a player's stored hero (also not too hard).
  • Add a function to show/hide hero categories.
With these additions and using the callback functions, it should be no problem to make a multiple hero selection system work.
 

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
2,010
Awarded Director's Cut due to:
1. how the resource outshines others alike and how it exceeds common expectations;
2. supports GUI, vJASS, and LUA;
3. high quality in performance, documentation and configuration.

It's a very inspiring resource, full of devotion and effort of the author in this trying time for Warcraft III. Hopefully, it encourages activity and engagement in this section, Spells and Systems. - The Staff

Great work.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
This system is based on the Particle Party hero selection system.
This is currently worded in an unclear way which caused some confusion. My understanding from this was that you based this system off another system resource and then improved it. Not that you originally made the system for your map and then extended it to become this resource.

I suggest changing it to the following:
This system is based on the hero selection system used in Particle Party.
 
This is currently worded in an unclear way which caused some confusion. My understanding from this was that you based this system off another system resource and then improved it. Not that you originally made the system for your map and then extended it to become this resource.

I suggest changing it to the following:
Sure.
Multipage system is good but from UX perspective if you can pack more info on initial screen is often better.
+ From my point of view random selection should be triggered on timeout only if currently selected hero is not available. Ie I click on a hero and I just stare at the screen then I got a random one.
That's a good point. I can change that.
 
Level 9
Joined
Nov 18, 2014
Messages
80
That'd be great! I appreciate it.

I have come up with a solution that should be doable. Maybe you can give me the tl;dr of your approach? Are you achieving it only with the callback functions or did you edit the internals?

My approach:
  • Add a config option to not automatically end hero selection after the last player picks (easy enough).
  • Add a function to clear a player's stored hero (also not too hard).
  • Add a function to show/hide hero categories.
With these additions and using the callback functions, it should be no problem to make a multiple hero selection system work.

I edited the internals.

My logic is the following:
Using P as player index, and M as maximum number of players on the map.
Information about the n-th hero of player P is stocked in array at the position P + (n-1) * M

Example:
Player (with playerIndex = 1) select 3 heroes on a map with 8 maximum players
First hero is playerHero[1], Second hero is playerHero[9], Third is playerHero[17] etc.



I have a patchnote where I kept track of everything (I think :hohum: ) I modified.
Works well for my map, still have issues with demo map:
  • on pickHero() crashes when bots pick their hero after all players picked theirs (Might be only because of timer and number of loop as the heroes are indeed picked and created)
  • demo map doesn't have enough heroes to support unique hero and 2 or 3 heroes per player, which might lead to unexpected behavior
  • Secondary hero model isn't displayed on demo map (working on my map). Weird, as secondary location is indeed correctly calculated (pick special effect correctly created)

I'll leave the demo map here, as I might not have much time to look why those errors are occuring on the demo map.

Here is the patch note, hope it covers everything, as I did tinker a bit while trying to debug demo map :grin:

Hero Selection Config
  • Moved constant HERO_CAN_BE_PICKED_MULTIPLE_TIMES to Hero Selection callback, changed to modifiable variable, as some maps needs to be able to pick different mode before selection.
  • Function GetPlayerBackgroundHeroLocation
    • Added variables BACKGROUND_SECONDARY_HEROES_OFFSET (distance bewteen 2 heroes location) & BACKGROUND_SECONDARY_HEROES_ANGLE_OFFSET (angle diffrence between 2 heroes location)
    • Added some calculation to dist & angle to include secondary heroes positions
  • Default position "LeftRightMiddleButton" isn't working as intended for left button. The button width is halfed, as there isn't any space available at the left of selection menu.
    Probably need to move the whole interface a few pixel to the right. No modifications done here for now.


Hero Selection Callback
  • Moved constant HERO_CAN_BE_PICKED_MULTIPLE_TIMES from Selection config and removed constant
  • Added array isRandomHero, storing if corresponding hero has been chosen randomly.
  • Added integer NUMBER_OF_HEROES_PER_PLAYER which needs to be set once before selection, storing how many heroes each player can pick.
  • Added array playerHeroesNb which stores how many heroes each player has picked.
  • Updated HeroSelectionOnEscape to create multiple heroes & adding starting ressources depending on player having random heroes.

Hero Selection
  • Function EndHeroSelection
    • Added loop to destroy all background heroes
  • Function OnPlayerLeave
    • Added loop to destroy all background heroes
  • Function PickHero
    • Changed Index "P" to Index "P + MAX_NUMBER_OF_PLAYERS * playerHeroesNb[P]" for some variabbles in section //Set variables
    • Added isRandomly handling in section // Set variables
    • Changed Index "P" to Index "P + MAX_NUMBER_OF_PLAYERS * playerHeroesNb[P]" in section //Create Background
    • Added playerHeroesNb handling
    • Added a test to check if player have selected all of its heroes (if yes, then execute old code that might end hero selection, if not, allow selection)
  • Function PreselectRandomCycle
    • Changed condition "not playerHasHero[P]" to "playerHeroesNb[P] != NUMBER_OF_HEROES_PER_PLAYER"
  • Function PreselectHero
    • Changed condition "not playerHasHero[P]" to "playerHeroesNb[P] != NUMBER_OF_HEROES_PER_PLAYER" (to enable button accept)
  • Function HeroSelectionPlayerForceRandom
    • Changed Index "GetPlayerId(whichPlayer)" to Index "GetPlayerId(whichPlayer) + MAX_NUMBER_OF_PLAYERS * playerHeroesNb[GetPlayerId(whichPlayer)]"
    • Added a check to prevent picking more than allowed number of heroes.
  • Function HeroSelectionAllRandom
    • Corrected callback name, now correctly call HeroSelectionOnAllRandom instead of calling itself (which provoked a crash due to infinit recursive loop)
    • Added loop to select in multiple heroes randomly per player
    • Changed logic to use existing HeroSelectionPlayerForceRandom function, instead of duplicating code (easier to maintain/change)
  • Function HeroSelectionForceEnd
    • Added loop to handle multiple forced selection for one player
  • Function PlayerReturnToHeroSelection
    • Added loop to delete all background heroes
    • Added playerHeroesNb reset
  • Function RestartHeroSelection
    • Added loop to delete all background heroes
    • Added playerHeroesNb reset
  • Function InitHeroSelection
    • Added loop to get all background heroes positions


I tried to make edits that would support more than the 2 heroes per player I needed, so it might be used by other maps.
Might not be the easiest or cleanest solution tho, so do as you want with that :cute:
 

Attachments

  • Antares Hero Selection v1.3 vJASS -- multiple heroes selection.w3m
    1.7 MB · Views: 6
Last edited:
Thanks for sharing!

In vJASS, you have access to multidimensional arrays, so you don't have to do that linear indexing that you're doing.

It looks like you've implemented it in such a way that one player can pick his or her second hero before any other players have picked theirs. I think this is not the route I want to go, because it would make systems where you pick a hero, then something else, like @kokon envisioned it, more difficult. I think it's better if there are multiple rounds of hero selections and the menu can switch to a new layout after the first if that's what the mapper wants.
 
Level 9
Joined
Nov 18, 2014
Messages
80
Thanks for sharing!

In vJASS, you have access to multidimensional arrays, so you don't have to do that linear indexing that you're doing.

It looks like you've implemented it in such a way that one player can pick his or her second hero before any other players have picked theirs. I think this is not the route I want to go, because it would make systems where you pick a hero, then something else, like @kokon envisioned it, more difficult. I think it's better if there are multiple rounds of hero selections and the menu can switch to a new layout after the first if that's what the mapper wants.

It was indeed made to allow a player to pick multiple heroes before other players pick their first.
I didn't know vJass allowed that, could be adapted to be cleaner (I used GUI logic there I guess :grin: )

It might be interesting to combine both ways, as you might want a first round for heroes and then a selection for items, with each selection allowing multiple picks without waiting for others (especially when heroes/items are not unique and can be picked by everyone).
 
It looks like you've implemented it in such a way that one player can pick his or her second hero before any other players have picked theirs. I think this is not the route I want to go, because it would make systems where you pick a hero, then something else, like @kokon envisioned it, more difficult. I think it's better if there are multiple rounds of hero selections and the menu can switch to a new layout after the first if that's what the mapper wants.
Personally i'm planning to use selection without players wainting for each other. Will try to cut warmup time of the game where no actual game happening.
But i would use this menu for game rules/ artifact pick / skill pick
 
Last edited:
I have the multiple hero selection working for the same hero pool in each step. The different hero pool each step version is still glitching in a few spots. When I have that fixed, I need to port the changes over to the JASS version and it'll be done.
 

Attachments

  • 2024-10-13 12-30-58_tvai.mp4
    13.2 MB
I made the Lua version work. Here it is.

There are two new config options:
NUMBER_OF_HERO_SELECTION_STEPS
NEW_HERO_ROSTER_EACH_STEP

If NEW_HERO_ROSTER_EACH_STEP is true, a new hero list is generated for each step. Otherwise, the same is used for each step.

The GetPlayerBackgroundHeroLocation function has the new parameter "whichStep", which you can use to control where the hero of each step appears as it is selected.

If you're using NEW_HERO_ROSTER_EACH_STEP, you need to set the selectedInStep field for each hero. You can have the same categories each step or different ones. Simply list all category names in CATEGORY_NAMES and if a category has no heroes in it in one step, it won't appear.

The system does not save each picked hero of a player, only the last one, as I don't want to require users who are not using this feature to index a 2D array. Instead, you have to assign the picked heroes to your own variable using the HeroSelectionOnPick function.

If this is all good, I'll port the changes over to the JASS version. Expect bugs, though. This system was not designed to do this and the code has become more and more spaghettified with each added feature.
 

Attachments

  • Antares Hero Selection v1.5 Lua.w3m
    1.8 MB · Views: 4
Level 9
Joined
Nov 18, 2014
Messages
80
Blizzard being blizzard, their last update broke your system interface a bit :cry:

Seems the maximum size for the window will have to change to adapt to the new UI.
I'll probably find where to change that, but might be a good thing to change the default setting in your next version :grin:

Button still there, if I click on this area, it still accepts.
1731590863075.png
 
Last edited:
Level 9
Joined
Nov 18, 2014
Messages
80
Ok, so we've gathered that frames that are using the bottom bar as a parent are scaled alongside the new Scale UI option. Is that the core of the bug?
Yes, that's the issue. UI default size changed and got bigger. Since the change, your system UI get behind ingame UI (as shown on screenshot).
I fixed it by reducing number of heroes on a same page.

The patch only highlighted the issue that your system UI doesn't have a max size. Which means it tries to expand to fit all buttons within it, even if that means getting behind UI or not displaying some button because there isn't space for them anymore.

It would be great if your frame had a max size, preventing it from getting behind game UI (would be even better if you could check against game new UI scaling option to adjust it). This way, you could have your system create a new page automatically if too many buttons are put in a same page. That would make your system way more resilient to UI changes :cute:

Not sure how much work that requires tho.
 
No, that makes no sense to me.

It should be up to the user to make sure the menu is aligned correctly and organize new pages if necessary. There's no way for me to know the extents that the menu is allowed to have. Different maps use different UIs.

I will make a small update to fix the HIDE_GAME_UI option. The bottom and top bars are no longer hidden because they are now separate frames.
 
Level 9
Joined
Nov 18, 2014
Messages
80
No, that makes no sense to me.

It should be up to the user to make sure the menu is aligned correctly and organize new pages if necessary. There's no way for me to know the extents that the menu is allowed to have. Different maps use different UIs.
Fair enough :grin:
I will make a small update to fix the HIDE_GAME_UI option. The bottom and top bars are no longer hidden because they are now separate frames.
:thumbs_up:
 
Level 11
Joined
Dec 16, 2017
Messages
418
Hi there, i want to change my Tavern hero choose that i have in Legion Hero Defense to this one, i just gotta figure out something, in my map i have some hero classes from wow, like warlock etc, with the specializations aswell, like affliction, demonology and destruction.
And what i do, is that if someone picks warlock affliction, i alsoo remove warlock demonology and destruction, so only 1 class can be available per game.

I want to add that feature to this system, i tried some things but they didn't work, in the vJASS version, below i will show you how i achieve that in my current hero selection, can someone guide to me to achieve it?

Thanks!
  • Heroes
    • Events
      • Time - Elapsed game time is 0.30 seconds
    • Conditions
    • Actions
      • -------- Towers --------
      • Set VariableSet LeftTower = Tower 0032 <gen>
      • Set VariableSet RightTower = Tower 0033 <gen>
      • Set VariableSet NEHall = Night Elves Hall 0001 <gen>
      • -------- Cinematics --------
      • Set VariableSet CinematicEndingPosition[1] = (Center of RedStand <gen>)
      • Set VariableSet CinematicEndingPosition[2] = (Center of BlueStand <gen>)
      • Set VariableSet CinematicEndingPosition[3] = (Center of TealStand <gen>)
      • Set VariableSet CinematicEndingPosition[4] = (Center of PurpleStand <gen>)
      • Set VariableSet CinematicEndingPosition[5] = (Center of YellowStand <gen>)
      • Set VariableSet CinematicEndingMove[1] = (Center of RedMove <gen>)
      • Set VariableSet CinematicEndingMove[2] = (Center of BlueMove <gen>)
      • Set VariableSet CinematicEndingMove[3] = (Center of TealMove <gen>)
      • Set VariableSet CinematicEndingMove[4] = (Center of PurpleMove <gen>)
      • Set VariableSet CinematicEndingMove[5] = (Center of YellowMove <gen>)
      • Set VariableSet CinematicArenaPosition[1] = (Center of ArenaRedSpawn <gen>)
      • Set VariableSet CinematicArenaPosition[2] = (Center of ArenaBlueSpawn <gen>)
      • Set VariableSet CinematicArenaPosition[3] = (Center of ArenaTealSpawn <gen>)
      • Set VariableSet CinematicArenaPosition[4] = (Center of ArenaPurpleSpawn <gen>)
      • Set VariableSet CinematicArenaPosition[5] = (Center of ArenaYellowSpawn <gen>)
      • -------- Class Hall Position --------
      • Set VariableSet ClassHall_Region[1] = (Center of ClassHallRed <gen>)
      • Set VariableSet ClassHall_Region[2] = (Center of ClassHallBlue <gen>)
      • Set VariableSet ClassHall_Region[3] = (Center of ClassHallTeal <gen>)
      • Set VariableSet ClassHall_Region[4] = (Center of ClassHallPurple <gen>)
      • Set VariableSet ClassHall_Region[5] = (Center of ClassHallYellow <gen>)
      • -------- Class Hall Types --------
      • Set VariableSet ClassHall_Type[1] = Demon Hunter Class Hall
      • Set VariableSet ClassHall_Type[2] = Demon Hunter Class Hall
      • Set VariableSet ClassHall_Type[3] = Demon Hunter Class Hall
      • Set VariableSet ClassHall_Type[4] = Death Knight Class Hall
      • Set VariableSet ClassHall_Type[5] = Death Knight Class Hall
      • Set VariableSet ClassHall_Type[6] = Death Knight Class Hall
      • Set VariableSet ClassHall_Type[7] = Druid Class Hall
      • Set VariableSet ClassHall_Type[8] = Druid Class Hall
      • Set VariableSet ClassHall_Type[9] = Druid Class Hall
      • Set VariableSet ClassHall_Type[10] = Paladin Class Hall
      • Set VariableSet ClassHall_Type[11] = Paladin Class Hall
      • Set VariableSet ClassHall_Type[12] = Paladin Class Hall
      • Set VariableSet ClassHall_Type[13] = Warrior Class Hall
      • Set VariableSet ClassHall_Type[14] = Warrior Class Hall
      • Set VariableSet ClassHall_Type[15] = Warrior Class Hall
      • Set VariableSet ClassHall_Type[16] = Hunter Class Hall
      • Set VariableSet ClassHall_Type[17] = Hunter Class Hall
      • Set VariableSet ClassHall_Type[18] = Hunter Class Hall
      • Set VariableSet ClassHall_Type[19] = Rogue Class Hall
      • Set VariableSet ClassHall_Type[20] = Rogue Class Hall
      • Set VariableSet ClassHall_Type[21] = Rogue Class Hall
      • Set VariableSet ClassHall_Type[22] = Shaman Class Hall
      • Set VariableSet ClassHall_Type[23] = Shaman Class Hall
      • Set VariableSet ClassHall_Type[24] = Shaman Class Hall
      • Set VariableSet ClassHall_Type[25] = Mage Class Hall
      • Set VariableSet ClassHall_Type[26] = Mage Class Hall
      • Set VariableSet ClassHall_Type[27] = Mage Class Hall
      • Set VariableSet ClassHall_Type[28] = Priest Class Hall
      • Set VariableSet ClassHall_Type[29] = Priest Class Hall
      • Set VariableSet ClassHall_Type[30] = Priest Class Hall
      • Set VariableSet ClassHall_Type[31] = Warlock Class Hall
      • Set VariableSet ClassHall_Type[32] = Warlock Class Hall
      • Set VariableSet ClassHall_Type[33] = Warlock Class Hall
      • Set VariableSet ClassHall_Type[34] = Necromancer Class Hall
      • Set VariableSet ClassHall_Type[35] = Necromancer Class Hall
      • Set VariableSet ClassHall_Type[36] = Necromancer Class Hall
      • Set VariableSet ClassHall_Type[37] = Warden Class Hall
      • Set VariableSet ClassHall_Type[38] = Warden Class Hall
      • Set VariableSet ClassHall_Type[39] = Warden Class Hall
      • Set VariableSet ClassHall_Type[40] = Gronn Class Hall
      • Set VariableSet ClassHall_Type[41] = Gronn Class Hall
      • Set VariableSet ClassHall_Type[42] = Genesaur Class Hall
      • Set VariableSet ClassHall_Type[43] = Genesaur Class Hall
      • Set VariableSet ClassHall_Type[44] = Chronomancer Class Hall
      • Set VariableSet ClassHall_Type[45] = Spellblader Class Hall
      • Set VariableSet ClassHall_Type[46] = Engineer Class Hall
      • Set VariableSet ClassHall_Type[47] = Illidari Class Hall
      • Set VariableSet ClassHall_Type[48] = Elder Sage Class Hall
      • Set VariableSet ClassHall_Type[49] = Beastmaster Class Hall
      • Set VariableSet ClassHall_Type[50] = Pandaren Brewmaster Class Hall
      • Set VariableSet ClassHall_Type[51] = Mountain King Class Hall
      • Set VariableSet ClassHall_Type[52] = Keeper of the Grove Class Hall
      • Set VariableSet ClassHall_Type[53] = Naga Sea Witch Class Hall
      • Set VariableSet ClassHall_Type[54] = Blademaster Class Hall
      • Set VariableSet ClassHall_Type[55] = Alchemist Class Hall
      • Set VariableSet ClassHall_Type[56] = Firelord Class Hall
      • -------- Hero Types --------
      • Set VariableSet Hero_Type[1] = |c00990099Demon Hunter HAVOC|r
      • Set VariableSet Hero_Type[2] = |c00990099Demon Hunter VENGEANCE|r
      • Set VariableSet Hero_Type[3] = |c00990099Demon Hunter TORMENTOR|r
      • Set VariableSet Hero_Type[4] = |c00990000Death Knight BLOOD|r
      • Set VariableSet Hero_Type[5] = |c00990000Death Knight FROST|r
      • Set VariableSet Hero_Type[6] = |c00990000Death Knight UNHOLY|r
      • Set VariableSet Hero_Type[7] = |c00ff6600Druid FERAL|r
      • Set VariableSet Hero_Type[8] = |c00ff6600Druid GUARDIAN|r
      • Set VariableSet Hero_Type[9] = |c00ff6600Druid RESTORATION|r
      • Set VariableSet Hero_Type[10] = |c00ff6666Paladin HOLY|r
      • Set VariableSet Hero_Type[11] = |c00ff6666Paladin PROTECTION|r
      • Set VariableSet Hero_Type[12] = |c00ff6666Paladin RETRIBUTION|r
      • Set VariableSet Hero_Type[13] = |cffa56f34Warrior ARMS|r
      • Set VariableSet Hero_Type[14] = |cffa56f34Warrior FURY|r
      • Set VariableSet Hero_Type[15] = |cffa56f34Warrior PROTECTION|r
      • Set VariableSet Hero_Type[16] = |c0066cc00Hunter BEAST MASTERY|r
      • Set VariableSet Hero_Type[17] = |c0066cc00Hunter MAKRSMANSHIP|r
      • Set VariableSet Hero_Type[18] = |c0066cc00Hunter SURVIVAL|r
      • Set VariableSet Hero_Type[19] = |c00ffff33Rogue ASSASSINATION|r
      • Set VariableSet Hero_Type[20] = |c00ffff33Rogue OUTLAW|r
      • Set VariableSet Hero_Type[21] = |c00ffff33Rogue SUBTLETY|r
      • Set VariableSet Hero_Type[22] = |c000033ccShaman EARTHFURY|r
      • Set VariableSet Hero_Type[23] = |c000033ccShaman ELEMENTAL|r
      • Set VariableSet Hero_Type[24] = |c000033ccShaman RESTORATION|r
      • Set VariableSet Hero_Type[25] = |c0066ffffMage ARCANE|r
      • Set VariableSet Hero_Type[26] = |c0066ffffMage FIRE|r
      • Set VariableSet Hero_Type[27] = |c0066ffffMage FROST|r
      • Set VariableSet Hero_Type[28] = |c00ffffffPriest DISCIPLINE|r
      • Set VariableSet Hero_Type[29] = |c00ffffffPriest HOLY|r
      • Set VariableSet Hero_Type[30] = |c00ffffffPriest SHADOW|r
      • Set VariableSet Hero_Type[31] = |c009966ffWarlock AFFLICTION|r
      • Set VariableSet Hero_Type[32] = |c009966ffWarlock DEMONOLOGY|r
      • Set VariableSet Hero_Type[33] = |c009966ffWarlock DESTRUCTION|r
      • Set VariableSet Hero_Type[34] = |c00006666Necromancer CHAOS|r
      • Set VariableSet Hero_Type[35] = |c00006666Necromancer DARK|r
      • Set VariableSet Hero_Type[36] = |c00006666Necromancer UNHOLY|r
      • Set VariableSet Hero_Type[37] = |c0099ff00Warden KNIFER|r
      • Set VariableSet Hero_Type[38] = |c0099ff00Warden ESCAPER|r
      • Set VariableSet Hero_Type[39] = |c0099ff00Warden ILLUSIONIST|r
      • Set VariableSet Hero_Type[40] = |c00999900Gronn MARAUDER|r
      • Set VariableSet Hero_Type[41] = |c00999900Gronn CHAINER|r
      • Set VariableSet Hero_Type[42] = |c00009966Genesaur DOCTOR|r
      • Set VariableSet Hero_Type[43] = |c00009966Genesaur BRUTE|r
      • Set VariableSet Hero_Type[44] = |c00ccccccChronomancer|r
      • Set VariableSet Hero_Type[45] = |c007EBFF1Spellblader|r
      • Set VariableSet Hero_Type[46] = |cffecce87Engineer|r
      • Set VariableSet Hero_Type[47] = |c00ccff66Illidari FELREAPER|r
      • Set VariableSet Hero_Type[48] = |c009966ffElder Sage|r
      • Set VariableSet Hero_Type[49] = |c00FF8C00Beastmaster|r
      • Set VariableSet Hero_Type[50] = |c0000FF7FPandaren Brewmaster|r
      • Set VariableSet Hero_Type[51] = |c001E90FFMountain King|r
      • Set VariableSet Hero_Type[52] = |c00008B8BKeeper of the Grove|r
      • Set VariableSet Hero_Type[53] = |c0020B2AANaga Sea Witch|r
      • Set VariableSet Hero_Type[54] = |c00B22222Blademaster|r
      • Set VariableSet Hero_Type[55] = |c007FFFD4Alchemist|r
      • Set VariableSet Hero_Type[56] = |c00800000Firelord|r
      • -------- Hero Classes --------
      • -------- Demon Hunter --------
      • Set VariableSet Hero_Class[1] = 1
      • Set VariableSet Hero_Class[2] = 1
      • Set VariableSet Hero_Class[3] = 1
      • -------- Death Knight --------
      • Set VariableSet Hero_Class[4] = 2
      • Set VariableSet Hero_Class[5] = 2
      • Set VariableSet Hero_Class[6] = 2
      • -------- Druid --------
      • Set VariableSet Hero_Class[7] = 3
      • Set VariableSet Hero_Class[8] = 3
      • Set VariableSet Hero_Class[9] = 3
      • -------- Paladin --------
      • Set VariableSet Hero_Class[10] = 4
      • Set VariableSet Hero_Class[11] = 4
      • Set VariableSet Hero_Class[12] = 4
      • -------- Warrior --------
      • Set VariableSet Hero_Class[13] = 5
      • Set VariableSet Hero_Class[14] = 5
      • Set VariableSet Hero_Class[15] = 5
      • -------- Hunter --------
      • Set VariableSet Hero_Class[16] = 6
      • Set VariableSet Hero_Class[17] = 6
      • Set VariableSet Hero_Class[18] = 6
      • -------- Rogue --------
      • Set VariableSet Hero_Class[19] = 7
      • Set VariableSet Hero_Class[20] = 7
      • Set VariableSet Hero_Class[21] = 7
      • -------- Shaman --------
      • Set VariableSet Hero_Class[22] = 8
      • Set VariableSet Hero_Class[23] = 8
      • Set VariableSet Hero_Class[24] = 8
      • -------- Mage --------
      • Set VariableSet Hero_Class[25] = 9
      • Set VariableSet Hero_Class[26] = 9
      • Set VariableSet Hero_Class[27] = 9
      • -------- Priest --------
      • Set VariableSet Hero_Class[28] = 10
      • Set VariableSet Hero_Class[29] = 10
      • Set VariableSet Hero_Class[30] = 10
      • -------- Warlock --------
      • Set VariableSet Hero_Class[31] = 11
      • Set VariableSet Hero_Class[32] = 11
      • Set VariableSet Hero_Class[33] = 11
      • -------- Necromancer --------
      • Set VariableSet Hero_Class[34] = 12
      • Set VariableSet Hero_Class[35] = 12
      • Set VariableSet Hero_Class[36] = 12
      • -------- Warden --------
      • Set VariableSet Hero_Class[37] = 13
      • Set VariableSet Hero_Class[38] = 13
      • Set VariableSet Hero_Class[39] = 13
      • -------- Gronn --------
      • Set VariableSet Hero_Class[40] = 14
      • Set VariableSet Hero_Class[41] = 14
      • -------- Genesaur --------
      • Set VariableSet Hero_Class[42] = 15
      • Set VariableSet Hero_Class[43] = 15
      • -------- Chronomancer --------
      • Set VariableSet Hero_Class[44] = 16
      • -------- Spellblade --------
      • Set VariableSet Hero_Class[45] = 17
      • -------- Engineer --------
      • Set VariableSet Hero_Class[46] = 18
      • -------- Illidari --------
      • Set VariableSet Hero_Class[47] = 19
      • -------- Elder Sage --------
      • Set VariableSet Hero_Class[48] = 20
      • -------- Beastmaster --------
      • Set VariableSet Hero_Class[49] = 21
      • -------- Pandaren Brewmaster --------
      • Set VariableSet Hero_Class[50] = 22
      • -------- Mountain King --------
      • Set VariableSet Hero_Class[51] = 23
      • -------- Keeper of the Grove --------
      • Set VariableSet Hero_Class[52] = 24
      • -------- Naga Sea Witch --------
      • Set VariableSet Hero_Class[53] = 25
      • -------- Blademaster --------
      • Set VariableSet Hero_Class[54] = 26
      • -------- Alchemist --------
      • Set VariableSet Hero_Class[55] = 27
      • -------- Firelord --------
      • Set VariableSet Hero_Class[56] = 28
  • Hero Selection
    • Events
      • Unit - A unit Sells a unit
    • Conditions
    • Actions
      • For each (Integer IntA) from 1 to 56, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Sold unit)) Equal to Hero_Type[IntA]
            • Then - Actions
              • Set VariableSet BuyingU = (Buying unit)
              • Set VariableSet SoldU = (Sold unit)
              • Set VariableSet HeroSpawn = (Center of RegionHeroSpawn <gen>)
              • Set VariableSet MaxPlayers = (Number of players in (All players))
              • Set VariableSet PlayerInteger = (Player number of (Owner of (Sold unit)))
              • Set VariableSet Player[PlayerInteger] = (Owner of (Buying unit))
              • Set VariableSet Hero[PlayerInteger] = (Sold unit)
              • Unit Group - Add (Sold unit) to PlayerHeroes[PlayerInteger]
              • Unit Group - Add Hero[PlayerInteger] to ArenaHeroes
              • Unit Group - Add Hero[PlayerInteger] to AliveHeroes
              • Unit - Explode BuyingU.
              • Unit - Move SoldU instantly to HeroSpawn
              • Camera - Pan camera for (Owner of SoldU) to HeroSpawn over 0.05 seconds
              • Selection - Select SoldU for (Owner of SoldU)
              • Unit - Make SoldU face 270.00 over 0.00 seconds
              • Special Effect - Create a special effect attached to the origin of SoldU using Abilities\Spells\Human\Resurrect\ResurrectTarget.mdl
              • Special Effect - Destroy (Last created special effect)
              • Unit - Create 1 ClassHall_Type[IntA] for (Owner of Hero[PlayerInteger]) at ClassHall_Region[PlayerInteger] facing Default building facing degrees
              • For each (Integer IntB) from 1 to 56, do (Actions)
                • Loop - Actions
                  • For each (Integer CurrentPlayer) from 1 to MaxPlayers, do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Hero_Class[IntA] Equal to Hero_Class[IntB]
                        • Then - Actions
                          • Player - Make Hero_Type[IntB] Unavailable for training/construction by (Player(CurrentPlayer))
                        • Else - Actions
              • Game - Display to (All players) the text: ((|c00996600 + (Name of (Owner of (Buying unit)))) + (|r + ( |c0000cc00decided to conquer the legion forces with|r + (|c00990000 + ((Name of (Sold unit)) + |r)))))
              • Custom script: call RemoveLocation(udg_HeroSpawn)
            • Else - Actions
 
Top