Help with Custom Function

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:
library Arrow initializer Init

//=======================================================================
private function Damage takes integer lvl returns real
    return 133.33+(66.66*lvl)
endfunction

private function Max_dist takes integer lvl returns real
    return 333.33+(666.66*lvl) 
endfunction

function CustomFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405
endfunction

private function CreateArrow takes player ForPlayer, unit Caster, integer DummyID, integer AbilID, real Period, real Damage, real Distance, real Move_Distance, location CastPoint  returns nothing

private struct SAD
    timer t
    unit cast
    unit dummy
    real castx
    real casty
    real targx
    real targy
    real Move_dist
    real angle
    integer level
    group Group1 = CreateGroup()
    group Group2 = CreateGroup()
   
    static method create takes nothing returns SAD
        local SAD data = SAD.allocate()
        set data.cast = Caster
        set data.castx = GetUnitX(Caster)
        set data.casty = GetUnitY(Caster)
        set data.targx = GetLocationX(CastPoint)
        set data.targy = GetLocationY(CastPoint)
        set data.angle = AngleXY(data.castx,data.casty,data.targx,data.targy)
        set data.level = GetUnitAbilityLevel(data.cast, GetSpellAbilityId())
        set Caster = data.cast       
        set data.dummy = CreateUnit(GetOwningPlayer(data.cast), DummyID, PolarProjectionX (data.castx, 10, data.angle), PolarProjectionY (data.casty, 10, data.angle) , Rad2Deg(data.angle))
        call SetUnitMoveSpeed(data.dummy, Move_Distance)
        set data.Move_dist = GetUnitMoveSpeed(data.dummy)
        call SetUnitPathing(data.dummy,false)
        call SetUnitScale(data.dummy,Scale,Scale,Scale)
        call SetUnitFlyHeight(data.dummy,Fly_height,0.00)
       
        call RemoveLocation(targ)
        set targ = null
        return data
    endmethod
   
    private method onDestroy takes nothing returns nothing
        call KillUnit(.dummy)
        call GroupClear(.Group1)
        call DestroyGroup(.Group1)
        call ReleaseTimer(.t)
    endmethod
endstruct

//=======================================================================
private function Move takes nothing returns nothing
    local SAD data = GetCSData(GetExpiredTimer())
    local unit u
    local real x = GetUnitX(data.dummy)
    local real y = GetUnitY(data.dummy)
    
    set data.Move_dist = GetUnitMoveSpeed(data.dummy)
    set data.dist = data.dist + data.Move_dist
    if data.dist >= Max_dist(data.level) then
        call data.destroy()
        return
    endif
    set x = PolarProjectionX(x, data.Move_dist, data.angle)
    set y = PolarProjectionY(y, data.Move_dist, data.angle)
    call SetUnitX(data.dummy, SafeX(x))
    call SetUnitY(data.dummy, SafeY(y))
    call GroupClear(data.Group2)
    call GroupEnumUnitsInRange(data.Group2,SafeX(x),SafeY(y),Radius,Condition(function CustomFilter))
        loop
            set u = FirstOfGroup(data.Group2)
            exitwhen u == null
            if not(IsUnitInGroup(u,data.Group1)) then
                call GroupAddUnit(data.Group1,u)
                call UnitDamageTarget(data.cast,u,Damage(data.level),false,false,A_type,D_type,null)
                call GroupRemoveUnit(data.Group2,u)
            endif
                call GroupRemoveUnit(data.Group2,u)
        endloop
endfunction
   
//=======================================================================
private function Actions takes nothing returns nothing
    local SAD data = SAD.create()
   
    set data.t = NewTimer()
    call TimerStart(data.t,Period,true,function Move)
    call SetCSData(data.t,data)
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A011' or GetSpellAbilityId() == 'A017'
endfunction


//=======================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope

endlibrary


okay so you know how you can create custom functions?

call CreateArrow(Hi,hi,hi,hi)

something like that?

well im trying to convert this trigger so i can easily create an arrow with just a line.

im having a lot of trouble though.

1. am i allowed to use structs in custom functions?
 

Cohadar

master of fugue
Reaction score
209
You must make it public not private.
Than you call it with Arrow_CreateArrow (LibraryName_FunctionName)

You can read about public and private in jasshlper documentation
(find the jasshelper.html in your newgen pack.)


And yes you can use structs anywhere you want.
 

Kenny

Back for now.
Reaction score
202
Ok so this creating in 3 lines thing is probably a bit simpler then you may think. Basically it is a 3 line function that will call a script from something such as a library. It is most commonly used in libraries. It would look something like this:

JASS:
public function CreateArrow takes player ForPlayer, unit Caster, integer DummyID, integer AbilID, real Period, real Damage, real Distance, real Move_Distance, location CastPoint  returns nothing
    call SAD.create(ForPlayer,Caster,DummyID,AbilID,Period,Damage,Distance,Move_Distance,CastPoint)
endfunction


So your probably thinking, wtf is up with that create thing, its got arguments... Yeah well for this to work properly it will need arguments. It is basically creating your own custom function, and functions more then likely need arguments.

This is probably the only complicated part of it. When you call SAD.create() you will need the user defined arguments to be added to the struct. Its only a little change from what you have.

Take a look at your second argument for this function you want, its a unit variable called Caster. So in your create method it will need to take an argument just like the function call. So:

JASS:
static method create takes nothing returns SAD


becomes:

JASS:
static method create takes unit Caster returns SAD // You will need to add the rest as well


Then you set a struct member to that argument, so:

JASS:
set data.cast = Caster


You have already done this. Basically what you need to do is assign arguments to both your function that will call the spell and its struct initialiser (create method). It may seem confusing and i probably didnt explain it great (im still learning to :)).

Heres something i have done along the lines of what you are looking for:

Its a knockback system i made that im still working on, i was going to upload it but it seems there are a fair few on here.

JASS:
library KBS initializer Init
//***************************************************************************************
//**                                                                                   **     
//**    Knockback System (KBS)                                    **By kenny!**        **
//**    v 1.00                                                                         **
//**                                                                                   **
//**    A system i made that can be used for knockback spells in a variety of          **
//**    applications in a map. User defined variables make it easy to give the desired **
//**    effect for any spell.                                                          **
//**                                                                                   **
//**    Requires:                                                                      **
//**        - A vJASS preprocessor (NewGen Pack).                                       **
//**        - No other systems.                                                        **
//**        - A dummy unit. This rarely changes in most maps though. ('h000')          **
//**        - The special effects found in the import/export section of this map.       **
//**          They are the "Dust.mdx" and the "SlideWater.mdx". Or you can use your    **
//**          own if you have some.                                                    **
//**                                                                                   **
//***************************************************************************************

//***************************************************************************************
//**                                                                                   **
//**    Other Information:                                                             **
//**        - Angle is taken in degrees. But can easily be changed if you know how.    **
//**        - Units will be stopped if they hit the map borders.                       **
//**        - Remember to import the special effect into your map if you need them.    **
//**                                                                                   **
//**    Sliding Distances:                                                             **
//**        - This is some general knowledge on the different distances and how to     **
//**          get them.                                                                **
//**        - A small knockback, such as one used for a bash would be around 15.00 for **
//**          the Startspeed and 0.50 for the deceleration.                            **
//**        - 25.00-30.00 for Startspeed with 0.50 would give a knockback for a small  **
//**          stomp spell of sorts.                                                    **
//**        - 62.50 Startspeed with a 1.5625 deceleration would give a very long       **
//**          knockback which is also quite fast.                                      **
//**                                                                                   **
//**    NOTE: This is all with an interval of 0.03125, which is recommended. This is   **
//**          32 intervals per second.                                                 **
//**                                                                                   **
//***************************************************************************************
                                                                           
//***************************************************************************************
//**                                                                                   **
//**    Usage:                                                                         **
//**                                                                                   **
//**        call KBS_Begin(Target,Startspeed,Deceleration,Angle,Killtrees)             **
//**                                                                                   **
//**    - Target        - The unit that will be used in the knockback.                 **
//**    - Startspeed    - The initial speed at which the unit will be knocked back.    **                 
//**    - Deceleration  - The deceleration of the unit. Slows the unit down over       **
//**                      the duration of the knockback.                               **
//**    - Angle         - The angle that the unit will be knocked back at.             **
//**                      THIS MUST BE IN DEGREES. <- Easier to GUI users.             **
//**    - Killtrees     - Whether or not trees will be knocked down when units get     **
//**                      close to them. If true then trees will be knocked down, if   **
//**                      false then the unit will go around them.                     **
//**                                                                                   **
//**    Example of Usage:                                                              **
//**                                                                                   **
//**        call KBS_Begin(target,15.00,0.50,270.00,true)                              **
//**                                                                                   **
//**    This will cause the target unit of a spell to be knocked back 15.00 range      **
//**    every interval, with a 0.50 decrease in speed (so 15.00 then 14.50 then 14.00  **
//**    and so on). It will be knocked back at an angle of 270.00, which I'm pretty    **
//**    sure is south, and it will knock down trees in its path.                       **
//**                                                                                   **
//***************************************************************************************

//***************************************************************************************
//**                                                                                   **
//**    Pros:                                                                          **
//**        - Do not need to write a knockback script yourself.                        **
//**        - Removes the need to write one everytime you need a knockback spell.      **
//**        - Completely self-contained. No need for other systems. MUI and leakless.  **
//**        - Includes a warning message if arguments in the function are invalid.     **
//**        - Easy implementation.                                                     **
//**                                                                                   **
//**    Cons:                                                                          **
//**        - May become tedious to find right length for knockback.                   **
//**        - Uses one dummy unit to knock down trees. This unit however is rarely     **
//**          changed in most maps.                                                    **
//**        - You did not write it yourself. So unless your alright at JASS you will   **
//**          have to read it a few times to get it.                                   **
//**                                                                                   **
//***************************************************************************************

globals
    // CONFIGURABLES:
    private constant integer Dummy_id = 'h000'           // This is the dummy unit.
    private constant real Period = 0.03125               // Recommended Interval.
    private constant real Radius = 150.00                // Radius for killing trees.
    private constant string Attachment_point = "origin"  // Attachment point for effects.
    private constant string Water_SFX = "SlideWater.mdx" // Water slide effect.
    private constant string Dirt_SFX = "Dust.mdx"        // Ground slide effect.
endglobals

//***************************************************************************************
//**                                                                                   ** 
//**          DO NOT TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOUR ARE DOING!             **
//**                                                                                   **
//***************************************************************************************     
globals
    private integer Total = 0
    private integer array DataArray
    private real Game_maxX
    private real Game_minX
    private real Game_maxY
    private real Game_minY
    private rect Rect1 = Rect(0.00,0.00,1.00,1.00)
    private timer Timer = CreateTimer()  
endglobals

private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

// Thanks to PitzerMike for this function.
private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean bool = IsDestructableInvulnerable(dest)
    local unit dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,GetDestructableX(dest),GetDestructableY(dest),0.00)
    local boolean result = false

    call UnitAddAbility(dummy,'Ahrl')
    if bool then
        call SetDestructableInvulnerable(dest,false)
    endif
    set result = IssueTargetOrder(dummy,"harvest",dest)
    call RemoveUnit(dummy)
    if bool then
        call SetDestructableInvulnerable(dest,true)
    endif

    set dest = null
    set dummy = null
    return result
endfunction

private struct Data
    unit targ
    
    real speed
    real decrease
    real sin
    real cos
    
    effect SFX
    integer sfxmode
    boolean killdest
    
    // Checking for terrain type.
    static method TerrainType takes unit u returns integer
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        
        if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            return 1
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            return 2
        endif
        
        return 0
    endmethod
    
    static method create takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns Data
        local Data d 
        
        if Target == null or Startspeed <= 0.00 or Deceleration <= 0.00 then
            call BJDebugMsg("Error: Invalid input in KBS_Begin") // Error message.
            return 0
        endif
        
        // Allocates struct members to user defined variables.
        set d = Data.allocate()
        set d.targ = Target
        set d.speed = Startspeed
        set d.decrease = Deceleration
        set d.sin = Sin(Angle)
        set d.cos = Cos(Angle)
        set d.killdest = Killtrees
        set d.sfxmode = d.TerrainType(d.targ)
        
        // Adding effects to the unit.
        if d.sfxmode == 1 then
            set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 2 then
            set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
        endif
        
        if Total == 0 then
            call TimerStart(Timer,Period,true,function Data.Execute) // Starting timer.
        endif
        
        set DataArray[Total] = d
        set Total = Total + 1
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local integer i = Total - 1
        local Data d
        local real x
        local real y
        local real newx
        local real newy
        
        loop
            exitwhen i < 0
            set d = DataArray<i>
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
                if Total &lt; 0 then
                    call PauseTimer(Timer)
                    set Total = 0
                else
                    set DataArray<i> = DataArray[Total]
                endif
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                call SetUnitPosition(d.targ,newx,newy) // Set units new position.
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1,x-Radius,y-Radius,x+Radius,y+Radius)
                    call EnumDestructablesInRect(Rect1,Condition(function TreeCheck),function KillEnumDestructables)
                endif
                
                set d.sfxmode = d.TerrainType(d.targ) // Checks for pathing again.
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                endif
                
                set d.speed = d.speed - d.decrease // Sets new speed.
            endif
            
            set i = i - 1
        endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .SFX != null then
            call DestroyEffect(.SFX) // Destroys effects if needed.
            set .SFX = null
        endif
    endmethod
endstruct

//***************************************************************************************
//** Only function used by this system. KBS_Begin.                                     **
public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),Killtrees)
endfunction                                                                                                
//**                                                                                   **
//***************************************************************************************

// Sets map boundries.
private function Init takes nothing returns nothing
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-50.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-50.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+50.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+50.00
endfunction

endlibrary</i></i>
 

cleeezzz

The Undead Ranger.
Reaction score
268
hmm i see you called data.execute in the timer, it seems like this method avoids attachment systems (kenny, you know the original trigger? that used CSData) so would it be more effective that way?

EDIT: kenny, thanks for the code, it really helped as an example.

JASS:
library CAS initializer Init

globals  
    private constant real Start = 10.00   
    private constant real Radius = 25.00       
    private constant real Scale = 1            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private timer t = CreateTimer()
endglobals
               
//=======================================================================
private struct Data
    unit u
    unit d
    real cx
    real cy
    real tx
    real ty
    real moved
    real cd
    real maxd
    real dmg
    real angle
    group g1 = CreateGroup()
    group g2 = CreateGroup()
   
    static method create takes string ut, unit u, location l, location tp, real moved, real maxd, real dmg returns Data
        
        local Data d = Data.allocate()

        set d.u = u
        set d.cx = GetUnitX(u)
        set d.cy = GetUnitY(u)
        set d.tx = GetLocationX(tp)
        set d.ty = GetLocationY(tp)
        set d.cd = Start
        set d.maxd = maxd
        set d.angle = AngleXY(d.cx,d.cy,d.tx,d.ty)
        set d.dmg = dmg
        set d.d = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (d.cx, Start, d.angle), PolarProjectionY (d.cy, Start, d.angle) , Rad2Deg(d.angle))
        call SetUnitMoveSpeed(d.d, moved)
        set d.moved = moved

        
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
        call TimerStart(t,Period,true,function Data.Execute)
        
        return Data
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local unit u
        
        
        set d.moved = GetUnitMoveSpeed(d.d)
        set d.cd = d.cd + d.moved
        
            if d.cd &gt;= d.maxd then
                call Data.destroy()
                return
            endif
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)    
        set x = SafeX(PolarProjectionX(x, d.moved, d.angle))
        set y = SafeY(PolarProjectionY(y, d.moved, d.angle))
        
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
        call GroupClear(d.g2)
        call GroupEnumUnitsInRange(d.g2,x,y,Radius,Condition(function CustomFilter))
            
            loop
                set u = FirstOfGroup(d.g2)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g1)) then
                        call GroupAddUnit(d.g1,d.u)
                        call UnitDamageTarget(d.u,u,d.dmg,false,false,A,D,null)
                        call GroupRemoveUnit(d.g2,u)
                    endif                    
                call GroupRemoveUnit(d.g2,u)
            endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call KillUnit(.d)
        call GroupClear(.g1)
        call DestroyGroup(.g1)
        call GroupClear(.g2)
        call DestroyGroup(.g2)
    endmethod
endstruct

private function Init takes nothing returns nothing
endfunction

public function SA takes string ut, unit u, location l, location tp, real moved, real maxd, real dmg returns nothing    
    call Data.create(DummyID,Caster,CasterLoc,TargetPoint,MoveDistance,MaxDistance,Damage)
endfunction  

endlibrary


im getting some errors though.

set d.moved = GetUnitMoveSpeed(d.d) <- this line Error: d is not of a type that allows . syntax

and can you check for any errors? xd

btw i need dummy ID in the function because i wanna be able to create different models of arrows
 

Kenny

Back for now.
Reaction score
202
hmm i see you called data.execute in the timer, it seems like this method avoids attachment systems (kenny, you know the original trigger? that used CSData) so would it be more effective that way?

I called Data.Execute as it is a method that is basically like a callback function, well it has the same properties. It is not needed though. Using callbacks in a struct does not remove the fact that you need an attachment system... The only reason my system does not use an attachment system is because it uses what i think is best called the 'struct array method' (i like that name :)). Basically this method creates separate instances of the struct repeatedly and stores the information from the first to the next and so on. It is probably slower than attachment systems, but as far i know it is safe and works well.

However, for your library in the state it is in you will still need an attachment system, the struct array method is quite complicated, i still dont get the full gist of it. So your library name would be something like:

JASS:
library CAS initializer Init requires CSData


to make sure that CSData is above it in the map header when the map is saved.

JASS:
im getting some errors though.

set d.moved = GetUnitMoveSpeed(d.d) &lt;- this line Error: d is not of a type that allows . syntax


Im pretty sure thats just because you arent using CSData. Try putting it back in the script.

Ill look through it some more and update later.
 

cleeezzz

The Undead Ranger.
Reaction score
268
struct array method..lol? but mine looks just like yours o_O brb, imma search for a tutorial lol.
 

cleeezzz

The Undead Ranger.
Reaction score
268
ok thanks that worked.

JASS:
scope SA initializer InitTrig

private function Damage takes i returns real
    return 133.33+(66.66*i)
endfunction

private function MaxDist takes i returns real
    return 333.33+(666.66*i)
endfunction

//=======================================================================
private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local integer i = GetUnitAbilityLevel(u,GetSpellAbilityId())
    call CAS_SA(&#039;h00J&#039;,u,GetUnitLoc(u),GetSpellTargetLoc(),0.03,33,MaxDist(i),Damage(i))
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;A011&#039; or GetSpellAbilityId() == &#039;A017&#039;
endfunction


//=======================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope


now. using the custom function, tried saving but it says Error:
private function Damage takes i returns real <- expected "returns", but its there?
 

Kenny

Back for now.
Reaction score
202
JASS:
private function Damage takes i returns real


needs to be:

JASS:
private function Damage takes integer i returns real


You forgot to specify variable type.
 

cleeezzz

The Undead Ranger.
Reaction score
268
zomg.

ok all saves good, but not working.

JASS:
library CAS initializer Init requires CSData

globals  
    private constant real Start = 10.00   
    private constant real Radius = 25.00       
    private constant real Scale = 1            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private timer t = CreateTimer()
endglobals
               
//=======================================================================
private struct Data
    unit u
    unit d
    real moved
    real cd
    real maxd
    real dmg
    real angle
    group g1 = CreateGroup()
    group g2 = CreateGroup()
   
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns Data
        
        local Data d = Data.allocate()

        set d.u = u
        set d.cd = Start
        set d.maxd = maxd
        set d.angle = AngleXY(cx,cy,tx,ty)
        set d.dmg = dmg
        set d.d = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, d.angle), PolarProjectionY (cy, Start, d.angle) , Rad2Deg(d.angle))
        call SetUnitMoveSpeed(d.d, moved)
        set d.moved = moved

        
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
        call TimerStart(t,period,true,function Data.Execute)
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local unit u
        local Data d
        
        
        set d.moved = GetUnitMoveSpeed(d.d)
        set d.cd = d.cd + d.moved
        
            if d.cd &gt;= d.maxd then
                call d.destroy()
                return
            endif
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)    
        set x = SafeX(PolarProjectionX(x, d.moved, d.angle))
        set y = SafeY(PolarProjectionY(y, d.moved, d.angle))
        
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
        call GroupClear(d.g2)
        call GroupEnumUnitsInRange(d.g2,x,y,Radius,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(d.g2)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g1)) then
                        call GroupAddUnit(d.g1,d.u)
                        call UnitDamageTarget(d.u,u,d.dmg,false,false,A,D,null)
                        call GroupRemoveUnit(d.g2,u)
                    endif                    
                call GroupRemoveUnit(d.g2,u)
            endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call KillUnit(.d)
        call GroupClear(.g1)
        call DestroyGroup(.g1)
        call GroupClear(.g2)
        call DestroyGroup(.g2)
    endmethod
endstruct

private function Init takes nothing returns nothing
endfunction

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns nothing    
    call Data.create(ut,u,cx,cy,tx,ty,period,moved,maxd,dmg)
endfunction  

endlibrary


JASS:
scope SA initializer InitTrig

private function Damage takes integer i returns real
    return 133.33+(66.66*i)
endfunction

private function MaxDist takes integer i returns real
    return 333.33+(666.66*i)
endfunction

//=======================================================================
private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local integer i = GetUnitAbilityLevel(u,GetSpellAbilityId())
    local real cx = GetUnitX(u)
    local real cy = GetUnitY(u)
    local real tx = GetLocationX(l)
    local real ty = GetLocationY(l)
    call CAS_SA(&#039;h00J&#039;,u,cx,cy,tx,ty,0.03,33,MaxDist(i),Damage(i))
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;A011&#039; or GetSpellAbilityId() == &#039;A017&#039;
endfunction


//=======================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope
 

Kenny

Back for now.
Reaction score
202
What part isn't working? Is it back to not moving? Trying putting some BJDebugMsg's in. Ill keep lookin through it when i can.
 

cleeezzz

The Undead Ranger.
Reaction score
268
yea its not moving plus, dummys don't die either.


edit: ok i got a lead. the dummy movespeed is fine. the set move speed is fine. it appears that either the timer is not working or its not running Data.Execute because i put a debug in the execute but it didn't even show up once.
 

Kenny

Back for now.
Reaction score
202
Your library still needs CSData, just putting it up the top doesnt mean it uses it (Sorry i should have explained better). So you will need to do what you did when it was a spell, use an attachment system.

Also you dont need the Init function either, just remove it and the part up the top where it says: Initializer Init.

Also put the timer back into the struct. Do not use the global one, as there will only be one instance for the timer because it gets destroyed.
 

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:
library CAS requires CSData

globals  
    private constant real Start = 10.00   
    private constant real Radius = 25.00       
    private constant real Scale = 1            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
endglobals
               
//=======================================================================
private struct Data
    unit u
    unit d
    real moved
    real cd
    real maxd
    real dmg
    real angle
    group g1 = CreateGroup()
    group g2 = CreateGroup()
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns Data
        
        local Data d = Data.allocate()
        local timer t = NewTimer()
        call BJDebugMsg(R2S(moved))
        set d.u = u
        set d.cd = Start
        set d.maxd = maxd
        set d.angle = AngleXY(cx,cy,tx,ty)
        set d.dmg = dmg
        set d.d = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, d.angle), PolarProjectionY (cy, Start, d.angle) , Rad2Deg(d.angle))
        call SetUnitMoveSpeed(d.d, moved)
        set d.moved = moved
        call BJDebugMsg(R2S(GetUnitMoveSpeed(d.d)))

        
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
        call TimerStart(t,period,true,function Data.Execute)
        call SetCSData(t,d)
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local unit u
        local Data d = GetCSData(GetExpiredTimer())
        
        set d.moved = GetUnitMoveSpeed(d.d)
        set d.cd = d.cd + d.moved
        
            if d.cd &gt;= d.maxd then
                call d.destroy()
                return
            endif
    
        call BJDebugMsg(R2S(d.cd))

        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)    
        set x = SafeX(PolarProjectionX(x, d.moved, d.angle))
        set y = SafeY(PolarProjectionY(y, d.moved, d.angle))
        
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
        call GroupClear(d.g2)
        call GroupEnumUnitsInRange(d.g2,x,y,Radius,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(d.g2)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g1)) then
                        call GroupAddUnit(d.g1,d.u)
                        call UnitDamageTarget(d.u,u,d.dmg,false,false,A,D,null)
                        call GroupRemoveUnit(d.g2,u)
                    endif                    
                call GroupRemoveUnit(d.g2,u)
            endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call GroupClear(.g1)
        call DestroyGroup(.g1)
        call GroupClear(.g2)
        call DestroyGroup(.g2)
        call ReleaseTimer(t)
    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns nothing    
    call Data.create(ut,u,cx,cy,tx,ty,period,moved,maxd,dmg)
endfunction  

endlibrary


it says the function NewTimer and ReleaseTimer is undefined.
 

Kenny

Back for now.
Reaction score
202
NewTimer() and ReleaseTimer() are CSSafety functions. I suggest you get it, using timers is too hazardous without it. Also make the timer a struct member, cause i think that would be the only way you can release it in the onDestroy method. So something like this:

JASS:
private struct Data
    timer t // The timer
    unit u
    unit d
    real moved
    real cd
    real maxd
    real dmg
    real angle
    group g1 = CreateGroup()
    group g2 = CreateGroup()
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns Data
        
        local Data d = Data.allocate()
        call BJDebugMsg(R2S(moved))
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.maxd = maxd
        set d.angle = AngleXY(cx,cy,tx,ty)
        set d.dmg = dmg
        set d.d = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, d.angle), PolarProjectionY (cy, Start, d.angle) , Rad2Deg(d.angle))
        call SetUnitMoveSpeed(d.d, moved)
        set d.moved = moved
        call BJDebugMsg(R2S(GetUnitMoveSpeed(d.d)))

        
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
        call TimerStart(d.t,period,true,function Data.Execute) // d.t instead of t
        call SetCSData(d.t,d) // same here
        
        return d
    endmethod


then:

JASS:
private method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call GroupClear(.g1)
        call DestroyGroup(.g1)
        call GroupClear(.g2)
        call DestroyGroup(.g2)
        call ReleaseTimer(.t) // . infront of t
    endmethod
 

cleeezzz

The Undead Ranger.
Reaction score
268
ok but i forgot to say, i already have CSSafety which is why this is a problem.
 

cleeezzz

The Undead Ranger.
Reaction score
268
k got one error now.

Missing Requirement: CSSaftey (libraries cannot require scopes)

wait but wtf? cssaftey isnt a scope...

Space or no space, same error
 

cleeezzz

The Undead Ranger.
Reaction score
268
lamee.......

thanks everyone.

EDIT: sigh one more error, the dummy doesn't damage T_T

JASS:
library CAS requires CSData,CSSafety

globals  
    private constant real Start = 30.00   
    private constant real Radius = 50       
    private constant real Scale = 0.6            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
endglobals
               
//=======================================================================
private struct Data
    unit u
    unit d
    real moved
    real cd
    real maxd
    real dmg
    real angle
    group g1 = CreateGroup()
    group g2 = CreateGroup()
    timer t
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns Data
        
        local Data d = Data.allocate()
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.maxd = maxd
        set d.angle = AngleXY(cx,cy,tx,ty)
        set d.dmg = dmg
        set d.d = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, d.angle), PolarProjectionY (cy, Start, d.angle) , Rad2Deg(d.angle))
        call SetUnitMoveSpeed(d.d, moved)
        set d.moved = moved
        
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
        call TimerStart(d.t,period,true,function Data.Execute)
        call SetCSData(d.t,d)
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local unit u
        local Data d = GetCSData(GetExpiredTimer())
        
        set d.moved = GetUnitMoveSpeed(d.d)
        set d.cd = d.cd + d.moved
        
            if d.cd &gt;= d.maxd then
                call d.destroy()
                return
            endif
            
            if d.d == null then
                call d.destroy()
                return
            endif

        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)    
        set x = SafeX(PolarProjectionX(x, d.moved, d.angle))
        set y = SafeY(PolarProjectionY(y, d.moved, d.angle))
        
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
        call GroupClear(d.g2)
        call GroupEnumUnitsInRange(d.g2,x,y,Radius,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(d.g2)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g1)) then
                        call GroupAddUnit(d.g1,u)
                        call UnitDamageTarget(d.u,u,d.dmg,false,false,A,D,null)
                        call GroupRemoveUnit(d.g2,u)
                    endif                    
                call GroupRemoveUnit(d.g2,u)
            endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call GroupClear(.g1)
        call DestroyGroup(.g1)
        call GroupClear(.g2)
        call DestroyGroup(.g2)
        call ReleaseTimer(.t)
    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real moved, real maxd, real dmg returns nothing    
    call Data.create(ut,u,cx,cy,tx,ty,period,moved,maxd,dmg)
endfunction  

endlibrary



JASS:
scope SA initializer Init

private function Damage takes integer i returns real
    return 133.33+(66.66*i)
endfunction

private function MaxDist takes integer i returns real
    return 333.33+(666.66*i)
endfunction

//=======================================================================
private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local integer i = GetUnitAbilityLevel(u,GetSpellAbilityId())
    local real cx = GetUnitX(u)
    local real cy = GetUnitY(u)
    local real tx = GetLocationX(l)
    local real ty = GetLocationY(l)
    call CAS_SA(&#039;h00J&#039;,u,cx,cy,tx,ty,0.03,33,MaxDist(i),Damage(i))
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;A011&#039; or GetSpellAbilityId() == &#039;A017&#039;
endfunction


//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope

JASS:
function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())&gt;0.405
endfunction


(oh and not super important but, it seems the arrow is a little bit off from where you click.)
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      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