//****************************************************************************\\
//** **\\
//** OVERRUN v2.0 **\\
//** by Kricz **\\
//** **\\
//** Requires: **\\
//** vJass, this trigger & Wc3 version 1.24 **\\
//** **\\
//** Credits: **\\
//** Vexorian: vJass, TimerUtils and xe **\\
//** Rising Duks: Knockback, Last Order & Group Utils **\\
//** Antinarf: IsTerrainWalkable **\\
//** **\\
//** **\\
//** Discription: **\\
//** The caster runs towards the target location, **\\
//** getting more faster and transparent the longer he runs. **\\
//** Damaged every enemy he strifes on his way depending on the **\\
//** moved distance and level. When the caster reaches his target, **\\
//** all enemy units get knocked back. **\\
//** **\\
//****************************************************************************\\
scope Overrun //requires TimerUtils, Knockback, Last Order, Group Utils, xebasic, xedamage, xepreload
globals
//Raw-Code of the Spell
private constant integer SPELL_ID = 'A000'
//Rawcode of the Spellbook for Spell Immunity
private constant integer SPELLBOOK_ID = 'A001'
//The acceleration with each interval
private constant real ACCELERATION = 375.
//Should trees get destroyed (ignores collosion with them!)
private constant boolean DESTROY_TREES = true
//The max transparency (0 = transparent, 255 = normal)
private constant real MAX_TRANSPARENT = 50.
//The Start-Factor of the units animation
private constant real ANIM_START_FACTOR = 1.25
//The End-Factor the unit will have when it reaches his target or the max range for this level
private constant real ANIM_END_FACTOR = 3.
//The Animation-Id you want to have while the unit moves
private constant integer AMIN_ID = 0
//The effect created at the start
private constant string EFFECT_START = "Abilities\\Spells\\Human\\Defend\\DefendCaster.mdl"
//The effect attached to the unit while moving
private constant string EFFECT_MOVE = "MDX\\KnockbackDust.mdx"
//The effect when the unit reaches its target / max range for the level
private constant string EFFECT_END = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarCaster.mdl"
//The "collision-size" of the unit while it move.
private constant real DAMAGE_AOE = 165.
//The knockback-AoE at the end
private constant real KNOCKBACK_AOE = 250.
//The knockback-StartSpeed at the end
private constant real KNOCKBACK_START_SPEED = 675.
//The knockback-speed-decrement
//Rising Dusk's KnockbackSystem will change this value itself (!!!) :
//KNOCKBACK_DECREMENT * 0.05 * 0.05
private constant real KNOCKBACK_DECREMENT = 1400.
endglobals
//In this function, you can setup the damage
//Please note, that the damage depends on the distance the unit moved! So this function uses the damage for 100% moved
private function DAMAGE takes integer lvl returns real
return 100. + 75. * lvl
endfunction
//The max-range of the spell
private function MAX_RANGE takes integer lvl returns real
return 800. + 200. * lvl
endfunction
//! textmacro OR_SETUP_DAMAGE
set .dtype = DAMAGE_TYPE_NORMAL
set .atype = ATTACK_TYPE_HERO
set .wtype = WEAPON_TYPE_WOOD_HEAVY_SLICE
//! endtextmacro
//Don't change things below here unless you really know what you're doing!!!
private struct spelldata
unit caster = null
integer lvl = 0
real cos = 0.
real sin = 0.
real dist = 0.
real speed = 0.
real angle = 0.
real x = 0.
real y = 0.
real moved = 0.
real percent = 0.
timer t = null
group g = null
effect fx = null
static group group
static boolexpr filter
static thistype temp
static delegate xedamage dmg
static method create takes unit caster, real distance, real angle returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .lvl = GetUnitAbilityLevel(.caster, SPELL_ID)
set .dist = distance
set .cos = Cos(angle)
set .sin = Sin(angle)
set .angle = angle
set .x = GetUnitX(.caster)
set .y = GetUnitY(.caster)
set .speed = GetUnitMoveSpeed(.caster)
set .t = NewTimer()
set .g = NewGroup()
set .fx = AddSpecialEffectTarget(EFFECT_MOVE, .caster, "origin")
call SetUnitPathing(.caster, false)
call SetUnitTimeScale(.caster, ANIM_START_FACTOR)
call SetTimerData(.t, this)
call UnitAddAbility(.caster, SPELLBOOK_ID)
call DestroyEffect(AddSpecialEffectTarget(EFFECT_START, .caster, "origin"))
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.periodic)
return this
endmethod
private method onDestroy takes nothing returns nothing
local unit u = null
local real angle = 0
call DestroyEffect(.fx)
call SetUnitTimeScale(.caster, 1.)
call SetUnitPathing(.caster, true)
call SetUnitVertexColor(.caster, 255, 255, 255, 255)
call UnitRemoveAbility(.caster, SPELLBOOK_ID)
call ReleaseGroup(.g)
if GetWidgetLife(.caster) > 0.405 then
call DestroyEffect(AddSpecialEffectTarget(EFFECT_END, .caster, "origin"))
call SetUnitAnimation(.caster, "stand")
set .temp = this
call GroupEnumUnitsInRange(.group, .x, .y, KNOCKBACK_AOE, .filter)
call IssueLastOrder(.caster)
loop
set u = FirstOfGroup(.group)
exitwhen u == null
set angle = Atan2(GetUnitY(u)- .y, GetUnitX(u) - .x) * bj_RADTODEG
call KnockbackTarget(.caster, u, angle, KNOCKBACK_START_SPEED, KNOCKBACK_DECREMENT, true, true, false)
call GroupRemoveUnit(.group, u)
endloop
call GroupClear(.group)
endif
endmethod
private static method FilterFunc takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnit(GetFilterUnit(), .temp.caster) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(.temp.caster)) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endmethod
private static method periodic takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local real damage = 0
local unit u = null
local real nx = 0.
local real ny = 0.
set .speed = .speed + ACCELERATION * XE_ANIMATION_PERIOD
set nx = .x + (.speed * XE_ANIMATION_PERIOD) * .cos
set ny = .y + (.speed * XE_ANIMATION_PERIOD) * .sin
if DESTROY_TREES then
call .damageDestructablesAOE(.caster, nx, ny, DAMAGE_AOE, 100000.00)
endif
if .moved >= .dist or .moved >= MAX_RANGE(.lvl) or GetWidgetLife(.caster) < 0.405 or not IsTerrainWalkable(nx, ny) then
call ReleaseTimer(.t)
call .destroy()
else
call SetUnitAnimationByIndex(.caster, AMIN_ID)
set .moved = .moved + .speed * XE_ANIMATION_PERIOD
call SetUnitPosition(.caster, nx, ny)
set .x = GetUnitX(.caster)
set .y = GetUnitY(.caster)
set .percent = (.moved / MAX_RANGE(.lvl))
set damage = DAMAGE(.lvl) * .percent
set .temp = this
call GroupEnumUnitsInRange(.group, .x, .y, DAMAGE_AOE, .filter)
loop
set u = FirstOfGroup(.group)
exitwhen u == null
if not IsUnitInGroup(u, .g) then
call .damageTarget(.caster, u, damage)
endif
call GroupRemoveUnit(.group, u)
call GroupAddUnit(.g, u)
endloop
call GroupClear(.group)
call SetUnitFacing(.caster, .angle * bj_RADTODEG)
call SetUnitVertexColor(.caster, 255, 255, 255, R2I(255. * (1. - .percent) + MAX_TRANSPARENT * .percent))
call SetUnitTimeScale(.caster, ANIM_START_FACTOR * (1. - .percent) + ANIM_END_FACTOR * .percent)
endif
endmethod
private static method register takes nothing returns boolean
local unit caster = null
local real dx = 0.
local real dy = 0.
local real distance = 0.
local real angle = 0.
if GetSpellAbilityId() == SPELL_ID then
set caster = GetSpellAbilityUnit()
set dx = GetSpellTargetX() - GetUnitX(caster)
set dy = GetSpellTargetY() - GetUnitY(caster)
set distance = SquareRoot(dx * dx + dy * dy)
set angle = Atan2(GetSpellTargetY() - GetUnitY(caster), GetSpellTargetX() - GetUnitX(caster))
call thistype.create(caster, distance, angle)
set caster = null
return true
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.register))
set .filter = Condition(function thistype.FilterFunc)
set .group = NewGroup()
set .dmg = xedamage.create()
//! runtextmacro OR_SETUP_DAMAGE()
call XE_PreloadAbility(SPELL_ID)
call XE_PreloadAbility(SPELLBOOK_ID)
loop
call SetPlayerAbilityAvailable(Player(i), SPELLBOOK_ID, false)
set i = i + 1
exitwhen i >= bj_MAX_PLAYER_SLOTS
endloop
set t = null
endmethod
endstruct
endscope