System Advanced Skill Learning System

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Advanced Skill Learning System

Have you ever whined about heroes not having enough learnable hero abilities? I mean, the heroes can have a maximum of five levelable abilities and that sucks. Plus the fact if they all are learned, they take so much space and you don't have enough room on the hero to display other important abilities. Well...not anymore!

Advanced Skill System allows you to increase the limit from 5 to 11! That is more than double the amount! How does the system do that? It transfers the learned spells to a Spell Book! Yes, that's right.

This system is quite complex to use in the beginning, so lets learn how to set up the system.


Step 1 – Creating the custom Spell Book and hero abilities menu

To begin, copy the ability “Spell Book” and paste it twice. Name one of them “Hero Abilities”.

ss_0000a.jpg


grid_0001.jpg

These two spell books need to have different base order ids, so change them. In my case, I changed them to “acidbomb” and “absorb”, for “Spell Book” and “Hero Abilities” respectively.

ss_0001.jpg

Lastly, change the to unit abilities by setting the “Stats – Item ability” to false to make the ability a unit ability.

ss_0002.jpg



Step 2 – Creating the custom ability for the hero to learn

The system requires 6 custom abilities to learn a single spell, so bear with me, as the process to make them takes some time. I've divided this step into 3 smaller steps.

- Creating the actual spell and its “container” spellbook.

Firstly, choose a spell you want the system to use. I've chosen “Breath of Fire”. Start by making the ability a unit ability (follow step 1 if you don't know how). Next, copy-paste the spell book with the “acidbomb” base order id. Change its name to “Breath of Fire (container)” and modify the spell list to contain “Breath of Fire”. Do not change this spell book's order id.

ss_0003.jpg


- Creating the ability needed to learn the spell and its “container” spellbook.

To learn the spell “Breath of Fire”, you need a dummy ability with three levels. I've based mine off “Channel” and renamed it to “Breath of Fire (Learn)”. Also, I've changed its base order id to remove the possiblity of clashing with other spells. As this skill has to display information about the spell “Breath of Fire” you have to change the tooltips to reflect the “Breath of Fire” tooltips.

grid_0000.jpg

Next, copy-paste the spell book with the "absorb" base order id. Change its name to "Breath of Fire (learn)(container)". Modify the spell list to contain "Breath of Fire (learn)". Again, do not change the order id.


- Creating the "requirement" ability and its container

To clarify, the "requirement" ability is the ability you cannot click on and displays the requirements needed to learn the next level of the spell. To create one, you need a non-aura, but passive ability, which does nothing. I've based mine of "Barrage", changed the fields to do nothing and made it a three level spell. Also, I've renamed it to "Breath of Fire (req)" and changed the tooltips.

grid_0002a.jpg

To finish with the abilities, you need to create one last "container". Copy-paste the spell book with the "absorb" base order id, rename it to "Breath of Fire (req)(container)" and modify its spell list to contain "Breath of Fire (req)".


Step 3 – Adding the ability to the hero and modifying the system options


Before you can add the “Breath of Fire” ability to the hero, you need to change a few system options (found in the configuration globals block):

- SPELL_BOOK – change this to the raw code of the “Spell Book” ability
- HERO_ABILITIES – change this to the raw code of the “Hero abilities” ability.

Now, if you've changed the system options, you need to add the “Spell Book” and custom hero abilities menu to the unit you want, by using the “UnitAddAdvancedSpellbook” function.

Here's an example how to do that using GUI:

- Set tmpunit = Pandaren Brewmaster 0004 <gen>
- Custom script: call UnitAddAdvancedSpellbook(udg_tmpunit)

After you've done that, you need to add all of the previously made abilities to the unit using the "UnitAddAbilityAdvanced" function:

- the function parameters are:

1) the unit you want to have the ability

2) the raw code of the ability
3) the raw code of the ability's container

4) the raw code of the ability needed to learn to "right" ability
5) the raw code of the "learn" ability's container

6) the raw code of the "requirement" ability
7) the raw code of the "requirement" ability's container​

And here's an example how to call the function using GUI:

NB! Make sure you call the function after you've added the custom spell book and hero abilities menu!


- Set tmpunit = Pandaren Brewmaster 0004 <gen>
- Custom script: call UnitAddAdvancedSpellbook(udg_tmpunit)
- Custom script: call UnitAddAbilityAdvanced(udg_tmpunit, 'A002', 'A004', 'A00A', 'A001', 'A003', 'A000')

If you have followed these steps correctly, you should have a working custom ability, which will be transferred to the spellbook when learnt!



The code behind the system (will be optimised, but does it's job):

JASS:
library SPELLBOOK initializer InitializeSystem
    // ver. 1.0
    // SYSTEM CONFIGURATION GLOBALS
    globals
        // determines whether the system is preloaded or not.
        // when loaded, increases the loading time but removes first-use lag.
        private constant boolean PRELOAD              = true
        // the number of skillpoints the hero starts with at level 1.
        private constant integer DEFAULT_SKILLPOINTS  = 1
        // the maximum level of the modified &#039;spellbook&#039; abilities.
        private constant integer SPELL_MAX_LEVEL      = 3
    endglobals
    
    // the level requirement &quot;skip&quot; for the abilities.
    // e.g to learn the second level of the spell, the hero itself must be level 3 etc.
    constant function GetLevelLearnRequirement takes integer level returns integer
        return level * 2 + 1
    endfunction    

    // RAWCODE CONFIGURATION GLOBALS
    globals
        // the raw code of the modified spellbook, where the learned abilities will be transferred.
        private constant integer SPELL_BOOK     = &#039;A008&#039;
        // the raw code of the modified spellbook, which acts as the place from where to learn the spells.
        private constant integer HERO_ABILITIES = &#039;A009&#039;
    endglobals

    // SYSTEM BUFFER GLOBALS
    // do not modify!
    globals     
        private constant integer SPELL_AMOUNT = 12 //amount of max spells possible in spellbook + 1.
    endglobals

    private struct herodata
        integer freePoints   = DEFAULT_SKILLPOINTS
        integer spellCount   = 0
        integer learntSpells = 0
       
        integer array skill[SPELL_AMOUNT]
        integer array skillSet[SPELL_AMOUNT]
        integer array learn[SPELL_AMOUNT]
        integer array learnSet[SPELL_AMOUNT]
        integer array reqSet[SPELL_AMOUNT]
        integer array req[SPELL_AMOUNT]
    endstruct
    
    // this function must be ran before trying to add &quot;advanced&quot; abilities for a unit.
    function UnitAddAdvancedSpellbook takes unit whichUnit returns nothing
        call UnitAddAbility(whichUnit, SPELL_BOOK)
        call UnitAddAbility(whichUnit, HERO_ABILITIES) 
        call SetUnitUserData(whichUnit, herodata.create())
    endfunction
    
    function UnitAddAbilityAdvanced takes unit whichUnit, integer skillId, integer skillContainerId, integer learnSkillId, integer learnSkillContainerId, integer reqSkillId, integer reqSkillContainerId returns nothing
        local herodata data = GetUnitUserData(whichUnit)
        local integer  n    = 0
        local unit     dum
        
        set data.spellCount = data.spellCount + 1
        // store the raw codes of the abilities, because we need them later.
        set data.skill[data.spellCount] = skillId
        set data.skillSet[data.spellCount] = skillContainerId
        set data.learn[data.spellCount] = learnSkillId
        set data.learnSet[data.spellCount] = learnSkillContainerId       
        set data.req[data.spellCount] =  reqSkillId
        set data.reqSet[data.spellCount] = reqSkillContainerId  
        // disable the &quot;container&quot; spellbooks as we don&#039;t want them to appear on the unit
        loop
            exitwhen (n &gt; bj_MAX_PLAYERS)
            call SetPlayerAbilityAvailable(Player(n), skillContainerId, false)
            call SetPlayerAbilityAvailable(Player(n), learnSkillContainerId, false) 
            call SetPlayerAbilityAvailable(Player(n), reqSkillContainerId, false) 
            set n = n + 1
        endloop
        // preload the abilities, if wanted.
        if (PRELOAD) then
            set dum = CreateUnit(Player(0), &#039;hfoo&#039;, 0, 0, 0)
            call UnitAddAbility(dum, skillContainerId) 
            call UnitAddAbility(dum, learnSkillContainerId)
            call UnitAddAbility(dum, reqSkillContainerId)
            call RemoveUnit(dum)
            set dum = null
        endif 
        // add the &quot;learn&quot; ability to the unit.
        call UnitAddAbility(whichUnit, learnSkillContainerId)
    endfunction
    
    private function GetLearnSkillIndex takes unit whichUnit, integer abilCode returns integer
        local herodata data  = GetUnitUserData(whichUnit)
        local integer  index = 0
        
        loop
            exitwhen (abilCode == data.learn[index])
            if (index &gt; data.spellCount) then
                return -1 // the unit does not have the specified &quot;learn&quot; ability
            endif
            set index = index + 1
        endloop
        return index
    endfunction

    private function UnitDisableAllLearnAbilities takes unit whichUnit returns nothing
        local herodata data  = GetUnitUserData(whichUnit)
        local integer  index = 0
        local integer  level
        
        loop
            exitwhen (index &gt; data.spellCount)
            // remember the level of the &quot;learn&quot; ability
            set level = GetUnitAbilityLevel(whichUnit, data.skill[index])
            if (level &lt; SPELL_MAX_LEVEL) then
                // remove the container with the &quot;learn&quot; ability
                call UnitRemoveAbility(whichUnit, data.learnSet[index])
                // add the the container with the &quot;requirement&quot; ability
                call UnitAddAbility(whichUnit, data.reqSet[index])
                // set the &quot;requirement&quot; ability to the right level
                call SetUnitAbilityLevel(whichUnit, data.req[index], level + 1)
            endif
            set index = index + 1
        endloop
    endfunction
    
    private function UnitDisableLearnAbility takes unit whichUnit, integer abilcode returns nothing
        local integer  index = GetLearnSkillIndex(whichUnit, abilcode)
        local integer  level
        local herodata data
 
        if (index &gt; -1) then
            set data = GetUnitUserData(whichUnit)
            set level = GetUnitAbilityLevel(whichUnit, data.learn[index])
            call UnitRemoveAbility(whichUnit, data.learnSet[index])
            call UnitAddAbility(whichUnit, data.reqSet[index])
            call SetUnitAbilityLevel(whichUnit, data.req[index], level)
        endif
    endfunction    
    
    private function UnitEnableLearnAbility takes unit whichUnit, integer abilcode returns nothing
        local integer  index = GetLearnSkillIndex(whichUnit, abilcode)
        local integer  level
        local herodata data
 
        if (index &gt; -1) then
            set data = GetUnitUserData(whichUnit)
            set level = GetUnitAbilityLevel(whichUnit, data.skill[index])
            call UnitRemoveAbility(whichUnit, data.reqSet[index])
            call UnitAddAbility(whichUnit, data.learnSet[index])
            call SetUnitAbilityLevel(whichUnit, data.learn[index], level + 1)
        endif     
    endfunction
    
    private function HeroLearnsSkill_eventresponse takes nothing returns nothing
        local integer  id     = GetSpellAbilityId()
        local unit     caster = GetTriggerUnit()
        local integer  index  = GetLearnSkillIndex(caster, id)
        local herodata data
        local integer  level
        
        if (index &gt; -1) then
            set data = GetUnitUserData(caster)
            // deduct one skillpoint.
            set data.freePoints = data.freePoints - 1             
            set level = GetUnitAbilityLevel(caster, data.skill[index])
            
            if (level == 0) then
                // the hero learns the spell for the first time. add it.
                call UnitAddAbility(caster, data.skillSet[index])
                //call SetUnitAbilityLevel(caster, data.learn[index], level + 1)
            else
                // otherwise, increase the level of the spell.
                call SetUnitAbilityLevel(caster, data.skill[index], level + 1)
            endif
            set id = GetUnitAbilityLevel(caster, data.learn[index])
            call SetUnitAbilityLevel(caster, data.learn[index], id + 1)
            
            // the hero has maxed out the spell, remove the &quot;learn&quot; ability.
            if (id == SPELL_MAX_LEVEL) then
                call UnitRemoveAbility(caster, data.learnSet[index])
                set data.learntSpells = data.learntSpells + 1
                if (data.learntSpells == data.spellCount) then
                    call UnitRemoveAbility(caster, HERO_ABILITIES)
                else
                    if (data.freePoints == 0) then
                        call UnitDisableAllLearnAbilities(caster)
                    endif
                endif
            else
                // do we need to disable learning of the abilities because there are not enough skill points.
                if (data.freePoints == 0) then
                    call UnitDisableAllLearnAbilities(caster)
                    // do we need to disable only learning of the just-learnt ability because the hero does
                    // not have level high enough to learn the next level of the spell. 
                elseif (GetHeroLevel(caster) &lt; GetLevelLearnRequirement(level + 1)) then
                    call UnitDisableLearnAbility(caster, data.learn[index])
                endif
            endif
        endif
        
        set caster = null
    endfunction
    
    private function HeroGainsLevel_eventresponse takes nothing returns nothing
        local unit     gainer = GetTriggerUnit()
        local herodata data   = GetUnitUserData(gainer)
        local integer  level  = GetHeroLevel(gainer)
        local integer  index  = 0
        local integer  spellL
        
        set data.freePoints = data.freePoints + 1        
        loop
            exitwhen (index &gt; data.spellCount)
            set spellL = GetUnitAbilityLevel(gainer, data.skill[index])  
            // we have to enable all these abilities, which are not maxed out and are low enough for the hero to learn.
            if (level &gt;= GetLevelLearnRequirement(spellL)) and (spellL &lt; SPELL_MAX_LEVEL) then
                call UnitEnableLearnAbility(gainer, data.learn[index])
            endif
            set index = index + 1
        endloop
        
        set gainer = null
    endfunction
    
    //===========================================================================
    private function InitializeSystem takes nothing returns nothing
        local trigger trig      = CreateTrigger() 
        local trigger levelGain = CreateTrigger()

        local integer index = 0
        local player  play
        local unit    dum
        
        if (PRELOAD) then
            set dum = CreateUnit(Player(0), &#039;hfoo&#039;, 0, 0, 0)
            call UnitAddAbility(dum, SPELL_BOOK)
            call UnitAddAbility(dum, HERO_ABILITIES)         
            call RemoveUnit(dum)
            set dum = null
        endif
        loop
            exitwhen (index == bj_MAX_PLAYER_SLOTS)
            set play = Player(index)
            call TriggerRegisterPlayerUnitEvent(trig, play, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(levelGain, play, EVENT_PLAYER_HERO_LEVEL, null)
            set index = index + 1            
        endloop        
        call TriggerAddAction(levelGain, function HeroGainsLevel_eventresponse)
        call TriggerAddAction(trig, function HeroLearnsSkill_eventresponse)
        
        set trig      = null
        set levelGain = null
    endfunction
endlibrary




A pros/cons list:

legend
- "+" means that issue will be fixed in future versions.

cons
- it is complex to set up the skills and the process takes some time.
- every skill you want to add requires creating 6 custom abilities.
- does not support 1-level ultimates skills. (+)
- does not support different level "gap" requirements for separate spells (e.g you have to be level 6 to learn spell x, but level 9 to learn y). (+)
- does not support setting the "advanced" skills for unit type, you have to add them to every unit you want to have the spellbook, manually (+)
- does not support more than one "advanced" spellbook on a unit.
- the system does not display the current amount of free skill points. (+)
- while all of the spells are not learnt, their icons jump around because the spellbook ignores tooltip button positions(+)
- does not support the 'Tome of Retraining' (+)
- without custom icons, the DISBTN versions of the "requirement" abilities show green.

pros
- multi unit instanceable.
- when preloaded, lag free.
- allows learnt skills to be transferred into a spellbook (up to 11 skills, as this is as much as the spellbook itself can hold).
- allows you to save space for other abilities you do not want appear in a spell book.

sidenotes

- does not use any attaching system but unit custom value (will be changed)
- requires newgen package



Download and the test the demo map with 4 abilities!

Happy mapping!


Andrewgosu, the Pandaren!
 

Attachments

  • AdvancedSkillSystem_Andrewgosu_2008.w3x
    20.3 KB · Views: 956

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Currently looking for ideas how to display the remaining skill points!

- An item in the inventory with charges representing the skill points?
- An ability with the same amount of level as the max hero level, which is in the spell book, to display the amount of skill points?
- something else?
 

DrEvil

FCRI Associate!
Reaction score
111
"- An item item the inventroy with charges representing the skill points?"

Dont you mean :

"- An item in the inventroy with charges representing the skill points?"

Typo ?

I like the look of this , will test in a few moments .
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
Lol. It is funny how you make your systems and spells partially a tutorial too. =P

Anyway, I'll check it out tomorrow hopefully and I might come back with some feedback. =D
 

XeNiM666

I lurk for pizza
Reaction score
138
lol!! nice tutorial!!! +rep!

i was thinking on how to do this lately..
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
Very cool and useful even though it is, indeed, a pain to set up. Can't wait for the next version!
 

D.V.D

Make a wish
Reaction score
73
It would be cool if you can make a ability system like in WOW. I know its possible because full screen inventory systems were made. It would just be really hard.
 

Sunchips

New Member
Reaction score
6
"Before you can add the “Breath of Fire” ability to the hero, you need to change a few system options (found in the configuration globals block)"

What? :S I don't understand a shit of that :(
 

Kitt

New Member
Reaction score
5
So, I've gotten this working correctly, and from what I can tell, it doesn't actually display the number of remaining unspent skill points, and the OP says that it does. So either the code provided is old, or the OP needs to be changed. I hoping for the former >.>

Edit: I've gone ahead and added functionality to do this. It's a bit painstaking to get it to work, but it does work very well once set up. I'll post instructions how to "upgrade" the current system for anyone who may find this thread and want to know what I did =) Give me a bit to write things up and post the files you'll need to import. I only have support for up to 10 unspent skill points right now, though things can easily be changed to support more - although you'll need to make more images by hand if you want to display a number above 10.

Also, it's important to note that this idea can be used to create other skills with "charges". I've seen a number of people ask about how to do this, and never have I found anyone who had a good answer. It is a bit of work, but can look really good once done. It could even be used to count down for skill which do something every X amount of attacks, or something like that.

Mew.
 

Kitt

New Member
Reaction score
5
Alright, as promised, here is how to get the little "plus" sign to show how many unspent skill points you have left. I must admit, this is a blatant brute force method, and makes this system even more of a pain to set up - you'll need to create 10 additional skills, and you'll need to important 20 different icon images. As mentioned, the system I'm describing here only supports displaying numbers up to 10 (though you will still have more than 10 points to spend, it will only display 10). This can be changed by simply changing a few things and importing a few more images, but those images can be a bit of a pain to make.

At any rate, why don't we get started? This short little fix assumes you already have the system above up and running. I will be appending the above code, and will be expanding from an already completed Advanced Skill Learning System.

Importing the Image Files

The first thing you'll need to do is import those files I mentioned. I've done numbers up to 10 already, so you may use mine. I've attached them to this post in a .zip file. Once you've gotten those imported, make sure to change the path for each of BTN images to ReplaceableTextures\CommandButtons\<image name>.blp and the DISBTN images to ReplaceableTextures\CommandButtonsDisabled\<image name>.blp where "<image name>" is whatever that images name is.


Making the "Hero Abilities" Copies

The next step is to copy the Hero Abilities ability that we made in the guide above. How ever many numbers you want it to be able to go up to is how many different copies you should have. My system goes up to 10, so I have 11 skills named Hero Abilities - the original one, and then 10 copies. To keep things organized, I changed the name of each one and add a "(default)" to the basic one (a plus sign with no numbers) and a "(01)", "(02)", etc. on each of the copies so that I could easily tell which number was on which one. Remember, these copies should be IDENTICAL to the Hero Abilities ability from above. If you make any change to one, you should do it to all the others as well - so make sure you don't need to make any more changes before you copy it =)

Finally, change the image of each one to it's corresponding .blp file. So "Hero Abilities (default)" should have a plus sign with no numbers on it, "Hero Abilities (01)" should have a plus sign with the number 1 on it, and so on. This is very important - if you don't do this, the numbers wont display like you want them to!

For reference, here is what mine look like:

HeroAbilities.gif


Changing the Code

Alright. Now we need to edit the code so that when you level up or get a skill, the number will change accordingly. The basic plan of action (for those who care) is remove the old "Hero Abilities" when a level is gained or whenever a skill point is spent, and then give them a new "Hero Abilities", but with a different image. Remember, the two abilities are IDENTICAL in function, they only differ in the image. So the system will work exactly as it did before, but our images will change according to how many free skill points we have! If you understand JASS, it shouldn't be too hard to find the changes following this logic - I've commented my name next to each part I edited as well, so it's easy to find. Here is the changed code:

JASS:
library SPELLBOOK initializer InitializeSystem
    // ver. 1.0
    // SYSTEM CONFIGURATION GLOBALS
    globals
        // determines whether the system is preloaded or not.
        // when loaded, increases the loading time but removes first-use lag.
        private constant boolean PRELOAD              = true
        // the number of skillpoints the hero starts with at level 1.
        private constant integer DEFAULT_SKILLPOINTS  = 1
        // the maximum level of the modified &#039;spellbook&#039; abilities.
        private constant integer SPELL_MAX_LEVEL      = 3
// Added by Kitt ------------------------------------------------------------------------------
        // the total number of level up icons we&#039;ll be using (number of levels + 1).
        private constant integer ICON_TOTAL = 11
        // an array to hold each of the different icon abilities.
        private integer array HERO_ABILITIES[ICON_TOTAL]
//---------------------------------------------------------------------------------------------
    endglobals

// Added by Kitt ------------------------------------------------------------------------------
    function SetAbilityValues takes nothing returns nothing
        // set the raw code of each of the different level up abilities here.
        set HERO_ABILITIES[0] = &#039;A001&#039;
        set HERO_ABILITIES[1] = &#039;A008&#039;
        set HERO_ABILITIES[2] = &#039;A009&#039;
        set HERO_ABILITIES[3] = &#039;A00B&#039;
        set HERO_ABILITIES[4] = &#039;A00A&#039;
        set HERO_ABILITIES[5] = &#039;A00D&#039;
        set HERO_ABILITIES[6] = &#039;A00C&#039;
        set HERO_ABILITIES[7] = &#039;A00F&#039;
        set HERO_ABILITIES[8] = &#039;A00E&#039;
        set HERO_ABILITIES[9] = &#039;A00H&#039;
        set HERO_ABILITIES[10] = &#039;A00G&#039;   
    endfunction
//----------------------------------------------------------------------------------------------
    
    // the level requirement &quot;skip&quot; for the abilities.
    // e.g to learn the second level of the spell, the hero itself must be level 3 etc.
    constant function GetLevelLearnRequirement takes integer level returns integer
        return level * 2 + 1
    endfunction    

    // RAWCODE CONFIGURATION GLOBALS
    globals
        // the raw code of the modified spellbook, where the learned abilities will be transferred.
        private constant integer SPELL_BOOK     = &#039;A000&#039;
        // Kitt: I removed a line here, it got moved to the SetHeroAbilities function because of the way it&#039;s declared. The code no longer makes sense here.
    endglobals

    // SYSTEM BUFFER GLOBALS
    // do not modify!
    globals     
        private constant integer SPELL_AMOUNT = 12 //amount of max spells possible in spellbook + 1.
    endglobals

    private struct herodata
        integer freePoints   = DEFAULT_SKILLPOINTS
        integer spellCount   = 0
        integer learntSpells = 0
       
        integer array skill[SPELL_AMOUNT]
        integer array skillSet[SPELL_AMOUNT]
        integer array learn[SPELL_AMOUNT]
        integer array learnSet[SPELL_AMOUNT]
        integer array reqSet[SPELL_AMOUNT]
        integer array req[SPELL_AMOUNT]
    endstruct
    
    // this function must be ran before trying to add &quot;advanced&quot; abilities for a unit.
    function UnitAddAdvancedSpellbook takes unit whichUnit returns nothing
        call UnitAddAbility(whichUnit, SPELL_BOOK)
        call UnitAddAbility(whichUnit, HERO_ABILITIES[DEFAULT_SKILLPOINTS]) 
        call SetUnitUserData(whichUnit, herodata.create())
    endfunction
    
    function UnitAddAbilityAdvanced takes unit whichUnit, integer skillId, integer skillContainerId, integer learnSkillId, integer learnSkillContainerId, integer reqSkillId, integer reqSkillContainerId returns nothing
        local herodata data = GetUnitUserData(whichUnit)
        local integer  n    = 0
        local unit     dum
        
        set data.spellCount = data.spellCount + 1
        // store the raw codes of the abilities, because we need them later.
        set data.skill[data.spellCount] = skillId
        set data.skillSet[data.spellCount] = skillContainerId
        set data.learn[data.spellCount] = learnSkillId
        set data.learnSet[data.spellCount] = learnSkillContainerId       
        set data.req[data.spellCount] =  reqSkillId
        set data.reqSet[data.spellCount] = reqSkillContainerId  
        // disable the &quot;container&quot; spellbooks as we don&#039;t want them to appear on the unit
        loop
            exitwhen (n &gt; bj_MAX_PLAYERS)
            //call SetPlayerAbilityAvailable(Player(n), skillContainerId, false)
            call SetPlayerAbilityAvailable(Player(n), learnSkillContainerId, false) 
            call SetPlayerAbilityAvailable(Player(n), reqSkillContainerId, false) 
            set n = n + 1
        endloop
        // preload the abilities, if wanted.
        if (PRELOAD) then
            set dum = CreateUnit(Player(0), &#039;hfoo&#039;, 0, 0, 0)
            call UnitAddAbility(dum, skillContainerId) 
            call UnitAddAbility(dum, learnSkillContainerId)
            call UnitAddAbility(dum, reqSkillContainerId)
            call RemoveUnit(dum)
            set dum = null
        endif 
        // add the &quot;learn&quot; ability to the unit.
        call UnitAddAbility(whichUnit, learnSkillContainerId)
    endfunction
    
    private function GetLearnSkillIndex takes unit whichUnit, integer abilCode returns integer
        local herodata data  = GetUnitUserData(whichUnit)
        local integer  index = 0
        
        loop
            exitwhen (abilCode == data.learn[index])
            if (index &gt; data.spellCount) then
                return -1 // the unit does not have the specified &quot;learn&quot; ability
            endif
            set index = index + 1
        endloop
        return index
    endfunction

    private function UnitDisableAllLearnAbilities takes unit whichUnit returns nothing
        local herodata data  = GetUnitUserData(whichUnit)
        local integer  index = 0
        local integer  level
        
        loop
            exitwhen (index &gt; data.spellCount)
            // remember the level of the &quot;learn&quot; ability
            set level = GetUnitAbilityLevel(whichUnit, data.skill[index])
            if (level &lt; SPELL_MAX_LEVEL) then
                // remove the container with the &quot;learn&quot; ability
                call UnitRemoveAbility(whichUnit, data.learnSet[index])
                // add the the container with the &quot;requirement&quot; ability
                call UnitAddAbility(whichUnit, data.reqSet[index])
                // set the &quot;requirement&quot; ability to the right level
                call SetUnitAbilityLevel(whichUnit, data.req[index], level + 1)
            endif
            set index = index + 1
        endloop
    endfunction
    
    private function UnitDisableLearnAbility takes unit whichUnit, integer abilcode returns nothing
        local integer  index = GetLearnSkillIndex(whichUnit, abilcode)
        local integer  level
        local herodata data
 
        if (index &gt; -1) then
            set data = GetUnitUserData(whichUnit)
            set level = GetUnitAbilityLevel(whichUnit, data.learn[index])
            call UnitRemoveAbility(whichUnit, data.learnSet[index])
            call UnitAddAbility(whichUnit, data.reqSet[index])
            call SetUnitAbilityLevel(whichUnit, data.req[index], level)
        endif
    endfunction    
    
    private function UnitEnableLearnAbility takes unit whichUnit, integer abilcode returns nothing
        local integer  index = GetLearnSkillIndex(whichUnit, abilcode)
        local integer  level
        local herodata data
 
        if (index &gt; -1) then
            set data = GetUnitUserData(whichUnit)
            set level = GetUnitAbilityLevel(whichUnit, data.skill[index])
            call UnitRemoveAbility(whichUnit, data.reqSet[index])
            call UnitAddAbility(whichUnit, data.learnSet[index])
            call SetUnitAbilityLevel(whichUnit, data.learn[index], level + 1)
        endif     
    endfunction
    
    private function HeroLearnsSkill_eventresponse takes nothing returns nothing
        local integer  id     = GetSpellAbilityId()
        local unit     caster = GetTriggerUnit()
        local integer  index  = GetLearnSkillIndex(caster, id)
        local herodata data
        local integer  level
        
        if (index &gt; -1) then
            set data = GetUnitUserData(caster)
// Added by Kitt ------------------------------------------------------------------------------
            // remove the current HERO_ABILITIES ability, and add the new one. Only do so if we haven&#039;t run out of icons yet.
            if (data.freePoints &lt;= ICON_TOTAL) then
                call UnitRemoveAbility(caster, HERO_ABILITIES[data.freePoints])
                call UnitAddAbility(caster, HERO_ABILITIES[data.freePoints - 1])
            endif
//---------------------------------------------------------------------------------------------
            // deduct one skillpoint.
            set data.freePoints = data.freePoints - 1             
            set level = GetUnitAbilityLevel(caster, data.skill[index])
            
            if (level == 0) then
                // the hero learns the spell for the first time. add it.
                call UnitAddAbility(caster, data.skillSet[index])
                //call SetUnitAbilityLevel(caster, data.learn[index], level + 1)
            else
                // otherwise, increase the level of the spell.
                call SetUnitAbilityLevel(caster, data.skill[index], level + 1)
            endif
            set id = GetUnitAbilityLevel(caster, data.learn[index])
            call SetUnitAbilityLevel(caster, data.learn[index], id + 1)
            
            // the hero has maxed out the spell, remove the &quot;learn&quot; ability.
            if (id == SPELL_MAX_LEVEL) then
                call UnitRemoveAbility(caster, data.learnSet[index])
                set data.learntSpells = data.learntSpells + 1
                if (data.learntSpells == data.spellCount) then
                    call UnitRemoveAbility(caster, HERO_ABILITIES[data.freePoints])
                else
                    if (data.freePoints == 0) then
                        call UnitDisableAllLearnAbilities(caster)
                    endif
                endif
            else
                // do we need to disable learning of the abilities because there are not enough skill points.
                if (data.freePoints == 0) then
                    call UnitDisableAllLearnAbilities(caster)
                    // do we need to disable only learning of the just-learnt ability because the hero does
                    // not have level high enough to learn the next level of the spell. 
                elseif (GetHeroLevel(caster) &lt; GetLevelLearnRequirement(level + 1)) then
                    call UnitDisableLearnAbility(caster, data.learn[index])
                endif
            endif
        endif
        
        set caster = null
    endfunction
    
    private function HeroGainsLevel_eventresponse takes nothing returns nothing
        local unit     gainer = GetTriggerUnit()
        local herodata data   = GetUnitUserData(gainer)
        local integer  level  = GetHeroLevel(gainer)
        local integer  index  = 0
        local integer  spellL

// Added by Kitt ------------------------------------------------------------------------------
        // remove the current HERO_ABILITIES ability, and add the new one. Only do so if we haven&#039;t run out of icons yet.
        if (data.freePoints &lt;= ICON_TOTAL) then
            call UnitRemoveAbility(gainer, HERO_ABILITIES[data.freePoints])
            call UnitAddAbility(gainer, HERO_ABILITIES[data.freePoints + 1])
        endif
//---------------------------------------------------------------------------------------------
        
        // add one skillpoint.
        set data.freePoints = data.freePoints + 1             
        
        loop
            exitwhen (index &gt; data.spellCount)
            set spellL = GetUnitAbilityLevel(gainer, data.skill[index])  
            // we have to enable all these abilities, which are not maxed out and are low enough for the hero to learn.
            if (level &gt;= GetLevelLearnRequirement(spellL)) and (spellL &lt; SPELL_MAX_LEVEL) then
                call UnitEnableLearnAbility(gainer, data.learn[index])
            endif
            set index = index + 1
        endloop
        
        set gainer = null
    endfunction
    
    //===========================================================================
    private function InitializeSystem takes nothing returns nothing
        local trigger trig      = CreateTrigger() 
        local trigger levelGain = CreateTrigger()

        local integer index = 0
        local player  play
        local unit    dum

// Added by Kitt ------------------------------------------------------------------------------
        call SetAbilityValues()
//---------------------------------------------------------------------------------------------
        
        if (PRELOAD) then
            set dum = CreateUnit(Player(0), &#039;hfoo&#039;, 0, 0, 0)
            call UnitAddAbility(dum, SPELL_BOOK)
            call UnitAddAbility(dum, HERO_ABILITIES[DEFAULT_SKILLPOINTS])         
            call RemoveUnit(dum)
            set dum = null
        endif
        loop
            exitwhen (index == bj_MAX_PLAYER_SLOTS)
            set play = Player(index)
            call TriggerRegisterPlayerUnitEvent(trig, play, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(levelGain, play, EVENT_PLAYER_HERO_LEVEL, null)
            set index = index + 1            
        endloop        
        call TriggerAddAction(levelGain, function HeroGainsLevel_eventresponse)
        call TriggerAddAction(trig, function HeroLearnsSkill_eventresponse)
        
        set trig      = null
        set levelGain = null
    endfunction
endlibrary


We actually have a few more settings we need to apply now. First find the ICON_TOTAL global value. It's at the very top, and should look like this:
JASS:
// Added by Kitt ------------------------------------------------------------------------------
        // the total number of level up icons we&#039;ll be using (number of levels + 1).
        private constant integer ICON_TOTAL = 11
        // an array to hold each of the different icon abilities.
        private integer array HERO_ABILITIES[ICON_TOTAL]
//---------------------------------------------------------------------------------------------


You need to set that value to 1 + the highest number you want to be displayed on the level up button. In my case, my numbers go up to 10, so mine is set to 11. This will tell the program how many abilities it should expect so that if we accidentally gain more skill points than we have images for, it wont glitch up on us.

Next, we need to register a whole ton more abilities. Remember all those copies of "Hero Abilities" we made? Well, here's where we do something with them. Fist, find the SetAbilityValues function. It should look like this:

JASS:
/ Added by Kitt ------------------------------------------------------------------------------
    function SetAbilityValues takes nothing returns nothing
        // set the raw code of each of the different level up abilities here.
        set HERO_ABILITIES[0] = &#039;A001&#039;
        set HERO_ABILITIES[1] = &#039;A008&#039;
        set HERO_ABILITIES[2] = &#039;A009&#039;
        set HERO_ABILITIES[3] = &#039;A00B&#039;
        set HERO_ABILITIES[4] = &#039;A00A&#039;
        set HERO_ABILITIES[5] = &#039;A00D&#039;
        set HERO_ABILITIES[6] = &#039;A00C&#039;
        set HERO_ABILITIES[7] = &#039;A00F&#039;
        set HERO_ABILITIES[8] = &#039;A00E&#039;
        set HERO_ABILITIES[9] = &#039;A00H&#039;
        set HERO_ABILITIES[10] = &#039;A00G&#039;   
    endfunction
//----------------------------------------------------------------------------------------------


Just like before, we need to set each of the raw values for each of our "Hero Abilities" abilities. I hope you took the time to number them like I suggested, because this is where that could be handy: The order matters!

HERO_ABILITIES[0] needs to be set to the raw code of the "Hero Abilities (default)" ability; this is what will show when we have no skill points to spend. Then, for the rest of them, HERO_ABILITIES[1] should be set to the raw code of "Hero Abilities (01)" and HERO_ABILITIES[2] should be set to the raw code of "Hero Abilities (02)", and so on for each one you made.

The End!

And there you have it! Everything should be working by now. When finished your system should work exactly as it did before, except now the level up icon displays the number of unspent skill points! Like I said, tedious, and very brute force - but it DOES get the job done. If someone has a problem, feel free to leave me a PM - but I believe the guide should walk you through it fairly well. Happy map making!

Mew =3
 

Attachments

  • LevelUpButtons.zip
    95.5 KB · Views: 344
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top