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

HeroScoreFrame

Introduction


HeroScoreFrame is a Frame-UI System for Warcraft 3 V1.31.1 or higher. It is a Hero-Player centric custom UI addition showing current Progress.
During the game it can display the Hero-Icon, current Level, 3 score Values (default unit killed, hero killed, building killed) and the items hold (with their charges and tooltips). The UI is only shown while the player holds a key (default Tab).
HeroScoreFrame is also interactive and the user can use it to: (un)share units with a player, add Player-Heroes to the HeroButtons at the left (of screen) or request to swap/switch.

Available in vjass and Lua.

How to Install:


Export and Import
war3mapImported\HeroScoreFrame.fdf
war3mapImported\HeroScoreFrame.toc
(optional)
war3mapImported\NumberDialog.fdf
war3mapImported\NumberDialog.toc
(WHEN USING THE EXPORT ALL BUTTON, IT CAN HAPPEN THAT THE CONTENT OF the fdf and toc FILES SWAP)

Copy paste Either
HeroScoreFrame vjass (and optional HeroScoreFrameOptions vjass / NumberDialog vjass )
or
TasButtonAction Lua & HeroScoreFrame Lua (and optional NumberDialog Lua )

After the File copy paste and the system copy paste it should work out of the box.

The GUI folder is optional, if you don't want you can skip. It gives events for interactions done with the alliance alteriang part of HeroScoreFrame.

API


JASS:
function HeroScoreFrameSetTargetUnit takes integer createContext, unit u returns nothing
function HeroScoreFrameSetTargetPlayer takes integer createContext, player p returns nothing
function HeroScoreFrameSetScale takes real scale returns nothing
function HeroScoreFrameSetAllyScale takes real scale returns nothing
function HeroScoreFrameSetTooltipScale takes real scale returns nothing
function HeroScoreFrameSetFaceOverlayText takes integer createContext, string text returns nothing
	Set Current Text of the OverlayText, is overwritten every Timeout when a timer is set
function HeroScoreFrameSetTargetTimer takes integer createContext, timer t returns nothing
	Read timer to display AutoReviveTime
function HeroScoreFrameGetPlayerContext takes player p returns integer
function HeroScoreFrameGetTargetPlayer takes integer createContext returns player
function HeroScoreFrameGetTargetUnit takes integer createContext returns unit

HeroScoreFrame throws events for interaction with the Buttons, when the GUI variables exist (Lua) or in vjass when the library HeroScoreFrameEventGUI is a thing.

Config


Some parts of HerScoreFrame can be tweaked within the config found at the top in Table HeroScoreFrame {.
Or in the globals block in the vjass version, but there some are functions right below the globals block.
Lua:
AutoRun = true --(true) will create Itself at 0s, (false) you need to HeroScoreFrameInit()
,TocPath = "war3mapImported\\HeroScoreFrame.toc"
,ParentFunc = function() return BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
,CreateOptions = true
,CreateOptionsInMenu = true
, OptionX = 0.1 
, OptionY = 0.55
-- HideText(true) hides the score Icons and Texts between Face and Items
,HideText = false
-- HideTextPack(true) only works with HideText(true), Then it makes the Frames take less space.
,HideTextPack = true
-- FACE_COLOR_BACKGROUND(true) moves the playercolor below the Face. (false) To the top of a HeroScoreFrame
, FACE_COLOR_BACKGROUND = true
-- AutoSearchTarget, when there is no valid Unit of the UIPlayer of a HeroScoreFrame search one
, AutoSearchTarget = true
, Scale = 0.7
--SizeX Y should match fdf values
,SizeX =  0.22
,SizeXPacked = 0.22 - 0.054
,SizeY = 0.075
-- how many HeroCards are created in InitFrames
, AutoCreateCount = GetBJMaxPlayers()
-- how many HeroCards are in one Col
, Rows = 6
-- X space between 2 Cols
, ColOffsetX = 0

-- Inital TooltipScale
, TooltipScale = 1.0
, TooltipWidth = 0.2
, TooltipFixedPosition = true
, TooltipFixedPositionX = 0.79
, TooltipFixedPositionY = 0.16
, TooltipFixedPositionPoint = FRAMEPOINT_BOTTOMRIGHT

-- can be used to prevent players from taking an UI
-- return false when no UI shall be used by that player
-- only affects auto filling
, AllowedPlayer = function (player)
	if GetPlayerSlotState(player) ~= PLAYER_SLOT_STATE_PLAYING then 
		-- return false
	end

	if (GetPlayerController(player) ~= MAP_CONTROL_USER and GetPlayerController(player) ~= MAP_CONTROL_COMPUTER) then
			return false
	end

	if player == Player(6) or player == Player(0) then
			-- return false
	end
	return true
end

-- FillByTeam(false) fill the UI based on PlayerNumber
-- FillByTeam(true) start with PlayerTeam than PlayerNumber
-- FillByTeam = false is recommented when there are no fixed Teams
, FillByTeam = false
, FillByTeamSkipCols = true
-- postion of the first HeroScoreFrame, 
, X = 0.4
, Y = 0.55
, Point = FRAMEPOINT_TOPRIGHT
-- Key has to be hold to show the UI
, TriggerKey = OSKEY_TAB

, AllyScale = 1.0
-- shown next to Share/Swap Buttons (current State)
, Texture = {
	[false] = "ui\\widgets\\glues\\thumbsdown-up"
	,[true] = "ui\\widgets\\glues\\thumbsup-up"
}

-- Read item specific text/icon, instead of itemCode text/icon.
, DynamicItems = false

-- Fixed postion of the PlayerControl-PopUp,
-- disable fixed position with AllyPoint = false or commenting it out
--, AllyPoint = FRAMEPOINT_TOPRIGHT
, AllyX = 0.79
, AllyY = 0.55
, AutoSwapBot = true
, AllowSwapEnemies = true
, SwitchAllianceType = bj_ALLIANCE_ALLIED_VISION -- choose a bj_ALLIANCE_xxxx
, SwitchAddStates = {ALLIANCE_SHARED_ADVANCED_CONTROL} -- add additional AllianceStates
-- Interpret Swap onto Enemy Players as Team Switch
-- SwapEnemyIsSwitch(true) change Teams, no unit owner change
-- SwapEnemyIsSwitch(false) change unit owner, not Team
, SwapEnemyIsSwitch = true
, AllowSwapAllies = true
, AllowShareAdv = true
, AllowShare = true

, AllowSendGoldAlly = true
, AllowSendLumberAlly = true
, AllowSendGoldEnemy = false
, AllowSendLumberEnemy = false


Changelog


V1.5f) vjass fix
V1.5d/e) Improved SwitchTeam & Setup
V1.5c) Reserve HandleIds for Inventory Display
V1.5b)

Fixed a dc when numberdialog is not included (vjass)
Fixed an weak error when numberdialog is not included (Lua)​
V1.5a)

If one can't send gold nor Lumber than the Send Frames are hidden.
Lua version did break without GUI variables.​
V1.5) Fix a visual Bug with the abused ButtonTexts (new Fdf) (No code changes)
V1.4)

Fix a visual Bug, a small white number was displayed at top left of a HeroScoreFrame
(vjass) Fixed: Hidden HeroScoreFrames were not reshown
Ally Control Frame can have a fixed Position instead of a dynamic
Ally Control Frame will not show when all Allow settings are disabled
AutoHero Finder hides HeroScoreFrames when they have a player, no unit and can't autofind a hero.
Added a Creation Failed Message, check the imported fdf&toc in such a case
V1.3)

Supports now DynamicItems
Changed names of the Frames inside the Ally Box to avoid possible conflicts
Added Send Lumber, Gold for the AllyBox. There are options to allow it for allies/enemies/none​

V1.2) Removed a possible Desync with inital HideText(true)
V1.1)
HeroFaceIcons shows Disabled Textures when the unit is dead.
Added a TextFrame over the Face (for Timed AutoRevive) (new fdf).
Increased the Size of the LevelBox and Level-Font (new fdf).
(vjass) Added - out of bounce Checks for functions: HeroScoreFrameSetTargetPlayer, HeroScoreFrameSetTargetUnit, HeroScoreFrameSetTargetTimer, HeroScoreFrameSetFaceOverlayText
Added Event 5, to set Text, tooltipText and Icons of the Infos Next to the Hero.
Tooltips were not on top
ItemHighlights are now above itemSlot Backgrounds (new fdf).
Added HSF-Options a UI to change Scales, HideText/HideTextPack​
V1) First Release
Previews
Contents

HeroScoreFrame (Map)

Reviews
Archian
Approved! Thanks for providing ingame screenshots!
Updated to V1.1) Highlights
Can display Timed AutoRevive over dead Heroes
Player got a UI to scale/HideText during the game
Event support: changing the Text/Icons/Tooltips next to the HeroFace (also in GUI).

V1.1 uses a new fdf.

HeroFaceIcons show Disabled Textures when the unit is dead.
Added a TextFrame over the Face.
It is only shown while the Unit is Dead. Meant to be used for timed Auto-Revive for it to work one either has to set the Revivetimer or the current text.
Increased the Size of the LevelBox and Level-Font (new fdf).
Added function HeroScoreFrameGetPlayerContext(player)
(vjass) Added - out of bounce Checks for functions: HeroScoreFrameSetTargetPlayer, HeroScoreFrameSetTargetUnit, HeroScoreFrameSetTargetTimer, HeroScoreFrameSetFaceOverlayText
Added Event 5, to set Text, tooltipText and Icons of the Infos Next to the Hero.
Tooltips were not on top
ItemHighlights are now above itemSlot Backgrounds (new fdf).
Added HSF-Options a UI which allows the player to change Scales, HideText/HideTextPack
it either is part of HeroScoreFrame or part of Options.
Update does not Recalc the Size anymore but Reads it from a global
 
Updated to V1.2) A Desync-Fix
Reserved HandleIds for HeroScoreFrameTextIcon1 /2/3 right after the creation, to remove a DC Reason.
When HideText = true, Events are enabled & a player unchecked HideText in the option-UI then a Desync happened, because only for him these frames "entered" the map's script.
 
Updated to V1.3)
Supports now DynamicItems (tooltips/Icon changed for one item by code during runtime)
Changed names of the Frames inside the Ally Box to avoid possible conflicts, (they had generic common Names)
Added Send Lumber, Gold for the AllyBox. Sending Resources Requires NumberDialog ( This is an optional feature, can not include it into your map, HeroScoreFrame still works)
 
Last edited:
Level 13
Joined
Oct 18, 2013
Messages
690
I'd like if there were a couple more configurables. For instant, the 3 icons on each hero card, where do you change that?
 
Hey Tasyen, really cool system.

After looking through it, I disabled all of the share control/resource options, but I do not see a way to disable the selectable box entirely.
Also, is it possible to support more than one hero per player?



Also, when you have 24 heroes active, I think it should shift over to recenter, as the resource/ally box gets cut off as shown below
(perhaps this is handled in something I removed, I deleted everything besides "HeroScoreFrame vjass")
 

Attachments

  • qwerty.png
    qwerty.png
    2.2 MB · Views: 83
Last edited:
I'd like if there were a couple more configurables. For instant, the 3 icons on each hero card, where do you change that?
Either in the HeroScoreFrame_Event becomes Equal to 5.00
Set HeroScoreFrame_Icon[1] to [3]. That allows dynamic changes during the match

Or you change the default Texture in HeroScoreFrame.fdf.
For Frame HeroScoreFrameTextIcon1/2/3
BackdropBackground "replaceabletextures\commandbuttons\btndemolish",

After looking through it, I disabled all of the share control/resource options, but I do not see a way to disable the selectable box entirely.
Right, I forgot about an option/case for that. One can not disable the box without some code/fdf changes. I think you could edit the fdf and remove Frame "FRAME" "HeroScoreFrameAlly" { and all of it until }.
Or you disable the line inside function InitFrames that creates the allyBox CreateGeneratedFrameHeroScoreFrameAlly.

Also, is it possible to support more than one hero per player?
Yes, it is. But the default will not. You would need to manualy give players slots and the unit using it.
The functions doing that
Code:
// function HeroScoreFrameSetTargetUnit takes integer createContext, unit u returns nothing
//  When AutoSearchTarget is active the unit should be owned by the player using that card

// function HeroScoreFrameSetTargetPlayer takes integer createContext, player p returns nothing
//  Makes the HeroScoreFrame with CreateContext target player
//  A HeroSccoreFrame with player null will hide itself

HeroScoreFrameSetTargetPlayer(0, Player(0))
HeroScoreFrameSetTargetPlayer(1, Player(0))
HeroScoreFrameSetTargetPlayer(2, Player(0))
Set Unit = Blutmagier 0000 <gen>
HeroScoreFrameSetTargetUnit(0, udg_Unit)
Set Unit = Paladin 0281 <gen>
HeroScoreFrameSetTargetUnit(1, udg_Unit)
Set Unit = Bergkönig 0282 <gen>
HeroScoreFrameSetTargetUnit(2, udg_Unit)

createContext starts with 0 and reaches bj_MAX_PLAYERS - 1

Also, when you have 24 heroes active, I think it should shift over to recenter, as the resource/ally box gets cut off as shown below
(perhaps this is handled in something I removed, I deleted everything besides "HeroScoreFrame vjass")
It is not handled anywhere. But you could pos the whole thing further left within the globals
// postion of the first HeroScoreFrame,
private real X = 0.4
private real Y = 0.55
private framepointtype Point = FRAMEPOINT_TOPRIGHT

Right now it places itself next to the clicked card and can't leave 4:3, but it would have to for the last col so it malforms.

Thanks for your feedback.
 
Level 13
Joined
Oct 18, 2013
Messages
690
Appreciate that man! i was just diving into the new UI stuff, and hadn't even looked in the .fdf file yet. Thx! (=

edit: If resource trading is entirely disabled, clicking on info cards ideally wouldn't pull up the trade resource tab at all. I gave it 5/5 anyways tho lol ^^
 
Last edited:
Currently getting a disconnect when trying this in Multiplayer when one player tabs and then click on an ally's hero. Have swap ally and enemy off. Don't know what's causing this issue but will look into in the future. In the map heroes are selected via a circle of power system and DO correctly show in the score when pressing tab after being selected, but clicking on an ally's hero causes the DC.

(Using the Vjass one)
 
Last edited:
Thanks for your report.

I relooked at the code: Probably happens when one does not have the numberdialog addon. Then the SendGold/Lumber Frames do not get a handleId right at their creation and then enter the map's code in a Local Player block which is a dc.

Updated to 1.5b)
Fixed a dc when numberdialog is not included (vjass)
Fixed a weak error when numberdialog is not included (Lua)

Small update if you want to do a update by hand to not lose setup:
Only HeroScoreFrame was changed.
Change the Version to 1.5b
vjass)
find function CreateGeneratedFrameHeroScoreFrameAlly
Add this 2 jass Lines to the end of the function
JASS:
call BlzGetFrameByName("HeroScoreFrameAllyIconButtonSendGold", index)
call BlzGetFrameByName("HeroScoreFrameAllyIconButtonSendLumber", index)

Lua)
Find this 2 Lines inside function CreateGeneratedFrameHeroScoreFrameAlly(index)
Lua:
ShowNumberDialog(GetTriggerPlayer(), 2, HeroScoreSendGoldAction)
ShowNumberDialog(GetTriggerPlayer(), 3, HeroScoreSendLumberAction)
and replace them with the one matching it, this will stop the weak error
Lua:
if ShowNumberDialog then
     ShowNumberDialog(GetTriggerPlayer(), 2, HeroScoreSendGoldAction)
end
if ShowNumberDialog then
     ShowNumberDialog(GetTriggerPlayer(), 3, HeroScoreSendLumberAction)
end
 
Updated to V1.5c)
Small update only to the main code section for the function that creates a slot of HeroScoreFrame HeroScoreFrame Lua/ HeroScoreFrame vjass.

Reserve HandleIds for Inventory Display frames of a HeroScoreFrame Slot, which fixes some desync when target Unit/Player of a slot is set in a async manner.

I recomment to disable AutoSearchTarget when one uses slots async.
 
Updated to V1.5d)
Switch Team Now swaps TargetUnit (in the UI)
Can choose the AllianceType after switch inside the config
(Lua) can now use GetPlayerColorTexture (Support for Self Enemy Ally Color)
Added getter TargetUnit/Player
tocpath setting now done in globals
Can now disable AutoCreation with AutoRun = false
(vjass) fixed FillByTeam (false)

Updated to V1.5e)
can choose Parent over ParentFunc from the globals
 
Last edited:
So I may have found an error in the NumberDialog. Whenever I send Gold via this dialog to another player the first time it works, but whenever I try to send Gold again it doesn't work. I've tried looking into LIBRARY_FrameNumberDialog and SendGoldAction, but haven't found any leads. Whatever the case it seems to be zeroing out the gold whenever I tried to send gold from one player to another more than once. Lmk if you find anything. I will continue to bug test.

Edit:
Also if you stop pressing tab whenever the NumberDialog is open, the dialog will still be visible upon pressing tab again.

Edit2:
I put a debug msg in ActionAcceptButton
JASS:
call BJDebugMsg("Value: " + I2S(NumberDialogResult) + " Action: " + R2S(NumberDialogEvent))
And it appears to be working correctly

But this debug msg later on does not appear
JASS:
            call BJDebugMsg("Send Gold: " + I2S(amount) + " " + GetPlayerName(GetTriggerPlayer()) + " -> " + GetPlayerName(SelectedPlayer[GetPlayerId(NumberDialogPlayer)]))

This leads me to believe it has something to do with the SendGoldAction function
Maybe in this part
JASS:
            set trig = CreateTrigger()
            call TriggerRegisterVariableEvent(trig, "NumberDialogEvent", EQUAL, eventNumberGold )
            call TriggerAddAction(trig, function SendGoldAction)

Edit 3:

:peasant-grin:Huzzah! I believe I have solved it.
1. NumberDialogEvent needed to be reset to 0 after the execution of SendGoldAction and SendLumberAction

JASS:
private function SendGoldAction takes nothing returns nothing
            local integer amount = NumberDialogResult
            if GetPlayerState(NumberDialogPlayer, PLAYER_STATE_RESOURCE_GOLD) < amount then
                set amount = GetPlayerState(NumberDialogPlayer, PLAYER_STATE_RESOURCE_GOLD)
            endif
            call AdjustPlayerStateBJ(- amount, NumberDialogPlayer, PLAYER_STATE_RESOURCE_GOLD)
            call AdjustPlayerStateBJ(amount, SelectedPlayer[GetPlayerId(NumberDialogPlayer)], PLAYER_STATE_RESOURCE_GOLD)
            call BJDebugMsg("Send Gold: " + I2S(amount) + " " + GetPlayerName(GetTriggerPlayer()) + " -> " + GetPlayerName(SelectedPlayer[GetPlayerId(NumberDialogPlayer)]))
            set NumberDialogEvent = 0
        endfunction
        private function SendLumberAction takes nothing returns nothing
            local integer amount = NumberDialogResult
            if GetPlayerState(NumberDialogPlayer, PLAYER_STATE_RESOURCE_LUMBER) < amount then
                set amount = GetPlayerState(NumberDialogPlayer, PLAYER_STATE_RESOURCE_LUMBER)
            endif
            call AdjustPlayerStateBJ(- amount, NumberDialogPlayer, PLAYER_STATE_RESOURCE_LUMBER)
            call AdjustPlayerStateBJ(amount, SelectedPlayer[GetPlayerId(NumberDialogPlayer)], PLAYER_STATE_RESOURCE_LUMBER)
            call BJDebugMsg("Send Lumber: " + I2S(amount) + " " + GetPlayerName(GetTriggerPlayer()) + " -> " + GetPlayerName(SelectedPlayer[GetPlayerId(NumberDialogPlayer)]))
            set NumberDialogEvent = 0
        endfunction



2. The ActionAcceptButton needed to reset the value of Value[playerId] to 0 after a player hits accepts and the frame needed to be updated as well. (I also added a local for playerId here)

JASS:
private function ActionAcceptButton takes nothing returns nothing
        local integer playerId = GetPlayerId(GetTriggerPlayer())
        set NumberDialogPlayer = GetTriggerPlayer()
        set NumberDialogResult = Value[playerId]
        set NumberDialogEvent = Action[playerId]
        // call BJDebugMsg("Value: " + I2S(NumberDialogResult) + " Action: " + R2S(NumberDialogEvent))
        set Value[playerId] = 0
        if GetLocalPlayer() == NumberDialogPlayer then
            call BlzFrameSetText(BlzGetFrameByName("NumberDisplayText", 0), I2S(Value[playerId]))
        endif
        call BlzFrameSetVisible(BlzFrameGetParent(BlzGetTriggerFrame()), false)
    endfunction
    private function ActionCancelButton takes nothing returns nothing
        local integer playerId = GetPlayerId(GetTriggerPlayer())
        if Value[playerId] == 0 then
            call BlzFrameSetVisible(BlzFrameGetParent(BlzGetTriggerFrame()), false)
        else
            set Value[playerId] = 0
            call Add(GetTriggerPlayer(), 0)
        endif
    endfunction
 
Last edited:
Top