HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Interrupting spell loop.

04-10-2007, 04:30 AM#1
Amaroqwlf
I'm making a spell trigger using an ability based on Channel, and I have all of the visual effects and damage working, but I haven't been able to do another thing I want. The spell is supposed to channel (as in, when you stop casting the spell will stop), but none of the things I've tried have resulted in the spell ceasing when the casting unit stops channeling.

The code of the spell's trigger is this:

Hidden information:
Collapse JASS:
function Trig_Blizzard_Test_Copy_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A000' ) ) then
        return false
    endif
    return true
endfunction

function spawnBlizzardEffect takes nothing returns nothing // This function spawns a Blizzard effect at a random point in the target circle.
    local timer t = GetExpiredTimer()
    local string t_table = I2S(CS_H2I( t ))
    local real lev 
    local integer nE = GetTableInt( t_table, "nE")
    local real iE // Interval between Effects.
    local real px 
    local real py 
    local real px2 
    local real py2 
        if ( nE >= 1 ) then
        set px = GetTableReal( t_table , "px")
        set py = GetTableReal( t_table , "py")
        set lev = GetTableReal( t_table , "lev")
        set iE = ( lev * 0.03 + 0.27) / ( lev * 3 )
        set px2 = px + GetRandomReal(0, ( lev * 25 + 70)) * Cos(GetRandomReal(0, 360.00) * bj_DEGTORAD)
        set py2 = py + GetRandomReal(0, ( lev * 25 + 70)) * Sin(GetRandomReal(0, 360.00) * bj_DEGTORAD)
        call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl", px2 , py2 ))
        call TimerStart( t , iE , true, function spawnBlizzardEffect )
    endif
    call SetTableInt( t_table , "nE", nE - 1) // This is how the number of effects is determined.
endfunction

function Trig_Blizzard_Test_Copy_Actions takes nothing returns nothing
    local unit u = GetSpellAbilityUnit()
    local real int = I2R(GetHeroInt( u , true))
    local real lev = I2R(GetUnitAbilityLevel( u , GetSpellAbilityId()))
    local integer nE = R2I( lev ) * 3 // Number of Effects.
    local location p = GetSpellTargetLoc()
    local real px = GetLocationX( p )
    local real py = GetLocationY( p )
    local timer t = CreateTimer()
    local string t_table = I2S(CS_H2I( t ))
    local integer a1 
    local integer a2 
    local integer b1 
    local integer b2 
    call RemoveLocation( p )
    set p = null
    set t_table = I2S(CS_H2I( t ))
    call SetTableReal( t_table , "px", px )
    call SetTableReal( t_table , "py", py )
    call SetTableReal( t_table , "lev", lev )
    set a1 = 1
    set a2 = 4
    loop // This creates four waves, each dealing damage based on intelligence with an AoE based on the spell's level.
        exitwhen a1 > a2 
        call UnitDamagePoint( u , 0.8, ( lev * 25 + 100), px , py , ( int * 2.00), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS)
        call SetTableInt( t_table , "nE", nE)
        call PauseTimer( t )
        call TimerStart( t , 0 , false, function spawnBlizzardEffect ) // Creates the first effect without delay.
        call TriggerSleepAction( 0.75 )
        set a1 = a1 + 1
    endloop
    call CleanAttachedVars( t )
    call PauseTimer( t )
    call DestroyTimer( t )
    set t = null
endfunction

//===========================================================================
function InitTrig_Blizzard_Test_Copy takes nothing returns nothing
    set gg_trg_Blizzard_Test_Copy = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blizzard_Test_Copy, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Blizzard_Test_Copy, Condition( function Trig_Blizzard_Test_Copy_Conditions ) )
    call TriggerAddAction( gg_trg_Blizzard_Test_Copy, function Trig_Blizzard_Test_Copy_Actions )
endfunction


I've tried things such as checking each round to see if the casting unit is == null, but that didn't work (the results of a test I tried seemed to show that GetSpellAbilityUnit() always returns the same unit in the same trigger).

Anyway, I'd like your help in devising some method to cancel the spell when the unit stops channeling the ability. I did look at some other spells listed on these forums that did this, but I couldn't figure out from reading them how they accomplished it. I already know how to stop and cancel the spell; what I need help with is how to detect if the unit is still channeling the Blizzard spell.
04-10-2007, 04:40 AM#2
Zwan
without looking too deeply, the first thing that comes to mind is timers. 90% of my triggered channel spells use timers, and if I need an immediate stop I destroy the timer/s right then.
04-11-2007, 12:28 AM#3
Amaroqwlf
Ah, perhaps I wasn't being clear enough. I do use timers for the effects of the spell. All I really need is a way to check if the unit is still channeling. I'll edit the first post to reflect this more.

EDIT: I'd like to change the thread title to "Detect if a unit is channeling a certain spell."
04-11-2007, 12:44 AM#4
wantok
Set up your channel ability so it gives the casting unit a buff while channeling. Check if the unit has the buff before doing actions.
04-11-2007, 12:49 AM#5
Pyrogasm
You can edit a thread title.

Second, you can check a unit's current order. Each spell/order has a specific OrderId, which you can find out by doing something like this:

Collapse JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    call BJDebugMsg(I2S(GetIssuedOrderId()))
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_001, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_001, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_001, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

A 6-digit number should show up, which is the OrderId of the order issued. After you find out what the orderid is, you can then do a periodic check to see if GetUnitCurrentOrder(YourUnit) == YOUR_ORDERID.

You could also detect the end of a spellcast. EVENT_PLAYER_UNIT_SPELL_ENDCAST detects when a unit finishes casting the spell via the full length of the channel being done. EVENT_PLAYER_UNIT_SPELL_FINISH detects when a unit stops casting/channeling for any reason, be it stun, moving, etc.
04-11-2007, 12:52 AM#6
akolyt0r
I would try something like that:
Collapse JASS:
local trigger t=CreateTrigger()
call TriggerRegisterUnitEvent(t,GetTriggerUnit(),EVENT_UNIT_DEATH) //When Unit Dead= no channeling anymore ^^
call TriggerRegisterUnitEvent(t,GetTriggerUnit(),EVENT_UNIT_SPELL_ENDCAST)
call TriggerRegisterPlayerUnitEventSimple(t,GetOwningPlayer(GetTriggerUnit()),EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddAction(t,function YourFunctionToStoptheSpell) //im to tired right now to really look at your function ...think of something for here for yourself
04-11-2007, 01:32 AM#7
Amaroqwlf
Well, I've got it working the way I want it. I added these lines of code:

Collapse JASS:
local string t_table = I2S(CS_H2I( t ))
local integer uO = GetUnitCurrentOrder( u )
local integer a1 

Collapse JASS:
set a1 = a1 + 1
    if GetUnitCurrentOrder( u ) != uO then
        set a1 = a2 + 1
    endif
endloop

One possible problem I thought of was that if they somehow managed to cast the spell again in a different location then it would allow them to cast both, but a sufficient cooldown period would easily prevent that. However, if it does become a problem, then I will use akolyt0r's suggestion.