• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] EnumUnitsInRange not working.

Status
Not open for further replies.
Level 21
Joined
Mar 27, 2012
Messages
3,232
Yesterday I coded a spell that's mostly working fine, but for some reason I can't manage to fix one part of the configuration that definitely has to exist.

The spell:

Whirling Slash - Makes you move forward a small distance while spinning, dealing damage to anything you move past.

Basically the problem is that units are not added to the group by EnumUnitsInRange, which causes the SINGLE_DAMAGE_EVENT option to never work right.
It took me an hour to write the spell and I've spent several hours trying to fix this now, but with no results.

JASS:
library EtherealWhirl initializer in
    globals
        private trigger CastTrig                        = CreateTrigger()
        private trigger LoopTrig                        = CreateTrigger()
        
        private unit array Unit
        private real array Damage
        private integer array Ticks
        private real array Angle
        private group array Victims
        private integer Units                           = 0
        
        private constant integer ETHEREAL_WHIRL_ABIL    = 'A000'
        private constant boolean SINGLE_DAMAGE_EVENT    = true //Determines whether the spell can damage each victim only once (easier to balance)
        private constant boolean CAN_DAMAGE_SELF        = false
        private constant real LOOP_PERIOD               = 0.0312500
        private constant real AOE                       = 300
        private constant real DURATION                  = 1.8   //Seconds
        
        private unit u
        private group g
        private integer i
    endglobals
    
    private function Cast takes nothing returns boolean
        local unit u = GetTriggerUnit()
        if GetSpellAbilityId() == ETHEREAL_WHIRL_ABIL then
            set Units = Units + 1
            set Unit[Units] = u
            set Ticks[Units] = R2I(DURATION/LOOP_PERIOD)/*
            //The magical formula called AngleBetweenPoints.*/
            set Angle[Units] = 57.32 * Atan2(GetSpellTargetY() - GetUnitY(u), GetSpellTargetX() - GetUnitX(u))
            set Victims[Units] = CreateGroup()
            static if SINGLE_DAMAGE_EVENT then
                set Damage[Units] = I2R(GetHeroAgi(u,true))*2
            else
                set Damage[Units] = I2R(GetHeroAgi(u,true))*2*LOOP_PERIOD
            endif
            call EnableTrigger(LoopTrig)
        endif
        set u = null
        return false
    endfunction
    
    private function IsNotGrouped takes nothing returns boolean
        static if not(CAN_DAMAGE_SELF) then
            if GetFilterUnit() == u  then
                return false
            endif
        endif
        static if SINGLE_DAMAGE_EVENT then
            if IsUnitInGroup(GetFilterUnit(),g) == false then
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Adding to group")
                call UnitDamageTarget(u,GetFilterUnit(),Damage[i],true,true,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
            endif
        else
            call UnitDamageTarget(u,GetFilterUnit(),Damage[i],true,true,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
        endif
        return true
    endfunction
    
    private function Loop takes nothing returns boolean
        local real dist
        set i = 1
        loop
            exitwhen i > Units
                set u = Unit[i]
                set dist = GetUnitMoveSpeed(u)*1.5*LOOP_PERIOD
                call SetUnitX(u, GetUnitX(u) + dist * Cos(Angle[i] * bj_DEGTORAD))
                call SetUnitY(u, GetUnitY(u) + dist * Sin(Angle[i] * bj_DEGTORAD))
                set g = Victims[i]
                call GroupEnumUnitsInRange(g,GetUnitX(u),GetUnitY(u),AOE,Filter(function IsNotGrouped))
                set Ticks[i] = Ticks[i] - 1
                if Ticks[i] == 0 then
                    set Unit[i] = Unit[Units]
                    set Damage[i] = Damage[Units]
                    set Ticks[i] = Ticks[Units]
                    set Angle[i] = Angle[Units]
                    call DestroyGroup(Victims[i])
                    set Victims[i] = Victims[Units]
                    set Victims[Units] = null
                    set Units = Units - 1
                else
                    set i = i + 1
                endif
        endloop
        if Units == 0 then
            call DisableTrigger(LoopTrig)
        endif
        //set g = null
        set u = null
        return false
    endfunction
    
    private function in takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 15
            call TriggerRegisterPlayerUnitEvent(CastTrig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
            set i = i + 1
        endloop
        call TriggerRegisterTimerEvent(LoopTrig,LOOP_PERIOD,true)
        call TriggerAddCondition(CastTrig,Condition(function Cast))
        call TriggerAddCondition(LoopTrig,Condition(function Loop))
    endfunction
endlibrary
 

Attachments

  • Ethereal Whirl.w3x
    10.6 KB · Views: 35
Last edited:
Level 22
Joined
Sep 24, 2005
Messages
4,821
You shouldn't use the same group you use to store the units affected with the temporary one you're using for enumerations.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Yes, it's as Bannar says.

EDIT: Dunno if you need it though... but here is a
JASS:
library EtherealWhirl initializer in
    globals
        private trigger CastTrig                        = CreateTrigger()
        private trigger LoopTrig                        = CreateTrigger()
        
        private unit array Unit
        private real array Damage
        private integer array Ticks
        private real array Angle
        private group array Victims
        private integer Units                           = 0
        
        private constant integer ETHEREAL_WHIRL_ABIL    = 'A000'
        private constant boolean SINGLE_DAMAGE_EVENT    = true //Determines whether the spell can damage each victim only once (easier to balance)
        private constant boolean CAN_DAMAGE_SELF        = false
        private constant real LOOP_PERIOD               = 0.0312500
        private constant real AOE                       = 300
        private constant real DURATION                  = 1.8   //Seconds
        
        private unit u
        private group g
        private group tg=CreateGroup() // Quickfix line; tempgroup
        private integer i
    endglobals
    
    private function Cast takes nothing returns boolean
        local unit u = GetTriggerUnit()
        if GetSpellAbilityId() == ETHEREAL_WHIRL_ABIL then
            set Units = Units + 1
            set Unit[Units] = u
            set Ticks[Units] = R2I(DURATION/LOOP_PERIOD)/*
            //The magical formula called AngleBetweenPoints.*/
            set Angle[Units] = 57.32 * Atan2(GetSpellTargetY() - GetUnitY(u), GetSpellTargetX() - GetUnitX(u))
            set Victims[Units] = CreateGroup()
            static if SINGLE_DAMAGE_EVENT then
                set Damage[Units] = I2R(GetHeroAgi(u,true))*2
            else
                set Damage[Units] = I2R(GetHeroAgi(u,true))*2*LOOP_PERIOD
            endif
            call EnableTrigger(LoopTrig)
        endif
        set u = null
        return false
    endfunction
    
    private function IsNotGrouped takes nothing returns boolean
        static if not(CAN_DAMAGE_SELF) then
            if GetFilterUnit() == u  then
                return false
            endif
        endif
        static if SINGLE_DAMAGE_EVENT then
            if IsUnitInGroup(GetFilterUnit(),g) == false then
                call GroupAddUnit(g,GetFilterUnit()) // Quickfix line
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Adding to group")
                call UnitDamageTarget(u,GetFilterUnit(),Damage[i],true,true,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
            endif
        else
            call UnitDamageTarget(u,GetFilterUnit(),Damage[i],true,true,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
        endif
        return true
    endfunction
    
    private function Loop takes nothing returns boolean
        local real dist
        set i = 1
        loop
            exitwhen i > Units
                set u = Unit[i]
                set dist = GetUnitMoveSpeed(u)*1.5*LOOP_PERIOD
                call SetUnitX(u, GetUnitX(u) + dist * Cos(Angle[i] * bj_DEGTORAD))
                call SetUnitY(u, GetUnitY(u) + dist * Sin(Angle[i] * bj_DEGTORAD))
                set g = Victims[i]
                // Quickfix line below, used tg to enumerate
                call GroupEnumUnitsInRange(tg,GetUnitX(u),GetUnitY(u),AOE,Filter(function IsNotGrouped))
                set Ticks[i] = Ticks[i] - 1
                if Ticks[i] == 0 then
                    set Unit[i] = Unit[Units]
                    set Damage[i] = Damage[Units]
                    set Ticks[i] = Ticks[Units]
                    set Angle[i] = Angle[Units]
                    call DestroyGroup(Victims[i])
                    set Victims[i] = Victims[Units]
                    set Victims[Units] = null
                    set Units = Units - 1
                else
                    set i = i + 1
                endif
        endloop
        if Units == 0 then
            call DisableTrigger(LoopTrig)
        endif
        //set g = null
        set u = null
        return false
    endfunction
    
    private function in takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 15
            call TriggerRegisterPlayerUnitEvent(CastTrig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
            set i = i + 1
        endloop
        call TriggerRegisterTimerEvent(LoopTrig,LOOP_PERIOD,true)
        call TriggerAddCondition(CastTrig,Condition(function Cast))
        call TriggerAddCondition(LoopTrig,Condition(function Loop))
    endfunction
endlibrary
 
Status
Not open for further replies.
Top