scope GravityFlux // requires Damage, Timer32, GTrigger, GroupUtils
native UnitAlive takes unit id returns boolean
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABILID = 'ABGF' // raw code of ability "Gravity Flux"
public constant integer DUMMYID = 'grFl' // raw code of unit "Gravity Flux Dummy"
private constant boolean SELF = true // true if includes mana cost
private constant real TIME = 1.0 // time taken for balls to reach target point
private constant string ART = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl" // effect upon enemy damage
private constant string ARTPOINT = "origin" // attachment point of damage effect
private constant string DEATHART = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl" // effect upon projectile death
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
private constant weapontype WEP = WEAPON_TYPE_WHOKNOWS // weapon type of damage
endglobals
private function GetMana takes integer level returns real
return 25.0 + (25.0 * level) // mana absorbed from unit
endfunction
private function GetTargetAoe takes integer level returns real
return 400.0 // target area of effect
endfunction
private function GetAoe takes integer level returns real
return 400.0 // area of effect of damage
endfunction
private function FilterTarget takes unit owner, unit target returns boolean
return UnitAlive(target) or IsUnitEnemy(target, GetOwningPlayer(owner)) // targets allowed for damage
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
private struct Data
real duration
real mana
real x
real y
integer level
integer count = 0
group ballgroup
group damagegroup
unit caster
static Data tempData
static hashtable Hash = InitHashtable()
static unit tempUnit
static real tempX
static real tempY
static real tempReal
static integer tempInt
private static method damageFunc takes nothing returns nothing
local thistype this = tempData
local unit u = GetEnumUnit()
call UnitDamageTargetEx(this.caster, u, this.mana, true, false, ATK, DMG, WEP)
call DestroyEffect(AddSpecialEffectTarget(ART, u, ARTPOINT))
set u = null
endmethod
private static method countFunc takes nothing returns boolean
local thistype this = tempData
local unit u = GetFilterUnit()
if IsUnitEnemy(u, GetOwningPlayer(this.caster)) and UnitAlive(u) then
set this.count = this.count + 1
call GroupAddUnit(this.damagegroup, u)
endif
set u = null
return false
endmethod
private static method groupFunc takes nothing returns nothing
local thistype this = tempData
local unit u = GetEnumUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real a = Atan2(this.y - y, this.x - x)
local real dist = LoadReal(Hash, GetHandleId(u), 0)
set x = x + dist * Cos(a)
set y = y + dist * Sin(a)
call SetUnitPosition(u, x, y)
set u = null
endmethod
private static method filterFunc takes nothing returns boolean
local thistype this = tempData
local unit u = GetFilterUnit()
local real x
local real y
local real mana
local real unitmana
if FilterTarget(this.caster, u) then
set x = GetUnitX(u)
set y = GetUnitY(u)
set mana = GetMana(this.level)
set unitmana = GetUnitState(u, UNIT_STATE_MANA)
if unitmana < mana then
set mana = unitmana
endif
set this.mana = this.mana + mana
set tempUnit = CreateUnit(GetOwningPlayer(this.caster), DUMMYID, x, y, Atan2(this.y - y, this.x - x) * bj_RADTODEG)
call GroupAddUnit(this.ballgroup, tempUnit)
call SetUnitState(u, UNIT_STATE_MANA, unitmana - mana)
set x = x - this.x
set y = y - this.y
call SaveReal(Hash, GetHandleId(tempUnit), 0, (SquareRoot(x * x + y * y) / TIME) * T32_PERIOD)
endif
set u = null
return false
endmethod
private static method GroupFlush takes nothing returns nothing
local unit u = GetEnumUnit()
local thistype this = tempData
call FlushChildHashtable(Hash, GetHandleId(u))
call GroupRemoveUnit(this.ballgroup, u)
call RemoveUnit(u)
set u = null
endmethod
private method periodic takes nothing returns nothing
if this.duration <= 0 then
set tempData = this
call GroupEnumUnitsInArea(ENUM_GROUP, this.x, this.y, GetAoe(this.level), Filter(function thistype.countFunc))
if this.count > 0 then
set this.mana = this.mana / this.count
call ForGroup(this.damagegroup, function thistype.damageFunc)
endif
call DestroyEffect(AddSpecialEffect(DEATHART, this.x, this.y))
call ForGroup(this.ballgroup, function thistype.GroupFlush)
call ReleaseGroup(this.ballgroup)
call this.stopPeriodic()
call this.deallocate()
else
set tempData = this
call ForGroup(this.ballgroup, function thistype.groupFunc)
set this.duration = this.duration - T32_PERIOD
endif
endmethod
implement T32x
private static method create takes unit caster, integer level, real x, real y, real mana returns thistype
local thistype this = thistype.allocate()
set this.duration = TIME
set this.mana = mana
set this.x = x
set this.y = y
set this.level = level
set this.count = 0
set this.ballgroup = NewGroup()
set this.damagegroup = NewGroup()
set this.caster = caster
static if SELF then
set tempX = GetUnitX(this.caster)
set tempY = GetUnitY(this.caster)
set tempUnit = CreateUnit(GetOwningPlayer(this.caster), DUMMYID, tempX, tempY, Atan2(y - tempY, x - tempX) * bj_RADTODEG)
set tempX = tempX - this.x
set tempY = tempY - this.y
call GroupAddUnit(this.ballgroup, tempUnit)
call SaveReal(Hash, GetHandleId(tempUnit), 0, (SquareRoot(tempX * tempX + tempY * tempY) / TIME) * T32_PERIOD)
endif
set tempData = this
call GroupEnumUnitsInArea(ENUM_GROUP, this.x, this.y, GetTargetAoe(this.level), Filter(function thistype.filterFunc))
call this.startPeriodic()
return this
endmethod
private static method manaTimeOut takes nothing returns nothing
local timer t = GetExpiredTimer()
call thistype.create(tempUnit, tempInt, tempX, tempY, tempReal - GetUnitState(tempUnit, UNIT_STATE_MANA))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
endmethod
private static method actions takes nothing returns nothing
local timer t
set tempUnit = GetTriggerUnit()
set tempInt = GetUnitAbilityLevel(tempUnit, ABILID)
set tempX = GetSpellTargetX()
set tempY = GetSpellTargetY()
static if SELF then
set t = CreateTimer()
set tempReal = GetUnitState(tempUnit, UNIT_STATE_MANA)
call TimerStart(t, 0.00, false, function thistype.manaTimeOut)
else
call thistype.create(tempUnit, tempInt, tempX, tempY, 0)
endif
set t = null
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call GT_RegisterStartsEffectEvent(t, ABILID)
call TriggerAddAction(t, function thistype.actions)
set t = null
//preload
call RemoveUnit(CreateUnit(Player(13), DUMMYID, 0, 0, 0))
endmethod
endstruct
endscope