Starting JASS

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
No need to go for struct first, you need it only when you want to play around with periodic thingy.
Follow my steps, you can't go wrong with it. :)

Thanks for the replies guys. I guess I'll go for an instant spell first then, something like a mass sleep
Pretty good choice :p
Try those mass entangle, mass stun stuffs.
If you did it successfully, do post the code here.
You need to get some comment about the optimization.

Have a good time on Jassing!
 

shiFt

Member
Reaction score
8
I found it easier to convert to start this way you learn where the GUI functions come from and this way your knowledge of GUI is passed onto JASS functions, Its quite confusing just jumping right into JASS without understanding how the functions work. By linking it to something you already understand it becomes a bit easier.

Then from there learn natives by converting BJs.
 

Ayanami

칼리
Reaction score
288
Alright, well did my first mass sleep spell and didn't want to create a new thread. Looks like it works fine in-game. So, any "bad" parts I need to note?

JASS:

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    if ( GetSpellAbilityId() == 'ABMS' ) then
        return true
    endif
    return false
endfunction

function Check takes unit caster, unit filter returns boolean
    if IsUnitType(filter, UNIT_TYPE_STRUCTURE) == false and IsUnitType(filter, UNIT_TYPE_DEAD) == false and IsUnitEnemy(filter, GetOwningPlayer(caster)) == true then
        return true
    endif
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit d
    local unit e
    local location cp = GetUnitLoc(c)
    local group g = CreateGroup()
    call GroupEnumUnitsInRange(g, GetUnitX(c), GetUnitY(c), 500.0, null)
    loop
        set e = FirstOfGroup(g)
        call GroupRemoveUnit(g, e)
        exitwhen e == null
        if Check(c, e) == true then
            set d = CreateUnitAtLoc(GetOwningPlayer(c), 'h001', cp, 0)
            call UnitAddAbility(d, 'AMS1')
            call IssueTargetOrder(d, "sleep", e)
            call UnitApplyTimedLife(d, 'BTLF', 1)
        endif
    endloop
    call DestroyGroup(g)
    call RemoveLocation(cp)
    set g = null
    set cp = null
    set e = null
    set d = null
    set c = null
endfunction

//===========================================================================
function InitTrig_Mass_Sleep takes nothing returns nothing
    set gg_trg_Mass_Sleep = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Mass_Sleep, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Mass_Sleep, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction( gg_trg_Mass_Sleep, function Trig_Mass_Sleep_Actions )
endfunction
 

hgkjfhfdsj

Active Member
Reaction score
55
Could you do a quick explanation of a struct?
in layman's terms (and how i usually understand them, i could be wrong, but whatever...), structs are global arrays, with integers as their index numbers.
so when you create structs instances, you are generating global arrays

JASS:
struct Data //declares a new struct type
     unit u // struct members
     effect array sfx[3] //compiles
     group g = CreateGroup() // can be initialized
     Data d //compiles
     thistype t //exactly the same as above

     method get takes nothing returns nothing //methods are like functions, except they work with 'instances'
         call KillUnit(.u) //kills the u of the struct instance
     endmethod

     static method retrieve takes thistype dx returns nothing //works like a functions
         call KillUnit(dx.u)
     endmethod
endstruct
// ...
function actions takes nothing returns nothing
local Data d = Data.create() //creates a new
     set d.u = GetTriggerUnit()
     call d.get() //calls the method, note the syntax 
     call Data.retrieve(d) //doesnt not work with instances 

     call d.destroy() //destroy an instance 
endfunction

storing/retrieving data into these variables would be much more easier and cleaner since you only need to attach the struct, ie an integer.

i think for a more in depth explanation you should read a tutorial (i wouldnt call this an explanantion lol). btw i suggest you start vJASS and skip JASS, if you havent done so already, the benefits are greater than when having to (un)learn jass and then learn vjass
 

Laiev

Hey Listen!!
Reaction score
188
Glenphir i optimized lot the code and commented everything, so any question we can answer

a little explanation... i use CONSTANT variables because constant things you can't change like normal things

example:

JASS:
private constant integer A = 0
private integer B = 0

set A = A + 1 //this don't compile
set B = B + 1 //this compile


JASS:
scope Testing initializer InitTrig //here is the name of function which will initializer, so the name of trigger don't matter anymore

globals
    //here, all the variables names can be ANYTHING what you want
    private constant integer ABILITY_ID = 'ABMS' //here is the ability ID, notice in Condition function, now you use this VARIABLE and not direct integer
    private constant integer DUMMY_ABILITY_ID = 'AMS1' //here is the ability which dummy will use
    private constant integer DUMMY_ID = 'h001' //here is the dummy
endglobals

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABILITY_ID //this will return true if ability id is that or false if not
endfunction

private function Check takes unit caster, unit filter returns boolean
    return not IsUnitType(filter, UNIT_TYPE_STRUCTURE) and not IsUnitType(filter, UNIT_TYPE_DEAD) and IsUnitEnemy(filter, GetOwningPlayer(caster)) //look here, every == false now is "not" before the function
endfunction

private function Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit d
    local unit e
    local group g = CreateGroup()
    local real x = GetUnitX(c) //variable is more fastes then function
    local real y = GetUnitY(c) //same like x
    
    //local location cp = GetUnitLoc(c) you don&#039;t need this <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" /> loc in jass is useless and also you don&#039;t use it in the group function
    
    call GroupEnumUnitsInRange(g, GetUnitX(c), GetUnitY(c), 500.0, null)
    
    loop
        set e = FirstOfGroup(g)
        call GroupRemoveUnit(g, e)
        exitwhen e == null
        if Check(c, e) then //you don&#039;t need == true, just remove it
            set d = CreateUnit(GetOwningPlayer(c), DUMMY_ID, x, y, 0) //notice here, now you use coordinates
            call UnitAddAbility(d, DUMMY_ABILITY_ID)
            call IssueTargetOrder(d, &quot;sleep&quot;, e)
            call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1) // you don&#039;t need to save this buff in global, because is just &#039;generic time&#039;
            set d = null //i do this always, just habit of doing this
        endif
        set e = null //i do this always too, just habit of doing this again lol
    endloop
    
    call DestroyGroup(g)
    // call RemoveLocation(cp) //you don&#039;t use location anymore
    set g = null
    set cp = null
    //set e = null // nulled before, so don&#039;t need here
    //set d = null // nulled before, so don&#039;t need here
    set c = null
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing //this trigger will initializer
    local trigger t = CreateTrigger() //local trigger, so don&#039;t need that long name anymore
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction
endscope


EDIT: note the scope and endscope... i need this to use private members :p
 

Laiev

Hey Listen!!
Reaction score
188
@Crazy
goes by the parties, FirstofGroup is more easy then ForGroup (at least to learn) :rolleyes:
 

Ayanami

칼리
Reaction score
288
Laiev
Thanks for the optimization. Just a few things I want to ask.

1) What exactly is a scope? I don't really get it.

2) What does "private" exactly do? I noticed you used "private" function and "private" integer. Is this different from using "function"?

3) Do I have to always null the local variable before a new value is set or can I null it at the end of the trigger?

Glenphir, dont use FirstOfGroup.
Instead:

JASS:
local /*FOR TEST*/ group Group = CreateGroup
//HumHum.
call GroupEnumUnitsInRect(Group, GetWorldBounds(), Filter(function hasBuff))
call ForGroup(Group, function YouSleepActions)


Better ;)

Tried using ForGroup. I prefer using FirstofGroup though, seems easier, at least to me.
 

Laiev

Hey Listen!!
Reaction score
188
1 - in scope and library you can declare private and public members... i don't know how explain scope exactly but the difference between scope and library is.. scope stay wheres is created (when map save) and you can't requer/use/needs scopes in library. Library you can use needs/uses/requires/optional after the initializer, so the library will change the position when the jasshelper save the map.

example:

JASS:
library TESTC
endlibrary

library TESTB
endlibrary

library TESTA initializer TESTME requires TESTB optional TESTC 
//when you save your map, jass helper will sort your libraries like this, like function... always declare it before use it.. in scope you can&#039;t do this... scope always is the last things in triggers (not last last... but you get it i think)
endlibrary

//also you can&#039;t requires/optional/use/need scopes... just libraries...


2 - private members can have the same name as others variables in others scope/library

3 - I don't know exactly but i always do it... lol
 

hgkjfhfdsj

Active Member
Reaction score
55
link
Initializers are functions which are called when the game is loading. Old Jass initializers would be called InitTrig_TriggerObjectName. Though with vJass, we'll take the neater approach.

Scopes allow you to easily declare initializers with desired function names, as well as use encapsulation (Limiting access to the contents of the scope from things outside of it).

private members cannot be accessed outside of scope eg

so in a way scope keeps things organized like how you would have categories in the trigger list.

JASS:
scope one
globals
       private integer ID = &#039;A000&#039;
       integer AID = &#039;A000&#039;
endglobals
      
       private function test takes nothing returns nothing 
       endfunction
       
       public function test2 takes nothing returns nothing
       endfunction
enscope
scope two
globals
       private integer ID == &#039;A000&#039; //global name redeclared but works b/c of the prefix private
       integer AID = &#039;A000&#039; //does not work
endglobals

       private function test takes nothing returns nothing //function name redeclared but compiles/works
            call one_test2() compiles
       endfunction   

       function test2 takes nothing returns nothing
            call test() //
       endfunction
endscope


3. end of use/trigger
 

saw792

Is known to say things. That is all.
Reaction score
280
(NB: Most of this is vJASS only)

1. A scope is a means of encapsulating a segment of code that performs some particular function. Code placed inside a scope should not need to be accessed anywhere else in the map and allows you to prevent this from occuring. Scopes are good for spells because all the code for that spell can be combined in the one section. Not so good for systems which need to be referenced elsewhere (see JASSHelper manual).

2. "private" in front of a function/global variable/struct within a scope (or library) prevents access to the function/variable/whatever outside the scope (or library) it is declared in. Other alternatives are "public" (allows access outside, but with the scope name prefixed) or no prefix.

Another advantage of using private before function names is you can then reuse function names in other scopes (rather than that ugly Trig_Something_Actions you can just use Actions inside every scope as a private function).

3. Local variables only need to be nulled at the end of functions, and again only if they are of a particular type. Any variable type that extends agent (which you can check in common.j, or just memorise) such as locations, groups, effects, units, and most of the other things you are used to leak-fixing in GUI should be nulled at the end of every function. This is only true for local variables, not global variables or variables passed as arguments to a function.

As for the groups issue: http://www.thehelper.net/forums/showthread.php?t=138374

That is how you use groups.

EDIT: Semi-beaten, but my explanation is probably better. I did forget to mention initializers though. Basically you can specify a function within the scope to be run at map initialization instead of having to rely on those crappy InitTrig_ functions using the initializer keyword as Laiev's example shows.

Libraries are used for system/general map code that you plan to use in multiple other places. Libraries get moved to the top of the map script so you can access them from anywhere else in the script, not just below. This does not occur with scopes. If one library needs functions from another library you can use the requires keyword to make sure they are compiled in the correct order.
 

Laiev

Hey Listen!!
Reaction score
188
other thing :p

public members you can callback outside library/scope but using the prefix name of name of scope/library

example:

JASS:
scope JustMe
globals
    public integer Now = &#039;A000&#039;
endglobals
endscope

library Hey
    set JustMe_Now = &#039;A001&#039;
endlibrary


EDIT: Saw fast :(
 

Crazy_Dead

New Member
Reaction score
24
other thing :p

public members you can callback outside library/scope but using the prefix name of name of scope/library

example:

JASS:
scope JustMe
globals
    public integer Now = &#039;A000&#039;
endglobals
endscope

library Hey
    set JustMe_Now = &#039;A001&#039;
endlibrary

Does that compile? Sweet... Didnt know that :S
 

saw792

Is known to say things. That is all.
Reaction score
280
Well no that won't compile because it's outside of a function in the library Hey. If it was within some function in Hey then yes, it would compile.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Stop, ignore struct first.
Part 1 :
JASS:
function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes unit caster, unit filter returns boolean
    if IsUnitType(filter, UNIT_TYPE_STRUCTURE) == false and IsUnitType(filter, UNIT_TYPE_DEAD) == false and IsUnitEnemy(filter, GetOwningPlayer(caster)) == true then
        return true
    endif
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit d
    local unit e
    local location cp = GetUnitLoc(c)
    local group g = CreateGroup()
    call GroupEnumUnitsInRange(g, GetUnitX(c), GetUnitY(c), 500.0, null)
    loop
        set e = FirstOfGroup(g)
        call GroupRemoveUnit(g, e)
        exitwhen e == null
        if Check(c, e) == true then
            set d = CreateUnitAtLoc(GetOwningPlayer(c), &#039;h001&#039;, cp, 0)
            call UnitAddAbility(d, &#039;AMS1&#039;)
            call IssueTargetOrder(d, &quot;sleep&quot;, e)
            call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1)
        endif
    endloop
    call DestroyGroup(g)
    call RemoveLocation(cp)
    set g = null
    set cp = null
    set e = null
    set d = null
    set c = null
endfunction

//===========================================================================
function InitTrig_Mass_Sleep takes nothing returns nothing
    set gg_trg_Mass_Sleep = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Mass_Sleep, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Mass_Sleep, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction( gg_trg_Mass_Sleep, function Trig_Mass_Sleep_Actions )
endfunction

Part 2 :
JASS:
globals
    unit caster
    player owner
endglobals

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes nothing returns boolean
    local unit u = GetFilterUnit()
    local unit d
    if IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_DEAD) == false and IsUnitEnemy(u, owner) then
        set d = CreateUnit(owner, &#039;h001&#039;, GetUnitX(u),GetUnitY(u), 0.)
        call UnitAddAbility(d, &#039;AMS1&#039;)
        call IssueTargetOrder(d, &quot;sleep&quot;, u)
        call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1.)
        set d = null
    endif
    set u = null
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local group g = CreateGroup()
    set caster = c
    set owner = GetOwningPlayer(c)
    call GroupEnumUnitsInRange(g, GetUnitX(c), GetUnitY(c), 500.0, Condition(function Check))
    call DestroyGroup(g)
    set g = null
    set c = null
endfunction

function InitTrig_Mass_Sleep takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
    //Since you won&#039;t access to gg_trg_Sleep, use local instead.
    //Does not need to null because the trigger will not be destroyed.
endfunction

Part 3 :
JASS:
globals
    unit caster
    player owner
    group enumGroup = CreateGroup()
    //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
endglobals

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes nothing returns boolean
    local unit u = GetFilterUnit()
    local unit d
    if IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_DEAD) == false and IsUnitEnemy(u, owner) then
        set d = CreateUnit(owner, &#039;h001&#039;, GetUnitX(u),GetUnitY(u), 0.)
        call UnitAddAbility(d, &#039;AMS1&#039;)
        call IssueTargetOrder(d, &quot;sleep&quot;, u)
        call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1.)
        set d = null
    endif
    set u = null
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    //Since the spell is instant, it is safe to use globals.
    set caster = GetTriggerUnit()
    set owner = GetOwningPlayer(caster)
    call GroupEnumUnitsInRange(enumGroup, GetUnitX(caster), GetUnitY(caster), 500., Condition(function Check))
endfunction

function InitTrig_Mass_Sleep takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
    //Since you won&#039;t access to gg_trg_Sleep, use local instead.
    //Does not need to null because the trigger will not be destroyed.
endfunction

Part 4 :
JASS:
globals
    unit caster
    player owner
    group enumGroup = CreateGroup()
    //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
    conditionfunc cf
endglobals

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes nothing returns boolean
    local unit u = GetFilterUnit()
    local unit d
    if IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_DEAD) == false and IsUnitEnemy(u, owner) then
        set d = CreateUnit(owner, &#039;h001&#039;, GetUnitX(u),GetUnitY(u), 0.)
        call UnitAddAbility(d, &#039;AMS1&#039;)
        call IssueTargetOrder(d, &quot;sleep&quot;, u)
        call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1.)
        set d = null
    endif
    set u = null
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    //Since the spell is instant, it is safe to use globals.
    set caster = GetTriggerUnit()
    set owner = GetOwningPlayer(caster)
    call GroupEnumUnitsInRange(enumGroup, GetUnitX(caster), GetUnitY(caster), 500., cf)
    //For condition, just set a variable to it instead of keep &quot;creating&quot; Condition, it is faster.
endfunction

function InitTrig_Mass_Sleep takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
    //Since you won&#039;t access to gg_trg_Sleep, use local instead.
    //Does not need to null because the trigger will not be destroyed.
    set cf = Condition(function Check)
    //Initialize it.
endfunction

Part 5 :
JASS:
globals
    unit caster
    player owner
    group enumGroup = CreateGroup()
    //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
    conditionfunc cf
    unit filterUnit
    //Globals, does not need to null
endglobals

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes nothing returns boolean
    set filterUnit = GetFilterUnit()
    local unit d
    if IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) == false and IsUnitType(filterUnit, UNIT_TYPE_DEAD) == false and IsUnitEnemy(filterUnit, owner) then
        set d = CreateUnit(owner, &#039;h001&#039;, GetUnitX(filterUnit),GetUnitY(filterUnit), 0.)
        call UnitAddAbility(d, &#039;AMS1&#039;)
        call IssueTargetOrder(d, &quot;sleep&quot;, filterUnit)
        call UnitApplyTimedLife(d, &#039;BTLF&#039;, 1.)
        set d = null
    endif
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    //Since the spell is instant, it is safe to use globals.
    set caster = GetTriggerUnit()
    set owner = GetOwningPlayer(caster)
    call GroupEnumUnitsInRange(enumGroup, GetUnitX(caster), GetUnitY(caster), 500., cf)
    //For condition, just set a variable to it instead of keep &quot;creating&quot; Condition, it is faster.
endfunction

function InitTrig_Mass_Sleep takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
    //Since you won&#039;t access to gg_trg_Sleep, use local instead.
    //Does not need to null because the trigger will not be destroyed.
    set cf = Condition(function Check)
    //Initialize it.
endfunction

Part 6 :
JASS:
globals
    unit caster
    player owner
    group enumGroup = CreateGroup()
    //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
    conditionfunc cf
    unit filterUnit
    //Globals, does not need to null
    unit dummy
    //Dummy with 0.000 for all animation time.
    //Sleep spell should be 999999.99 on cast range.
    //Don&#039;t remove it, we shall reuse it all the time
endglobals

function Trig_Mass_Sleep_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == &#039;ABMS&#039;
endfunction

function Check takes nothing returns boolean
    set filterUnit = GetFilterUnit()
    if IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) == false and IsUnitType(filterUnit, UNIT_TYPE_DEAD) == false and IsUnitEnemy(filterUnit, owner) then
        call IssueTargetOrder(dummy, &quot;sleep&quot;, filterUnit)
    endif
    return false
endfunction

function Trig_Mass_Sleep_Actions takes nothing returns nothing
    //Since the spell is instant, it is safe to use globals.
    set caster = GetTriggerUnit()
    set owner = GetOwningPlayer(caster)
    call SetUnitOwner(dummy,owner,false)
    //Change the dummy&#039;s owner to caster.
    //You need to do this if you put damaging stuffs in object editor.
    //This is for killing credits.
    call GroupEnumUnitsInRange(enumGroup, GetUnitX(caster), GetUnitY(caster), 500., cf)
    //For condition, just set a variable to it instead of keep &quot;creating&quot; Condition, it is faster.
endfunction

function InitTrig_Mass_Sleep takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
    call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
    //Since you won&#039;t access to gg_trg_Sleep, use local instead.
    //Does not need to null because the trigger will not be destroyed.
    set cf = Condition(function Check)
    //Initialize it.
    set dummy = CreateUnit(Player(15), &#039;h001&#039;, 0., 0., 0.)
    call UnitAddAbility(dummy,SLEEP_ID)
endfunction

Part 7 :
JASS:
library MySpell initializer InitTrig_Mass_Sleep//Scoping is good.
                                //You can prevent any naming repeatation.
                                //Same named function/variables are not allowed in Jass.
                //You need to define the initialization function for scoped scripts, because War3 didn&#039;t know which 1 is yours.
//Ignore &quot;scope&quot;, it is bad. =(
//privatelized it all, since no other place will use it.
    globals
        private unit caster
        private player owner
        private group enumGroup = CreateGroup()
        //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
        //GroupUtils is good choice for it, it provides global enuming group.
        private conditionfunc cf
        private unit filterUnit
        //Globals, does not need to null
        private unit dummy
        //Dummy with 0.000 for all animation time.
        //Sleep spell should be 999999.99 on cast range.
        //Don&#039;t remove it, we shall reuse it all the time.
        //You should use it for all instant dummy spell casting. (Make the dummy library, Jesus4Lyf&#039;s Dummy would be a good choice)
    endglobals

    private function Trig_Mass_Sleep_Conditions takes nothing returns boolean
        return GetSpellAbilityId() == &#039;ABMS&#039;
    endfunction

    private function Check takes nothing returns boolean
        set filterUnit = GetFilterUnit()
        if IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) == false and IsUnitType(filterUnit, UNIT_TYPE_DEAD) == false and IsUnitEnemy(filterUnit, owner) then
            call IssueTargetOrder(dummy, &quot;sleep&quot;, filterUnit)
        endif
        return false
    endfunction

    private function Trig_Mass_Sleep_Actions takes nothing returns nothing
        //Since the spell is instant, it is safe to use globals.
        set caster = GetTriggerUnit()
        set owner = GetOwningPlayer(caster)
        call SetUnitOwner(dummy,owner,false)
        //Change the dummy&#039;s owner to caster.
        //You need to do this if you put damaging stuffs in object editor.
        //This is for killing credits.
        call GroupEnumUnitsInRange(enumGroup, GetUnitX(caster), GetUnitY(caster), 500., cf)
        //For condition, just set a variable to it instead of keep &quot;creating&quot; Condition, it is faster.
    endfunction

    private function InitTrig_Mass_Sleep takes nothing returns nothing
        local trigger trig = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(trig, Condition( function Trig_Mass_Sleep_Conditions ) )
        call TriggerAddAction(trig, function Trig_Mass_Sleep_Actions )
        //Since you won&#039;t access to gg_trg_Sleep, use local instead.
        //Does not need to null because the trigger will not be destroyed.
        set cf = Condition(function Check)
        //Initialize it.
        set dummy = CreateUnit(Player(15), &#039;h001&#039;, 0., 0., 0.)
        call UnitAddAbility(dummy,SLEEP_ID)
    endfunction
endlibrary

Part 8 :
JASS:
library Sleepy initializer Init//Scoping is good.
        //I want the spell name to be Sleepy, hence the library would be Sleepy.
                                //You can prevent any naming repeatation.
                                //Same named function/variables are not allowed in Jass.
                //You need to define the initialization function for scoped scripts, because War3 didn&#039;t know which 1 is yours.
//Ignore &quot;scope&quot;, it is bad. =(
//privatelized it all, since no other place will use it.
    globals
        private unit caster
        private player owner
        private group enumGroup = CreateGroup()
        //Since you are creating and destroying group everytime, why not just create it at init and reuse it?
        //GroupUtils is good choice for it, it provides global enuming group.
        private conditionfunc cf
        private unit filterUnit
        //Globals, does not need to null
        private unit dummy
        //Dummy with 0.000 for all animation time.
        //Sleep spell should be 999999.99 on cast range.
        //Don&#039;t remove it, we shall reuse it all the time.
        //You should use it for all instant dummy spell casting. (Make the dummy library, Jesus4Lyf&#039;s Dummy would be a good choice)
    endglobals

    private function SleepUnits takes nothing returns boolean
        set filterUnit = GetFilterUnit()
        if IsUnitType(filterUnit,UNIT_TYPE_STRUCTURE) == false and IsUnitType(filterUnit,UNIT_TYPE_DEAD) == false and IsUnitEnemy(filterUnit,owner) then
            call IssueTargetOrder(dummy,&quot;sleep&quot;,filterUnit)
        endif
        return false
    endfunction

    private function Act takes nothing returns nothing
        //Since the spell is instant, it is safe to use globals.
        set caster = GetTriggerUnit()
        set owner = GetOwningPlayer(caster)
        call SetUnitOwner(dummy,owner,false)
        //Change the dummy&#039;s owner to caster.
        //You need to do this if you put damaging stuffs in object editor.
        //This is for killing credits.
        call GroupEnumUnitsInRange(enumGroup,GetUnitX(caster),GetUnitY(caster),500.,cf)
        //For condition, just set a variable to it instead of keep &quot;creating&quot; Condition, it is faster.
    endfunction

    private function Cond takes nothing returns boolean
        return GetSpellAbilityId() == &#039;ABMS&#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 Cond))
        call TriggerAddAction(trig,function Act)
        //Since you won&#039;t access to gg_trg_Sleep, use local instead.
        //Does not need to null because the trigger will not be destroyed.
        set cf = Condition(function SleepUnits)
        //Initialize it.
        set dummy = CreateUnit(Player(15),&#039;h001&#039;,0.,0.,0.)
        call UnitAddAbility(dummy,SLEEP_ID)
    endfunction
endlibrary

Part 9*Last :
JASS:
library Sleepy initializer Init

    globals
        private constant integer SPELL_ID = &#039;ABMS&#039;
        private constant integer SLEEP_ID = &#039;AMS1&#039;
        private constant string SPELL_ORDER = &quot;sleep&quot;
        private constant integer DUMMY_ID = &#039;h001&#039;
        //For easier configuration.
    endglobals
    
    globals
        private unit caster
        private player owner
        private group enumGroup = CreateGroup()
        private conditionfunc cf
        private unit filterUnit
        private unit dummy
    endglobals

    private function SleepUnits takes nothing returns boolean
        set filterUnit = GetFilterUnit()
        if IsUnitType(filterUnit,UNIT_TYPE_STRUCTURE) == false and IsUnitType(filterUnit,UNIT_TYPE_DEAD) == false and IsUnitEnemy(filterUnit,owner) then
            call IssueTargetOrder(dummy,SPELL_ORDER,filterUnit)
        endif
        return false
    endfunction

    private function Act takes nothing returns nothing.
        set caster = GetTriggerUnit()
        set owner = GetOwningPlayer(caster)
        call SetUnitOwner(dummy,owner,false)
        call GroupEnumUnitsInRange(enumGroup,GetUnitX(caster),GetUnitY(caster),500.,cf)
    endfunction

    private function Cond takes nothing returns boolean
        return GetSpellAbilityId() == SPELL_ID
    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 Cond))
        call TriggerAddAction(trig,function Act)

        set cf = Condition(function SleepUnits)
        set dummy = CreateUnit(Player(15),DUMMY_ID,0.,0.,0.)
        call UnitAddAbility(dummy,SLEEP_ID)
    endfunction
endlibrary

Another optimization :
JASS:
library Sleepy initializer Init requires GT, GroupUtils, DummyCaster//Those libraries can help you to make your spell for efficient.

    globals
        private constant integer SPELL_ID = &#039;ABMS&#039;
        private constant integer SLEEP_ID = &#039;AMS1&#039;
        private constant string SPELL_ORDER = &quot;sleep&quot;
        //For easier configuration.
    endglobals
    
    globals
        private unit caster
        private player owner
        private conditionfunc cf
        private unit filterUnit
    endglobals

    private function SleepUnits takes nothing returns boolean
        set filterUnit = GetFilterUnit()
        if not IsUnitType(filterUnit,UNIT_TYPE_STRUCTURE) and not IsUnitType(filterUnit,UNIT_TYPE_DEAD) and IsUnitEnemy(filterUnit,owner)/*=true as default*/ then
            call UnitAddAbility(DUMMY,SLEEP_ID)
            call SetUnitOwner(DUMMY,owner,false)
            call IssueTargetOrder(DUMMY,SPELL_ORDER,filterUnit)
//We use dummy from DummyCaster by jesus4lyf
            call UnitRemoveAbility(DUMMY,SLEEP_ID)
        endif
        return false
    endfunction

    private function Act takes nothing returns boolean
        set caster = GetTriggerUnit()
        set owner = GetOwningPlayer(caster)
        call GroupEnumUnitsInRange(ENUMGROUP,GetUnitX(caster),GetUnitY(caster),500.,cf)
        //ENUMGROUP is from GroupUtils.
        return false
        //Return false, required by GT.
    endfunction
    
    private function Init takes nothing returns nothing
        call GT_AddStartEffectsAction(function Act,SPELL_ID)
        //GT, automatic register spell for you, does not requires condition if you used it.
        
        set cf = Condition(function SleepUnits)
    endfunction
endlibrary
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
^
don't you need to move the dummy first before casting?
you could give him a large cast range, but moving him would be safer

EDIT: nvm

I guess DummyCaster solves that
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
^
don't you need to move the dummy first before casting?
you could give him a large cast range, but moving him would be safer

As long as the sleep spell is instant, without casting time, missle, it is safe.
This method never fails for me.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top