scope MassiveAirstrike //requires T32, GT, GroupUtils, Status
globals
private constant integer ABILID = 'A000'
private constant integer DUMMYID = 'u000'
private constant integer ARROWID = 'h006'
private constant string TRAIL = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
private constant string TRAILATTACH = "chest"
private constant string ARROWFX = "Abilities\\Weapons\\Banditmissile\\Banditmissile.mdl"
private constant string ARROWATTACH = "chest"
private constant string HITFX = "Abilities\\Weapons\\BallistaMissile\\BallistaMissileTarget.mdl"
private constant string HITATTACH = "chest"
private constant attacktype AT = ATTACK_TYPE_NORMAL
private constant damagetype DT = DAMAGE_TYPE_MAGIC
private constant weapontype WT = null
private constant boolean PRELOAD = true
private constant player DUMMYOWNER = Player(PLAYER_NEUTRAL_PASSIVE)
private player TempPlayer = Player(PLAYER_NEUTRAL_PASSIVE)
endglobals
private function ArrowAmount takes integer lvl returns integer
return 15 * lvl
endfunction
private function AirSpeed takes integer lvl returns real
return 19.
endfunction
private function ArrowSpeed takes integer lvl returns real
return 22.
endfunction
private function Distance takes integer lvl returns real
return 800.
endfunction
private function Height takes integer lvl returns real
return 0.
endfunction
private function RandomAoe takes integer lvl returns real
return 400.
endfunction
private function ArrowAoe takes integer lvl returns real
return 85.
endfunction
private function Damage takes integer lvl returns real
return 55. + 10. * lvl
endfunction
private function DistanceInterval takes integer lvl returns real
return 200.
endfunction
private function ArmorReductionAmount takes integer lvl returns integer
return lvl * (-1)
endfunction
private function ArmorTime takes integer lvl returns real
return 6. + lvl
endfunction
private function EnumFilter takes unit u returns boolean
return GetWidgetLife(u) > 0.405 and/*
*/ IsUnitType(u, UNIT_TYPE_DEAD) == false and/*
*/ IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and/*
*/ IsUnitVisible(u, TempPlayer) and/*
*/ IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false and/*
*/ IsUnitEnemy(u, TempPlayer)
endfunction
globals
private constant real MINX = GetRectMinX(bj_mapInitialPlayableArea)
private constant real MAXX = GetRectMaxX(bj_mapInitialPlayableArea)
private constant real MINY = GetRectMinY(bj_mapInitialPlayableArea)
private constant real MAXY = GetRectMaxY(bj_mapInitialPlayableArea)
endglobals
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
private struct TimedArmor
unit affected
real time
integer value
private method periodic takes nothing returns nothing
if .time > 0. then
set .time = .time - T32_PERIOD
else
call Status[.affected].modArmorBonus(.value)
call .stopPeriodic()
call .destroy()
endif
endmethod
static method create takes unit whichunit, integer armorvalue, real time returns thistype
local thistype this = .allocate()
set .affected = whichunit
set .time = time
set .value = armorvalue * (-1)
call Status[whichunit].modArmorBonus(armorvalue)
call .startPeriodic()
return this
endmethod
implement T32x
endstruct
private struct Arrow
unit caster
unit dummy
real distance
real distancex
real height
real damage
real speedcos
real speedsin
real speed
real aoe
real armortime
integer armorred
effect model
private static thistype dat
private static location zloc = Location(0.,0.)
private static method bexpr takes nothing returns boolean
local unit u = GetFilterUnit()
if EnumFilter(u) then
call UnitDamageTarget(dat.caster, u, dat.damage, false, false, AT, DT, WT)
call TimedArmor.create(u, dat.armorred, dat.armortime)
call DestroyEffect(AddSpecialEffectTarget(HITFX, u, HITATTACH))
endif
set u = null
return false
endmethod
private method periodic takes nothing returns nothing
local real dummyx = GetUnitX(.dummy)
local real dummyy = GetUnitY(.dummy)
local real dummyz
local real newx = dummyx + .speedcos
local real newy = dummyy + .speedsin
set .distancex = .distancex + .speed
if MINX <= newx and newx <= MAXX and MINY <= newy and newy <= MAXY then
call SetUnitX(.dummy, newx)
call SetUnitY(.dummy, newy)
call MoveLocation(zloc, newx, newy)
set dummyz = ParabolaZ(.height, .distance, .distancex) +/*
*/ GetLocationZ(zloc)
call SetUnitFlyHeight(.dummy, dummyz, 0.)
if .distancex > .distance then
set dat = this
set TempPlayer = GetOwningPlayer(caster)
call GroupEnumUnitsInArea(ENUM_GROUP, newx, newy, .aoe, Filter(function Arrow.bexpr))
call .stopPeriodic()
call DestroyEffect(.model)
call RemoveUnit(.dummy)
call .destroy()
endif
else
call .stopPeriodic()
call DestroyEffect(.model)
call RemoveUnit(.dummy)
call .destroy()
endif
endmethod
static method create takes unit caster, real fromx, real fromy, real fromz returns thistype
local thistype this = .allocate()
local integer lvl = GetUnitAbilityLevel(caster, ABILID)
local real aoe2 = RandomAoe(lvl)
local real interval = DistanceInterval(lvl)
local real tox = fromx + GetRandomReal(interval, aoe2) * Cos(GetRandomReal(0., 360.) * bj_DEGTORAD)
local real toy = fromy + GetRandomReal(interval, aoe2) * Sin(GetRandomReal(0., 360.) * bj_DEGTORAD)
local real angle = Atan2(toy - fromy, tox - fromx)
set .speed = ArrowSpeed(lvl)
set .speedcos = .speed * Cos(angle)
set .speedsin = .speed * Sin(angle)
set .caster = caster
set .distance = SquareRoot(tox * fromx + toy * fromy)
set .distancex = .distance/2
set .height = fromz
set .damage = Damage(lvl)
set .aoe = ArrowAoe(lvl)
set .armorred = ArmorReductionAmount(lvl)
set .armortime = ArmorTime(lvl)
set .dummy = CreateUnit(DUMMYOWNER, ARROWID, fromx, fromy, angle * bj_RADTODEG)
call SetUnitScale(.dummy, 2., 2., 2.)
call SetUnitFlyHeight(.dummy, fromz, 0.)
set .model = AddSpecialEffectTarget(ARROWFX, .dummy, ARROWATTACH)
call .startPeriodic()
return this
endmethod
implement T32x
endstruct
private struct Movement
unit caster
unit dummy
real distance
real speedcos
real speedsin
real velocity
real creationrate
real ticker
real height
integer amount
effect trail
private method periodic takes nothing returns nothing
local real dummyx
local real dummyy
local real newx
local real newy
if .distance > 0. then
set dummyx = GetUnitX(.dummy)
set dummyy = GetUnitY(.dummy)
set newx = dummyx + .speedcos
set newy = dummyy + .speedsin
set .distance = .distance - .velocity
if (MINX <= newx) and (newx <= MAXX) and (MINY <= newy) and (newy <= MAXY) then
call SetUnitX(.dummy, newx)
call SetUnitY(.dummy, newy)
if .ticker < .creationrate then
set .ticker = .ticker + T32_PERIOD
else
set .ticker = 0.
call Arrow.create(.caster, newx, newy, .height)
endif
else
call BJDebugMsg("out of map")
call KillUnit(.dummy)
call DestroyEffect(.trail)
call .stopPeriodic()
call .destroy()
endif
else
call BJDebugMsg("spell ends")
call KillUnit(.dummy)
call DestroyEffect(.trail)
call .stopPeriodic()
call .destroy()
endif
endmethod
private static method create takes unit caster, real targetx, real targety returns thistype
local thistype this = .allocate()
local integer lvl = GetUnitAbilityLevel(caster, ABILID)
local real casterx = GetUnitX(caster)
local real castery = GetUnitY(caster)
local real angle = Atan2(targety - castery, targetx - casterx)
local real height = Height(lvl)
set .velocity = AirSpeed(lvl)
set .caster = caster
set .speedcos = .velocity * Cos(angle)
set .speedsin = .velocity * Sin(angle)
set .dummy = CreateUnit(DUMMYOWNER, DUMMYID, casterx, castery, angle * bj_RADTODEG)
set .trail = AddSpecialEffectTarget(TRAIL, .dummy, TRAILATTACH)
set .ticker = 0.
set .distance = Distance(lvl)
set .amount = ArrowAmount(lvl)
set .creationrate = (.distance/.velocity)/.amount
if height != 0. then
set .height = height
call SetUnitFlyHeight(.dummy, .height, 0.)
else
set .height = 270.
endif
call .startPeriodic()
return this
endmethod
private static method Check takes nothing returns boolean
if GetSpellAbilityId() == ABILID then
call create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call GT_RegisterFinishesCastingEvent(t, ABILID)
call TriggerAddCondition(t, Condition(function Movement.Check))
static if PRELOAD then
call Preload(TRAIL)
call Preload(ARROWFX)
call Preload(HITFX)
endif
endmethod
implement T32x
endstruct
endscope