1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  4. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  5. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[GUI-Friendly] Talent 1.24b

Submitted by Tasyen
This bundle is marked as approved. It works and satisfies the submission rules.

What is Talent?


Talent provides Heroes at specific levels a choice out of multiple Options.
Options and choices have to be setuped for each heroType using Talent.
You might know such a behaviour from heroes of the storm.


Talent can add abilities or increase the level of them when selecting an choice.
One can also use the TalentEvent System to do actions when a talent was picked/removed.
Any amount of heroes can use Talent at the same time and can pick individual.

Requiers quite a lot of Object Editor abilities managing the choices.
Each choice is an abilitiy, each choice-tier is a spellbook and each hero using Talent needs the default / or hero specific UI spellbook to be considered beeing able to do choices.

New 1.24a.
There is now Talent Control an Unit used as User Interface allowing the player:
  1. show choices picked by a selected hero (might bug, if choices are not unique or a hero has more than 9)
  2. show the possible choices of level x of a selected hero.
  3. Reset the last Choice done by a own hero.



How to install


  • Make sure World Editor generates unknown variables in Preferences is set.
  • Copy the Talent Folder.
    • Copy or Create the UI-Choice (Spellbook)
    • Copy or Create the empty hero skill
    • Copy the 3 Talent Conrol Skill if you use Talent Control.
    • Copy the unit Talent Control
  • update references inside TalentControl Init
  • update references inside Talent Init
  • Installed



Definitions

This are options you can change in the jass code.
Code (vJASS):

constant function TalentUseSkillPoints takes nothing returns boolean
  //UseSkillPoints will spent and requier Skill-Points to pick talents.

constant function TalentControlSkillPoints takes nothing returns boolean
  //This will make the system only give your hero skill Points if he get's a choice.
  //       your heroes need atleast 1 learnable Skill to adjust skillPoints.

constant function TalentHideUIWhenUnneeded takes nothing returns boolean
  //Hide the UI Button when you can't learn a talent.
constant function TalentIncreaseByDoubleLearning takes nothing returns boolean
  //Increases the Level of abilities gained by choices, if the ability is already owned.
 



How to use Talent?




ObjectEditor:
Create Tier spellbooks, which containing the choices.
Make sure Tier spellbooks use the same Orderstring as the UI-book​
Create choices and add them to the tiers.
in 1 Tier each choice have to use an unique OrderString
Trigger Editor:
Now you need to tell Talent when a hero gains this tier, you can do that with jass or GUI.
The data is saved inside TalentHash onto the HeroTypeId, also one can setup auto added abilities onto the choice AbilityId.
Choices can add any amount of abilities, as long you start with index 0 and don't make any gaps (GUI hasn't to care about that).
One can also give each HeroType an custom UI-book.
Config Hero in Jass

Code (vJASS):

//Example for using Talent by Tasyen.
function Trig_SkillSelection_Paladin_Actions takes nothing returns nothing
   //Which HeroType is this
   local integer heroTypeId = 'H001'

   //you can give this hero a specific learn Book.
//   call SaveInteger( udg_SkillTrainHash, heroTypeId, -1, 'A00G')

   //this are hidden Spellbooks gained, when reaching that level.
   call SaveInteger( udg_SkillTrainHash, heroTypeId, 1, 'A00G')
   call SaveInteger( udg_SkillTrainHash, heroTypeId, 4, 'A00B')
   call SaveInteger( udg_SkillTrainHash, heroTypeId, 6, 'A00C')
   call SaveInteger( udg_SkillTrainHash, heroTypeId, 8, 'A00D')
   call SaveInteger( udg_SkillTrainHash, heroTypeId, 10, 'A00E')

   //Mark Level 10 as last choice, after doing it the selection skills are removed.
   call SaveBoolean(udg_SkillTrainHash, heroTypeId, 10, true)

  //Optional, you can now define automatic added skills (only use positive numbers starting with 0, no gaps), when picking a choice.
   call SaveInteger( udg_SkillTrainHash, 'A002', 0, 'Anhe')
   call SaveInteger( udg_SkillTrainHash, 'A001', 0, 'ACfb')
   call SaveInteger( udg_SkillTrainHash, 'A003', 0, 'ACfs')
   call SaveInteger( udg_SkillTrainHash, 'A004', 0, 'ACfn')
   call SaveInteger( udg_SkillTrainHash, 'A005', 0, 'AChx')
   call SaveInteger( udg_SkillTrainHash, 'A006', 0, 'ACif')
   call SaveInteger( udg_SkillTrainHash, 'A007', 0, 'ACmi')
   call SaveInteger( udg_SkillTrainHash, 'A008', 0, 'Awrs')
endfunction

//===========================================================================
function InitTrig_SkillSelection_Paladin takes nothing returns nothing
    set gg_trg_SkillSelection_Paladin = CreateTrigger(  )
    call TriggerAddAction( gg_trg_SkillSelection_Paladin, function Trig_SkillSelection_Paladin_Actions )
endfunction
 



Config Hero in GUI

  • Talen GUI Bloodmage
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Which HeroType uses this --------
      • Set Talent_GUI_HeroType = Bloodmage
      • -------- ---- --------
      • -------- Define at which levels an talent choice can be done for this hero. Index 0 is not supported --------
      • Set Talent_GUI_Levels[1] = 1
      • Set Talent_GUI_Levels[2] = 5
      • Set Talent_GUI_Levels[3] = 10
      • -------- Save the last index --------
      • Set Talent_GUI_Levels_Last = 3
      • -------- ---- --------
      • -------- Define the Choice Container added on each Talent_GUI_Level --------
      • Set Talent_GUI_Tiers[1] = Container - Choice (Bloodmage, Level 1)
      • Set Talent_GUI_Tiers[2] = Container - Choice (Bloodmage, Level 5)
      • Set Talent_GUI_Tiers[3] = Container - Choice (Bloodmage, Level 10)
      • -------- ---- --------
      • -------- Custom UI is optional, but might be good, if you want an special icon or use different Levels. --------
      • -------- beaware that your hero has to have the custom UI or the default UI, ability to be autoregistered by this System. --------
      • Set Talent_GUI_CustomUI = UI Choice (Bloodmage)
      • -------- ---- --------
      • -------- Register this Hero --------
      • Trigger - Run TalentGUI <gen> (ignoring conditions)
      • -------- ---- --------
      • -------- ---- --------
      • -------- Optional: define autoadded skills for choices, a choice can add multiple Skills. --------
      • -------- ---- --------
      • Set Talent_GUI_Choice = Choice - Flamestrike + Banish (Bloodmage, Level 1)
      • Set Talent_GUI_Choice_SkillGained = Flamestrike
      • Trigger - Run Talent_GUI_AddSkill2Choice (ignoring conditions)
      • Set Talent_GUI_Choice_SkillGained = Banish
      • Trigger - Run Talent_GUI_AddSkill2Choice (ignoring conditions)
      • -------- ---- --------
      • -------- ---- --------
      • Set Talent_GUI_Choice = Choice - Manadrain + Warstomp (Bloodmage, Level 1)
      • Set Talent_GUI_Choice_SkillGained = Drain Mana
      • Trigger - Run Talent_GUI_AddSkill2Choice (ignoring conditions)
      • Set Talent_GUI_Choice_SkillGained = WarStomp
      • Trigger - Run Talent_GUI_AddSkill2Choice (ignoring conditions)



It is also possible to copy the talent setup from another heroType with one line.
call TalentCopy('H003', 'H001')   //'H003' uses the same talents as 'H001'





Talent Event


Variable Info
Talent__Event 1 = Hero Picks a Talent
2 = Hero gains a TalentTier
3 = A hero finished the last choice he can do.
-1 = lost a choice cause of Reset
Talent__Event_Hero the hero gaining/doing the choice
Talent__Event_Choice the choice choosen/reseted or the choice container gained
Talent__Event_Level the level from which this choice/container is


On Choice

  • Demo Event Choose Skill
    • Events
      • Game - Talent__Event becomes Equal to 1.00
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Proper name of Talent__Event_Hero) + ( picked + (Name of Talent__Event_Choice)))
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • Talent__Event_Choice Equal to Choice - 6 Str (Paladin, Level 1)
          • Then - Actions
            • Hero - Modify Strength of Talent__Event_Hero: Add 6
            • Special Effect - Create a special effect attached to the origin of Talent__Event_Hero using Abilities\Spells\Items\AIsm\AIsmTarget.mdl
              • Special Effect - Destroy (Last created special effect)
          • Else - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • Talent__Event_Choice Equal to Choice - 6 Int (Paladin, Level 1)
              • Then - Actions
                • Hero - Modify Intelligence of Talent__Event_Hero: Add 6
                • Special Effect - Create a special effect attached to the origin of Talent__Event_Hero using Abilities\Spells\Items\AIim\AIimTarget.mdl
                  • Special Effect - Destroy (Last created special effect)
              • Else - Actions
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • Talent__Event_Choice Equal to Choice - 6 Agi (Paladin, Level 1)
                  • Then - Actions
                    • Hero - Modify Agility of Talent__Event_Hero: Add 6
                    • Special Effect - Create a special effect attached to the origin of Talent__Event_Hero using Abilities\Spells\Items\AIam\AIamTarget.mdl
                      • Special Effect - Destroy (Last created special effect)
                  • Else - Actions



Gain A Choice


  • Demo Event Gain a Choice
    • Events
      • Game - Talent__Event becomes Equal to 2.00
    • Conditions
    • Actions
    • Game - Display to (All players) the text: ((Proper name of Talent__Event_Hero) + ( can now choose a skill + (Name of Talent__Event_Choice)))



Reset


  • Demo Reset
    • Events
      • Player - Player 1 (Red) types a chat message containing reset as An exact match
    • Conditions
    • Actions
      • -------- Trigger based changes your have to revert yourself, best by using the -1 Event --------
      • Set Talent__Reseter = LastSelected
      • -------- How many talent choices are undone? if you want all, use a absurd high number. --------
      • Set Talent__ResetAmount = 99
      • Trigger - Run TalentReset (ignoring conditions)

  • Demo Event Reset Skill
    • Events
      • Game - Talent__Event becomes Equal to -1.00
    • Conditions
    • Actions
      • -------- Talent__Event_Level on Reset is incorrect, if a hero picks the same choice in different Choice Tiers. --------
      • Game - Display to (All players) the text: ((Proper name of Talent__Event_Hero) + ( lost + ((Name of Talent__Event_Choice) + ( Talent From LVL: + (String(Talent__Event_Level))))))
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • Talent__Event_Choice Equal to Choice - 6 Str (Paladin, Level 1)
          • Then - Actions
            • Hero - Modify Strength of Talent__Event_Hero: Remove 6
          • Else - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • Talent__Event_Choice Equal to Choice - 6 Int (Paladin, Level 1)
              • Then - Actions
                • Hero - Modify Intelligence of Talent__Event_Hero: Remove 6
              • Else - Actions
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • Talent__Event_Choice Equal to Choice - 6 Agi (Paladin, Level 1)
                  • Then - Actions
                    • Hero - Modify Agility of Talent__Event_Hero: Remove 6
                  • Else - Actions






Technical how do this work:



Talent uses some spellbook tricks.
  1. Spellbooks using the same Orderstring will show all spells in each book with the same Orderstring the unit currently has when opening one of them.
  2. Skills inside spellbooks will show themself, even if the spellbook containing them is disabled.
With this 2 facts above I did now following:
  • Create an Empty-UI Spellbook: it's purpose is to show currently avaible Talents, give vargue info when this hero will gain Talents and identify a hero using this system.
  • Create Choice-Container Spellbooks: This ones contain the avaible choices of a Tier-Level. They are dynamicly added/removed. At a pretty early stage I decided that it would be best to show only one Tier at the same time, out of 2 reasons:
    • It allows to reuse OrderStrings in different Tier levels, reduces the amount of orders this system blocks overall.
    • It would be overloaded, with showing only 1 tier at the same time your choices are quite clear.
  • Create Choices: Best here are channel based skills to define the Orderstring to avoid same OrderStrings in one Tier.
    • The choices itself will never be finished casting, by using the "start channeling event" wierd effects from cast points are excluded.
    • At an early stage one had to define that a choice is a choice by saving a boolean/Integer on each Choice, but after some versions I got an Idea how to identify a choice without saving anything at the choice and without forcing any special order/name. Choices have a special attribute already: They are in a choice container, more directly they are in the container the hero currently choose from. If one removes the choice container, inside the "start channeling Event" and the hero hasn't the choice after the remove anymore, it is a choice if not, simply readd the choice again.
Now the datastruct is set.



System Code

Code (vJASS):

//Talent 1.24a
//by Tasyen

//===========================================================================
// Gives wanted Heroes on specific Levels a choice between optins.
// can replace the default skill choicing or work seperate.
//===========================================================================
//Event:
//===========================================================================
//   udg_Talent__Event
//           = 1 => on Choice.
//               after the Auotskills are added
//           = 2 => choice-Container aviable, does only call when there is no choice for this hero yet.
//           = 3 => Finished all choices of its hero Type.
//           = -1 => on Reset for each choice reseted.
//               before the autoskills are removed

//   udg_Talent__Event_Hero = the unit gaining the skill
//   udg_Talent__Event_Choice = the choice choosen/reseted or the choice container gained.
//    udg_Talent__Event_Level = the level from which this choice/container is.
//===========================================================================
//udg_TalentTrigger is an array of Triggers controlling this system.
//       udg_TalentTrigger[0] = Enables Choices| specific unit starts channel
//       udg_TalentTrigger[1] = On Levelup| specific unit
//       udg_TalentTrigger[2] = EnterPlayable Map
//       , if you alreay have a EnterPlayable Map trigger you might remove the event inside the init and let yours call this one.
//       udg_TalentTrigger[3] = Make Talent UI Visbile; Event On Unit Selection.
//       udg_TalentTrigger[4] = Hides the UI when spending Skill-Points for something else.

// once your map reached a state in which there is no choice possible anymore it might be a good idea to disable 0 to 4.

//       udg_TalentReset = No Event; when called resets udg_Talent__Reseter and calls for each choice undone the reset event(-1).
//       a successful reset will enable udg_TalentTrigger[0]
//           Reset uses following values
//                   udg_Talent__ResetAmount = amount of talents undone starting from last selected. (use an absurd high number to undo all talents of a hero)
//                   udg_Talent__Reseter = the hero losing talents.

//   function TalentResetDo takes unit u, integer amountOfResets returns nothing
//       - undo amountOfResets choices for unit u.
//   function TalentCopy takes integer result, integer copyOrigin returns nothing
//       - units from type result will use the setup from copyOrigin
//===========================================================================
//Definitions:
//===========================================================================

//UseSkillPoints will spent and requier Skill-Points to pick talents.
constant function TalentUseSkillPoints takes nothing returns boolean
   return false
endfunction

//This will make the system only give your hero skill Points if he get's a choice.
//       your heroes need atleast 1 learnable Skill to adjust skillPoints.
constant function TalentControlSkillPoints takes nothing returns boolean
   return false
endfunction

//Hide the UI Button when you can't learn a talent.
//At true will give udg_TalentTrigger[3] the Event "selects a unit" for each player.
constant function TalentHideUIWhenUnneeded takes nothing returns boolean
   return true
endfunction

//Increases the Level of abilities gained by choices, if the ability is already owned.
constant function TalentIncreaseByDoubleLearning takes nothing returns boolean
   return true
endfunction

//===========================================================================
//Hashtable
//handleId

constant function TalentHashIndex_LastLevel takes nothing returns integer
   return -1
endfunction
constant function TalentHashIndex_LevelOfLastChoice takes nothing returns integer
   return -2
endfunction
constant function TalentHashIndex_CurrentChoice takes nothing returns integer
   return -3
endfunction
constant function TalentHashIndex_CurrentChoiceLevel takes nothing returns integer
   return -4
endfunction
constant function TalentHashIndex_SelectionsDone takes nothing returns integer
   return -5
endfunction
constant function TalentHashIndex_SkillPoints takes nothing returns integer
   return -10
endfunction
constant function TalentHashIndex_HasChoice takes nothing returns integer
   return 0
endfunction

//UnitTypeId
//   0 to x choice containers
//   x  =  last talent(true)
constant function TalentHashIndex_DataCustomUI takes nothing returns integer
   return -1
endfunction
constant function TalentHashIndex_DataCopyData takes nothing returns integer
   return -2
endfunction
//===========================================================================

function TalentGetUnitTypeId takes unit u returns integer
   local integer heroTypeId = GetUnitTypeId(u)
   local integer copyId = LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCopyData())
   if copyId != 0 then   //Copy another HeroType?
       return copyId
   else
       return heroTypeId
   endif
endfunction
function TalentCopy takes integer result, integer copyOrigin returns nothing
   call SaveInteger(udg_TalentHash, result, TalentHashIndex_DataCopyData(), copyOrigin)
endfunction
//has the general Choice UI or hero specific Choice UI.
function TalentHas takes unit u returns boolean
   return GetUnitAbilityLevel(u, udg_Talent_DefaultUI) != 0 or GetUnitAbilityLevel(u, LoadInteger(udg_TalentHash, TalentGetUnitTypeId(u), TalentHashIndex_DataCustomUI())) != 0
endfunction

//has the general Choice UI or hero specific Choice UI.
function TalentHasCondition takes nothing returns boolean
   return TalentHas(GetTriggerUnit())
endfunction

function TalentAddSelection takes unit u, integer uId returns nothing
   local integer containerGained
   local integer heroTypeId = TalentGetUnitTypeId(u)
   local integer currentLevel = GetHeroLevel(u)
   local player owner
   //Start from the last skill selection added.
   local integer loopA = LoadInteger(udg_TalentHash, uId,TalentHashIndex_LevelOfLastChoice())
   // Only show 1 SelectionContainer at the same time.
   if LoadBoolean(udg_TalentHash, uId,TalentHashIndex_HasChoice()) then
       return
   endif
   set owner = GetOwningPlayer(u)
   loop
       exitwhen loopA > currentLevel
       set containerGained = LoadInteger(udg_TalentHash, heroTypeId, loopA)    
       if containerGained != 0 then
           call UnitAddAbility(u, containerGained)
           call UnitMakeAbilityPermanent(u, true, containerGained)
           call SetPlayerAbilityAvailable(owner, containerGained, false)
     
           //Remember the container gained
           call SaveInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoice(), containerGained)
           //Remember the level of the container gained
           call SaveInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoiceLevel(), loopA)
           //Mark unit to have a selection.
           call SaveBoolean(udg_TalentHash, uId, TalentHashIndex_HasChoice(), true)
           //Remember this Level to leave lower levels out for further selections checks.
           call SaveInteger(udg_TalentHash, uId,TalentHashIndex_LevelOfLastChoice(),loopA +1)
           // show UI
           call SetPlayerAbilityAvailable(owner, udg_Talent_DefaultUI, true)
           call SetPlayerAbilityAvailable(owner, LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()), true)
           //Throw Selection Event

           set udg_Talent__Event_Choice = containerGained
           set udg_Talent__Event_Hero = u
           set udg_Talent__Event_Level = loopA
           set udg_Talent__Event = 2
           set udg_Talent__Event = 0
           set owner = null
           return
       endif
       set loopA = loopA + 1
   endloop
   //if this part of code is reached there is no choice avaible
 
   //Remember this Level to leave lower levels out for further selections checks.
   call SaveInteger(udg_TalentHash, uId,TalentHashIndex_LevelOfLastChoice(),currentLevel + 1)
 
   //Hide UI when wanted so
   if TalentHideUIWhenUnneeded() then
       call SetPlayerAbilityAvailable(owner, udg_Talent_DefaultUI, false)
       call SetPlayerAbilityAvailable(owner, LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()), false)
   endif
   set owner = null
endfunction
function TalentLevelUpA takes unit u, integer uId returns nothing
   local integer lastLevel = LoadInteger(udg_TalentHash, uId, TalentHashIndex_LastLevel())
   local integer currentLevel = IMaxBJ(GetHeroLevel(u), GetUnitLevel(u))
   local integer heroTypeId = TalentGetUnitTypeId(u)
   local integer containerGained
   loop
       set containerGained = LoadInteger(udg_TalentHash, heroTypeId, lastLevel)    
       if containerGained != 0 then
           call UnitModifySkillPoints(u, 1)
       endif
       set lastLevel = lastLevel + 1
       exitwhen lastLevel > currentLevel
   endloop
   //Save last Level
   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_LastLevel(), currentLevel + 1)
   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_SkillPoints(), GetHeroSkillPoints(u))
endfunction
function TalentLevelUp takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local integer uId = GetHandleId(u)
   //Reduce if he gained a skill Point.
   if LoadInteger(udg_TalentHash, uId, TalentHashIndex_SkillPoints()) < GetHeroSkillPoints(u) then
       call UnitModifySkillPoints(u, -1)
   endif
   call TalentLevelUpA(u,uId)
   call TalentAddSelection(u,uId)
   set u = null
endfunction

function TalentPickDo takes unit u, integer skillId returns nothing
   local integer uId = GetHandleId(u)
   local integer heroTypeId = TalentGetUnitTypeId(u)
   local integer skillGained
   local integer skillContainer = LoadInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoice())
   local integer skillContainerLevel = LoadInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoiceLevel())
   local integer selectionsDone = LoadInteger(udg_TalentHash, uId,TalentHashIndex_SelectionsDone()) + 1
   local integer loopB = 0
   local integer abilitylevel
   //add Skills
   loop
       set skillGained = LoadInteger(udg_TalentHash, skillId, loopB)
 
       if skillGained != 0 then
           set abilitylevel = GetUnitAbilityLevel(u, skillGained)
           if abilitylevel == 0 then
               call UnitAddAbility(u, skillGained)
               call UnitMakeAbilityPermanent(u, true, skillGained)
           elseif TalentIncreaseByDoubleLearning() then
               call SetUnitAbilityLevel(u, skillGained, abilitylevel + 1)
           endif
       endif
       exitwhen skillGained == 0
       set loopB = loopB + 1
   endloop
 
   //remove Container of this Selection
   //call UnitRemoveAbility(u, skillContainer)
 
   //Throw Selection Event
   set udg_Talent__Event_Choice = skillId
   set udg_Talent__Event_Hero = u
   set udg_Talent__Event_Level = skillContainerLevel
   set udg_Talent__Event = 1
   set udg_Talent__Event = 0
 
   //Save Choices
   call SaveInteger(udg_TalentHash, uId, selectionsDone, skillId)
   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_SelectionsDone(), selectionsDone)
   call SaveInteger(udg_TalentHash, uId, skillId, skillContainerLevel)
 
 
   //Unmark having a selection.
   call SaveBoolean(udg_TalentHash, uId, TalentHashIndex_HasChoice(), false)
   //Last choice for this heroType?
   if LoadBoolean(udg_TalentHash, heroTypeId, skillContainerLevel) then
       //has herospeciifc learnbook?
       if HaveSavedInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()) then
           call UnitRemoveAbility(u, LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()))
       else
           call UnitRemoveAbility(u, udg_Talent_DefaultUI)
       endif
       call UnitAddAbility(u, udg_Talent_EmptyHeroSkill)
       call SetUnitAbilityLevel (u, udg_Talent_EmptyHeroSkill, 4)
       //Throw Finish Choices Event.
       set udg_Talent__Event = 3
       set udg_Talent__Event = 0
   else
       //Check for further choices.
       call TalentAddSelection(u,uId)
   endif
   set u = null
endfunction
function TalentPickTimer takes nothing returns nothing
   local unit u
   local integer uId
   local integer skillContainer
   local integer skillId
   local integer gId = GetHandleId(udg_Talent_PickGroup)
   loop
       set u = FirstOfGroup(udg_Talent_PickGroup)
       exitwhen u == null
       call GroupRemoveUnit(udg_Talent_PickGroup,u)
       set uId = GetHandleId(u)
       set skillId = LoadInteger(udg_TalentHash,uId, gId)
       set skillContainer = LoadInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoice())
       //Remove the choice-container, if the unit loses the casted spell its a choice.
 
       call UnitRemoveAbility(u, skillContainer)
       if GetUnitAbilityLevel(u, skillId) != 0 then
           call UnitAddAbility(u, skillContainer)
       else
           //choice
     
           //Stop spellcasting
           call IssueImmediateOrder(u, "stop")
     
           // Skill-Points?
           if TalentUseSkillPoints() then
               if GetHeroSkillPoints(u) != 0 then
                   call UnitModifySkillPoints(u, -1)
                   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_SkillPoints(), GetHeroSkillPoints(u))
               else
                   //Not enough Skill-Points
                   call DisplayTimedTextToPlayer(GetOwningPlayer(u), 0, 0, 20, "Not enough Skill-Points")
                   call UnitAddAbility(u, skillContainer)
                   return
               endif
           endif
     
           // run the add skill script
           call TalentPickDo(u, skillId)
       endif
   endloop
endfunction
function TalentPick takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local integer uId = GetHandleId(u)

   //Is allowed to make a choice?
   if LoadBoolean(udg_TalentHash, uId, TalentHashIndex_HasChoice()) then
       call GroupAddUnit(udg_Talent_PickGroup, u)
       call SaveInteger(udg_TalentHash,uId, GetHandleId(udg_Talent_PickGroup), GetSpellAbilityId())
       call TimerStart(udg_Talent_PickTimer,0.01,false, function TalentPickTimer)
   endif
   set u = null
endfunction

function TalentLevelUpSimple takes nothing returns nothing
   call TalentAddSelection(GetTriggerUnit(),GetHandleId(GetTriggerUnit()))
endfunction
function TalentAdd2Hero takes unit u returns nothing
   local integer uId = GetHandleId(u)
   //call GroupAddUnit(udg_Talent_User, u)
   call TriggerRegisterUnitEvent( udg_TalentTrigger[0], u, EVENT_UNIT_SPELL_CHANNEL )
   call TriggerRegisterUnitEvent( udg_TalentTrigger[1], u, EVENT_UNIT_HERO_LEVEL)
   if TalentControlSkillPoints() then
       call UnitModifySkillPoints(u, -1)
       call TalentLevelUpA(u,uId)
   endif
   if TalentHideUIWhenUnneeded() and TalentUseSkillPoints() then
       call TriggerRegisterUnitEvent( udg_TalentTrigger[4], u, EVENT_UNIT_HERO_SKILL)
   endif
   call TalentAddSelection(u,uId)
   set u = null
endfunction
function TalentAutoOnEnterMap takes nothing returns nothing
   call TalentAdd2Hero(GetTriggerUnit())
endfunction

function TalentResetDo takes unit u, integer amountOfResets returns nothing
   local integer uId
   local integer heroTypeId
   local integer selectionsDone
   local integer skillGained
   local integer choice
   local integer level
   local integer loopB = 0
   local integer abilitylevel
   //stop nullpointer.
   if u == null then
       return
   endif
   // reset less then 1 does not make sense.
   if amountOfResets < 1 then
       return
   endif
   set uId = GetHandleId(u)
   set heroTypeId = TalentGetUnitTypeId(u)
   set selectionsDone = LoadInteger(udg_TalentHash, uId, TalentHashIndex_SelectionsDone())
   //No selections done -> skip the rest.
   if selectionsDone == 0 then
       return
   endif
   set udg_Talent__Event_Hero = u
 
   //Remove Autoadded Skills
   loop
       set choice = LoadInteger(udg_TalentHash, uId, selectionsDone)
       set udg_Talent__Event_Choice = choice
       set level = LoadInteger(udg_TalentHash, uId, choice)
       set udg_Talent__Event_Level = level
       //Throw a event that this choice is going to be lost.
       set udg_Talent__Event = -1
       set udg_Talent__Event = 0
       //Remove all Skill this Choice added.
       set loopB = 0
       loop
           set skillGained = LoadInteger(udg_TalentHash, choice, loopB)
           exitwhen skillGained == 0
           set abilitylevel = GetUnitAbilityLevel(u, skillGained)
           if abilitylevel > 1 and TalentIncreaseByDoubleLearning() then
               call SetUnitAbilityLevel(u, skillGained, abilitylevel - 1)
           else
               call UnitRemoveAbility(u, skillGained)
           endif
           set loopB = loopB + 1
       endloop
       set selectionsDone = selectionsDone - 1
       set amountOfResets = amountOfResets - 1
       exitwhen selectionsDone <= 0 or amountOfResets <= 0
   endloop
 
   //Enable Choices again.
   call  EnableTrigger (udg_TalentTrigger[0])
 
   //Remove Current Choice Container.
   call UnitRemoveAbility(u, LoadInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoice()))
 
   //Forget this unit?
   if selectionsDone <= 0 then
       //Full Reset
       call FlushChildHashtable(udg_TalentHash, uId)
   else
       //Partly Reset.
 
       //Has no Choice,dat is needed to run the addChoice function.
       call SaveBoolean(udg_TalentHash, uId,TalentHashIndex_HasChoice(), false)

       //Save Level Progress of talents to the choice Level.
       call SaveInteger(udg_TalentHash, uId, TalentHashIndex_LevelOfLastChoice(), level)
 
       //Save Level Progress skillPoints
       call SaveInteger(udg_TalentHash, uId, TalentHashIndex_LastLevel(), level)
 
       //Choices Done
       call SaveInteger(udg_TalentHash, uId,TalentHashIndex_SelectionsDone(), selectionsDone)
   endif
 
   //Regain Choice UI
   //has herospeciifc learnbook?
   if HaveSavedInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()) then
       call UnitAddAbility(u, LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI()))
   else
       call UnitAddAbility(u, udg_Talent_DefaultUI)
 
   endif
   call UnitRemoveAbility(u, udg_Talent_EmptyHeroSkill)
 
   //Recalc skillpoints if wanted.
   if TalentUseSkillPoints() then
       call UnitModifySkillPoints(u, -9999)
       call TalentLevelUpA(u,uId)
   endif
   call TalentAddSelection(u,uId)
endfunction

function TalentReset takes nothing returns nothing
   call TalentResetDo(udg_Talent__Reseter, udg_Talent__ResetAmount)
       set udg_Talent__Reseter = null
endfunction

function TalentShowUI takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local player owner = GetOwningPlayer(u)
   local integer customUI = LoadInteger(udg_TalentHash, TalentGetUnitTypeId(u), TalentHashIndex_DataCustomUI())
   local boolean show = LoadBoolean(udg_TalentHash, GetHandleId(u), TalentHashIndex_HasChoice() )
   call SetPlayerAbilityAvailable(owner, udg_Talent_DefaultUI, show)
   call SetPlayerAbilityAvailable(owner, customUI, show)
   set u = null
   set owner = null
endfunction

function TalentSpentSkillPoints takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local player owner = GetOwningPlayer(u)
   local integer customUI
   local integer skillPoints = GetHeroSkillPoints(u)
 
   call SaveInteger(udg_TalentHash, GetHandleId(u), TalentHashIndex_SkillPoints(), skillPoints - 1)
   //Spent the last Point?
   if skillPoints == 1 then
       set customUI = LoadInteger(udg_TalentHash, TalentGetUnitTypeId(u), TalentHashIndex_DataCustomUI())
       call SetPlayerAbilityAvailable(owner, udg_Talent_DefaultUI, false)
       call SetPlayerAbilityAvailable(owner, customUI, false)
   endif
   set u = null
   set owner = null
endfunction

function TalentShowUICon takes nothing returns boolean
   return TalentHas(GetTriggerUnit()) and IsUnitOwnedByPlayer(GetTriggerUnit(), GetTriggerPlayer())
endfunction


//runs when executing the Talent <gen> trigger.
function TalentInit takes nothing returns nothing
   local group g = CreateGroup()
   local unit fog
   local integer fogId
   local integer loopA = 0
   set udg_TalentTrigger[0] = CreateTrigger()
   set udg_TalentTrigger[1] = CreateTrigger()
   set udg_TalentTrigger[2] = CreateTrigger()
   set udg_TalentTrigger[3] = CreateTrigger()
   set udg_TalentTrigger[4] = CreateTrigger()

   set udg_TalentReset = CreateTrigger()
     
   call TriggerAddAction( udg_TalentReset, function TalentReset)
 
   //Do a choice.
   call TriggerAddAction( udg_TalentTrigger[0],  function TalentPick )
 
   call TriggerAddAction( udg_TalentTrigger[4],  function TalentSpentSkillPoints )
     
   //Get a choice when Level Up
   //when using skillpoints the default hero skill system should not be used for this hero.
   if TalentControlSkillPoints() then
       call TriggerAddAction( udg_TalentTrigger[1], function TalentLevelUp)
   else
       call TriggerAddAction( udg_TalentTrigger[1], function TalentLevelUpSimple)
   endif
 
   call TriggerAddAction( udg_TalentTrigger[3], function TalentShowUI)
   call TriggerAddCondition( udg_TalentTrigger[3], Condition( function TalentShowUICon ))
 
 
   //Get Choices on Entering Map for lvl 0/1.
   call TriggerRegisterEnterRectSimple( udg_TalentTrigger[2], GetPlayableMapRect() )
   call TriggerAddAction( udg_TalentTrigger[2], function TalentAutoOnEnterMap)
   call TriggerAddCondition( udg_TalentTrigger[2], Condition( function TalentHasCondition ))
   loop
       call SetPlayerAbilityAvailable(Player(loopA),  udg_Talent_EmptyHeroSkill, false)
       if TalentHideUIWhenUnneeded() then
           call TriggerRegisterPlayerUnitEvent(udg_TalentTrigger[3], Player(loopA), EVENT_PLAYER_UNIT_SELECTED, null)
       endif
       set loopA = loopA + 1
       exitwhen loopA == bj_MAX_PLAYER_SLOTS
   endloop
 
   //Add possible choices to all Units having the Talent book.
   call GroupEnumUnitsInRect (g, GetPlayableMapRect(), null)
   loop
       set fog = FirstOfGroup(g)
       exitwhen fog == null
       call GroupRemoveUnit(g,fog)
       if TalentHas(fog) then
           call TalentAdd2Hero(fog)
       endif
   endloop
 
   //cleanup
   call DestroyGroup(g)
   set g = null
   set fog = null
 
   //make this trigger unuseable
   call TriggerClearActions(gg_trg_Talent)
   call TriggerClearConditions(gg_trg_Talent)
endfunction
//===========================================================================
function InitTrig_Talent takes nothing returns nothing
   set gg_trg_Talent = CreateTrigger(  )
   set udg_TalentHash = InitHashtable(  )
   call TriggerAddAction( gg_trg_Talent, function TalentInit)
endfunction
 

Code (vJASS):

//TalentControl 1.0
//by Tasyen

//===========================================================================
// An Subresource of Talent, it generates an Unit with skills to checkout Talent of others.
//   or checkout talents of further levels
//===========================================================================

//   TalentControl Is MPI, while Talent is MUI

//Definitions:
//===========================================================================

constant function TalentDialogButtonPrefix takes nothing returns string
   return "Level: "
endfunction
constant function TalentDialogButtonSufix takes nothing returns string
   return ""
endfunction
constant function TalentDialogNextPageButton takes nothing returns string
   return "Next Page"
endfunction
constant function TalentDialogExitButton takes nothing returns string
   return "Exit"
endfunction
constant function TalentDialogTitle takes nothing returns string
   return "Talents"
endfunction
//Number of Tiers shown on each Page, page control is only shown if surpassed.
constant function TalentDialogPageSize takes nothing returns integer
   return 5
endfunction
//Number of talents the TalentControl reset spell will reset.
constant function TalentResetsBySkill takes nothing returns integer
   return 1
endfunction
//===========================================================================
//Will return the choice done
//ChoiceIndex is not the level the talent was gained, it is the choice done overall, starting with 1.
//will return -1, if an invalid Index was choosen.
function TalentHeroGetChoice takes unit u, integer choiceIndex returns integer
   local integer uId = GetHandleId(u)
   if choiceIndex <= LoadInteger(udg_TalentHash,uId,-5) and choiceIndex > 0 then
       return LoadInteger(udg_TalentHash, uId, choiceIndex)
   else
       return -1
   endif
endfunction

function TalentPrintChoicesDone takes player p, unit u returns nothing
   local integer uId = GetHandleId(u)
   local integer selectionsDone = LoadInteger(udg_TalentHash, uId, TalentHashIndex_SelectionsDone())
   local integer loopA = 1
   local integer choice
   local integer choiceLevel
   loop
       exitwhen selectionsDone < loopA
       set choice = TalentHeroGetChoice(u, loopA)
       set choiceLevel = LoadInteger(udg_TalentHash,uId,choice)
       call DisplayTimedTextToPlayer(p, 0, 0, 20, GetObjectName(choice)+" at level: "+I2S(choiceLevel))
       set loopA = loopA + 1
   endloop
endfunction

function TalentClearShower takes unit dummy returns nothing
   local integer dummyId =  GetHandleId(dummy)
   local integer playerId = GetPlayerId(GetOwningPlayer(dummy))
   local integer selectionsDone = LoadInteger(udg_TalentHash, dummyId, TalentHashIndex_SelectionsDone())
   call UnitRemoveAbility(dummy, udg_TalentControlDummyChoice[playerId])
   call UnitRemoveAbility(dummy, udg_TalentControlDummyContainer[playerId])
   loop
       exitwhen selectionsDone < 1
       call UnitRemoveAbility(dummy, LoadInteger(udg_TalentHash,dummyId,selectionsDone))
       set selectionsDone = selectionsDone - 1
   endloop
   call FlushChildHashtable(udg_TalentHash, dummyId)
endfunction

//Choices have to be added from last learned to first learned to be ordered correctly
function TalentAddChoicesDone takes unit hero, unit dummy returns nothing
   local integer uId = GetHandleId(hero)
   local integer dummyId = GetHandleId(dummy)
   local integer selectionsDone = LoadInteger(udg_TalentHash, uId, TalentHashIndex_SelectionsDone())
   local integer choice
   local integer choiceLevel
   call TalentClearShower(dummy)
   call SaveInteger(udg_TalentHash,dummyId,TalentHashIndex_SelectionsDone(), selectionsDone)
   loop
       exitwhen selectionsDone < 1
       set choice = TalentHeroGetChoice(hero, selectionsDone)
       set choiceLevel = LoadInteger(udg_TalentHash,uId,choice)
       call UnitAddAbility(dummy, choice)
       call SaveInteger(udg_TalentHash,dummyId,selectionsDone, choice)
       set selectionsDone = selectionsDone - 1
   endloop
endfunction

function TalentShowOptions takes integer containerGained, unit dummy, unit target returns nothing
   local player owner = GetOwningPlayer(dummy)
   local integer playerId = GetPlayerId(owner)
   local integer customUI = LoadInteger(udg_TalentHash, TalentGetUnitTypeId(target), TalentHashIndex_DataCustomUI())
   call TalentClearShower(dummy)
   if customUI == 0 then
       call UnitAddAbility(dummy, udg_Talent_DefaultUI)
       set udg_TalentControlDummyContainer[playerId] = udg_Talent_DefaultUI
   else
       call UnitAddAbility(dummy, customUI)
       set udg_TalentControlDummyContainer[playerId] = customUI
   endif
   set udg_TalentControlDummyChoice[playerId] = containerGained
   call UnitAddAbility(dummy, containerGained)
   call SetPlayerAbilityAvailable(owner, udg_TalentControlDummyChoice[playerId], false)
   call SetPlayerAbilityAvailable(owner, udg_TalentControlDummyContainer[playerId], true)
   set owner = null
endfunction
//calculates the Values Of Buttons.
function TalentGetButtonValues takes integer playerId, integer dialogId, integer heroTypeId returns nothing
   local integer count = 0
   local integer container
   local integer level = 0
   loop
       set container = LoadInteger(udg_TalentHash,heroTypeId,level)
       if container != 0 then
           set count = count + 1
           call SaveInteger(udg_TalentHash, dialogId, count, container)
           call SaveStr(udg_TalentHash, dialogId, count,  TalentDialogButtonPrefix()+I2S(level)+TalentDialogButtonSufix())
       endif
       //First do the stuff to include the last Level.
       exitwhen LoadBoolean(udg_TalentHash, heroTypeId, level)
       set level = level + 1
   endloop
   //amount of buttons created.
   set udg_TalentControlDialogButtonCount[playerId] = count

   //needs Page control?
   set udg_TalentControlDialogHasPages[playerId] = ( count > TalentDialogPageSize() )
endfunction

function TalenCleanButtons takes integer playerId returns nothing
   local integer dialogId = GetHandleId(udg_TalentControlDialog[playerId])
   local integer LoopA = 1
   local button b
   loop
       set b = LoadButtonHandle(udg_TalentHash,dialogId,LoopA)
       exitwhen b == null
       call FlushChildHashtable(udg_TalentHash, GetHandleId(b))
       set LoopA = LoopA + 1
   endloop
   call DialogClear(udg_TalentControlDialog[playerId])
endfunction
function TalentShowPage takes integer playerId, dialog d, integer page returns boolean
   local integer countAtPage = 0
   local integer count = page * TalentDialogPageSize()
   local button b
   local integer dialogId = GetHandleId(d)
   local boolean doneSomething = false

   call TalenCleanButtons(playerId)
 
   loop
       exitwhen countAtPage >= TalentDialogPageSize() or count >= udg_TalentControlDialogButtonCount[playerId]
       set count = count + 1
       set countAtPage = countAtPage + 1
       set doneSomething = true
       set b = DialogAddButton(d, LoadStr(udg_TalentHash,dialogId,count), 0)
 
       call SaveButtonHandle(udg_TalentHash,dialogId,countAtPage,b)
       call SaveInteger(udg_TalentHash, GetHandleId(b),0,count)
   endloop

   if udg_TalentControlDialogHasPages[playerId] then
       set udg_TalentControlDialogNextPage[playerId] = DialogAddButton(d, TalentDialogNextPageButton(), 0)
   endif
   set udg_TalentControlDialogExit[playerId] = DialogAddButton(d, TalentDialogExitButton(), 0)
   if doneSomething then
       set udg_TalentControlDialogPageNr[playerId] = page
   endif

   return doneSomething
endfunction


function TalentDummyCasts takes nothing returns nothing
   local unit dummy = GetTriggerUnit()
   local integer skillId = GetSpellAbilityId()
   local player owner =GetOwningPlayer(dummy)
   local unit target = GetSpellTargetUnit()
   local integer playerId = GetPlayerId(owner)
   local integer dialogId
   local integer dummyId = GetHandleId(GetTriggerUnit())
   local integer heroTypeId
   if LoadInteger(udg_TalentHash, GetHandleId(target),-5) != 0 or TalentHas(target) then
       if skillId == udg_TalentControl_ChoicesDone then
           call TalentAddChoicesDone (target, GetTriggerUnit())
       elseif skillId == udg_TalentControl_ResetLastChoice then
           //Using the GUI Reset Interface avoids problems with default world Editor.
           set udg_Talent__Reseter = target
           set udg_Talent__ResetAmount = TalentResetsBySkill()
           call TriggerExecute(udg_TalentReset)
       elseif skillId == udg_TalentControl_TalentListViewer then
           set dialogId = GetHandleId(udg_TalentControlDialog[playerId])
           set heroTypeId = TalentGetUnitTypeId(target)
     
           //is other heroType?
           if heroTypeId != udg_TalentControlDialogUnitType[playerId] then
               //Yes rebuild the dialog
               set udg_TalentControlDialogUnitType[playerId] = heroTypeId
               call TalenCleanButtons(playerId)
               call FlushChildHashtable(udg_TalentHash, dialogId)
               //Create Buttons
               call TalentGetButtonValues(playerId, dialogId, heroTypeId)
               call TalentShowPage(playerId, udg_TalentControlDialog[playerId], 0)        
           endif
           set udg_TalentControlDialogTarget[playerId] = target
           call DialogSetMessage(udg_TalentControlDialog[playerId], TalentDialogTitle())
           call DialogDisplay (owner, udg_TalentControlDialog[playerId], true)
       endif
   endif
   set owner = null
   set dummy = null
   set target = null
endfunction

function TalentDialogButton takes nothing returns nothing
   local dialog d =  GetClickedDialog ()
   local button b = GetClickedButton ()
   local integer dialogId = GetHandleId(d)
   local integer playerId = GetPlayerId(GetTriggerPlayer())
   local integer loopA = 1
   local integer container

   if  b == udg_TalentControlDialogNextPage[playerId] then   //PageControl?
       if not TalentShowPage(playerId, d, udg_TalentControlDialogPageNr[playerId] + 1) then
           call TalentShowPage(playerId, d, 0)
       endif
       call DialogSetMessage(udg_TalentControlDialog[playerId], TalentDialogTitle())
       call DialogDisplay(GetTriggerPlayer(), d, true)
 
   elseif b == udg_TalentControlDialogExit[playerId] then   //Exit?
 
   else   //Normal Button
       set container = LoadInteger(udg_TalentHash, dialogId, LoadInteger(udg_TalentHash, GetHandleId(b),0))
       call TalentShowOptions( container,  udg_TalentControlDummy[playerId], udg_TalentControlDialogTarget[playerId])
   endif
   set d = null
   set b = null
endfunction
//runs when executing the Talent <gen> trigger.
function TalentControlInit takes nothing returns nothing
   local integer loopA = 0
   local trigger dialogTrigger = CreateTrigger()
   //make this trigger unuseable
   call TriggerClearActions(gg_trg_TalentControl)
   call TriggerClearConditions(gg_trg_TalentControl)

   call TriggerAddAction( gg_trg_TalentControl, function TalentDummyCasts)
   call TriggerAddAction( dialogTrigger, function TalentDialogButton)
 
   loop
       if GetPlayerController(Player(loopA)) == MAP_CONTROL_USER then   //Only players can use this
           set udg_TalentControlDummy[loopA] = CreateUnit(Player(loopA), udg_TalentControl_DummyType, 0,0,0)
           call TriggerRegisterUnitEvent( gg_trg_TalentControl, udg_TalentControlDummy[loopA], EVENT_UNIT_SPELL_EFFECT)
           call UnitAddAbility(udg_TalentControlDummy[loopA], udg_TalentControl_ChoicesDone)
           call UnitAddAbility(udg_TalentControlDummy[loopA], udg_TalentControl_TalentListViewer)
           call UnitAddAbility(udg_TalentControlDummy[loopA], udg_TalentControl_ResetLastChoice)    
           if udg_TalentControlDialog[loopA] == null then
                   set udg_TalentControlDialog[loopA] = DialogCreate()
               endif
           call TriggerRegisterDialogEvent (dialogTrigger, udg_TalentControlDialog[loopA])
       endif
       set loopA = loopA + 1
       exitwhen loopA == bj_MAX_PLAYER_SLOTS
   endloop
endfunction
//===========================================================================
function InitTrig_TalentControl takes nothing returns nothing
   set gg_trg_TalentControl = CreateTrigger(  )
   call TriggerAddAction( gg_trg_TalentControl, function TalentControlInit)
endfunction


 

Code (vJASS):

//Talent GUI
//by Tasyen
//===========================================================================
// Makes Talent Registering useable for GUI.
//===========================================================================
function TalentGuiRegisterHero takes nothing returns nothing
   local integer heroTypeId = udg_Talent_GUI_HeroType
   local integer loopA = 1
   if heroTypeId == 0 then
       return
   endif
   loop
       exitwhen loopA > udg_Talent_GUI_Levels_Last
       call SaveInteger(udg_TalentHash, heroTypeId, udg_Talent_GUI_Levels[loopA], udg_Talent_GUI_Tiers[loopA])
       set loopA = loopA + 1
   endloop
   call SaveBoolean(udg_TalentHash, heroTypeId, udg_Talent_GUI_Levels[udg_Talent_GUI_Levels_Last], true)
   if udg_Talent_GUI_CustomUI != 0 then
       call SaveInteger( udg_TalentHash, heroTypeId, -1, udg_Talent_GUI_CustomUI)
       set udg_Talent_GUI_CustomUI = 0
   endif
   set udg_Talent_GUI_HeroType = 0
endfunction
function TalentGuiAddSkill takes nothing returns nothing
   local integer size = LoadInteger(udg_TalentHash, udg_Talent_GUI_Choice,-1)
   call SaveInteger(udg_TalentHash, udg_Talent_GUI_Choice,size,udg_Talent_GUI_Choice_SkillGained)
   call SaveInteger(udg_TalentHash, udg_Talent_GUI_Choice,-1,size + 1)
endfunction
//===========================================================================
function InitTrig_TalentGUI takes nothing returns nothing
   set gg_trg_TalentGUI = CreateTrigger(  )
   set udg_Talent_GUI_AddSkill2Choice = CreateTrigger(  )
   call TriggerAddAction( gg_trg_TalentGUI, function TalentGuiRegisterHero)
   call TriggerAddAction( udg_Talent_GUI_AddSkill2Choice, function TalentGuiAddSkill)
endfunction
 



Changelog:
V 1.24b:
Tier 2 and 3 for Bloodmage demo are now unique spellbooks.​
V1.24a:
SkillPoint control & usage are now splited and each can be setuped indepently.
Added TalentControl
Added TalentCopy (integer result, integer copyOrigin)
result will use the setup from copyOrigin
Fixed a serious bug, leading to a buggy group control: a talent picker counted as channeling for any action he done afterwards.
Added better api for reset.​
Changelog: V1.22 - first uploaded Version.

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

Talent 1.24b (Map)

Reviews
Dr Super Good
Comments and Suggestions: Potentially useful system for people who like this style of hero progression. Easy to use and flexible. Although the demo map does work correctly, it is very easy to think that the system is bugging out due to the...
  1. streetpunk

    streetpunk

    Joined:
    Oct 9, 2015
    Messages:
    721
    Resources:
    2
    Spells:
    2
    Resources:
    2
    It's a nice adition to the hive, a virtualy simple system wich extends the possibilities for map maker. As I was testing it, I realized that the game crashes if you cast 2 flame strikes at once
     
    Last edited: Dec 7, 2017
  2. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,186
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    Not for me, was able to pick flamestrike with all 3 palas + bloodmage and cast them almost the same time.

    Did the map break for you, can i know what your did?

    The choices should be made with channel based skills, to control taken order and skip strange sideeffects (the spells are not casted but their might happen something still).
     
    Last edited: Dec 5, 2017
  3. streetpunk

    streetpunk

    Joined:
    Oct 9, 2015
    Messages:
    721
    Resources:
    2
    Spells:
    2
    Resources:
    2
    I didn't modified anything, I just ran the map, pick paladin get tomes, learn flamestrike. pick bloodmage, also learn flamestrike. then cast 2 flamestrikes at the same time at the same spot, game crashed.

    PS: I use 1.26
     
  4. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,186
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    That is sad, but i can not test what crahses on 1.26, with having the newest version of warcraft.

    1.26 has this Crash reason infos. Was there one, it might sometimes help?
     
  5. ssbbssc2

    ssbbssc2

    Joined:
    Aug 20, 2015
    Messages:
    108
    Resources:
    0
    Resources:
    0
    crash with 2 flamestrikes confirmed
     
  6. ssbbssc2

    ssbbssc2

    Joined:
    Aug 20, 2015
    Messages:
    108
    Resources:
    0
    Resources:
    0
    meh
    Might Crash when used with warcraft 3 V1.26 or below.
     
  7. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,186
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    Updated to 1.24a:
    fixed a serious bug:
    After picking a talent the hero was marked as channeling for the whole time, preventing new orders during an order in group selection mode.​
     
  8. BloodForBlood

    BloodForBlood

    Joined:
    Mar 15, 2017
    Messages:
    95
    Resources:
    0
    Resources:
    0
    Why you didn't use Table instead of Hashtable?
     
  9. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,186
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    This is a jass resouce not a vjass resouce.
     
  10. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,258
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    Edited the tags to include GUI/Triggers as it fits the niche.
     
  11. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,360
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Comments and Suggestions:
    Potentially useful system for people who like this style of hero progression. Easy to use and flexible.

    Although the demo map does work correctly, it is very easy to think that the system is bugging out due to the demonstration choices made. For example it looks like it repeats the Blood Mage level 1 talent selection at level 5, however that is intended despite it saying "level 1". Like wise at level 10 it suddenly learns the Paladin level 1 talent despite not being a Paladin. This is potentially quite confusing to users since only by reading the triggers will they realize that this is the intended behaviour demonstrating how flexible the system is. A solution might be to give each talent tier a unique name which does not mention hero names or level numbers.​
     
  12. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,186
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    Kinda don't want to do any big changes to Talent 1.24. Because I changed Talent to beeing based on dynamic channel abilities (using the natives brought in Warcraft 3 1.29) by switching text & icon. In which choices and tiers are all defined in jass. But somehow I never uploaded the code driven Talent version into the spell section.

    But your feedback doesn't sound like big changes are needed, I'll do it.

    Edit: Uploaded Talent 1.24b.
     
    Last edited: May 14, 2019