• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Some questions about vJass

Status
Not open for further replies.
Level 17
Joined
Mar 21, 2011
Messages
1,611
Hi again,

I created this trigger just for efficiency and wanna ask if it is fine

JASS:
function PlayerUnitEvent takes trigger t, playerunitevent e returns nothing
    set bj_forLoopAIndex = 0
    loop
        exitwhen bj_forLoopAIndex == 11
        if GetPlayerController(Player(bj_forLoopAIndex)) == MAP_CONTROL_USER then
            call TriggerRegisterPlayerUnitEvent(t, Player(bj_forLoopAIndex), e, null)
        endif
        set bj_forLoopAIndex = bj_forLoopAIndex+1
    endloop
endfunction

JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call PlayerUnitEvent( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Condition( function Trig_Sand_Pulse_Conditions ) )
    call TriggerAddAction( t, function Trig_Sand_Pulse_Actions )
    set t = null
endfunction

also, should i use bj_forLoopAIndex in my loop or create my own local counter variable for that?

thanks
 
Level 18
Joined
May 11, 2012
Messages
2,103
Hi again,

I created this trigger just for efficiency and wanna ask if it is fine

JASS:
function PlayerUnitEvent takes trigger t, playerunitevent e returns nothing
    set bj_forLoopAIndex = 0
    loop
        exitwhen bj_forLoopAIndex == 11
        if GetPlayerController(Player(bj_forLoopAIndex)) == MAP_CONTROL_USER then
            call TriggerRegisterPlayerUnitEvent(t, Player(bj_forLoopAIndex), e, null)
        endif
        set bj_forLoopAIndex = bj_forLoopAIndex+1
    endloop
endfunction

JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call PlayerUnitEvent( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Condition( function Trig_Sand_Pulse_Conditions ) )
    call TriggerAddAction( t, function Trig_Sand_Pulse_Actions )
    set t = null
endfunction

also, should i use bj_forLoopAIndex in my loop or create my own local counter variable for that?

thanks

Creating your own local variable is better I guess
 
Just use a local integer for it. Also no need to call this extra function for your event. Just make the loop inside your "InitTrig_Sand_Pulse" function.

You can store Player(index) into a local player variable to reduce function calls in case you add the event.

Also change "Condition (function YourFunc)" to "Filter (function YourFunc)"
 
Level 11
Joined
Dec 19, 2012
Messages
411
In my opinion, using bj_forLoopAIndex is fine as long as you didn't use it 2nd time while any loop is using it (to prevent collide better use local variable).

Why don't u directly use TriggerRegisterAnyUnitEventBJ ?

Also, this is NOT vJASS, it is JASS.

Also change "Condition (function YourFunc)" to "Filter (function YourFunc)"

Just want to know, why it should change to Filter?
 
Last edited:
Level 17
Joined
Mar 21, 2011
Messages
1,611
Why don't u directly use TriggerRegisterAnyUnitEventBJ ?
because the map has only 12 players and it loops through 16

Just use a local integer for it. Also no need to call this extra function for your event. Just make the loop inside your "InitTrig_Sand_Pulse" function.

You can store Player(index) into a local player variable to reduce function calls in case you add the event.

Also change "Condition (function YourFunc)" to "Filter (function YourFunc)"
what i wanted to do is create a function for all my spells that only includes the needed players. so wouldnt it be a lot of work to put every single spell event in there? maybe i understood it wrong
 
You could easily do one loop in init function for all your events:

JASS:
local integer i = 0
local player p
loop
    set p = Player(i)
    if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
        call TriggerRegisterPlayerUnitEvent(trigger1, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        ... // all player events
    endif
    set i = i + 1
    exitwhen i > 11
endloop
 
The condition/filter function is like a normal function but which returns a boolean value. You can normaly declare and initialisize local variables as you do in your Action functions.

Or did we misunderstand something maybe?

You are correct.

Condition / Action functions are still functions. Local variables must be declared at the top of any function.

Example:
JASS:
function test takes nothing returns nothing
    local unit u
endfunction

I declared the local unit variable in the function above.
 
Level 17
Joined
Mar 21, 2011
Messages
1,611
JASS:
function SandPulseConditionsAndActions takes nothing returns boolean
    if (GetSpellAbilityId() == 'A019') then
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
        call UnitApplyTimedLife(d, 'BTLF', 1.00)
        call GroupEnumUnitsInRange(TempGroup, x, y, 325.00, null)    
        loop
            set fog = FirstOfGroup(TempGroup)
            exitwhen fog == null
            if IsUnitAlive(fog) and IsUnitEnemy(fog, p) then
                call IssueTargetOrder(d, "curse", fog)
            endif
            call GroupRemoveUnit(TempGroup, fog)
        endloop
        set u = null
        set d = null
        set p = null
        set fog = null
    endif
    return false
endfunction
//===========================================================================
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call Filter( t, Condition( function SandPulseConditionsAndActions ) )
    set t = null
endfunction

For this example, i replaced Condition with filter, but now it gives me an error that the variables arent at the top of the trigger, where to put them now?
Also the trigger is put into a local variable t so i cant catch it with this one:

JASS:
        set i = 0
        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerUnitEvent(???!??!?!!??, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
                //all player events
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
 
JASS:
function SandPulseConditionsAndActions takes nothing returns boolean
    if (GetSpellAbilityId() == 'A019') then
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
        call UnitApplyTimedLife(d, 'BTLF', 1.00)
        call GroupEnumUnitsInRange(TempGroup, x, y, 325.00, null)    
        loop
            set fog = FirstOfGroup(TempGroup)
            exitwhen fog == null
            if IsUnitAlive(fog) and IsUnitEnemy(fog, p) then
                call IssueTargetOrder(d, "curse", fog)
            endif
            call GroupRemoveUnit(TempGroup, fog)
        endloop
        set u = null
        set d = null
        set p = null
        set fog = null
    endif
    return false
endfunction
//===========================================================================
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call Filter( t, Condition( function SandPulseConditionsAndActions ) )
    set t = null
endfunction

For this example, i replaced Condition with filter, but now it gives me an error that the variables arent at the top of the trigger, where to put them now?
Also the trigger is put into a local variable t so i cant catch it with this one:

JASS:
        set i = 0
        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerUnitEvent(???!??!?!!??, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
                //all player events
            endif
            set i = i + 1
            exitwhen i > 11
        endloop

That is because they are not at the top of your function.
This
JASS:
    if (GetSpellAbilityId() == 'A019') then
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
Has to be like this.
JASS:
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
    if (GetSpellAbilityId() == 'A019') then

This
JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call Filter( t, Condition( function SandPulseConditionsAndActions ) )
    set t = null
endfunction

Needs to be this.
JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Condition( function SandPulseConditionsAndActions ) )
    set t = null
endfunction

You should look up a tutorial on local variables to better understand them.
 
Level 17
Joined
Mar 21, 2011
Messages
1,611
ok, but now it looks like the variables are declared BEFORE the condition is checked. Does that mean that they will run for every spell cast?
also, if i put the trigger into a local, i have to use the TriggerRegisterAnyUnitEventBJ, so what is more efficient now? Because i will loop through unnecessary players then
 
Nope, it's no problem if trigger is local variable. Imagine in this post that "trigger1" is a local trigger variable: http://www.hiveworkshop.com/forums/...ome-questions-about-vjass-250339/#post2508725

And yes, you create variables before conditions are checked. And as a filter condition should return a boolean you have to return false in end of function, else it would try to run the ActionFunction after, which does not exist anymore. (this way it's a bit faster)
 
Level 17
Joined
Mar 21, 2011
Messages
1,611
This is my current result:

JASS:
function SandPulseConditionsAndActions takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
    if (GetSpellAbilityId() == 'A019') then
        call UnitApplyTimedLife(d, 'BTLF', 1.00)
        call GroupEnumUnitsInRange(TempGroup, x, y, 325.00, null)    
        loop
            set fog = FirstOfGroup(TempGroup)
            exitwhen fog == null
            if IsUnitAlive(fog) and IsUnitEnemy(fog, p) then
                call IssueTargetOrder(d, "curse", fog)
            endif
            call GroupRemoveUnit(TempGroup, fog)
        endloop
    endif
        set u = null
        set d = null
        set p = null
        set fog = null
        return false
endfunction
//===========================================================================
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Filter( function SandPulseConditionsAndActions ) )
    set t = null
endfunction


Nope, it's no problem if trigger is local variable. Imagine in this post that "trigger1" is a local trigger variable: http://www.hiveworkshop.com/forums/w...9/#post2508725

.. sorry, maybe i'm just too stupid, but i dont get it.
let me explain my problem:

JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Filter( function SandPulseConditionsAndActions ) )
    set t = null
endfunction

i create a local trigger variable t, and it gets removed after that. So i cant catch it in this one as "t"?:


JASS:
        set i = 0
        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerUnitEvent( ---->  t  <---- , p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
                //all player events
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
 
Yo looks ok now. Only watch on indention. (after your endif)

JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t, Filter( function SandPulseConditionsAndActions ) )
    set t = null
endfunction
--> (what you want)
JASS:
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    local player p
    local integer i = 0
        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
                //all player events if more needed (for other triggers)
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
    call TriggerAddCondition( t, Filter( function SandPulseConditionsAndActions ) )
endfunction
And no need to null your "fog" unit variable because you you exit your loop if fog equals null.
 
Level 17
Joined
Mar 21, 2011
Messages
1,611
aaah so i have to put the loop into the IntTrig_Sand_Pulse, oh i missunderstood something the whole time.. thank you.

now 2 little questions left.
1. dont i have to null the local trigger and local player?

2.
JASS:
    globals
        

            group TempGroup
            
    endglobals
i created a global group for my spells so i can add/remove units from it like i used it in this spell. But seems like it doesnt work :/
before, i used a udg_TempGroup variable from the variable editor and this one worked for me
 
1. No, you do not need null this local trigger unless you don't destroy it. Basicly if you will never destroy a handle there is no sense to null it.

Nulling players.... maybe noone can answer you that question. I'm not very sure here. Actually it would be logical that you don't have to null players, because players always exist and should never be removed.

But some people say they may leak because blizzard was just nap at it's implementation. Me personaly don't null them, but it's up to you I guess.

2. group TempGroup = CreateGroup()

Same for forces/hashtables... you have to initialisize these stuff, with the GUI it happens automatically. :)
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
Also keep in mind that triggers are not directly stored in variables. Variables of the "trigger" type are actually pointers to actual triggers.
It is hinted at by having Create/Destroy functions for them.

This means that although your trigger variable may be local, the actual trigger can not be. As long as you have any variable to use for registering conditions, you can register things to it.
Putting the trigger into a local variable means that you can't register anything to that trigger later. But you can during that one function.
 
Level 17
Joined
Mar 21, 2011
Messages
1,611
JASS:
function SandPulseConditionsAndActions takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetTriggerPlayer()
        local unit d = CreateUnit(p, 'h00B', x, y, 0)
        local unit fog
    if (GetSpellAbilityId() == 'A019') then
        call UnitApplyTimedLife(d, 'BTLF', 1.00)
        call GroupEnumUnitsInRange(TempGroup, x, y, 325.00, null)    
        loop
            set fog = FirstOfGroup(TempGroup)
            exitwhen fog == null
            if IsUnitAlive(fog) and IsUnitEnemy(fog, p) then
                call IssueTargetOrder(d, "curse", fog)
            endif
            call GroupRemoveUnit(TempGroup, fog)
        endloop
    endif
        set u = null
        set d = null
        set p = null
        return false
endfunction
//===========================================================================
function InitTrig_Sand_Pulse takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    local player p
    local integer i = 0
        loop
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
    call TriggerAddCondition( t, Filter( function SandPulseConditionsAndActions ) )
    set p = null
endfunction


thanks so much to all who helped me, especially IcemanBo!!!
 
Status
Not open for further replies.
Top