System (another) Advanced Skill Learning System

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Advanced Skill Learning System
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Actually, this system is "dummy learns skills and hero gets the skills" system (or "dummy learns skills for hero")

I think this system is a little complex.
To set up the system, we need some steps.

◊ Requires:
- JassNewGenPack
- PUI

◊ Step 1 - Create some unit, abilities and item for the system

We need:
  • Unit:
    • Skill Learner: the dummy that do the learning
  • Abilities:
    • Hero Skill: an instant cast ability (hero use)
    • Cancel: an instant cast ability as well (dummy use)
    • One Slot Inventory: (optional) ability that gives One slot inventory (dummy use)
    • Tome of Retraining: (optional) based on Berserk (item)
  • Item:
    • Hero Skill: to display current unspent skill points
    • Tom of Retraining: (optional) for retraining purpose. This item must have Stats - Perishable: False

◊ Step 2 - Create custom abilities for hero to learn

For each hero ability, we need 3 abilities
- One real ability (for hero to use)
- Two fake abilities: one for the learning of skill, dummy uses and one for the requirement

For example:
The hero has Storm Bolt to learn

  • Real ability: normal tooltip, nothing else
    pic1g.jpg
  • Fake ability for learning:
    pic2omx.jpg
  • Fake ability for requirement: remember the tooltip with "requires level #" and also it has a level in which the tooltip does not has requirement. (errr... how should I explain this, when your hero has enough level to learn an skill but he/she doesn't have skill point, so learning of this skill will be disabled, right ?)
    pic3ryg.jpg

◊ Step 3 - Register your hero's skills into the system

here is the register function:
JASS:
function InitHeroAbilities takes unit hero, string skillz returns nothing

  • hero: ofc it's your hero
  • skillz: a (very) long string that contains data about hero's skills.

string skillz​
(real ability)_(ability learn)_(ability disable)_(spell book)_(option string);
note:
(spell book) is the spell book that contains the real ability, in the demo map, passive abilities are put in a spell book. If you don't have this, just put "0"
(option string) contains the maximum level, level requirement, level skip and "no skill point disable level"

for my Storm Bolt: its raw id is 'A000', ability learn is 'AL00', ability disable is 'AD00' => I have this string:
JASS:
skillz = I2S('A000')+"_"+I2S('AL00')+"_"+I2S('AD00')


I don't need to put it into a spell book, so:
JASS:
skillz = skillz + "_0_"

max level is 4, it requires level 1 to learn, level skip is 2 and level at which the learning is disabled if there are no skill point is 1
JASS:
skillz = skillz +"4"+"01"+"2"+"1" //requires level should be written in two... letters.


the final string skillz
JASS:
skillz = I2S('A000')+"_"+I2S('AL00')+"_"+I2S('AD00')+"_0_40121;" //remember the ";"


that's the string skillz for ONE skill.
---
So, to register StormBolt to hero:
JASS:
call InitHeroAbilities( hero, I2S('A000')+"_"+I2S('AL00')+"_"+I2S('AD00')+"_0_40121;" )

---
If you want your hero to have 10 learnable skills, you will have to write a very long string, 10 skillz string, one after another
---
in the demo map, my "Holy Warrior" has 10 learnable skills. And here is some pics:
pic4agb.jpg

pic5m.jpg

pic6gmt.jpg

pic7zwd.jpg

◊ Other Info

- MUI
- complex (a little)
- Support Spell Book (but your Spell Book must be specific and contains the skills which requires it)
- Support Tome of Retraining but also unlearn spells that's in cooldown :(
- pretty laggy because first time add.
- custom icons should be imported (or the "requirement" abilities will show green.) But I think use BLPaletter with 30% quality for DISBTN is ok.
- every skill you want to add requires 3 abilities
- System's code:
JASS:
library AdvancedSkillSystem initializer Init requires PUI

//       ###### CONFIGURATION GLOBALS #####
globals
    private constant integer SKILL_LEARNER = 'skle'
    //raw id of the skill learner dummy
    private constant integer HEROBUTTON_ABIL = 'Ahsk'
    //raw id of the Hero Skill dialog ability
    private constant integer ONESLOTINVENTORY = 'Aosi'
    //raw id of the 'one slot inventory' ability for dummy
    private constant integer SKILLPOINT_SHOWER = 'hsbt'
    //raw id of the item that show the un-spent skill points
    private constant integer RETRAIN_ITEM = 'trtn'
    //raw id of the 'Tome of Retraining' item
    private constant integer CANCEL_ABIL = 'Aesc'
    //raw id of the close Hero Skill dialog ability
    private constant integer DEFAULT_SKILLPOINTS  = 1
    //skill points gained per level
    private constant integer MAXIMUMSKILLPERHERO = 10
    //how many skills that a hero can have
endglobals

//________________________________________________________________________________________________
//-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>
//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//              Do not modify the below code (unless you know what you are doing)
globals
    private boolexpr ESCF
    private group ENUMER = CreateGroup()
    private boolean NoCheckSelect = false
endglobals

private function CountToChar takes string st, string char, integer start returns integer
    local integer i
    local integer im = StringLength(st)
    local integer l = StringLength(char)
    set i = start
    loop
        exitwhen i > im-(l-1)
        if SubString(st,i-1,i+l-1) == char then
        return i-1
        endif
        set i = i + 1
    endloop
    if i == im then
        return i
    endif
    return i-1
endfunction

function NewTextTagEx takes string msg,real size, real x, real y,real z, real vel,real ang, real life,real fade, boolean checkvis returns texttag
    local texttag tt
    local integer int = 0
    set tt = CreateTextTag()
    call SetTextTagPos(tt, x, y, z)
    call SetTextTagColor(tt, 255, 255, 255, 255)
    call SetTextTagVelocity(tt, 0, 0)
    call SetTextTagVisibility(tt, true)
    call SetTextTagText(tt, msg, size * 0.023 / 10 )
    call SetTextTagVelocityBJ( tt, vel, ang )
    call SetTextTagPermanent( tt, false)
    call SetTextTagLifespan(tt, life)
    call SetTextTagFadepoint(tt,fade)
    if checkvis then
        loop
            exitwhen int > 9
            if GetLocalPlayer() == Player(int) then
                call SetTextTagVisibility( tt , IsVisibleToPlayer(x,y, Player(int) )  )
            endif
            set int = int + 1
        endloop
    endif
    set bj_lastCreatedTextTag = tt
    set tt = null
    return bj_lastCreatedTextTag
endfunction

private struct abildata
    integer id
    integer idlearn
    integer iddisable
    integer lvlcur = 0
    integer lvlmax
    integer lvlreq
    integer lvlskip
    integer lvlnolearn
    integer bookid
endstruct

private struct data
    //! runtextmacro PUI()
    unit hero
    unit learner
    player heroowner
    abildata array abi [MAXIMUMSKILLPERHERO]
    integer numberskills = -1
    integer unspentskillpoint
    integer totalskillpoint = 0
    item    skillpointshower
    
    integer currentlevel = 1
endstruct

private function CheckHeroAbilities takes unit c returns nothing
    local data d = data[c]
    local integer lvl = GetHeroLevel(c)
    local integer i = 0
    local boolean allskill = true
    loop
        exitwhen i > d.numberskills
        if d.abi<i>.lvlcur &lt; d.abi<i>.lvlmax then
        
            if lvl &lt; (d.abi<i>.lvlreq + (d.abi<i>.lvlcur) * d.abi<i>.lvlskip) then
                call UnitRemoveAbility(d.learner,d.abi<i>.idlearn)
                call UnitAddAbility(d.learner,d.abi<i>.iddisable)
                call SetUnitAbilityLevel(d.learner,d.abi<i>.iddisable,d.abi<i>.lvlcur+1)
            else                
                if d.unspentskillpoint &gt; 0 then
                    call UnitRemoveAbility(d.learner,d.abi<i>.iddisable)
                    call UnitAddAbility(d.learner,d.abi<i>.idlearn)
                    call SetUnitAbilityLevel(d.learner,d.abi<i>.idlearn,d.abi<i>.lvlcur+1)
                else
                    call UnitRemoveAbility(d.learner,d.abi<i>.idlearn)
                    call UnitAddAbility(d.learner,d.abi<i>.iddisable)
                    call SetUnitAbilityLevel(d.learner,d.abi<i>.iddisable,d.abi<i>.lvlnolearn)
                endif
            endif
            set allskill = false
        endif
        set i = i + 1
    endloop

    if allskill then
        call UnitRemoveAbility(d.hero,HEROBUTTON_ABIL)
        if d.heroowner == GetLocalPlayer() then
            call ClearSelection()
            call SelectUnit(d.hero,true)
        endif
    endif
    
endfunction

function HeroRetraining takes unit hero returns nothing
    local data d = data[hero]
    local integer i = 0
    local integer ret = 0 //returned skill points
    loop
        exitwhen i &gt; d.numberskills
        if d.abi<i>.lvlcur &gt; 0 then
            set d.unspentskillpoint = d.unspentskillpoint + d.abi<i>.lvlcur
            set d.totalskillpoint = d.totalskillpoint + d.abi<i>.lvlcur
            set ret = ret + d.abi<i>.lvlcur
            set d.abi<i>.lvlcur = 0
            if d.abi<i>.bookid != 0 then
                call SetPlayerAbilityAvailable(d.heroowner,d.abi<i>.id,false)
                if GetUnitAbilityLevel(d.hero,d.abi<i>.bookid) &gt; 0 then
                    call UnitRemoveAbility(d.hero,d.abi<i>.bookid)
                endif
            else
                call UnitRemoveAbility(d.hero,d.abi<i>.id)
            endif
        endif
        set i = i + 1
    endloop
    
    call DestroyEffect( AddSpecialEffectTarget(&quot;Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl&quot;,d.hero,&quot;origin&quot;))
    call NewTextTagEx( &quot;|c008040FF+&quot;+I2S(ret)+&quot;!|r&quot; , 15, GetUnitX(hero), GetUnitY(hero), 0. , 128, 90, 3., 0.5, true )
    
    call SetItemCharges(d.skillpointshower,d.unspentskillpoint)
    if GetUnitAbilityLevel(d.hero,HEROBUTTON_ABIL) == 0 then
        call UnitAddAbility(d.hero,HEROBUTTON_ABIL)
    endif
    
    call CheckHeroAbilities(hero)
endfunction

function InitHeroAbilities takes unit hero, string skillz returns nothing
    local data d = data.create()
    local integer int = 0
    local integer c1 = 1
    local integer c2 = 0
    local string str
    set d.hero = hero
    set d.heroowner = GetOwningPlayer(hero)
    set d.learner = CreateUnit( d.heroowner, SKILL_LEARNER, 0.,0.,0.)
    call UnitRemoveType(d.learner,UNIT_TYPE_PEON)
    call UnitAddAbility(d.learner, CANCEL_ABIL )
    call UnitAddAbility(d.learner,ONESLOTINVENTORY)
    set d.skillpointshower = CreateItem( SKILLPOINT_SHOWER, 0.,0.)
    call UnitAddItem( d.learner, d.skillpointshower )
    
    set data[d.hero] = d
    set data[d.learner] = d
    
    set d.unspentskillpoint = 1
    call UnitAddAbility(d.hero,HEROBUTTON_ABIL)
    call SetItemCharges(d.skillpointshower,1)
    set d.totalskillpoint = d.totalskillpoint - 1
    
    set int = -1
    loop
        exitwhen c1 &gt; StringLength(skillz) or int &gt; MAXIMUMSKILLPERHERO
        set int = int + 1
        set d.abi[int] = abildata.create()
        set c2 = CountToChar(skillz, &quot;_&quot;,c1)
        set d.abi[int].id = S2I(SubString(skillz,c1-1,c2))
        set c1 = c2+2
        set c2 = CountToChar(skillz, &quot;_&quot;,c1)
        set d.abi[int].idlearn = S2I(SubString(skillz,c1-1,c2))
        set c1 = c2+2
        set c2 = CountToChar(skillz, &quot;_&quot;,c1)
        set d.abi[int].iddisable = S2I(SubString(skillz,c1-1,c2))
        set c1 = c2+2
        set c2 = CountToChar(skillz, &quot;_&quot;,c1)
        set d.abi[int].bookid = S2I(SubString(skillz,c1-1,c2))
        if d.abi[int].bookid != 0 then
            call SetPlayerAbilityAvailable(d.heroowner,d.abi[int].id,false)
        endif
        set c1 = c2+2 
        set c2 = CountToChar(skillz, &quot;;&quot;,c1)
        set str = SubString(skillz,c1-1,c2)
        set c1 = c2+2
        set d.abi[int].lvlmax = S2I(SubString(str,0,1))
        set d.abi[int].lvlreq = S2I(SubString(str,1,3))
        set d.abi[int].lvlskip = S2I(SubString(str,3,4))
        set d.abi[int].lvlnolearn = S2I(SubString(str,4,5)) 
        set d.totalskillpoint = d.totalskillpoint + d.abi[int].lvlmax
    endloop
    set d.numberskills = int
    call CheckHeroAbilities(hero)
endfunction

private function AbilityClicked takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local integer abi = GetSpellAbilityId()
    local integer lvl = GetUnitAbilityLevel(c,abi)
    local data d = data[c]
    local integer i = 0
    if abi == HEROBUTTON_ABIL then
        call PauseUnit(c,true)
        call IssueImmediateOrder(c,&quot;stop&quot;)
        call PauseUnit(c,false)
        call SetUnitX(d.learner,GetUnitX(c))
        call SetUnitY(d.learner,GetUnitY(c))
        set NoCheckSelect = true
        if d.heroowner == GetLocalPlayer() then
            call ClearSelection()
            call SelectUnit(d.learner,true)
        endif
    endif
    if GetUnitName(c) != &quot;Skill Learner&quot; then
        set c = null
        return
    endif
    call PauseUnit(c,true)
    call IssueImmediateOrder(c,&quot;stop&quot;)
    call PauseUnit(c,false)
    
    if abi == CANCEL_ABIL then
        if d.heroowner == GetLocalPlayer() then
            call ClearSelection()
            call SelectUnit(d.hero,true)
        endif
        set c = null
        return
    endif
    loop
        exitwhen i &gt; d.numberskills
        if abi == d.abi<i>.idlearn then
            set d.abi<i>.lvlcur = d.abi<i>.lvlcur + 1
            if d.abi<i>.lvlcur == 1 then
                call DestroyEffect( AddSpecialEffectTarget(&quot;Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl&quot;,d.hero,&quot;origin&quot;))
                if d.abi<i>.bookid != 0 then
                    call SetPlayerAbilityAvailable(d.heroowner,d.abi<i>.id,true)
                    
                    if GetUnitAbilityLevel(d.hero,d.abi<i>.bookid) == 0 then
                        call UnitAddAbility(d.hero,d.abi<i>.bookid)
                    endif
                else
                    call UnitAddAbility(d.hero,d.abi<i>.id)
                endif
            else
                call DestroyEffect( AddSpecialEffectTarget(&quot;Abilities\\Spells\\Items\\AIlm\\AIlmTarget.mdl&quot;,d.hero,&quot;origin&quot;))
            endif
            call SetUnitAbilityLevel(d.hero,d.abi<i>.id,d.abi<i>.lvlcur)
            
            if d.abi<i>.lvlcur == d.abi<i>.lvlmax then
                call UnitRemoveAbility(c,abi)
            endif
            exitwhen true
        endif
        set i = i + 1
    endloop
    
    set d.unspentskillpoint = d.unspentskillpoint - 1
    call SetItemCharges(d.skillpointshower,d.unspentskillpoint)
    
    call CheckHeroAbilities(d.hero)
    
    set c = null
endfunction

private function LevelUp takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local data d = data[c]
    local integer lvl = GetHeroLevel(c)
    local integer i = 0
    local integer sk = (lvl - d.currentlevel) * DEFAULT_SKILLPOINTS
    if d.totalskillpoint &gt; 0 then
    
    if sk &lt;= d.totalskillpoint then
        set d.unspentskillpoint = d.unspentskillpoint + sk
        set d.totalskillpoint = d.totalskillpoint - sk
    else
        set d.unspentskillpoint = d.unspentskillpoint + d.totalskillpoint
        set d.totalskillpoint = 0
    endif
    
    endif
    
    set d.currentlevel = lvl
    
    if d.unspentskillpoint &gt; 0 and GetUnitAbilityLevel(c,HEROBUTTON_ABIL) == 0 then
        call UnitAddAbility(c,HEROBUTTON_ABIL)
    endif
    
    call SetItemCharges(d.skillpointshower,d.unspentskillpoint)
    
    call CheckHeroAbilities(d.hero)
endfunction

private function UseTome takes nothing returns nothing
    local unit c
    local item it = GetManipulatedItem()
    local data d
    local boolean canuse = false
    local integer i = 0
    if GetItemTypeId(it) != RETRAIN_ITEM then
        set it = null
        return
    endif
    set c = GetTriggerUnit()
    set d = data[c]
    
    loop
        exitwhen i &gt; d.numberskills
        if d.abi<i>.lvlcur &gt; 0 then
            set canuse = true
        endif
        set i = i + 1
    endloop
    
    if canuse then
        call HeroRetraining(c)
        
        if GetItemCharges(it) == 0 then
            call UnitRemoveItem(c,it)
            call RemoveItem(it)
        endif
    else
        if (GetLocalPlayer() == d.heroowner) then
            call ClearTextMessages()
            call DisplayTimedTextToPlayer( d.heroowner, 0.52, -1.00, 2.00, &quot;|cffffcc00Only Heroes that have learned spells can use this item.|r&quot; )
        endif
        call SetItemCharges(it,GetItemCharges(it)+1)
    endif
    set c = null
    set it = null
endfunction

private function ESCPressedF takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == SKILL_LEARNER
endfunction

private function ESCPressed takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local unit u
    local data d
    local sound snd
    call SyncSelections()
    call GroupEnumUnitsSelected(ENUMER, p, ESCF)
    set u = FirstOfGroup(ENUMER)
    if u != null then
        set d = data<u>
        set snd = CreateSound(&quot;Sound\\Interface\\MouseClick1.wav&quot;,false,false,false,100,100,&quot;&quot;)
        call SetSoundVolume(snd,0)
        if d.heroowner == GetLocalPlayer() then
            call ClearSelection()
            call SelectUnit(d.hero,true)
            call SetSoundVolume(snd,127)
        endif
        call StartSound(snd)
        call KillSoundWhenDone(snd)
        set snd = null
    endif
    call GroupClear(ENUMER)
    set u = null
endfunction

private function SelectAnUnit takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local data d
    local sound snd
    if GetUnitTypeId(u) != SKILL_LEARNER or NoCheckSelect then
        set NoCheckSelect = false
        set u = null
        return
    endif
    set d = data<u>
    call SetUnitX(u, GetUnitX(d.hero))
    call SetUnitY(u, GetUnitY(d.hero))
    set snd = CreateSound(&quot;Sound\\Interface\\MouseClick1.wav&quot;,false,false,false,100,100,&quot;&quot;)
    call SetSoundVolume(snd,0)
    if d.heroowner == GetLocalPlayer() then
        call SetCameraPosition(GetUnitX(u),GetUnitY(u))
        call SetSoundVolume(snd,127)
    endif
    call StartSound(snd)
    call KillSoundWhenDone(snd)
    set snd = null
    set u = null
endfunction

private function Init takes nothing returns nothing
    local trigger tr = CreateTrigger()
    local trigger tr2 = CreateTrigger()
    local trigger use = CreateTrigger()
    local trigger esc = CreateTrigger()
    local trigger sec = CreateTrigger()
    local integer i = 0
    set ESCF = Condition( function ESCPressedF )
    loop
        call TriggerRegisterPlayerUnitEvent(tr,Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null )
        call TriggerRegisterPlayerUnitEvent(use,Player(i), EVENT_PLAYER_UNIT_USE_ITEM, null )
        call TriggerRegisterPlayerUnitEvent(tr2,Player(i), EVENT_PLAYER_HERO_LEVEL, null )
        call TriggerRegisterPlayerEvent(esc, Player(i), EVENT_PLAYER_END_CINEMATIC)
        call TriggerRegisterPlayerUnitEvent(sec,Player(i), EVENT_PLAYER_UNIT_SELECTED, null )
        set i = i + 1
        exitwhen i == 16
    endloop
    call TriggerAddAction( use, function UseTome )
    call TriggerAddAction( tr, function AbilityClicked )
    call TriggerAddAction( tr2, function LevelUp )
    call TriggerAddAction( esc, function ESCPressed )
    call TriggerAddAction( sec, function SelectAnUnit )
    set tr = null
    set tr2 = null
    set use = null
    set esc = null
endfunction

endlibrary</u></u></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


◊ Credit
- Thanks Cohadar for PUI
- Thanks Andrewgosu for the concept of this system

-----
I will greatly appreciate any helps to improve this system :)

p.s: sorry if there are some "out of nowhere" words :nuts:

EDIT: attach the demo map
 

Attachments

  • [System] Advanced Skill System.w3x
    101.3 KB · Views: 284

Horus

New Member
Reaction score
0
Hello everyone! :)
I need help. When i'm trying to run your map, appears an error with text:

"667 compile errors.
Map test aborted due scripts error.
" :(

(This message can appears when i want to add a unit at the battlefield, or save the map with another name)

WarCraft: TFT 1.24 without any mods

P.S. Please, sorry for my grammar, english isn't my native language :)
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
Hello everyone! :)
I need help. When i'm trying to run your map, appears an error with text:

"667 compile errors.
Map test aborted due scripts error.
" :(

(This message can appears when i want to add a unit at the battlefield, or save the map with another name)

WarCraft: TFT 1.24 without any mods

P.S. Please, sorry for my grammar, english isn't my native language :)

You need newgen.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top