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
- Fake ability for learning:
- 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 ?)
◊ Step 3 - Register your hero's skills into the system
here is the register function:
- 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:
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:
that's the string skillz for ONE skill.
---
So, to register StormBolt to hero:
JASS:
---
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:
◊ 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 = 039;skle039;
//raw id of the skill learner dummy
private constant integer HEROBUTTON_ABIL = 039;Ahsk039;
//raw id of the Hero Skill dialog ability
private constant integer ONESLOTINVENTORY = 039;Aosi039;
//raw id of the 'one slot inventory' ability for dummy
private constant integer SKILLPOINT_SHOWER = 039;hsbt039;
//raw id of the item that show the un-spent skill points
private constant integer RETRAIN_ITEM = 039;trtn039;
//raw id of the 'Tome of Retraining' item
private constant integer CANCEL_ABIL = 039;Aesc039;
//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 < d.abi<i>.lvlmax then
if lvl < (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 > 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 > d.numberskills
if d.abi<i>.lvlcur > 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) > 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("Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl",d.hero,"origin"))
call NewTextTagEx( "|c008040FF+"+I2S(ret)+"!|r" , 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 > StringLength(skillz) or int > MAXIMUMSKILLPERHERO
set int = int + 1
set d.abi[int] = abildata.create()
set c2 = CountToChar(skillz, "_",c1)
set d.abi[int].id = S2I(SubString(skillz,c1-1,c2))
set c1 = c2+2
set c2 = CountToChar(skillz, "_",c1)
set d.abi[int].idlearn = S2I(SubString(skillz,c1-1,c2))
set c1 = c2+2
set c2 = CountToChar(skillz, "_",c1)
set d.abi[int].iddisable = S2I(SubString(skillz,c1-1,c2))
set c1 = c2+2
set c2 = CountToChar(skillz, "_",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, ";",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,"stop")
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) != "Skill Learner" then
set c = null
return
endif
call PauseUnit(c,true)
call IssueImmediateOrder(c,"stop")
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 > 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("Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl",d.hero,"origin"))
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("Abilities\\Spells\\Items\\AIlm\\AIlmTarget.mdl",d.hero,"origin"))
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 > 0 then
if sk <= 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 > 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 > d.numberskills
if d.abi<i>.lvlcur > 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, "|cffffcc00Only Heroes that have learned spells can use this item.|r" )
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("Sound\\Interface\\MouseClick1.wav",false,false,false,100,100,"")
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("Sound\\Interface\\MouseClick1.wav",false,false,false,100,100,"")
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