wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Resources > - Submit a resource -
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 07-16-2010, 07:33 AM   #1
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default [script] AbilityEvent

A library that catches when a hero learns or unlearns an ability and allows execution of code whenever such an event happens.

This uses vJass, AutoIndex, Table, TimerUtils, LinkedList, SkillLearnable and optionally SpellEvent.

Collapse Library code:
/**
 *                   ABILITY EVENT
 *                     by Deaod
 *
 * A library that allows execution of code whenever
 * a unit learns, unlearns or changes the level of
 * an ability.
 *
 * NOTES:
 *  Because of the way this library currently works,
 *  I'd like to ask all users of this library to
 *  make sure all calls to SetUnitAbilityLevel
 *  that affect a hero and a learnable ability
 *  contain a valid new level for the ability, even
 *  if its on the second call (ie. its okay to call
 *  SetUnitAbilityLevel more than once to verify
 *  the desired new level).
 *  Such a verification could look like this:
 *
 *  call SetUnitAbilityLevel(whichUnit, whichAbility, SetUnitAbilityLevel(whichUnit, whichAbility, desiredLevel))
 *
 *  The same applies to IncUnitAbilityLevel. Don't
 *  use it under unverified circumstances. Better
 *  yet, don't use it at all, and use
 *  SetUnitAbilityLevel instead.
 *
 *  Should Vexorian decide to include support for
 *  calling a function hooked in one of its hooks,
 *  the need for verification on the users end
 *  becomes unnecessary (after an update to this
 *  library of course).
 *
 *  This library makes heavy use of Tables. You
 *  might want to increase MAX_INSTANCES in Table.
 *  This does not affect read or write speed for
 *  Tables.
 *
 * KNOWN PROBLEMS:
 *  This library is probably the longest library I
 *  have ever written. It's goal is to detect any
 *  and all possibilities through which a unit
 *  could learn an ability. Sadly, there are so
 *  many ways that detecting all of them would be
 *  too complex and/or too slow.
 *  This library does not detect usage of Chaos
 *  based abilities.
 *  It also does not detect learning an ability
 *  through the fulfillment of tech dependencies.
 *  It fails to detect a unit morphing into a unit
 *  of the same type (TypeId, eg. 'h000').
 *
 * CREDITS:
 *  - Ammorth (LinkedList)
 *  - Anitarf (SpellEvent)
 *  - grim001 (AutoIndex)
 *  - Vexorian (Table, JassHelper)
 *  - MindWorX (JassNewGenPack)
 *  - PitzerMike (JassNewGenPack)
 *  - PipeDream (Grimoire)
 *  - SFilip (TESH)
 *
 * Learning API:
 *
 *  function interface LearnCallback takes unit learningUnit, integer learnedAbility returns nothing
 *  Parameters:
 *      learningUnit - the unit which learned learnedAbility
 *      learnedAbility - the ability learningUnit learned
 *
 *  function OnAbilityLearn takes integer abilityID, LearnCallback callback returns nothing
 *  Parameters:
 *      abilityID - whenever abilityID is learned by a unit, callback is executed
 *      callback - function executed whenever a unit learns abilityID
 * 
 * 
 * Unlearning API:
 *
 *  function interface UnlearnCallback takes unit unlearningUnit, integer unlearnedAbility returns nothing
 *  Parameters:
 *      unlearningUnit - the unit which unlearned unlearnedAbility
 *      unlearnedAbility - the ability unlearningUnit unlearned
 *
 *  function OnAbilityUnlearn takes integer abilityID, UnlearnCallback callback returns nothing
 *  Parameters:
 *      abilityID - whenever abilityID is unlearned by a unit, callback is executed
 *      callback - function executed whenever a unit unlearns abilityID
 *
 *
 * Level Change API:
 * 
 *  function interface LevelChangeCallback takes unit levelingUnit, integer leveledAbility, integer newLevel returns nothing
 *  Parameters:
 *      levelingUnit - the unit that changed its ability level
 *      leveledAbility - the ability that changed its level
 *      newLevel - the new level of the ability
 * 
 *  function OnAbilityLevelChange takes integer abilityID, LevelChangeCallback callback returns nothing
 *  Parameters:
 *      abilityID - whenever a unit changes the level of this ability, callback is executed
 *      callback - function executed whenever a unit changes the level of abilityID
 *
 */
library AbilityEvent requires AutoIndex, Table, TimerUtils, LinkedList, SkillLearnable, optional SpellEvent
    
    // CONFIGURATION CONSTANTS
    // It's okay, go ahead and modify those.
    globals
        private constant    integer             MAXIMUM_HERO_ABILITIES          = 5
        // valid values range from 1 to 5, more than that is impossible in the current version of WC3 (hardcoded limit)
        // only decrease when you are absolutely sure no hero will have more than this many abilities he can learn.
        
        private constant    integer             RETRAINING_ABILITY              = 'Aret'
        // As custom abilities based off of 'Aret' wont work, you should never change this.
    endglobals
    
    // Don't touch anything blow.
    
    function interface LearnCallback takes unit learningUnit, integer abilityLearned returns nothing
    function interface UnlearnCallback takes unit unlearningUnit, integer abilityUnlearned returns nothing
    function interface LevelChangeCallback takes unit levelingUnit, integer abilityLeveled, integer newLevel returns nothing
    
    globals
        private Table AbilityLearnEvents
        private Table AbilityUnlearnEvents
        private Table AbilityLevelChangeEvents
        
        private integer array Ability
        private integer AbilityCount=0
        private Table AbilityTable
        
        private rect WorldBounds
        private group InitGroup
        
        private integer TempAbilityID
        private LearnCallback TempLearnCallback
        private LevelChangeCallback TempLevelChangeCallback
    endglobals
    
    private function AddAbilityToStack takes integer abilityID returns nothing
        if not AbilityTable.exists(abilityID) then
            set Ability[AbilityCount]=abilityID
            set AbilityTable[abilityID]=AbilityCount
            set AbilityCount=AbilityCount+1
        endif
    endfunction
    
    // struct for all heroes
    // only detects hero abilities
    private struct Hero
        integer array ability[MAXIMUM_HERO_ABILITIES]
        integer array abilityLevel[MAXIMUM_HERO_ABILITIES]
        integer abilityCount=0
        Table abilityTable
        
        private boolean selectedSkill=false
        private integer selectedSkillId
        
        private static method createFilter takes unit u returns boolean
            return IsUnitType(u, UNIT_TYPE_HERO) and not IsCheckingHeroSkill()
        endmethod
        
        private method onCreate takes nothing returns nothing
        local integer i
            set abilityTable=Table.create()
            set i=0
            loop
                exitwhen i>=AbilityCount
                if HeroCanLearnSkill(me, Ability[i]) and GetUnitAbilityLevel(me, Ability[i])>0 then
                    call learnAbility(Ability[i], 1)
                    call learnAbility(Ability[i], GetUnitAbilityLevel(me, Ability[i]))
                endif
                set i=i+1
            endloop
        endmethod
        
        private method onDestroy takes nothing returns nothing
        local integer i
            set i=abilityCount-1
            loop
                exitwhen i<0
                call unlearnAbility(ability[i])
                set i=i-1
            endloop
            call abilityTable.destroy()
        endmethod
        
        method learnAbility takes integer abilityID, integer newLevel returns nothing
        local List list
        local Link link
            if not hasLearned(abilityID) then
                set ability[abilityCount]=abilityID
                set abilityLevel[abilityTable[abilityID]]=newLevel
                set abilityTable[abilityID]=abilityCount
                set abilityCount=abilityCount+1
                // fire learn events
                set list=List(AbilityLearnEvents[abilityID])
                if list>0 then
                    set link=list.first
                    loop
                        exitwhen link==0
                        call LearnCallback(link.data).evaluate(me, abilityID)
                        set link=link.next
                    endloop
                endif
            elseif abilityLevel[abilityTable[abilityID]]!=newLevel then
                set abilityLevel[abilityTable[abilityID]]=newLevel
                // fire level change events
                set list=List(AbilityLevelChangeEvents[abilityID])
                if list>0 then
                    set link=list.first
                    loop
                        exitwhen link==0
                        call LevelChangeCallback(link.data).evaluate(me, abilityID, newLevel)
                        set link=link.next
                    endloop
                endif
            endif
        endmethod
        
        method unlearnAbility takes integer abilityID returns nothing
        local integer index=abilityTable[abilityID]
        local List list
        local Link link
            // fire unlearn events
            set list=List(AbilityUnlearnEvents[abilityID])
            if list>0 then
                set link=list.first
                loop
                    exitwhen link==0
                    call UnlearnCallback(link.data).evaluate(me, abilityID)
                    set link=link.next
                endloop
            endif
            set abilityCount=abilityCount-1
            set ability[index]=ability[abilityCount]
            set abilityLevel[index]=abilityLevel[abilityCount]
            set abilityLevel[abilityCount]=0
            call abilityTable.flush(abilityID)
        endmethod
        
        method hasLearned takes integer abilityID returns boolean
            return abilityTable.exists(abilityID)
        endmethod
        
        private static method OnLearnAbility takes nothing returns nothing
        local thistype s=thistype[GetTriggerUnit()]
            call s.learnAbility(GetLearnedSkill(), GetLearnedSkillLevel())
        endmethod
        
        private static method AfterSelectSkill takes nothing returns nothing
        local thistype s=thistype(GetTimerData(GetExpiredTimer()))
            if s.selectedSkill==false then
                // request succeeded
            else
                // request failed
                set s.selectedSkill=false
            endif
            call ReleaseTimer(GetExpiredTimer())
        endmethod
        
        private static method OnSelectSkill takes unit u, integer abilityID returns nothing
        local thistype s
        local timer t
            if HeroCanLearnSkill(u, abilityID) then
                set s=thistype[u]
                set s.selectedSkill=true
                set s.selectedSkillId=abilityID
                set t=NewTimer()
                call SetTimerData(t, s)
                call TimerStart(t, 0, false, function thistype.AfterSelectSkill)
            endif
        endmethod
        
        private static method OnSpellEffect takes nothing returns nothing
        local unit u
        local integer abilityId
        local thistype s
        local integer i
            static if LIBRARY_SpellEvent then
                set u=SpellEvent.CastingUnit
                set abilityId=SpellEvent.AbilityId
            else
                set u=GetTriggerUnit()
                set abilityId=GetSpellAbilityId()
            endif
            if abilityId==RETRAINING_ABILITY then
                set s=thistype[u]
                // no need to check s, only heroes with learned abilities can cast this ability,
                // and thats a subset of all units this struct has an instance for
                set i=s.abilityCount-1
                loop
                    exitwhen i<0
                    call s.unlearnAbility(s.ability[i])
                    set i=i-1
                endloop
                set u=null
            elseif abilityId==0 then
                set s=thistype[u]
                if s.selectedSkill and GetUnitAbilityLevel(u, s.selectedSkillId)-1==s.abilityLevel[s.abilityTable[s.selectedSkillId]] then
                    // SelectHeroSkill was used, most certainly
                    set s.selectedSkill=false
                    call s.learnAbility(s.selectedSkillId, GetUnitAbilityLevel(u, s.selectedSkillId))
                else
                    // cant tell for sure, but most probably the unit learned a skill over the menu, which has its separate event
                endif
            endif
            set u=null
        endmethod
        
        private static method onInit takes nothing returns nothing
        local trigger t
            
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
            call TriggerAddAction(t, function thistype.OnLearnAbility)
            
            static if LIBRARY_SpellEvent then
                call RegisterSpellEffectResponse(0, thistype.OnSpellEffect)
            else
                set t=CreateTrigger()
                call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
                call TriggerAddAction(t, function thistype.OnSpellEffect)
            endif
            
            set AbilityLearnEvents=Table.create()
            set AbilityUnlearnEvents=Table.create()
            set AbilityLevelChangeEvents=Table.create()
            
            set AbilityTable=Table.create()
            
            set WorldBounds=GetWorldBounds()
            static if LIBRARY_GroupUtils then
                set InitGroup=ENUM_GROUP
            else
                set InitGroup=CreateGroup()
            endif
        endmethod
        
        implement AutoCreate
        implement AutoDestroy
    endstruct
    
    // hero specifc hook.
    hook SelectHeroSkill Hero.OnSelectSkill
    
    // struct for all units
    // detects all unit abilities
    private struct Unit
        Table ability
        Table abilityLevel
        integer abilityCount=0
        Table abilityTable
        
        private static method createFilter takes unit u returns boolean
            return not IsCheckingHeroSkill()
        endmethod
        
        private method onCreate takes nothing returns nothing
        local integer i
            set ability=Table.create()
            set abilityLevel=Table.create()
            set abilityTable=Table.create()
            // which abilities does the unit have
            set i=0
            loop
                exitwhen i>=AbilityCount
                if not HeroCanLearnSkill(me, Ability[i]) and GetUnitAbilityLevel(me, Ability[i])>0 then
                    call learnAbility(Ability[i], 1)
                    call learnAbility(Ability[i], GetUnitAbilityLevel(me, Ability[i]))
                endif
                set i=i+1
            endloop
        endmethod
        
        private method onDestroy takes nothing returns nothing
        local integer i
            set i=abilityCount-1
            loop
                exitwhen i<0
                call unlearnAbility(ability[i])
                set i=i-1
            endloop
            call ability.destroy()
            call abilityLevel.destroy()
            call abilityTable.destroy()
        endmethod
        
        method learnAbility takes integer abilityID, integer newLevel returns nothing
        local List list
        local Link link
            if not hasLearned(abilityID) then
                set ability[abilityCount]=abilityID
                set abilityLevel[abilityTable[abilityID]]=newLevel
                set abilityTable[abilityID]=abilityCount
                set abilityCount=abilityCount+1
                // fire learn events
                set list=List(AbilityLearnEvents[abilityID])
                if list>0 then
                    set link=list.first
                    loop
                        exitwhen link==0
                        call LearnCallback(link.data).evaluate(me, abilityID)
                        set link=link.next
                    endloop
                endif
            elseif abilityLevel[abilityTable[abilityID]]!=newLevel then
                set abilityLevel[abilityTable[abilityID]]=newLevel
                // fire level change events
                set list=List(AbilityLevelChangeEvents[abilityID])
                if list>0 then
                    set link=list.first
                    loop
                        exitwhen link==0
                        call LevelChangeCallback(link.data).evaluate(me, abilityID, newLevel)
                        set link=link.next
                    endloop
                endif
            endif
        endmethod
        
        method unlearnAbility takes integer abilityID returns nothing
        local integer index=abilityTable[abilityID]
        local List list
        local Link link
            // fire unlearn events
            set list=List(AbilityUnlearnEvents[abilityID])
            if list>0 then
                set link=list.first
                loop
                    exitwhen link==0
                    call UnlearnCallback(link.data).evaluate(me, abilityID)
                    set link=link.next
                endloop
            endif
            set abilityCount=abilityCount-1
            set ability[index]=ability[abilityCount]
            set abilityLevel[index]=abilityLevel[abilityCount]
            set abilityLevel[abilityCount]=0
            call abilityTable.flush(abilityID)
        endmethod
        
        method hasLearned takes integer abilityID returns boolean
            return abilityTable.exists(abilityID)
        endmethod
        
        implement AutoCreate
        implement AutoDestroy
    endstruct
    
    // hook responses
    
    private function OnAddAbility takes unit u, integer abilityID returns nothing
        if not IsCheckingHeroSkill() and GetUnitAbilityLevel(u, abilityID)<=0 then
            if HeroCanLearnSkill(u, abilityID) then
                call Hero[u].learnAbility(abilityID, 1)
            else
                call Unit[u].learnAbility(abilityID, 1)
            endif
        endif
    endfunction
    
    private function OnSetAbilityLevel takes unit u, integer abilityID, integer newLevel returns nothing
        if newLevel>0 and GetUnitAbilityLevel(u, abilityID)>0 then
            if HeroCanLearnSkill(u, abilityID) then
                call Hero[u].learnAbility(abilityID, newLevel)
            else
                call Unit[u].learnAbility(abilityID, newLevel)
            endif
        endif
    endfunction
    
    private function OnRemoveAbility takes unit u, integer abilityID returns nothing
        if not IsCheckingHeroSkill() and GetUnitAbilityLevel(u, abilityID)>0 then
            if HeroCanLearnSkill(u, abilityID) then
                call Hero[u].unlearnAbility(abilityID)
            else
                call Unit[u].unlearnAbility(abilityID)
            endif
        endif
    endfunction
    
    private function OnIncAbilityLevel takes unit u, integer abilityID returns nothing
        if GetUnitAbilityLevel(u, abilityID)>0 then
            if HeroCanLearnSkill(u, abilityID) then
                call Hero[u].learnAbility(abilityID, GetUnitAbilityLevel(u, abilityID)+1)
            else
                call Unit[u].learnAbility(abilityID, GetUnitAbilityLevel(u, abilityID)+1)
            endif
        endif
    endfunction
    
    private function OnDecAbilityLevel takes unit u, integer abilityID returns nothing
        if GetUnitAbilityLevel(u, abilityID)>1 then
            if HeroCanLearnSkill(u, abilityID) then
                call Hero[u].learnAbility(abilityID, GetUnitAbilityLevel(u, abilityID)-1)
            else
                call Unit[u].learnAbility(abilityID, GetUnitAbilityLevel(u, abilityID)-1)
            endif
        endif
    endfunction
    
    // fuck BJs
    private function OnAddAbilityBJ takes integer abilityID, unit u returns nothing
        call OnAddAbility(u, abilityID)
    endfunction
    private function OnSetAbilityLevelBJ takes integer abilityID, unit u, integer newLevel returns nothing
        call OnSetAbilityLevel(u, abilityID, newLevel)
    endfunction
    private function OnRemoveAbilityBJ takes integer abilityID, unit u returns nothing
        call OnRemoveAbility(u, abilityID)
    endfunction
    private function OnIncAbilityLevelBJ takes integer abilityID, unit u returns nothing
        call OnIncAbilityLevel(u, abilityID)
    endfunction
    private function OnDecAbilityLevelBJ takes integer abilityID, unit u returns nothing
        call OnDecAbilityLevel(u, abilityID)
    endfunction
    
    // register relevant hooks
    
    hook UnitAddAbility             OnAddAbility
    hook SetUnitAbilityLevel        OnSetAbilityLevel
    hook UnitRemoveAbility          OnRemoveAbility
    hook IncUnitAbilityLevel        OnIncAbilityLevel
    hook DecUnitAbilityLevel        OnDecAbilityLevel
    hook UnitAddAbilityBJ           OnAddAbilityBJ
    hook SetUnitAbilityLevelSwapped OnSetAbilityLevelBJ
    hook UnitRemoveAbilityBJ        OnRemoveAbilityBJ
    hook UnitRemoveBuffBJ           OnRemoveAbilityBJ
    hook IncUnitAbilityLevelSwapped OnIncAbilityLevelBJ
    hook DecUnitAbilityLevelSwapped OnDecAbilityLevelBJ
    
    // Morph events
    
    globals
        private integer array UnitType
    endglobals
    
    private function MorphSpellCast takes nothing returns nothing
    local unit u
    local integer id
        static if LIBRARY_SpellEvent then
            set u=SpellEvent.CastingUnit
        else
            set u=GetTriggerUnit()
        endif
        set id=GetUnitId(u)
        set UnitType[id]=GetUnitTypeId(u)
        set u=null
    endfunction
    
    private function MorphSpellEndCast takes nothing returns nothing
    local unit u
    local integer id
    local integer i
    local Unit U
    local Hero h
        static if LIBRARY_SpellEvent then
            set u=SpellEvent.CastingUnit
        else
            set u=GetTriggerUnit()
        endif
        set id=GetUnitId(u)
        if UnitType[id]!=GetUnitTypeId(GetTriggerUnit()) then
            // morph event
            // currently disregards units morphing into themselves, feel free to contribute your thoughts on how to detect that with as little user interaction as possible.
            // which abilities did the unit lose
            set U=Unit[u]
            set i=0
            loop
                exitwhen i>=U.abilityCount
                if GetUnitAbilityLevel(u, U.ability[i])<=0 then
                    call U.unlearnAbility(U.ability[i])
                endif
                set i=i+1
            endloop
            set h=Hero[u]
            set i=0
            loop
                exitwhen i>=h.abilityCount
                if GetUnitAbilityLevel(u, h.ability[i])<=0 then
                    call h.unlearnAbility(h.ability[i])
                endif
                set i=i+1
            endloop
            // which abilities did the unit gain
            set i=0
            loop
                exitwhen i>=AbilityCount
                if GetUnitAbilityLevel(u, Ability[i])>0 then
                    if HeroCanLearnSkill(u, Ability[i]) then
                        if not h.hasLearned(Ability[i]) then
                            call h.learnAbility(Ability[i], 1)
                        endif
                        call h.learnAbility(Ability[i], GetUnitAbilityLevel(u, Ability[i]))
                    else
                        if not U.hasLearned(Ability[i]) then
                            call U.learnAbility(Ability[i], 1)
                        endif
                        call U.learnAbility(Ability[i], GetUnitAbilityLevel(u, Ability[i]))
                    endif
                endif
                set i=i+1
            endloop
        endif
    endfunction
    
    private function UpgradeFinish takes nothing returns nothing
    local unit u=GetTriggerUnit()
    local integer i
    local Unit U
    local Hero h
        // which abilities did the unit lose
        set U=Unit[u]
        set i=0
        loop
            exitwhen i>=U.abilityCount
            if GetUnitAbilityLevel(u, U.ability[i])<=0 then
                call U.unlearnAbility(U.ability[i])
            endif
            set i=i+1
        endloop
        set h=Hero[u]
        set i=0
        loop
            exitwhen i>=h.abilityCount
            if GetUnitAbilityLevel(u, h.ability[i])<=0 then
                call h.unlearnAbility(h.ability[i])
            endif
            set i=i+1
        endloop
        // which abilities did the unit gain
        set i=0
        loop
            exitwhen i>=AbilityCount
            if GetUnitAbilityLevel(u, Ability[i])>0 then
                if HeroCanLearnSkill(u, Ability[i]) then
                    if not h.hasLearned(Ability[i]) then
                        call h.learnAbility(Ability[i], 1)
                    endif
                    call h.learnAbility(Ability[i], GetUnitAbilityLevel(u, Ability[i]))
                else
                    if not U.hasLearned(Ability[i]) then
                        call U.learnAbility(Ability[i], 1)
                    endif
                    call U.learnAbility(Ability[i], GetUnitAbilityLevel(u, Ability[i]))
                endif
            endif
            set i=i+1
        endloop
    endfunction
    
    private function Init takes nothing returns nothing
    local trigger t
        static if LIBRARY_SpellEvent then
            call RegisterSpellCastResponse(0, MorphSpellCast)
            call RegisterSpellEndCastResponse(0, MorphSpellEndCast)
        else
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
            call TriggerAddAction(t, function MorphSpellCast)
            
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
            call TriggerAddAction(t, function MorphSpellEndCast)
        endif
        set t=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_UPGRADE_FINISH)
        call TriggerAddAction(t, function UpgradeFinish)
    endfunction
    
    // Learn Event registration
    
    private function AbilityLearnEventAddedEnum takes nothing returns boolean
    local unit u=GetFilterUnit()
    local Hero h
    local Unit U
        if GetUnitAbilityLevel(u, TempAbilityID)>0 then
            if HeroCanLearnSkill(u, TempAbilityID) then
                set h=Hero[u]
                if h.hasLearned(TempAbilityID) then
                    call TempLearnCallback.evaluate(u, TempAbilityID) // fire learn event directly
                else
                    call h.learnAbility(TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID)) // fire learn event indirectly
                endif
            else
                set U=Unit[u]
                if U.hasLearned(TempAbilityID) then
                    call TempLearnCallback.evaluate(u, TempAbilityID)
                else
                    call U.learnAbility(TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID))
                endif
            endif
        endif
        set u=null
        return false
    endfunction
    
    function OnAbilityLearn takes integer abilityID, LearnCallback callback returns nothing
    local List list=List(AbilityLearnEvents[abilityID])
        if list<=0 then
            set list=List.create()
            call Link.create(list, callback)
            set AbilityLearnEvents[abilityID]=list
        else
            call Link.createLast(list, callback)
        endif
        call AddAbilityToStack(abilityID)
        set TempAbilityID=abilityID
        set TempLearnCallback=callback
        call GroupEnumUnitsInRect(InitGroup, WorldBounds, function AbilityLearnEventAddedEnum)
    endfunction
    
    // Unlearn Event registration
    
    function OnAbilityUnlearn takes integer abilityID, UnlearnCallback callback returns nothing
    local List list=List(AbilityUnlearnEvents[abilityID])
        if list<=0 then
            set list=List.create()
            call Link.create(list, callback)
            set AbilityUnlearnEvents[abilityID]=list
        else
            call Link.createLast(list, callback)
        endif
        call AddAbilityToStack(abilityID)
    endfunction
    
    // Level Change Event registration
    
    private function AbilityLevelChangeEventAddedEnum takes nothing returns boolean
    local unit u=GetFilterUnit()
    local Hero h
    local Unit U
        if GetUnitAbilityLevel(u, TempAbilityID)>0 then
            if HeroCanLearnSkill(u, TempAbilityID) then
                set h=Hero[u]
                if h.hasLearned(TempAbilityID) then
                    call TempLevelChangeCallback.evaluate(u, TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID)) // fire level change event directly
                else
                    call h.learnAbility(TempAbilityID, 1)
                    call h.learnAbility(TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID)) // fire level change event indirectly
                endif
            else
                set U=Unit[u]
                if U.hasLearned(TempAbilityID) then
                    call TempLevelChangeCallback.evaluate(u, TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID))
                else
                    call U.learnAbility(TempAbilityID, 1)
                    call U.learnAbility(TempAbilityID, GetUnitAbilityLevel(u, TempAbilityID))
                endif
            endif
        endif
        set u=null
        return false
    endfunction
    
    function OnAbilityLevelChange takes integer abilityID, LevelChangeCallback callback returns nothing
    local List list=List(AbilityLevelChangeEvents[abilityID])
        if list<=0 then
            set list=List.create()
            call Link.create(list, callback)
            set AbilityLevelChangeEvents[abilityID]=list
        else
            call Link.createLast(list, callback)
        endif
        call AddAbilityToStack(abilityID)
        set TempAbilityID=abilityID
        set TempLevelChangeCallback=callback
        call GroupEnumUnitsInRect(InitGroup, WorldBounds, function AbilityLevelChangeEventAddedEnum)
    endfunction
    
endlibrary

There is also a wrapper module made specifically for spells.
Expand Module code:
__________________

Last edited by Deaod : 08-08-2010 at 04:50 PM. Reason: Huge Update
Deaod is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 07-16-2010, 08:22 PM   #2
DioD
obey
 
DioD's Avatar
 
Join Date: Feb 2006
Posts: 1,532

Submissions (4)

DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)

Send a message via ICQ to DioD
Default

dont understand what problem with

blabla = GetUnitAbilityLevel()
RemoveAbility
AddSkillPoints (blabla)

???
DioD is offline   Reply With Quote
Old 07-17-2010, 08:56 AM   #3
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

This wasnt meant to replace (un)learning an ability. It was meant to detect when a hero (un)learns a specific ability. This could be used by passive abilities.
__________________
Deaod is offline   Reply With Quote
Old 07-17-2010, 09:39 AM   #4
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

It would be sufficient for passive abilities to just check for when a hero uses an item of the retraining type, which is an incredibly simple check since most maps will only have one item of such type. A few dozen lines of code total. Instead, you have over a hundred lines of code with 5 library requirements to accomplish the same task. This just seems like overkill.
__________________

Last edited by Anitarf : 07-17-2010 at 09:42 AM.
Anitarf is offline   Reply With Quote
Old 07-17-2010, 11:04 AM   #5
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Well, in order to accurately tell which abilities a hero unlearned when he used Aret, youd have to know which abilities he has learned. Also, a hero can learn an ability via script just as well as via the menu (you can use SelectHeroSkill and UnitAddAbiliy). The difference is, that only learning an ability over the menu will trigger the event EVENT_PLAYER_HERO_SKILL (or EVENT_UNIT_HERO_SKILL).

SelectHeroSkill will trigger a spell event, with triggering unit being the unit that was passed to SelectHeroSkill. GetSpellAbilityId() will return 0. Such a spell event will also be triggered by manually selecting a skill over the menu. I dont know what else could also be triggering such an event, so i rely on checking if the level increased by one. That in turn requires keeping track of an ability's level.

I just noticed a bug with SetUnitAbilityLevel or DecUnitAbilityLevel. Will fix it ASAP.
__________________
Deaod is offline   Reply With Quote
Old 07-17-2010, 11:21 AM   #6
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Deaod
Well, in order to accurately tell which abilities a hero unlearned when he used Aret, youd have to know which abilities he has learned. Also, a hero can learn an ability via script just as well as via the menu (you can use SelectHeroSkill and UnitAddAbiliy). The difference is, that only learning an ability over the menu will trigger the event EVENT_PLAYER_HERO_SKILL (or EVENT_UNIT_HERO_SKILL).
My point is, getting a hero skill in a way other than the player selecting it in the skill menu is a map-specific exception that shouldn't have to be accommodated by every public resource out there, but should be handled by the map author instead.

Let's say I want to make a triggered passive ability. All I really need to check is the learn event and the item use event. In a large majority of maps, that will be enough. Even in maps where it isn't, it would be a lot less work for the author of that map to tweak my code to work there than it would be for everyone else using this triggered skill to import all these libraries into their map.
__________________

Last edited by Anitarf : 07-17-2010 at 11:24 AM.
Anitarf is offline   Reply With Quote
Old 07-19-2010, 08:31 AM   #7
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Alright, updated.

Now detects all "unit learns specifc ability" events. Other events have been removed.
Now detects "unit changes level of specifc ability" events.
Actually works.
__________________
Deaod is offline   Reply With Quote
Old 08-08-2010, 04:52 PM   #8
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Another update.

Could some moderator please change the actual thread title?
__________________
Deaod is offline   Reply With Quote
Old 01-15-2011, 02:52 PM   #9
Bribe
User
 
Bribe's Avatar
 
Join Date: Mar 2010
Posts: 233

Submissions (1)

Bribe will become famous soon enough (30)Bribe will become famous soon enough (30)

Send a message via AIM to Bribe
Default

call TimerStart(NewTimer(), 0, false, function thistype.onInitCallback) // fuck module initializers

NewTimer() returns null from struct/module initializers because TimerUtils initializes through a library. Your futile attempt to bypass has failed :P
Bribe is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 06:48 PM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2020, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services