HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

How do you "loop" functions?

02-27-2008, 11:41 PM#1
Joker
How do you "loop" functions where a function on the top of the script can call on one thats on the bottom?

Whole Trigger

Collapse JASS:
library Shield uses TT, ABCT, PUI

globals
    private constant real REGEN_DELAY = 4.5
    private constant real REGEN_INTERVAL = 1.5
    private constant real MAX_SHIELD = 120.
    public boolean array HEALING
    private boolean array STOP
    private constant string REGEN_START = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"
    private constant string REGEN_EFFECT = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"
endglobals

    private struct shield
        unit a
        integer pui
        
        static method create takes unit a, integer pui returns shield
            local shield dat = shield.allocate()
            set dat.a = a
            set dat.pui = pui
            return dat
        endmethod
        
        method onDestroy takes nothing returns nothing
            call SetWidgetLife(.a, GetUnitState(.a, UNIT_STATE_MAX_LIFE) )
        endmethod
    endstruct
    

private function Callback takes nothing returns boolean
    local shield dat = TT_GetData()
    local real mana = GetUnitState(dat.a, UNIT_STATE_MANA)

    if HEALING[dat.pui] then
        call SetUnitState(dat.a, UNIT_STATE_MANA, mana+REGEN_INTERVAL)
        call DestroyEffect( AddSpecialEffectTarget( REGEN_EFFECT, dat.a, "chest" ) )
    
        if mana >= MAX_SHIELD then
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            set HEALING[dat.pui] = false
            return true
        endif
        
        if STOP[dat.pui] then
            return true
            set HEALING[dat.pui] = false
            call Actions()
        endif
    else
        return true
    endif
    return false
endfunction

//===========================================================================
private function Delay takes nothing returns boolean
    local shield dat = ABCT_GetData()
    
        if GetWidgetLife(dat.a) > 0.406 and not STOP[dat.pui] and not HEALING[dat.pui] then  
            set HEALING[dat.pui] = true
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            call DestroyEffect( AddSpecialEffectTarget( REGEN_START, dat.a, "overhead" ) )
            call TT_Start(function Callback, dat)
        elseif STOP[dat.pui] then
            set HEALING[dat.pui] = false
        endif
    return true
endfunction
    
//==============================================================================
private function Actions takes nothing returns nothing
    local unit a = GetTriggerUnit()
    local integer PUI = GetUnitIndex(a)
    local real mana = GetUnitState(a, UNIT_STATE_MANA)
    local real damage = GetEventDamage()
    local timer t = NewTimer()
    
    if not HEALING[PUI] then
        set STOP[PUI] = false
        call ABCT_Start(function Delay, shield.create(a, PUI), REGEN_DELAY )
    elseif HEALING[PUI] then
        set STOP[PUI] = true
    endif
    
    set a = null
endfunction

//===========================================================================
public function On takes unit WhichUnit returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterUnitEvent( trig, WhichUnit, EVENT_UNIT_DAMAGED )
    call TriggerAddAction( trig, function Actions )
endfunction

endlibrary



Part I need help with

Collapse JASS:
private function Callback takes nothing returns boolean
    local shield dat = TT_GetData()
    local real mana = GetUnitState(dat.a, UNIT_STATE_MANA)

    if HEALING[dat.pui] then
        call SetUnitState(dat.a, UNIT_STATE_MANA, mana+REGEN_INTERVAL)
        call DestroyEffect( AddSpecialEffectTarget( REGEN_EFFECT, dat.a, "chest" ) )
    
        if mana >= MAX_SHIELD then
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            set HEALING[dat.pui] = false
            return true
        endif
        
        if STOP[dat.pui] then
            return true
            set HEALING[dat.pui] = false
            call Actions()
        endif
    else
        return true
    endif
    return false
endfunction

//===========================================================================
private function Delay takes nothing returns boolean
    local shield dat = ABCT_GetData()
    
        if GetWidgetLife(dat.a) > 0.406 and not STOP[dat.pui] and not HEALING[dat.pui] then  
            set HEALING[dat.pui] = true
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            call DestroyEffect( AddSpecialEffectTarget( REGEN_START, dat.a, "overhead" ) )
            call TT_Start(function Callback, dat)
        elseif STOP[dat.pui] then
            set HEALING[dat.pui] = false
        endif
    return true
endfunction
    
//==============================================================================
private function Actions takes nothing returns nothing
    local unit a = GetTriggerUnit()
    local integer PUI = GetUnitIndex(a)
    local real mana = GetUnitState(a, UNIT_STATE_MANA)
    local real damage = GetEventDamage()
    local timer t = NewTimer()
    
    if not HEALING[PUI] then
        set STOP[PUI] = false
        call ABCT_Start(function Delay, shield.create(a, PUI), REGEN_DELAY )
    elseif HEALING[PUI] then
        set STOP[PUI] = true
    endif
    
    set a = null
endfunction



What I'm trying to do is replicate Halo's concept of shield recharge.


Brief Description:

If you take a hit, you heal your shield back after # seconds. If you take another hit, the timer starts over, and your recharge is halted.

My trigger does everything, except one part of it is messed. If you take a hit while your recharging, your shield doesn't regen until you get hit again. So, that's why I'm trying to "loop" it I guess. Also, I'm not sure about my code's efficiency...
02-28-2008, 12:10 AM#2
midiway
Actions() is a private function, you would need to make it public or don't use any access modifier, them you can call it through call ExecuteFunc( "Actions" )
02-28-2008, 12:13 AM#3
Joker
Quote:
Originally Posted by midiway
Actions() is a private function, you would need to make it public or don't use any access modifier, them you can call it through call ExecuteFunc( "Actions" )
They are in the same scope. This does not matter. Function Callback cannot declare Actions() because Function callback is called AFTER Actions (I think).

Edit: I just realized calling actions isn't going to help. So...what can I do to get the effect I want?
02-28-2008, 12:16 AM#4
midiway
So, use ExecuteFunc and you are done
02-28-2008, 12:40 AM#5
Joker
Just tried, it doesn't work.
02-28-2008, 12:52 AM#6
midiway
The game crashed? Did you try ExecuteFunc( "Shield_Actions" )?
02-28-2008, 01:40 AM#7
Joker
No, it doesn't crash, it doesn't do anything, mainly since GetTriggerUnit() would be null...along with the dmg source.
02-28-2008, 08:09 AM#8
Pyrogasm
ExecuteFunc passes event responses as far as I know, so... you might have to make "Actions" a public function or give it a unique name that you can call with ExecuteFunc. Maybe there's something with the SCOPE_PRIVATE prefix. I'd check the JASSHelper Manual.

If you really want to call Actions I'd do something like this instead:
Collapse JASS:
private function Callback takes nothing returns boolean
    local shield dat = TT_GetData()
    local real mana = GetUnitState(dat.a, UNIT_STATE_MANA)

    if HEALING[dat.pui] then
        call SetUnitState(dat.a, UNIT_STATE_MANA, mana+REGEN_INTERVAL)
        call DestroyEffect( AddSpecialEffectTarget( REGEN_EFFECT, dat.a, "chest" ) )
    
        if mana >= MAX_SHIELD then
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            set HEALING[dat.pui] = false
            return true
        endif
        
        if STOP[dat.pui] then
            return true
            set HEALING[dat.pui] = false
            call ExecuteFunc("ShieldThing123123")
        endif
    else
        return true
    endif
    return false
endfunction

//===========================================================================
private function Delay takes nothing returns boolean
    local shield dat = ABCT_GetData()
    
        if GetWidgetLife(dat.a) > 0.406 and not STOP[dat.pui] and not HEALING[dat.pui] then  
            set HEALING[dat.pui] = true
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            call DestroyEffect( AddSpecialEffectTarget( REGEN_START, dat.a, "overhead" ) )
            call TT_Start(function Callback, dat)
        elseif STOP[dat.pui] then
            set HEALING[dat.pui] = false
        endif
    return true
endfunction
    
//==============================================================================
private function Actions takes nothing returns nothing
    local unit a = GetTriggerUnit()
    local integer PUI = GetUnitIndex(a)
    local real mana = GetUnitState(a, UNIT_STATE_MANA)
    local real damage = GetEventDamage()
    local timer t = NewTimer()
    
    if not HEALING[PUI] then
        set STOP[PUI] = false
        call ABCT_Start(function Delay, shield.create(a, PUI), REGEN_DELAY )
    elseif HEALING[PUI] then
        set STOP[PUI] = true
    endif
    
    set a = null
endfunction

function ShieldThing123123 takes nothing returns nothing //Just some name you know that definitely won't conflict with anything
    call Actions()                                       //This allows you to keep Actions a private function
endfunction

Ah... here's what the JASSHelper manual has to say:
Quote:
Originally Posted by JASSHelper Manual
SCOPE_PREFIX and SCOPE_PRIVATE

Whenever you are inside an scope/library declaration, SCOPE_PREFIX and SCOPE_PRIVATE are enabled string constants that you could use.

SCOPE_PREFIX will return the name (as a Jass string) of the current scope concatenated with an underscode. (The prefix added for public memebers)
SCOPE_PRIVATE will return the name (as a Jass string) of the current prefix for private members.

Collapse JASS:
scope test

    private function kol takes nothing returns nothing
        call BJDebugMsg("...")
    endfunction

    function lala takes nothing returns nothing
         call ExecuteFunc(SCOPE_PRIVATE+"kol")
    endfunction

endscope

In the example, we are allowing lala() to call the private function kol via ExecuteFunc.
So, you'd do this:
Collapse JASS:
private function Callback takes nothing returns boolean
    local shield dat = TT_GetData()
    local real mana = GetUnitState(dat.a, UNIT_STATE_MANA)

    if HEALING[dat.pui] then
        call SetUnitState(dat.a, UNIT_STATE_MANA, mana+REGEN_INTERVAL)
        call DestroyEffect( AddSpecialEffectTarget( REGEN_EFFECT, dat.a, "chest" ) )
    
        if mana >= MAX_SHIELD then
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            set HEALING[dat.pui] = false
            return true
        endif
        
        if STOP[dat.pui] then
            return true
            set HEALING[dat.pui] = false
            call ExecuteFunc(SCOPE_PRIVATE+"Actions")
        endif
    else
        return true
    endif
    return false
endfunction

//===========================================================================
private function Delay takes nothing returns boolean
    local shield dat = ABCT_GetData()
    
        if GetWidgetLife(dat.a) > 0.406 and not STOP[dat.pui] and not HEALING[dat.pui] then  
            set HEALING[dat.pui] = true
            call SetWidgetLife(dat.a, GetUnitState(dat.a, UNIT_STATE_MAX_LIFE))
            call DestroyEffect( AddSpecialEffectTarget( REGEN_START, dat.a, "overhead" ) )
            call TT_Start(function Callback, dat)
        elseif STOP[dat.pui] then
            set HEALING[dat.pui] = false
        endif
    return true
endfunction
    
//==============================================================================
private function Actions takes nothing returns nothing
    local unit a = GetTriggerUnit()
    local integer PUI = GetUnitIndex(a)
    local real mana = GetUnitState(a, UNIT_STATE_MANA)
    local real damage = GetEventDamage()
    local timer t = NewTimer()
    
    if not HEALING[PUI] then
        set STOP[PUI] = false
        call ABCT_Start(function Delay, shield.create(a, PUI), REGEN_DELAY )
    elseif HEALING[PUI] then
        set STOP[PUI] = true
    endif
    
    set a = null
endfunction
02-28-2008, 09:48 AM#9
Anitarf
Quote:
Originally Posted by Joker
No, it doesn't crash, it doesn't do anything, mainly since GetTriggerUnit() would be null...along with the dmg source.
That's correct, it would be null. Also, you are returning a value before attempting to call Actions anyway, so the call never happens in the first place.

Also, it's called recursion, not looping. Best way to do it would be using the .evaluate mechanic with a function interface, not ExecuteFunc.
02-28-2008, 09:51 AM#10
Pyrogasm
Does .evaluate pass event responses?
02-28-2008, 09:58 AM#11
Anitarf
I'm not sure, but he doesn't have any to begin with because Callaback is run by a timer, not by a trigger.
02-28-2008, 07:21 PM#12
Pyrogasm
Oh, I see.