• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Cooldown Reset Issue

Status
Not open for further replies.
Level 12
Joined
Oct 16, 2010
Messages
680
yeah that certainly looks better but if want to
JASS:
    //Replace with accurate timer
    call TriggerSleepAction(0)
as u said replace it with a timer then u have to chose one method from those I told or something similar.And then its better to store the unit(now that you have to store it anyway) in a way where u don't have to check for the buff
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
I refer to the example by Zwiebelchen when using timers:
JASS:
local timer t = CreateTimer()
call SaveInteger(TimerHash, GetHandleId(t), 0, data)
call TimerStart(t, x, false, function callback)

local timer t = GetExpiredTimer()
local data d = LoadInteger(TimerHash, GetHandleId(t), 0)
call FlushChildHashtable(TimerHash, GetHandleId(t))
call DestroyTimer(t)
set t = null

The first part of the code is how to attach data and the second part is how to receive it.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
That will do for most cases but there are still things that are not so easily done.
Lets make a simple example:
JASS:
function INeedTimersThatContinueThisFunction takes nothing returns boolean
    local integer i = 1
    loop
        if (1 > 10) then
            
            return true
        endif
        call TriggerSleepAction(1.5)
        set i = i + 1
    endloop
    
    return false
endfunction
Now how easy can an example be?
(You may not change the functionality of the loop and the actions that are after the return true statement may not be called. In other words, it must do exacly the same.)
How would you replace this wait with a timer?
 
Level 12
Joined
Oct 16, 2010
Messages
680
That will do for most cases but there are still things that are not so easily done.
what xonox showed is OK for all cases. What is the meaning of your example by the way? I assume u wanted if (i>10) then

triggersleepaction can bug in some cases and doesen't executes what is below and if u want to use timer then there's no need of it
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
By using the first method I created a rockfall ability(works in a way similar to blizzard)
JASS:
native UnitAlive takes unit u returns boolean
//! import "MoveMod.j"
//! import "ExtraFunctions.j"
library Rockfall initializer in requires MoveMod
    globals
        private trigger CastTrig = CreateTrigger()
        private trigger LoopTrig = CreateTrigger()
        
        private real array TargetX
        private real array TargetY
        private unit array Caster
        private real array Area
        private integer array Rocks
        private integer array Ticks
        private real array DropFactor
        private integer Targets     = 0
        
        private unit array Unit
        private unit array Owner
        private real array Damage
        private integer array Fall
        private integer Units       = 0
        
        private unit array Victim
        private integer array Slow
        private integer array Duration
        private integer Slows       = 0
        
        private constant integer SLOW_AMOUNT    = 300//R1000
        private constant real FALL_DELAY        = 0.7
        private constant real SPLASH            = 150
        private constant integer ABIL           = 'A000'
        private constant string SFX             = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        private constant integer DUMMY          = 'h000'
        private constant real TIMEOUT           = 0.0312500
        
        private player p
    endglobals
    
    private function filter takes nothing returns boolean
        local unit u = GetFilterUnit()
        if IsUnitAlly(u,p) then
            return false
        endif
        if not(UnitAlive(u)) then
            return false
        endif
        return true
    endfunction
    
    private function Loop takes nothing returns nothing
        local integer i = 1
        local real r
        local real x
        local real y
        local real angle
        local group g
        local unit u
        local integer ID
        loop
            exitwhen i > Slows
            if Duration[i] == 0 then
                set ID = GetUnitUserData(Victim[i])
                call AddMoveSpeedRating(Victim[i],ID,-Slow[i])
                set Victim[i] = Victim[Slows]
                set Slow[i] = Slow[Slows]
                set Duration[i] = Duration[Slows]
                set Slows = Slows - 1
            else
                set Duration[i] = Duration[i] - 1
                set i = i + 1
            endif
        endloop
        set i = 1
        loop
            exitwhen i > Units
            if Fall[i] == 0 then
                call KillUnit(Unit[i])
                call DestroyEffect(AddSpecialEffect(SFX,GetUnitX(Unit[i]),GetUnitY(Unit[i])))
                set g = CreateGroup()
                set p = GetOwningPlayer(Owner[i])
                call GroupEnumUnitsInRange(g,GetUnitX(Unit[i]),GetUnitY(Unit[i]),SPLASH,Filter(function filter))
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    set ID = GetUnitUserData(u)
                    call UnitDamageTarget(Owner[i],u,Damage[i],true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null)
                    call AddMoveSpeedRating(u,ID,-SLOW_AMOUNT)
                    call Debug(R2S(GetUnitMoveSpeed(u)))
                    set Slows = Slows + 1
                    set Victim[Slows] = u
                    set Slow[Slows] = -SLOW_AMOUNT
                    set Duration[Slows] = 32
                    call GroupRemoveUnit(g,u)
                endloop
                call DestroyGroup(g)
                set g = null
                set Unit[i] = Unit[Units]
                set Owner[i] = Owner[Units]
                set Damage[i] = Damage[Units]
                set Fall[i] = Fall[Units]
                set Units = Units - 1
            else
                set Fall[i] = Fall[i] - 1
                set i = i + 1
            endif
        endloop
        set i = 1
        loop
            exitwhen i > Targets
            if Ticks[i] == 0 then
                set TargetX[i] = TargetX[Targets]
                set TargetY[i] = TargetY[Targets]
                set Caster[i] = Caster[Targets]
                set Area[i] = Area[Targets]
                set Rocks[i] = Rocks[Targets]
                set Ticks[i] = Ticks[Targets]
                set DropFactor[i] = DropFactor[Targets]
                set Targets = Targets - 1
            else
                set r = I2R(Ticks[i])*DropFactor[i]
                loop
                    if r < Rocks[i] then
                        set r = GetRandomReal(0,Area[i])
                        set angle = GetRandomReal(0,360)
                        set x = TargetX[i] + r * Cos(angle * bj_DEGTORAD)
                        set y = TargetY[i] + r * Sin(angle * bj_DEGTORAD)
                        set Units = Units + 1
                        set Unit[Units] = CreateUnit(GetOwningPlayer(Caster[i]),DUMMY,x,y,GetRandomReal(0,360))
                        set Owner[Units] = Caster[i]
                        set Damage[Units] = GetHeroInt(Caster[i],true)
                        set Fall[Units] = R2I(0.7/TIMEOUT)
                        call SetUnitFlyHeight(Unit[Units],0,1000./FALL_DELAY)
                        set Rocks[i] = Rocks[i] - 1
                    else
                        exitwhen true
                    endif
                endloop
                set Ticks[i] = Ticks[i] - 1
                set i = i + 1
            endif
        endloop
        if Slows == 0 and Units == 0 and Targets == 0 then
            call DisableTrigger(LoopTrig)
        endif
    endfunction
    
    private function Cast takes nothing returns nothing
        if GetSpellAbilityId() == ABIL then
            set Targets = Targets + 1
            set TargetX[Targets] = GetSpellTargetX()
            set TargetY[Targets] = GetSpellTargetY()
            set Caster[Targets] = GetTriggerUnit()
            set Area[Targets] = 400
            set Rocks[Targets] = 30
            set Ticks[Targets] = R2I(I2R(5)/TIMEOUT)
            set DropFactor[Targets] = I2R(Rocks[Targets])/I2R(Ticks[Targets])
            call EnableTrigger(LoopTrig)
        endif
    endfunction
    
    private function in takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 15
            call TriggerRegisterPlayerUnitEvent(CastTrig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
            set i = i + 1
        endloop
        call TriggerAddAction(CastTrig,function Cast)
        call TriggerRegisterTimerEvent(LoopTrig,TIMEOUT,true)
        call TriggerAddAction(LoopTrig,function Loop)
    endfunction
endlibrary
By using the second method I created a custom factory ability. It has a looping timer which checks some conditions every time that it loops and stops looping if needed.
JASS:
native UnitAlive takes unit u returns boolean
//! import "TimerHash.j"
library Spawner
    private function handler takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer ID = GetHandleId(t)
        local unit u = LoadUnitHandle(TimerHash,ID,0)
        local integer id
        if UnitAlive(u) or GetUnitTypeId(u) != null then
            set id = LoadInteger(TimerHash,ID,1)
            call CreateUnit(GetOwningPlayer(u),id,GetUnitX(u),GetUnitY(u),0)
        else
            call DestroyTimer(t)
            call FlushChildHashtable(TimerHash,ID)
        endif
        set t = null
    endfunction
    
    function DesignateSpawner takes unit u, integer id, real timeout returns nothing
        local timer t = CreateTimer()
        local integer ID = GetHandleId(t)
        call SaveUnitHandle(TimerHash,ID,0,u)
        call SaveInteger(TimerHash,ID,1,id)
        call TimerStart(t,timeout,true,function handler)
        set t = null
    endfunction
endlibrary

You won't be able to compile those scripts because you don't have the imports, but you can look at them to get the idea.
 
Status
Not open for further replies.
Top