HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Periodic timer with VJass

12-31-2007, 05:23 AM#1
MasterofSickness
After several months of being absent from wc3 mapping I'm now also very new to vJass. Nevertheless I gave it a try and here is my first prob I can't get rid of:
I'm using NewGen Pack and when I try to save, JassHelper says
Code:
"Line xxx: Missing requirement: MyLibrary (library cannot require scopes)"

Well, and here is the trigger (ABC is a script from cohadar and MyLibrary is a library of mine with some collected functions):
Collapse JASS:
library EffectDestroyer uses ABC, MyLibrary
//==============================================================================
private struct EffectWrapper
    private effect fx
    
    static method create takes effect fx returns EffectWrapper
        local EffectWrapper ret = EffectWrapper.allocate()
        set ret.fx = fx
        return ret
    endmethod
    
    method onDestroy takes nothing returns nothing
        call DestroyEffect(.fx)
    endmethod

endstruct


//==============================================================================
private function EffectDestroyer takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local EffectWrapper ew=ClearTimerStructA(t) // ABC
    call ew.destroy()
    call ReleaseTimer(t) // CSSafety
endfunction
        
//==============================================================================
//  Exported function
//==============================================================================
function DestroyEffectTimed takes effect fx, real delay returns nothing
    local timer t=NewTimer() // CSSafety
    local EffectWrapper e=EffectWrapper.create(fx)
    call SetTimerStructA(t,e) // ABC
    call TimerStart(t,delay,false,function EffectDestroyer)
endfunction

endlibrary

// Forced by World Editor
function InitTrig_Effects takes nothing returns nothing
endfunction

I think that the prob is somehow stupid, I can feel it, but at the moment I don't get it. But that is not all, first please help me with that and afterwards there can come the actual prob (the periodic timer).

Besides that I want to thank for that vJass, jasshelper, grimoire, and whatever new stuff too of course!!!
Big thanks to Vex, PitzerMike, Pipedream, cohadar, grim, Toadcop and all the others I just this moment have not in mind. This community still rockz
12-31-2007, 05:27 AM#2
moyack
Can you post MyLibrary code? is MyLibrary a scope actually?
12-31-2007, 10:44 AM#3
MasterofSickness
I already thought that there mustn't be a scope in the library "MyLibrary" and there also is no.

Ah! I found it!
I'm so ...
Listen, I wrote following:
Collapse JASS:
library EffectDestroyer uses ABC, MyLibrary
BUT! only the trigger name of the WE-Trigger-Window is MyLibrary, the library itself in the trigger I called "CustomScriptCode" *mheeee
So, of course I have to write this:
Collapse JASS:
library EffectDestroyer uses ABC, CustomScriptCode
And yes, that worked!
BUT NOW HERE COMES MY REAL PROBLEM!

As mentioned I want to make a periodic timer.
Therefor I don't want to use global variables of type udg_*, gamecache or handlevars, I want to make it with the new vJass.
After much reading the past days in the forum, I found this A B C script from cohadar and I thought that I could get it with the help from his Little School of ABC.
The result is the following trigger of which I think I have coded almost everything wrong. The sad is I can't think of other ways, I'm too new for that, so I ask you for help.

All I want to do, is to move units with a periodic timer and that without the use of udg, gc, handlevars.

This would be my function I set to a trigger Actions with event EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER:
Collapse JASS:
call DestroyLocation(GetUnitX(GetTriggerUnit()),GetOrderPointX(),GetUnitY(GetTriggerUnit()),GetOrderPointY(),GetOwningPlayer(GetTriggerUnit()),GetTriggerUnit())
And for the new function (which looks strange, cause it is so long) I tried to use this "EffectDestroyer"-library from cohadar (see 1st post), only changed to the values I need, but I think that I made many mistakes (1st prob is, that jasshelper says "ret is not of a type that allows .syntax"):
Collapse JASS:
library TimerLocations uses ABC, CustomScriptCode
//==============================================================================
private struct LocationWrapper //Wrapper: Hülle, Verpackung
    private real x1
    private real x2
    private real y1
    private real y2
    private player p
    private unit u
    
    static method create takes real x1, real x2, real y1, real y2, player p, unit u returns LocationWrapper
        local LocationWrapper ret = LocationWrapper.allocate()
        set ret.x1 = x1
        set ret.x2 = x2
        set ret.y1 = y1
        set ret.y2 = y2
        set ret.p = p
        set ret.u = u
        return ret
    endmethod

endstruct


//==============================================================================
private function LocationDestroyer takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local LocationWrapper lw=ClearStructA(t) // ABC
    local unit u2
    local real x
    local real y
    local real xy
    call RemoveUnit(ret.u)
    set u2=CreateUnit(ret.p,'h031',ret.x1,ret.y1,0)
    set xy=xy+1
    set x=ret.x1+xy*Cos( Atan2(ret.y2-ret.y1,ret.x2-ret.x1) )
    set y=ret.y1+xy*Sin( Atan2(ret.y2-ret.y1,ret.x2-ret.x1) )

    if xy>=SquareRoot(Pow(ret.x2-ret.x1,2)+Pow(ret.y2-ret.y1,2)) then
    call PauseTimer(t)
    call RemoveUnit(u2)
    call CreateUnit(ret.p,'h01B',ret.x2,ret.y2,0)
    call ReleaseTimer(t) // CSSafety
    return
    endif
    
    call SetUnitPosition(u,x,y)
endfunction
        
//==============================================================================
//  Exported function
//==============================================================================
function DestroyLocation takes real x1, real x2, real y1, real y2, player p, unit u returns nothing
    local timer t=NewTimer() // CSSafety
    local LocationWrapper l=LocationWrapper.create(x1,x2,y1,y2,p,u)
    call SetStructA(t,l) // ABC
    call TimerStart(t,0.4,true,function LocationDestroyer)
endfunction

endlibrary

// Forced by World Editor
function InitTrig_Physics takes nothing returns nothing
endfunction

If you can give me some clues or another way of doing this that would be great. I mean before I wrote this I tried to make it with Vex's Magic Timer... but hey... hehe, I'm sadly much too dumb for this heavy code...
12-31-2007, 02:06 PM#4
cohadar
Here is an extension of ABC to use timers the noob way.

Collapse JASS:
//==============================================================================
//  ABCT - ABC Timer extension library by Cohadar - v1.0
//==============================================================================
//
//  FUNCTIONS:
//       * ABCT_Start(userFunc, struct, period)
//         ABCT_GetData() -> struct
//
//       * userFunc is a user function that takes nothing and return boolean
//         userFunc should return true to stop timer.
//
//       * GetData() is a function that can be used inside userFunc
//         GetData() will return struct passed to Start function
//==============================================================================
library ABCT uses ABC

//==============================================================================
private struct Trigger
    trigger trig
    triggeraction action
    integer data
    
    private static method cleanUp takes nothing returns nothing
        local Trigger T = ClearTriggerStructA(GetTriggeringTrigger()) // ABC
        call DisableTrigger(T.trig)
        call TriggerRemoveAction(T.trig, T.action)
        call DestroyTrigger(T.trig)
        call T.destroy()
    endmethod
    
    static method create takes code userFunc, integer data, real period returns Trigger
        local Trigger T = Trigger.allocate()
        set T.trig = CreateTrigger()
        call TriggerAddCondition(T.trig, Condition(userFunc))
        set T.data = data
        set T.action = TriggerAddAction(T.trig, function Trigger.cleanUp)
        call SetTriggerStructA(T.trig, T) // ABC
        call TriggerRegisterTimerEvent(T.trig, period, true)
        return T
    endmethod
    
endstruct

//==============================================================================
public function Start takes code userFunc, integer data, real period returns nothing
    if userFunc == null then
        call BJDebugMsg("ERROR: ABCT_Start - null userFunc")
        return
    endif
    call Trigger.create(userFunc, data, period)
endfunction

//==============================================================================
public function GetData takes nothing returns integer
    return Trigger(GetTriggerStructA(GetTriggeringTrigger())).data // ABC
endfunction

endlibrary
01-02-2008, 01:27 AM#5
MasterofSickness
Hi cohadar
Ok, so I reread, rethought, reread, rethought, read something new, thought somehow other and finally understood a few more relations.

Thx 4 posting the extension, but I didn't understand it right, because I just wanted to stay at this nice trigger of yours (the "EffectDestroyer") only changed for moving units.

I realized I made a lot of mistakes and this new code should work now, but it does not?? The unit turns to the pointed direction, but then just stay on its position. If I'm ordering the unit a 2nd time to another location, the game becomes VERY laggy, and by a 3rd order the game almost freezes. What's wrong with this?
Collapse JASS:
library temp uses ABC, CustomScriptCode
//==============================================================================
private struct DataWrapper //Wrapper[ENG->GER]: Hülle, Verpackung
    real x1
    real x2
    real y1
    real y2
    real dist
    unit u
    
    static method create takes real x1, real x2, real y1, real y2, unit u returns DataWrapper
        local DataWrapper ret = DataWrapper.allocate()
        set ret.x1 = x1
        set ret.x2 = x2
        set ret.y1 = y1
        set ret.y2 = y2
        set ret.u = u
        return ret
    endmethod

endstruct


//==============================================================================
private function MovePeriodic_Callback takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local DataWrapper dw=ClearStructA(t) // ABC
    local real x
    local real y
    call DisplayTextToForce( GetPlayersAll(), "Love" )
    call BJDebugMsg(R2S(dw.x1))
    set dw.dist=dw.dist+1.0
    call BJDebugMsg("dist: "+R2S(dw.dist))
    set x=dw.x1+dw.dist*Cos( Atan2(dw.y2-dw.y1,dw.x2-dw.x1) )
    call BJDebugMsg("x: "+R2S(x))
    set y=dw.y1+dw.dist*Sin( Atan2(dw.y2-dw.y1,dw.x2-dw.x1) )
    call BJDebugMsg("y: "+R2S(y))
    if dw.dist>=SquareRoot(Pow(dw.x2-dw.x1,2)+Pow(dw.y2-dw.y1,2)) then
    call BJDebugMsg("finished")
    call PauseTimer(t)
    call ReleaseTimer(t) // CSSafety [instead of call DestroyTimer(t) and set t = null]
    return
    endif
    call SetUnitPosition(dw.u,x,y)
    call BJDebugMsg("New Pos:"+R2S(x))
endfunction
        
//==============================================================================
//  Exported function
//==============================================================================
function MovePeriodic takes real x1, real x2, real y1, real y2, unit u returns nothing
    local timer t=NewTimer() // CSSafety
    local DataWrapper dw=DataWrapper.create(x1,x2,y1,y2,u)
    call SetStructA(t,dw) // ABC
    call TimerStart(t,0.03,true,function MovePeriodic_Callback)
    //native TimerStart           takes timer whichTimer, real timeout, boolean periodic, code handlerFunc returns nothing
    //"timeout" means that after this delay the func will be executed!
endfunction

endlibrary

// Forced by World Editor
function InitTrig_Physics takes nothing returns nothing
endfunction

There must be a minor prob...

EDIT:
W8!
Is it perhaps caused by this line of code within the timer callback?
Collapse JASS:
local DataWrapper dw=ClearStructA(t) // ABC
That it always makes the vars stay the same? So that especially the dist - var never changes?
01-12-2008, 10:37 AM#6
MasterofSickness
So, back again after reading the manual several times (anyway almost everything in it except the chapter about interface *g which I want to read the next time when my brain cools down)
and some stuff about hash tables (yeah! now I understand the system behind ABC a bit) I rewrote my old trigger and now it also works.

First to my question from one post above:
Quote:
EDIT:
W8!
Is it perhaps caused by this line of code within the timer callback?
Collapse JASS:
local DataWrapper dw=ClearStructA(t) // ABC
That it always makes the vars stay the same? So that especially the dist - var never changes?
So, when the function ClearStructA(->timer) from the library ABC (v4.6) is called, then the hash system clears (nulls) the information which were stored with SetStructA(->timer, integer) to a private global timer array "KeyA" with its index of the specific timers integer value.
Once the timer is nulled from its global timer array index ("KeyA[-> integer value of timer]"), the stored informations from the global integer array index ("ValueA[-> integer value of timer]") can't be connected a 2nd time to the same integer value of the timer, because when the function ClearStructA() runs this 2nd time, the timer can't be found in its global timer array with its timer integer value, because we already have set it to null. So, a wrong index from the global integer array Value is used (in the system it is nulled before it returns a value, so we get null from the global integer array "Value") and the stored integer informations can't be called.
:) Well, I think that was roughly the prob I had.

And now, I have a new trigger as already mentioned, but I want to know if this usage is ok, so that there won't be any leaks or any efficiency loss through the usage of it. I want to use the ABC system the right way, not the noob way...
Quote:
Here is an extension of ABC to use timers the noob way.

Finally the trigger:
Collapse JASS:
library temp2 uses ABC, CustomScriptCode // CustomScriptCode contains the CSSafety functions
//==============================================================================
private struct DataWrapper // Wrapper[ENG->GER]: Hülle, Verpackung
    real x1
    real x2
    real y1
    real y2
    real dist
    unit u
    
    static method create takes real x1, real x2, real y1, real y2, unit u returns DataWrapper
        local DataWrapper r = DataWrapper.allocate() // ".allocate" because of the static method's name "create"
        set r.x1 = x1
        set r.x2 = x2
        set r.y1 = y1
        set r.y2 = y2
        set r.u = u
        return r
    endmethod

endstruct


//==============================================================================
private function Callback takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local DataWrapper dw=GetStructA(t) // ABC
    local real x
    local real y
    set dw.dist=dw.dist+1.0
    call BJDebugMsg("dist: "+R2S(dw.dist))
    set x=dw.x1+dw.dist*Cos( Atan2(dw.y2-dw.y1,dw.x2-dw.x1) )
    call BJDebugMsg("x: "+R2S(x))
    set y=dw.y1+dw.dist*Sin( Atan2(dw.y2-dw.y1,dw.x2-dw.x1) )
    call BJDebugMsg("y: "+R2S(y))
    if dw.dist>=SquareRoot(Pow(dw.x2-dw.x1,2)+Pow(dw.y2-dw.y1,2)) then
    call BJDebugMsg("finished")
    call ClearStructA(t) // ABC
    call ReleaseTimer(t) // CSSafety [instead of call PauseTimer(t), call DestroyTimer(t) and set t = null]
    return
    endif
    call SetUnitPosition(dw.u,x,y)
endfunction
        
//==============================================================================
//  Exported function
//==============================================================================
function MovePeriodic2 takes real x1, real x2, real y1, real y2, unit u returns nothing
    local timer t=NewTimer() // CSSafety
    local DataWrapper dw=DataWrapper.create(x1,x2,y1,y2,u)
    call SetStructA(t,dw) // ABC
    call TimerStart(t,0.03,true,function Callback)
endfunction

endlibrary

And the call (only for testing):
Collapse JASS:
private function Actions takes nothing returns nothing
    call MovePeriodic2(GetUnitX(GetTriggerUnit()),GetOrderPointX(),GetUnitY(GetTriggerUnit()),GetOrderPointY(),GetTriggerUnit())
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
endfunction
01-12-2008, 04:12 PM#7
cohadar
Collapse JASS:
//==============================================================================
//  First of all you were using old ABC functions
//  SetStructA, GetStructA and ClearStructA
//  Abc can also be used for triggers and dialogs now, check the new version.
//
//  Below you will see a lot of code changes.
//  The biggest one was using ticks.
//  ticks are cool and efficient way of doing movement - learn it.
//==============================================================================

library temp2 uses ABC

globals
    private constant real PERIOD = 0.03
    private constant real SPEED = 400. // you can change this any way you like
endglobals

//==============================================================================
private struct DataWrapper // Wrapper[ENG->GER]: Hülle, Verpackung
    real dx
    real dy
    real angle
    integer ticks
    unit u
    
    static method create takes real dx, real dy, real angle, integer ticks, unit u returns DataWrapper
        local DataWrapper r = DataWrapper.allocate() // ".allocate" because of the static method's name "create"
        set r.dx = dx
        set r.dy = dy
        set r.angle = angle
        set r.ticks = ticks
        set r.u = u
        return r
    endmethod

endstruct


//==============================================================================
private function Callback takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local DataWrapper dw=GetTimerStructA(t) // ABC
    
    set dw.ticks = dw.ticks - 1 
    if dw.ticks <0 then
        call BJDebugMsg("finished")
        call ClearTimerStructA(t) // ABC
        call ReleaseTimer(t) // CSSafety
    else
        call SetUnitX(dw.u, GetUnitX(dw.u) + dw.dx)
        call SetUnitY(dw.u, GetUnitY(dw.u) + dw.dy)
    endif
endfunction
        
//==============================================================================
//  Exported function
//==============================================================================
function MovePeriodic2 takes real x1, real x2, real y1, real y2, unit u returns nothing
    local timer t=NewTimer() // CSSafety
    local real Dx = x2-x1
    local real Dy = y2-y1
    local real distance = SquareRoot(Dx*Dx + Dy*Dy)
    local real angle = Atan2(Dy, Dx)  // Dy goes first
    local integer ticks = R2I(distance / (SPEED*PERIOD)) // remember this formula
    local real dx = Dx / ticks
    local real dy = Dy / ticks
    local DataWrapper dw=DataWrapper.create(dx, dy, angle, ticks, u)
    call SetTimerStructA(t,dw) // ABC
    call TimerStart(t,PERIOD,true,function Callback)
endfunction

endlibrary