• 🏆 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!

[JASS] Loop isn't looping?

Status
Not open for further replies.
Level 3
Joined
Jan 24, 2015
Messages
26
I have a script where, after casting an ability a unit should continuously spray fire in front of them until they either die or ( this isn't implemented yet ) the ability times out. However,

JASS:
function Trig_Ignis_Fatuus_JASS_Conditions takes nothing returns boolean
    local unit caster = GetSpellAbilityUnit()
    local player owner = GetOwningPlayer(caster)
    local unit dummy
    local integer ability_level = GetUnitAbilityLevel(caster, 'A01R')
    if(GetSpellAbilityId() == 'A01R') then
        loop
            exitwhen GetUnitState(caster, UNIT_STATE_LIFE) <= 0.0  
            set dummy = CreateUnit(owner, 'h003', GetUnitX(caster), GetUnitY(caster), GetUnitFacing(caster))
            call UnitApplyTimedLife(dummy, 'BTFL', 0.5)
            call UnitAddAbility(dummy, 'A01S')
            call SetUnitAbilityLevel(dummy, 'A01S', ability_level)
            call IssuePointOrder(dummy, "breathoffire", GetUnitX(dummy) + (1.0 * Sin(GetUnitFacing(dummy) * bj_DEGTORAD)), GetUnitY(dummy) + (1.0 * Sin(GetUnitFacing(dummy) * bj_DEGTORAD)))
            call PolledWait(0.2)
        endloop
    endif
    return false
    set caster = null
    set owner = null
    set dummy = null
endfunction

this excerpt of code works perfectly fine, except it only loops once; only one dummy unit is created and it only casts the breath of fire variant once. Can I not use PolledWaits inside of loops? I can remove the exitwhen condition and it will still only loop once, so I'm not entirely sure what else the cause could be.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
The BJ "PolledWait" leaks a handle index due to a JASS bug. You either need to call a custom implementation of "PolledWait" which nulls the local declared local timer or resort to some other method for timing.

Your mathematics look incorrect? Surely the X axis should be computed with "Cos" instead of "Sin"? I mean usually X is "Cos" and Y is "Sin" based on their mathematical meanings and phases such as "SOHCAHTOA".
 
Level 3
Joined
Jan 24, 2015
Messages
26
Does seem like PolledWait can't be called in a loop, unfortunately. Any way to handle this otherwise?

Also, thanks for the catch, Dr Super Good. Guess I accidentally forgot to change it when I pasted the y part, heh.
 
Level 3
Joined
Jan 24, 2015
Messages
26
I'd appreciate if someone could give me a more sophisticated answer, then, because I don't really have any experience with working with timers nor much experience with JASS, so I'm not entirely sure how to structure something like this.

If it helps, I found myself basing the exitwhen around the caster having a specific buff ( B00E ) since messing around made it apparent that basing the dummy spell on a self-only Roar seems more appropriate than Channel.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Trig_Ignis_Fatuus_JASS_Conditions
You cannot use TriggerSleepAction inside trigger conditions. Only inside timer callbacks and trigger actions. Calling TriggerSleepAction inside trigger conditions results in a thread crash.

PolledWait works by calling TriggerSleepAction as we all know from how it is implemented.

JASS:
function PolledWait takes real duration returns nothing
    local timer t
    local real  timeRemaining
    if (duration > 0) then
        set t = CreateTimer()
        call TimerStart(t, duration, false, null)
        loop
            set timeRemaining = TimerGetRemaining(t)
            exitwhen timeRemaining <= 0
            if (timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD) then
                call TriggerSleepAction(0.1 * timeRemaining)
            else
                call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
            endif
        endloop
        call DestroyTimer(t)
    endif
endfunction

If you want to use it, you need to call this custom implementation instead to prevent a handle index leak.

JASS:
function PolledWaitFix takes real duration returns nothing
    local timer t
    local real  timeRemaining
    if (duration > 0) then
        set t = CreateTimer()
        call TimerStart(t, duration, false, null)
        loop
            set timeRemaining = TimerGetRemaining(t)
            exitwhen timeRemaining <= 0
            if (timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD) then
                call TriggerSleepAction(0.1 * timeRemaining)
            else
                call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
            endif
        endloop
        call DestroyTimer(t)
        set t = null
    endif
endfunction
 
Status
Not open for further replies.
Top