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

any way to save "code"?

Status
Not open for further replies.
Level 12
Joined
Jan 2, 2016
Messages
973
I have a function:
JASS:
    function SlideToUnitLoop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local real h = y-yc
        local real w = x-xc
        local real a = Atan2(h,w)
        if h*h+w*w <= 10000.00 or IsUnitDeadBJ(c) or IsUnitDeadBJ(u) then
            call RecTimer(t)
        else
            call SetUnitX(c, xc + dist*Cos(a))
            call SetUnitY(c, yc + dist*Sin(a))
        endif
        set t = null
        set c = null
        set u = null
    endfunction
    
    function SlideToUnit takes unit u, unit t, real speed, code actionFunc returns nothing
        local timer t1 = GetFreeTimer()
        local integer id1 = GetHandleId(t1)
        local timer t2
        local integer id2
        if actionFunc != null then
            set t2 = GetFreeTimer()
            set id2 = GetHandleId(t2)
            call SaveUnitHandle(udg_Table, id2, 'unit', u)
            call SaveUnitHandle(udg_Table, id2, 'targ', t)
            call SaveReal(udg_Table, id2, 'dist', speed*0.05)
            call TimerStart( t2, 0.05, true, actionFunc )
            set t2 = null
        endif
        call SaveUnitHandle(udg_Table, id1, 'unit', u)
        call SaveUnitHandle(udg_Table, id1, 'targ', t)
        call SaveReal(udg_Table, id1, 'dist', speed*0.05)
        call TimerStart( t1, 0.05, true, function SlideToUnitLoop )
        set t1 = null
        set u = null
        set t = null
    endfunction
But I don't want to start a 2-nd timer for the actionFunc, I want everything to happen with only one timer.
Is there any way I can save the "actionFunc" code somehow, and then call it inside the SlideToUnitLoop?

JASS:
    private function Fade takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local real h = y-yc
        local real w = x-xc
        local integer i = GetPlayerId(GetOwningPlayer(u))
        if IsUnitAliveBJ( u ) then
            if h*h+w*w <= 10000.00 then
                call RecTimer(t)
                call ShowUnit( c , false )
                call UnitRemoveAbility( u , 'A02J' )
                if Current_Type[i] == 1 then
                    call UnitAddAbility( u , 'A02L' )
                elseif Current_Type[i] == 2 then
                    call UnitAddAbility( u , 'A02K' )
                elseif Current_Type[i] == 3 then
                    call UnitAddAbility( u , 'A02M' )
                endif
                set SEF_C[i] = SEF_C[i] + 1
                set Current_Type[i] = 0
                if SEF_C[i] < 3 then
                    call UnitAddAbility( u , 'A02J' )
                else
                    call UnitAddAbility( u , 'A02N' )
                endif
            else
                call SetUnitVertexColor(c, 255, 255, 255, (255*R2I(h*h+w*w)/250000)-10)
            endif
        else
            call RecTimer(t)
        endif
        set t = null
        set c = null
        set u = null
    endfunction

call SlideToUnit( u , c , 400.00 , function Fade)
 
Level 12
Joined
May 22, 2015
Messages
1,051
I'm pretty sure you can't store them. Instead, you can use a trigger. The trigger's condition will be the function you want to run. You can pass triggers around however you want from there.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Yeah, I could do that, but then how would it look like?:
JASS:
    function SlideToUnitLoop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local trigger tr = LoadTriggerHandle(udg_Table, id, 'trig')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local real h = y-yc
        local real w = x-xc
        local real a = Atan2(h,w)
        if h*h+w*w <= 10000.00 or IsUnitDeadBJ(c) or IsUnitDeadBJ(u) then
            call RecTimer(t)
        else
            call SaveUnitHandle(udg_Table, GetHandleId(tr), 'unit', c)
            call SaveUnitHandle(udg_Table, GetHandleId(tr), 'targ', u)
            call SetUnitX(c, xc + dist*Cos(a))
            call SetUnitY(c, yc + dist*Sin(a))
            call TriggerEvaluate(tr)
        endif
        set t = null
        set c = null
        set u = null
        set tr = null
    endfunction
And then how do I refer to the evaluating trigger since there isn't any native "GetEvaluatingTrigger"?
Would I need to make the function it calls an action (instead of Condition)?
Or GetTriggeringTrigger() works in those cases too?
 
Level 12
Joined
May 22, 2015
Messages
1,051
Yeah, I could do that, but then how would it look like?:
JASS:
    function SlideToUnitLoop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local trigger tr = LoadTriggerHandle(udg_Table, id, 'trig')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local real h = y-yc
        local real w = x-xc
        local real a = Atan2(h,w)
        if h*h+w*w <= 10000.00 or IsUnitDeadBJ(c) or IsUnitDeadBJ(u) then
            call RecTimer(t)
        else
            call SaveUnitHandle(udg_Table, GetHandleId(tr), 'unit', c)
            call SaveUnitHandle(udg_Table, GetHandleId(tr), 'targ', u)
            call SetUnitX(c, xc + dist*Cos(a))
            call SetUnitY(c, yc + dist*Sin(a))
            call TriggerEvaluate(tr)
        endif
        set t = null
        set c = null
        set u = null
        set tr = null
    endfunction
And then how do I refer to the evaluating trigger since there isn't any native "GetEvaluatingTrigger"?
Would I need to make the function it calls an action (instead of Condition)?
Or GetTriggeringTrigger() works in those cases too?

I am not sure why you need to know which trigger is running in this case. You would not know which function is running if you are using "code".

The "Condition" vs "Action" thing is just a speed "hack". Conditions of triggers run faster than the actions (I don't know a whole lot about it, but it is well discussed on this site in various places - I can find at least one if you want it). You just add whatever code you want, make it always return false (always fails to pass, so the trigger actions [which don't exist] are never run), into the condition function for a trigger. Then you do as you wrote: call TriggerEvaluate(myTrigger) to run it.

You should not create a new trigger each time you want to do this. Create one trigger that is a global access point to your function. You can't pass parameters into the function, but you can use globals if you need to.

EDIT:
Thinking about it, I am pretty sure GetTriggeringTrigger() will work when you do call TriggerEvaluate(myTrigger). I use that in some spots in my own map and it works as I want it to.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Well, I may not know which function is runing, but the way I'm doing it right now (until I apply your idea later) allows me to get the values I need from the 2-nd timer's hashtable :p
But if "GetTriggeringTrigger()" really works when evaluating (not executing) it, then I'll be able to get the values I need from the trigger's hashtable.

And I was never planing to create a trigger every time :D
Was gonna do it the way you suggested (before you suggested it) :D
 
Level 12
Joined
May 22, 2015
Messages
1,051
Well, I may not know which function is runing, but the way I'm doing it right now (until I apply your idea later) allows me to get the values I need from the 2-nd timer's hashtable :p
But if "GetTriggeringTrigger()" really works when evaluating (not executing) it, then I'll be able to get the values I need from the trigger's hashtable.

And I was never planing to create a trigger every time :D
Was gonna do it the way you suggested (before you suggested it) :D

Just watch out - I don't know the full context, but there could be a problem with doing it that way. With the single trigger, multiple uses of the trigger would cause the data from the second use to overwrite the first one. Creating a new trigger each time will leak triggers. Creating and destroying them is a lot of extra work.

You might be able to just attach all the data to the first timer under different child keys. I think GetExpiredTimer() will work inside the trigger, so you can get to it that way. Might need a test though.

I hope that makes sense for you :p
 
Level 12
Joined
Jan 2, 2016
Messages
973
Well, we may be talking about 2 completely different things :D
I got some idea how to do things from what you've said, but I feel like you meant something completely different :D

Anyways, I'll do it the way I understood (as it seems good enough).
 
Level 12
Joined
Jan 2, 2016
Messages
973
It worked ^_^
JASS:
    function SlideToUnitLoop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local real h = y-yc
        local real w = x-xc
        local real a = Atan2(h,w)
        local trigger tr = LoadTriggerHandle(udg_Table, id, 'trig')
        if h*h+w*w <= 10000.00 or IsUnitDeadBJ(c) or IsUnitDeadBJ(u) then
            call RecTimer(t)
        else
            call SetUnitX(c, xc + dist*Cos(a))
            call SetUnitY(c, yc + dist*Sin(a))
        endif
        call SaveUnitHandle(udg_Table, GetHandleId(tr), 'unit', c)
        call SaveUnitHandle(udg_Table, GetHandleId(tr), 'targ', u)
        call SaveReal(udg_Table, GetHandleId(tr), 'dist', h*h+w*w)
        call TriggerEvaluate(tr)
        set t = null
        set c = null
        set u = null
        set tr = null
    endfunction
    
    function SlideToUnit takes unit u, unit d, real speed, trigger tr returns nothing
        local timer t = GetFreeTimer()
        local integer id = GetHandleId(t)
        call SaveUnitHandle(udg_Table, id, 'unit', u)
        call SaveUnitHandle(udg_Table, id, 'targ', d)
        call SaveTriggerHandle(udg_Table, id, 'trig', tr)
        call SaveReal(udg_Table, id, 'dist', speed*0.05)
        call TimerStart( t, 0.05, true, function SlideToUnitLoop )
        set t = null
        set u = null
        set d = null
        set tr = null
    endfunction

JASS:
    private function FadeFunc takes nothing returns boolean
        local trigger t = GetTriggeringTrigger()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local integer i = GetPlayerId(GetOwningPlayer(u))
        if IsUnitAliveBJ( u ) then
            if dist <= 10000.00 then
                call ShowUnit( c , false )
                call UnitRemoveAbility( u , 'A02J' )
                if Current_Type[i] == 1 then
                    call UnitAddAbility( u , 'A02L' )
                elseif Current_Type[i] == 2 then
                    call UnitAddAbility( u , 'A02K' )
                elseif Current_Type[i] == 3 then
                    call UnitAddAbility( u , 'A02M' )
                endif
                set SEF_C[i] = SEF_C[i] + 1
                set Current_Type[i] = 0
                if SEF_C[i] < 3 then
                    call UnitAddAbility( u , 'A02J' )
                else
                    call UnitAddAbility( u , 'A02N' )
                endif
            else
                call SetUnitVertexColor(c, 255, 255, 255, (255*R2I(dist)/250000)-10)
            endif
        endif
        call FlushChildHashtable(udg_Table, id)
        set t = null
        set c = null
        set u = null
        return false
    endfunction
//////////////////////////////////
        call SlideToUnit( u , c , 400.00 , Fade)
/////////////////////////////////
        call TriggerAddCondition( Fade, Condition( function FadeFunc ))
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
One used to be able to do this using the type casting exploit. However one could also use the type casting exploit and code arrays to create custom assembly code to get Warcraft III to do anything you wanted (and I mean anything, if you ran it as an administrator it literally could do anything), even delete user's Windows folder corrupting their OS installation. Hence why the type casting exploit was fixed, especially after that one fake DotA Allstars map which messed up thousands of peoples computers.

As such the only way to do it now is to bind the function to a trigger (recommended) or to use a string of the function name (slower, can have issues).
 
Level 12
Joined
Jan 2, 2016
Messages
973
Hmm, I noticed something quite interesting while reading this.
JASS:
function interface Arealfunction takes real x returns real

function double takes real x returns real
    return x*2.0
endfunction

function triple takes real x returns real
    return x*2.0
endfunction

function Test1 takes real x, Arealfunction F returns real
    return F.evaluate(F.evaluate(x)*F.evaluate(x))
endfunction

function Test2 takes nothing returns nothing
 local Arealfunction fun = Arealfunction.double //syntax to get pointer to function

   call BJDebugMsg( R2S(  Test1(1.2, fun) ))

   call BJDebugMsg( R2S(  Test1(1.2, Arealfunction.triple ) )) //also possible...
endfunction
In this example we are actually having functions as arguments and as a variable. You may also typecast(see bellow) a function pointer to integer and then back to the interface function it originated.

Would it be more efficient to save the function interface (as integer) into the hashtable, instead of a trigger, and then just call it trough evaluate?
Does it even work like that?
 
Level 7
Joined
Oct 19, 2015
Messages
286
Would it be more efficient to save the function interface (as integer) into the hashtable, instead of a trigger, and then just call it trough evaluate?
it wouldn't be more efficient, since vJass function interfaces are doing the same thing that you are doing with a trigger. However, function interfaces are easier to work with (you don't have to bother with making a trigger yourself), so I would still recommend using them.
 
Status
Not open for further replies.
Top