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

[vJASS] Move units(like an arrow)

Status
Not open for further replies.
Level 6
Joined
Apr 16, 2011
Messages
158
I will leave my doubt of the day here:
something that I still did not understand and how to move a unit on the map
What I want to do:
-create a unit in front of the "caster" order to move up to a point X with a speed Y,this movement should be done Z number of times

I'll leave my code here,he is creating units,i will still set the cordeadas,but what I need to know is how to move the unit.
JASS:
library Code initializer onInit requires Tt,SpellEffectEvent 
//==================================================================================//
   globals
    //  Id of ability
    private constant integer    ID_ABILITY               = 'A000'
    // Id of dummy
    private constant integer    ID_DUMMY                 = 'u000'
    // Model of dummy
    private constant string     MODEL_MISSILE            = "Effect_StarfallMissle.mdx"
    // Attack and damage type
    private constant attacktype ATTACK_TYPE              = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE              = DAMAGE_TYPE_NORMAL
    // Speed of dummy
    private constant real       SPEED                    = 1600.
    // AOE of damage
    private constant real       AREA_OF_EFFECT           = 110.
    endglobals
    
    // Number of missiles
    private function Missiles takes integer level returns integer
        return 4*level
    endfunction
    
    // Damage 
    private function GetDamage takes integer heroInt,integer level returns real
        return (heroInt/10.)+(level*15.)
    endfunction
    
    //interval dummys
    private function GetTimeout takes integer level returns real
        return .18
    endfunction
    
    //Target filter
    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner)
    endfunction
    
//==================================================================================//
    
    private struct Spell extends array
        private static unit      array      caster
        private static unit      array      dummy
        private static player    array      owner
        private static integer   array      waves
        private static real      array      damage
        private static real      array      angle
        private static real      array      distance
        private static real      array      x
        private static real      array      y
        private static real      array      xx
        private static real      array      yy
        private static real      array      dx
        private static real      array      dy
        
    
        implement CTM
        local unit t
        local unit d
        
        implement CTMExpire
        set dummy[this] = CreateUnit(owner[this], ID_DUMMY, x[this], y[this], angle[this] * bj_RADTODEG)
        call UnitApplyTimedLife(dummy[this], 'BTLF', 1.)
        call SetUnitPosition(dummy[this], GetUnitX(dummy[this]) + 30. * Cos(angle[this]), GetUnitY(dummy[this]) + 30. * Sin(angle[this]))
        
        call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(dummy[this]), GetUnitY(dummy[this]), AREA_OF_EFFECT, null)
        loop
            set t = FirstOfGroup(bj_lastCreatedGroup)
            exitwhen t == null
            call GroupRemoveUnit(bj_lastCreatedGroup, t)
            // How i move?
            if TargetFilter(caster[this], owner[this], t) then
            call UnitDamageTarget(caster[this], t, damage[this], false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
            endif
        endloop
        set waves[this] = waves[this] - 1
            if waves[this] == 0 then
                call this.destroy()
                set dummy[this]  = null
                set caster[this] = null
                set owner[this]  = null
             endif
        implement CTMEnd
        
    
    
    private static method run takes nothing returns nothing
        local integer  level      =      GetUnitAbilityLevel(GetTriggerUnit(), ID_ABILITY)
        local thistype this       =      create(GetTimeout(level))
        local integer  heroInt 
        
        // caster and owner
        set caster[this]          =      GetTriggerUnit()
        set owner[this]           =      GetOwningPlayer(caster[this])
        
        // hero Int
        set heroInt               =      GetHeroInt(caster[this], true)
        
        // Get x,y and xx,yy
        set x[this]               =      GetUnitX(caster[this])
        set y[this]               =      GetUnitY(caster[this])
        
        set xx[this]              =      GetSpellTargetX()
        set yy[this]              =      GetSpellTargetY()
        
        //  dx dy
        set dx[this]              =      x[this] - xx[this]
        set dy[this]              =      y[this] - yy[this]
        
        // angle and distance
        set angle[this]           =      Atan2(dy[this],dx[this])
        set distance[this]        =      SquareRoot(dx[this] * dx[this] + dy[this] * dy[this])
        
        // damage and number of waves
        set damage[this]          =      GetDamage(heroInt,level)
        set waves[this]           =      Missiles(level)
        
    endmethod

    
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ID_ABILITY, function thistype.run)
    endmethod
        
    endstruct
endlibrary
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
The idea of moving a unit like a missile is;
- Find the XY of caster & target/point
- Set their distance & angle
- In the loop subtract the distance by the speed
- Lastly, kill/remove the missile and end the spell

in your code, you dont need those static arrays coz your struct index which is this makes your variables arrays already...
you dont need those "x,y,xx,yy,dx,dy" members coz you dont need them in the loop just use locals...
you should null your variable first before you destroy them...
your speed 0.18 is too slow, make it at least 0.04...

here's the code I've edit, not really optimized but its Ok;

JASS:
library Code initializer onInit requires Tt,SpellEffectEvent 
//==================================================================================//
   globals
    //  Id of ability
    private constant integer    ID_ABILITY               = 'AHfs'
    // Id of dummy
    private constant integer    ID_DUMMY                 = 'hpea'
    // Model of dummy
    private constant string     MODEL_MISSILE            = "Effect_StarfallMissle.mdx"
    // Attack and damage type
    private constant attacktype ATTACK_TYPE              = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE              = DAMAGE_TYPE_NORMAL
    // Speed of dummy
    private constant real       SPEED                    = 1600.
    // AOE of damage
    private constant real       AREA_OF_EFFECT           = 110.
    endglobals
    
    // Number of missiles
    private function Missiles takes integer level returns integer
        return 4*level
    endfunction
    
    // Damage
    private function GetDamage takes integer heroInt,integer level returns real
        return (heroInt/10.)+(level*15.)
    endfunction
    
    //interval dummys
    private function GetTimeout takes integer level returns real
        return .18
    endfunction
    
    //Target filter
    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner)
    endfunction
    
//==================================================================================//
    
    private struct Spell extends array
        private unit            caster
        private unit            dummy
        private player          owner
//        private integer         waves
        private real            damage
        private real            angle
        private real            distance
        private real            x
        private real            y
        private real            xx
        private real            yy
        private real            dx
        private real            dy
        
        //================
        private static real speed = 30.
    
        implement CTM
            local unit t
//            local unit d
          
        
        implement CTMExpire
            
            if .distance > 0 then
                set .distance = .distance - speed
                call SetUnitPosition(dummy, GetUnitX(dummy) + speed * Cos(angle), GetUnitY(dummy) + speed * Sin(angle))
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(dummy), GetUnitY(dummy), AREA_OF_EFFECT, null)
                loop
                    set t = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen t == null
                    call GroupRemoveUnit(bj_lastCreatedGroup, t)
                    // How i move?
                    if TargetFilter(caster, owner, t) then
                    call UnitDamageTarget(caster, t, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                endloop
            else
                call KillUnit(.dummy)
                set dummy  = null
                set owner = null
                set caster = null
                call .destroy()
            endif
    implement CTMEnd
        
    private static method run takes nothing returns nothing
        local integer  level      =      GetUnitAbilityLevel(GetTriggerUnit(), ID_ABILITY)
        local thistype this       =      create(0.03125)
        local integer  heroInt 
        
        // caster and owner
        set .caster          =      GetTriggerUnit()
        set .owner           =      GetOwningPlayer(caster)
        
        // hero Int
        set heroInt               =      GetHeroInt(caster, true)
        
        // Get x,y and xx,yy
        set .x            =      GetUnitX(caster)
        set .y            =      GetUnitY(caster)
        
        set .xx              =      GetSpellTargetX()
        set .yy              =      GetSpellTargetY()
        
        //  dx dy
        set .dx              =      x - xx
        set .dy              =      y - yy
        
        // angle and distance
        set .angle           =      Atan2(yy-y,xx-x)
        set .distance        =      SquareRoot(dx * dx + dy * dy)
        
        // damage and number of waves
        set .damage          =      GetDamage(heroInt,level)
        //set .waves           =      Missiles(level)
        set .dummy = CreateUnit(owner, ID_DUMMY, x+80*Cos(angle), y+80*Sin(angle), angle)
        
    endmethod

    
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ID_ABILITY, function thistype.run)
    endmethod
        
    endstruct
endlibrary

this movement should be done Z number of times
if you want a missiles that's firing like a machinegun then another struct is needed, one is for the creation & other is for the launch...
 
Level 6
Joined
Apr 16, 2011
Messages
158
The idea of moving a unit like a missile is;
if you want a missiles that's firing like a machinegun then another struct is needed, one is for the creation & other is for the launch...
Yes!

you still need this?
JASS:
local thistype this=create(0.03125)

JASS:
library Code initializer onInit requires Tt,SpellEffectEvent 
//==================================================================================//
   globals
    //  Id of ability
    private constant integer    ID_ABILITY               = 'A000'
    // Id of dummy
    private constant integer    ID_DUMMY                 = 'u001'

    // Attack and damage type
    private constant attacktype ATTACK_TYPE              = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE              = DAMAGE_TYPE_NORMAL
    
    // AOE of damage
    private constant real       AREA_OF_EFFECT           = 110.
    endglobals
    
    // Number of missiles
    private function GetMissiles takes integer level returns integer
        return 4*level
    endfunction
    
    // Damage 10% + level*15
    private function GetDamage takes integer heroInt,integer level returns real
        return (heroInt/10.)+(level*15.) 
    endfunction
    
    //interval dummys
    private function GetTimeout takes integer level returns real
        return .18
    endfunction
    
    //Target filter
    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner)
    endfunction
    
//==================================================================================//
    
    private struct Spell extends array
        private player          owner
        private integer         waves
        private unit            caster
        private unit            dummy
        private real            damage
        private real            angle
        private real            distance
        private real            x
        private real            y
        private real            xx
        private real            yy
        private real            dx
        private real            dy
        
        //================
        private static real speed = 30.
    
        implement CTM
            local unit t
          
        implement CTMExpire
            if .distance > 0 then
                set .distance = .distance - .speed
                call SetUnitPosition(.dummy, GetUnitX(.dummy) + 30. * Cos(.angle), GetUnitY(.dummy) + 30. * Sin(.angle))
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(.dummy), GetUnitY(.dummy), AREA_OF_EFFECT, null)
                loop
                    set t = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen t == null
                    call GroupRemoveUnit(bj_lastCreatedGroup, t)
                    if TargetFilter(caster, owner, t) then
                    call UnitDamageTarget(.caster, t, .damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                endloop         
            else
            call KillUnit(.dummy)
            set dummy  = null
            set owner = null
            set caster = null
            call .destroy()
           endif
    implement CTMEnd
        
    private static method run takes nothing returns nothing
        local integer  level = GetUnitAbilityLevel(GetTriggerUnit(), ID_ABILITY)
        local thistype this = create(0.03125)
        local integer  heroInt 
        
        // caster and owner
        set .caster = GetTriggerUnit()
        set .owner  = GetOwningPlayer(caster)
        
        // Get hero Int
        set heroInt = GetHeroInt(caster, true)
        
        // Get x,y and xx,yy
        set .x = GetUnitX(caster)
        set .y = GetUnitY(caster)
        
        set .xx = GetSpellTargetX()
        set .yy =GetSpellTargetY()
        
        //  dx dy
        set .dx = x - xx
        set .dy = y - yy
        
        // angle and distance
        set .angle = Atan2(yy-y,xx-x)
        set .distance = SquareRoot(dx * dx + dy * dy)
        
        // damage
        set .damage = GetDamage(heroInt,level)
        set .waves  = GetMissiles(level)
        set .dummy = CreateUnit(.owner, ID_DUMMY, GetUnitX(.caster), GetUnitY(.caster), .angle *  bj_RADTODEG)
    endmethod

    
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ID_ABILITY, function thistype.run)
    endmethod
        
    endstruct
endlibrary
 
Level 10
Joined
Sep 21, 2007
Messages
517
This struct can be used to shoot seperate missiles. Other functions can be used to launch several bullets over a time-span without another struct needed. An example of this is setting up a timer which runs every 0.10 seconds, shooting a bullet each time and incrementing a counter until it reaches, for example 10 times (10 bullets). Or for a shotgun you can create several bullets at the same time, all which aim at different angles in the scope of the angle/unit's facing. @mateuspv, just dont try to overcomplicate this bro,
basically this is the movement you want to do:

JASS:
// assuming you got the struct data, like in your code
set data.x = GetUnitX(data.dummy)
set data.y = GetUnitY(data.dummy

set data.x1 = data.x + data.speed *Cos(data.angle)
set data.y1 = data.y + data.speed*Sin(data.angle)

call SetUnitX(data.dummy, data.x1)
call SetUnitY(data.dummy, data.y1)
*Notice, speed is a member of the struct, also try drawing a triangle from two points, make the hypetenuse the distance. You will know why we are using these formulas. consider the angle to be the interior angle.

Peace
 
Level 6
Joined
Apr 16, 2011
Messages
158
confused :S
endstruct always refers to the last struct?
I am getting a strange error, in any case I think that was not very good

JASS:
    private struct Spell extends array
        private player          owner
        private integer         waves
        private unit            caster
        private real            damage
        private real            angle
        private real            distance
        private real            x
        private real            y
        private real            xx
        private real            yy
        private real            dx
        private real            dy
        endstruct
        
        struct Data extends array // need array right?
        private real            x
        private real            y
        private real            xx
        private real            yy
        private unit            dummy
        private static real speed = 30.
        endstruct
    
    
    private static method missiles takes nothing returns nothing
        set Data.dummy = CreateUnit(Spell.owner, ID_DUMMY, GetUnitX(Spell.caster), GetUnitY(Spell.caster), Spell.angle *  bj_RADTODEG)
        set Data.x = GetUnitX(Data.dummy)
        set Data.y = GetUnitY(Data.dummy

        set Data.xx = Data.x + Data.speed *Cos(Data.angle)
        set Data.yy = Data.y + Data.speed*Sin(Data.angle)

        call SetUnitX(Data.dummy, Data.xx)
        call SetUnitY(Data.dummy, Data.yy)
        call SetUnitPosition(Data.dummy, GetUnitX(Data.dummy) + 30. * Cos(Spell.angle), GetUnitY(Data.dummy) + 30. * Sin(Spell.angle))
    endmethod
    
    implement CTM
     local unit t
          
    implement CTMExpire
      if .distance > 0 then
        //call thistype.missiles
        // Now 1 loop ?
        // loop
        //exitwhen Spell.waves == null
        //set Spell.distance = Spell.distance - Data.speed
        call GroupEnumUnitsInRange(bj_lastCreatedGroup, Data.x, Data.y, AREA_OF_EFFECT, null)
        loop
            set t = FirstOfGroup(bj_lastCreatedGroup)
            exitwhen t == null
            call GroupRemoveUnit(bj_lastCreatedGroup, t)
            if TargetFilter(Data.caster, Data.owner, t) then
                call UnitDamageTarget(Data.caster, t, Data.damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
            endif
        endloop
        else
       //set Spell.waves[this] = Spell.waves[this] - 1
       //if Spell.waves[this] == 0 then
            call KillUnit(Data.dummy)
            set Data.dummy  = null
            set Spell.owner = null
            set Data.caster = null
            call .destroy()
      //endif
           endif
    implement CTMEnd
        
    private static method run takes nothing returns nothing
        local integer  level = GetUnitAbilityLevel(GetTriggerUnit(), ID_ABILITY)
        local thistype this = create(0.03125)
        local integer  heroInt 
        
        // caster and owner
        set Spell.caster = GetTriggerUnit()
        set Spell.owner  = GetOwningPlayer(caster)
        
        // Get hero Int
        set heroInt = GetHeroInt(caster, true)
        
        // Get x,y and xx,yy
        set Spell.x = GetUnitX(Spell.caster)
        set Spell.y = GetUnitY(Spell.caster)
        
        set Spell.xx = GetSpellTargetX()
        set Spell.yy = GetSpellTargetY()
        
        //  dx dy
        set Spell.dx = Spell.x - Spell.xx
        set Spell.dy = Spell.y - Spell.yy
        
        // angle and distance
        set Spell.angle = Atan2(Spell.yy-Spell.y,Spell.xx-Spell.x)
        set Spell.distance = SquareRoot(Spell.dx * Spell.dx + Spell.dy * Spell.dy)
        
        // damage
        set Spell.damage = GetDamage(heroInt,level)
        set Spell.waves  = GetMissiles(level)
    endmethod
endlibrary
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
U get an error because method declarations are only allowed inside a struct.
JASS:
private static method missiles takes nothing returns nothing

But i think thats not your problem. Seriously dont take me wrong, but writing a spell using a library with fucking 1500 lines of code for simple timer handling while you dont even know what "extends array" or "method" means isnt helpful. Start without thirdparty libraries and keep it simple, it wont help you if its working but ur not understanding why.

The whole optimizations like "extends array" or the whole timer optimizing stuff is so unnecessary since the performance gain is sooo small.
This line however is really slow:
JASS:
call SetUnitPosition(.dummy, GetUnitX(.dummy) + 30. * Cos(.angle), GetUnitY(.dummy) + 30. * Sin(.angle))
You do not want to calculate trigonometric functions when you instead can just use a vector. Sin/Cos/Tan/Atan is _VERY_ bad, performance wise.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
extends array is just used to clear those uneeded static methods like create/allocate/destroy and deallocate,
if you're not using those or you are using a custom ones like TimerTools, other than that there's no need to extends array...

another useful of extends XXX is for you to use other members of X struct...
JASS:
struct A
    static real r
    real rr
    
    method c takes nothing returns nothing
        call BJDebugMsg("value of rr == "+R2S(.rr))
    endmethod
endstruct

struct B extends A
    static method onInit takes nothing returns nothing
        local B this = 0
        set r = 1
        set .rr = 123.
        call BJDebugMsg("value of r == "+R2S(r))      
        call .c()
    endmethod
endstruct

EDIT: HERE...

JASS:
library Code initializer onInit requires SpellEffectEvent, CTL
//==================================================================================//
   globals
    //  Id of ability
    private constant integer    ID_ABILITY               = 'AHfs'
    // Id of dummy
    private constant integer    ID_DUMMY                 = 'hpea'
    // Model of dummy
    private constant string     MODEL_MISSILE            = "Effect_StarfallMissle.mdx"
    // Attack and damage type
    private constant attacktype ATTACK_TYPE              = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE              = DAMAGE_TYPE_NORMAL
    // Speed of dummy
    private constant real       SPEED                    = 1600.
    // AOE of damage
    private constant real       AREA_OF_EFFECT           = 110.
    endglobals
    
    // Number of missiles
    private function Missiles takes integer level returns integer
        return 4*level
    endfunction
    
    // Damage
    private function GetDamage takes integer heroInt,integer level returns real
        return (heroInt/10.)+(level*15.)
    endfunction
    
    //interval dummys
    private function GetTimeout takes integer level returns real
        return .18
    endfunction
    
    //Target filter
    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner)
    endfunction
    
//==================================================================================//
    
    private struct Spell extends array
        private unit            caster
        private unit            dummy
        private player          owner
        //private integer         waves
        private real            damage
        private real            angle
        private real            distance
        private real            x
        private real            y
        private real            xx
        private real            yy
        private real            dx
        private real            dy
        
        //================
        private static real speed = 30.
    
        implement CTL
            local unit t
           
          
        
        implement CTLExpire
            
            if .distance > 0 then
                set .distance = .distance - speed
                call SetUnitPosition(dummy, GetUnitX(dummy) + speed * Cos(angle), GetUnitY(dummy) + speed * Sin(angle))
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(dummy), GetUnitY(dummy), AREA_OF_EFFECT, null)
                loop
                    set t = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen t == null
                    call GroupRemoveUnit(bj_lastCreatedGroup, t)
                    // How i move?
                    if TargetFilter(caster, owner, t) then
                    call UnitDamageTarget(caster, t, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                endloop
            else
                call KillUnit(.dummy)
                set dummy  = null
                set owner = null
                set caster = null
                call .destroy()
            endif
    implement CTLEnd
        
    static method mg takes unit u, real xSpell, real ySpell returns nothing
        local integer  level      =      GetUnitAbilityLevel(u, ID_ABILITY)
        local thistype this       =      create()
        local integer  heroInt 
        
        // caster and owner
        set .caster          =      GetTriggerUnit()
        set .owner           =      GetOwningPlayer(u)
        
        // hero Int
        set heroInt               =      GetHeroInt(u, true)
        
        // Get x,y and xx,yy
        set .x            =      GetUnitX(u)
        set .y            =      GetUnitY(u)
        
        set .xx              =      xSpell
        set .yy              =      ySpell
        
        //  dx dy
        set .dx              =      x - xx
        set .dy              =      y - yy
        
        // angle and distance
        set .angle           =      Atan2(yy-y,xx-x)
        set .distance        =      SquareRoot(dx * dx + dy * dy)
        
        // damage and number of waves
        set .damage          =      GetDamage(heroInt,level)
        //set .waves           =      Missiles(level)
        set .dummy = CreateUnit(owner, ID_DUMMY, x+80*Cos(angle), y+80*Sin(angle), angle)
        
    endmethod
endstruct


//============================
struct Cast
    unit u
    real xSpell
    real ySpell
    real dur
    
    private static timer t = CreateTimer()
    private static integer index = 0
    private static integer array Ar
    
    static method looper takes nothing returns nothing
        local thistype this
        local integer i = 0
        loop
            set i = i + 1
            set this = Ar[i]
            if .dur > 0 then
                set .dur = .dur - 0.18
                call Spell.mg(.u, .xSpell, .ySpell)            
            else
                call .destroy()
                set Ar[i] = Ar[index]
                set Ar[index] = this
                set index = index - 1
                set i = i- 1                
                if index==0 then
                    call PauseTimer(t)
                endif
            endif
            exitwhen i==index
        endloop    
    endmethod  
    
    static method run takes nothing returns nothing
        local thistype this = create()
        set .u = GetTriggerUnit()
        set .xSpell = GetSpellTargetX()
        set .ySpell = GetSpellTargetY()
        set .dur = 10.
        if index==0 then
            call TimerStart(t, 0.18, true, function thistype.looper)
        endif
        set index = index + 1
        set Ar[index] = this        
    endmethod

    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ID_ABILITY, function thistype.run)
    endmethod
        
    endstruct
endlibrary
 
Last edited:
Level 14
Joined
Jun 27, 2008
Messages
1,325
With TimerUtils instead of CTL:
JASS:
library Code initializer onInit requires SpellEffectEvent, TimerUtils
//==================================================================================//
   globals
    //  Id of ability
    private constant integer    ID_ABILITY               = 'AHfs'
    // Id of dummy
    private constant integer    ID_DUMMY                 = 'hpea'
    // Model of dummy
    private constant string     MODEL_MISSILE            = "Effect_StarfallMissle.mdx"
    // Attack and damage type
    private constant attacktype ATTACK_TYPE              = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE              = DAMAGE_TYPE_NORMAL
    // Speed of dummy
    private constant real       SPEED                    = 1600.
    // AOE of damage
    private constant real       AREA_OF_EFFECT           = 110.
    endglobals
    
    // Number of missiles
    private function Missiles takes integer level returns integer
        return 4*level
    endfunction
    
    // Damage
    private function GetDamage takes integer heroInt,integer level returns real
        return (heroInt/10.)+(level*15.)
    endfunction
    
    //interval dummys
    private function GetTimeout takes integer level returns real
        return .18
    endfunction
    
    //Target filter
    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner)
    endfunction
    
//==================================================================================//
    
    private struct Spell
		private integer 		ticks
		private integer 		ticksMax
        private unit            caster
        private unit            dummy
        private player          owner
        private real            damage
        private real            x
        private real            y
        private real            vx
        private real            vy
        
        method tick takes nothing returns nothing
			local timer tim = GetEpiredTimer()
			local thistype this = GetTimerData(tim)
			local real dummyX
			local real dummyY
			local unit t
			
            if ticks < ticksMax then
                set .ticks = .ticks + 1
				set dummyX = .x + .ticks * .vx
				set dummyY = .y + .ticks * .vy
                call SetUnitPosition(dummy, dummyX, dummyY)
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, dummyX, dummyY, AREA_OF_EFFECT, null)
                loop
                    set t = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen t == null
                    call GroupRemoveUnit(bj_lastCreatedGroup, t)
                    if TargetFilter(.caster, .owner, t) then
						call UnitDamageTarget(.caster, t, .damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                endloop
            else
                call KillUnit(.dummy)
                set dummy  = null
                set owner = null
                set caster = null
				call ReleaseTimer(tim)
                call .destroy()
            endif
		endmethod
	
		static method run takes nothing returns nothing
			local thistype this = thistype.create()
			local timer t = NewTimer()
			local real angle
			local real dx
			local real dy
			local real xx
			local real yy
			local real distance
			local real duration
			
			set .caster = GetTriggerUnit()
			set .owner = GetOwningPlayer(u)
			set .x = GetUnitX(caster)
			set .y = GetUnitY(caster)
			set xx = GetSpellTargetX()
			set yy = GetSpellTargetY()
			set dx = xx - x
			set dy = yy - y
			set angle = Atan2(dy, dy)
			set distance = SquareRoot(dx * dx + dy * dy)
			
			set .ticks = 0
			set duration = distance/SPEED
			set .ticksMax = R2I(duration/0.18)
			set .vx = dx/.ticksMax
			set .vy = dy/.ticksMax
			
			set .damage = GetDamage(GetHeroInt(u, true), GetUnitAbilityLevel(u, ID_ABILITY))
			
			set .dummy = CreateUnit(.owner, ID_DUMMY, .x+80*Cos(angle), .y+80*Sin(angle), angle)
			call SetTimerData(t, this)
			call TimerStart(t, 0.18, true, function thistype.looper)
		endmethod

		private static method onInit takes nothing returns nothing
			call RegisterSpellEffectEvent(ID_ABILITY, function thistype.run)
		endmethod
	endstruct
endlibrary

Less code, and its faster.
 
Level 6
Joined
Apr 16, 2011
Messages
158
...Seriously dont take me wrong, but writing a spell using a library with fucking 1500 lines of code for simple timer handling while you dont even know what "extends array" or "method" means isnt helpful. Start without thirdparty libraries and keep it simple, it wont help you if its working but ur not understanding why....
The idea is exactly that,err.
So posting here I understand much more than reading.


"extends array" is on no way related to the "extends" that is used in inheritance. Its just the same keyword...
I wondered this a few days.

I'm going to give a revised in codes and take advantage of a free time to see if study a little more about vjass

Ty all :thumbs_up:
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
T32 & CTL are faster and efficient for this kind of things since the timeout is fast and uses one timer...
Yea i get the idea about those systems, and properly used they indeed are slightly faster. But the difference is soo small that it does in my opinion not legitimate the higher complexity and length of the code. However, there are different opinions about this - no need to argue about it. But for someone who is still learning the very basics of vJass, such a system is a shot to the knee since he has no chance to understand "how" its working.

Anyway, thanks to your ~100 sin/cos calculations my code is still faster :thumbs_up:
about your code, "tick" should be static & you have an undeclared looper in TimerStart which should
be 'tick', & you have 2 undeclared variables/function and most of all, it doesnt work :)...
Thx, i wrote this plain in the webbrowser so its possible that there are some bugs. But i think you get the idea :)
 
Status
Not open for further replies.
Top