Problems With Timer etc

inevit4ble

Well-Known Member
Reaction score
38
Hi Every1,

Ok, the desired effect of this spell is to:
Pause Trigger Unit
Lock camera for owning player to unit
Disable control for player
Create SFX
Display Text
Start Timer for 6 sec

Upon Timer end it is meant to:
Reset camera
Enable control
Destroy SFX
Set Unit HP to 100%
Reset Cooldowns for unit
Display Text
Unpause Unit

Also it needs to check if any enemies are in range, if more than 1 then no effects occur
And if unit has taken damage within the last 20sec, if true then no effects occur
I haven't started on the damage check yet, I wanted to get the rest of the stuff to work first​

So far:
Casting spell triggers script
Unit is paused
SFX is created
Text is displayed

Main Problem == Timer doesn't seem to end/run its handler so I don't know if the second half of the stuff works or not

Other Problems:
How do I order a unit to "stop"?
How do I pan/lock camera to unit?
How do I Enable/Disable Control for Player?
Is there anything else I am doing wrong?

I've tried what I can but wrapped them in " /* " " */ " when I couldn't get it :(

Thanks a lot! :)

JASS:
scope Rest initializer Init
//========================================================
//====================SET UP==============================
globals
    private constant integer rest = 'A02E'
    private constant string ZZZsfx = "Abilities\\Spells\\Other\\CreepSleep\\CreepSleepTarget.mdl"
    private constant integer dmy = 'h00C'
endglobals
//========================================================
//====================END UP==============================     
//========================================================
globals
    private effect array zzz
    private timer array dur
    private group g
    private unit array char
    private boolexpr b
endglobals
//========================================================
    private function RestAoE takes unit u returns boolean
        return (GetWidgetLife(u) > 0.405)
    endfunction
    
    private function pick takes nothing returns boolean
        return RestAoE(GetFilterUnit())
    endfunction

//========================================================
    private function UnitHpAdd takes unit u returns real
        local real max
        local real cur
        
        
        set max = GetUnitState(u, UNIT_STATE_MAX_LIFE)
        set cur = GetUnitState(u, UNIT_STATE_LIFE)
        
        return max - cur
    endfunction
    
    private function restEnd takes nothing returns nothing
        local integer i
        local integer i2 = 1
        local real add
        
        //finds which player is ending rest
        loop
            exitwhen i2 == 5 //Only 4 possible timers
            if GetExpiredTimer() == dur[i2] then
                set i = i2
            endif
            set i2 = i2 + 1
        endloop
        
        //Null Timer
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
        
        //Rest Camera
        
            
        //Destroy SFX
        call DestroyEffect(zzz<i>)
        
        //Reset HP
        set add = UnitHpAdd(char<i>)
        call SetUnitState(char<i>, UNIT_STATE_LIFE, GetUnitState(char<i>, UNIT_STATE_LIFE) + add)
        
        //Reset Cooldowns
        call UnitResetCooldown(char<i>)
        
        //Screen Print &quot;Done Resting!&quot;
        call DisplayTextToPlayer(GetOwningPlayer(char<i>), 0, 0, &quot;Done Resting!&quot;)
        
        //Unpause TriggerUnit()
        call PauseUnit(char<i>, false)
        
        set char <i> = null
    endfunction

//========================================================
    private function check takes nothing returns boolean
        return GetSpellAbilityId() == rest
    endfunction
//========================================================
    private function actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local player p = GetOwningPlayer(u)
        local integer e = 0
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local unit f
        
        
        call GroupEnumUnitsInRange(g, x, y, 1500., b)
        
        loop
            set f = FirstOfGroup(g)
            exitwhen f == null
            
            call GroupRemoveUnit(g, f)
            
            if (IsUnitEnemy(f, GetOwningPlayer(u)) == true) then
                set e = e + 1
            endif
        endloop
        
        if e == 0 then
            set char[GetPlayerId(p)] = u
        
            //Stops endless loop bug I had in GUI
            //call IssueTargetOrder(u, &quot;stop&quot;, nothing)
        
            //Pause Unit
            call PauseUnit(u, true)
        
            //Lock camera for player to unit
            /*if (GetLocalPlayer() == p) then
                call CameraSetupApplyForceDuration( lock, false, 0.)
            endif*/
        
            //Create ZZZ SFX on Trigger Unit Head
            set zzz[GetPlayerId(p)] = AddSpecialEffectTarget(ZZZsfx, u, &quot;overhead&quot;)
        
            //Screen Print &quot;Resting...&quot;
            call DisplayTimedTextToPlayer(p, 0., 0., 5.95, &quot;Resting...&quot;)
        
            //Starts Timer to End Resting
            set dur[GetPlayerId(p)] = CreateTimer()
            call TimerStart(dur[GetPlayerId(p)], 6., false, function restEnd )
        else
            call DisplayTimedTextToPlayer(p, 0., 0., 5., &quot;You cannot rest nearby enemies!&quot;)
        endif    
        
        
        call DestroyGroup(g)
        set g = null
        set u = null
        set p = null
        
    endfunction

//========================================================
    private function Init takes nothing returns nothing
        local trigger t
        local integer i = 0
    
        set t = CreateTrigger(  )
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function check))
        call TriggerAddAction( t, function actions )
        
        //Globals
        set g = CreateGroup()
        set b = Condition(function pick)
        
        //Preloads
        call Preload(ZZZsfx)
        
        set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), dmy, 0, 0, 0)
        call UnitAddAbility(bj_lastCreatedUnit, rest)
        call KillUnit(bj_lastCreatedUnit)
    endfunction

endscope</i></i></i></i></i></i></i></i>
 

luorax

Invasion in Duskwood
Reaction score
67
Huh, it looks okayish for first - try to add some [ljass]BJDebugMsg()[/ljass] after each important call (like when the timer expires, when the player is found, things like that), that way you can easily debunk the buggy part.

However you should use TimerUtils, that makes your life easier, and it's more effective (actually timer recycling is way more effective than dynamic timers). I can help you improving this if you want, feel free to PM me :)

EDIT: okay, I debugged it: the system fails at retrieving the the expired timer. Because i is not initialized (it's okay, because the loop should give it a value), that unitialized variable crashes the thread.

EDIT2: oh, and I got the error: in JASS, player numbers go from 0 to 11, not like in GUI. So player 1 is Player(0) in GUI.
So this is how the loop should look like:

JASS:
local integer i
local integer i2 = 0
local real add
        
 //finds which player is ending rest
loop
    exitwhen i2 == 4 //Only 4 possible timers
    if GetExpiredTimer() == dur[i2] then
        set i = i2
    endif
    set i2 = i2 + 1
endloop


The way you can order the unit to stop:
JASS:
call IssueImmediateOrder(u,&quot;stop&quot;)


Do this after the unit has been paused.

EDIT3: don't destroy your global group (called g). [ljass]call GroupEnumUnitsInRange(g, x, y, 1500., b)[/ljass] automatically clears it (neither null it). If you destroy it, the spell bugs, and will always return 0 as the enemy count.
 

inevit4ble

Well-Known Member
Reaction score
38
Ok, I've made the changes you suggested:
Changed "stop" order and put if after the pause (not sure how this works cause the unit is paused)
Removed group destroy and null


But I don't follow you on the timer side of things. I thought I was initializing it via
JASS:
//Starts Timer to End Resting
            set dur[GetPlayerId(p)] = CreateTimer()
            call TimerStart(dur[GetPlayerId(p)], 6., false, function restEnd )

And TimerUtils is a system for timers?
And recycling timers lets me use the same timer over and over instead of creating new ones each instance?

Of course it still doesn't run properly so what do I need to do to get it going?

Is there an answer to how I manipulate the camera and control for player? can't seem to fill arguments correctly.

Thanks
 

tooltiperror

Super Moderator
Reaction score
231
>And recycling timers lets me use the same timer over and over instead of creating new ones each instance?
Yes, the point of timer recycling is making a big pile of timers in memory, and when you need a timer, take one ([LJASS]NewTimer()[/LJASS]) instead of making a new one. Then when you're done, send it back to the pile instead of destroying it ([LJASS]ReleaseTimer(timer)[/LJASS])

>Is there an answer to how I manipulate the camera and control for player? can't seem to fill arguments correctly.
JASS:
if (GetLocalPlayer() == Player(0)) then
    // this code will only run for Player(0)
    // including camera actions
endif
 

luorax

Invasion in Duskwood
Reaction score
67
This code worked for me:

JASS:

scope Rest initializer Init
//========================================================
//====================SET UP==============================
globals
    private constant integer rest = &#039;AHtc&#039;
    private constant string ZZZsfx = &quot;Abilities\\Spells\\Other\\CreepSleep\\CreepSleepTarget.mdl&quot;
endglobals
//========================================================
//====================END UP==============================     
//========================================================
globals
    private effect array zzz
    private timer array dur
    private group g
    private unit array char
    private boolexpr b
endglobals
//========================================================
    private function RestAoE takes unit u returns boolean
        return (GetWidgetLife(u) &gt; 0.405)
    endfunction
    
    private function pick takes nothing returns boolean
        return RestAoE(GetFilterUnit())
    endfunction

//========================================================
    private function UnitHpAdd takes unit u returns real
        local real max
        local real cur
        
        
        set max = GetUnitState(u, UNIT_STATE_MAX_LIFE)
        set cur = GetUnitState(u, UNIT_STATE_LIFE)
        
        return max - cur
    endfunction
    
    private function restEnd takes nothing returns nothing
        local integer i
        local integer i2 = 0
        local real add
        
        //finds which player is ending rest
        loop
            exitwhen i2 == 4 //Only 4 possible timers
            if GetExpiredTimer() == dur[i2] then
                set i = i2
            endif
            set i2 = i2 + 1
        endloop
        
        //Null Timer
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
        
        //Rest Camera
        
            
        //Destroy SFX
        call DestroyEffect(zzz<i>)
        
        //Reset HP
        set add = UnitHpAdd(char<i>)
        call SetUnitState(char<i>, UNIT_STATE_LIFE, GetUnitState(char<i>, UNIT_STATE_LIFE) + add)
        
        //Reset Cooldowns
        call UnitResetCooldown(char<i>)
        
        //Screen Print &quot;Done Resting!&quot;
        call DisplayTextToPlayer(GetOwningPlayer(char<i>), 0, 0, &quot;Done Resting!&quot;)
        
        //Unpause TriggerUnit()
        call PauseUnit(char<i>, false)
        
        set char <i> = null
    endfunction

//========================================================
    private function check takes nothing returns boolean
        return GetSpellAbilityId() == rest
    endfunction
//========================================================
    private function actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local player p = GetOwningPlayer(u)
        local integer e = 0
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local unit f
        
        call GroupEnumUnitsInRange(g, x, y, 1500., b)
        
        loop
            set f = FirstOfGroup(g)
            exitwhen f == null
            
            call GroupRemoveUnit(g, f)

            
            if (IsUnitEnemy(f, GetOwningPlayer(u)) == true) then
                set e = e + 1
            endif
        endloop
        
        if e == 0 then
            set char[GetPlayerId(p)] = u
        
            //Stops endless loop bug I had in GUI
            //call IssueTargetOrder(u, &quot;stop&quot;, nothing)
        
            //Pause Unit
            call PauseUnit(u, true)
            
            call IssueImmediateOrder(u,&quot;stop&quot;)
            
            //Lock camera for player to unit
            /*if (GetLocalPlayer() == p) then
                call CameraSetupApplyForceDuration( lock, false, 0.)
            endif*/
        
            //Create ZZZ SFX on Trigger Unit Head
            set zzz[GetPlayerId(p)] = AddSpecialEffectTarget(ZZZsfx, u, &quot;overhead&quot;)
        
            //Screen Print &quot;Resting...&quot;
            call DisplayTimedTextToPlayer(p, 0., 0., 5.95, &quot;Resting...&quot;)
        
            //Starts Timer to End Resting
            set dur[GetPlayerId(p)] = CreateTimer()
            call TimerStart(dur[GetPlayerId(p)], 6., false, function restEnd )
        else
            call DisplayTimedTextToPlayer(p, 0., 0., 5., &quot;You cannot rest nearby enemies!&quot;)
        endif    
        
        
        set u = null
        set p = null
        
    endfunction

//========================================================
    private function Init takes nothing returns nothing
        local trigger t
        local integer i = 0
    
        set t = CreateTrigger(  )
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function check))
        call TriggerAddAction( t, function actions )
        
        //Globals
        set g = CreateGroup()
        set b = Condition(function pick)
        
        //Preloads
        call Preload(ZZZsfx)

    endfunction

endscope
</i></i></i></i></i></i></i></i>


Note that I've removed the preload part.
TimerUtils is a timer system, yes. It creates some timers at the start (default value is 256), and once you call NewTimer() returns the last available timer. You can attach data to the timer, and if you "destroy" it (ReleaseTimer()), it's simply stopped and recycled for later use. It's slightly faster than creating/destroying them in each run.

The way you pan the camera for the owner:
JASS:

if GetLocalPlayer()==p then
    call PanCameraToTimed(GetUnitX(u),GetUnitY(u),0.)
    call SetCameraTargetController(u, 0., 0., false)
endif

The way you reset it:
JASS:

if GetLocalPlayer()==p then
    call ResetToGameCamera(&lt;DURATION&gt;)
endif
 

inevit4ble

Well-Known Member
Reaction score
38
:) I feel silly now. Was searching your code to find the differences (beside the preload)
I forgot to change i2 = 0 instead of 1....

And I will look into TimerUtils for future use. It sounds like a plan!

Thanks!
 
General chit-chat
Help Users

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top