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

[JASS] Talent

Talent is an Mui System giving units at wanted Levels the option to pick 1 option of a collection of choices (Tier). The intention was to mimic Hots Talents without custom UI nor a Dummy for the core.
I uploaded an earlier object Editor driven Version in the spell section some timer ago.

JASS:
//Talent 1.30.12
//by Tasyen

// Talent provides at wanted Levels a choice from a collection (Tier), from which the user picks one.
// Tiers are unitType specific (a paladin has different Choices then a demon hunter), This also include the Levels obtaining them.
// One can handle choices by Events or one can bind Code to choices.
// Regardless using Events or binded code, creating reset (revert picking a choice) is quite easy.
// By using dynamic abilities the amount of Object Editor data to manage Talent is quite low and almost fixed.
// Talent is mui.
// Choices have a fixed arrayIndex which one can use.

// Only Unit having the ability udg_TalentSpells[1] can use Talent also there needs to exist data for them.
//   In the demo map udg_TalentSpells are placed in a SpellBook. This makes them seperated and easy to add/remove.
//   udg_Talent_DefaultUI/CustomUI can also be placed on an item the units have or be a spellBook in a SpellBook, which is nice.

// It is also recommented using "function TalentHeroSetCopy", if multiple unitTypes share the same Talent Setup, morphing units for example.

// Before an TalentUser is removed from them game, one should use "FlushChildHashtable(udg_TalentHash, GetHandleId(unit))"
// Also it is recommented to do "call GroupRemoveUnit(udg_TalentUser, unit)"

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

//TalentAutoDetectNewUser (true) will create an "unit enters map" event for udg_TalentTrigger[TT_AutoDetectUnits()]
constant function TalentAutoDetectNewUser takes nothing returns boolean
   return true
endfunction

//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

//TalentIgnoreSilence (true) makes units able to pick talents while beeing silenced or doomed.
//Doom does still disable a TalentBook in an item.
constant function TalentIgnoreSilence takes nothing returns boolean
   return true
endfunction

//TalentRemoveWhenDone (true) makes units lose the TalentBook Abilitiy if they picked the last talent.
constant function TalentRemoveWhenDone takes nothing returns boolean
   return true
endfunction

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

//Increases the Level of abilities gained by choices, if the ability is already owned.
constant function TalentImproveAbilities takes nothing returns boolean
   return true
endfunction
//(true) only add the new ability if the unit has the to replaced Ability
constant function TalentReplacedAbilityRequiered takes nothing returns boolean
   return true
endfunction

//Throw an Event when an unit picks a choiceTalent
constant function TalentThrowEventPick takes nothing returns boolean
   return true
endfunction

//Throw an Event when an unit gains a choice to pick a talent
constant function TalentThrowEventAvailable takes nothing returns boolean
   return true
endfunction
//Throw an Event when an unit resets a choice
constant function TalentThrowEventReset takes nothing returns boolean
   return true
endfunction
//Throw an Event when an unit picked the last Talent of its unitType.
constant function TalentThrowEventFinish takes nothing returns boolean
   return true
endfunction

function TalentStringsInit takes nothing returns nothing
//Customiceable Strings of Talent

   set udg_TalentStrings[0] = "Not enough Skill Points"   //Error Message when using TalentSpentSkillPoints(true)
 
//Customiceable Strings of TalentPreMadeChoice
   set udg_TalentStrings[1] = "Learn:"           //TalentChoiceCreateAddSpells First Word.
   set udg_TalentStrings[2] = "\n"               //TalentChoiceCreateAddSpells First Seperator.
   set udg_TalentStrings[3] = ", "               //TalentChoiceCreateAddSpells Further Seperator.
   set udg_TalentStrings[9] = ""                           //TalentChoiceCreateImproveSpell   Prefix
   set udg_TalentStrings[10] = "\nManacost-Bonus"           //TalentChoiceCreateImproveSpell ManaCost-Bonus
   set udg_TalentStrings[11] = "\nCooldown-Bonus"           //TalentChoiceCreateImproveSpell Cooldown-Bonus
 
   set udg_TalentStrings[15] = "Weapon: "           //TalentChoiceCreateImproveWeapon PreFix
   set udg_TalentStrings[16] = "\nDamage-Bonus "           //TalentChoiceCreateImproveWeapon Damage-Bonus
   set udg_TalentStrings[17] = "\nAttackSpeedCooldown-Bonus "           //TalentChoiceCreateImproveWeapon AttackSpeedCooldown-Bonus
 

   set udg_TalentStrings[20] = ""                   //TalentChoiceCreateSustain Prefix
   set udg_TalentStrings[21] = "Life-Bonus "       //TalentChoiceCreateSustain Life-Bonus
   set udg_TalentStrings[22] = "\nMana-Bonus "       //TalentChoiceCreateSustain Mana-Bonus
   set udg_TalentStrings[23] = "\nArmor-Bonus "       //TalentChoiceCreateSustain Armor-Bonus
 
   set udg_TalentStrings[28] = ""       //TalentChoiceCreateStats Prefix
   set udg_TalentStrings[29] = "Str-Bonus"       //TalentChoiceCreateStats Str-Bonus
   set udg_TalentStrings[30] = "\nAgi-Bonus"       //TalentChoiceCreateStats Agi-Bonus
   set udg_TalentStrings[31] = "\nInt-Bonus"       //TalentChoiceCreateStats Agi-Bonus
 
//Customiceable Strings of TalentControl    
   set udg_TalentStrings[100] ="Level: "   //TalentControl Tier Prefix
   set udg_TalentStrings[101] =""   //TalentControl Tier SuFix
   set udg_TalentStrings[102] ="ReplaceableTextures\\CommandButtons\\BTNStatUp.blp"   //TalentControl Tier Icon
   set udg_TalentStrings[103] ="This Unit is no Talent User"   //Invalid Target
endfunction
//===========================================================================
//API:
//===========================================================================
//   function TalentAddSelection takes unit u returns nothing
   //Test if u gets a new Tier to pick from, done automatically in: udg_TalentTrigger[TT_LevelUp()] (LevelUp).

//   function TalentAdd2Hero takes unit u returns nothing
   // can be used to force talentDetetcion
   //do not use it more than once for one unit.

//   function TalentResetDo takes unit u, integer amountOfResets returns nothing
   //This will undo the last amountOfResets done choices of unit u. Each Time calling the needed "udg_TalentChoiceOnReset" and throwing an event.
   //An OnLearn Requiers an onReset doing the opposite, if one wants to use this feature.
   //call it with 1 to remove the last done choice.
   //To undo all done Choices of an unit, call it with an absurd high number.

//   function TalentPickDo takes unit u, integer buttonNr returns nothing
   //unit u learns choice buttonNr of currentSelection Tier.
   //will only work if the hasSelection flag is set.
   //buttonNr is expected to be 1 to udg_TalentSpellsLast including both
   //buttonNr also should not exceed TalentTierGetChoiceCount of the current Tier.

//   function TalentGetUnitTypeId takes unit u returns integer
   //returns the used heroTypeId for unit inside Talent

//   function TalentCopyFindRealOne takes integer heroTypeId returns integer
   //TalentGetUnitTypeId but using the unitTypeId

//===========================================================================
//TalentHero API
//===========================================================================
// TalentHero makes reading/writing HeroSheets(TalentTrees) more simple..

//   function TalentHeroSetCopy takes integer result, integer copyOrigin returns nothing
   //units from type result will use the setup from copyOrigin
   //also supports copy copy...
   //TalentHeroSetCopy is quite important, if an hero can morph
   //reading further data from result is disabled

//   function TalentHeroTierCreate takes integer heroTypeId, integer level returns integer
   //Create a new Tier for that hero at level.
   //returns udg_TalentTierLast

//   function TalentHeroGetTier takes integer heroTypeId, integer level returns integer
   //get the tier at that level for heroTypeId
   //0 = no tier

//   function TalentHeroSetTier takes integer heroTypeId, integer level, integer tier returns nothing
   //heroTypeId will use at level given tier.

//   function TalentHeroGetFinalTier takes integer heroTypeId returns integer
 
//   function TalentHeroSetFinalTier takes integer heroTypeId, integer level returns nothing
   //Units picking a choice of the tier added at level will be considered as Finished with their Talents.
   //this one has to be set, if you consider using TalentControl.
    
//   function TalentHeroGetCustomBook takes integer heroTypeId returns integer
   //abilityId of custom Book used.
//   function TalentHeroSetCustomBook takes integer heroTypeId, integer customUI returns nothing
//===========================================================================
//TalentUnit API
//===========================================================================
//Access Hashtable Data for ative units

//function TalentUnitGetCustomBook takes unit u returns integer
//function TalentUnitAddBook takes unit u returns nothing
//function TalentUnitRemoveBook takes unit u returns nothing
//function TalentUnitGetSelectionsDoneCount takes integer unitHandle returns integer
//   How many selections this unit has done?
//function TalentUnitGetSelectionButtonUsed takes integer unitHandle, integer selectionIndex returns integer
//   ButtonNr used, 1 to udg_TalentSpellsLast (included)
//function TalentUnitGetSelectionLevel takes integer unitHandle, integer selectionIndex returns integer
//   level of that selectionDone (1 to TalentUnitGetSelectionsDoneCount)
//function TalentUnitGetChoiceDone takes integer unitHandle, integer selectionIndex returns integer
//   arrayIndex of the choice of that selectionDone
//function TalentUnitGetCurrentTier takes integer unitHandle returns integer
//   the tier from which unit can pick from
//function TalentUnitGetCurrentTierLevel takes integer unitHandle returns integer
//   from which level the tier the unit picks currently is from?
//function TalentUnitGetSkillPontLevel takes integer unitHandle returns integer
//function TalentUnitGetSkillPonts takes integer unitHandle returns integer
//function TalentUnitGetTalentProgressLevel takes integer unitHandle returns integer
//function TalentUnitHasChoice takes integer unitHandle returns boolean

//function TalentUnitIsBookHidden takes integer unitHandle returns boolean
//function TalentUnitSetBookHidden takes unit u, boolean flag returns nothing
//function TalentUnitIsSpellHiden takes integer unitHandle, integer talentSpellNr returns boolean
//function TalentUnitSetSpellHiden takes unit u, integer talentSpellNr, boolean flag returns nothing
//===========================================================================
//TalentTier API
//===========================================================================
//   function TalentTierCreate takes nothing returns integer
   //creates a new Tier
   //a Tier is an collection of choices from which the user can pick one.
   //returns udg_TalentTierLast the ArrayIndex of the tier

//   function TalentTierAddChoice takes integer tier, integer choice returns nothing
   //Adds a Choice to the tier, tier is the ArrayIndex of the tier choice the ArrayIndex of Choice.

//   function TalentTierGetChoiceCount takes integer tier returns integer
   //returns the amount of choices added to this tier

//   function TalentTierGetChoice takes integer tier, integer index returns integer
   //returns the choice index (0 means no choice was added yet)
   //will return the to this tier last added choice if index is to high
   //expects index > 0

//===========================================================================
//TalentChoice API
//===========================================================================

//   function TalentChoiceCreate takes code onLearn, code onReset returns integer
   //if you do not need the function binding for this choice, you could use "set udg_TalentChoiceLast = udg_TalentChoiceLast + 1" instead.
   //Creates a choice and 1 Triggers for each OnLearn/OnReset if they are not null.
   //returns the ArrayIndex of the Choice
   //afterwards one should set udg_TalentChoiceText[returnedValue], udg_TalentChoiceHead[returnedValue], udg_TalentChoiceIcon[returnedValue]

//   function TalentChoiceCreateEx takes code onLearn, code onReset returns integer
   //Wrapper creating a choice and adding it to the last Created Tier
   //use this over TalentChoiceCreate and TalentTierAddChoice in most cases.
   //returns the choice ArrayIndex.

//   function TalentChoiceCreateTrigger takes trigger onLearn, trigger onReset returns integer

//   function TalentChoiceCreateTriggerEx takes trigger onLearn, trigger onReset returns integer
   //like TalentChoiceCreateEx
 
//   function TalentChoiceCreateAll takes string head, string text, string icon, code onLearn, code onReset returns integer
   //creates the Choice with the wanted data

//   function TalentChoiceCreateAllTrigger takes string head, string text, string icon, trigger onLearn, trigger onReset returns integer

//   function TalentChoiceCreateAllEx takes string head, string text, string icon, code onLearn, code onReset  returns integer
   //Create and Add

//   function TalentChoiceCreateAllTriggerEx takes string head, string text, string icon, trigger onLearn, trigger onReset  returns integer

//   function TalentChoiceAddAbility takes integer choice, integer abilityId returns nothing
   //Add abilityId to choiceIndex
   //one can attach multiple abilities to one choice.
   //one can attach the same ability multiple times to one choice to increase its level.
   //   ^^ needs function TalentImproveAbilities to return true

//   function TalentChoiceAddAbilityEx takes integer abilityId returns nothing
   //Add to last created Choice

//   function TalentChoiceReplaceAbility takes integer choice, integer oldAbility, integer newAbility returns nothing
   //TalentImproveAbilities(true)oldAbility - 1 Level and newAbility + 1 Level
   //TalentImproveAbilities(false) removed oldAbility, add newAbility set level of newAbility to level of oldAbility

//   function TalentChoiceGetAbilityCount takes integer choice returns integer
//===========================================================================
//Variables inside Events and Code Binding:
//===========================================================================
//   udg_Talent__Unit        = the unit doing the choice
//   udg_Talent__Choice        = the arrayIndex of the selected choice.
//    udg_Talent__Level        = the level from which this choice/Tier is.
//   udg_Talent__Tier       = the tierIndex from which the choice is.
//   udg_Talent__Button       = the Index of the Button used, 1 to udg_TalentSpellsLast.
//                           , this variable is needed for event based talentAction stuff.

//===========================================================================
//Event:
//===========================================================================
//   To identyfy a choice in an Event use HeroType, udg_Talent__Level and udg_Talent__Button.
//    main filter heroType, now all others are blocked.
//   then check for the level
//   now do according to button used the stuff

//   udg_Talent__Event
//           = 1 => on Choice.
//               after the Auotskills are added
//           = 2 => Tier 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

//   Events can be indivudal (de)aktivaded inside "Definitions"

//===========================================================================
//Code Binding
//===========================================================================
// One can directly bind functions/triggers to an choice, 1 for picking the choice, 1 for reseting the choice.
// Talent allways uses triggers, but one can let the triggers be generated by only giving the functions.
//   udg_TalentChoiceOnLearn       -   Executes when Picked
//   udg_TalentChoiceOnReset       -   Executes when Reset, should do the opposite of OnLearn, if one wants to use the reset feature.
//                               -   if there is no reset in your project, just skip reset.

//===========================================================================
//Tier and Choice variables
//===========================================================================
// TalentChoice is a simple rising Array, each index represents a new choice.
//   udg_TalentChoiceLast       - last Index used from TalentChoice
//   udg_TalentChoiceHead       - the headLine shown
//   udg_TalentChoiceText       - the mainTooltip shown
//   udg_TalentChoiceIcon       - the image shown
//   udg_TalentChoiceOnLearn       - trigger
//   udg_TalentChoiceOnReset       - trigger

//   TalentChoice Abilities are Saved in the hash.
//   With the used ArrayIndex as main Key.
//   rising Positive sec Keys are the abilities gained
//    falling negative sec Keys are the abilities replaced.
//=====
// Tier is managed inside the hash.
// used tiers are from 1 to udg_TalentTierLast.
// Tiers use negative main Keys, (Background Info).

//===========================================================================
//TalentSpells
//===========================================================================
//   udg_Talent_DefaultUI       - A SpellBook which is seen as the default Book everyBody uses if an Talent user has no custom One.
//                               -> The SpellBook needs to contain all udg_TalentSpells
//   udg_Talent_EmptyHeroSkill   - TalentControlSkillPoints requier Heroes to have Learnable Skills, this skill is used if your heroes have non. It is disabled but should be inside the heroes Learn Skills if one wants to use that feature and your Hero wouldn't have a learnable Skill otherwise.
//                               - its a bit hacky but the best solution i came up with.
//                               - unneeded if you do not use skillPoints with Talents.
//   udg_TalentSpells           - ability Array, the dynamic Buttons. starting with 1. I suggest 8 Channel Based abilities with different unique OrderIds.

//   udg_TalentSpellsLast       - last index of udg_TalentSpells, actually it does not makes much sense to change it from default 8.
//   udg_TalentSpellsPrefix       - text displayed before the choicesHead, if a choice uses this Button.
//   udg_TalentSpellsSufix       - text displayed after choicesHead

//   The displayed HeadLine is ButtonPrefix + choiceHead + ButtonSufix

//===========================================================================
//udg_TalentTrigger is an array of Triggers controlling this system.
//       udg_TalentTrigger[TT_PickChoice()] = Enables Choices| player unit starts channel, choices won't pass events behind it
//       udg_TalentTrigger[TT_LevelUp()] = On Levelup| It checks for new Talent Tiers.
//       udg_TalentTrigger[TT_AutoDetectUnits()] = EnterPlayable Map Event
//           , if you alreay have a EnterPlayable Map trigger you might remove the event inside the init and let yours call this one.
//           , the EnterPlayable Map Event can be quite costly and break your project if there are to many and the map is big.
//       udg_TalentTrigger[TT_SelectUnit()] = Make Talent UI (In)Visbile; Event On Unit Selection.
//       udg_TalentTrigger[TT_SpentSkillPoints()] = Hides the UI when spending Skill-Points for something else.

// you could disable all TalentTriggers[0 to 4], if you do not use reset and all Choices are done.

//       udg_TalentReset = when called resets udg_Talent__Unit and calls for each choice undone the reset event(-1).
//       a successful reset will enable udg_TalentTrigger[TT_PickChoice()]
//           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__Unit = the hero losing talents.

//===========================================================================
//udg_TalentStrings contain all builtIn Strings which can/should be localiced used by This System.

//===========================================================================
//TT = TalentTrigger, ArrayIndexes
constant function TT_PickChoice takes nothing returns integer
   return 0
endfunction
constant function TT_LevelUp takes nothing returns integer
   return 1
endfunction
constant function TT_AutoDetectUnits takes nothing returns integer
   return 2
endfunction
constant function TT_SelectUnit takes nothing returns integer
   return 3
endfunction
constant function TT_SpentSkillPoints takes nothing returns integer
   return 4
endfunction

//Hashtable
//unit 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_IsBookHidden takes nothing returns integer
   return -6
endfunction
constant function TalentHashIndex_IsUsingBook takes nothing returns integer
   return -7
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
constant function TalentHashIndex_FinalTierLevel takes nothing returns integer
   return -3
endfunction

//TalentSpells
// at 0 they save its array index.
//===========================================================================
function TalentCopyFindRealOne takes integer heroTypeId returns integer
   local integer copyId = LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCopyData())
   if copyId != 0 then
       return TalentCopyFindRealOne(copyId)
   else
       return heroTypeId
   endif
endfunction
function TalentGetUnitTypeId takes unit u returns integer
   return TalentCopyFindRealOne(GetUnitTypeId(u))
endfunction


//TalentJ
//Handleing Choice / Tier Creations
function TalentChoiceCreateTrigger takes trigger onLearn, trigger onReset returns integer
   set udg_TalentChoiceLast = udg_TalentChoiceLast + 1
   set udg_TalentChoiceOnLearn[udg_TalentChoiceLast] = onLearn
   set udg_TalentChoiceOnReset[udg_TalentChoiceLast] = onReset
   return udg_TalentChoiceLast
endfunction
function TalentChoiceCreate takes code onLearn, code onReset returns integer
   set udg_TalentChoiceLast = udg_TalentChoiceLast + 1
   if onLearn != null then
       set udg_TalentChoiceOnLearn[udg_TalentChoiceLast] = CreateTrigger()
       call TriggerAddAction(udg_TalentChoiceOnLearn[udg_TalentChoiceLast], onLearn)
   endif
   if onReset != null then
       set udg_TalentChoiceOnReset[udg_TalentChoiceLast] = CreateTrigger()
       call TriggerAddAction(udg_TalentChoiceOnReset[udg_TalentChoiceLast], onReset)
   endif
   return udg_TalentChoiceLast
endfunction

function TalentChoiceCreateAll takes string head, string text, string icon, code onLearn, code onReset returns integer
   call TalentChoiceCreate(onLearn, onReset)
   set udg_TalentChoiceHead[udg_TalentChoiceLast] = head
   set udg_TalentChoiceText[udg_TalentChoiceLast] = text
   set udg_TalentChoiceIcon[udg_TalentChoiceLast] = icon
   return udg_TalentChoiceLast
endfunction
function TalentChoiceCreateAllTrigger takes string head, string text, string icon, trigger onLearn, trigger onReset returns integer
   call TalentChoiceCreateTrigger(onLearn, onReset)
   set udg_TalentChoiceHead[udg_TalentChoiceLast] = head
   set udg_TalentChoiceText[udg_TalentChoiceLast] = text
   set udg_TalentChoiceIcon[udg_TalentChoiceLast] = icon
   return udg_TalentChoiceLast
endfunction

function TalentTierCreate takes nothing returns integer
   set udg_TalentTierLast = udg_TalentTierLast + 1
   return udg_TalentTierLast
endfunction

function TalentTierAddChoice takes integer tier, integer choice returns nothing
   local integer count = LoadInteger(udg_TalentHash, -tier, 0) + 1
   call SaveInteger(udg_TalentHash, -tier, count, choice)
   call SaveInteger(udg_TalentHash, -tier, 0, count)
endfunction
function TalentTierGetChoiceCount takes integer tier returns integer
   if tier > 0 then //tiers are saved in the negative side, convert positive calls in negative ones
       return LoadInteger(udg_TalentHash, -tier, 0)
   else
       return LoadInteger(udg_TalentHash, tier, 0)
   endif
endfunction
function TalentTierGetChoice takes integer tier, integer index returns integer
   if tier > 0 then //tiers are saved in the negative side, convert positive calls in negative ones
       return LoadInteger(udg_TalentHash, -tier, index)
   else
       return LoadInteger(udg_TalentHash, tier, index)
   endif
endfunction

function TalentChoiceCreateEx takes code onLearn, code onReset returns integer
   local integer choice = TalentChoiceCreate(onLearn, onReset)
   call TalentTierAddChoice(udg_TalentTierLast, choice)
   return choice
endfunction
function TalentChoiceCreateTriggerEx takes trigger onLearn, trigger onReset returns integer
   local integer choice = TalentChoiceCreateTrigger(onLearn, onReset)
   call TalentTierAddChoice(udg_TalentTierLast, choice)
   return choice
endfunction
function TalentChoiceCreateAllEx takes string head, string text, string icon, code onLearn, code onReset  returns integer
   local integer choice = TalentChoiceCreateAll(head, text, icon, onLearn, onReset)
   call TalentTierAddChoice(udg_TalentTierLast, choice)
   return choice
endfunction
function TalentChoiceCreateAllTriggerEx takes string head, string text, string icon, trigger onLearn, trigger onReset  returns integer
   local integer choice = TalentChoiceCreateAllTrigger(head, text, icon, onLearn, onReset)
   call TalentTierAddChoice(udg_TalentTierLast, choice)
   return choice
endfunction
function TalentChoiceGetAbilityCount takes integer choice returns integer
   return LoadInteger(udg_TalentHash, choice, 0)
endfunction
function TalentChoiceAddAbility takes integer choice, integer abilityId returns nothing
   local integer count = LoadInteger(udg_TalentHash, choice, 0) + 1
   call SaveInteger(udg_TalentHash, choice, count, abilityId)
   call SaveInteger(udg_TalentHash, choice, 0, count)
endfunction
function TalentChoiceAddAbilityEx takes integer abilityId returns nothing
   call TalentChoiceAddAbility(udg_TalentChoiceLast, abilityId)
endfunction

function TalentChoiceReplaceAbility takes integer choice, integer oldAbility, integer newAbility returns nothing
   local integer count = LoadInteger(udg_TalentHash, choice, 0) + 1
   call SaveInteger(udg_TalentHash, choice, count, newAbility)
   call SaveInteger(udg_TalentHash, choice, -count, oldAbility)
   call SaveInteger(udg_TalentHash, choice, 0, count)
endfunction
function TalentChoiceReplaceAbilityEx takes integer oldAbility, integer newAbility returns nothing
   call TalentChoiceReplaceAbility(udg_TalentChoiceLast, oldAbility, newAbility)
endfunction

//TalentHero
//Access data by UnitTypeId
function TalentHeroTierCreate takes integer heroTypeId, integer level returns integer
   call SaveInteger(udg_TalentHash, heroTypeId, level, TalentTierCreate())
   return udg_TalentTierLast
endfunction
function TalentHeroGetTier takes integer heroTypeId, integer level returns integer
   return LoadInteger(udg_TalentHash, TalentCopyFindRealOne(heroTypeId), level)
endfunction
function TalentHeroSetTier takes integer heroTypeId, integer level, integer tier returns nothing
   call SaveInteger(udg_TalentHash, heroTypeId, level, tier)
endfunction
function TalentHeroGetFinalTier takes integer heroTypeId returns integer
   return LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_FinalTierLevel())
endfunction
function TalentHeroSetFinalTier takes integer heroTypeId, integer level returns nothing
   call SaveInteger(udg_TalentHash, heroTypeId, TalentHashIndex_FinalTierLevel(), level)
endfunction
function TalentHeroGetCustomBook takes integer heroTypeId returns integer
   return LoadInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI())
endfunction
function TalentHeroSetCustomBook takes integer heroTypeId, integer customUI returns nothing
   call SaveInteger(udg_TalentHash, heroTypeId, TalentHashIndex_DataCustomUI(), customUI)
endfunction

function TalentHeroSetCopy takes integer result, integer copyOrigin returns nothing
   call SaveInteger(udg_TalentHash, result, TalentHashIndex_DataCopyData(), copyOrigin)
endfunction
//TalentUnit
//Using some TalentHero with an unit
function TalentUnitGetCustomBook takes unit u returns integer
   return TalentHeroGetCustomBook(TalentGetUnitTypeId(u))
endfunction

function TalentUnitAddBook takes unit u returns nothing
   local integer customUI = TalentUnitGetCustomBook(u)
   if customUI != 0 then
       call UnitAddAbility(u, customUI)
   else
       call UnitAddAbility(u, udg_Talent_DefaultUI)
   endif
endfunction
function TalentUnitRemoveBook takes unit u returns nothing
   local integer customUI = TalentUnitGetCustomBook(u)
   if customUI != 0 then
       call UnitRemoveAbility(u, customUI)
   else
       call UnitRemoveAbility(u, udg_Talent_DefaultUI)
   endif
endfunction
function TalentUnitGetSelectionsDoneCount takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_SelectionsDone())
endfunction

function TalentUnitGetSelectionButtonUsed takes integer unitHandle, integer selectionIndex returns integer
   return LoadInteger(udg_TalentHash, unitHandle, selectionIndex)
endfunction
function TalentUnitGetSelectionLevel takes integer unitHandle, integer selectionIndex returns integer
   return R2I(LoadReal(udg_TalentHash, unitHandle, selectionIndex))
endfunction
function TalentUnitGetChoiceDone takes unit u, integer selectionIndex returns integer
   local integer uId = GetHandleId(u)
   return TalentTierGetChoice(TalentHeroGetTier(TalentGetUnitTypeId(u), TalentUnitGetSelectionLevel(uId, selectionIndex)), TalentUnitGetSelectionButtonUsed(uId, selectionIndex))
endfunction
function TalentUnitGetCurrentTier takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_CurrentChoice())
endfunction
function TalentUnitGetCurrentTierLevel takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_CurrentChoiceLevel())
endfunction
function TalentUnitGetSkillPontLevel takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_LastLevel())
endfunction
function TalentUnitGetSkillPonts takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_SkillPoints())
endfunction
function TalentUnitGetTalentProgressLevel takes integer unitHandle returns integer
   return LoadInteger(udg_TalentHash, unitHandle, TalentHashIndex_LevelOfLastChoice())
endfunction
function TalentUnitHasChoice takes integer unitHandle returns boolean
   return LoadBoolean(udg_TalentHash, unitHandle, TalentHashIndex_HasChoice())
endfunction
function TalentUnitIsBookHidden takes integer unitHandle returns boolean
   return LoadBoolean(udg_TalentHash, unitHandle, TalentHashIndex_IsBookHidden())
endfunction
function TalentUnitSetBookHidden takes unit u, boolean flag returns nothing
   local integer uId = GetHandleId(u)
   if TalentUnitIsBookHidden(uId) != flag then
       call BlzUnitHideAbility(u, udg_Talent_DefaultUI, flag)
       call BlzUnitHideAbility(u, TalentUnitGetCustomBook(u), flag)
       call SaveBoolean(udg_TalentHash, uId, TalentHashIndex_IsBookHidden(), flag)
   endif
endfunction
function TalentUnitIsSpellHiden takes integer unitHandle, integer talentSpellNr returns boolean
   return LoadBoolean(udg_TalentHash, unitHandle, udg_TalentSpells[talentSpellNr])
endfunction
function TalentUnitSetSpellHiden takes unit u, integer talentSpellNr, boolean flag returns nothing
   local integer uId = GetHandleId(u)
   if TalentUnitIsSpellHiden(uId, talentSpellNr) != flag then
       //if flag then
       //   call Debug(GetUnitName(u) + " "+GetObjectName(udg_TalentSpells[talentSpellNr])+" -> disabled")
       //else
       //   call Debug(GetUnitName(u) + " "+GetObjectName(udg_TalentSpells[talentSpellNr])+" -> enabled")
       //endif
       call BlzUnitHideAbility(u, udg_TalentSpells[talentSpellNr], flag)
       call SaveBoolean(udg_TalentHash, uId, udg_TalentSpells[talentSpellNr], flag)
   endif
endfunction
function TalentUnitIsUsingBook takes integer unitHandle returns boolean
   return LoadBoolean(udg_TalentHash, unitHandle, TalentHashIndex_IsUsingBook())
endfunction
function TalentUnitSetUsingBook takes integer unitHandle, boolean flag returns nothing
   call SaveBoolean(udg_TalentHash, unitHandle, TalentHashIndex_IsUsingBook(), flag)
endfunction
//Talent
//=========


function TalentHas takes unit u returns boolean
   return GetUnitAbilityLevel(u, udg_TalentSpells[1]) != 0
endfunction

function TalentHideButtons takes unit u returns nothing
   local integer LoopA = 1
   loop //Hide all choice Spells
       exitwhen LoopA > udg_TalentSpellsLast
       call TalentUnitSetSpellHiden(u, LoopA, true)
       set LoopA = LoopA + 1
   endloop
endfunction

function TalentShowTier takes unit u, integer tier returns nothing
   local integer LoopA = 1
   local integer spell
   local integer choiceIndex
   local integer tierChoiceCount = TalentTierGetChoiceCount(tier)
   local player p = GetOwningPlayer(u)
   loop //Take over Data to choice Spells
       exitwhen LoopA > tierChoiceCount
       set choiceIndex = TalentTierGetChoice(tier,LoopA)
       set spell = udg_TalentSpells[LoopA]

       if p == GetLocalPlayer() then
           call BlzSetAbilityExtendedTooltip(spell, udg_TalentChoiceText[choiceIndex], 1)
           call BlzSetAbilityTooltip(spell, udg_TalentSpellsPrefix[LoopA] + udg_TalentChoiceHead[choiceIndex] + udg_TalentSpellsSufix[LoopA], 1)
           call BlzSetAbilityIcon(spell, udg_TalentChoiceIcon[choiceIndex])
       endif
    
       call TalentUnitSetSpellHiden(u, LoopA, false)
       set LoopA = LoopA + 1
   endloop
 
   loop //Hide all not used choice Spells
       exitwhen LoopA > udg_TalentSpellsLast
       call TalentUnitSetSpellHiden(u, LoopA, true)
       set LoopA = LoopA + 1
   endloop
   set p = null
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 returns nothing
   local integer tierGained
   local integer heroTypeId = TalentGetUnitTypeId(u)
   local integer currentLevel = IMaxBJ(GetHeroLevel(u), GetUnitLevel(u))
   local integer uId = GetHandleId(u)
   local player owner
   //Start from the last skill selection added.
   local integer loopA = TalentUnitGetTalentProgressLevel(uId)
   // Only show 1 SelectionContainer at the same time.
   if TalentUnitHasChoice(uId) then
       return
   endif
   set owner = GetOwningPlayer(u)
   loop
       exitwhen loopA > currentLevel
       set tierGained = TalentHeroGetTier(heroTypeId, loopA)        
       if tierGained != 0 then
           call TalentShowTier(u, tierGained)
        
           //Remember the container gained
           call SaveInteger(udg_TalentHash, uId, TalentHashIndex_CurrentChoice(), tierGained)
           //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)
        
           if TalentHideUIWhenUnneeded() then   // show UI
               call TalentUnitSetBookHidden(u,false)
           endif
        
           if TalentThrowEventAvailable() then //Throw Selection Event
               set udg_Talent__Choice = 0
               set udg_Talent__Unit = u
               set udg_Talent__Level = loopA
               set udg_Talent__Tier = tierGained
               set udg_Talent__Event = 2
               set udg_Talent__Event = 0
           endif
           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 TalentUnitSetBookHidden(u,true)
   endif
   call ForceUICancelBJ(owner)   //Close Book!
   call TalentHideButtons(u)
   set owner = null
endfunction
function TalentLevelUpA takes unit u, integer uId returns nothing
   local integer lastLevel = TalentUnitGetSkillPontLevel(uId)
   local integer currentLevel = IMaxBJ(GetHeroLevel(u), GetUnitLevel(u))
   local integer heroTypeId = TalentGetUnitTypeId(u)
   local integer tierGained
   loop
       set tierGained = TalentHeroGetTier(heroTypeId, lastLevel)        
       if tierGained != 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 TalentUnitGetSkillPonts(uId) < GetHeroSkillPoints(u) then
       call UnitModifySkillPoints(u, -1)
   endif
   call TalentLevelUpA(u,uId)
   call TalentAddSelection(u)
   set u = null
endfunction
function TalentAddSkill takes unit u, integer skillGained, integer newLevel returns nothing
   local integer skillGainedLevel = GetUnitAbilityLevel(u, skillGained)
   if skillGainedLevel == 0 then //Already got skillGained?
       call UnitAddAbility(u, skillGained)
       call UnitMakeAbilityPermanent(u, true, skillGained)
       call SetUnitAbilityLevel(u, skillGained, newLevel)
   elseif TalentImproveAbilities() then//Can upgrade Levels?
       call SetUnitAbilityLevel(u, skillGained, skillGainedLevel + 1)
   endif
endfunction
function TalentRemoveSkill takes unit u, integer skillLost returns nothing
   local integer skillLostLevel = GetUnitAbilityLevel(u, skillLost)
   if TalentImproveAbilities() and skillLostLevel > 1 then //Can Decrease Level?
       set skillLostLevel = skillLostLevel - 1
       call SetUnitAbilityLevel(u, skillLost, skillLostLevel)
   else
       call UnitRemoveAbility(u, skillLost)
   endif
endfunction
function TalentReplaceSkill takes unit u, integer skillReplaced, integer skillGained returns nothing
   local integer skillReplacedLevel = GetUnitAbilityLevel(u, skillReplaced)
   if not TalentReplacedAbilityRequiered() or skillReplacedLevel != 0 then
       call TalentRemoveSkill(u, skillReplaced)
       if skillGained != 0 then
           call TalentAddSkill(u, skillGained, skillReplacedLevel)
       endif
   endif
endfunction

function TalentPickDo takes unit u, integer buttonNr returns nothing
   local integer uId                = GetHandleId(u)
   local integer heroTypeId        = TalentGetUnitTypeId(u)
   local integer tier                = TalentUnitGetCurrentTier(uId)
   local integer tierLevel        = TalentUnitGetCurrentTierLevel(uId)
   local integer selectionsDone    = TalentUnitGetSelectionsDoneCount(uId)   + 1
   local integer choiceIndex        = TalentTierGetChoice(tier, buttonNr)
   local integer skillGained
   local integer skillReplaced
   local integer loopB            = TalentChoiceGetAbilityCount(choiceIndex)
   if not TalentUnitHasChoice(uId) then //Requiers to have a Choice
       return
   endif
 
   loop   //Load all saved Abilities and add/improve them to the unit
       exitwhen loopB == 0
       set skillGained = LoadInteger(udg_TalentHash, choiceIndex, loopB)
       set skillReplaced = LoadInteger(udg_TalentHash, choiceIndex, -loopB)
    
       if skillReplaced != 0 then //Replaces?
           call TalentReplaceSkill(u, skillReplaced, skillGained)
       else
           call TalentAddSkill(u, skillGained,1)
       endif
       set loopB = loopB - 1
   endloop

   //Execute OnLearn
   set udg_Talent__Unit = u
   set udg_Talent__Button = buttonNr
   set udg_Talent__Choice = choiceIndex
   set udg_Talent__Tier = tier
   set udg_Talent__Level = tierLevel
   call TriggerExecute(udg_TalentChoiceOnLearn[choiceIndex])
 
   if TalentThrowEventPick() then
       //Throw Selection Event
       set udg_Talent__Event = 1
       set udg_Talent__Event = 0
   endif
   //Save Choices
   //call SaveInteger(udg_TalentHash, uId, selectionsDone, choiceIndex) //Save the picked ChoiceIndex
   call SaveInteger(udg_TalentHash, uId, selectionsDone, buttonNr) //Save the picked ButtonIndex
   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_SelectionsDone(), selectionsDone)
   call SaveReal(udg_TalentHash, uId, selectionsDone, I2R(tierLevel))

   //Unmark having a selection.
   call SaveBoolean(udg_TalentHash, uId, TalentHashIndex_HasChoice(), false)
   //Last choice for this heroType?
   if TalentHeroGetFinalTier(heroTypeId) == tierLevel then
       if TalentRemoveWhenDone() then
           //has herospeciifc learnbook?
           if TalentUnitIsUsingBook(uId) then
               call TalentUnitRemoveBook(u)
           else
               call TalentHideButtons(u)
           endif
       else
           call TalentHideButtons(u)
           call ForceUICancelBJ(GetOwningPlayer(u))   //Close Book!
       endif
    
       if IsUnitType(u, UNIT_TYPE_HERO) and TalentControlSkillPoints() then
           call UnitAddAbility(u, udg_Talent_EmptyHeroSkill)
           call SetUnitAbilityLevel (u, udg_Talent_EmptyHeroSkill, 4)
       endif
       //Throw Finish Choices Event.
       if TalentThrowEventFinish() then
           set udg_Talent__Event = 3
           set udg_Talent__Event = 0
       endif
   else
       //Check for further choices.
       call TalentAddSelection(u)
   endif
   set u = null
endfunction

function TalentPickCondition takes nothing returns boolean
   return LoadInteger(udg_TalentHash, GetSpellAbilityId(),0 ) != 0
endfunction
function TalentPick takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local integer uId = GetHandleId(u)
   local sound s
   //Is allowed to make a choice?
   if TalentUnitHasChoice(uId) then
       if TalentUseSkillPoints() and IsUnitType(u, UNIT_TYPE_HERO) then
           if GetHeroSkillPoints(u) > 0 then
               call UnitModifySkillPoints(u, -1)
               call TalentPickDo(u, LoadInteger(udg_TalentHash, GetSpellAbilityId(),0))
           else
               call DisplayTextToPlayer(GetOwningPlayer(u),0,0, udg_TalentStrings[0])
               if GetLocalPlayer() == GetTriggerPlayer() then
                   set s = CreateSoundFromLabel("Error", false, false, false, 10000, 10000)
                   call StartSound(s)
                   call KillSoundWhenDone(s)
                   set s = null
               endif
           endif
       else
           call TalentPickDo(u, LoadInteger(udg_TalentHash, GetSpellAbilityId(),0))
       endif
   endif
   call IssueImmediateOrder(u, "stop")
   set u = null
endfunction

function TalentLevelUpSimple takes nothing returns nothing
   call TalentAddSelection(GetTriggerUnit())
endfunction
function TalentMakeSilenceImmune takes unit u returns nothing
   local integer loopA = udg_TalentSpellsLast
   local integer customUI = TalentUnitGetCustomBook(u)
   if TalentIgnoreSilence() then   //Talent Immune to Silence/Doom?
       loop   // Make Talent Spells Immune to Disables
           exitwhen loopA == 0
           call BlzUnitDisableAbility(u, udg_TalentSpells[loopA], false, false)
           call BlzUnitDisableAbility(u, udg_TalentSpells[loopA], false, true)
           call BlzUnitDisableAbility(u, udg_TalentSpells[loopA], false, false)
           call BlzUnitDisableAbility(u, udg_TalentSpells[loopA], false, true)   //Make sure the second boolean has the same amount of true and falses to untouch the counter
           set loopA = loopA - 1
       endloop
       if TalentUnitIsUsingBook(GetHandleId(u)) then
           if customUI == 0 then   //Make Default UI Immune to silence
               call BlzUnitDisableAbility(u, udg_Talent_DefaultUI, false, false)
               call BlzUnitDisableAbility(u, udg_Talent_DefaultUI, false, true)
               call BlzUnitDisableAbility(u, udg_Talent_DefaultUI, false, false)
               call BlzUnitDisableAbility(u, udg_Talent_DefaultUI, false, true)
           else   //Make CustomUi Immune to silence
               call BlzUnitDisableAbility(u, customUI, false, false)
               call BlzUnitDisableAbility(u, customUI, false, true)
               call BlzUnitDisableAbility(u, customUI, false, false)
               call BlzUnitDisableAbility(u, customUI, false, true)
           endif
       endif
   endif
endfunction
function TalentAdd2Hero takes unit u returns nothing
   local integer uId = GetHandleId(u)
   if not IsUnitInGroup(u, udg_TalentUser) then
       call GroupAddUnit(udg_TalentUser, u)
       call TalentUnitSetUsingBook(uId, GetUnitAbilityLevel(u, udg_Talent_DefaultUI) != 0 or GetUnitAbilityLevel(u, TalentHeroGetCustomBook(TalentGetUnitTypeId(u))) != 0)
       call TalentMakeSilenceImmune(u)
       if TalentControlSkillPoints() then
           call UnitModifySkillPoints(u, -1)
           call TalentLevelUpA(u,uId)
       endif
   endif
   call TalentAddSelection(u)
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 skillReplaced
   local integer choice
   local integer level
   local integer loopB = 0
   local integer customUI
   local integer tier
   local integer spellNr
   local boolean isUsingBook
   //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 = TalentUnitGetSelectionsDoneCount(uId)
   //No selections done -> skip the rest.
   if selectionsDone == 0 then
       return
   endif
 
   set udg_Talent__Unit = u
   //Remove Autoadded Skills
   loop
       set level = TalentUnitGetSelectionLevel(uId, selectionsDone)
       set tier = TalentHeroGetTier(heroTypeId, level)
       set spellNr = TalentUnitGetSelectionButtonUsed(uId, selectionsDone)
       set choice = TalentTierGetChoice(tier, spellNr)
    
       set udg_Talent__Choice = choice
       set udg_Talent__Tier = tier
       set udg_Talent__Level = level
       set udg_Talent__Button = spellNr
    
    
       if TalentThrowEventReset() then   //Throw a event that this choice is going to be lost.
           set udg_Talent__Event = -1
           set udg_Talent__Event = 0
       endif
    
       set loopB = TalentChoiceGetAbilityCount(choice)
       loop   //Load all saved Abilities and add/improve them to the unit
           exitwhen loopB == 0
           set skillGained = LoadInteger(udg_TalentHash, choice, loopB)
           set skillReplaced = LoadInteger(udg_TalentHash, choice, -loopB)
        
           if skillReplaced != 0 then //Replaces?
               call TalentReplaceSkill(u, skillGained, skillReplaced)
           else
               call TalentRemoveSkill(u, skillGained)
           endif
           set loopB = loopB - 1
       endloop
    
       call TriggerExecute(udg_TalentChoiceOnReset[choice])
    
       set selectionsDone = selectionsDone - 1
       set amountOfResets = amountOfResets - 1
       exitwhen selectionsDone <= 0 or amountOfResets <= 0
   endloop
 
   call EnableTrigger(udg_TalentTrigger[TT_PickChoice()]) //allow choices again

   set isUsingBook = TalentUnitIsUsingBook(uId)
   //Forget this unit?
   if selectionsDone <= 0 then
       set loopB = udg_TalentSpellsLast
       loop
           exitwhen loopB == 0
           call TalentUnitSetSpellHiden(u,loopB,false)
           set loopB = loopB - 1
       endloop
       call TalentUnitSetBookHidden(u,false)
    
       //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
   if TalentRemoveWhenDone() then
       if isUsingBook then
           call TalentUnitAddBook(u)
           call TalentUnitSetUsingBook(uId, true)
       endif
       call TalentMakeSilenceImmune(u)
   endif
   if TalentControlSkillPoints() then
       call UnitRemoveAbility(u, udg_Talent_EmptyHeroSkill)
   endif
 
   //Recalc skillpoints if wanted.
   if TalentUseSkillPoints() and IsUnitType(u, UNIT_TYPE_HERO) then
       call UnitModifySkillPoints(u, -9999)
       call TalentLevelUpA(u,uId)
   endif
   call TalentAddSelection(u)
endfunction

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

function TalentShowUI takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local integer uId = GetHandleId(u)
   local player owner = GetOwningPlayer(u)
   local integer customUI = TalentUnitGetCustomBook(u)
   local boolean show = TalentUnitHasChoice(uId)
   local integer tier = TalentUnitGetCurrentTier(uId)
   if show then
       call TalentShowTier(u, tier)
   else
       call TalentHideButtons(u)
   endif
   if TalentHideUIWhenUnneeded() then

       call TalentUnitSetBookHidden(u,show)
   endif
        
   set u = null
   set owner = null
endfunction

function TalentSpentSkillPoints takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local integer uId = GetHandleId(u)
   local player owner = GetOwningPlayer(u)
   local integer skillPoints = GetHeroSkillPoints(u)
 
   call SaveInteger(udg_TalentHash, uId, TalentHashIndex_SkillPoints(), skillPoints - 1)
   //Spent the last Point?
   if skillPoints == 1 then
       call TalentUnitSetBookHidden(u,true)
   endif
   set u = null
   set owner = null
endfunction

function TalentShowUICon takes nothing returns boolean
   return TalentHas(GetTriggerUnit()) and GetPlayerAlliance(GetOwningPlayer(GetTriggerUnit()), GetTriggerPlayer(), ALLIANCE_SHARED_CONTROL)
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
   local player p
   loop   //Save ArrayIndex onto the choiceSpells
       set loopA = loopA + 1
       exitwhen loopA > udg_TalentSpellsLast
       call SaveInteger(udg_TalentHash, udg_TalentSpells[loopA], 0, loopA)
   endloop
 
 
   set udg_TalentTrigger[TT_PickChoice()] = CreateTrigger()
   set udg_TalentTrigger[TT_LevelUp()] = CreateTrigger()
   set udg_TalentTrigger[TT_AutoDetectUnits()] = CreateTrigger()
   set udg_TalentTrigger[TT_SelectUnit()] = CreateTrigger()
   set udg_TalentTrigger[TT_SpentSkillPoints()] = CreateTrigger()

   set udg_TalentReset = CreateTrigger()
        
   call TriggerAddAction( udg_TalentReset, function TalentReset)
 
   //Do a choice.
   call TriggerAddAction( udg_TalentTrigger[TT_PickChoice()],  function TalentPick )
   call TriggerAddCondition( udg_TalentTrigger[TT_PickChoice()],  Condition(function TalentPickCondition) )
 
   call TriggerAddAction( udg_TalentTrigger[TT_SpentSkillPoints()],  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[TT_LevelUp()], function TalentLevelUp)
   else
       call TriggerAddAction( udg_TalentTrigger[TT_LevelUp()], function TalentLevelUpSimple)
   endif
 
   call TriggerAddAction( udg_TalentTrigger[TT_SelectUnit()], function TalentShowUI)
   call TriggerAddCondition( udg_TalentTrigger[TT_SelectUnit()], Condition( function TalentShowUICon ))
 
 
   //Get Choices on Entering Map for lvl 0/1.
   if TalentAutoDetectNewUser() then
       call TriggerRegisterEnterRectSimple( udg_TalentTrigger[TT_AutoDetectUnits()], GetPlayableMapRect() )
   endif
   call TriggerAddAction( udg_TalentTrigger[TT_AutoDetectUnits()], function TalentAutoOnEnterMap)
   call TriggerAddCondition( udg_TalentTrigger[TT_AutoDetectUnits()], Condition( function TalentHasCondition ))
   set loopA = 0
   loop
       set p = Player(loopA)
       if udg_Talent_EmptyHeroSkill != 0 then
           call SetPlayerAbilityAvailable(p,  udg_Talent_EmptyHeroSkill, false)
       endif
       call TriggerRegisterPlayerUnitEvent(udg_TalentTrigger[TT_PickChoice()], p, EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
       call TriggerRegisterPlayerUnitEvent(udg_TalentTrigger[TT_LevelUp()], p, EVENT_PLAYER_HERO_LEVEL, null)
       call TriggerRegisterPlayerUnitEvent(udg_TalentTrigger[TT_SelectUnit()], p, EVENT_PLAYER_UNIT_SELECTED, null)
    
       if TalentHideUIWhenUnneeded() and TalentUseSkillPoints() then
           call TriggerRegisterPlayerUnitEvent(udg_TalentTrigger[TT_SpentSkillPoints()], p, EVENT_PLAYER_HERO_SKILL, 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 p = 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
   //This has to run before any TalentHeroSheet generations
   set gg_trg_Talent = CreateTrigger(  )
   set udg_TalentHash = InitHashtable(  )
   call TriggerAddAction( gg_trg_Talent, function TalentInit) //The TalentInit has to run after all TalentHeroSheets were generated
   call ExecuteFunc("TalentStringsInit")   //TalentStringsInit should run before any TalentHeroSheet was generated
endfunction


JASS:
function TalentStr takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_STR, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
endfunction
function TalentStrReset takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_STR, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
endfunction
function TalentAgi takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_AGI, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
endfunction
function TalentAgiReset takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_AGI, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
endfunction
function TalentInt takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_INT, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
endfunction
function TalentIntReset takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_INT, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
endfunction
function TalentKroneOfKing takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_INT, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
   call ModifyHeroStat( bj_HEROSTAT_STR, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
   call ModifyHeroStat( bj_HEROSTAT_AGI, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, 6 )
endfunction
function TalentKroneOfKingReset takes nothing returns nothing
   call ModifyHeroStat( bj_HEROSTAT_INT, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
   call ModifyHeroStat( bj_HEROSTAT_STR, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
   call ModifyHeroStat( bj_HEROSTAT_AGI, udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -6 )
endfunction
function TalentMithrilBlade takes nothing returns nothing
   call BlzSetUnitBaseDamage(udg_Talent__Unit, BlzGetUnitBaseDamage(udg_Talent__Unit, 1) + 20, 1)
endfunction
function TalentMithrilBladeReset takes nothing returns nothing
   call BlzSetUnitBaseDamage(udg_Talent__Unit, BlzGetUnitBaseDamage(udg_Talent__Unit, 1) - 20, 1)
endfunction
function TalentMithrilArmor takes nothing returns nothing
   call BlzSetUnitArmor(udg_Talent__Unit, BlzGetUnitArmor(udg_Talent__Unit) + 10)
endfunction
function TalentMithrilArmorReset takes nothing returns nothing
   call BlzSetUnitArmor(udg_Talent__Unit, BlzGetUnitArmor(udg_Talent__Unit) - 10)
endfunction
function TalentStatChange takes nothing returns nothing
   call ModifyHeroStat( udg_StatType[udg_Talent__Choice], udg_Talent__Unit, bj_MODIFYMETHOD_ADD, udg_StatPower[udg_Talent__Choice] )
endfunction
function TalentStatChangeReset takes nothing returns nothing
   call ModifyHeroStat( udg_StatType[udg_Talent__Choice], udg_Talent__Unit, bj_MODIFYMETHOD_ADD, -udg_StatPower[udg_Talent__Choice] )
endfunction
//Example for using Talent by Tasyen.
function TalentPaladin takes nothing returns nothing
   //Which HeroType is this; Custom Paladin
   local integer heroTypeId = 'H001'
   local integer choice
   local integer abilityId
 
   call TalentHeroSetFinalTier(heroTypeId, 8)    //Mark Level 8 as last choice
   //HeroTypeId gains at Level 0: create a new Tier
   call TalentHeroTierCreate(heroTypeId, 0)

   //Create a new Choice and add it to the last Created Tier
   set choice = TalentChoiceCreateEx( function TalentStr , function TalentStrReset)   //activade function TalentStr when Picking this Talent
   set udg_TalentChoiceText[choice] = "Gain 6 Str"
   set udg_TalentChoiceHead[choice] = "Handschue der Kraft"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower.blp"

   set choice = TalentChoiceCreateEx( function TalentAgi , function TalentAgiReset)
   set udg_TalentChoiceText[choice] = "Gain 6 Agi"
   set udg_TalentChoiceHead[choice] = "Schuhe der Beweglichkeit"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility.blp"

   set choice = TalentChoiceCreateEx( function TalentInt , function TalentIntReset)
   set udg_TalentChoiceText[choice] = "Gain 6 Int"
   set udg_TalentChoiceHead[choice] = "Robe der Weißen"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNRobeOfTheMagi.blp"

   //Level 2
   call TalentHeroTierCreate(heroTypeId, 2)
   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'Awfb'
   call TalentChoiceAddAbility(choice, abilityId) //Skill gained when picking this choice
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)

   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'AHhb'
   call TalentChoiceAddAbility(choice, abilityId)
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)


   //Level 4
   call TalentHeroTierCreate(heroTypeId, 4)

   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'Ainf'
   call TalentChoiceAddAbility(choice, abilityId)
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)

   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'Afbt'
   call TalentChoiceAddAbility(choice, abilityId)
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)

   //Create Own Variabes and attach them

   set choice = TalentChoiceCreateEx( function TalentStatChange , function TalentStatChangeReset)   //activade function TalentStr when Picking this Talent
   set udg_TalentChoiceText[choice] = "Gain 8 Str"
   set udg_TalentChoiceHead[choice] = "Handschue der Kraft"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower.blp"
   set udg_StatType[choice] = bj_HEROSTAT_STR   //choice is the index of the last create Choice, so attach custom Data to it.
   set udg_StatPower[choice] = 8
 
   set choice = TalentChoiceCreateEx( function TalentStatChange, function TalentStatChangeReset)
   set udg_TalentChoiceText[choice] = "Gain 8 Int"
   set udg_TalentChoiceHead[choice] = "Robe der Weißen"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNRobeOfTheMagi.blp"
   set udg_StatType[choice] = bj_HEROSTAT_INT
   set udg_StatPower[choice] = 8


   //Level 6
   call TalentHeroTierCreate(heroTypeId, 6)

   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'AHre'
   call TalentChoiceAddAbility(choice, abilityId)
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)

   set choice = TalentChoiceCreateEx(null, null)
   set abilityId = 'AHav'
   call TalentChoiceAddAbility(choice, abilityId)
   set udg_TalentChoiceText[choice] = BlzGetAbilityExtendedTooltip(abilityId,1)
   set udg_TalentChoiceHead[choice] = BlzGetAbilityTooltip(abilityId,1)
   set udg_TalentChoiceIcon[choice] = BlzGetAbilityIcon(abilityId)

   //Level 8
   call TalentHeroTierCreate(heroTypeId, 8)

   set choice = TalentChoiceCreateEx(function TalentKroneOfKing, function TalentKroneOfKingReset)
   set udg_TalentChoiceText[choice] = "Gain + 6 to all stats"
   set udg_TalentChoiceHead[choice] = "Krone des Königs"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHelmutPurple.blp"

   set choice = TalentChoiceCreateEx(function TalentMithrilBlade, function TalentMithrilBladeReset)
   set udg_TalentChoiceText[choice] = "Gain 20 ATK"
   set udg_TalentChoiceHead[choice] = "Mithril Blade"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNArcaniteMelee.blp"

   set choice = TalentChoiceCreateEx(function TalentMithrilArmor, function TalentMithrilArmorReset)
   set udg_TalentChoiceText[choice] = "Gain 10 Armor"
   set udg_TalentChoiceHead[choice] = "Mithril Armor"
   set udg_TalentChoiceIcon[choice] = "ReplaceableTextures\\CommandButtons\\BTNHumanArmorUpThree.blp"

endfunction

//===========================================================================
function InitTrig_Talent_Paladin takes nothing returns nothing
    set gg_trg_Talent_Paladin = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Talent_Paladin, function TalentPaladin )
endfunction

1.30.12
Shared Units are better supported.
hiding the button now is mui, prevoius mpi.
Changed API
Support of Talent usage without a Talentbook was improved
New Definition: "TalentReplacedAbilityRequiered"​
1.30.11 Correct String execution Order
1.30.10
FinalTier is no longer saved as boolean, instead saves the level.
Added API functions doing most Hashwork
Organized the API in categories:
TalentTier, TalentChoice, TalentHero, TalentUnit, Talent
Moved all Strings into one String array which is set inside Talent.
TalentGUI: CreateTier is now done automatic inside CreateChoice, when needed.​
 

Attachments

  • Talent V1.30.12.w3x
    87.1 KB · Views: 79
Last edited:
I feel this would be better off in the spells section as it requires editor data. You can't just copy the script to your map and use it.

Submission Guidelines said:
Spells or systems which require a demo map or would make the most sense to have a demo map should be submitted to the Spells section. If the code is simple or straightforward enough to be more or less copy & paste, you should submit it here.
 
Top