Yet another trigger crashing the game

Exide

I am amazingly focused right now!
Reaction score
448
Hi.
As the thread name says, I've got yet another trigger that crashes my game, and I don't know why..
The trigger is for a spell that is supposed to pick all units in *area* and have a dummy unit cast entangling roots on them.
The dummies manages to cast the entangle roots (I can see the spell effect, and hear the sound) but less than half a second after they've cast their spells, the game crashes.

Here's my trigger:
JASS:

function Trig_Entangling_Roots_Conditions takes nothing returns boolean
    return (GetSpellAbilityId() == 'A00A')
endfunction

function EnemiesInRange_func takes nothing returns boolean
    return (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true) and (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false)
endfunction

function Trig_Entangling_Roots_Actions takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local unit u
    local unit t
    local group g = CreateGroup()
    local integer i = GetUnitAbilityLevel(GetTriggerUnit(), 'A00A')
    local real range
    

    if (i == 1) then
        set range = 400
    elseif (i == 2) then
        set range = 450
    elseif (i == 3) then
        set range = 500
    elseif (i == 4) then
        set range = 600
    endif
    
    call GroupEnumUnitsInRange(g, x, y, range, Filter(function EnemiesInRange_func))
    if (CountUnitsInGroup(g) > 0) then
        loop
            exitwhen CountUnitsInGroup(g) == 0
            
            set u = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h005', x, y, 270)
            call UnitAddAbility(u, 'A00B')
            call SetUnitAbilityLevel(u, 'A00B', i)
            call UnitApplyTimedLife(u, 'BTLF', 3)
            
            set t = FirstOfGroup(g)
            call IssueTargetOrder(u, "entanglingroots", t)
            call GroupRemoveUnit(g, t)
            set u = null
            set t = null
        endloop
    endif
    
    call DestroyGroup(g)
    call RemoveLocation(loc)
    set loc = null
    set g = null
endfunction

//===========================================================================
function InitTrig_Entangling_Roots takes nothing returns nothing
    local trigger Entangling_Roots = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Entangling_Roots, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Entangling_Roots, Condition( function Trig_Entangling_Roots_Conditions ) )
    call TriggerAddAction( Entangling_Roots, function Trig_Entangling_Roots_Actions )
endfunction


'A00B' = Entangling Roots (Dummy, target ability)

-I was also wonder if there's a way to "GetSpellTargetX" (and Y), so that I don't have to use a local point variable?

EDIT: The crash is immidiate. (The game just shuts down, no error messages, no nothing.)
EDIT #2: I discovered that if I add a 0.5 sec (and higher, 0.4 and shorter crashes) wait between call UnitApplyTimedLife(u, 'BTLF', 3) and set t = FirstOfGroup(g), the game does not crash.. -Why?
 

emjlr3

Change can be a good thing
Reaction score
395
i guess maybe your loop hits op limit(which should not crash), somehow your dummy casting of roots is making an infinite loop (which would crash), or a data field on the object editor is bogus
 

Jesus4Lyf

Good Idea™
Reaction score
397
Try putting all your loop code inside "EnemiesInRange_func" instead. (Try the below first.)

Edit: Also, just general advice...
JASS:
loop
            set t=FirstOfGroup(g)
            exitwhen t==null
            call GroupRemoveUnit(g, t)

            set u = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h005', x, y, 270)
            call UnitAddAbility(u, 'A00B')
            call SetUnitAbilityLevel(u, 'A00B', i)
            call UnitApplyTimedLife(u, 'BTLF', 3.)
            call IssueTargetOrder(u, "entanglingroots", t)
        endloop
        set u = null

You may not appreciate exactly how much more efficient this is, but it's MUCH better, and may even solve your bug. Oh, and this includes "if (CountUnitsInGroup(g) > 0) then". ;)
 

Exide

I am amazingly focused right now!
Reaction score
448
i guess maybe your loop hits op limit(which should not crash), somehow your dummy casting of roots is making an infinite loop (which would crash), or a data field on the object editor is bogus

Yes, I am suspecting an endless loop to be the problem, but I have no idea why.
This is what my trigger looks like at the moment (I've tried a ton of different things..)

JASS:

function Trig_Entangling_Roots_Conditions takes nothing returns boolean
    return (GetSpellAbilityId() == 'A00A')
endfunction

function EnemiesInRange_func takes nothing returns boolean
    return (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true) and (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true)
endfunction

function Trig_Entangling_Roots_Actions takes nothing returns nothing
    local integer i = GetUnitAbilityLevel(GetTriggerUnit(), 'A00A')
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local unit u = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h005', x, y, 270)
    local unit t
    local real range = 400
    local group g = CreateGroup()
    
    
    if (i == 2) then
        set range = 450
    elseif (i == 3) then
        set range = 500
    elseif (i == 4) then
        set range = 600
    endif
    
    call UnitAddAbility(u, 'A00B')
    call SetUnitAbilityLevel(u, 'A00B', i)
    call UnitApplyTimedLife(u, 'BTLF', 3)
    
    call GroupEnumUnitsInRange(g, x, y, range, Filter(function EnemiesInRange_func))
    if (CountUnitsInGroup(g) > 0) then
        loop
            exitwhen CountUnitsInGroup(g) == 0
            
            set t = FirstOfGroup(g)
            call GroupRemoveUnit(g, t)
            call TriggerSleepAction(0.5)
            call IssueTargetOrder(u, "entanglingroots", t)
            set t = null
        endloop
    endif
        
    call DestroyGroup(g)
    call RemoveLocation(loc)
    set loc = null
    set g = null
    set u = null
endfunction

//===========================================================================
function InitTrig_Entangling_Roots takes nothing returns nothing
    local trigger Entangling_Roots = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Entangling_Roots, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Entangling_Roots, Condition( function Trig_Entangling_Roots_Conditions ) )
    call TriggerAddAction( Entangling_Roots, function Trig_Entangling_Roots_Actions )
endfunction


This works, but it's slow, because of the 0.5 sec wait. If I remove it, or lower it to 0.4 or below, the game crashes.

I have no idea how this trigger could cause an endless loop, since I'm removing FirstOfGroup from *group*, after using it. -So it should only loop X times, where X is the number of units in the group..

EDIT: I've tested the ability without the trigger, it works as it is supposed to (doing nothing). I've also tested 'A00B' (Entangling Roots), it also works. -It costs 1 mana, my dummy unit has 5000, it has 99999 cast range and 0 cooldown.
 

emjlr3

Change can be a good thing
Reaction score
395
systematically eliminate parts of your code until it works
 

Exide

I am amazingly focused right now!
Reaction score
448
If I remove
JASS:

call IssueTargetOrder(u, "entanglingroots", t)


the game does not crash.
 

emjlr3

Change can be a good thing
Reaction score
395
you need a new dummy unit for each cast
 

Exide

I am amazingly focused right now!
Reaction score
448
Exide, you should seriously update your loop to incorporate what I suggested. Count(group)==0 is the same as FirstOfGroup(group)==null here. And you have no idea exactly how much more efficient it is to use FirstOfGroup(group)==null instead.

Indeed I don't. :p
I tried this trigger now:

JASS:

function Trig_Entangling_Roots_Conditions takes nothing returns boolean
    return (GetSpellAbilityId() == 'A00A')
endfunction

function EnemiesInRange_func takes nothing returns boolean
    return (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true) and (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true)
endfunction

function RootSpell_func takes unit whichunit returns nothing
    local integer i = GetUnitAbilityLevel(GetTriggerUnit(), 'A00A')
    local real x = GetUnitX(whichunit)
    local real y = GetUnitY(whichunit)
    local unit u = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h005', x, y, 270)
    
    call UnitAddAbility(u, 'A00B')
    call SetUnitAbilityLevel(u, 'A00B', i)
    call UnitApplyTimedLife(u, 'BTLF', 3)
    call IssueTargetOrder(u, "entanglingroots", whichunit)
    
    set u = null
endfunction


function Trig_Entangling_Roots_Actions takes nothing returns nothing
    local integer i = GetUnitAbilityLevel(GetTriggerUnit(), 'A00A')
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local real range = i * 50 + 400
    local group g = CreateGroup()
    
    
    call GroupEnumUnitsInRange(g, x, y, range, Filter(function EnemiesInRange_func))
    loop
        exitwhen FirstOfGroup(g) == null
        call RootSpell_func(FirstOfGroup(g))
        call GroupRemoveUnit(g,FirstOfGroup(g))
    endloop
    
    call DestroyGroup(g)
    call RemoveLocation(loc)
    set loc = null
    set g = null
endfunction

//===========================================================================
function InitTrig_Entangling_Roots takes nothing returns nothing
    local trigger Entangling_Roots = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Entangling_Roots, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Entangling_Roots, Condition( function Trig_Entangling_Roots_Conditions ) )
    call TriggerAddAction( Entangling_Roots, function Trig_Entangling_Roots_Actions )
endfunction


Probably very effecient, but it still don't work..
 

Kenny

Back for now.
Reaction score
202
JASS:
function Trig_Entangling_Roots_Actions takes nothing returns nothing
    local integer i = GetUnitAbilityLevel(GetTriggerUnit(), 'A00A')
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local real range = i * 50 + 400
    local group g = CreateGroup()
    local unit t = null
    local unit u = null
    
    
    call GroupEnumUnitsInRange(g, x, y, range, Filter(function EnemiesInRange_func))
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g, t)

        set u = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h005', x, y, 270)
        call UnitAddAbility(u, 'A00B')
        call SetUnitAbilityLevel(u, 'A00B', i)
        call UnitApplyTimedLife(u, 'BTLF', 3.)
        call IssueTargetOrder(u, "entanglingroots", t)
    endloop
    
    call DestroyGroup(g)
    call RemoveLocation(loc)
    set loc = null
    set g = null
    set u = null
endfunction


Just use that Jesus4Lyf said. Function calls are slow, and due to how small the loop for this actually is, its probably just better to keep it all within the single function.

I'm not sure if the above will work, but thats how it should be (without errors of course).
 

Exide

I am amazingly focused right now!
Reaction score
448
Just use that Jesus4Lyf said. Function calls are slow, and due to how small the loop for this actually is, its probably just better to keep it all within the single function.

I'm not sure if the above will work, but thats how it should be (without errors of course).

Everyone keeps insuring me that "this way is the most efficient", so I don't know what to believe. :p
I don't care much for efficiency, as long as it works.

I tried your trigger (which is basically the same as my original one, and Jesus4Lyf's trigger - only with a different 'exitwhen -function') the game still crashes. :(
I'm starting to believe that the trigger is innocent, but then again, it works (somewhat) with waits..
 

Jesus4Lyf

Good Idea™
Reaction score
397
From kenny!'s code (which looks good to me)...
Try changing
JASS:
call IssueTargetOrder(u, "entanglingroots", t)

to
JASS:
call IssueTargetOrderById(u,852171,t)

If that works we have a bug to report.

If it doesn't there's two more things.
  1. Your dummy unit may be somehow botched, for example having no model or a botched model, so try changing that (the dummy unit type to a peasant or something).
  2. The order thing of your dummy ability may not be entanglingroots. Check. XD
Don't get too excited to hear suggestions. You have a perculiar bug which no one seems to have any ideas about, so I'm offering the best help I can in the absence of solid advice. But do try these things. :D
 

Exide

I am amazingly focused right now!
Reaction score
448
I seem to have found the answer to my problem.
I based this spell on Flame Strike (because I wanted that pretty 'AoE ring', that I don't know how to get with the ability 'channel'.)
The thing is I had put the same buff on my Flame Strike ability, as on the Entangling Roots (dummy) ability. -And I believe that caused the crash.
Because, when I used a wait the Flame strike buff was removed by the time the dummy buff was applied. Or something..
I never thought that would cause a crash, though.

So yea, changing the buff on the Flame Strike Ability seems to have solved my problem. :)

Thank you everyone for trying to help. Rep will be spread.
 

emjlr3

Change can be a good thing
Reaction score
395
knew it was an object editor issue

nothing in your code screamed crash
 
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