• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[vJASS] Spell: AOE Hex, immobile hexed unit?

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I've made a AOE-Hex but there is currently a few things I need some help with:

1) I would like to include an option of making the hexed unit immobile.
2) Can you tell me how to replace the red BJ function in my trigger?
3) Can you see anything wrong with my dynamic index, it seems to be working but I'm not sure.
4) Should I change anything?
5) Should it dispell on StopCast instead of spell duration, and how would I do that?

To help you understand how it works, its a channeling hex, it hex one unit in AOE per INTERVAL. If INTERVAL == 0 it will hex all units at the first run.

JASS:
scope AoeHex initializer Init
    
    globals
        private constant integer AOE_HEX        = 'A000' 
        private constant integer HEX_HIDDEN     = 'A001'
        private constant integer DUMMY          = 'n000'
        private constant real    INTERVAL       = 0.0
        private constant real    AOE_RADIUS     = 200
    
        private real array  x 
        private real array  y
        private unit array  caster
        private group array hexed
        private integer     cur
        private integer     index = 0
        private trigger     t0    = CreateTrigger()
    endglobals

    private function SpellFilter takes nothing returns boolean
        return GetSpellAbilityId() == AOE_HEX
    endfunction
    
    private function OnStart takes nothing returns boolean 
        if SpellFilter() then 
            if hexed[index] == null then 
                set hexed[index] = CreateGroup()
            endif
            set caster[index] = GetTriggerUnit()
            set x[index] = GetLocationX(GetSpellTargetLoc())
            set y[index] = GetLocationY(GetSpellTargetLoc())
            set index = index + 1
            if index == 1 then
                call EnableTrigger(t0)
            endif
        endif
        return false 
    endfunction

    private function OnStop takes nothing returns boolean 
        local integer i = 0
        if SpellFilter() then 
            loop
                if caster[i] == GetTriggerUnit() then
                    call GroupClear(hexed[i])
                    set caster[i] = caster[index - 1]
                    set hexed[i] = hexed[index - 1]
                    set x[i] = x[index - 1]
                    set y[i] = y[index - 1]
                    set i = index
                endif
                set i = i + 1
                exitwhen i >= index
            endloop
            set index = index - 1
            if index == 0 then
                call DisableTrigger(t0)
            endif
        endif
        return false 
    endfunction
    
    private function GroupFilter takes nothing returns boolean
        return not IsUnitInGroup(GetFilterUnit(), hexed[cur]) and IsPlayerEnemy(GetOwningPlayer(caster[cur]), GetOwningPlayer(GetFilterUnit()))
    endfunction
    
    private function Hex takes unit target returns nothing
        local unit u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), DUMMY, 0, 0, 0)
        call UnitApplyTimedLife(u, 'BTLF', 0.3)
        call IssueTargetOrder(u, "hex", target)
        call GroupAddUnit(hexed[cur], target)
        set u = null
    endfunction
    
    private function HexAll takes nothing returns nothing
        call Hex(GetEnumUnit())
    endfunction
    
    private function OnTime takes nothing returns boolean
        local group g = CreateGroup()
        if INTERVAL == 0 then
            call DisableTrigger(t0)
        endif
        set cur = 0
        loop
            call GroupEnumUnitsInRangeOfLoc(g, Location(x[cur], y[cur]), AOE_RADIUS, function GroupFilter) 
            if INTERVAL == 0 then 
                call ForGroup(g, function HexAll)
            else 
                call Hex(GroupPickRandomUnit(g))
            endif
            set cur = cur + 1
            exitwhen cur == index
        endloop
        call DestroyGroup(g)
        set g = null
        return false 
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local integer i = 0
        local player p
        loop
            set p = Player(i)
            call TriggerRegisterPlayerUnitEvent(t1, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t2, p, EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerRegisterTimerEvent(t0, INTERVAL, true)
        call TriggerAddCondition(t0, Condition(function OnTime))
        call TriggerAddCondition(t1, Condition(function OnStart))
        call TriggerAddCondition(t2, Condition(function OnStop))
        call DisableTrigger(t0)
    endfunction
endscope
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
2) Can you tell me how to replace the red BJ function in my trigger?
Not that it is too critical to do so but this will work.

JASS:
    private function OnTime takes nothing returns boolean
         local group g = CreateGroup()
         set cur = 0
         loop
             call GroupEnumUnitsInRangeOfLoc(g, Location(x[cur], y[cur]), AOE_RADIUS, function GroupFilter) 
             if INTERVAL == 0 then 
                 call ForGroup(g, function HexAll)
             else 
                 set bj_groupRandomConsidered = 0
                 set bj_groupRandomCurrentPick = null
                 call ForGroup(g, function GroupPickRandomUnitEnum)
                 call Hex(bj_groupRandomCurrentPick)
             endif
             set cur = cur + 1
             exitwhen cur == index
         endloop
         call DestroyGroup(g)
         set g = null
         return false 
     endfunction

Any further optimizations would require a destructive group iteration to eliminate the ForGroup call.

4) Should I change anything?
JASS:
    private function OnStop takes nothing returns boolean 
         local integer i = 0
         if SpellFilter() then 
             loop
                 if caster[i] == GetTriggerUnit() then
                     call GroupClear(hexed[i])
                     set caster[i] = caster[index - 1]
                     set hexed[i] = hexed[index - 1]
                     set x[i] = x[index - 1]
                     set y[i] = y[index - 1]
                     set i = index
                 endif
                 set i = i + 1
                 exitwhen i >= index
             endloop
             set index = index - 1
             if index == 0 then
                 call DisableTrigger(t0)
             endif
         endif
         return false 
     endfunction
This function has a poor complexity. It makes little difference unless you have dozens of instances stopping all the time but could be improved by using a hashtable to map the unit to an index for O(1) lookup.

Anyway here is a minor improvement for it in its current form.
JASS:
    private function OnStop takes nothing returns boolean 
         local integer i = 0
         if SpellFilter() then 
             loop
                 if caster[i] == GetTriggerUnit() then
                     call GroupClear(hexed[i])
                     set caster[i] = caster[index - 1]
                     set hexed[i] = hexed[index - 1]
                     set x[i] = x[index - 1]
                     set y[i] = y[index - 1]
                     exitwhen true // Exit loop immediatly
                 endif
                 set i = i + 1
                 exitwhen i >= index
             endloop
             set index = index - 1
             if index == 0 then
                 call DisableTrigger(t0)
             endif
         endif
         return false 
     endfunction
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
1. By immobile, do you mean has 0 movement or is it stun? If 0 movement speed, make the movement speed of the transformed unit (e.g. Chicken) to zero.
2. If you don't need it to be random, use FirstOfGroup().

@Shadow Flux
0 movement speed, realized it could be done through checking if the unit has a specific buff. Will be implementing it. Ah good catch, it doesn't need to be random.

@Dr_Super_good
I though the index never would reach a size that would require a hashtable, perhaps wrongly. Thanks for your advice.

Gonna implement some changes.
 
Status
Not open for further replies.
Top