• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Talent Jui

What is Talent Jui



Talent Jui is the 3. edition of my resource Talent. It offers a choice talent system similar to heroes of the storm. On levels you decided, heroes/units can pick one talent from a group of choices (tier) specially defined for that unitTyped. This system works for any amount of units at the same time. But one player can only obeserve talents of one unit at one time. Talent Jui provides a custom created dialog (which can be slightly customized) to perform the choices from the player perspective. Choices and tiers are created using jass/GUI. Cause of using the frame natives, Talent Jui does not need any object Editor data to manage itself.
This system also includes an easy way to create unlearning/reseting choices.

How to install


Requiers Warcraft 3 1.31+
  • Make sure World Editor generates unknown variables in Preferences is set.
  • Copy the Talent Folder.
  • update references inside Talent Init
  • export
    • war3mapImported\TalentBox.fdf
      war3mapImported\TalentBox.toc
      WHEN USING THE EXPORT ALL BUTTON, IT CAN HAPPEN THAT THE CONTENT OF THIS FILES SWAP
    • import them into your map
  • Installed

How to Use



You have to feed the talent data with choices and tiers for unitTypes that shall use talent. Also your choices needs to activade code/triggers when they were picked. Talent provides 2 ways to handle that: events or code binding. Checkout the examples included in the map for that.

Lua version



The Lua Version has differences to the jass Version outside of beeing not jass. In the jass Version Level 0 was a valid Level for a Tier. The Lua Version starts with Level 1. It has a different api when not using the GUI triggers. The Trigger binding is gone, Lui calls binded functions instead of Triggers. Each Choice is a table, one can attach data to it like to any table. Cause it is dangerous to execute stuff in the root (crash wise and garbage collector wise) The Lua Version starts a 0.0s timer after it passed registered so named "unitSheetsFunctions" are called which should be the Custom Unit Talent Trees (checkout the Hero Demos). UnitSheetsFunctions are only relevant when using Lua directly. When using GUI, it is not important.

TasStats



Talent has a feature called TasStats this feature is optional, you could delete it and Talent would still work. It is an "simple" editable addon to make choices add/reduce stats when a specific key for the choice table is set and it reverts it onreset. Unlike the old TalentPreMadeChoice TasStats does not use OnLearn/OnReset.
Having TasStats installed makes picking/reseting choices a little bit heavier. But it reduces the need of OnLearn/OnReset callbacks/Triggers.
TasStats does not work for morphing units or illusions.

Lua

jass


On default TasStats provides this keys for stats
Lua:
TasStr
TasAgi
TasInt
TasLife
TasLifeReg
TasMana
TasManaReg
TasArmor
TasDamage
TasAttackSpeed
TasTurnSpeed
TasCastPoint
TasCastBackswing
Using it is done this way (inside a UnitSheet:
Lua:
local choice
-- create a choice
choice = TalentHeroCreateChoiceEx()
-- set TasStat - TasLife to 200
choice.TasLife = 200
choice.TasMana = 100
choice.TasArmor = 1
-- Set Title
choice.Head = "Sustain Healer"
-- set icon
choice.Icon = "ReplaceableTextures\\CommandButtons\\BTNForestTrollShadowPriest.blp"
-- autocalc Text
TalentTasStatsGetText()

TasStats (Lua version) has another feature it can change integer/real(Level) fields of abilities which is done over the Choice.Key TasSpellField.
One has to be aware that to use this feature without wierd results, the ability-fields current value should not be set to x only add value x to it.
An example
Lua:
choice = TalentHeroCreateChoiceEx()
choice.TasSpellField = {
    -- change Ability Anh1
    Anh1 = {
        -- reduce manacosts of all levels by 2
        ABILITY_ILF_MANA_COST = -2
        -- reduce cooldown by 0.1 seconds
        ,ABILITY_RLF_COOLDOWN = -0.1
    }
}

Ability Fields support Level specific changes, instead of a number use a table
choice.TasSpellField = {
    -- holy Light
    AHhb = {
        -- reduce cooldown of Level 3 (object Editor Level 3)
        ABILITY_RLF_COOLDOWN = {-0, -0, -5}
        -- Instead of Listing the 0s you could write to an int index. Don't forget the [], if you plan to use this feature.
        ABILITY_RLF_COOLDOWN = {[3] = -5}
    }

the Jass version has a set of array variables, when you set a value at the index of the choice. Then it will adjuste the wanted base stat when the choice is picked.
This are the arrays
JASS:
integer array udg_TalentTasStatStr
integer array udg_TalentTasStatAgi
integer array udg_TalentTasStatInt
integer array udg_TalentTasStatLife
integer array udg_TalentTasStatMana
real array udg_TalentTasStatLifeReg
real array udg_TalentTasStatManaReg
real array udg_TalentTasStatArmor
integer array udg_TalentTasStatDamage
real array udg_TalentTasStatAttackSpeed
real array udg_TalentTasStatCastPoint
real array udg_TalentTasStatCastBackswing
use udg_TalentChoiceLast to get the index used by the last created Choice, right after you created a Choice.
The GUI example below adds 20 Base-ATK on pick
  • Set TalentGUI_UnitType = Bergkönig
  • Set TalentGUI_Level = 1
  • Set TalentGUI_ChoiceHead = Axe
  • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNOrcMeleeUpOne.blp
  • Set TalentGUI_ChoiceText = Gain 20 Base-ATK
  • Trigger - Run TalentGUICreateChoice (ignoring conditions)
  • Set TalentTasStatDamage[TalentChoiceLast] = 20


Credits


Nestharus
Bribe
Luashine


ChangeLog

1.38 LUI/1.36e JUI) Icon Show Button, Useage conditions.
1.37) (Lua) Unit Specific TalentTrees
1.36d) (vjass) Fixed an minior Error in TalentGrid
1.36c)
Added OnlyOwnUnit & FixedTarget
Lua) Fixed some problems with TalentBox
1.36b) Lua)
Reworked the Included Save&Load helpers
improved TalentGrid Settings​
1.36
Added a new additional UI
A model hints a possible choice​
1.35b (v)jass)
Added TasTalentStat , without AbilityField
Model over the show Button hints a possible choice
Moved TalentChoiceCreateAddSpells & TalentChoiceCreateReplaceSpell from Premade into Talent
Added function TalentChoiceAddSpells​
1.35a

Added GroupMode
more support for GetLocalizedString​
1.35

TalentGUIAddSpell resets the Spell to 0 after usage
Added the tooltip from TasButtonList
Can Hide choiceText+Box
(Lua)
Improved error messages for UnitSheets callbacks.
+function TalentChoiceAddSpells(choice, "AHbz,AHwe,AHab,AHmt")
+Talent.TasStats (choice add stats/AbilityFields)
Removed TalentPreMadeChoice
fixed some mp unSafe code​
1.34d

Supports Localized data for choices
(jass) FrameLoader is optional now
(Lua) Improved OnLearn/OnReset callback functions
(Lua) Talent-functions taking ObjectEditor ObjectCodes now work without putting them into FourCC.​
1.34c (vjass only) repeats the toc Loding after Loading the game
1.34b Recreates all Talent custom UI, after Loading the game to counter Save&Load Bug.
1.34a Fixed a possible desync with the Lua version
1.34 Added function TalentGetMacro(unit) it returns a text that could be used in TalentMacroDo to pick the talents the unit had done.
1.33

Resets the Talent Event real before Setting it to the wanted value.
TalentBox will now close when the current Selected Target dies.
TalentBox will now close after doing a choice and no further choice can be done.
Maybe the overglowing was fixed.​
1.32a Fixed a bug in Lui with Talents beeing unselectable when adding abilties.
1.32.00

Improved the Dialog for allied shared Units.
Improved Level Boxes and Page switching.
fixed a bug with the Reset Button will be disable on Level not beeing the current selection.
One can now alter the space between Choice, the Bottom and the top.
Added an boolean array to disable the reset button as long that boolean is true.
Added udg_Talent__UnitCode inside Events binded Code it is the unitType beeing used by udg_Talent__Unit.
The Choice-Description fuses now with the Bottom and Right of the Choice Frame.
Fixed a glitch with disabled Reset Button.
Non Talent Users Show now a Box with the title reading "No Talent User".
Added a Lua Version​
Requiers Warcraft 3 1.31+

Keywords: SkillTree, Talents, masteries, hots like, hero progress, 1 of 3, 1 of 2, 1 of many.
Contents

Talent Jui 1.36f (Map)

Talent Lui 1.38a (Map)

Reviews
MyPad
Tested, and works very well with the game. Approved.
Correct me if I'm wrong but there appear to be a few minor leaks throughout the JASS. Basically, they always occur during error catching, where when function should not fire due to it not being the correct player, but the locals are failed to be cleaned up when returning. I forget where I saw a few other errors like this, they are few and far between but also wanted to double-check if this would cause a leak.
Your are right. This are indeed minior leaks in jass. As they prevent that the handleId of unit u is reused as soon unit u is removed from the Game.
 
The system did not create code to do that, Therefore you need to write/change some code when you want that.
if you mod a version with BlzFrameGetChild you could set the texture of child [0] [1] [2] & [3] of open button to the wanted Icon. After Talent created the UI-Frames should be (1s expired event). use on some of the lines from the hidden tag. but only use the lines for the UI mode you use (Grid/Box). Running them when the Show Button is missing probably crashs warcraft 3.

Code:
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 0) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 1) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 2) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 3) , iconPath, 0, false)

BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 0) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 1) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 2) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 3) , iconPath, 0, false)


call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 0) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 1) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 2) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 3) , iconPath, 0, false)

call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 0) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 1) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 2) , iconPath, 0, false)

or You would need to change the code that creates the open button and create a button with instead. The show button is in the grid or box script and you would search for such lines

set FrameShow = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentGridShowButton",
local framehandle showButton = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentShowButton"

TalentGrid.Frame.Show = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentGridShowButton",
TalentBox.Frame.Show = BlzCreateFrameByType("GLUETEXTBUTTON"
 
Level 5
Joined
Oct 31, 2011
Messages
80
The system did not create code to do that, Therefore you need to write/change some code when you want that.
if you mod a version with BlzFrameGetChild you could set the texture of child [0] [1] [2] & [3] of open button to the wanted Icon. After Talent created the UI-Frames should be (1s expired event). use on some of the lines from the hidden tag. but only use the lines for the UI mode you use (Grid/Box). Running them when the Show Button is missing probably crashs warcraft 3.

Code:
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 0) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 1) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 2) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentGrid.Frame.Show, 3) , iconPath, 0, false)

BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 0) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 1) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 2) , iconPath, 0, false)
BlzFrameSetTexture(BlzFrameGetChild(TalentBox.Frame.Show, 3) , iconPath, 0, false)


call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 0) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 1) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 2) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton", 0), 3) , iconPath, 0, false)

call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 0) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 1) , iconPath, 0, false)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton", 0), 2) , iconPath, 0, false)

or You would need to change the code that creates the open button and create a button with instead. The show button is in the grid or box script and you would search for such lines

set FrameShow = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentGridShowButton",
local framehandle showButton = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentShowButton"

TalentGrid.Frame.Show = BlzCreateFrameByType("GLUETEXTBUTTON", "TalentGridShowButton",
TalentBox.Frame.Show = BlzCreateFrameByType("GLUETEXTBUTTON"
Thank you very much, I will try!
 
Level 5
Joined
Oct 31, 2011
Messages
80
Another question, how do I remove all talent choices from a hero and add other talent choices? Like in RPGs where the mage class is fire and changes to ice and the talent tree changes completely.
 
This system is an unitcode/unittype based system. Therefore changing a talent-Tree for one unit is not supported.
you could morph the hero, that makes your unit use a different talent tree.
There is also the use Talents of another unitcode, but it only supports unitCode -> unitCode. (now I wonder why I did not allow to treat one unit as another unitCode?)
Lua:
  TalentHeroCopy(unitCode, copyOrigin)
JASS:
 call TalentHeroSetCopy('H003', 'H001')	//'H003' uses the same talents as 'H001'

When that mage is only picked once in the match your could change the current used one. By TalentHeroCopy or TalentHeroSetCopy inside the Choice Action

Removing Tier-choices has no api and I don't want to talk about that right now as that would be to much.
 
Level 5
Joined
Oct 31, 2011
Messages
80
I understood. Example, I have a hero and I use an integer variable, when my integer variable has the value 1 that hero has a talent tree, and when I change this variable to 2 I have another one and so on during the game.
 
Your example is almost right, it is just a variable inside Talent. Hence you need to use that function. When none such value is stored it uses the own unitCode/HeroClass (default).

Edit: Updated Talent Lui to V1.37)
TalentGetUnitCode & TalentHeroCopy now also work for specific units -> specific units can now be given a wanted Talent Tree.
Updated Talent, TalentGrid & TalentBox

Checkout the 3 new GUI demo Triggers, when one wants to give an non Talent User a TalentTree one needs to do some steps.

  • Antonidas Copy bloodmage
    • Events
      • Time - Elapsed game time is 2.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Antonidas
      • Set Talent__Unit = Antonidas 0059 <gen>
      • -------- Create Unit data --------
      • Custom script: TalentAddUnit(udg_Talent__Unit)
      • -------- If the unit already has picked Talents it might be smart to first reset it --------
      • Custom script: TalentMacroDo(udg_Talent__Unit, "-u")
      • -------- Make Unit Copy Bloodmage --------
      • Custom script: TalentHeroCopy(udg_Talent__Unit, 'H005')
      • -------- Tell Talent to check for possible choices --------
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Antonidas done
  • Sylva Copy Antonidas
    • Events
      • Time - Elapsed game time is 3.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Ranger
      • Set Talent__Unit = Sylvanas Windrunner 0060 <gen>
      • Set Unit = Antonidas 0059 <gen>
      • Custom script: TalentAddUnit(udg_Talent__Unit)
      • Custom script: TalentHeroCopy(udg_Talent__Unit, udg_Unit)
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Ranger Done
      • Wait 5.00 seconds
      • -------- Change another time --------
      • Set Talent__Unit = Sylvanas Windrunner 0060 <gen>
      • Game - Display to (All players) the text: Ranger Copy Pala
      • Custom script: TalentMacroDo(udg_Talent__Unit, "-u")
      • Custom script: TalentHeroCopy(udg_Talent__Unit, 'H001')
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Ranger Done
 
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
Your example is almost right, it is just a variable inside Talent. Hence you need to use that function. When none such value is stored it uses the own unitCode/HeroClass (default).

Edit: Updated Talent Lui to V1.37)
TalentGetUnitCode & TalentHeroCopy now also work for specific units -> specific units can now be given a wanted Talent Tree.
Updated Talent, TalentGrid & TalentBox

Checkout the 3 new GUI demo Triggers, when one wants to give an non Talent User a TalentTree one needs to do some steps.

  • Antonidas Copy bloodmage
    • Events
      • Time - Elapsed game time is 2.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Antonidas
      • Set Talent__Unit = Antonidas 0059 <gen>
      • -------- Create Unit data --------
      • Custom script: TalentAddUnit(udg_Talent__Unit)
      • -------- If the unit already has picked Talents it might be smart to first reset it --------
      • Custom script: TalentMacroDo(udg_Talent__Unit, "-u")
      • -------- Make Unit Copy Bloodmage --------
      • Custom script: TalentHeroCopy(udg_Talent__Unit, 'H005')
      • -------- Tell Talent to check for possible choices --------
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Antonidas done
  • Sylva Copy Antonidas
    • Events
      • Time - Elapsed game time is 3.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Ranger
      • Set Talent__Unit = Sylvanas Windrunner 0060 <gen>
      • Set Unit = Antonidas 0059 <gen>
      • Custom script: TalentAddUnit(udg_Talent__Unit)
      • Custom script: TalentHeroCopy(udg_Talent__Unit, udg_Unit)
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Ranger Done
      • Wait 5.00 seconds
      • -------- Change another time --------
      • Set Talent__Unit = Sylvanas Windrunner 0060 <gen>
      • Game - Display to (All players) the text: Ranger Copy Pala
      • Custom script: TalentMacroDo(udg_Talent__Unit, "-u")
      • Custom script: TalentHeroCopy(udg_Talent__Unit, 'H001')
      • Custom script: TalentAddSelection(udg_Talent__Unit)
      • Game - Display to (All players) the text: Ranger Done
Very good, your triggers are very good, they help the community a lot. This talent is one of the most interesting I've ever seen. I always follow to see if there are new updates.
 
unit specific talent trees was added in V1.37, vjass version is on V1.36d so it does not have it.

But one is able to replace/change the current TalentTree for an unitCode during a match or swap out Tiers at wanted Levels. the given api for tiers and choices (Talenttree) are mostly about adding.

One can use TalentHeroSetCopy to use a different talentree. That also works during match, but one needs to unlearn all talents and restore the talent progress to avoid bugs.
An example that makes all bloodmages swap between Bloodmage & Paladin TalentTree. one would need to do unlearning for all Bloodmages, restore the Talent progress and search for current Talent. If one has more than one bloodmage
  • DemoReplaceBloodMageTree
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetCopy('H005', 'H001')
        • Else - Actions
          • Custom script: call TalentHeroSetCopy('H005', 0)
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)
One could swap out only tiers. But this needs tier-variables.
Lets say we want that Bloodmage can either pick stats or spells at Level 5.
JASS:
//Example for using Talent by Tasyen.
function TalentBloodMage takes nothing returns nothing
	local integer heroTypeId = 'H005'	//Custom BloodMage
	local integer choice
	local integer abilityId

	call TalentHeroSetFinalTier(heroTypeId, 10) 	//Mark Level 10 as last choice, after the heroe picks it, the selection skills are removed.

	call TalentHeroTierCreate(heroTypeId, 0)

	set choice = TalentChoiceCreateAddSpellsSimple("AHfs,ANbf,ANfb") //Create a choice adding this 3 spells and add the choice to the last created Tier
	set udg_TalentChoiceHead[choice] = "Fire Magic"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNFire.blp"
	
	set choice = TalentChoiceCreateAddSpellsSimple("ANfl,AOcl,ANmo")
	set udg_TalentChoiceHead[choice] = "Lightning Magic"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNMonsoon.blp"

	//LEVEL 5
	call TalentHeroTierCreate(heroTypeId, 5)
set udg_BlutMagierTier5[0] = udg_TalentTierLast // store this for later usage

 	set choice = TalentChoiceCreateStats(6, 3, 3)
	set udg_TalentChoiceHead[choice] = "Magic Power: Str"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHelmOfValor.blp"

 	set choice = TalentChoiceCreateStats(3, 6, 3)
	set udg_TalentChoiceHead[choice] = "Magic Power: AGI"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHoodOfCunning.blp"

 	set choice = TalentChoiceCreateStats(3, 3, 6)
	set udg_TalentChoiceHead[choice] = "Magic Power: Int"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNPipeOfInsight.blp"


set udg_BlutMagierTier5[1] = TalentTierCreate() // store this for later usage // this is not used in the default Tree
	set choice = TalentChoiceCreateAddSpellsSimple("AHhb,AHds,AHad") //Create a choice adding this 3 spells and add the choice to the last created Tier
	set udg_TalentChoiceHead[choice] = "Holy Magic"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHolyBolt.blp"

	set choice = TalentChoiceCreateAddSpellsSimple("AHad,AHab,AOae")
	set udg_TalentChoiceHead[choice] = "Aura Magic"
	set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNBrilliance.blp"
	
	//Level 10
	call TalentHeroTierCreate(heroTypeId, 10)

	call TalentChoiceCreateAddSpell('AHpx',true)
	call TalentChoiceCreateAddSpell('AUin',true)


endfunction

//===========================================================================
function InitTrig_Talent_BloodMag_Kopieren takes nothing returns nothing
    set gg_trg_Talent_BloodMag_Kopieren = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Talent_BloodMag_Kopieren, function TalentBloodMage )
endfunction
  • DemoReplaceBloodMageTier
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier2 as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[1])
        • Else - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[0])
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)

I updated the vjass version to include this 2 demos.
 
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
unit specific talent trees was added in V1.37, vjass version is on V1.36d so it does not have it.

But one is able to replace/change the current TalentTree for an unitCode during a match or swap out Tiers at wanted Levels. the given api for tiers and choices (Talenttree) are mostly about adding.

One can use TalentHeroSetCopy to use a different talentree. That also works during match, but one needs to unlearn all talents and restore the talent progress to avoid bugs.
An example that makes all bloodmages swap between Bloodmage & Paladin TalentTree. one would need to do unlearning for all Bloodmages, restore the Talent progress and search for current Talent. If one has more than one bloodmage
  • DemoReplaceBloodMageTree
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetCopy('H005', 'H001')
        • Else - Actions
          • Custom script: call TalentHeroSetCopy('H005', 0)
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)
One could swap out only tiers. But this needs tier-variables.
Lets say we want that Bloodmage can either pick stats or spells at Level 5.
JASS:
//Example for using Talent by Tasyen.
function TalentBloodMage takes nothing returns nothing
    local integer heroTypeId = 'H005'    //Custom BloodMage
    local integer choice
    local integer abilityId

    call TalentHeroSetFinalTier(heroTypeId, 10)     //Mark Level 10 as last choice, after the heroe picks it, the selection skills are removed.

    call TalentHeroTierCreate(heroTypeId, 0)

    set choice = TalentChoiceCreateAddSpellsSimple("AHfs,ANbf,ANfb") //Create a choice adding this 3 spells and add the choice to the last created Tier
    set udg_TalentChoiceHead[choice] = "Fire Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNFire.blp"
   
    set choice = TalentChoiceCreateAddSpellsSimple("ANfl,AOcl,ANmo")
    set udg_TalentChoiceHead[choice] = "Lightning Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNMonsoon.blp"

    //LEVEL 5
    call TalentHeroTierCreate(heroTypeId, 5)
set udg_BlutMagierTier5[0] = udg_TalentTierLast // store this for later usage

     set choice = TalentChoiceCreateStats(6, 3, 3)
    set udg_TalentChoiceHead[choice] = "Magic Power: Str"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHelmOfValor.blp"

     set choice = TalentChoiceCreateStats(3, 6, 3)
    set udg_TalentChoiceHead[choice] = "Magic Power: AGI"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHoodOfCunning.blp"

     set choice = TalentChoiceCreateStats(3, 3, 6)
    set udg_TalentChoiceHead[choice] = "Magic Power: Int"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNPipeOfInsight.blp"


set udg_BlutMagierTier5[1] = TalentTierCreate() // store this for later usage // this is not used in the default Tree
    set choice = TalentChoiceCreateAddSpellsSimple("AHhb,AHds,AHad") //Create a choice adding this 3 spells and add the choice to the last created Tier
    set udg_TalentChoiceHead[choice] = "Holy Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHolyBolt.blp"

    set choice = TalentChoiceCreateAddSpellsSimple("AHad,AHab,AOae")
    set udg_TalentChoiceHead[choice] = "Aura Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNBrilliance.blp"
   
    //Level 10
    call TalentHeroTierCreate(heroTypeId, 10)

    call TalentChoiceCreateAddSpell('AHpx',true)
    call TalentChoiceCreateAddSpell('AUin',true)


endfunction

//===========================================================================
function InitTrig_Talent_BloodMag_Kopieren takes nothing returns nothing
    set gg_trg_Talent_BloodMag_Kopieren = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Talent_BloodMag_Kopieren, function TalentBloodMage )
endfunction
  • DemoReplaceBloodMageTier
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier2 as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[1])
        • Else - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[0])
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)

I updated the vjass version to include this 2 demos.
Very good, thank you for your attention, your systems are always very useful and unique and help keep the Warcraft community alive.

As a suggestion for the next versions, it would be nice to facilitate this change of a hero's talent tree and use an icon instead of the button to access the talents.
 
Level 5
Joined
Oct 31, 2011
Messages
80
Hello friend! Would there be a way to clear a unit's entire talent tree and add a completely new one as many times as I want during the game?

in jass version
 
y, same answer as last time. Jass only has unitTypeId based talenttrees and you can change the tree during the match for all of unitTypeId. But first need to unlearn all choosen talents.

unit specific talent trees was added in V1.37, vjass version is on V1.36d so it does not have it.

But one is able to replace/change the current TalentTree for an unitCode during a match or swap out Tiers at wanted Levels. the given api for tiers and choices (Talenttree) are mostly about adding.

One can use TalentHeroSetCopy to use a different talentree. That also works during match, but one needs to unlearn all talents and restore the talent progress to avoid bugs.
An example that makes all bloodmages swap between Bloodmage & Paladin TalentTree. one would need to do unlearning for all Bloodmages, restore the Talent progress and search for current Talent. If one has more than one bloodmage
  • DemoReplaceBloodMageTree
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetCopy('H005', 'H001')
        • Else - Actions
          • Custom script: call TalentHeroSetCopy('H005', 0)
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)
One could swap out only tiers. But this needs tier-variables.
Lets say we want that Bloodmage can either pick stats or spells at Level 5.
JASS:
//Example for using Talent by Tasyen.
function TalentBloodMage takes nothing returns nothing
    local integer heroTypeId = 'H005'    //Custom BloodMage
    local integer choice
    local integer abilityId

    call TalentHeroSetFinalTier(heroTypeId, 10)     //Mark Level 10 as last choice, after the heroe picks it, the selection skills are removed.

    call TalentHeroTierCreate(heroTypeId, 0)

    set choice = TalentChoiceCreateAddSpellsSimple("AHfs,ANbf,ANfb") //Create a choice adding this 3 spells and add the choice to the last created Tier
    set udg_TalentChoiceHead[choice] = "Fire Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNFire.blp"
   
    set choice = TalentChoiceCreateAddSpellsSimple("ANfl,AOcl,ANmo")
    set udg_TalentChoiceHead[choice] = "Lightning Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNMonsoon.blp"

    //LEVEL 5
    call TalentHeroTierCreate(heroTypeId, 5)
set udg_BlutMagierTier5[0] = udg_TalentTierLast // store this for later usage

     set choice = TalentChoiceCreateStats(6, 3, 3)
    set udg_TalentChoiceHead[choice] = "Magic Power: Str"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHelmOfValor.blp"

     set choice = TalentChoiceCreateStats(3, 6, 3)
    set udg_TalentChoiceHead[choice] = "Magic Power: AGI"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHoodOfCunning.blp"

     set choice = TalentChoiceCreateStats(3, 3, 6)
    set udg_TalentChoiceHead[choice] = "Magic Power: Int"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNPipeOfInsight.blp"


set udg_BlutMagierTier5[1] = TalentTierCreate() // store this for later usage // this is not used in the default Tree
    set choice = TalentChoiceCreateAddSpellsSimple("AHhb,AHds,AHad") //Create a choice adding this 3 spells and add the choice to the last created Tier
    set udg_TalentChoiceHead[choice] = "Holy Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHolyBolt.blp"

    set choice = TalentChoiceCreateAddSpellsSimple("AHad,AHab,AOae")
    set udg_TalentChoiceHead[choice] = "Aura Magic"
    set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNBrilliance.blp"
   
    //Level 10
    call TalentHeroTierCreate(heroTypeId, 10)

    call TalentChoiceCreateAddSpell('AHpx',true)
    call TalentChoiceCreateAddSpell('AUin',true)


endfunction

//===========================================================================
function InitTrig_Talent_BloodMag_Kopieren takes nothing returns nothing
    set gg_trg_Talent_BloodMag_Kopieren = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Talent_BloodMag_Kopieren, function TalentBloodMage )
endfunction
  • DemoReplaceBloodMageTier
    • Events
      • Player - Player 1 (Red) types a chat message containing BlutMagier2 as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Name of the current trigger)
      • Set Talent__Unit = Blutmagier 0024 <gen>
      • Custom script: call TalentMacroDo(udg_Talent__Unit, "-u")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) And 1) Equal to 1
        • Then - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[1])
        • Else - Actions
          • Custom script: call TalentHeroSetTier('H005',5, udg_BlutMagierTier5[0])
      • Custom script: call SaveBoolean(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_HasChoice(), false)
      • Custom script: call SaveInteger(udg_TalentHash, GetHandleId(udg_Talent__Unit), TalentHashIndex_LevelOfLastChoice(), 0)
      • Custom script: call TalentAddSelection(udg_Talent__Unit)

I updated the vjass version to include this 2 demos.
 
Level 5
Joined
Nov 3, 2018
Messages
80
Hey there! i just got back into editing and back your system helped me a lot , thanks!

i had a question about the actual version of the system , is it possible to pick multiple choices for one level or picking choices from previous tiers in other levels?

like for example you have 5 skills on level 1 and you can pick 2 instead of just 1

if this is possible could you provide me with a GUI example pretty please? :)
 
Last edited:
Level 5
Joined
Nov 3, 2018
Messages
80
this system was made to pick only one choice per tier.

One can make choices that give more than one skill.

The same tier can be in multiple levels, but then one could still pick the same option again, there is no feature to disable a choice codewise.
I Understand , thank you very much for replying so quickly! :)

is it possible to make certain talents appear triggering it ? ill try to explain it
Hero has 2 abilities Fireball and Iceball

there's 6 talents in the first talent row (ice and fireball talents) all hidden or non existant atm

HERO LEVELS UP and chooses to learn Fireball
1st row shows/creates 3 talents regarding fireball while keeping the iceball ones hidden/not created

is it possible in gui?
 
It is possible to extend/create a talent tree while the game runs or make an unit use a new/different tree.

Adding an non talent unit to talent was not ported to gui. so easiest to have some talent already for the unitcode.

Gui examples to add new choices after the hero learns a skill using the default warcraft 3 hero learn feature: The examples will change the tree for all instances of that hero, so it best works when each hero is unique.
For this examples the blademaster was given some choice at lvl 1 like all demos do.

  • Talent BladeMaster
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Windlauf
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- ---- --------
      • -------- ---- --------
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Head = Axe
      • Set TalentGUI_Icon = ReplaceableTextures\CommandButtons\BTNOrcMeleeUpOne.blp
      • Set TalentGUI_Text = Gain 20 Base-ATK
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Kritischer Schlag
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Level = 4
      • Set TalentGUI_Spell = Inferno (Tichondrius)
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Hexerei
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Custom script: TalentAddSelection(GetTriggerUnit())
  • Talent BladeMaster Kopieren
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Spiegelbild
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- ---- --------
      • -------- ---- --------
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Spell = Ausdauer-Aura
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Unheilige Aura
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = ReplaceableTextures\CommandButtons\BTNGargoyle.blp
      • Set TalentGUI_Text = 200 Life & Unholy Aura
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_TasLife = 200
      • Trigger - Run TalentGUIAddTasStats (ignoring conditions)


  • Talent Blademaster Expand Windwlak
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Windlauf
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Spell = Gottesschild (Neutral Hostile)
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Heiliges Licht
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Level = 4
      • Set TalentGUI_ChoiceHead = Armor
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNArmorGolem.blp
      • Set TalentGUI_ChoiceText = +500 Max Life
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatLife[TalentChoiceLast] = 500
      • Set TalentGUI_ChoiceHead = ManaStone
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNPendantOfMana.blp
      • Set TalentGUI_ChoiceText = +250 Max Mana
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatMana[TalentChoiceLast] = 250
      • -------- Update Max Talent Level --------
      • Trigger - Run TalentGUI <gen> (ignoring conditions)
  • Talent Blademaster Expand Mirror
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Spiegelbild
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • Set TalentGUI_Level = 10
      • Set TalentGUI_ChoiceHead = Helm
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNHelmOfValor.blp
      • Set TalentGUI_ChoiceText = +6 STR|n+6 AGI
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatAgi[TalentChoiceLast] = 6
      • Set TalentTasStatStr[TalentChoiceLast] = 6
      • Set TalentGUI_Spell = Heiltrank (Geringer)
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • -------- Update Max Talent Level --------
      • Trigger - Run TalentGUI <gen> (ignoring conditions)


Remove/hide you could do, by creating for each an own tree and changing the used one. Because I did not built any feature to remove choices. This tree replace dont work that good with talent reset, therefore either first reset then change or disable the reset feature.
 

Attachments

  • Talent Lui V1.37 Blademaster.w3x
    106.7 KB · Views: 5
  • Talent Jui V1.36d1 Blademaster.w3x
    125.6 KB · Views: 4
Level 5
Joined
Nov 3, 2018
Messages
80
It is possible to extend/create a talent tree while the game runs or make an unit use a new/different tree.

Adding an non talent unit to talent was not ported to gui. so easiest to have some talent already for the unitcode.

Gui examples to add new choices after the hero learns a skill using the default warcraft 3 hero learn feature: The examples will change the tree for all instances of that hero, so it best works when each hero is unique.
For this examples the blademaster was given some choice at lvl 1 like all demos do.

  • Talent BladeMaster
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Windlauf
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- ---- --------
      • -------- ---- --------
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Head = Axe
      • Set TalentGUI_Icon = ReplaceableTextures\CommandButtons\BTNOrcMeleeUpOne.blp
      • Set TalentGUI_Text = Gain 20 Base-ATK
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Kritischer Schlag
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Level = 4
      • Set TalentGUI_Spell = Inferno (Tichondrius)
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Hexerei
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Custom script: TalentAddSelection(GetTriggerUnit())
  • Talent BladeMaster Kopieren
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Spiegelbild
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- ---- --------
      • -------- ---- --------
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Spell = Ausdauer-Aura
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_Text = (Extended Tooltip of TalentGUI_Spell for level 3)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Unheilige Aura
      • Set TalentGUI_Head = (Name of TalentGUI_Spell)
      • Set TalentGUI_Icon = ReplaceableTextures\CommandButtons\BTNGargoyle.blp
      • Set TalentGUI_Text = 200 Life & Unholy Aura
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_TasLife = 200
      • Trigger - Run TalentGUIAddTasStats (ignoring conditions)


  • Talent Blademaster Expand Windwlak
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Windlauf
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • -------- For which Level create choices? --------
      • Set TalentGUI_Level = 1
      • Set TalentGUI_Spell = Gottesschild (Neutral Hostile)
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Spell = Heiliges Licht
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentGUI_Level = 4
      • Set TalentGUI_ChoiceHead = Armor
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNArmorGolem.blp
      • Set TalentGUI_ChoiceText = +500 Max Life
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatLife[TalentChoiceLast] = 500
      • Set TalentGUI_ChoiceHead = ManaStone
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNPendantOfMana.blp
      • Set TalentGUI_ChoiceText = +250 Max Mana
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatMana[TalentChoiceLast] = 250
      • -------- Update Max Talent Level --------
      • Trigger - Run TalentGUI <gen> (ignoring conditions)
  • Talent Blademaster Expand Mirror
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Spiegelbild
    • Actions
      • Trigger - Turn off (This trigger)
      • -------- Who uses this? --------
      • Set TalentGUI_UnitType = Klingenmeister
      • Set TalentGUI_Level = 10
      • Set TalentGUI_ChoiceHead = Helm
      • Set TalentGUI_ChoiceIcon = ReplaceableTextures\CommandButtons\BTNHelmOfValor.blp
      • Set TalentGUI_ChoiceText = +6 STR|n+6 AGI
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • Set TalentTasStatAgi[TalentChoiceLast] = 6
      • Set TalentTasStatStr[TalentChoiceLast] = 6
      • Set TalentGUI_Spell = Heiltrank (Geringer)
      • Set TalentGUI_ChoiceHead = (Name of TalentGUI_Spell)
      • Set TalentGUI_ChoiceIcon = (Icon of TalentGUI_Spell)
      • Set TalentGUI_ChoiceText = (Extended Tooltip of TalentGUI_Spell for level 1)
      • Trigger - Run TalentGUICreateChoice (ignoring conditions)
      • -------- Update Max Talent Level --------
      • Trigger - Run TalentGUI <gen> (ignoring conditions)


Remove/hide you could do, by creating for each an own tree and changing the used one. Because I did not built any feature to remove choices. This tree replace dont work that good with talent reset, therefore either first reset then change or disable the reset feature.
This is excellent just what i needed!

1708543062909.png

you even provided map examples , oh thank you so much friend! :D
 
Level 5
Joined
Nov 3, 2018
Messages
80
so i was doing an ability selection that works with a dialog box (basically you choose a skill and depending on which button of the dialog box you clicked its the one you get so i replicated the trigger i used for getting abilities with the talent tiers and they do appear but they're not clickeable for some reason

any idea what i might be doing wrong? the talents are getting created successfully but i cannot click them

EDIT Solved my issue it was just that a level 1 hero cannot choose a talent
1708643319232.png
 

Attachments

  • 1708643345861.png
    1708643345861.png
    5 KB · Views: 9
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
1710141486656.png


Would it be possible to change the button to a button icon, or could I create a button that calls the talent tree?

What would be the command that calls the talent tree? And how do I disable the default button?

I would also like the command to disappear with the talent button, please.
 
Last edited:
I did not implement an iconButton mode.
if you mod newest warcraft 3 then you can change the Textures used by the show button,do this one after they are created.
JASS:
// GridMode
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton",0), 0), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton",0), 1), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton",0), 2), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentGridShowButton",0), 3), icon, 0, true)

call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton",0), 0), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton",0), 1), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton",0), 2), icon, 0, true)
call BlzFrameSetTexture(BlzFrameGetChild(BlzGetFrameByName("TalentShowButton",0), 3), icon, 0, true)

if you want to show the talent UI by yourself
JASS:
// Box Mode
call BlzFrameSetVisible(BlzGetFrameByName("TalentBox", 0), true)
call BlzFrameSetVisible(BlzGetFrameByName("TalentShowButton", 0), false)
call TalentBoxUpdate(GetTriggerPlayer())

//Grid mode
call BlzFrameSetVisible(TalentGridJUI_FrameParent, true)
call BlzFrameSetVisible(TalentGridJUI_FrameShow, false)
call TalentGridUpdate(GetTriggerPlayer())

I would also like the command to disappear with the talent button, please.
Hides the hero command for one unit only, call BlzUnitHideAbility(udg_Unit, 'AHer', true) beaware that this is counter based, to undo it you need the same amount of falses as you used true for that unit.
One can hide the learn button for all heroes by using a custom "units/commandfunc.txt" file in your map and giving the learn skill the icon coords 0/-11.

good luck
 
Level 5
Joined
Oct 31, 2011
Messages
80
Custom script: call TalentHeroSetCopy(udg_Talent__Unit, GetUnitTypeId(udg_Talent__Unit, 'o00M'))

I did it and it gave me an error.
Use the GetUnitTypeId() function to get a unit's unit-type (aka unit ID):
  • Custom script: call TalentHeroSetCopy(udg_Talent__Unit, GetUnitTypeId(udg_Talent__Unit))
 
Level 5
Joined
Oct 31, 2011
Messages
80
I don't understand how I'm going to declare the two units in it? This call was for one unit to copy another's taelnto tree. Then I had the ID of both of them on that call.
Look at what I wrote and what you wrote. Hint: They're not the same :p

You can just copy and paste my custom script.
1710620050968.png
 

Uncle

Warcraft Moderator
Level 65
Joined
Aug 10, 2018
Messages
6,647
I don't understand how I'm going to declare the two units in it? This call was for one unit to copy another's taelnto tree. Then I had the ID of both of them on that call.
Oh, it takes two Units. You see how it's taking udg_Talent__Unit as the first parameter. Just do that for the second parameter but with your other Unit.
  • Custom script: call TalentHeroSetCopy(udg_Unit_1, udg_Unit_2)
If it were to take two Unit-Types (unit id) then you'd simply wrap your variables with the GetUnitTypeId() function:
  • Custom script: call TalentHeroSetCopy(GetUnitTypeId(udg_Unit_1), GetUnitTypeId(udg_Unit_2))
Or a combination of the two.
 
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
This System is very good, Taysen always has great systems that contribute a lot to the community. I would like to leave some suggestions if there is an update following suggestions.

Option for heroes to have more than one Talent Tree and be able to switch between them at any time, just like World of Warcraft where each Class has 2 to 4 Talent Trees each for a role, for example tank, DPS, and Healer.

An icon as a button instead of the current one. icon button that does not take up the skill space.

Option to disable the tree option if the hero is outside a safe region, or in combat.

These are just these 3 suggestions because the system already does the rest very well.
 
Option for heroes to have more than one Talent Tree and be able to switch between them at any time, just like World of Warcraft where each Class has 2 to 4 Talent Trees each for a role, for example tank, DPS, and Healer.
I dont want to extend the system in this direction. There is another public Talent system quite fitting for wow trees. This, my, system aimed more to be something like Heroes of the Storm.

An icon as a button instead of the current one. icon button that does not take up the skill space.

Option to disable the tree option if the hero is outside a safe region, or in combat.
Okay, I add this 2 suggestions (icon button + Talent useage condition), they are good.

Edit: Updated Lua version to V1.38
ShowButton can be an IconButton also can set Size
One can know have an condition to block using Talent.
Talent can now be setuped to not create itself automatic

On default the UseCondition will try to use a GUI Trigger which has to be named "TasTalent_UseCondition" or "TasTalent UseCondition"
  • TasTalent_UseCondition
    • Events
    • Conditions
      • (Talent__Unit is alive) Equal to True
      • (Talent__Unit is paused) Equal to False
      • Or - Any (Conditions) are true
        • Conditions
          • (Talent__Unit has buff Inneres Fire) Equal to True
          • (Talent__Unit is A Hero) Equal to True
    • Actions
      • -------- Talent GUI use Condition, optinal default conditions --------
      • -------- only conditions are used, with Talent__Unit --------
      • -------- This Trigger needs to be called "TasTalent_UseCondition" or "TasTalent UseCondition" --------
one could change the UseCondition in Settings of Talent.

Edit: Updated vjass to 1.36e
ShowButton can be an IconButton also can set Size
One can know have an condition to block using Talent
the Condition requies a GUI trigger existing, if you dont want that remove it from the Talent code.
 
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
I dont want to extend the system in this direction. There is another public Talent system quite fitting for wow trees. This, my, system aimed more to be something like Heroes of the Storm.
I understand, but wouldn't it be possible to change the talent tree and declare the unit as a Variable instead of an ID?

Instead of this:
  • Custom script: call TalentHeroSetCopy('H005', 'H001')
Being able to declare it this way:
  • Custom script: call TalentHeroSetCopy('udg_Talent__unit', 'udg_Hero_unit')

one could change the UseCondition in Settings of Talent.

Edit: Updated vjass to 1.36e
ShowButton can be an IconButton also can set Size
One can know have an condition to block using Talent
the Condition requies a GUI trigger existing, if you dont want that remove it from the Talent code.

This is very good, one of the best systems here, the other is also yours than TasItemBag. If you could update the button icon in TalentGrid too, that would be amazing, TalentGrid has a great designer.
 
Last edited:
You are right with some small changes to the vjass system one can have the unit specific Talents by using the TalentHeroSetCopy feature.
Thanks for your will, I didn't consider that it was that easy to make, was expecting that I needed to do big changes. But all it took was changing a constant to avoid data colisions in unit handle data and adding an if check.

Updated vjass to 1.36f) an specific unit can now use an wanted Talent of unitCode.
Has 2 demos that make one dwarf only; use Paladin talents and another to make that dwarf use Uther Talents instead.

aye, thats how to do this, udg_Talent__Unit use 'H001'.
  • Custom script: call TalentHeroSetCopy(GetHandleId(udg_Talent__Unit), 'H001')
Edit:
This is very good, one of the best systems here, the other is also yours than TasItemBag. If you could update the button icon in TalentGrid too, that would be amazing, TalentGrid has a great designer.
Both Modes should support the Icon Button feature. But the default setup is: one Text Mode other Icon mode.
 
Last edited:
Level 5
Joined
Oct 31, 2011
Messages
80
Both Modes should support the Icon Button feature. But the default setup is: one Text Mode other Icon mode.
Sorry if I ask too many questions, I have little knowledge of vjass, is it complicated to add the icon button to TalentGrid?
 
it is easy, you open TalentGrid between globals and endglobals you find variables used by the system. Search for
private string ShowButtonIcon = ""
now insert your wanted IconFilePath into "".
next to ShowButtonIcon you also find other options for the ShowButton

When the path contains \ use \\ or use /
 
Level 5
Joined
Oct 31, 2011
Messages
80
1712434503709.png


Taysen, what command does this button use to reset talents?

If I want to reset talents using an item or something similar.
 
Level 5
Joined
Oct 31, 2011
Messages
80
Tasyen, you contribute a lot to the warcraft community, as do other developers here. I would like to pay tribute to everyone who contributes resources here.

And rather than putting the names of all those I use resources here I will use the names for the characters in my game (map).

As an example in the image I made to honor you.

It is written: Tasyen, Hivework High King.
1712683423079.png
 
y, you use call BlzFrameSetVisible(frame, false) onto the show buttons and the talentbox/grid, when the cinematic starts.

After the cinematic you call BlzFrameSetVisible(frame, true) them to reshow it.

Edit:
For frame you use one of these
BlzGetFrameByName("TalentGridShowButton", 0)
BlzGetFrameByName("TalentShowButton", 0)
 
Last edited:
Level 4
Joined
Jan 9, 2024
Messages
38
Another question:
After I started using a custom inventory UI in my map, the talents won't show up anymore.
Is this a bug or do I need to customize something in order to make it work?
 
I can only throw random ideas, without more details.

maybe the inits does not run anymore.

Check if the frames exist. when it prints 0 to the screen that frame does not exist. Try such at 5s or at some time you are sure that Talent Init did run.
call BJDebugMsg(I2S(GetHandleId(BlzGetFrameByName("TalentShowButton", 0))))
call BJDebugMsg(I2S(GetHandleId(BlzGetFrameByName("TalentBox", 0))))

call BJDebugMsg(I2S(GetHandleId(BlzGetFrameByName("TalentGridShowButton", 0))))
call BJDebugMsg(I2S(GetHandleId(BlzGetFrameByName("TalentGridParent", 0))))

Talent JUI uses file imports check, if they are still there and are at the expected paths.

the systems might both use the same parent and somehow make it unshow able. Either one does hide/scale the parent on init or repeatly scale/hide the parent.

good luck, or provide more details.
 
Level 4
Joined
Jan 9, 2024
Messages
38
Unfortunately I'm not used to vJASS or coding in general.
These are the relevant scripts from the inventory system:

JASS:
/*****************************************************************************
*
*    Inventory v1.0.8
*       by SmitingDevil
*
*    Custom inventory that is compatible with the vanilla one
*
******************************************************************************
*
*    Requirements:
*
*       Table by Bribe
*          https://www.hiveworkshop.com/threads/lua-vjass-new-table.188084/
*
*       Alloc - choose whatever you like
*          e.g.: by AGD https://www.hiveworkshop.com/threads/global-alloc.324937/
*
*       HoverOriginButton by Tasyen
*           https://www.hiveworkshop.com/threads/hoveroriginbutton.337965/
*
*       GetMainSelectedUnit (vJASS) by Tasyen
*           https://www.hiveworkshop.com/threads/getmainselectedunit.325337/
*
*       Sync by TriggerHappy
*           https://www.hiveworkshop.com/threads/sync-game-cache.279148/
*
*       List<T> by Bannar
*           https://www.hiveworkshop.com/threads/containers-list-t.249011/
*
*       InventoryEvent by Bannar
*           https://www.hiveworkshop.com/threads/snippet-inventoryevent.287084/
*
*       StringIterator by edo494
*           https://www.hiveworkshop.com/threads/snippet-stringiterator.246143/
*
*       WorldBounds by Nestharus
*           https://raw.githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
*
*       TimerUtils by Magtheridon96/Vexorian/Bribe
*           https://www.hiveworkshop.com/threads/system-timerutilsex.204500/#post-2019478
*
******************************************************************************
*
*    Inventory Struct API:
*
*       General:
*
*        | static method create takes nothing returns thistype
*        |    Default constructor.
*        |
*        | static method createEx takes integer slotCount, integer cols, real buttonSize, real spaceGap, real borderSize, real titleSize, real posX, real posY returns thistype
*        |    Constructor that builds the inventory in one go.
*        |
*        | method destroy takes nothing returns nothing
*        |    Default destructor.
*
*
*       Access:
*
*        | readonly emptySlotTexture
*        | readonly slotIndicatorModel
*        | readonly backdrop
*        | readonly buttonSize
*
*
*       Modifiers:
*
*        [Design]
*
*        | method setSlotCount takes integer count returns thistype
*        |    Sets the number of inventory slots.
*        |
*        | method setSlotEmptyTexture takes string texture returns thistype
*        |    Sets the default texture for slots.
*        |
*        | method setSlotIndicatorModel takes string str returns thistype
*        |    Sets the model that shows a slot is selected.
*        |
*        | method setButtonSize takes real size returns thistype
*        |    Sets the size of the inventory slots and other buttons.
*        |
*        | method setButtonSpaceGap takes real size returns thistype
*        |    Sets the size of the space between inventory slots.
*        |
*        | method setColumnCount takes integer cols returns thistype
*        |    Sets the number of slots in a row.
*        |
*        | method setTitle takes string str returns thistype
*        |    Sets the name of the inventory.
*        |
*        | method setTitleSize takes real size returns thistype
*        |    Sets the size of the title's margins.
*        |
*        | method setBorderSize takes real size returns thistype
*        |    Sets the size of the inventory's margins.
         |
*        | method setOpenButtonPosition takes real x, real y returns thistype
*        |    Sets the position of the open button icon.
*        |
*        | method setOpenButtonTexture takes string str returns thistype
*        |    Sets the texture for open button icon.
*        |
*        | method build takes nothing returns nothing
*        |    Creates the inventory and all its elements.
*        |    All methods for design must be called before running this method.
*        |        They cannot be modified after build.
*        |        Only title name and methods for the open button are the only exceptions.
*        |            They can be modified before and after build and are optional.
*
*        [Technical]
*
*        | method setPosition takes real x, real y returns thistype
*        |    Moves the inventory to given point on the screen
*        |
*        | method show takes boolean flag returns nothing
*        |    Hides or displays the inventory
*        |
*        | method showEx takes player p, boolean flag returns nothing
*        |    Hides or displays the inventory for specific player only
*        |    Links the inventory to player as the one being displayed
*
*
*****************************************************************************/
library Inventory initializer Init requires TimerUtilsEx, WorldBounds, ListT, StringIterator, Sync, InventoryEvent, HoverOriginButton, GetMainSelectedUnit
    globals
        private framehandle dummyFrame
        private framehandle dummyFrameEx
        private framehandle dummyIcon
        private framehandle array playerFrame
        private integer originItemSlot = -1
        private integer originItemSlotEx = -1
        private Table player2Inventory
        //private Table item2Unit
        player LOCAL_PLAYER
        framehandle GAME_UI
        framehandle ORIGIN_ITEM_BUTTON_ONE
        
        //private integer count = 0
    endglobals
    
    function IsFrameEnabled takes framehandle frame, player p returns boolean
        if GetLocalPlayer() == p or p == null then
            return BlzFrameGetEnable(frame)
        else
            return false
        endif
    endfunction
    
    function UnfocusFrame takes framehandle frame, player p returns nothing
        if IsFrameEnabled(frame, p) then
            call BlzFrameSetEnable(frame, false)
            call BlzFrameSetEnable(frame, true)
        else
            call BlzFrameSetEnable(frame, true)
            call BlzFrameSetEnable(frame, false)
        endif
    endfunction
    
    function print takes string msg returns nothing
        call DisplayTimedTextToPlayer(LOCAL_PLAYER, 0, 0, 3, msg)
    endfunction
    
    private function IsMouseDraggingItem takes nothing returns boolean
        local integer i = 0
        loop
            if BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_COMMAND_BUTTON, i)) then
                exitwhen true
            endif
            set i = i + 1
            exitwhen i == 12
        endloop
        return i == 11
    endfunction

    private module MyModule
        private static method onInit takes nothing returns nothing
            //this is run on map init
            call init()
        endmethod
    endmodule
    
    private struct Frame extends array
        implement Alloc
        
        framehandle handle
        
        static method create takes framehandle frame returns thistype
            local thistype this = allocate()
            
            set handle = frame
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set handle = null
            call deallocate()
        endmethod
    endstruct
    
    private struct UnitItem extends array
        implement Alloc
        
        item itemHandle
        unit unitHandle
        
        static method create takes unit u, item it returns thistype
            local thistype this = allocate()
            
            set unitHandle = u
            set itemHandle = it
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set unitHandle = null
            set itemHandle = null
            
            call deallocate()
        endmethod
    endstruct

    private struct Slot extends array
        implement Alloc
        
        private framehandle actionButton
        private framehandle icon
        private framehandle tooltipParent
        private framehandle tooltipText
        private framehandle tooltipBackdrop
        readonly framehandle indicator
        readonly Inventory parent
        readonly static Table frame2Slot
        readonly static Table frame2Item
        readonly static Table unit2Item
        readonly static Table player2Unit
        readonly static Table data2Frame
        private static trigger actionTrigger
        private static trigger enterTrigger
        //private static framehandle clickedFrame
        
        static method create takes real size, real x, real y, Inventory parent returns thistype
            local thistype this = allocate()

            set actionButton = BlzCreateFrame("ScriptDialogButton", parent.backdrop, 0, 0)
            call BlzFrameSetSize(actionButton, size, size)
            call BlzFrameSetPoint(actionButton, FRAMEPOINT_TOPLEFT, parent.backdrop, FRAMEPOINT_TOPLEFT, x, y)
            
            set frame2Slot[GetHandleId(actionButton)] = this
            set frame2Item[GetHandleId(actionButton)] = Table.create()

            set icon = BlzCreateFrameByType("BACKDROP", "SlotIcon", actionButton, "", 0)
            call BlzFrameSetAllPoints(icon, actionButton)
            call BlzFrameSetTexture(icon, parent.emptySlotTexture, 0, true)

            set tooltipParent = BlzCreateFrameByType("FRAME", "SlotTooltipParent", actionButton, "", 0)
            call BlzFrameSetTooltip(actionButton, tooltipParent)

            set tooltipBackdrop = BlzCreateFrameByType("BACKDROP", "SlotTooltipBackdrop", tooltipParent, "", 0)
            call BlzFrameSetVisible(tooltipBackdrop, false)

            set tooltipText = BlzCreateFrameByType("TEXT", "SlotTooltipText", tooltipBackdrop, "", 0)
            call BlzFrameSetSize(tooltipText, 0.2, 0)
            call BlzFrameSetPoint(tooltipText, FRAMEPOINT_TOPLEFT, actionButton, FRAMEPOINT_TOPRIGHT, 0, 0)

            call BlzFrameSetPoint(tooltipBackdrop, FRAMEPOINT_TOPLEFT, tooltipText, FRAMEPOINT_TOPLEFT, -0.007, 0.007)
            call BlzFrameSetPoint(tooltipBackdrop, FRAMEPOINT_BOTTOMRIGHT, tooltipText, FRAMEPOINT_BOTTOMRIGHT, 0.007, -0.007)
            call BlzFrameSetTexture(tooltipBackdrop, "UI\\Widgets\\ToolTips\\Human\\human-tooltip-background.blp", 0, true)
            
            set indicator = BlzCreateFrameByType("SPRITE", "SlotIndicator", actionButton, "", 0)
            call BlzFrameSetAllPoints(indicator, actionButton)
            call BlzFrameSetScale(indicator, parent.buttonSize/0.036)
            call BlzFrameSetVisible(indicator, false)
            call BlzFrameSetModel(indicator, parent.slotIndicatorModel, 0)
            
            call BlzTriggerRegisterFrameEvent(actionTrigger, actionButton, FRAMEEVENT_CONTROL_CLICK)

            set .parent = parent

            return this
        endmethod
        
        private method update takes item itm returns nothing
            if itm != null then
                call BlzFrameSetTexture(icon, BlzGetItemIconPath(itm), 0, true)
                call BlzFrameSetVisible(tooltipBackdrop, true)
                call BlzFrameSetText(tooltipText, GetLocalizedString("|cffffcc00" + GetItemName(itm) + "|r\n\n" + BlzGetAbilityExtendedTooltip(GetItemTypeId(itm), 0)))
            else
                call BlzFrameSetTexture(icon, parent.emptySlotTexture, 0, true)
                call BlzFrameSetVisible(tooltipBackdrop, false)
            endif
        endmethod
        
        private static method onExpired takes nothing returns nothing
            local UnitItem data = ReleaseTimer(GetExpiredTimer()) 
            
            call SetItemVisible(data.itemHandle, true)
            call UnitAddItem(data.unitHandle, data.itemHandle)
            call UnitDropItemSlot(data.unitHandle, data.itemHandle, 0)
            
            call data.destroy()
        endmethod
        
        private static method clickAction takes nothing returns nothing
            local SyncData d = GetSyncedData()
            local StringIterator iter = StringIterator.create(d.readString(0))
            local Frame clickedFrame = data2Frame[d]
            local integer originSlot
            local integer pid
            local integer selectedIndex = S2I(iter.read())
            local unit mainSelectedUnit = GetMainSelectedUnit(selectedIndex)
            local framehandle frame
            local framehandle pFrame
            local boolean itemOnMouse
            local player syncer
            local item itemInOriginSlot
            local item slotItem
            local item item0
            local thistype slot
            local thistype pSlot
            local Table table
            local Table tb
            
            call data2Frame.remove(d)
            
            //call print("Click Action: " + GetUnitName(mainSelectedUnit))
            //call ClearTextMessages()
            //call print("------------------------------------------------------")
            if mainSelectedUnit != null then
                set frame = clickedFrame.handle
                set syncer = d.from
                set pid = GetPlayerId(syncer)
                set table = frame2Item[GetHandleId(frame)]
                set slot = frame2Slot[GetHandleId(frame)]
                set originSlot = S2I(iter.read())
                if iter.read() == "true" then
                    set itemOnMouse = true
                else
                    set itemOnMouse = false
                endif
                
                if itemOnMouse then
                    set itemInOriginSlot = UnitItemInSlot(mainSelectedUnit, originSlot)
                    if itemInOriginSlot != null then
                        set pFrame = playerFrame[pid]
                        set playerFrame[pid] = null
                        call SetItemPosition(itemInOriginSlot, WorldBounds.minX, WorldBounds.minY)
                        call SetItemVisible(itemInOriginSlot, false)
                        
                        if LOCAL_PLAYER == syncer then
                            call slot.update(itemInOriginSlot)
                            set originItemSlot = -1
                            set originItemSlotEx = -1
                        endif
                        
                        set slotItem = table.item[GetHandleId(mainSelectedUnit)]
                        set table.item[GetHandleId(mainSelectedUnit)] = itemInOriginSlot
                        set playerFrame[pid] = pFrame
                        if pFrame == null then
                            if slotItem != null then
                                //call print("Click Slot - itemOnMouse - no pFrame: " + GetItemName(slotItem))
                                call UnitAddItem(mainSelectedUnit, slotItem)
                                call UnitDropItemSlot(mainSelectedUnit, slotItem, originSlot)
                            endif
                        else
                            if originSlot == 0 then
                                set playerFrame[pid] = null
                                set slot = frame2Slot[GetHandleId(pFrame)]
                                set tb = frame2Item[GetHandleId(pFrame)]
                                if slotItem == null then
                                    call tb.item.remove(GetHandleId(mainSelectedUnit))
                                else
                                    set tb.item[GetHandleId(mainSelectedUnit)] = slotItem
                                endif
                                //call print("Click Slot - itemOnMouse - pFrame - originSlot 0: " + GetItemName(slotItem))
                                if LOCAL_PLAYER == syncer then
                                    call slot.update(slotItem)
                                    call BlzFrameSetVisible(dummyIcon, false)
                                    call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                                    call BlzFrameSetVisible(slot.indicator, false)
                                endif
                                if unit2Item.item.has(GetHandleId(mainSelectedUnit)) then
                                    set item0 = unit2Item.item[GetHandleId(mainSelectedUnit)]
                                    call TimerStart(NewTimerEx(UnitItem.create(mainSelectedUnit, item0)), 0, false, function thistype.onExpired)
                                    //call UnitAddItem(mainSelectedUnit, item0)
                                    //call UnitDropItemSlot(mainSelectedUnit, item0, 0)
                                    call unit2Item.item.remove(GetHandleId(mainSelectedUnit))
                                endif
                            else
                                set playerFrame[pid] = null 
                                if slotItem != null then
                                    call UnitAddItem(mainSelectedUnit, slotItem)
                                    call UnitDropItemSlot(mainSelectedUnit, slotItem, originSlot)
                                endif
                                set playerFrame[pid] = pFrame
                            endif
                            set pFrame = null
                        endif
                    endif
                    set itemInOriginSlot = null
                else
                    if table.item.has(GetHandleId(mainSelectedUnit)) then

                        if playerFrame[GetPlayerId(syncer)] != null then
                            set pFrame = playerFrame[GetPlayerId(syncer)]
                            set playerFrame[GetPlayerId(syncer)] = null
                            set pSlot = frame2Slot[GetHandleId(pFrame)]
                            set tb = frame2Item[GetHandleId(pFrame)]
                            set slotItem = tb.item[GetHandleId(mainSelectedUnit)]
                            call SetItemPosition(slotItem, WorldBounds.minX, WorldBounds.minY)
                            call SetItemVisible(slotItem, false)
                            if LOCAL_PLAYER == syncer then
                                call BlzFrameSetVisible(pSlot.indicator, false)
                            endif
                            
                            if unit2Item.item.has(GetHandleId(mainSelectedUnit)) then
                                set item0 = unit2Item.item[GetHandleId(mainSelectedUnit)]
                                call UnitAddItem(mainSelectedUnit, item0)
                                call UnitDropItemSlot(mainSelectedUnit, item0, 0)
                                call unit2Item.item.remove(GetHandleId(mainSelectedUnit))
                            endif
                        endif
                        
                        if LOCAL_PLAYER == syncer then
                            call BlzFrameSetVisible(slot.indicator, true)
                            call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, frame)
                            set originItemSlot = -1
                            set originItemSlotEx = -1
                            call BlzFrameSetEnable(dummyFrameEx, true)
                        endif

                        set slotItem = UnitItemInSlot(mainSelectedUnit, 0)
                        if slotItem != null then
                            set unit2Item.item[GetHandleId(mainSelectedUnit)] = slotItem
                            //set item2Unit.unit[GetHandleId(slotItem)] = mainSelectedUnit
                            //call print("Clicked slot no item on mouse: " + GetItemName(slotItem))
                            if LOCAL_PLAYER == syncer then
                                call BlzFrameSetTexture(dummyIcon, BlzGetAbilityIcon(GetItemTypeId(slotItem)), 0, true)
                                call BlzFrameSetVisible(dummyIcon, true)
                            endif
                            call SetItemPosition(slotItem, WorldBounds.minX, WorldBounds.minY)
                            call SetItemVisible(slotItem, false)
                            set slotItem = null
                        endif
                            
                        set slotItem = table.item[GetHandleId(mainSelectedUnit)]
                        call UnitAddItem(mainSelectedUnit, slotItem)
                        call UnitDropItemSlot(mainSelectedUnit, slotItem, 0)
                        set slotItem = null

                        set playerFrame[GetPlayerId(syncer)] = frame
                    endif
                endif
                
                set frame = null
                set mainSelectedUnit = null
                set syncer = null
            endif
            
            call d.destroy()
            call clickedFrame.destroy()
        endmethod
        
        private static method onClick takes nothing returns nothing
            local SyncData req = SyncData.create(GetTriggerPlayer())
            local string str
            
            set data2Frame[req] = Frame.create(BlzGetTriggerFrame())
            
            call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
            
            if frame2Slot.has(GetHandleId(BlzGetTriggerFrame())) then
                set str = ""
                if LOCAL_PLAYER == GetTriggerPlayer() then
                    set str = I2S(GetSelectedUnitIndex()) + " "
                    set str = str + I2S(originItemSlot) + " "
                    if IsMouseDraggingItem() then
                        set str = str + "true" 
                    else
                        set str = str + "false" 
                    endif
                endif
                set req.onComplete = Filter(function thistype.clickAction)
                call req.syncString(str, StringLength(str))
                //call SyncStr(str, GetTriggerPlayer(), function thistype.clickAction)
            endif
        endmethod
        
        private static method onEnter takes nothing returns nothing
            call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
            call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
            if BlzGetTriggerFrame() == dummyFrameEx then
                if IsMouseDraggingItem() then
                    set originItemSlotEx = 0
                endif
            endif
        endmethod
        
        private static method onItemMove takes nothing returns nothing
            local item item0
            local unit u = GetInventoryManipulatingUnit()
            local item itm 
            local item swapped 
            local integer slotFrom
            local integer slotTo = GetInventorySlotTo()
            local player p = GetOwningPlayer(u)
            local integer pid = GetPlayerId(p)
            local thistype slot
            local framehandle pFrame
            local Table tb
            
            if LOCAL_PLAYER == p then
                set originItemSlot = slotTo
            endif
            
            set pFrame = playerFrame[pid]
            set playerFrame[pid] = null
            if pFrame != null then
                //call print("Item Move: " + GetItemName(GetInventoryManipulatedItem()))
                set itm = GetInventoryManipulatedItem()
                set swapped = GetInventorySwappedItem()
                set slot = frame2Slot[GetHandleId(pFrame)]
                set slotFrom = GetInventorySlotFrom()
                
                if slotTo == slotFrom then
                    
                else
                    call BlzFrameSetEnable(dummyFrame, true)
                    
                    set tb = frame2Item[GetHandleId(pFrame)]
                    
                    if slotFrom == 0 then
                        if swapped != null then
                            set tb.item[GetHandleId(u)] = swapped
                            call SetItemPosition(swapped, WorldBounds.minX, WorldBounds.minY)
                            call SetItemVisible(swapped, false)
                            
                            if LOCAL_PLAYER == p then
                                call slot.update(swapped)
                                call BlzFrameSetVisible(slot.indicator, false)
                                call BlzFrameSetVisible(dummyIcon, false)
                                call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                                //set originItemSlot = -1
                                set originItemSlotEx = -1
                            endif
                        else
                            call tb.item.remove(GetHandleId(u))
                            if LOCAL_PLAYER == p then
                                call slot.update(null)
                                call BlzFrameSetVisible(slot.indicator, false)
                                call BlzFrameSetVisible(dummyIcon, false)
                                call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                                //set originItemSlot = -1
                                set originItemSlotEx = -1
                            endif
                        endif
                    elseif slotTo == 0 then
                        set tb.item[GetHandleId(u)] = itm
                        call print("sloTo 0 - swapped item: " + GetItemName(itm))
                        call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
                        call SetItemVisible(itm, false)
                        
                        if LOCAL_PLAYER == p then
                            call slot.update(itm)
                            call BlzFrameSetVisible(slot.indicator, false)
                            call BlzFrameSetVisible(dummyIcon, false)
                            call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                            //set originItemSlot = -1
                            set originItemSlotEx = -1
                        endif
                        
                        call UnitDropItemSlot(u, swapped, slotFrom)
                    endif
                    if slotFrom == 0 or slotTo == 0 then
                        set pFrame = null
                        set item0 = unit2Item.item[GetHandleId(u)]
                        //call print("sloTo 0 - item0: " + GetItemName(item0))
                        if item0 != null then
                            call unit2Item.item.remove(GetHandleId(u))
                            call SetItemVisible(item0, true)
                            call UnitAddItem(u, item0)
                            call UnitDropItemSlot(u, item0, 0)
                            set item0 = null
                        endif
                    endif
                endif
            endif
            
            set u = null
            set itm = null
            set swapped = null 
            set playerFrame[pid] = pFrame
            set pFrame = null
        endmethod
        
        private static method onItemDrop takes nothing returns nothing
            local item itm = GetManipulatedItem()
            local item item0
            local unit u = GetTriggerUnit()
            local integer pid = GetPlayerId(GetTriggerPlayer())
            local thistype slot
            local framehandle pFrame = playerFrame[pid]
            local Table tb
            
            if pFrame != null and UnitItemInSlot(u, 0) == itm then
                set playerFrame[pid] = null
                //call print("Item Drop: " + GetItemName(itm))
                call BlzFrameSetEnable(dummyFrame, true)
                set slot = frame2Slot[GetHandleId(pFrame)]
                set tb = frame2Item[GetHandleId(pFrame)]
                call tb.item.remove(GetHandleId(u))
                if LOCAL_PLAYER == GetTriggerPlayer() then
                    call slot.update(null)
                    call BlzFrameSetVisible(slot.indicator, false)
                    call BlzFrameSetVisible(dummyIcon, false)
                    call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                    set originItemSlot = -1
                    set originItemSlotEx = -1
                endif
                set item0 = unit2Item.item[GetHandleId(u)]
                if item0 != null then
                    //call print("Item Drop - item0: " + GetItemName(item0))
                    call unit2Item.item.remove(GetHandleId(u))
                    call TimerStart(NewTimerEx(UnitItem.create(u, item0)), 0, false, function thistype.onExpired)
                    set item0 = null
                endif
            endif
        endmethod
        
        private static method mouseAction takes nothing returns nothing
            local SyncData d = GetSyncedData()
            local StringIterator iter = StringIterator.create(d.readString(0))
            local IntegerListItem node
            local Inventory inv
            local Table tb
            local player p = d.from
            local integer pid = GetPlayerId(p) 
            local integer selectedIndex
            local integer originSlot
            local thistype slot
            local boolean itemOnMouse
            local item item0
            local item itm
            local unit u
            local unit mainUnit
            local string str = iter.read()
            local framehandle pFrame
            
            call d.destroy()
            
            if not player2Inventory.has(pid) then
                return
            endif
            
            if str == "true" then
                set itemOnMouse = true
            else
                set itemOnMouse = false
            endif
            set originSlot = S2I(iter.read())
            set selectedIndex = S2I(iter.read())
            //set count = count + 1
            
            if itemOnMouse then
                //call print("Main Selected Unit Index: " + I2S(selectedIndex))
                if playerFrame[pid] != null and originSlot == 0 then
                    set u = GetMainSelectedUnit(selectedIndex)
                    set slot = frame2Slot[GetHandleId(playerFrame[pid])]
                    set item0 = unit2Item.item[GetHandleId(u)]
                    set tb = frame2Item[GetHandleId(playerFrame[pid])]
                    
                    if item0 == null then
                        call tb.item.remove(GetHandleId(u))
                    else
                        call unit2Item.item.remove(GetHandleId(u))
                        set tb.item[GetHandleId(u)] = item0
                    endif
                    
                    if LOCAL_PLAYER == p then
                        call slot.update(item0)
                        call BlzFrameSetVisible(slot.indicator, false)
                        call BlzFrameSetVisible(dummyIcon, false)
                        call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                        set originItemSlot = -1
                        set originItemSlotEx = -1
                        call ForceUICancel()
                        call BlzFrameSetEnable(dummyFrameEx, true)
                    endif
                    
                    set item0 = null
                    set u = null
                    set playerFrame[pid] = null
                endif
            else
                set pFrame = playerFrame[pid]
                set playerFrame[pid] = null
                set mainUnit = GetMainSelectedUnit(selectedIndex)
                set u = player2Unit.unit[pid]
                set player2Unit.unit[pid] = mainUnit
                if mainUnit != u and u != null then
                    if unit2Item.item.has(GetHandleId(u)) then
                        set item0 = unit2Item.item[GetHandleId(u)]
                        set itm = UnitItemInSlot(u, 0)
                        call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
                        call SetItemVisible(itm, false)
                        call UnitAddItem(u, item0)
                        call UnitDropItemSlot(u, item0, 0)
                        call unit2Item.item.remove(GetHandleId(u))
                        set itm = null
                        set item0 = null
                    endif
                    
                    set inv = player2Inventory[pid]
                    set node = inv.slots.first
                    loop
                        exitwhen node == 0
                        set slot = node.data
                        set tb = frame2Item[GetHandleId(slot.actionButton)]
                        set itm = tb.item[GetHandleId(mainUnit)]
                        if itm != null then
                             call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
                             call SetItemVisible(itm, false)
                        endif
                        if LOCAL_PLAYER == p then
                            call slot.update(itm)
                        endif
                        set itm = null
                        set node = node.next
                    endloop
                    
                    if unit2Item.item.has(GetHandleId(mainUnit)) then
                        set item0 = unit2Item.item[GetHandleId(mainUnit)]
                        //call print("mainUnit - item0: " + GetItemName(item0))
                        call UnitAddItem(mainUnit, item0)
                        call UnitDropItemSlot(mainUnit, item0, 0)
                        call unit2Item.item.remove(GetHandleId(mainUnit))
                        set item0 = null
                    endif
                    
                    if pFrame != null then
                        set slot = frame2Slot[GetHandleId(pFrame)]
                        set pFrame = null
                        if LOCAL_PLAYER == p then
                            call BlzFrameSetVisible(slot.indicator, false)
                            call BlzFrameSetVisible(dummyIcon, false)
                            call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                            set originItemSlot = -1
                            set originItemSlotEx = -1
                            call BlzFrameSetEnable(dummyFrameEx, true)
                        endif
                    endif
                endif
                set playerFrame[pid] = pFrame
            endif
        endmethod
        
        private static method onMouseClick takes nothing returns nothing
            local SyncData req = SyncData.create(GetTriggerPlayer())
            local string str = ""
            if LOCAL_PLAYER == GetTriggerPlayer() then
                if IsMouseDraggingItem() then
                    set str = "true " 
                else
                    set str = "false " 
                endif
                set str = str + I2S(originItemSlotEx) + " "
                set str = str + I2S(GetSelectedUnitIndex())
            endif
            set req.onComplete = Filter(function thistype.mouseAction)
            call req.syncString(str, StringLength(str))
            //call print(str + ": " + I2S(StringLength(str)) + " characters")
            //call SyncStr(str, GetTriggerPlayer(), function thistype.mouseAction)
        endmethod
        
        private static method onInit takes nothing returns nothing
            set frame2Slot = Table.create()
            set frame2Item = Table.create()
            set unit2Item = Table.create()
            set player2Unit = Table.create()
            set data2Frame = Table.create()
            
            set actionTrigger = CreateTrigger()
            set enterTrigger = CreateTrigger()
            call TriggerAddCondition(actionTrigger, function thistype.onClick)
            call TriggerAddCondition(enterTrigger, function thistype.onEnter)
            
            set ORIGIN_ITEM_BUTTON_ONE = BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)
            
            set dummyFrame = BlzCreateFrameByType("GLUETEXTBUTTON", "DummyFrame", GAME_UI, "", 0)
            call BlzFrameSetSize(dummyFrame, 0.030, 0.031)
            call BlzFrameSetAbsPoint(dummyFrame, FRAMEPOINT_CENTER, 0.5318, 0.097)
            
            set dummyIcon = BlzCreateFrameByType("BACKDROP", "DummyIcon", dummyFrame, "", 0)
            call BlzFrameSetAllPoints(dummyIcon, dummyFrame)
            call BlzFrameSetVisible(dummyIcon, false)
            
            set dummyFrameEx = BlzCreateFrameByType("GLUETEXTBUTTON", "DummyFrame", dummyFrame, "", 0)
            call BlzFrameSetSize(dummyFrameEx, 0.04, 0.04)
            call BlzFrameSetAbsPoint(dummyFrameEx, FRAMEPOINT_CENTER, 0.5318, 0.097)
            call BlzTriggerRegisterFrameEvent(enterTrigger, dummyFrameEx, FRAMEEVENT_MOUSE_ENTER)
            
            call RegisterNativeEvent(EVENT_ITEM_INVENTORY_MOVE, function thistype.onItemMove)
            
            call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onItemDrop)
            
            call RegisterAnyPlayerEvent(EVENT_PLAYER_MOUSE_UP, function thistype.onMouseClick)
        endmethod
    endstruct

    struct Inventory extends array
        implement Alloc
            
        private static trigger closeTrigger
        private static trigger openTrigger
        private static Table frame2Inventory
        
        private framehandle title
        private framehandle closeButton
        private framehandle openIcon
        private framehandle nextButton
        private framehandle prevButton
        private framehandle pageNumber
        private integer slotCount
        private integer columns
        private real borderSize
        private real titleSize
        private real spaceGap

        readonly string emptySlotTexture
        readonly string slotIndicatorModel
        readonly framehandle backdrop
        readonly real buttonSize
        
        framehandle openButton
        IntegerList slots

        method setSlotCount takes integer count returns thistype
            set slotCount = count
            return this
        endmethod

        method setColumnCount takes integer cols returns thistype
            set columns = cols
            return this
        endmethod

        method setTitle takes string str returns thistype
            call BlzFrameSetText(title, GetLocalizedString(str))
            return this
        endmethod

        method setTitleSize takes real size returns thistype
            set titleSize = size
            return this
        endmethod

        method setBorderSize takes real size returns thistype
            set borderSize = size
            return this
        endmethod

        method setButtonSize takes real size returns thistype
            set buttonSize = size
            return this
        endmethod

        method setButtonSpaceGap takes real size returns thistype
            set spaceGap = size
            return this
        endmethod

        method setSlotEmptyTexture takes string texture returns thistype
            set emptySlotTexture = texture
            return this
        endmethod

        method setPosition takes real x, real y returns thistype
            call BlzFrameSetAbsPoint(backdrop, FRAMEPOINT_CENTER, x, y)
            return this
        endmethod
        
        method setOpenButtonPosition takes real x, real y returns thistype
            call BlzFrameSetAbsPoint(openButton, FRAMEPOINT_CENTER, x, y)
            return this
        endmethod
        
        method setOpenButtonTexture takes string str returns thistype
            call BlzFrameSetTexture(openIcon, str, 0, true)
            return this
        endmethod
        
        method setSlotIndicatorModel takes string str returns thistype
            set slotIndicatorModel = str
            return this
        endmethod

        method show takes boolean flag returns nothing
            call BlzFrameSetVisible(backdrop, flag)
        endmethod
        
        method showEx takes player p, boolean flag returns nothing
            if LOCAL_PLAYER == p then
                call BlzFrameSetVisible(backdrop, flag)
            endif
            if flag then
                set player2Inventory[GetPlayerId(p)] = this
            else
                call player2Inventory.remove(GetPlayerId(p))
            endif
        endmethod

        method build takes nothing returns nothing
            local integer rows = slotCount/columns
            local integer i = 0
            local integer j = 0
            local real x = borderSize
            local real y = -borderSize - titleSize
            
            call BlzFrameSetSize(backdrop, columns*buttonSize + (columns - 1)*spaceGap + 2*borderSize, rows*buttonSize + (rows - 1)*spaceGap + 2*borderSize + titleSize)
            
            loop
                exitwhen i == slotCount
                call slots.push(Slot.create(buttonSize, x, y, this))
                set x = x + spaceGap + buttonSize
                set j = j + 1
                if j == columns then
                    set j = 0
                    set x = borderSize
                    set y = y - spaceGap - buttonSize
                endif
                set i = i + 1
            endloop
            
            call BlzFrameSetSize(openButton, buttonSize, buttonSize)

            call BlzFrameSetSize(title, 0, titleSize)
            call BlzFrameSetPoint(title, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_TOP, 0, -borderSize*.75)
            //call BlzFrameSetSize(pageNumber, 0, titleSize) 
            //call BlzFrameSetPoint(pageNumber, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_BOTTOM, 0, borderSize)
            
            call BlzFrameSetSize(openButton, buttonSize, buttonSize)
            call BlzTriggerRegisterFrameEvent(openTrigger, openButton, FRAMEEVENT_CONTROL_CLICK)

            call BlzFrameSetPoint(closeButton, FRAMEPOINT_TOPRIGHT, backdrop, FRAMEPOINT_TOPRIGHT, 0, 0)
            call BlzFrameSetSize(closeButton, buttonSize, buttonSize)
            call BlzFrameSetText(closeButton, "X")
            call BlzTriggerRegisterFrameEvent(closeTrigger, closeButton, FRAMEEVENT_CONTROL_CLICK)

//            call BlzFrameSetPoint(nextButton, FRAMEPOINT_BOTTOMRIGHT, backdrop, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
//            call BlzFrameSetSize(nextButton, buttonSize, buttonSize)
//            call BlzFrameSetText(nextButton, ">")
//
//            call BlzFrameSetPoint(prevButton, FRAMEPOINT_BOTTOMLEFT, backdrop, FRAMEPOINT_BOTTOMLEFT, 0, 0)
//            call BlzFrameSetSize(prevButton, buttonSize, buttonSize)
//            call BlzFrameSetText(prevButton, "<")
        endmethod
        
        private static method closeAction takes nothing returns nothing
            local SyncData d = GetSyncedData()
            local integer pid = GetPlayerId(d.from)
            local thistype this = player2Inventory[pid]
            local unit selectedUnit = GetMainSelectedUnit(d.readInt(0))
            local item item0
            local item itemSlot
            local framehandle pFrame
            local Slot slot
            local Table tb
            
            if LOCAL_PLAYER == GetTriggerPlayer() then
                call BlzFrameSetVisible(this.backdrop, false)
            endif
            
            call player2Inventory.remove(pid)
            
            set pFrame = playerFrame[pid]
            set playerFrame[pid] = null
            if pFrame != null then
                set slot = Slot.frame2Slot[GetHandleId(pFrame)]
                set tb = Slot.frame2Item[GetHandleId(pFrame)]
                set itemSlot = tb.item[GetHandleId(selectedUnit)]
                call SetItemPosition(itemSlot, WorldBounds.minX, WorldBounds.minY)
                call SetItemVisible(itemSlot, false)
                set itemSlot = null
                set pFrame = null
                
                if LOCAL_PLAYER == GetTriggerPlayer() then
                    call BlzFrameSetVisible(slot.indicator, false)
                    call BlzFrameSetVisible(dummyIcon, false)
                    call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
                    call BlzFrameSetEnable(dummyFrameEx, true)
                endif
                
                set item0 = Slot.unit2Item.item[GetHandleId(selectedUnit)]
                if item0 != null then
                    call UnitAddItem(selectedUnit, item0)
                    call UnitDropItemSlot(selectedUnit, item0, 0)
                    call Slot.unit2Item.item.remove(GetHandleId(selectedUnit))
                    set item0 = null
                endif
            endif
            
            set selectedUnit = null
            call d.destroy()
        endmethod
        
        private static method close takes nothing returns nothing
            local SyncData req = SyncData.create(GetTriggerPlayer())
            call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
            set req.onComplete = Filter(function thistype.closeAction)
            call req.syncInt(GetSelectedUnitIndex())
        endmethod
        
        private static method open takes nothing returns nothing
            local thistype this = frame2Inventory[GetHandleId(BlzGetTriggerFrame())]
            call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
            if LOCAL_PLAYER == GetTriggerPlayer() then
                call BlzFrameSetVisible(.backdrop, true)
            endif
            set player2Inventory[GetPlayerId(GetTriggerPlayer())] = this
        endmethod

        static method createEx takes integer slotCount, integer cols, real buttonSize, real spaceGap, real borderSize, real titleSize, real posX, real posY returns thistype
            local thistype this = allocate()
            local integer rows = slotCount/columns
            local integer i = 0
            local integer j = 0
            local real x = borderSize
            local real y = -borderSize - titleSize

            set .slotCount = slotCount
            set .columns = cols
            set .buttonSize = buttonSize
            set .spaceGap = spaceGap
            set .buttonSize = buttonSize
            set .borderSize = borderSize
            set .titleSize = titleSize

            set backdrop = BlzCreateFrame("QuestButtonBackdropTemplate", GAME_UI, 0, this)
            call BlzFrameSetSize(backdrop, columns*buttonSize + (columns - 1)*spaceGap + 2*borderSize, rows*buttonSize + (rows - 1)*spaceGap + 2*borderSize + titleSize)
            call BlzFrameSetAbsPoint(backdrop, FRAMEPOINT_CENTER, posX, posY)

            set title = BlzCreateFrameByType("TEXT", "InventoryTitle", backdrop, "", this)
            call BlzFrameSetSize(title, 0, titleSize)
            call BlzFrameSetPoint(title, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_TOP, 0, -borderSize*.75)
            call BlzFrameSetTextAlignment(title, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_TOP)
            call BlzFrameSetScale(title, 1.2)

//            set pageNumber = BlzCreateFrameByType("TEXT", "InventoryPage", backdrop, "", this)
//            call BlzFrameSetSize(pageNumber, 0, titleSize) 
//            call BlzFrameSetPoint(pageNumber, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_BOTTOM, 0, borderSize)
//            call BlzFrameSetTextAlignment(pageNumber, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
//            call BlzFrameSetText(pageNumber, "1")

            set openButton = BlzCreateFrameByType("GLUETEXTBUTTON", "InventoryOpen", GAME_UI, "", this)
            set openIcon = BlzCreateFrameByType("BACKDROP", "InventoryOpenIcon", openButton, "", this)
            call BlzFrameSetAllPoints(openIcon, openButton)
            
            set closeButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
            call BlzFrameSetPoint(closeButton, FRAMEPOINT_TOPRIGHT, backdrop, FRAMEPOINT_TOPRIGHT, 0, 0)
            call BlzFrameSetSize(closeButton, buttonSize, buttonSize)
            call BlzFrameSetText(closeButton, "X")
            call BlzTriggerRegisterFrameEvent(closeTrigger, closeButton, FRAMEEVENT_CONTROL_CLICK)

//            set nextButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
//            call BlzFrameSetPoint(nextButton, FRAMEPOINT_BOTTOMRIGHT, backdrop, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
//            call BlzFrameSetSize(nextButton, buttonSize, buttonSize)
//            call BlzFrameSetText(nextButton, "→")
//
//            set prevButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
//            call BlzFrameSetPoint(prevButton, FRAMEPOINT_BOTTOMLEFT, backdrop, FRAMEPOINT_BOTTOMLEFT, 0, 0)
//            call BlzFrameSetSize(prevButton, buttonSize, buttonSize)
//            call BlzFrameSetText(prevButton, "←")
//            call BlzFrameSetVisible(prevButton, false)

            set slots = IntegerList.create()
            loop
                exitwhen i == slotCount
                call slots.push(Slot.create(buttonSize, x, y, this))
                set x = x + spaceGap + buttonSize
                set j = j + 1
                if j == columns then
                    set j = 0
                    set x = borderSize
                    set y = y - spaceGap - buttonSize
                endif
                set i = i + 1
            endloop

            call BlzFrameSetVisible(backdrop, false)

            return this
        endmethod

        static method create takes nothing returns thistype
            local thistype this = allocate()

            set backdrop = BlzCreateFrame("QuestButtonBackdropTemplate", GAME_UI, 0, this)

            set title = BlzCreateFrameByType("TEXT", "InventoryTitle", backdrop, "", this)
            call BlzFrameSetTextAlignment(title, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_TOP)
            call BlzFrameSetScale(title, 1.2)

//            set pageNumber = BlzCreateFrameByType("TEXT", "InventoryPage", backdrop, "", this)
//            call BlzFrameSetTextAlignment(pageNumber, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
//            call BlzFrameSetText(pageNumber, "1")

            set openButton = BlzCreateFrameByType("GLUETEXTBUTTON", "InventoryOpen", GAME_UI, "", this)
            set openIcon = BlzCreateFrameByType("BACKDROP", "InventoryOpenIcon", openButton, "", this)
            call BlzFrameSetAllPoints(openIcon, openButton)
            set frame2Inventory[GetHandleId(openButton)] = this
            
            set closeButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)

            //set nextButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)

            //set prevButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)

            set slots = IntegerList.create()

            call BlzFrameSetVisible(backdrop, false)

            return this
        endmethod
        
        private static method init takes nothing returns nothing
            set GAME_UI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
            set LOCAL_PLAYER = GetLocalPlayer()
            set player2Inventory = Table.create()
            set closeTrigger = CreateTrigger()
            call TriggerAddCondition(closeTrigger, Filter(function thistype.close))
            set openTrigger = CreateTrigger()
            call TriggerAddCondition(openTrigger, Filter(function thistype.open))
            set frame2Inventory = Table.create()
        endmethod
        
        implement MyModule
    endstruct
    
    private function MouseOnItem takes nothing returns nothing
        local integer index = HoverOriginButton_CurrentSelectedButtonIndex - HoverOriginButton_ItemButtonOffset
        if not IsMouseDraggingItem() then
            set originItemSlot = index
        endif
        if index > 0 then
            call BlzFrameSetEnable(dummyFrameEx, true)
            set originItemSlotEx = index
        endif
    endfunction
    
    private function MouseLeftItem takes nothing returns nothing
        if not IsMouseDraggingItem() then
            set originItemSlot = -1
        endif
        set originItemSlotEx = -1
    endfunction
    
    private function Init takes nothing returns nothing
        call HoverOriginButtonAdd(false, function MouseOnItem)
        call HoverOriginButtonAddClose(function MouseLeftItem)
        //set item2Unit = Table.create()
    endfunction
endlibrary

JASS:
/*****************************************************************************
*
*    InventoryEvent v1.0.1.8
*       by Bannar
*
*    For intuitive inventory event handling.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterPlayerUnitEvent by Bannar
*          hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
*       ExtensionMethods by Bannar
*           https://www.hiveworkshop.com/pastebin/a998754d6441bc4e70a39a229111d6a7.15770
*
******************************************************************************
*
*    Event API:
*
*       integer EVENT_ITEM_INVENTORY_MOVE
*       integer EVENT_ITEM_INVENTORY_USE
*
*       Use RegisterNativeEvent or RegisterIndexNativeEvent for event registration.
*       GetNativeEventTrigger and GetIndexNativeEventTrigger provide access to trigger handles.
*
*
*       function GetInventoryManipulatingUnit takes nothing returns unit
*          Returns unit which manipulated event item.
*
*       function GetInventoryManipulatedItem takes nothing returns item
*          Returns manupilated event item.
*
*       function GetInventorySlotFrom takes nothing returns integer
*          Returns slot index of manipulated item from which it was moved or used.
*
*       function GetInventorySlotTo takes nothing returns integer
*          Returns slot index of manipulated item to which it was moved.
*
*       function GetInventorySwappedItem takes nothing returns item
*          Returns item which manipulated item switched position with if any.
*
*****************************************************************************/
library InventoryEvent requires RegisterPlayerUnitEvent, ExtensionMethods

    globals
        integer EVENT_ITEM_INVENTORY_MOVE
        integer EVENT_ITEM_INVENTORY_USE
    endglobals
    
    globals
        private unit eventUnit = null
        private item eventItem = null
        private integer eventSlotFrom = -1
        private integer eventSlotTo = -1
    endglobals
    
    function GetInventoryManipulatingUnit takes nothing returns unit
        return eventUnit
    endfunction
    
    function GetInventoryManipulatedItem takes nothing returns item
        return eventItem
    endfunction
    
    function GetInventorySlotFrom takes nothing returns integer
        return eventSlotFrom
    endfunction
    
    function GetInventorySlotTo takes nothing returns integer
        return eventSlotTo
    endfunction
    
    function GetInventorySwappedItem takes nothing returns item
        return UnitItemInSlot(eventUnit, eventSlotTo)
    endfunction
    
    function GetEventInventoryUnit takes nothing returns unit
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventoryUnit is obsolete, use GetInventoryManipulatingUnit instead.")
        return GetInventoryManipulatingUnit()
    endfunction
    
    function GetEventInventoryItem takes nothing returns item
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventoryItem is obsolete, use GetInventoryManipulatedItem instead.")
        return GetInventoryManipulatedItem()
    endfunction
    
    function GetEventInventorySlotFrom takes nothing returns integer
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySlotFrom is obsolete, use GetInventorySlotFrom instead.")
        return GetInventorySlotFrom()
    endfunction
    
    function GetEventInventorySlotTo takes nothing returns integer
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySlotTo is obsolete, use GetInventorySlotTo instead.")
        return GetInventorySlotTo()
    endfunction
    
    function GetEventInventorySwapped takes nothing returns item
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySwapped is obsolete, use GetInventorySwappedItem instead.")
        return GetInventorySwappedItem()
    endfunction
    
    function GetInventoryEventTrigger takes integer whichEvent returns trigger
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetInventoryEventTrigger is obsolete, use GetNativeEventTrigger instead.")
        return GetNativeEventTrigger(whichEvent)
    endfunction
    
    function RegisterInventoryEvent takes code func, integer whichEvent returns nothing
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function RegisterInventoryEvent is obsolete, use RegisterNativeEvent instead.")
        call RegisterNativeEvent(whichEvent, func)
    endfunction
    
    private function FireEvent takes integer evt, unit u, item itm, integer slotFrom, integer slotTo returns nothing
        local unit prevUnit = eventUnit
        local item prevItem = eventItem
        local integer prevSlotFrom = eventSlotFrom
        local integer prevSlotTo = eventSlotTo
        local integer playerId = GetPlayerId(GetOwningPlayer(u))
    
        set eventUnit = u
        set eventItem = itm
        set eventSlotFrom = slotFrom
        set eventSlotTo = slotTo
    
        call TriggerEvaluate(GetNativeEventTrigger(evt))
        if IsNativeEventRegistered(playerId, evt) then
            call TriggerEvaluate(GetIndexNativeEventTrigger(playerId, evt))
        endif
    
        set eventUnit = prevUnit
        set eventItem = prevItem
        set eventSlotFrom = prevSlotFrom
        set eventSlotTo = prevSlotTo
    
        set prevUnit = null
        set prevItem = null
    endfunction
    
    private function OnItemOrder takes nothing returns nothing
        local integer order = GetIssuedOrderId()
        local unit u = GetTriggerUnit()
        local item itm
        local integer slotFrom
        local integer slotTo
    
        if order >= 852002 and order <= 852007 then // between moveslot1 and moveslot6
            set itm = GetOrderTargetItem()
            set slotFrom = GetUnitItemSlot(u, itm)
            set slotTo = order - 852002 // moveslot1
            call FireEvent(EVENT_ITEM_INVENTORY_MOVE, u, itm, slotFrom, slotTo)
        else
            set slotFrom = order - 852008 //  useslot1
            set itm = UnitItemInSlot(u, slotFrom)
            call FireEvent(EVENT_ITEM_INVENTORY_USE, u, itm, slotFrom, -1)
        endif
    
        set u = null
        set itm = null
    endfunction
    
    private function OnAnyOrder takes nothing returns nothing
        local integer order = GetIssuedOrderId()
        if order >= 852002 and order <= 852013 then // between moveslot1 and useslot6
            call OnItemOrder()
        endif
    endfunction

    private module InventoryEventInit
        private static method onInit takes nothing returns nothing
            set EVENT_ITEM_INVENTORY_MOVE = CreateNativeEvent()
            set EVENT_ITEM_INVENTORY_USE = CreateNativeEvent()
            set MOVED = EVENT_ITEM_INVENTORY_MOVE
            set USED = EVENT_ITEM_INVENTORY_USE
    
            // MOVED is order of type TARGET_ORDER yet USED can be anyone of them
            call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function OnAnyOrder)
            call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function OnAnyOrder)
            call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function OnAnyOrder)
        endmethod
    endmodule
    
    struct InventoryEvent extends array
        // Events below are depreated in favor of EVENT_ alike globals
        readonly static integer MOVED
        readonly static integer USED
    
        implement InventoryEventInit
    endstruct
endlibrary

JASS:
/*************************Inventory Setup**********************************

scope SetupInventories initializer Init

    private function CreateInv takes player p returns nothing
        local Inventory inv = Inventory.create()/*
        */.setTitle("|cffffcc00Bag|r")    /*
        */.setTitleSize(0.015)      /*
        */.setBorderSize(0.029)     /*
        */.setButtonSize(0.03)      /*
        */.setSlotCount(12)         /*
        */.setColumnCount(4)        /*
        */.setPosition(0.45, 0.35)  /*
        */.setButtonSpaceGap(0.01)  /*
        */.setSlotIndicatorModel("UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdx")    /*
        */.setSlotEmptyTexture("war3mapImported\\UdInvTile.blp")  /*
        */.setOpenButtonTexture("ReplaceableTextures\\CommandButtons\\BTNINV_Misc_Bag_08.blp")
 
        call inv.build()
        call inv.showEx(p, false)
        call BlzFrameSetAbsPoint(inv.openButton, FRAMEPOINT_CENTER, 0.6, 0.15)
        //call BlzFrameSetPoint(inv.openButton, FRAMEPOINT_TOPLEFT, BlzGetFrameByName("TipsTextArea", 0), FRAMEPOINT_TOPRIGHT, 0, 0)
    endfunction

    private function SetupInv takes nothing returns nothing
        local integer i = 0
        local player p

        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call CreateInv(p)
            endif

            set i = i + 1
            exitwhen i > 23
        endloop
 
        call DestroyTimer(GetExpiredTimer())
        set p = null
    endfunction

    private function Init takes nothing returns nothing
        call TimerStart(CreateTimer(), 0.01, false, function SetupInv)
    endfunction

endscope
 
i wont inspect this 1+k lines of vjass code deeply until more simpler errors were checked out.

Does Talent not show up again after hiding?


Does Talent not show up at all? ->>>
Make a new trigger with event game time elapsed 3s or press esc-key action.

In that trigger you add this custom script lines they will print frameNames and numbers.
When a number is 0 that frame is not existing at that point.
Code:
call BJDebugMsg("TalentShowButton "+ I2S(GetHandleId(BlzGetFrameByName("TalentShowButton", 0))))
call BJDebugMsg("TalentBox "+I2S(GetHandleId(BlzGetFrameByName("TalentBox", 0))))

call BJDebugMsg("TalentGridShowButton "+I2S(GetHandleId(BlzGetFrameByName("TalentGridShowButton", 0))))
call BJDebugMsg("TalentGridParent "+I2S(GetHandleId(BlzGetFrameByName("TalentGridParent", 0))))

call BJDebugMsg("InventoryOpen "+I2S(GetHandleId(BlzGetFrameByName("InventoryOpen", 0))))
When both Talent Sets are 0, then no Talent-UI was created.
This can happen when the init does not run,
the fdf map import is broken/missing
your map does not have one of the Talent UI scripts TalentGrid/TalentBox enabled.
 
Level 4
Joined
Jan 9, 2024
Messages
38
Code:
call BJDebugMsg("TalentGridShowButton "+I2S(GetHandleId(BlzGetFrameByName("TalentGridShowButton", 0))))
call BJDebugMsg("TalentGridParent "+I2S(GetHandleId(BlzGetFrameByName("TalentGridParent", 0))))

call BJDebugMsg("InventoryOpen "+I2S(GetHandleId(BlzGetFrameByName("InventoryOpen", 0))))

Only these 3 messages return a 0, so TalentBox is working and active.
But when I have the inventory system installed and I click on the talent icon ingame it says "No Talent User". When I deactivate the inventory system it works just fine, and I can pick talents.
 
Last edited:
good so both systems are installed and work, but there is a crossfire which breaks a feature.

I now made a test map with both systems.
When one has TalentBox already open it shows for a really short time the Talents.

Then I added some DebugMsg into the TalentBox showing function (function TalentShowUI). For some reason selecting an unit triggers it 2 additional times with a total other unit as TriggerUnit, but with a short delay. This makes Talent unuseable.
^^any mouse click triggers it 2 times, suggests it is some sync thing.

I am not sure how to fix it, would need more effort to figure out solving this crossfire. But sounds like the author of Inventory would be more suited to fix it.
 
Level 4
Joined
Jan 9, 2024
Messages
38
Thanks for looking in to it. I'll go with your talent system for now. This is the best talent system I've seen so far and it's great for RPG maps.
 
Top