• 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.

[JASS] Channel/casting ChecK?

Status
Not open for further replies.
Level 4
Joined
Aug 12, 2004
Messages
76
Hello, I am trying to make multiple channel type spells.

For one thing, I was trying to modify big bad voodoo so that while you are channeling, you heal x hp / second as long as you are casting, but I just couldn't find the right order to check if the unit was still casting.

I was thinking that maybe I could create 2 different triggers with when begin channeling/casting and end channeling/casting, so that I could create global variable, but... i realized that I can't use globals because I have a lot of units that have this ability.

So, is there a way to check whether the units are still channeling or not using local variables?
 
Level 17
Joined
Apr 13, 2008
Messages
1,608
I think a conditional wait is a good idea. If you don't know what's that well go to the Trigger Editor and look up Wait( conditional) then convert it to custom text and you'll get the idea how to use it and what it does.

I don't think there is a way to figure out if the unit is in channeling state or not, but I think when the unit channels the spell its current order will be "channeling of your spell"'s order. So get the unitorderid and use that as a condition.
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Making a trigger would be better.
JASS:
    local trigger t = CreateTrigger()
    call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST) // it is better to be GetTriggerUnit()
    call TriggerAddAction(t, function Stopping_the_effect_of_the_ability)
This should be somewhere in the actions part of the trigger.
You just need to make the spell stop in the function.
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Why should i not be serious?

Making this trigger in the action function of the trigger that runs when the ability is used, will make it fire when the unit stops channeling for any reason.
Now what follows depends.
Turning off a timer, turning off a trigger, setting a boolean variable to true/false.
Handle Variables is recommended for this unless the effect of the spell is in another trigger.

P.s. this is way better, especially when the spell has no cooldown.
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
Well no missunderstands
I have a channel detection system for my spellz which cannot fail whatever happens ^_^ keh keh
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Not every, just when the cooldown is more than duration :p

And yes a trigger requires more code.
But as to which is better it depends, especially on what we are comparing the two methods by :p
 
Level 4
Joined
Aug 12, 2004
Messages
76
Making a trigger would be better.
JASS:
    local trigger t = CreateTrigger()
    call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST) // it is better to be GetTriggerUnit()
    call TriggerAddAction(t, function Stopping_the_effect_of_the_ability)
This should be somewhere in the actions part of the trigger.
You just need to make the spell stop in the function.


Wait... how can it intervene though with local variable? Like it can detect stopping the effect of ability but can that variable be local variable?

So like my spell would be something like

function takes nothing returns nothing

local unit u = unit casting ability
local unit t = target
local boolean casting = true
local trigger t = CreateTrigger()


So I would be doing something like
if casting == true then
do actions
else
do nothing

call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST) // it is better to be GetTriggerUnit()
call TriggerAddAction(t, function Stopping_the_effect_of_the_ability)

^ would I be able to change a local variable from another trigger? Or would it be better to have the effects, checking conditions and stopping the effects as seperate functions?


how would I change a local variable using other triggers?

Sorry I am only a beginner in jass ><
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Wait... how can it intervene though with local variable? Like it can detect stopping the effect of ability but can that variable be local variable?

So like my spell would be something like

function takes nothing returns nothing

local unit u = unit casting ability
local unit t = target
local boolean casting = true
local trigger t = CreateTrigger()


So I would be doing something like
if casting == true then
do actions
else
do nothing

call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST) // it is better to be GetTriggerUnit()
call TriggerAddAction(t, function Stopping_the_effect_of_the_ability)

^ would I be able to change a local variable from another trigger? Or would it be better to have the effects, checking conditions and stopping the effects as seperate functions?


how would I change a local variable using other triggers?

Sorry I am only a beginner in jass ><

JASS:
variable? Like it can detect stopping the effect of ability but can that variable be local variable?

So like my spell would be something like

function takes nothing returns nothing

local unit u = unit casting ability
local unit t = target
local boolean casting = true
local trigger t = CreateTrigger()
call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerAddAction(t, function Stopping_the_effect_of_the_ability)
No need for this if as the trigger will go off instantly when you begin the effect of the ability(if that is the event of the initial trigger).
call TriggerRegisterUnitEvent(t,GetSpellAbilityUnit(), EVENT_PLAYER_UNIT_SPELL_ENDCAST)
When wc3 comes to this line, it will check which unit the GetSpellAbilityUnit()(TriggerUnit(), or a local variable) refers to and will add that unit to the events on the other trigger. It will not add this as an exact string.
About changing local variables in onother trigger - handle variables is the simplest way(though not the fastest)/
 
Level 4
Joined
Aug 12, 2004
Messages
76
Hmm would it be good if like set custom unit value to 1 to represent channeling and custom unit value to 0 to represent not channeling?

Is there more custom value that u can store to a unit than just custom unit value? Or is there more?
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
There is only one custom value u can store per unit.
There are Handle Variables(a great system by KaTTaNa) which allows you to attach unlimited number of variables to stuff(like units)
 
Level 4
Joined
Aug 12, 2004
Messages
76
is there a place where I can learn handle var?
And about structs as well, for I heard handle var is related to structs.
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Structs are by no means required for Handle Variables.
It is vise-versa Handle Variables make usage of local structs in other functions possible.
It is a lil but funny but here you can get the basics of Handle Variables.
 
Last edited:
Level 4
Joined
Aug 12, 2004
Messages
76
JASS:
 function Trig_Spells_Conditions takes nothing returns boolean
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) ) then
        return false
    endif
    return true
endfunction

                    //Big Bad Voodoo Effects                   
function bigbadvoodoo takes nothing returns nothing
    local boolean casting = GethandleBoolean (GetExpiredTimer(), "casting)
    local unit caster = GetHandleUnit (GetExpiredTimer(), "caster")
    local integer heal = GetHandleInt (GetExpiredTimer(), "heal")
        if casting == true then
    call SetUnitState(caster,UNIT_STATE_LIFE,GetUnitState(caster,UNIT_STATE_LIFE) + heal)
    else
    endif
endfunction

                    //Channel Checker
function voodoostopper takes nothing returns nothing
endfunction

                    //Main Body of Spells
function Trig_Spells_Actions takes nothing returns nothing
    local unit caster = GetSpellAbilityUnit()
    local integer spelllevel = GetUnitAbilityLevel (caster, GetSpellAbilityId())
    local timer t = CreateTimer()
    local trigger stopper = CreateTrigger()    
  
    if (GetSpellAbilityId() == 'AOvd') and (spelllevel >= 3) then
        call SetHandleUnit (t, "caster", caster)
        call SetHandleInt (t, "heal", spelllevel * 100)
        call SetHandleBoolean (t, "casting", true)
        call TimerStart (t, 5, true, bigbadvoodoo)
        call TriggerRegisterUnitEvent(stopper, caster, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddAction(stopper, function voodoostopper)
        call TriggerSleepAction (45.00)
        call DestroyTimer(t)        
    else                              
    endif 
    set caster = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Spells takes nothing returns nothing
    set gg_trg_Spells = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spells, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spells, Condition( function Trig_Spells_Conditions ) )
    call TriggerAddAction( gg_trg_Spells, function Trig_Spells_Actions )

I don't know what I am supposed to put for the function voodoo stopper, how do I change the handle variable boolean from there to work on the other one? I am pretty confused because this is my first time even touching the idea of using handle vars, and the only reference I had was the post by spiwn, hopefully I am doing it right...

Help please?

Oh and if you know a place with a good handle var tutorial and structs can you tell me please? I tried searching for it in this website and wc3campaigns, thank you.
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
You are doing it right. I posted again in that thread ;)
As you want a repeatable timer you should also attach an integer.
call SetHandleInt (t, "time", 0).
Do not use TrigerSleepAction!! Timers are used for that.
In the Trig_Spells_Actions do not destroy the timer, just null it.
Do it like this ;)
JASS:
function bigbadvoodoo takes nothing returns nothing
    local timer t=GetExpiredTimer
    local boolean casting = GetHandleBoolean (t, "casting)
    local unit caster
    local integer heal
    local integer i=GetHandleInt(t,"time")
    if ((i<15) and (casting == true) then
    caster = GetHandleUnit (t, "caster")
    heal = GetHandleInt (t, "heal")
    call SetUnitState(caster,UNIT_STATE_LIFE,GetUnitState(caster,UNIT_STATE_LIFE) + heal)
    set caster=null
    else
    call FlushHandleLocals(t)
    call PauseTimer(t)
    call DestroyTimer(t)
    endif
    set t=null
endfunction
This is for that part. Now for stopping you have to do something else - attach the timer to the unit like this:
call SetHandleHandle(caster,"timer",t)
JASS:
function voodoostopper takes nothing returns nothing
call SetHandleBoolean(GetHandleTimer(GetTriggerUnit(),"timer"),"casting",false)
endfunction

The final version should look like this:
JASS:
function Trig_Spells_Conditions takes nothing returns boolean
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) ) then
        return false
    endif
    return true
endfunction

//Big Bad Voodoo Effects
function bigbadvoodoo takes nothing returns nothing
    local timer t=GetExpiredTimer
    local boolean casting = GetHandleBoolean (t, "casting)
local unit caster
    local integer heal
    local integer i=GetHandleInt(t,"time")
    if ((i<15) and (casting == true) then
    caster = GetHandleUnit (t, "caster")
    heal = GetHandleInt (t, "heal")
    call SetUnitState(caster,UNIT_STATE_LIFE,GetUnitState(caster,UNIT_STATE_LIFE) + heal)
    set caster=null
    else
    call FlushHandleLocals(t)
    call PauseTimer(t)
    call DestroyTimer(t)
    endif
    set t=null
endfunction

                    //Channel Checker
function voodoostopper takes nothing returns nothing
call SetHandleBoolean(GetHandleTimer(GetTriggerUnit(),"timer"),"casting",false)
endfunction

                    //Main Body of Spells
function Trig_Spells_Actions takes nothing returns nothing
    local unit caster = GetSpellAbilityUnit()
    local integer spelllevel = GetUnitAbilityLevel (caster, GetSpellAbilityId())
    local timer t = CreateTimer()
    local trigger stopper = CreateTrigger()

    if (GetSpellAbilityId() == 'AOvd') and (spelllevel >= 3) then
        call SetHandleUnit (t, "caster", caster)
        call SetHandleInt (t, "heal", spelllevel * 100)
        call SetHandleBoolean (t, "casting", true)
        call SetHandleBoolean (t, "time", 0)
        call TimerStart (t, 5, true, bigbadvoodoo)
        call SetHandleBoolean(caster, "timer", t)
        call TriggerRegisterUnitEvent(stopper, caster, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddAction(stopper, function voodoostopper)
        call TriggerSleepAction (45.00)
        call DestroyTimer(t)
    else
    endif
    set caster = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Spells takes nothing returns nothing
    set gg_trg_Spells = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spells, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spells, Condition( function Trig_Spells_Conditions ) )
    call TriggerAddAction( gg_trg_Spells, function Trig_Spells_Actions )
Offcourse the thing that i have done with a counter can be done with another timer that runs once and when it finishes sets the boolean variable to false, but if you want to make a spell that does different things you may want a counter.
Also know that handle variables are kinda slow(for performance maniacs) so use as less as possible. To implement this I made this(the same thing without the boolean variable)
JASS:
function Trig_Spells_Conditions takes nothing returns boolean
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) ) then
        return false
    endif
    return true
endfunction

//Big Bad Voodoo Effects
function bigbadvoodoo takes nothing returns nothing
    local timer t=GetExpiredTimer
    local unit caster
    local integer heal
    local integer i=GetHandleInt(t,"time")
    if (i<15) then
    set caster = GetHandleUnit (t, "caster")
    set heal = GetHandleInt (t, "heal")
    call SetUnitState(caster,UNIT_STATE_LIFE,GetUnitState(caster,UNIT_STATE_LIFE) + heal)
    set caster=null
    else
    call FlushHandleLocals(t)
    call PauseTimer(t)
    call DestroyTimer(t)
    endif
    set t=null
endfunction

                    //Channel Checker
function voodoostopper takes nothing returns nothing
call SetHandleint(GetHandleTimer(GetTriggerUnit(),"timer"),"time",20)
endfunction

                    //Main Body of Spells
function Trig_Spells_Actions takes nothing returns nothing
    local unit caster = GetSpellAbilityUnit()
    local integer spelllevel = GetUnitAbilityLevel (caster, GetSpellAbilityId())
    local timer t = CreateTimer()
    local trigger stopper = CreateTrigger()

    if (GetSpellAbilityId() == 'AOvd') and (spelllevel >= 3) then
        call SetHandleUnit (t, "caster", caster)
        call SetHandleInt (t, "heal", spelllevel * 100)
        call SetHandleBoolean (t, "time", 0)
        call TimerStart (t, 5, true, bigbadvoodoo)
        call SetHandleBoolean(caster, "timer", t)
        call TriggerRegisterUnitEvent(stopper, caster, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddAction(stopper, function voodoostopper)
        call TriggerSleepAction (45.00)
        call DestroyTimer(t)
    else
    endif
    set caster = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Spells takes nothing returns nothing
    set gg_trg_Spells = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spells, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spells, Condition( function Trig_Spells_Conditions ) )
    call TriggerAddAction( gg_trg_Spells, function Trig_Spells_Actions )
About structs and handles - to use structs, you have to download the Jass New Gen Pack as they are a part of the vJass(an little bit enhanced version of Jass). If you have downloaded go in the JNGP folder, then in the JassHelper folde and open the manual(an html file). There you can see the basics of structs.
For further tutorials search this site and in here.
When you learn about structs, you have to download a struct attachment system(they are basically like handle variables, but usually are faster and safer, and can attach structs to a variable(like a timer).
 
Last edited:
Level 4
Joined
Aug 12, 2004
Messages
76
Hmm thank you very much!

Although, is it possible for it not to be attached to something other than timers so that I can make the channeling thing for all units kind of general?

For example, maybe something like

When the unit begins casting, without using a timer, that unit is marked as casting. So I could just select that unit and get the attached handle variables directly without having to rely on timer?

So, when it begins casting it would be attached with Handle Var Boolean "casting" true. When it stops casting, it would be attached with handle var boolean "casting" false.
(That's what it does with timer, but so it can be accessed any time without it.)
So, this would be one trigger.
On the main body of spells, when you cast a spell, it checks the handle variable without usimng the timer so that you can just get the handle variable right there.

Is that possibe/
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
As far as I got what you posted I think the answer is yes.
You can attach a variable to anything(not all kinds variables though).
I did that in the code:
SetHandleTimer(GetTriggerUnit(),"timer",t)
(Yes there are mistakes in my code(which I think are corrected now))
That attaches a timer to the unit.
You can attach a boolean too.
 
Level 4
Joined
Aug 12, 2004
Messages
76
As far as I got what you posted I think the answer is yes.
You can attach a variable to anything(not all kinds variables though).
I did that in the code:
SetHandleTimer(GetTriggerUnit(),"timer",t)
(Yes there are mistakes in my code(which I think are corrected now))
That attaches a timer to the unit.
You can attach a boolean too.

So I can basically do

SetHandleBoolean (GetTriggerUnit(), "casting", true)
or
SetHandleint (GetTriggerUnit(), "heal, 100) ?
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
For the purposes you describe it is better to use a boolean.
I used SetHandleint (GetTriggerUnit(), "heal", 100) because in the timer callback I already was checking to see if i<15. So by setting it to 100 i do the same thing, but with less attached objects.
 
Level 4
Joined
Aug 12, 2004
Messages
76
okay I finally think I did this right

JASS:
function Trig_Spell_Casting_End_Conditions takes nothing returns boolean
    if (IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) then
        return true
    else
     return false
    endif
endfunction

function Trig_Spell_Casting_End_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    call SetHandleBoolean (caster, "casting", false)
endfunction

//===========================================================================
function InitTrig_Spell_Casting_End takes nothing returns nothing
    set gg_trg_Spell_Casting_End = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell_Casting_End, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
    call TriggerAddCondition( gg_trg_Spell_Casting_End, Condition( function Trig_Spell_Casting_End_Conditions ) )
    call TriggerAddAction( gg_trg_Spell_Casting_End, function Trig_Spell_Casting_End_Actions )
endfunction

Is the checker and

JASS:
function Trig_Spell_Casting_Start_Conditions takes nothing returns boolean
    if (IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) then
        return true
    else
     return false
    endif
endfunction

function Trig_Spell_Casting_Start_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    call SetHandleBoolean (caster, "casting", true)
endfunction

//===========================================================================
function InitTrig_Spell_Casting_Start takes nothing returns nothing
    set gg_trg_Spell_Casting_Start = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell_Casting_Start, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spell_Casting_Start, Condition( function Trig_Spell_Casting_Start_Conditions ) )
    call TriggerAddAction( gg_trg_Spell_Casting_Start, function Trig_Spell_Casting_Start_Actions )
endfunction

as the beginning of spell casting.

and I can call upon anyhting and flush the triggeredunit of its handle vars but when I save in JNGP, it says SetHandleBoolean isnt a function and it gives me an error. Am I doing something wrong?
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
You sure you have the Handle variable system? It must be somewhere before those trigger(somewhere above it in the actual jass code) using a library is a good way of organizing the order of code(again in the jasshelper manual).
There is a thing about this(those triggers).
1. U can use call SetHandleBoolean (GetTriggerUnit(), "casting", false)
As u need only once to use the unit, there is no need to store it. This way it faster, no need to null anything. I'd suggest this being a local trigger or a function( like StartWaitForEndCast(GetTriggerUnit())
and in the body of that function having a local trigger like the one you made before).
2. This way you will end up with a timer again, as there is no other way to check if the attached variable is a boolean. So this is the same thing as above :)
 
Level 4
Joined
Aug 12, 2004
Messages
76
You sure you have the Handle variable system? It must be somewhere before those trigger(somewhere above it in the actual jass code) using a library is a good way of organizing the order of code(again in the jasshelper manual).
There is a thing about this(those triggers).
1. U can use call SetHandleBoolean (GetTriggerUnit(), "casting", false)
As u need only once to use the unit, there is no need to store it. This way it faster, no need to null anything. I'd suggest this being a local trigger or a function( like StartWaitForEndCast(GetTriggerUnit())
and in the body of that function having a local trigger like the one you made before).
2. This way you will end up with a timer again, as there is no other way to check if the attached variable is a boolean. So this is the same thing as above :)


Lol... I need to have the handle variable system? I thought JGNP just allowed me to use it from the beginning... ><

Sorry... I am very new to jass and all this... How do I put the handle variable system in? I can't seem to find any manual in my JGNP pack either, except for grimoire...
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
You just copy from hereand paste the system in the header of the map(this is in the trigger section at the very top, looks like a map).
There are two lines you should put in the initialization trigger(in the link above) and you should use a global variable of type game cache(you choose the name).
You should write that name in the second function of the handle variable system.
 
Status
Not open for further replies.
Top