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.
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though

      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