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

When do/don't waits break the function?

Status
Not open for further replies.

EdgeOfChaos

E

EdgeOfChaos

I want to know when you can safely use a Wait, and when using a Wait will end the function. Consider this loop:

JASS:
        loop
            exitwhen b.isBattleOver()
            call DisplayTextToForce(GetPlayersAll(),"Battle not over")
            call PolledWait(1.0)
            call DisplayTextToForce(GetPlayersAll(),"Battle not over")
        endloop
When I run this in my map, this Wait ends the function. The first text will display, the second will not (not even one time). But other places in my code, a Wait will function as intended. What determined whether this happens or not? And it is not just the loop. I've put waits in loops before and had them work, and waits in other parts of my code have broken it.

(And yes I know waits are bad, etc.., but I have reasons for using them)
 

EdgeOfChaos

E

EdgeOfChaos

Ahh.. I'm using it in a function that takes some parameters and gets called, which must be why it's breaking. Thanks for the help. I do wish there was a viable alternative for waits, but even vjass timers suck.
 

EdgeOfChaos

E

EdgeOfChaos

You know what I mean.

Storing values that need to be kept in hashtables sucks, especially when you have lots of locals and lots of waits
 
You know what I mean.

Storing values that need to be kept in hashtables sucks, especially when you have lots of locals and lots of waits

It's easy with something like TimerUtils.

TriggerSleepActionis just too much trouble most of the time.

JASS:
struct Data
    unit u
endstruct

function Callback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Data d = GetTimerData(t)

    call BJDebugMsg(I2S(GetHandleId(d.u)))

    call ReleaseTimer(t)
endfunction

function Init takes nothing returns nothing
    local Data d = Data.create()

    set d.u = CreateUnit(Player(0), 'hfoo', 0, 0, 0)

    call TimerStart(NewTimerEx(d), 1, false function Callback)
endfunction
 

EdgeOfChaos

E

EdgeOfChaos

I have ~10 locals I'm using, and using 3-5 waits. This method would maybe double the length of my code for each spell (which is already long) and I just don't think the extra syntax/loss of readability is worth it. I'll work around it - using executefunc, disabling pause, and not requiring too much precision.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
put it in a struct, then you can simply use those variables instead of the locals:
JASS:
struct INeedVariables
    
    public real x
    public real y
    public real damage
    public unit source
    public unit target
    public attacktype at
    public damagetype dt
    public weapontype wt
    public timer t
    
    public static method create takes unit source, unit target returns thistype
        local thistype this = .allocate()
        
        set .source = source
        set .target = target
        
        return this
    endmethod
    
    public method destroy takes nothing returns nothing
        call ReleaseTimer(.t)
        set .source = null
        set .target = null
        set .at = null
        set .dt = null
        set .wt = null
        set .t = null
        
        call .deallocate()
    endmethod
    
endstruct




function foo2 takes nothing returns nothing
    local INeedVariables data = GetTimerData(GetExpiredTimer())
    
    call UnitDamageTarget(data.source, data.target, data.damage, true, false, data.at, data.dt, data.wt)
    call SetUnitX(data.target, data.x)
    call SetUnitY(data.target, data.y)
    
    call data.destroy()
endfunction

function foo takes unit source, unit target, real damage returns nothing
    local INeedVariables data = INeedVariables.create(source, target, damage)
    set data.at = ATTACK_TYPE_MAGIC
    set data.dt = DAMAGE_TYPE_MAGIC
    set data.wt = WEAPON_TYPE_WHOKNOWS
    
    set data.x = (GetUnitX(source) + GetUnitX(target)) / 2
    set data.y = (GetUnitY(source) + GetUnitY(target)) / 2
    
    set data.t = NewTimerEx(data)
    call TimerStart(data.t, 5, false, function foo2)
endfunction

In "foo2", you will have the exact same data as in foo, noone will interfere with the values of those variables, noone will be needing a lot of locals.
(Ofcourse, you can do this with multiple timers before it ends.)

You could even use "this" instead of "data" and you dont have to write the prefix except for the dot:
JASS:
function foo2 takes nothing returns nothing
    local INeedVariables this = GetTimerData(GetExpiredTimer())
    
    call UnitDamageTarget(.source, .target, .damage, true, false, .at, .dt, .wt)
    call SetUnitX(.target, .x)
    call SetUnitY(.target, .y)
    
    call .destroy()
endfunction
 

EdgeOfChaos

E

EdgeOfChaos

Yes but using that technique more than doubles code length, as you can see even in that above example. I'm going to have lots of triggers using waits and they all require different local variables. This requires an absurd amount of code for what it does (replacing one line, with a little more precision)
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
and you though it would be ride in the park?

JASS:
function DelayedCallbackClean takes nothing returns nothing
	local timer t=GetExpiredTimer()
	call FlushChildHashtable(HY,GetHandleId(t))
	call DestroyTimer(t)
	set t=null
endfunction

function DelayedCallback takes real delay, code callback returns integer
	local timer t=CreateTimer()
	local integer h=GetHandleId(t)
	call TimerStart(t,delay,false,callback)
	set t=null
	return h
endfunction
example:
JASS:
local integer h
	if IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
		set h=DelayedCallback(0,function MakeGroundNormalAgain)
		call SaveReal(HY,h,0,x)
		call SaveReal(HY,h,1,y)
		call SetTerrainPathable(x,y,PATHING_TYPE_WALKABILITY,true)
	endif
and you only have to pass the data into hashtable, thats all
 
Status
Not open for further replies.
Top