• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

GroupEnumUnitsInRange fails? Help please!

Status
Not open for further replies.
Level 11
Joined
Oct 11, 2012
Messages
711
I am trying to make a spell, its like an AOE life drain, the spell has two triggers. The first trigger is used for selecting a group of enemy units and use dummies to cast magic leash on them. The second trigger is used for causing damage every 0.2 second to the group of units that are effected by the leash.
My problem is that my spell sometimes works and sometimes not.... I really cannot fix it. I just know that the first trigger sometimes fails to select the group (I used the IsUnitGroupEmptyBJ to detect it)..Please help, here are the triggers:(I know that my spell is inefficient and may have MUI issue, but please ignore that for the purpose of this thread, thank you)

The first trigger:
JASS:
function Trig_ChainConditions takes nothing returns boolean
    return ((GetSpellAbilityId() == 'A405'))
endfunction

function Trig_ChainFunc001005 takes nothing returns boolean
    return IsUnitEnemy(GetEnumUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction

function Trig_Chain1 takes nothing returns nothing
    local timer t = GetExpiredTimer()
    call DisableTrigger(gg_trg_chaindamage)
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
endfunction

function Trig_ChainActions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer p = GetPlayerId(GetTriggerPlayer())
    local location stloc = GetSpellTargetLoc()
    local real x = GetLocationX(stloc)
    local real y = GetLocationY(stloc)
    local unit dummy
    local unit u
    local group g = CreateGroup()
    call GroupEnumUnitsInRange( g, GetLocationX(stloc), GetLocationY(stloc), 700.00, Condition(function Trig_ChainFunc001005) )
    set u = FirstOfGroup(g)
    loop
        exitwhen u == null
        set u = FirstOfGroup(g)
        set dummy = CreateUnit(Player(p),'h02X',x,y,bj_UNIT_FACING)
        call ShowUnit(dummy,false)
        call UnitApplyTimedLife( dummy, 'BHwe', 3.20 )
        call IssueTargetOrder( dummy, "magicleash", u )
        call GroupAddUnit(udg_leashgroup,u)
        call GroupRemoveUnit(g,u)
    endloop
    call EnableTrigger(gg_trg_chaindamage)
    call TimerStart(t,3.00,false,function Trig_Chain1)
    call RemoveLocation(stloc)
    set stloc = null
    set t = null
    set dummy = null
    set g = null
endfunction

//===========================================================================
function InitTrig_Chain takes nothing returns nothing
    set gg_trg_Chain = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Chain, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(gg_trg_Chain, Condition(function Trig_ChainConditions))
    call TriggerAddAction(gg_trg_Chain, function Trig_ChainActions)
endfunction

The second trigger:

JASS:
function Trig_chaindamageActions takes nothing returns nothing
    local integer p = GetPlayerId(GetTriggerPlayer())
    local unit u
    set u = FirstOfGroup(udg_leashgroup)
    loop
        exitwhen u == null
        if IsUnitEnemy(u,Player(p)) then
            call UnitDamageTarget( gg_unit_Hblm_0002, u, 100.00, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEMOLITION, WEAPON_TYPE_WHOKNOWS )
            call GroupRemoveUnit(udg_leashgroup,u)
        endif
    endloop
endfunction

//===========================================================================
function InitTrig_chaindamage takes nothing returns nothing
    set gg_trg_chaindamage = CreateTrigger()
    call DisableTrigger(gg_trg_chaindamage)
    call TriggerRegisterTimerEventPeriodic( gg_trg_chaindamage, 0.20 )
    call TriggerAddAction(gg_trg_chaindamage, function Trig_chaindamageActions)
endfunction
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Yes, use filter unit in boolexpr functions. You could use a timer to do the second trigger, and consolidate your triggers to one script, your using jass but doing it the gui triggers way.

EDIT: Good luck practicing scripting.
 
Level 11
Joined
Oct 11, 2012
Messages
711
Yes, use filter unit in boolexpr functions. You could use a timer to do the second trigger, and consolidate your triggers to one script, your using jass but doing it the gui triggers way.

EDIT: Good luck practicing scripting.

Thanks. I spent a whole day to figure out the problem >_<

Yea, I am still learning.. I am a noob....

I will try to improve it as you suggested. +Rep
 
Level 20
Joined
Aug 13, 2013
Messages
1,696
Don't use this because it is slower than coordinates:
JASS:
local location stloc = GetSpellTargetLoc()
local real x = GetLocationX(stloc)
local real y = GetLocationY(stloc)

Will Transform to:

Use coordinates because it is faster, doesn't need to remove because they're reals.
JASS:
local real x = GetSpellTargetX ( )
local real y = GetSpellTargetY ( )

Use this coordinates in your GroumEnums function.

And Also store this to boolexpr expression in Init func:
JASS:
local boolexpr = Condition ( function Trig_ChainFunc001005 )

You can merge the two triggers into 1 trigger by adding function so that it will not needed a two init func.

Anyway Keep Learning and Practicing JASS ^^ and ask questions if you didn't understand :) .
 
Level 11
Joined
Oct 11, 2012
Messages
711
Don't use this because it is slower than coordinates:
JASS:
local location stloc = GetSpellTargetLoc()
local real x = GetLocationX(stloc)
local real y = GetLocationY(stloc)

Will Transform to:

Use coordinates because it is faster, doesn't need to remove because they're reals.
JASS:
local real x = GetSpellTargetX ( )
local real y = GetSpellTargetY ( )

Use this coordinates in your GroumEnums function.

And Also store this to boolexpr expression in Init func:
JASS:
local boolexpr = Condition ( function Trig_ChainFunc001005 )

You can merge the two triggers into 1 trigger by adding function so that it will not needed a two init func.

Anyway Keep Learning and Practicing JASS ^^ and ask questions if you didn't understand :) .

Thanks a lot !! I didn't know that I can use "GetSpellTargetX", LOL. Great.
I am having a problem with another simple spell and have posted the problem here:
http://www.hiveworkshop.com/forums/world-editor-help-zone-98/why-there-always-dummy-created-middle-map-trigger-posted-241854/

Please take a look at it if you have time. Thanks again. :)
 
Level 9
Joined
Dec 3, 2010
Messages
162
If you're coding in JASS, Trigger "Actions" are unnecessary. In fact, you should totally avoid actions and include all your code within your Condition. For example:
JASS:
function OnCast takes nothing returns boolean
    if ((GetSpellAbilityId() == 'A405')) then // your spell condition(s)
        // all your spell code goes here
    endif

    return false // simply return false
endfunction

function InitFunc takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function OnCast))
    // there's no longer a "TriggerAddAction()" anymore
    set t = null
endfunction

Do try avoid using udg variables. You can define globals via JASS.
JASS:
globals
    group LeashGroup
endglobals

Like mentioned above, you don't need a separate trigger for your timer function. An example:
JASS:
globals
    real TimerDuration = 3 // duration
    real TimerPeriod = 0.2 // timer interval
    real TimerCount // a variable to keep track of the current duration left
endglobals

function PeriodicFunc takes nothing returns nothing
    if TimerCount <= 0 then
        call BJDebugMsg("3 seconds have passed! Time to go!")
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    else
        call BJDebugMsg("I'm printing this message every 0.2 seconds!")
        set TimerCount = TimerCount - TimerPeriod
    endif
endfunction

function OnCast takes nothing returns boolean
    local timer t

    if ((GetSpellAbilityId() == 'A405')) then
        // spell codes
        set t = CreateTimer()
        set TimerCount = TimerDuration
        call TimerStart(t, TimerPeriod, true, function PeriodicFunc)
        // spell codes
    endif

    set t = null

    return false
endfunction

function InitFunc takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function OnCast))
    set t = null
endfunction
 
Level 11
Joined
Oct 11, 2012
Messages
711
If you're coding in JASS, Trigger "Actions" are unnecessary. In fact, you should totally avoid actions and include all your code within your Condition. For example:
JASS:
function OnCast takes nothing returns boolean
    if ((GetSpellAbilityId() == 'A405')) then // your spell condition(s)
        // all your spell code goes here
    endif

    return false // simply return false
endfunction

function InitFunc takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function OnCast))
    // there's no longer a "TriggerAddAction()" anymore
    set t = null
endfunction

Do try avoid using udg variables. You can define globals via JASS.
JASS:
globals
    group LeashGroup
endglobals

Like mentioned above, you don't need a separate trigger for your timer function. An example:
JASS:
globals
    real TimerDuration = 3 // duration
    real TimerPeriod = 0.2 // timer interval
    real TimerCount // a variable to keep track of the current duration left
endglobals

function PeriodicFunc takes nothing returns nothing
    if TimerCount <= 0 then
        call BJDebugMsg("3 seconds have passed! Time to go!")
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    else
        call BJDebugMsg("I'm printing this message every 0.2 seconds!")
        set TimerCount = TimerCount - TimerPeriod
    endif
endfunction

function OnCast takes nothing returns boolean
    local timer t

    if ((GetSpellAbilityId() == 'A405')) then
        // spell codes
        set t = CreateTimer()
        set TimerCount = TimerDuration
        call TimerStart(t, TimerPeriod, true, function PeriodicFunc)
        // spell codes
    endif

    set t = null

    return false
endfunction

function InitFunc takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function OnCast))
    set t = null
endfunction

Thanks a lot!!! Your example really helps, its better than a tutorial for me. LOL
+Rep
 
Status
Not open for further replies.
Top