Cooldown system issues

Nexor

...
Reaction score
74
I've made with some help a cooldown system and I want the Heroes to decrease the cooldown by every cast to a minimum time of cooldown. the only issue is that it decreases everytime with 1 no matter what values I write there.
I tried to decrease it with 0.001 or set the value to value*0.99 but again, decreases with 1 and the function runs twice :S it's really strange.
Here's what I got:

JASS:
library LearnAbilities initializer InitTrig_Cooldown_set_and_fire uses CDSys
globals
    private constant integer HASH = 8192
    private real array ABIL
    real array abil
    private integer array INDEX
    integer array index
endglobals

private struct abil
    static method operator []= takes integer id, real value returns nothing
        set ABIL[id-(id/HASH)*HASH] = R2I(value)   // This was the issue should be value instead of R2I(value)
    endmethod
    static method operator[] takes integer id returns real
        return ABIL[id-(id/HASH)*HASH]
    endmethod
endstruct

private struct index
    static method operator []= takes integer id, integer value returns nothing
        set INDEX[id-(id/HASH)*HASH] = value
    endmethod
    static method operator[] takes integer id returns integer
        return INDEX[id-(id/HASH)*HASH]
    endmethod
endstruct


function Trig_Learn_ability_Actions takes nothing returns nothing
    local integer abi = GetLearnedSkill()
    local integer i = index[abi]
    local real abil_id = abil<i>
    local integer fake = &#039;A003&#039;
    
    if abil_id != 0 then
        debug call BJDebugMsg(&quot;Ability Id: &quot;+I2S(abi))
        debug call BJDebugMsg(&quot;Index: &quot;+I2S(i))
        debug call BJDebugMsg(&quot;Cooldown: &quot;+R2S(abil_id))
        if i == 1 then
            set fake = &#039;A003&#039;
        elseif i == 2 then
            set fake = &#039;A000&#039;
        elseif i == 3 then
            set fake = &#039;A001&#039;
        elseif i == 4 then
            set fake = &#039;A002&#039;
        endif
        call UnitAddCooldown(HERO, i, abi,fake,abil_id)
    endif
endfunction

function Trig_Cooldown_Add_Actions takes nothing returns nothing
    local integer abi = GetSpellAbilityId()
    local integer i = index[abi]
    local real abil_id = abil<i>
    call RunCooldown( GetTriggerUnit(), abi)
    call Cooldown(GetTriggerUnit(), i, abil_id)
    
    call BJDebugMsg(&quot;Old CD: &quot;+R2S(abil[index[abi]]))
    set abil[index[abi]] = abil[index[abi]] * 0.9999
    call BJDebugMsg(&quot;New CD: &quot;+R2S(abil[index[abi]]))
    
    call TriggerSleepAction( 0.20 )
    call SetUnitManaPercentBJ( GetTriggerUnit(), 100 )
endfunction

//===========================================================================
//===========================================================================
function InitTrig_Cooldown_set_and_fire takes nothing returns nothing
    local trigger t1 = CreateTrigger(  )
    local trigger t2 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_HERO_SKILL )
    call TriggerAddAction( t1, function Trig_Learn_ability_Actions )
    call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t2, function Trig_Cooldown_Add_Actions )
    set t1 = null
    set t2 = null
    
    set index[&#039;AHtb&#039;] = 1
    set abil[index[&#039;AHtb&#039;]] = 5.
    set index[&#039;AHtc&#039;] = 2
    set abil[index[&#039;AHtc&#039;]] = 10.
    set index[&#039;AHav&#039;] = 3
    set abil[index[&#039;AHav&#039;]] = 15.
    
endfunction
endlibrary</i></i>



Okay I solved the issue with the 1 thing, but the function still runs twice and I don't know why :S:S
 

Viikuna

No Marlo no game.
Reaction score
265
Post the whole code pls, so we can see what UnitAddCooldow does.

EDIT. Actually, i KNOW THE REASON.

lols caps. Your initializer function has InitTrig prefix, so it might be that its called twice. Once by Blizzards InitTrig thingies, and once by JassHelpers code initializer thingy, which exists so we wouldnt have to type that InitTrig alla time.

Add one BJDebugMsg to your initializer.
 

Nexor

...
Reaction score
74
okay, here's what I got so far, it's a very long code :S

JASS:
library CDSys initializer Cooldown_set_and_fire requires PUI, ABC

    globals
        constant integer MAX_ABILITY = 6
        constant real SCROLL_CD = 5
        private constant string Effect       = &quot;Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl&quot;
        private constant string Attach       = &quot;origin&quot;
        private constant boolean Text_Bool   = true   //Display text when cooldown is ready
        private string CD_Text               = &quot;|r is ready to use!&quot; // Text after cooldown runs (local player)
        private constant real NewCooldownMod = 0.02
    endglobals
    
    private struct CD
        private static integer pui_unit
        private static thistype pui_data
        private static integer i
        unit u
        timer array t [MAX_ABILITY]
        integer array abil [MAX_ABILITY]
        integer array abil2 [MAX_ABILITY]
        integer array lv [MAX_ABILITY]
        real array dur [MAX_ABILITY]
        boolean array t_ready [MAX_ABILITY]
        integer array numberofuses [MAX_ABILITY]
        
        static method operator [] takes unit whichunit returns thistype
            set thistype.pui_data = thistype(GetUnitIndex(whichunit))
            if thistype.pui_data.u != whichunit then
                if thistype.pui_data.u != null then
                    set thistype.i = 1
                    loop
                    exitwhen thistype.i &gt; MAX_ABILITY
                        set thistype.pui_data.abil[thistype.i] = 0
                        set thistype.pui_data.abil2[thistype.i] = 0
                        set thistype.pui_data.lv[thistype.i] = 0
                        set thistype.pui_data.dur[thistype.i] = 0.
                        set thistype.pui_data.t_ready[thistype.i] = true
                        set thistype.pui_data.numberofuses[thistype.i] = 0
                        set thistype.i = thistype.i + 1
                    endloop
                endif
                set thistype.pui_data.u = whichunit    
            endif
            return thistype.pui_data
        endmethod
        
        //Never call create or destroy on this struct.
    endstruct
    
    globals
        private CD d
        private integer pos
    endglobals
    
    private function NewCooldown takes unit whichunit, integer whichslot, real cd returns real
        return cd - (NewCooldownMod*CD[whichunit].lv[whichslot])
    endfunction
    
    private function UnitRemoveCooldown takes unit whichunit, integer whichslot returns nothing
        set d = CD[whichunit]
        call UnitRemoveAbility(d.u,d.abil[pos])
        set d.abil[whichslot] = 0
        set d.abil2[whichslot] = 0
        set d.dur[whichslot] = 0
        set d.lv[whichslot] = 0
        set d.t_ready[whichslot] = true
    endfunction
    
    private function RemoveCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call SetPlayerAbilityAvailable(GetOwningPlayer(d.u),d.abil[pos],true)
        
        if d.abil2[pos] != 0 then
            call UnitRemoveAbility(d.u,d.abil2[pos])
            call DestroyEffect( AddSpecialEffectTarget(Effect, d.u, Attach)) 
            if Text_Bool then
                call DisplayTimedTextToPlayer(GetOwningPlayer(d.u), 0,0,5, &quot;|cffffcc00&quot;+GetObjectName(d.abil[pos])+CD_Text)
            endif
        else
            call UnitRemoveCooldown(d.u,pos)
        endif
        call PauseTimer(d.t[pos])
        set d.t_ready[pos] = true
        call UnitResetCooldown(d.u)
    endfunction
    
    private function AddCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call SetPlayerAbilityAvailable(GetOwningPlayer(d.u),d.abil[pos],false)
        if d.abil2[pos] != 0 then
            call UnitAddAbility(d.u,d.abil2[pos])
        else
            call UnitRemoveAbility(d.u,d.abil[pos])
        endif
        call PauseTimer(d.t[pos])
        set d.t_ready[pos] = false
        call TimerStart(d.t[pos],d.dur[pos],false,function RemoveCD)
    endfunction
    
    function TimerReady takes unit whichunit, integer whichslot returns boolean
        set d = CD[whichunit]
        return d.t_ready[whichslot]
    endfunction
    
    function UnitAddCooldown takes unit whichunit, integer whichslot, integer abil, integer abil2, real duration returns nothing
        set d = CD[whichunit]
       if d.t[whichslot] == null then
            set d.t[whichslot] = CreateTimer()
            call SetTimerStructA(d.t[whichslot],d)
            call SetTimerStructB(d.t[whichslot],whichslot)
        endif
        set d.abil[whichslot] = abil
        set d.abil2[whichslot] = abil2
        set d.dur[whichslot] = duration
        set d.lv[whichslot] = GetUnitAbilityLevel(d.u,d.abil[whichslot])
    endfunction
    
    function Cooldown takes unit whichunit, integer whichslot, real duration returns nothing
       set d = CD[whichunit]
       if d.t[whichslot] == null then
            set d.t[whichslot] = CreateTimer()
            call SetTimerStructA(d.t[whichslot],d)
            call SetTimerStructB(d.t[whichslot],whichslot)
        endif
        set d.dur[whichslot] = duration
        set d.t_ready[whichslot] = false
        set d.lv[whichslot] = GetUnitAbilityLevel(d.u,d.abil[whichslot])
        call PauseTimer(d.t[whichslot])
        call TimerStart(d.t[whichslot],.0,true,function AddCD) //Allow the spell to be casted
    endfunction
    
    function ResetCooldown takes unit whichunit, integer whichslot returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 and TimerGetRemaining(d.t[whichslot]) != 0 and d.t_ready[whichslot] == false then
            call PauseTimer(d.t[whichslot])
            call TimerStart(d.t[whichslot],.0,false,function RemoveCD)
        endif
    endfunction
    
    function ResetCooldownAll takes unit whichunit returns nothing
        local integer i = 1
        set d = CD[whichunit]
        loop
            exitwhen i &gt; MAX_ABILITY
            call ResetCooldown(d.u, i)
            set i = i + 1
        endloop
    endfunction

globals
    private constant real MIN_MULT = 0.75  // Minimum multiplier for cooldown reduction
    private constant integer HASH = 8192
    public real array ABIL
    public integer array INDEX
    public integer array ITEM
    public real array CDMOD
    real array cdmod
    integer array item_type
    real array abili
    integer array index
endglobals

public struct abili
    static method operator []= takes integer id, real value returns nothing
        set ABIL[id-(id/HASH)*HASH] = value
    endmethod
    static method operator[] takes integer id returns real
        return ABIL[id-(id/HASH)*HASH]
    endmethod
endstruct

public struct cdmod
    static method operator []= takes integer id, real value returns nothing
        set CDMOD[id-(id/HASH)*HASH] = value
    endmethod
    static method operator[] takes integer id returns real
        return CDMOD[id-(id/HASH)*HASH]
    endmethod
endstruct

public struct index
    static method operator []= takes integer id, integer value returns nothing
        set INDEX[id-(id/HASH)*HASH] = value
    endmethod
    static method operator[] takes integer id returns integer
        return INDEX[id-(id/HASH)*HASH]
    endmethod
endstruct

public struct item_type
    static method operator []= takes integer id, integer value returns nothing
        set ITEM[id-(id/HASH)*HASH] = value
    endmethod
    static method operator[] takes integer id returns integer
        return ITEM[id-(id/HASH)*HASH]
    endmethod
endstruct
    
    function RestartCooldown takes unit whichunit, integer whichslot returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] != 0 and abili[whichslot] &gt; 0 then
            call Cooldown(whichunit, whichslot, d.dur[whichslot])
        endif
    endfunction
    
    function RestartCooldownAll takes unit whichunit returns nothing
        local integer i = 1
        set d = CD[whichunit]
        loop
            exitwhen i &gt; MAX_ABILITY
            if d.abil<i> != 0 and abili<i> &gt; 0 then
                call RestartCooldown(d.u, i)
            endif
            set i = i + 1
        endloop
    endfunction
    
    function AddCooldown takes unit whichunit, integer whichslot, real time returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 and TimerGetRemaining(d.t[whichslot])+time &gt; 0 then
            call PauseTimer(d.t[whichslot])
            //set d.dur[whichslot] = time
            if time != 0 then
                call TimerStart(d.t[whichslot],TimerGetRemaining(d.t[whichslot])+time,false,function RemoveCD)        
            endif
        endif
    endfunction
    
    function MultiplyCooldown takes unit whichunit, integer whichslot, real multi returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 and multi &gt; 0.0 then
            call PauseTimer(d.t[whichslot])
            //set d.dur[whichslot] = time
            if TimerGetRemaining(d.t[whichslot])*multi &gt; 0 then
                call TimerStart(d.t[whichslot],TimerGetRemaining(d.t[whichslot])*multi,false,function RemoveCD)    
            else
                call TimerStart(d.t[whichslot],0.,false,function RemoveCD)    
            endif
        endif
    endfunction
    
    function GetRemainingCooldown takes unit whichunit, integer whichslot returns real
        return TimerGetRemaining(CD[whichunit].t[whichslot])
    endfunction
    
    function GetCooldown takes unit whichunit, integer whichslot returns real
        return CD[whichunit].dur[whichslot]
    endfunction
    
    function GetAbilityNameByIndex takes unit whichunit, integer whichslot returns string
        return GetObjectName(CD[whichunit].abil[whichslot])
    endfunction
    
    function GetAbilityByIndex takes unit whichunit, integer whichslot returns integer
        return CD[whichunit].abil[whichslot]
    endfunction
    
    function RunCooldown takes unit whichunit, integer abil returns nothing
        local integer i = 1
        set d = CD[whichunit]
        loop
            exitwhen i &gt; MAX_ABILITY
            if d.abil<i> == abil then
                call Cooldown(whichunit, i, d.dur<i>)
            endif
            set i = i + 1
        endloop
    endfunction
    
    function Ability2Index takes unit whichunit, integer abil_id returns integer
        local integer count = 1
        set d = CD[whichunit]
        loop
        exitwhen count &gt; MAX_ABILITY
            if CD[whichunit].abil[count] == abil_id then
                return count
            endif
            set count = count + 1
        endloop
        return 0
    endfunction
    
    function GetBaseCooldown takes unit whichunit, integer whichslot returns real
        return abili[GetAbilityByIndex(whichunit, whichslot)]
    endfunction
    
    function AddUses takes unit whichunit, integer whichslot, integer use returns nothing
        set d = CD[whichunit]
        set d.numberofuses[whichslot] = d.numberofuses[whichslot] + use
    endfunction
    
    function GetUses takes unit whichunit, integer whichslot returns integer
        set d = CD[whichunit]
        return d.numberofuses[whichslot]
    endfunction

function LearnAbility_Actions takes nothing returns nothing
    local integer abi = GetLearnedSkill()
    local integer i = index[abi]
    local real abil_cd = abili[abi]
    local integer fake
    
    
    debug call BJDebugMsg(I2S(i)+&quot; - &quot;+R2S(abil_cd))
    
    if GetUnitAbilityLevel(GetTriggerUnit(), abi) != 1 then
        set abil_cd = CD[GetTriggerUnit()].dur<i>
    endif
    
    if abil_cd != 0 then
        if i == 1 then
            set fake = &#039;A003&#039;
        elseif i == 2 then
            set fake = &#039;A000&#039;
        elseif i == 3 then
            set fake = &#039;A001&#039;
        elseif i == 4 then
            set fake = &#039;A002&#039;
        endif
        call UnitAddCooldown( GetTriggerUnit(), i, abi, fake, abil_cd )
    endif
    
endfunction

function AddCooldown_Actions takes nothing returns nothing
    local integer abi = GetSpellAbilityId()
    local integer i = index[abi]
    local real abil_cd = abili[abi] * MIN_MULT
    local real cd = GetCooldown( GetTriggerUnit(), i)
    local real newcd = 0
    
    if i != 5 then
        set newcd = NewCooldown(GetTriggerUnit(),i,cd)
        if newcd &lt; abil_cd then
            set newcd = abil_cd
        endif
    else
        set newcd = cd
    endif
    
    
    call Cooldown(GetTriggerUnit(), i, newcd)
    call AddUses(GetTriggerUnit(),i,1)
    call UnitResetCooldown(GetTriggerUnit())
endfunction

function AddCooldown_Conditions takes nothing returns boolean
    return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

//! runtextmacro Globals( &quot;Runes&quot;, &quot;item Item&quot;, &quot;real X&quot;, &quot;real Y&quot; )

//! runtextmacro Callback( &quot;Runes&quot;, &quot;call CreateItem( GetItemTypeId(Item_Runes), X_Runes, Y_Runes)&quot; )

function Trig_Runes_Actions takes nothing returns nothing
    local integer itype = GetItemTypeId( GetManipulatedItem() )
    local integer atype
    
    if GetItemTypeId(GetManipulatedItem()) == &#039;I000&#039; then
        call ResetCooldownAll( GetTriggerUnit() )
        //! runtextmacro Timer( &quot;Runes&quot;,&quot;set Item_Runes = GetManipulatedItem()&quot;,&quot;set X_Runes = GetItemX(Item_Runes)&quot;,&quot;set Y_Runes = GetItemY(Item_Runes)&quot; )
    elseif GetItemTypeId(GetManipulatedItem()) == &#039;I001&#039; then
        call SetUnitManaPercentBJ(GetTriggerUnit(), 100)
        call SetUnitLifePercentBJ(GetTriggerUnit(), 100)
        //! runtextmacro Timer( &quot;Runes&quot;,&quot;set Item_Runes = GetManipulatedItem()&quot;,&quot;set X_Runes = GetItemX(Item_Runes)&quot;,&quot;set Y_Runes = GetItemY(Item_Runes)&quot; )
    elseif GetItemType( GetManipulatedItem()) == ITEM_TYPE_POWERUP then
        set atype = item_type[itype]
        if CD[GetTriggerUnit()].abil[index[atype]] != 0 then
            if GetLocalPlayer() == GetOwningPlayer( GetTriggerUnit() ) then
                call ClearTextMessages()
            endif
            call IssueImmediateOrder(GetTriggerUnit(), &quot;stop&quot;)
            call SetUnitAnimation( GetTriggerUnit(), &quot;stand&quot; )
            call DisplayTimedTextToPlayer(GetOwningPlayer(GetTriggerUnit()), 1,-1,5,&quot;|cffffcc00You can&#039;t learn a new ability!|r&quot;)
            //! runtextmacro Timer( &quot;Runes&quot;,&quot;set Item_Runes = GetManipulatedItem()&quot;,&quot;set X_Runes = GetItemX(Item_Runes)&quot;,&quot;set Y_Runes = GetItemY(Item_Runes)&quot; )
        else
            call UnitAddAbility(GetTriggerUnit(), atype)
            call UnitAddCooldown( GetTriggerUnit(), index[atype], atype, 0,abili[atype])
        endif
    endif
endfunction
//===========================================================================
//===========================================================================
//===========================================================================
function Cooldown_set_and_fire takes nothing returns nothing
    local trigger t1 = CreateTrigger(  )
    local trigger t2 = CreateTrigger(  )
    local trigger t3 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t3, EVENT_PLAYER_UNIT_PICKUP_ITEM )
    call TriggerAddAction( t3, function Trig_Runes_Actions )
    call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_HERO_SKILL )
    call TriggerAddAction( t1, function LearnAbility_Actions )
    call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t2, function AddCooldown_Actions )
    call TriggerAddCondition( t2, Condition( function AddCooldown_Conditions ) )
    set t1 = null
    set t2 = null
    set t3 = null
    
    //Mountain King abilities
    set index[&#039;AHtb&#039;] = 1
    set abili[&#039;AHtb&#039;] = 5.
    set index[&#039;AHtc&#039;] = 2
    set abili[&#039;AHtc&#039;] = 10.
    set index[&#039;AHbh&#039;] = 3
    set abili[&#039;AHbh&#039;] = -1
    set index[&#039;AHav&#039;] = 4
    set abili[&#039;AHav&#039;] = 15.
    //Blood Mage abilities
    set index[&#039;AHfs&#039;] = 1
    set abili[&#039;AHfs&#039;] = 12.
    set index[&#039;AHbn&#039;] = 2
    set abili[&#039;AHbn&#039;] = 20.
    set index[&#039;AHdr&#039;] = 3
    set abili[&#039;AHdr&#039;] = 8.
    set index[&#039;AHpx&#039;] = 4
    set abili[&#039;AHpx&#039;] = 30.
    //Water Guardian abilties
    set index[&#039;A006&#039;] = 1
    set abili[&#039;A006&#039;] = 15
    set index[&#039;A005&#039;] = 2
    set abili[&#039;A005&#039;] = 14
    set index[&#039;A004&#039;] = 3
    set abili[&#039;A004&#039;] = -1
    set index[&#039;A008&#039;] = 4
    set abili[&#039;A008&#039;] = 20
    //
    //Scroll Abilities
    //================
    //Scroll of Strength
    set index[&#039;A009&#039;] = 5
    set abili[&#039;A009&#039;] = SCROLL_CD
    set item_type[&#039;I002&#039;] = &#039;A009&#039;
    //Scroll of Agility
    set index[&#039;A00A&#039;] = 5
    set abili[&#039;A00A&#039;] = SCROLL_CD
    set item_type[&#039;I003&#039;] = &#039;A00A&#039;
    //Scroll of Intelligence
    set index[&#039;A00B&#039;] = 5
    set abili[&#039;A00B&#039;] = SCROLL_CD
    set item_type[&#039;I004&#039;] = &#039;A00B&#039;
    //Not In Use Abilities
    //====================
    //Drain Spirit
    set index[&#039;A00E&#039;] = 1
    set abili[&#039;A00E&#039;] = 10
endfunction
endlibrary</i></i></i></i></i>
 

Nexor

...
Reaction score
74
The abilities get messed up. This system works the following:
-Learn ability
-cast ability -> go in cooldown, add fake ability to caster
-after cooldown -> change back to castable ability

But now when I cast the ability, the other player with the same unit will go into cooldown with the same ability :S:S
 

Nexor

...
Reaction score
74
Sorry for bumping too early, I really need this system to get working I promised it to my buddies :D:D
They'll kick me if I'm not ready with it, but I can't find the problem that occurs when two of the same unit-type cast a spell :S
 

Jesus4Lyf

Good Idea™
Reaction score
397
Your code is not really readable. You have functions named "Cooldown, AddCD, UnitAddCooldown, ResetCooldown, ResetCooldownAll, AddUses, AddCooldown_Actions" all of which could (judging just by the name) do nearly the same thing. We don't know what each function should do, so I don't like your chances of getting help.

I suggest you restructure your code. ;)
(As in, rewrite.)
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
//  Functions :
//
//  GetUnitAbilityCooldown(unit whichUnit, integer ability&#039;s id) -&gt; real
//  IsUnitAbilityCoolingDown(unit whichUnit, integer ability&#039;s id) -&gt; boolean
//  ResetUnitAbilityCooldown(unit whichUnit, integer ability&#039;s id)
//
//  Spells API :
//  set FakeAbility[which ability] = which fake ability (Automatically get registered in system.)
//  set AbilityCooldown[which ability][which level] = duration(real)
//
library CooldownSystem initializer Init requires AIDS

    globals
        private constant integer FAKE_ABIL = StringHash(&quot;Fake Ability&quot;)
        private constant integer FLAG = StringHash(&quot;Flag&quot;)
        private constant integer ID = StringHash(&quot;Data&quot;)
        private hashtable ht
    endglobals
    
    private struct AbilData
        private static thistype d
        timer t
        integer abil_id
        integer lv
        unit u
        
        static method create takes nothing returns thistype
            set thistype.d = thistype.allocate()
            if thistype.d.t == null then
                set thistype.d.t = CreateTimer()
                call SaveInteger(ht,GetHandleId(thistype.d.t),ID,thistype.d)
            endif
            return thistype.d
        endmethod
    endstruct
    
    private struct Cooldown extends array
        private static timer t = CreateTimer()
        private static thistype d
        private static integer abil_id
        private static integer lv
        private static AbilData abil
        
        static method resetcooldown takes unit whichUnit, integer whichAbil returns nothing
            set thistype.d = thistype[whichUnit]
            set thistype.abil = LoadInteger(ht,thistype.d,whichAbil)
            if thistype.abil != 0 then
                call UnitRemoveAbility(whichUnit,LoadInteger(ht,thistype.abil.abil_id,FAKE_ABIL))
                call UnitAddAbility(whichUnit,thistype.abil.abil_id)
                call SetUnitAbilityLevel(whichUnit,thistype.abil.abil_id,thistype.abil.lv)
                call RemoveSavedInteger(ht,thistype.d,thistype.abil.abil_id)
                call thistype.abil.destroy()
                call thistype.d.AIDS_removeLock()
            endif
        endmethod
        
        static method stopcooldown takes nothing returns nothing
            set thistype.abil = LoadInteger(ht,GetHandleId(GetExpiredTimer()),ID)
            call resetcooldown(thistype.abil.u,thistype.abil_id)
        endmethod
        
        static method startcooldown takes nothing returns nothing
            call UnitRemoveAbility(thistype.d.unit,thistype.abil_id)
            call UnitAddAbility(thistype.d.unit,LoadInteger(ht,abil_id,FAKE_ABIL))
            call TimerStart(thistype.abil.t,LoadReal(ht,thistype.abil_id,thistype.lv),false,function thistype.stopcooldown)
        endmethod
        
        static method fire takes nothing returns boolean
            set thistype.abil_id = GetSpellAbilityId()
            if LoadInteger(ht,thistype.abil_id,0) == 1 then
                set thistype.d = thistype[GetTriggerUnit()]
                set thistype.lv = GetUnitAbilityLevel(thistype.d.unit,thistype.abil_id)
                set thistype.abil = AbilData.create()
                set thistype.abil.abil_id = thistype.abil_id
                set thistype.abil.u = thistype.d.unit
                call SaveInteger(ht,thistype.d,thistype.abil_id,thistype.abil)
                call TimerStart(thistype.t,0.,false,function thistype.startcooldown)
                call thistype.d.AIDS_addLock()
            endif
            return false
        endmethod
        
        method AIDS_onDestroy takes nothing returns nothing
            call FlushChildHashtable(ht,this)
        endmethod
        //! runtextmacro AIDS()
    endstruct
    
    struct FakeAbility
        static method operator []= takes integer abil_id, integer fakeAbil returns nothing
            call SaveInteger(ht,abil_id,0,1)//flag it
            call SaveInteger(ht,abil_id,FAKE_ABIL,fakeAbil)
        endmethod
    endstruct
    
    struct AbilityCooldown
        method operator []= takes integer i, real duration returns nothing
            call SaveReal(ht,this,i,duration)
        endmethod
        static method operator [] takes integer i returns thistype
            return i
        endmethod
    endstruct
    
    function GetUnitAbilityCooldown takes unit whichUnit, integer whichAbil returns real
        return TimerGetRemaining(AbilData(LoadInteger(ht,Cooldown[whichUnit],whichAbil)).t)
    endfunction
    
    function IsUnitAbilityCoolingDown takes unit whichUnit, integer whichAbil returns boolean
        return HaveSavedInteger(ht,Cooldown[whichUnit],whichAbil)
    endfunction
    
    function ResetUnitAbilityCooldown takes unit whichUnit, integer whichAbil returns nothing
        call Cooldown.resetcooldown(whichUnit,whichAbil)
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger t
        
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Cooldown.fire))
        
        set ht = InitHashtable()
    endfunction
endlibrary


Feel free to add your stuff inside, but don't mess it.
Hmm, this is more efficient and easy to use. After setting up the ability stuff in your spell init, the system will do it's job automatically for you. It also support practically unlimited ability cooldown for a unit. So, you can put spellbook on the unit, adding mass of abilities into it, casting it crazily... :p
 

Nexor

...
Reaction score
74
There were some errors in your code, two "thistype." are missing, but the real problem is that I want to change the cooldown of the ability unit-specific.

Like after some uses of Thunder Clap, Player Red's Mountain King can cast is much faster (less cooldown) as Player Blue's MK.

I don't see a function to set it to a unit.

@Jesus4Lyf:

Yeah I see what you meant :D
I just wanted to make my system usable first. I explain some of the functions what they shall do:
-call UnitResetCooldown: resets a unit's spell in the selected slot
-call UnitResetCooldownAll: resets all spell of a unit
-call UnitRestartCooldown: restarts the cooldown of a unit (the cooldown runs again without casting the spell)
-call UnitRestartCooldownAll: restarts all spells of a unit

I know that the names are a bit confusing because Reset and Restart are very similar to each other, but you get the idea I think
 

Nexor

...
Reaction score
74
Okay, I've got the problem but could not solve it.

When a unit learns a new skill the old one will get overwritten on every unit.
I can't repair it :S
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1

      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