How to refer to variable in struct from another trigger ?

Nexor

...
Reaction score
74
I'm currently making a cooldown system for my map. It's a basic idea to make cooldowns dynamic. You cast the spell, it starts a timer, adds a fake icon to the unit and after some seconds changes back to normal, so you can use the ability again, simple. But I want to change the cooldown as the skill cools down. examples help a lot:

- Mountain King casts Thunder Clap (removes real skill, adds fake, starts timer with 10 second time)
- Another skill or item or something takes effect and the cooldown will be reduced to 8 seconds.

How to make that?
Here's the cooldown-system (maybe a snippet) I wrote :

JASS:
library CDLibrary

globals
    
endglobals
struct CD
    unit u
    integer a_real
    integer a_fake
    real dur
    effect eff
endstruct


private function CDCallback takes nothing returns nothing
    local CD cd = GetTimerStructA(GetExpiredTimer())
    call UnitRemoveAbility(cd.u, cd.a_fake)
    call UnitAddAbility(cd.u, cd.a_real)
    call ClearTimerStructA(GetExpiredTimer())
endfunction

function Cooldown takes unit u, integer ability_real, integer ability_fake, real duration returns nothing
    local CD cd = CD.create()
    local timer t = CreateTimer()
    set cd.u = u
    set cd.a_real = ability_real
    set cd.a_fake = ability_fake
    set cd.dur = duration
    call UnitRemoveAbility(cd.u, cd.a_real)
    call UnitAddAbility(cd.u, cd.a_fake)
    call SetTimerStructA(t, cd)
    
    call TimerStart(t, duration, false, function CDCallback)
    set t = null
    
endfunction

endlibrary
 

Frozenhelfir

set Gwypaas = Guhveepaws
Reaction score
56
>How to refer to variable in struct from another trigger ?

Make the struct into a global variable instead of a local.

JASS:
globals
     (private) CD CD_Array[8190]
endglobals


then just fill it up with units using a unit indexer. You'd reference it by something like this:
JASS:
local integer index = GetUnitIndex(u) //<- needs a unit indexer, tons out there

set CD_Array[index].a_real = ability_real


You can create the struct when the unit enters the map, and destroy it when it dies (unless a hero)

JASS:
function Actions takes nothing returns nothing
//fires on the unit enters map event
local integer index = GetUnitIndex(GetTriggerUnit())
set CD_Array[index] = CD_Array[index].create()
 

Nexor

...
Reaction score
74
Okay, then there will be a bump and I'll post my code, what I've done so far (yea, it isn't working)
I used PUI for unit indexer. I think it works for the cooldown thing, but not for modifying the cooldown.
The code:

JASS:
library CDLibrary uses PUI

globals
    timer array T
    CD array CD_Array[8190]
endglobals

struct CD
    unit u
    integer a_real
    integer a_fake
    real dur
    effect eff
endstruct

private function CDCallback takes nothing returns nothing
    local integer i = 0
    local integer index
    local boolean b = false
    loop
        exitwhen b == true
        if T<i> == GetExpiredTimer() then
            set index = i
            set CD_Array[index] = GetTimerStructA(GetExpiredTimer())
            set b = true
        endif
        set i = i + 1
    endloop
    call UnitRemoveAbility(CD_Array[index].u, CD_Array[index].a_fake)
    call UnitAddAbility(CD_Array[index].u, CD_Array[index].a_real)
    call DisplayTextToPlayer(GetOwningPlayer(CD_Array[index].u), 0, 0, &quot;|cffffcc00&quot;+GetObjectName(CD_Array[index].a_real)+&quot;|r is ready!&quot;)
    call ClearTimerStructA(GetExpiredTimer())
    call DisableTrigger( gg_trg_Timer )
    call PauseTimer(GetExpiredTimer())
endfunction

function Cooldown takes unit u, integer ability_real, integer ability_fake, real duration returns nothing
    local integer index = GetUnitIndex(u)
    //call BJDebugMsg(I2S(index))
    set CD_Array[index] = CD.create()
    set T[index] = CreateTimer()
    set CD_Array[index].u = u
    set CD_Array[index].a_real = ability_real
    set CD_Array[index].a_fake = ability_fake
    set CD_Array[index].dur = duration
    call UnitRemoveAbility(CD_Array[index].u, CD_Array[index].a_real)
    call UnitAddAbility(CD_Array[index].u, CD_Array[index].a_fake)
    call SetTimerStructA(T[index], CD_Array[index])
    call TimerStart(T[index], duration, false, function CDCallback)
endfunction

function Cooldown_Modify takes unit u, integer abil_id, real modify returns nothing
    local integer index = GetUnitIndex(u)+1
    local real time = TimerGetRemaining(T[index])
    //call BJDebugMsg(I2S(index))
    if time != 0 then
        call PauseTimer(T[index])
        if  time - modify &lt;= 0 and modify &lt; -time then
            set time = 0
        else
            set time = time + modify
        endif
        if time &gt; 0 then
            //call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0,&quot;New cooldown for |cffffcc00&quot;+GetObjectName(abil_id)+&quot;:|r &quot; + R2S(time))
        endif
        call TimerStart(T[index], time, false, function CDCallback)
        //call BJDebugMsg(&quot;CD modified to: &quot;+R2S(time))
    else
        return
    endif
endfunction

endlibrary
</i>
 

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:
    loop
        exitwhen b == true
        if T<i> == GetExpiredTimer() then
            set index = i
            set CD_Array[index] = GetTimerStructA(GetExpiredTimer())
            set b = true
        endif
        set i = i + 1
    endloop</i>


i would just attach the index by making another integer member in the struct to save the index, that loop is mad inefficient.

and i think it would be better to just use a local timer for this rather than an array
 

Nexor

...
Reaction score
74
Sorry for editing the whole post but I got this one...

So here's the second problem, how do I refer back to the struct I need from the callback function. The code:

JASS:
private function CDCallback takes nothing returns nothing
    local integer i = 0
    local boolean b = false
    local integer index
    local integer ind
    local timer t = GetExpiredTimer()
    //call BJDebugMsg(&quot;Timer callback&quot;)
    loop
        exitwhen b == true
        set CD_Array<i> = GetTimerStructA(t)
        if CD_Array<i>.t == t then
            set b = true
            set index = i
        endif
        set i = i + 1
    endloop
    set ind = CD_Array[index].index
    call UnitRemoveAbility(CD_Array[ind].u, CD_Array[ind].a_fake)
    call UnitAddAbility(CD_Array[ind].u, CD_Array[ind].a_real)
    call DisplayTextToPlayer(GetOwningPlayer(CD_Array[ind].u), 0, 0, &quot;|cffffcc00&quot;+GetObjectName(CD_Array[ind].a_real)+&quot;|r is ready!&quot;)
    call ClearTimerStructA(GetExpiredTimer())
    call DisableTrigger( gg_trg_Timer )
    call PauseTimer(GetExpiredTimer())
endfunction</i></i>


I says that CD_Array is not of a type that allows .syntax :S:S
 

Nexor

...
Reaction score
74
I have the newest NewGen, and I don't get this replacement. Could please replace it and send the code? I replaced them but it says that cannot convert integer to null... :S:S

I post the map too for checking for actual triggers.

View attachment TEST_1.w3x
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
library CDLibrary uses PUI

private struct CD
    unit u
    integer a_real
    integer a_fake
    real dur
    effect eff
    integer index
    timer t
endstruct


globals
    CD array CD_Array
    timer TIMER = CreateTimer()
endglobals

private function CDCallback takes nothing returns nothing
    local integer i = 0
    local boolean b = false
    local integer index
    local integer ind
    local timer t = GetExpiredTimer()
    //local cd cd = GetTimerStructA(t)
    //call BJDebugMsg(&quot;Timer callback&quot;)
    loop
        exitwhen b == true
        set CD_Array<i> = GetTimerStructA(t)
        if CD(CD_Array[index]).t == t then
            set b = true
            set index = i
        endif
        set i = i + 1
    endloop
    set ind = CD(CD_Array[index])
    call UnitRemoveAbility(CD(CD_Array[index]).u, CD(CD_Array[index]).a_fake)
    call UnitAddAbility(CD(CD_Array[index]).u, CD(CD_Array[index]).a_real)
    call DisplayTextToPlayer(GetOwningPlayer(CD(CD_Array[index]).u), 0, 0, &quot;|cffffcc00&quot;+GetObjectName(CD(CD_Array[index]).a_real)+&quot;|r is ready!&quot;)
    call ClearTimerStructA(GetExpiredTimer())
    call DisableTrigger( gg_trg_Timer )
    call PauseTimer(GetExpiredTimer())
endfunction

function Cooldown takes unit u, integer ability_real, integer ability_fake, real duration returns nothing
    local integer index = GetUnitIndex(u)
    local timer t = CreateTimer()
    set TIMER = t
    //call BJDebugMsg(I2S(index))
    set CD_Array[index] = CD.create()
    set CD(CD_Array[index]).u = u
    set CD(CD_Array[index]).a_real = ability_real
    set CD(CD_Array[index]).a_fake = ability_fake
    set CD(CD_Array[index]).dur = duration
    set CD(CD_Array[index]).index = index
    set CD(CD_Array[index]).t = TIMER
    call UnitRemoveAbility(CD(CD_Array[index]).u, CD(CD_Array[index]).a_real)
    call UnitAddAbility(CD(CD_Array[index]).u, CD(CD_Array[index]).a_fake)
    call SetTimerStructA(TIMER, CD(CD_Array[index]))
    call TimerStart(TIMER, duration, false, function CDCallback)
endfunction

function Cooldown_Add takes unit u, integer abil_id, real modify returns nothing
    local integer index = GetUnitIndex(u)+1
    local real time = TimerGetRemaining(CD(CD_Array[index]).t)
    local string s = &quot;&quot;
    //call BJDebugMsg(I2S(index))
    if time &gt; 0 then
        call PauseTimer(CD(CD_Array[index]).t)
        if  time + modify &lt;= 0 and modify &lt; 0 then
            set time = 0
        else
            set time = time + modify
        endif
        set s = &quot;New cooldown for |cffffcc00&quot;+GetAbilityName(abil_id)+&quot;:|r &quot; + I2S(R2I(time))
        call DisplayTimedTextToPlayer(GetOwningPlayer(u), 0,0,10,s)
        call TimerStart(CD(CD_Array[index]).t, time, false, function CDCallback)
        //call BJDebugMsg(&quot;CD modified to: &quot;+R2S(time))
    else
        return
    endif
endfunction

endlibrary

</i>


If you want to use global struct, make sure the global placed under the struct, so jasshelper will compile it.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
My homemade CD System :
JASS:
library CDSys requires PUI, ABC

    globals
        private constant integer MAX_ABILITY = 6
    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]
        
        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.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 RemoveCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call UnitRemoveAbility(d.u,d.abil2[pos])
        call UnitAddAbility(d.u,d.abil[pos])
        call SetUnitAbilityLevel(d.u,d.abil[pos],d.lv[pos])
        call PauseTimer(d.t[pos])
    endfunction
    
    private function AddCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call UnitRemoveAbility(d.u,d.abil[pos])
        call UnitAddAbility(d.u,d.abil2[pos])
        call PauseTimer(d.t[pos])
        call TimerStart(d.t[pos],d.dur[pos],false,function RemoveCD)
    endfunction
    
    function Cooldown 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])
        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 then
            call PauseTimer(d.t[whichslot])
            call TimerStart(d.t[whichslot],.0,false,function RemoveCD)
        endif
    endfunction
    
    function ModifyCooldown takes unit whichunit, integer whichslot, real time returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 then
            call PauseTimer(d.t[whichslot])
            set d.dur[whichslot] = time
            if time &gt; d.dur[whichslot] then
                call TimerStart(d.t[whichslot],time - TimerGetRemaining(d.t[whichslot]),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 GetAbilityByIndex takes unit whichunit, integer whichslot returns integer
        return CD[whichunit].abil[whichslot]
    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
endlibrary
 

Nexor

...
Reaction score
74
Hm that's the thing I wanted to make. what does the [ljass]integer whichslot[/ljass] refer to?

And what if I want to increase/reduce cooldown by a percent? [ * ; / ]

I know I should make another function to it, but should I base it on the modify (Addition/removal) [ + / - ] function?

I tried to modify my spell to increase it's cooldown by 5 seconds, but it was set to 0 :S:S what happened?
 

Nexor

...
Reaction score
74
Sorry for doubleposting but I must post this in a new post.

I've found the error that caused my ability to get resetted when I tried to modify it.

JASS:
set d.dur[whichslot] = time
            if time &gt; d.dur[whichslot] then
                call TimerStart(d.t[whichslot],time - TimerGetRemaining(d.t[whichslot]),false,function RemoveCD)    
            else
                call TimerStart(d.t[whichslot],0.,false,function RemoveCD)    
            endif


This part in the Modify function will reset the ability no matter what.
You set the duration to the time the user wants to set it. The variables will be equal so it means that the else part will run EVERYTIME -> ability reset.
 

Nexor

...
Reaction score
74
Triplepost... I know but don't want to start a new thread.

I repaired your trigger and added some other functions to it, if you don't mind.
The exceeded cooldown system:

JASS:
library CDSys requires PUI, ABC

    globals
        private constant integer MAX_ABILITY = 6
    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]
        
        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.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
        private string Effect = &quot;Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl&quot;
        private string Attach = &quot;origin&quot;
    endglobals
    
    private function RemoveCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call UnitRemoveAbility(d.u,d.abil2[pos])
        call UnitAddAbility(d.u,d.abil[pos])
        call SetUnitAbilityLevel(d.u,d.abil[pos],d.lv[pos])
        call PauseTimer(d.t[pos])
        call DestroyEffect( AddSpecialEffectTarget(Effect, d.u, Attach)) 
    endfunction
    
    private function AddCD takes nothing returns nothing
        set d = GetTimerStructA(GetExpiredTimer())
        set pos = GetTimerStructB(GetExpiredTimer())
        call UnitRemoveAbility(d.u,d.abil[pos])
        call UnitAddAbility(d.u,d.abil2[pos])
        call PauseTimer(d.t[pos])
        call TimerStart(d.t[pos],d.dur[pos],false,function RemoveCD)
    endfunction
    
    function Cooldown 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])
        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 then
            call PauseTimer(d.t[whichslot])
            call TimerStart(d.t[whichslot],.0,false,function RemoveCD)
        endif
    endfunction
    
    function RestartCooldown takes unit whichunit, integer whichslot returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 then
            call PauseTimer(d.t[whichslot])
            call TimerStart(d.t[whichslot],d.dur[whichslot],false,function RemoveCD)
        endif
    endfunction
    
    function AddCooldown takes unit whichunit, integer whichslot, real time returns nothing
        set d = CD[whichunit]
        if d.abil[whichslot] &gt; 0 then
            call PauseTimer(d.t[whichslot])
            //set d.dur[whichslot] = time
            if TimerGetRemaining(d.t[whichslot])+time &gt; 0 then
                call TimerStart(d.t[whichslot],TimerGetRemaining(d.t[whichslot])+time,false,function RemoveCD)    
            else
                call TimerStart(d.t[whichslot],0.,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 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 GetAbilityByIndex takes unit whichunit, integer whichslot returns integer
        return CD[whichunit].abil[whichslot]
    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
endlibrary
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Just modify it freely. I claim no credit from it. ;)
The whichslot is the position of skills on a unit.
You can adjust the MAX_ABILITY to match your needs.
If the hero in your map contains 4 maximum active skills then change it to 4.
The hero casts skill 1, use slot 1, skill 2 uses slot 2, vice versa.
 

Nexor

...
Reaction score
74
Is there any cooldown systems out there?
This one is ubercool I gotta say, really easily upgradeable. I added some functions to it, like:

-UnitAddCooldown: to add cooldown to unit's ability before it casts anything
-GetAbilityNameByIndex: returns ability name
-RestartCooldown: the name tells it
-MultiplyCooldown: multiply the current cooldown with a number higher than 0.0
 
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