scope CorruptedArrows //version 1.05
/*******************************************************************************************************************
* Requires:
* -CTL (By Nestharus)
* -WorldBounds (By Nestharus)
* -Table (By Bribe)
* -GroupUtils (By Rising_Dusk)
* -IsDestructableTree (PitzerMike)
* -SpellEffectEvent (By Bribe)
* -RegisterPlayerUnitEvent (By Magtheridon96)
*
* How to Import:
* -Copy both abilities from object editor (Abilities)
* -Copy Multishot - Dummy from object editor (Units)
* -Copy Corrupted arrows from object editor (Buffs/Effects)
* -Copy Multishot trigger
* -Copy Libraries Folder
*
* Give credits if use :)
*
***********************************************************************************************************************/
/**************************************************************************************
* *
* CONFIGURATION *
* *
**************************************************************************************/
globals
//Main ability rawcode
private constant integer SPELL_CODE = 'A002'
//Armor debuff ability rawcode
private constant integer DEBUF_CODE = 'A000'
//Dummy rawcode
private constant integer DUMMY_CODE = 'h001'
//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_MAGIC
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_DEATH
//Should arrows destroy trees?
private constant boolean DESTROY_TREE = true
endglobals
//Damage function
private function GetDamage takes integer level returns real
return level * 30.00
endfunction
//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
set caster[this] = GetTriggerUnit()
set owner[this] = GetTriggerPlayer()
set level = GetUnitAbilityLevel(caster[this], SPELL_CODE)
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] = GetDamage(level)
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, level)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_CODE,function thistype.onCast)
endmethod
endstruct
endscope