Dashing spell Help!

Coding Help

Well, i need a simple dash using JNGP. I need it to learn more about jass and all, so please make it simple and easy to understand! ???
Dash? Just "shooting" the caster towards the target area?
I am looking into similar things right too for the moment ^^ (However, since I am exploring the options to just use one timer for the whole map, I think someone else here have a simple way of doing it. )
You will need a timer for this. Now, there is probably someone here who could make a easy dash-spell here, you could also check out the Key Timers2, but that might be for a more experienced user.
I'll come back with something if no1 else have given you a answer (:
Hmmm, definitely you've started with a difficult spell :)

Please in the triggers section check the DASH trigger. this code is heavily commented.

In order to see the effect, just order any red unit to attack.

To do: add eyecandy...


Code (jass) Select
library DASH initializer init requires Alloc, GetWidgetMeasures // Alloc is a library to manage struct creation and deletion

globals // with vJASS we can define globals freely, here's an example
    private constant real MINDIST = 116. //this is the min dist for melee units. this variable is only valid inside the library, for being "private"
    private constant real DT = 0.02 // timer interval...
    private constant real SPEED = 1300. // sets the unit speed...
    private          hashtable HT = InitHashtable() // this is the key to make any spell MUI...
    private          key DKEY // this "type" of data is a constant integer which is unique for this code. Useful with hastables...
endglobals

private struct data extends array // this struct allos to store data in one variable name
    unit c // we define the type of objects or handle the struct will use
    unit t // in this case, the caster unit and the target unit
    timer tm
   
    implement Alloc // injects alloc into the struct
   
    method destroy takes nothing returns nothing
        set .c = null // a short way to write "this.c"
        set .t = null
        call PauseTimer(.tm)
        call .deallocate() // very important frees the data to be used later...
    endmethod
   
    private static method Loop takes nothing returns nothing
    // this method is only callable inside the struct. Any function outside the struct won't be able to call it.
        local thistype D = thistype(LoadInteger(HT, GetHandleId(GetExpiredTimer()), DKEY)) // we get the WHOLE DATA
        local real a = GetWidgetsAngle(D.c, D.t) // we now can call any part of the data in this function!!
        local real d = GetWidgetsDistance(D.c, D.t)
        if d <= MINDIST then
            call D.destroy()
            return
        endif
        call SetUnitFacing(D.c, a)
        call SetUnitX(D.c, GetUnitX(D.c) + SPEED * DT * Cos(a))
        call SetUnitY(D.c, GetUnitY(D.c) + SPEED * DT * Sin(a))
    endmethod
   
    method start takes nothing returns nothing
        call SaveInteger(HT, GetHandleId(this.tm), DKEY, integer(this)) // this is the data struct, integer(this) will get the index of the data
        call TimerStart(this.tm, DT, true, function thistype.Loop)
    endmethod
   
    static method create takes unit caster, unit target returns thistype
        local thistype d = thistype.allocate() // thistype refers to data, allocate creates the data struct
        set d.c = caster // now we set the components of the struct...
        set d.t = target
        if d.tm == null then
            set d.tm = CreateTimer()
        endif
        return d
    endmethod
endstruct

private function dashit takes nothing returns boolean
    local data D
    if GetIssuedOrderId() == OrderId("Attack") then
        call DisplayTimedTextFromPlayer(Player(0), 0,0,3, "c: " + GetUnitName(GetTriggerUnit())+ "| t: " + GetUnitName(GetOrderTargetUnit()))
        set D = data.create(GetTriggerUnit(), GetOrderTargetUnit())
        call D.start() // a variable can use their own functions :D
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
    call TriggerAddCondition(t, Condition(function dashit)) // we use Conditions because they're faster then Actions...
    set t = null
endfunction

endlibrary
Well, the test ability trigger cant be enable!
I have a lot of codes there, sorry for not putting all cleaned up in the testmap, but the idea is that you check the "DASH" library only and if you want the dependencies (Alloc, GetWidgetMeasures). One good practice to understand the code is to read it from the end to the beginning.

Go ahead a fill me with questions :)
I cant see how it work if it cant even have a test ability trigger to do that, guy!
Hmm, Moyack, you mentioned hashtables. Now, I am very curious about the speed in those. I mean, a normal global variable with an array should be faster, but that speed difference, is it noticable, or am I a bit overanalytic?
Quote from: Judash137 on January 29, 2013, 10:44:44 AM
I cant see how it work if it cant even have a test ability trigger to do that, guy!
Do you need an ability to cast it?? ok...

Quote from: rvonsonsnadtz on January 29, 2013, 12:08:00 PM
Hmm, Moyack, you mentioned hashtables. Now, I am very curious about the speed in those. I mean, a normal global variable with an array should be faster, but that speed difference, is it noticable, or am I a bit overanalytic?
Yes, a global array is way faster but searching in it will be slow as more data is stored in the array. In the other hand, hashtables are a little bit slower but searching and getting data is way faster and totally direct. You won't notice any difference...
Well, glad that Moyack came to help.. Did some reading now about Key-Timers 2 that it isn't as good as it says. However, those posts are from august 2011, so if it is updated since, then perhaps their is some hope, otherwise, well..
My testing with it does atleast show that it doesn't fit my needs at all.. A quite quick test showed that it built up a HUGE nr of processes somewhere (in comparison with a much simpler yet more effective approach from me, which seemed to keep the CPU-usage quite steady).

Btw, a bit off-topic, but Moyack, I see u use the
Code (Jass) Select

local trigger t = CreateTrigger()
call RegisterEvent(t, blahblah)
call TriggerAddAction(t, blahblah)
set t = null

However.. By some unknown reasons, my triggers using this won't fire.. No clue why.
They want the "set gg_trg_blahblah = CreateTrigger()"
Code updated:

Code (jass) Select
library DASH initializer init requires Alloc, GetWidgetMeasures // Alloc is a library to manage struct creation and deletion

globals // with vJASS we can define globals freely, here's an example
    private constant integer ABILID = 'A000' //This will define the ability rawcode we'll use...
    private constant real MINDIST = 116. //this is the min dist for melee units. this variable is only valid inside the library, for being "private"
    private constant real DT = 0.02 // timer interval...
    private constant real SPEED = 1300. // sets the unit speed...
    private          hashtable HT = InitHashtable() // this is the key to make any spell MUI...
    private          key DKEY // this "type" of data is a constant integer which is unique for this code. Useful with hastables...
endglobals

private struct data extends array // this struct allos to store data in one variable name
    unit c // we define the type of objects or handle the struct will use
    unit t // in this case, the caster unit and the target unit
    timer tm
   
    implement Alloc // injects alloc into the struct
   
    method destroy takes nothing returns nothing
        set .c = null // a short way to write "this.c"
        set .t = null
        call PauseTimer(.tm)
        call .deallocate() // very important frees the data to be used later...
    endmethod
   
    private static method Loop takes nothing returns nothing
    // this method is only callable inside the struct. Any function outside the struct won't be able to call it.
        local thistype D = thistype(LoadInteger(HT, GetHandleId(GetExpiredTimer()), DKEY)) // we get the WHOLE DATA
        local real a = GetWidgetsAngle(D.c, D.t) // we now can call any part of the data in this function!!
        local real d = GetWidgetsDistance(D.c, D.t)
        if d <= MINDIST then
            call PauseUnit(D.c, false) // unpuase the unit
            call IssueTargetOrder(D.c, "attack", D.t)
            call D.destroy()
            return
        endif
        call SetUnitFacing(D.c, a)
        call SetUnitX(D.c, GetUnitX(D.c) + SPEED * DT * Cos(a))
        call SetUnitY(D.c, GetUnitY(D.c) + SPEED * DT * Sin(a))
    endmethod
   
    method start takes nothing returns nothing
        call SaveInteger(HT, GetHandleId(this.tm), DKEY, integer(this)) // this is the data struct, integer(this) will get the index of the data
        call PauseUnit(this.c, true) // this is to make the unit facing change work...
        call TimerStart(this.tm, DT, true, function thistype.Loop)
    endmethod
   
    static method create takes unit caster, unit target returns thistype
        local thistype d = thistype.allocate() // thistype refers to data, allocate creates the data struct
        set d.c = caster // now we set the components of the struct...
        set d.t = target
        if d.tm == null then
            set d.tm = CreateTimer()
        endif
        return d
    endmethod
endstruct

private function dashit takes nothing returns boolean
    local data D
    if GetSpellAbilityId() == ABILID then
        set D = data.create(GetTriggerUnit(), GetSpellTargetUnit())
        call D.start() // a variable can use their own functions :D
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function dashit)) // we use Conditions because they're faster then Actions...
    set t = null
endfunction

endlibrary


the map is now cleaned up.

Quote from: rvonsonsnadtz on January 29, 2013, 06:10:39 PM
Btw, a bit off-topic, but Moyack, I see u use the
Code (Jass) Select

local trigger t = CreateTrigger()
call RegisterEvent(t, blahblah)
call TriggerAddAction(t, blahblah)
set t = null

However.. By some unknown reasons, my triggers using this won't fire.. No clue why.
They want the "set gg_trg_blahblah = CreateTrigger()"
Have you set the function as [lcode=jass]library bla initializer <your funciton name>[/lcode]??
Well, it still have no ability to test yet!
Judash137, any questions????