• 🏆 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!

[Solved] Need help with a jass ability

Status
Not open for further replies.
Level 12
Joined
Jan 13, 2008
Messages
559
Hi, I implemented the following ability into my map: Corrupted Arrows v1.05

I changed a couple of lines but nothing that should explain the following problem:
When casting it on multiple units, only the first unit that gets hit, gets the armor reduction and I can't figure out why.

Here is the current and changed code:

JASS:
scope CorruptedArrows //version 1.05

/**************************************************************************************
*                                                                                     *
*                             CONFIGURATION                                           *
*                                                                                     *                                              
**************************************************************************************/

    globals
        //Main ability rawcode
        private constant integer        SPELL_CODE      =   'A05M'
        //Armor debuff ability rawcode
        private constant integer        DEBUF_CODE      =   'A05N'
        //Dummy rawcode
        private constant integer        DUMMY_CODE      =   'h018'
       
        //Ammout of arrows shotted
        private constant integer        AMMOUT          =   7
       
        //Angle at which arrows are shooted. You can set it to 360 to make nova spell
        private constant real           ANGLE_ARC       =   50
       
        //Arrows dize
        private constant real           DUMMY_SCALE     =   100
        //Arrows height
        private constant real           DUMMY_HEIGHT    =   70
        //Range to pick units to damage
        private constant real           DAMAGE_RANGE    =   40
        //Move effect cooldown
        private constant integer        MOVE_CD         =   3
       
        //Effect that appear on damaged units
        private constant string         DAMAGE_EFFECT   =   "Abilities\\Spells\\Other\\BlackArrow\\BlackArrowMissile.mdl"
       
        //Damage and attack type
        private constant attacktype     ATTACK_TYPE     =   ATTACK_TYPE_HERO
        private constant damagetype     DAMAGE_TYPE     =   DAMAGE_TYPE_DEATH
       
        //Should arrows destroy trees?
        private constant boolean        DESTROY_TREE    =   false
    endglobals
   
    //Total distance function
    private function GetDistance takes integer level returns real
        return level * 50.00 + 650.00
    endfunction
   
    //Speed function
    private function GetSpeed takes integer level returns real
        return level * 2.00 + 23.00
    endfunction


/**************************************************************************************
*                                                                                     *
*                          DAMAGE FILTER FUNCTIOn                                     *
*                                                                                     *                                              
**************************************************************************************/
   
    private function TargetFilter takes unit u, player p returns boolean
        return IsUnitEnemy(u, p) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(u, UNIT_TYPE_FLYING)
    endfunction

/**************************************************************************************
*                                                                                     *
*                             CONFIGURATION END                                       *
*                                                                                     *                                              
**************************************************************************************/
   
    private function Tree_Kill takes nothing returns boolean
        local destructable dummy = GetFilterDestructable()
        if IsDestructableTree(dummy) then
            call KillDestructable(dummy)
        endif
        set dummy = null
        return false
    endfunction

    private struct CorruptedArrows extends array
   
    private static unit array caster
    private static unit array dummy
   
    private static player array owner
   
    private static real array distance
    private static real array speed
    private static real array damage
    private static rect array tree_rect
   
    private static integer array moveCD
    private static integer array moveCCD
   
    private static group array ignoreGroup
   
    static Table array missiles
   
        implement CTL
   
            local unit u
            local unit t
            local unit e
            local real x
            local real y
            local real a
            local real dx
            local real dy
            local group d
            local integer index
            local integer i
   
        implement CTLExpire
   
            set distance[this] = distance[this] - speed[this]
            set index = 0
            set i = 0
   
            loop
                set u = missiles[this].unit[index]
                set a = missiles[this].real[index]
               
                set dx = GetUnitX(u)
                set dy = GetUnitY(u)
   
                set x = dx + speed[this] * Cos(a)
                set y = dy + speed[this] * Sin(a)

                if (x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY ) then
               
                    call SetUnitX(u, x)
                    call SetUnitY(u, y)
                   
                    set moveCCD[this] = moveCCD[this] + 1
               
               
                    if moveCCD[this] == moveCD[this] then
               
                        set e = CreateUnit(owner[this], DUMMY_CODE, x, y, a * bj_RADTODEG)
               
                        call SetUnitFlyHeight(e, DUMMY_HEIGHT, 0)
                        call SetUnitScale(e, DUMMY_SCALE * 0.01, 0, 0)
               
                        call UnitApplyTimedLife(e, 'BTLF', 0.50)
                        call SetUnitAnimation(e, "death")
                   
                        set moveCCD[this] = moveCCD[this] - moveCD[this]
                   
                        set e = null
               
                    endif
               
                else
               
                    call KillUnit(u)
               
                endif
               
               
                set d = NewGroup()
       
                call GroupUnitsInArea(d, x, y, DAMAGE_RANGE)
       
                loop
                    set t = FirstOfGroup(d)
                    exitwhen t == null
           
                    if TargetFilter(t, owner[this]) and not IsUnitInGroup(t, ignoreGroup[this]) then
           
                        call UnitDamageTarget(caster[this], t, damage[this], false, true, ATTACK_TYPE, DAMAGE_TYPE, null)
                        call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT, t, "chest"))
                       
                        call IssueTargetOrder(dummy[this], "faeriefire", t)
               
                        call GroupAddUnit(ignoreGroup[this], t)
                    endif
           
                    call GroupRemoveUnit(d, t)
           
                endloop
               
                call ReleaseGroup(d)
               
                set d = null
       
                static if DESTROY_TREE then
                    call SetRect(tree_rect[this], x - DAMAGE_RANGE, y - DAMAGE_RANGE, x + DAMAGE_RANGE, y + DAMAGE_RANGE)
                    call EnumDestructablesInRect(tree_rect[this],function Tree_Kill,null)
                endif
               
                set u = null
               
                set index = index + 1

                exitwhen index == AMMOUT
               
            endloop
   
            if distance[this] <= 0 then
   
                loop
       
                    call UnitApplyTimedLife(missiles[this].unit[i], 'BTLF', 0.50)
                    call SetUnitAnimation(missiles[this].unit[i], "death")
   
                    exitwhen i == AMMOUT
       
                    set i = i + 1
                endloop
   
                call missiles[this].destroy()
               
                call KillUnit(dummy[this])
               
                set caster[this] = null
                set dummy[this] = null
                set owner[this] = null
               
                call ReleaseGroup(ignoreGroup[this])
               
                set ignoreGroup[this] = null
               
                call destroy()
   
            endif
   
        implement CTLNull
        implement CTLEnd
   
        private static method onCast takes nothing returns nothing
   
            local thistype this = create()
   
            local unit u
            local real cx
            local real cy
            local real tx
            local real ty
            local real a
            local real ainc
            local real arc
            local integer level
            local integer index = 0
            local integer agi
            local real realmana
   
            set caster[this] = GetTriggerUnit()
            set owner[this] = GetTriggerPlayer()
            set level = GetUnitAbilityLevel(caster[this], SPELL_CODE)
            set agi = GetHeroAgi(GetTriggerUnit(),true)
            set realmana = GetUnitState(caster[this],UNIT_STATE_MANA)
 
   
            set cx = GetUnitX(caster[this])
            set cy = GetUnitY(caster[this])
            set tx = GetSpellTargetX()
            set ty = GetSpellTargetY()
   
            set distance[this] = GetDistance(level)
            set speed[this] = GetSpeed(level)
            set damage[this] = agi*2
            set ignoreGroup[this] = NewGroup()
           
            set moveCD[this] = MOVE_CD
            set moveCCD[this] = 0
   
            set arc = ANGLE_ARC * bj_DEGTORAD
   
            set a = Atan2(ty - cy, tx - cx) - (arc/ 2)
            set ainc = arc / AMMOUT
   
            set missiles[this] = Table.create()
   
            loop
                set u = CreateUnit(owner[this], DUMMY_CODE, cx, cy, a * bj_RADTODEG)
       
                set missiles[this].unit[index] = u
                set missiles[this].real[index] = a
       
                call SetUnitScale(u, DUMMY_SCALE * 0.01, 0, 0)
                call SetUnitFlyHeight(u, DUMMY_HEIGHT, 0)
       
                set a = a + ainc
       
                exitwhen index == AMMOUT
   
                set index = index + 1
               
            endloop
           
            set u = null
   
            static if DESTROY_TREE then
                set tree_rect[this] = Rect(0, 0, 0, 0)
            endif
           
            set dummy[this] = CreateUnit(owner[this], DUMMY_CODE, cx, cy, 0)
           
            call ShowUnit(dummy[this], false)
           
            call UnitAddAbility(dummy[this], DEBUF_CODE)
            call SetUnitAbilityLevel(dummy[this], DEBUF_CODE, R2I(realmana))
   
        endmethod
   
        private static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(SPELL_CODE,function thistype.onCast)
        endmethod
   
    endstruct
endscope
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
I opened up the original map and found that it had the same issue. Dummy casters need to have the 'Amov' ability removed, or have zero movement speed in the OE, to be able to cast spells almost instantly to multiple targets. Given that the person that made this spell uses the same dummy unit for both effects and casting abilities, you will need to go with the former solution.

Go to the onCast method, and add this line right after the dummy unit is created: call UnitRemoveAbility(dummy[this], 'Amov')
 
Status
Not open for further replies.
Top