Name | Type | is_array | initial_value |
do
local funcs = {}
function onInit(code)
if type(code) == "function" then
table.insert(funcs, code)
end
end
local old = InitBlizzard
function InitBlizzard()
old()
for i = 1, #funcs do
funcs[i]()
end
funcs = nil
end
end
--[[ requires Indexer, TimedHandles, RegisterPlayerUnitEvent
-- --------------------------------------- Utilities v1.9 --------------------------------------- --
-- How to Import:
-- 1 - Copy this library into your map
-- 2 - Copy the dummy unit in object editor and match its raw code below
-- 3 - Copy the Indexer library over to your map and follow its install instructions
-- 4 - Copy the TimedHandles library over to your map and follow its install instructions
-- 5 - Copy the RegisterPlayerUnitEvent library over to your map and follow its install instructions
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
-- The dummy caster unit id
local DUMMY = FourCC('dumi')
-- Update period
local PERIOD = 0.031250000
-- location z
local location = Location(0,0)
-- Closest Unit
local bj_closestUnitGroup
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
-- Returns the terrain Z value
function GetLocZ(x, y)
MoveLocation(location, x, y)
return GetLocationZ(location)
end
-- Similar to GetUnitX and GetUnitY but for Z axis
function GetUnitZ(unit)
return GetLocZ(GetUnitX(unit), GetUnitY(unit)) + GetUnitFlyHeight(unit)
end
-- Similar to SetUnitX and SetUnitY but for Z axis
function SetUnitZ(unit, z)
SetUnitFlyHeight(unit, z - GetLocZ(GetUnitX(unit), GetUnitY(unit)), 0)
end
-- Anlge between 2D points
function AngleBetweenCoordinates(x, y, x2, y2)
return Atan2(y2 - y, x2 - x)
end
-- Similar to AddSpecialEffect but scales the effect and considers z and return it
function AddSpecialEffectEx(effect, x, y, z, scale)
bj_lastCreatedEffect = AddSpecialEffect(effect, x, y)
if z ~= 0 then
BlzSetSpecialEffectZ(bj_lastCreatedEffect, z + GetLocZ(x, y))
end
BlzSetSpecialEffectScale(bj_lastCreatedEffect, scale)
return bj_lastCreatedEffect
end
-- Returns a group of enemy units of the specified player within the specified AOE of x and y
function GetEnemyUnitsInRange(player, x, y, aoe, structures, magicImmune)
local group = CreateGroup()
local g = CreateGroup()
local unit
GroupEnumUnitsInRange(g, x, y, aoe, nil)
for i = 0, BlzGroupGetSize(g) - 1 do
unit = BlzGroupUnitAt(g, i)
if IsUnitEnemy(unit, player) and UnitAlive(unit) and (structures or (not IsUnitType(unit, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(unit, UNIT_TYPE_MAGIC_IMMUNE))) then
GroupAddUnit(group, unit)
end
end
DestroyGroup(g)
return group
end
-- Returns the closest unit in a unit group with center at x and y
function GetClosestUnitGroup(x, y, group)
local md = 100000
local unit
local dx
local dy
bj_closestUnitGroup = nil
for i = 0, BlzGroupGetSize(group) - 1 do
unit = BlzGroupUnitAt(group, i)
if UnitAlive(unit) then
dx = GetUnitX(unit) - x
dy = GetUnitY(unit) - y
if (dx*dx + dy*dy)/100000 < md then
bj_closestUnitGroup = unit
md = (dx*dx + dy*dy)/100000
end
end
end
return bj_closestUnitGroup
end
-- Link an effect to a unit buff or ability
function LinkEffectToBuff(unit, buffId, model, attach)
EffectLink:buff(unit, buffId, model, attach)
end
-- Link an effect to an unit item.
function LinkEffectToItem(unit, i, model, attach)
EffectLink:item(unit, i, model, attach)
end
-- Spams the specified effect model at a location with the given interval for the number of times count
function SpamEffect(model, x, y, z, scale, interval, count)
local timer = CreateTimer()
TimerStart(timer, interval, true, function()
if count > 0 then
DestroyEffect(AddSpecialEffectEx(model, x, y, z, scale))
else
PauseTimer(timer)
DestroyTimer(timer)
end
count = count - 1
end)
end
-- Spams the specified effect model attached to a unit for the given interval for the number of times count
function SpamEffectUnit(unit, model, attach, interval, count)
local timer = CreateTimer()
TimerStart(timer, interval, true, function()
if count > 0 then
DestroyEffect(AddSpecialEffectTarget(model, unit, attach))
else
PauseTimer(timer)
DestroyTimer(timer)
end
count = count - 1
end)
end
-- Add the specified ability to the specified unit for the given duration. Use hide to show or not the ability button.
function UnitAddAbilityTimed(unit, ability, duration, level, hide)
TimedAbility:add(unit, ability, duration, level, hide)
end
-- Resets the specified unit ability cooldown
function ResetUnitAbilityCooldown(unit, ability)
local timer = CreateTimer()
TimerStart(timer, 0.01, false, function()
BlzEndUnitAbilityCooldown(unit, ability)
PauseTimer(timer)
DestroyTimer(timer)
end)
end
-- Returns the distance between 2 coordinates in Warcraft III units
function DistanceBetweenCoordinates(x1, y1, x2, y2)
local dx = (x2 - x1)
local dy = (y2 - y1)
return SquareRoot(dx*dx + dy*dy)
end
-- Makes the specified source damage an area respecting some basic unit filters
function UnitDamageArea(unit, x, y, aoe, damage, attacktype, damagetype, structures, magicImmune, allies)
local group = CreateGroup()
local player = GetOwningPlayer(unit)
GroupEnumUnitsInRange(group, x, y, aoe, nil)
GroupRemoveUnit(group, unit)
for i = 0, BlzGroupGetSize(group) - 1 do
local u = BlzGroupUnitAt(group, i)
if UnitAlive(u) and (allies or IsUnitEnemy(u, player)) and (structures or (not IsUnitType(u, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE))) then
UnitDamageTarget(unit, u, damage, true, false, attacktype, damagetype, nil)
end
end
DestroyGroup(group)
end
-- Makes the specified source damage a group. Creates a special effect if specified
function UnitDamageGroup(unit, group, damage, attacktype, damagetype, effect, attach, destroy)
for i = 0, BlzGroupGetSize(group) - 1 do
local u = BlzGroupUnitAt(group, i)
UnitDamageTarget(unit, u, damage, true, false, attacktype, damagetype, nil)
if effect and attach then
DestroyEffect(AddSpecialEffectTarget(effect, u, attach))
end
end
if destroy then
DestroyGroup(group)
end
return group
end
-- Returns a random range given a max value
function GetRandomRange(radius)
local r = GetRandomReal(0, 1) + GetRandomReal(0, 1)
if r > 1 then
return (2 - r)*radius
end
return r*radius
end
-- Returns a random value in the x/y coordinates depending on the value of boolean x
function GetRandomCoordInRange(center, radius, x)
local theta = 2*bj_PI*GetRandomReal(0, 1)
local r
if x then
r = center + radius*Cos(theta)
else
r = center + radius*Sin(theta)
end
return r
end
-- Clones the items in the source unit inventory to the target unit
function CloneItems(source, target, isIllusion)
for i = 0, bj_MAX_INVENTORY do
local item = UnitItemInSlot(source, i)
local j = GetItemCharges(item)
item = CreateItem(GetItemTypeId(item), GetUnitX(target), GetUnitY(target))
SetItemCharges(item, j)
UnitAddItem(target, item)
if isIllusion then
if GetItemTypeId(item) == FourCC('ankh') then
BlzItemRemoveAbility(item, FourCC('AIrc'))
end
BlzSetItemBooleanField(item, ITEM_BF_ACTIVELY_USED, false)
end
end
end
-- Add the mount for he unit mana pool
function AddUnitMana(unit, real)
SetUnitState(unit, UNIT_STATE_MANA, (GetUnitState(unit, UNIT_STATE_MANA) + real))
end
-- Add the specified amounts to a hero str/agi/int base amount
function UnitAddStat(unit, strength, agility, intelligence)
if strength ~= 0 then
SetHeroStr(unit, GetHeroStr(unit, false) + strength, true)
end
if agility ~= 0 then
SetHeroAgi(unit, GetHeroAgi(unit, false) + agility, true)
end
if intelligence ~= 0 then
SetHeroInt(unit, GetHeroInt(unit, false) + intelligence, true)
end
end
-- Returns the closest unit from the x and y coordinates in the map
function GetClosestUnit(x, y, boolexpr)
local group = CreateGroup()
local md = 100000
bj_closestUnitGroup = nil
GroupEnumUnitsInRect(group, bj_mapInitialPlayableArea, boolexpr)
for i = 0, BlzGroupGetSize(group) - 1 do
local unit = BlzGroupUnitAt(group, i)
if UnitAlive(unit) then
local dx = GetUnitX(unit) - x
local dy = GetUnitY(unit) - y
if (dx*dx + dy*dy)/100000 < md then
bj_closestUnitGroup = unit
md = (dx*dx + dy*dy)/100000
end
end
end
DestroyGroup(group)
DestroyBoolExpr(boolexpr)
return bj_closestUnitGroup
end
-- Creates a chain lightning with the specified ligihtning effect with the amount of bounces
function CreateChainLightning(source, target, damage, aoe, duration, interval, bounces, attacktype, damagetype, lightning, effect, attach, rebounce)
local player = GetOwningPlayer(source)
local group = GetEnemyUnitsInRange(player, GetUnitX(target), GetUnitY(target), aoe, false, false)
if BlzGroupGetSize(group) == 1 then
DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(source), GetUnitY(source), GetUnitZ(source) + 60.0, GetUnitX(target), GetUnitY(target), GetUnitZ(target) + 60.0), duration)
DestroyEffect(AddSpecialEffectTarget(effect, target, attach))
UnitDamageTarget(source, target, damage, false, false, attacktype, damagetype, nil)
DestroyGroup(group)
else
local timer = CreateTimer()
local damaged = CreateGroup()
local prev = nil
local this = target
local next = nil
GroupRemoveUnit(group, this)
GroupAddUnit(damaged, this)
UnitDamageTarget(source, this, damage, false, false, attacktype, damagetype, nil)
DestroyEffect(AddSpecialEffectTarget(effect, this, attach))
TimerStart(timer, interval, true, function()
DestroyGroup(group)
if bounces > 0 then
group = GetEnemyUnitsInRange(player, GetUnitX(this), GetUnitY(this), aoe, false, false)
GroupRemoveUnit(group, this)
if not rebounce then
BlzGroupRemoveGroupFast(damaged, group)
end
if BlzGroupGetSize(group) == 0 then
PauseTimer(timer)
DestroyTimer(timer)
DestroyGroup(group)
DestroyGroup(damaged)
else
next = GetClosestUnitGroup(GetUnitX(this), GetUnitY(this), group)
if next == prev and BlzGroupGetSize(group) > 1 then
GroupRemoveUnit(group, prev)
next = GetClosestUnitGroup(GetUnitX(this), GetUnitY(this), group)
end
if next then
DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(this), GetUnitY(this), GetUnitZ(this) + 60.0, GetUnitX(next), GetUnitY(next), GetUnitZ(next) + 60.0), duration)
DestroyEffect(AddSpecialEffectTarget(effect, next, attach))
GroupAddUnit(damaged, next)
UnitDamageTarget(source, next, damage, false, false, attacktype, damagetype, nil)
DestroyGroup(group)
prev = this
this = next
next = nil
else
PauseTimer(timer)
DestroyTimer(timer)
DestroyGroup(group)
DestroyGroup(damaged)
end
end
else
PauseTimer(timer)
DestroyTimer(timer)
DestroyGroup(group)
DestroyGroup(damaged)
end
bounces = bounces - 1
end)
end
DestroyGroup(group)
end
-- Add the specified amount to the specified player gold amount
function AddPlayerGold(player, amount)
SetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD) + amount)
end
-- Creates a text tag in an unit position for a duration
function CreateTextOnUnit(unit, string, duration, red, green, blue, alpha)
local texttag = CreateTextTag()
SetTextTagText(texttag, string, 0.015)
SetTextTagPosUnit(texttag, unit, 0)
SetTextTagColor(texttag, red, green, blue, alpha)
SetTextTagLifespan(texttag, duration)
SetTextTagVelocity(texttag, 0.0, 0.0355)
SetTextTagPermanent(texttag, false)
end
-- Add health regeneration to the unit base value
function UnitAddHealthRegen(unit, regen)
BlzSetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, BlzGetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE) + regen)
end
-- Retrieves a dummy from the pool. Facing angle in radians
function DummyRetrieve(player, x, y, z, face)
return DummyPool:retrieve(player, x, y, z, face)
end
-- Recycles a dummy unit type, putting it back into the pool.
function DummyRecycle(unit)
DummyPool:recycle(unit)
end
-- Recycles a dummy with a delay.
function DummyRecycleTimed(unit, delay)
DummyPool:timed(unit, delay)
end
-- Casts an ability in the target unit. Must have no casting time
function CastAbilityTarget(unit, ability, order, level)
local dummy = DummyRetrieve(GetOwningPlayer(unit), 0, 0, 0, 0)
UnitAddAbility(dummy, ability)
SetUnitAbilityLevel(dummy, ability, level)
IssueTargetOrder(dummy, order, unit)
UnitRemoveAbility(dummy, ability)
DummyRecycle(dummy)
end
-- Returns a random unit within a group
function GroupPickRandomUnitEx(group)
if BlzGroupGetSize(group) > 0 then
return BlzGroupUnitAt(group, GetRandomInt(0, BlzGroupGetSize(group) - 1))
else
return nil
end
end
-- Returns true if a unit is within a cone given a facing and fov angle in degrees (Less precise)
function IsUnitInConeEx(unit, x, y, face, fov)
return Acos(Cos((Atan2(GetUnitY(unit) - y, GetUnitX(unit) - x)) - face*bj_DEGTORAD)) < fov*bj_DEGTORAD/2
end
-- Returns true if a unit is within a cone given a facing, fov angle and a range in degrees (takes collision into consideration). Credits to AGD.
function IsUnitInCone(unit, x, y, range, face, fov)
if IsUnitInRangeXY(unit, x, y, range) then
x = GetUnitX(unit) - x
y = GetUnitY(unit) - y
range = x*x + y*y
if range > 0 then
face = face*bj_DEGTORAD - Atan2(y, x)
fov = fov*bj_DEGTORAD/2 + Asin(BlzGetUnitCollisionSize(unit)/SquareRoot(range))
return RAbsBJ(face) <= fov or RAbsBJ(face - 2.00*bj_PI) <= fov
end
return true
end
return false
end
-- Makes the source unit damage enemy unit in a cone given a direction, foy and range
function UnitDamageCone(unit, x, y, face, fov, aoe, damage, attacktype, damagetype, structures, magicImmune, allies)
local group = CreateGroup()
local player = GetOwningPlayer(unit)
GroupEnumUnitsInRange(group, x, y, aoe, nil)
GroupRemoveUnit(group, unit)
for i = 0, BlzGroupGetSize(group) - 1 do
local u = BlzGroupUnitAt(group, i)
if UnitAlive(u) and IsUnitInCone(u, x, y, aoe, face, fov) then
if (allies or IsUnitEnemy(u, player)) and (structures or (not IsUnitType(u, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE))) then
UnitDamageTarget(unit, u, damage, true, false, attacktype, damagetype, nil)
end
end
end
DestroyGroup(group)
end
-- Heals all allied units of specified player in an area
function HealArea(player, x, y, aoe, amount, effect, attach)
local group = CreateGroup()
local unit
GroupEnumUnitsInRange(group, x, y, aoe, nil)
for i = 0, BlzGroupGetSize(group) - 1 do
unit = BlzGroupUnitAt(group, i)
if IsUnitAlly(unit, player) and UnitAlive(unit) and not IsUnitType(unit, UNIT_TYPE_STRUCTURE) then
SetWidgetLife(unit, GetWidgetLife(unit) + amount)
if effect ~= "" then
if attach ~= "" then
DestroyEffect(AddSpecialEffectTarget(effect, unit, attach))
else
DestroyEffect(AddSpecialEffect(effect, GetUnitX(unit), GetUnitY(unit)))
end
end
end
end
DestroyGroup(group)
end
-- Pretty obvious.
function R2I2S(real)
return I2S(R2I(real))
end
-- Returns an ability real level field as a string. Usefull for toolltip manipulation.
function AbilityRealField(unit, ability, field, level, multiplier, integer)
if integer then
return R2I2S(BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ability), field, level)*multiplier)
else
return R2SW(BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ability), field, level)*multiplier, 1, 1)
end
end
-- Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModified(player, loc, duration)
local x = GetLocationX(loc)
local y = GetLocationY(loc)
local dx = x - GetCameraTargetPositionX()
local dy = y - GetCameraTargetPositionY()
local dist = SquareRoot(dx*dx + dy*dy)
if GetLocalPlayer() == player then
if dist >= bj_SMARTPAN_TRESHOLD_SNAP then
PanCameraToTimed(x, y, duration)
elseif dist >= bj_SMARTPAN_TRESHOLD_PAN then
PanCameraToTimed(x, y, duration)
else
-- User is close, dont move camera
end
end
end
-- Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModifiedXY(player, x, y, duration)
local dx = x - GetCameraTargetPositionX()
local dy = y - GetCameraTargetPositionY()
local dist = SquareRoot(dx*dx + dy*dy)
if GetLocalPlayer() == player then
if dist >= bj_SMARTPAN_TRESHOLD_SNAP then
PanCameraToTimed(x, y, duration)
elseif dist >= bj_SMARTPAN_TRESHOLD_PAN then
PanCameraToTimed(x, y, duration)
else
-- User is close, dont move camera
end
end
end
-- Start the cooldown for the source unit unit the new value
function StartUnitAbilityCooldown(unit, ability, cooldown)
local timer = CreateTimer()
TimerStart(timer, 0.01, false, function()
BlzStartUnitAbilityCooldown(unit, ability, cooldown)
PauseTimer(timer)
DestroyTimer(timer)
end)
end
-- ---------------------------------------------------------------------------------------------- --
-- Systems --
-- ---------------------------------------------------------------------------------------------- --
-- ----------------------------------------- Dummy Pool ----------------------------------------- --
do
local group = CreateGroup()
local player = Player(PLAYER_NEUTRAL_PASSIVE)
DummyPool = setmetatable({}, {})
local mt = getmetatable(DummyPool)
mt.__index = mt
function mt:recycle(unit)
if GetUnitTypeId(unit) ~= DUMMY then
print("[DummyPool] Error: Trying to recycle a non dummy unit")
else
GroupAddUnit(group, unit)
SetUnitX(unit, WorldBounds.maxX)
SetUnitY(unit, WorldBounds.maxY)
SetUnitOwner(unit, player, false)
ShowUnit(unit, false)
BlzPauseUnitEx(unit, true)
end
end
function mt:retrieve(owner, x, y, z, face)
if BlzGroupGetSize(group) > 0 then
bj_lastCreatedUnit = FirstOfGroup(group)
BlzPauseUnitEx(bj_lastCreatedUnit, false)
ShowUnit(bj_lastCreatedUnit, true)
GroupRemoveUnit(group, bj_lastCreatedUnit)
SetUnitX(bj_lastCreatedUnit, x)
SetUnitY(bj_lastCreatedUnit, y)
SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
BlzSetUnitFacingEx(bj_lastCreatedUnit, face*bj_RADTODEG)
SetUnitOwner(bj_lastCreatedUnit, owner, false)
else
bj_lastCreatedUnit = CreateUnit(owner, DUMMY, x, y, face*bj_RADTODEG)
SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
end
return bj_lastCreatedUnit
end
function mt:timed(unit, delay)
local timer = CreateTimer()
if GetUnitTypeId(unit) ~= DUMMY then
print("[DummyPool] Error: Trying to recycle a non dummy unit")
else
TimerStart(timer, delay, false, function()
GroupAddUnit(group, unit)
SetUnitX(unit, WorldBounds.maxX)
SetUnitY(unit, WorldBounds.maxY)
SetUnitOwner(unit, player, false)
ShowUnit(unit, false)
BlzPauseUnitEx(unit, true)
PauseTimer(timer)
DestroyTimer(timer)
end)
end
end
onInit(function()
local timer = CreateTimer()
local unit
TimerStart(timer, 0, false, function()
for i = 0, 20 do
unit = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
BlzPauseUnitEx(unit, false)
GroupAddUnit(group, unit)
end
PauseTimer(timer)
DestroyTimer(timer)
end)
end)
end
-- ---------------------------------------- Timed Ability --------------------------------------- --
do
TimedAbility = setmetatable({}, {})
local mt = getmetatable(TimedAbility)
mt.__index = mt
local timer = CreateTimer()
local ability = {}
local array = {}
local key = 0
function mt:destroy(i)
UnitRemoveAbility(self.unit, self.id)
array[i] = array[key]
key = key - 1
ability[self.unit][self.id] = nil
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:add(unit, id, duration, level, hide)
if not ability[unit] then ability[unit] = {} end
local this = ability[unit][id]
if not this then
this = {}
setmetatable(this, mt)
this.unit = unit
this.id = id
key = key + 1
array[key] = this
ability[unit][id] = this
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.duration <= 0 then
i = this:destroy(i)
end
this.duration = this.duration - PERIOD
i = i + 1
end
end)
end
end
if GetUnitAbilityLevel(unit, id) ~= level then
UnitAddAbility(unit, id)
SetUnitAbilityLevel(unit, id, level)
UnitMakeAbilityPermanent(unit, true, id)
BlzUnitHideAbility(unit, id, hide)
end
this.duration = duration
end
end
-- ----------------------------------------- Effect Link ---------------------------------------- --
do
EffectLink = setmetatable({}, {})
local mt = getmetatable(EffectLink)
mt.__index = mt
local timer = CreateTimer()
local array = {}
local items = {}
local key = 0
local k = 0
function mt:destroy(i, item)
DestroyEffect(self.effect)
if item then
items[i] = items[k]
k = k - 1
else
array[i] = array[key]
key = key - 1
if key == 0 then
PauseTimer(timer)
end
end
self = nil
return i - 1
end
function mt:buff(unit, buffId, model, attach)
local this = {}
setmetatable(this, mt)
key = key + 1
array[key] = this
this.unit = unit
this.buff = buffId
this.effect = AddSpecialEffectTarget(model, unit, attach)
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if GetUnitAbilityLevel(this.unit, this.buff) == 0 then
i = this:destroy(i, false)
end
i = i + 1
end
end)
end
end
function mt:item(unit, i, model, attach)
local this = {}
setmetatable(this, mt)
k = k + 1
items[k] = this
this.item = i
this.effect = AddSpecialEffectTarget(model, unit, attach)
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function()
local item = GetManipulatedItem()
local i = 1
local this
while i <= k do
this = items[i]
if this.item == item then
i = this:destroy(i, true)
end
i = i + 1
end
end)
end)
end
end
--[[
-- ------------------------ Indexer v1.1 by Chopinski ----------------------- --
Simple Unit Indexer for LUA.
Simply copya nd paste to import
]]--
do
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
local ability = FourCC('Adef')
local onIndex = {}
local onDeindex = {}
local id = 0
local source
local SetUnitId = SetUnitUserData
function SetUnitUserData(unit, id) end
local function IndexUnit(unit)
if GetUnitUserData(unit) == 0 then
id = id + 1
source = unit
if GetUnitAbilityLevel(unit, ability) == 0 then
UnitAddAbility(unit, ability)
UnitMakeAbilityPermanent(unit, true, ability)
BlzUnitDisableAbility(unit, ability, true, true)
end
SetUnitId(unit, id)
for i = 1, #onIndex do
onIndex[i]()
end
source = nil
end
end
onInit(function()
local trigger = CreateTrigger()
local region = CreateRegion()
local rect = GetWorldBounds()
RegionAddRect(region, rect)
RemoveRect(rect)
TriggerRegisterEnterRegion(CreateTrigger(), region, Filter(function()
IndexUnit(GetFilterUnit())
end))
for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function()
IndexUnit(GetFilterUnit())
end))
TriggerRegisterPlayerUnitEvent(trigger, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
end
TriggerAddCondition(trigger, Filter(function()
if GetIssuedOrderId() == 852056 then
if GetUnitAbilityLevel(GetTriggerUnit(), ability) == 0 then
source = GetTriggerUnit()
for i = 1, #onDeindex do
onDeindex[i]()
end
source = nil
end
end
end))
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function RegisterUnitIndexEvent(code)
if type(code) == "function" then
table.insert(onIndex, code)
end
end
function RegisterUnitDeindexEvent(code)
if type(code) == "function" then
table.insert(onDeindex, code)
end
end
function GetIndexUnit()
return source
end
end
--[[
Allow to retrieve the x and y position of a player mouse
]]--
do
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
local mouse = {}
local trigger = CreateTrigger()
onInit(function()
for i = 0, bj_MAX_PLAYER_SLOTS do
local player = Player(i)
if GetPlayerController(player) == MAP_CONTROL_USER and GetPlayerSlotState(player) == PLAYER_SLOT_STATE_PLAYING then
mouse[player] = {}
TriggerRegisterPlayerEvent(trigger, player, EVENT_PLAYER_MOUSE_MOVE)
end
end
TriggerAddCondition(trigger, Condition(function()
local player = GetTriggerPlayer()
mouse[player].x = BlzGetTriggerPlayerMouseX()
mouse[player].y = BlzGetTriggerPlayerMouseY()
end))
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function GetPlayerMouseX(player)
return mouse[player].x or 0
end
function GetPlayerMouseY(player)
return mouse[player].y or 0
end
end
--[[ mapbounds.lua v1.0.0 |
Description:
Nestharus's WorldBounds ported into Lua, with few simple but useful
additions. Aside from providing map boundary data thru variables,
also provides premade functions for checking whether a coordinate
is inside map boundaries, getting a random coordinate within
map boundaries, and getting a bounded coordinate value.
Requirements:
- None
API:
Prefixes:
MapBounds
- Refers to initial playable map bounds
WorldBounds
- Refers to world bounds
Variables:
number: <Prefix>.centerX
number: <Prefix>.centerY
number: <Prefix>.minX
number: <Prefix>.minY
number: <Prefix>.maxX
number: <Prefix>.maxY
rect: <Prefix>.rect
region: <Prefix>.region
- These variables are intended to be READONLY
Functions:
function <Prefix>:getRandomX() -> number
function <Prefix>:getRandomY() -> number
- Returns a random coordinate inside the bounds
function <Prefix>:getBoundedX(number: x, number: margin=0.00) -> number
function <Prefix>:getBoundedY(number: y, number: margin=0.00) -> number
- Returns a coordinate that is inside the bounds
function <Prefix>:containsX(number: x) -> boolean
function <Prefix>:containsY(number: y) -> boolean
- Checks if the bounds contain the input coordinate
]]--
MapBounds = setmetatable({}, {})
WorldBounds = setmetatable({}, getmetatable(MapBounds))
do
local mt = getmetatable(MapBounds)
mt.__index = mt
function mt:getRandomX()
return GetRandomReal(self.minX, self.maxX)
end
function mt:getRandomY()
return GetRandomReal(self.minY, self.maxY)
end
local function GetBoundedValue(bounds, v, minV, maxV, margin)
margin = margin or 0.00
if v < (bounds[minV] + margin) then
return bounds[minV] + margin
elseif v > (bounds[maxV] - margin) then
return bounds[maxV] - margin
end
return v
end
function mt:getBoundedX(x, margin)
return GetBoundedValue(self, x, "minX", "maxX", margin)
end
function mt:getBoundedY(y, margin)
return GetBoundedValue(self, y, "minY", "maxY", margin)
end
function mt:containsX(x)
return self:getBoundedX(x) == x
end
function mt:containsY(y)
return self:getBoundedY(y) == y
end
local function InitData(bounds)
bounds.region = CreateRegion()
bounds.minX = GetRectMinX(bounds.rect)
bounds.minY = GetRectMinY(bounds.rect)
bounds.maxX = GetRectMaxX(bounds.rect)
bounds.maxY = GetRectMaxY(bounds.rect)
bounds.centerX = (bounds.minX + bounds.maxX) / 2.00
bounds.centerY = (bounds.minY + bounds.maxY) / 2.00
RegionAddRect(bounds.region, bounds.rect)
end
local oldInit = InitGlobals
function InitGlobals()
oldInit()
MapBounds.rect = bj_mapInitialPlayableArea
WorldBounds.rect = GetWorldBounds()
InitData(MapBounds)
InitData(WorldBounds)
end
end
--[[ LineSegmentEnumeration v2.2a
API:
function LineSegment.EnumUnits(number: ax, number: ay, number: bx, number: by, number: offset, boolean: checkCollision)
function LineSegment.EnumDestructables(number: ax, number: ay, number: bx, number: by, number: offset)
function LineSegment.EnumItems(number: ax, number: ay, number: bx, number: by, number: offset)
- returns the enumerated widgets as a table
]]--
LineSegment = {}
do
local RECT = Rect(0, 0, 0, 0)
local GROUP = CreateGroup()
local ox
local oy
local dx
local dy
local da
local db
local ui
local uj
local wdx
local wdy
local uui
local uuj
local function prepare_rect(ax, ay, bx, by, offset)
local x_max
local x_min
local y_max
local y_min
-- get center coordinates of rectangle
ox, oy = 0.5*(ax + bx), 0.5*(ay + by)
-- get rectangle major axis as vector
dx, dy = 0.5*(bx - ax), 0.5*(by - ay)
-- get half of rectangle length (da) and height (db)
da, db = math.sqrt(dx*dx + dy*dy), offset
-- get unit vector of the major axis
ui, uj = dx/da, dy/da
-- prepare bounding rect
if ax > bx then
x_min, x_max = bx - offset, ax + offset
else
x_min, x_max = ax - offset, bx + offset
end
if ay > by then
y_min, y_max = by - offset, ay + offset
else
y_min, y_max = ay - offset, by + offset
end
SetRect(RECT, x_min, y_min, x_max, y_max)
end
local function rect_contains_widget(w, offset)
wdx, wdy = GetWidgetX(w) - ox, GetWidgetY(w) - oy
dx, dy = wdx*ui + wdy*uj, wdx*(-uj) + wdy*ui
da, db = da + offset, db + offset
return dx*dx <= da*da and dy*dy <= db*db
end
local function widget_filter(w, offset)
if rect_contains_widget(w, offset) then
table.insert(LineSegment.enumed, w)
end
end
function LineSegment.EnumUnits(ax, ay, bx, by, offset, checkCollision)
prepare_rect(ax, ay, bx, by, offset)
GroupEnumUnitsInRect(GROUP, RECT)
local enumed = {}
LineSegment.enumed = enumed
for i = 0, BlzGroupGetSize(GROUP) - 1 do
local u = BlzGroupUnitAt(GROUP, i)
widget_filter(u, checkCollision and BlzGetUnitCollisionSize(u) or 0.)
end
return enumed
end
function LineSegment.EnumDestructables(ax, ay, bx, by, offset)
prepare_rect(ax, ay, bx, by, offset)
local enumed = {}
LineSegment.enumed = enumed
EnumDestructablesInRect(RECT, Filter(function ()
widget_filter(GetFilterDestructable(), 0.)
end))
return enumed
end
function LineSegment.EnumItems(ax, ay, bx, by, offset)
prepare_rect(ax, ay, bx, by, offset)
local enumed = {}
LineSegment.enumed = enumed
EnumItemsInRect(RECT, Filter(function ()
widget_filter(GetFilterItem(), 0.)
end))
return enumed
end
end
--[[
/**************************************************************
*
* v1.0.5 by TriggerHappy
* ----------------------
*
* Use this to destroy a handle after X amount seconds.
*
* It's useful for things like effects where you may
* want it to be temporary, but not have to worry
* about the cleaning memory leak. By default it supports
* effects, lightning, weathereffect, items, ubersplats, and units.
*
* Installation
----------------------
* 1. Copy this script and over to your map inside a blank trigger.
*
* API
* ----------------------
* call DestroyEffectTimed(AddSpecialEffect("effect.mdx", 0, 0), 5)
* call DestroyLightningTimed(AddLightning("CLPB", true, 0, 0, 100, 100), 5)
*
**************************************************************/
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local PERIOD = 0.05
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
Timed = setmetatable({}, {})
local mt = getmetatable(Timed)
mt.__index = mt
local timer = CreateTimer()
local array = {}
local key = 0
function mt:destroy(i)
if self.flag == 0 then
DestroyEffect(self.type)
elseif self.flag == 1 then
DestroyLightning(self.type)
elseif self.flag == 2 then
RemoveWeatherEffect(self.type)
elseif self.flag == 3 then
RemoveItem(self.type)
elseif self.flag == 4 then
RemoveUnit(self.type)
elseif self.flag == 5 then
DestroyUbersplat(self.type)
elseif self.flag == 6 then
RemoveDestructable(self.type)
end
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:handle(type, duration, flag)
local this = {}
setmetatable(this, mt)
this.type = type
this.flag = flag
this.ticks = duration/PERIOD
key = key + 1
array[key] = this
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:destroy(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function DestroyEffectTimed(effect, duration)
Timed:handle(effect, duration, 0)
end
function DestroyLightningTimed(lightning, duration)
Timed:handle(lightning, duration, 1)
end
function RemoveWeatherEffectTimed(weathereffect, duration)
Timed:handle(weathereffect, duration, 2)
end
function RemoveItemTimed(item, duration)
Timed:handle(item, duration, 3)
end
function RemoveUnitTimed(unit, duration)
Timed:handle(unit, duration, 4)
end
function DestroyUbersplatTimed(ubersplat, duration)
Timed:handle(ubersplat, duration, 5)
end
function RemoveDestructableTimed(destructable, duration)
Timed:handle(destructable, duration, 6)
end
end
--[[
/* ------------------- SpellEffectEvent v1.1 by Chopinski ------------------ */
-- Full credits to Bribe for the original library. I just modified it to store
-- some usefull information in a table to be used later instead of calling
-- these functions all the time for every ability.
/* ----------------------------------- END ---------------------------------- */
]]--
do
local funcs = {}
local trigger = nil
local location = Location(0, 0)
Spell = {
source = {
unit,
player,
handle,
isHero,
isStructure,
id,
x,
y,
z
},
target = {
unit,
player,
handle,
isHero,
isStructure,
id,
x,
y,
z
},
ability,
level,
id,
x,
y,
z
}
local function GetUnitZ(unit)
MoveLocation(location, GetUnitX(unit), GetUnitY(unit))
return GetUnitFlyHeight(unit) + GetLocationZ(location)
end
local function GetSpellTargetZ()
MoveLocation(location, Spell.x, Spell.y)
if Spell.target.unit then
return GetUnitZ(Spell.target.unit)
else
return GetLocationZ(location)
end
end
function RegisterSpellEffectEvent(ability, code)
if type(code) == "function" then
if not trigger then
trigger = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerAddCondition(trigger, Condition(function()
local f = funcs[GetSpellAbilityId()]
if f then
if GetUnitAbilityLevel(GetTriggerUnit(), FourCC('Aloc')) == 0 then
Spell.source.unit = GetTriggerUnit()
Spell.source.player = GetOwningPlayer(Spell.source.unit)
Spell.source.handle = GetHandleId(Spell.source.unit)
Spell.source.id = GetUnitUserData(Spell.source.unit)
Spell.source.x = GetUnitX(Spell.source.unit)
Spell.source.y = GetUnitY(Spell.source.unit)
Spell.source.z = GetUnitZ(Spell.source.unit)
Spell.source.isHero = IsUnitType(Spell.source.unit, UNIT_TYPE_HERO)
Spell.source.isStructure = IsUnitType(Spell.source.unit, UNIT_TYPE_STRUCTURE)
Spell.target.unit = GetSpellTargetUnit()
Spell.target.player = GetOwningPlayer(Spell.target.unit)
Spell.target.handle = GetHandleId(Spell.target.unit)
Spell.target.id = GetUnitUserData(Spell.target.unit)
Spell.target.x = GetUnitX(Spell.target.unit)
Spell.target.y = GetUnitY(Spell.target.unit)
Spell.target.z = GetUnitZ(Spell.target.unit)
Spell.target.isHero = IsUnitType(Spell.target.unit, UNIT_TYPE_HERO)
Spell.target.isStructure = IsUnitType(Spell.target.unit, UNIT_TYPE_STRUCTURE)
Spell.x = GetSpellTargetX()
Spell.y = GetSpellTargetY()
Spell.z = GetSpellTargetZ()
Spell.id = GetSpellAbilityId()
Spell.level = GetUnitAbilityLevel(Spell.source.unit, Spell.id)
Spell.ability = BlzGetUnitAbility(Spell.source.unit, Spell.id)
end
f()
end
end))
end
funcs[ability] = code
end
end
end
-- Arcing Text Tag v1.0.0.3 by Maker encoded to Lua
DEFINITION = 1.0/32.0
SIZE_MIN = 0.013 -- Minimum size of text
SIZE_BONUS = 0.005 -- Text size increase
TIME_LIFE = 0.5 -- How long the text lasts
TIME_FADE = 0.3 -- When does the text start to fade
Z_OFFSET = 50 -- Height above unit
Z_OFFSET_BON = 50 -- How much extra height the text gains
VELOCITY = 2.0 -- How fast the text move in x/y plane
TMR = CreateTimer()
ANGLE_RND = true -- Is the angle random or fixed
if not ANGLE_RND then
ANGLE = bj_PI/2.0 -- If fixed, specify the Movement angle of the text.
end
tt = {}
as = {} -- angle, sin component
ac = {} -- angle, cos component
ah = {} -- arc height
t = {} -- time
x = {} -- origin x
y = {} -- origin y
str = {} -- text
ic = 0 -- Instance count
rn = {} ; rn[0] = 0
next = {} ; next[0] = 0
prev = {} ; prev[0] = 0 --Needed due to Lua not initializing them.
function ArcingTextTag(s, u)
local this = rn[0]
if this == 0 then
ic = ic + 1
this = ic
else
rn[0] = rn[this]
end
next[this] = 0
prev[this] = prev[0]
next[prev[0]] = this
prev[0] = this
str[this] = s
x[this] = GetUnitX(u)
y[this] = GetUnitY(u)
t[this] = TIME_LIFE
local a
if ANGLE_RND then
a = GetRandomReal(0, 2*bj_PI)
else
a = ANGLE
end
as[this] = Sin(a)*VELOCITY
ac[this] = Cos(a)*VELOCITY
ah[this] = 0.
if IsUnitVisible(u, GetLocalPlayer()) then
tt[this] = CreateTextTag()
SetTextTagPermanent(tt[this], false)
SetTextTagLifespan(tt[this], TIME_LIFE)
SetTextTagFadepoint(tt[this], TIME_FADE)
SetTextTagText(tt[this], s, SIZE_MIN)
SetTextTagPos(tt[this], x[this], y[this], Z_OFFSET)
end
if prev[this] == 0 then
TimerStart(TMR, DEFINITION, true, function()
local this = next[0]
local p
while (this ~= 0) do
p = Sin(bj_PI*t[this])
t[this] = t[this] - DEFINITION
x[this] = x[this] + ac[this]
y[this] = y[this] + as[this]
SetTextTagPos(tt[this], x[this], y[this], Z_OFFSET + Z_OFFSET_BON * p)
SetTextTagText(tt[this], str[this], SIZE_MIN + SIZE_BONUS * p)
if t[this] <= 0.0 then
tt[this] = null
next[prev[this]] = next[this]
prev[next[this]] = prev[this]
rn[this] = rn[0]
rn[0] = this
if next[0] == 0 then
PauseTimer(TMR)
end
end
this = next[this]
end
end)
end
return this
end
--[[
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
* Lua version by Chopinski
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
]]--
do
local trigger = {}
local f = {}
local n = {}
function RegisterPlayerUnitEvent(playerunitevent, code)
if type(code) == "function" then
local i = GetHandleId(playerunitevent)
if not trigger[i] then
trigger[i] = CreateTrigger()
for j = 0, bj_MAX_PLAYERS do
TriggerRegisterPlayerUnitEvent(trigger[i], Player(j), playerunitevent, null)
end
end
if not n[i] then n[i] = 1 end
if not f[i] then f[i] = {} end
table.insert(f[i], code)
TriggerAddCondition(trigger[i], Filter(function()
f[i][n[i]]()
n[i] = n[i] + 1
if n[i] > #f[i] then n[i] = 1 end
end))
end
end
function RegisterPlayerUnitEventForPlayer(playerunitevent, code, player)
if type(code) == "function" then
local i = (bj_MAX_PLAYERS + 1) * GetHandleId(playerunitevent) + GetPlayerId(player)
if not trigger[i] then
trigger[i] = CreateTrigger()
TriggerRegisterPlayerUnitEvent(trigger[i], player, playerunitevent, null)
end
if not n[i] then n[i] = 1 end
if not f[i] then f[i] = {} end
table.insert(f[i], code)
TriggerAddCondition(event[i].trigger, Filter(function()
f[i][n[i]]()
n[i] = n[i] + 1
if n[i] > #f[i] then n[i] = 1 end
end))
end
end
function GetPlayerUnitEventTrigger(playerunitevent)
return trigger[GetHandleId(playerunitevent)]
end
end
--[[
-- ------------------------------------- Missile Effect v2.8 ------------------------------------ --
-- Credits to Forsakn for the first translation of Missile Effect to LUA
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
MissileEffect = setmetatable({}, {})
local mt = getmetatable(MissileEffect)
mt.__index = mt
function mt:destroy()
local size = #self.array
for i = 1, size do
local this = self.array[i]
DestroyEffect(this.effect)
this = nil
end
DestroyEffect(self.effect)
self = nil
end
function mt:scale(effect, scale)
self.size = scale
BlzSetSpecialEffectScale(effect, scale)
end
function mt:orient(yaw, pitch, roll)
self.yaw = yaw
self.pitch = pitch
self.roll = roll
BlzSetSpecialEffectOrientation(self.effect, yaw, pitch, roll)
for i = 1, #self.array do
local this = self.array[i]
this.yaw = yaw
this.pitch = pitch
this.roll = roll
BlzSetSpecialEffectOrientation(this.effect, yaw, pitch, roll)
end
end
function mt:move(x, y, z)
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
BlzSetSpecialEffectPosition(self.effect, x, y, z)
for i = 1, #self.array do
local this = self.array[i]
BlzSetSpecialEffectPosition(this.effect, x - this.x, y - this.y, z - this.z)
end
return true
end
return false
end
function mt:attach(model, dx, dy, dz, scale)
local this = {}
this.x = dx
this.y = dy
this.z = dz
this.yaw = 0
this.pitch = 0
this.roll = 0
this.path = model
this.size = scale
this.effect = AddSpecialEffect(model, dx, dy)
BlzSetSpecialEffectZ(this.effect, dz)
BlzSetSpecialEffectScale(this.effect, scale)
BlzSetSpecialEffectPosition(this.effect, BlzGetLocalSpecialEffectX(this.effect) - dx, BlzGetLocalSpecialEffectY(this.effect) - dy, BlzGetLocalSpecialEffectZ(this.effect) - dz)
table.insert(self.array, this)
return this.effect
end
function mt:detach(effect)
for i = 1, #self.array do
local this = self.array[i]
if this.effect == effect then
table.remove(self.array, i)
DestroyEffect(effect)
this = nil
break
end
end
end
function mt:setColor(red, green, blue)
BlzSetSpecialEffectColor(self.effect, red, green, blue)
end
function mt:timeScale(real)
BlzSetSpecialEffectTimeScale(self.effect, real)
end
function mt:alpha(integer)
BlzSetSpecialEffectAlpha(self.effect, integer)
end
function mt:playerColor(integer)
BlzSetSpecialEffectColorByPlayer(self.effect, Player(integer))
end
function mt:animation(integer)
BlzPlaySpecialEffect(self.effect, ConvertAnimType(integer))
end
function mt:create(x, y, z)
local this = {}
setmetatable(this, mt)
this.path = ""
this.size = 1
this.yaw = 0
this.pitch = 0
this.roll = 0
this.array = {}
this.effect = AddSpecialEffect("", x, y)
BlzSetSpecialEffectZ(this.effect, z)
return this
end
end
--[[ requires Missiles
-- ------------------------------------- Missile Utils v2.8 ------------------------------------- --
-- This is a simple Utils library for the Relativistic Missiles system.
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
function CreateMissileGroup()
return MissileGroup:create()
end
function DestroyMissileGroup(group)
if group then
group:destroy()
end
end
function MissileGroupGetSize(group)
if group then
return #group.group
else
return 0
end
end
function GroupMissileAt(group, position)
if group then
return group:missileAt(position)
else
return nil
end
end
function ClearMissileGroup(group)
if group then
group:clear()
end
end
function IsMissileInGroup(missile, group)
if group and missile then
if #group.group > 0 then
return group:contains(missile)
else
return false
end
else
return false
end
end
function GroupRemoveMissile(group, missile)
if group and missile then
if #group.group > 0 then
group:remove(missile)
end
end
end
function GroupAddMissile(group, missile)
if group and missile then
if not group:contains(missile) then
group:insert(missile)
end
end
end
function GroupPickRandomMissile(group)
if group then
if #group.group > 0 then
return group:missileAt(GetRandomInt(0, #group.group - 1))
else
return nil
end
else
return nil
end
end
function FirstOfMissileGroup(group)
if group then
if #group.group > 0 then
return group.group[1]
else
return nil
end
else
return nil
end
end
function GroupAddMissileGroup(source, destiny)
if source and destiny then
if #source.group > 0 and source ~= destiny then
destiny:addGroup(source)
end
end
end
function GroupRemoveMissileGroup(source, destiny)
if source and destiny then
if source == destiny then
source:clear()
elseif #source.group > 0 then
destiny:removeGroup(source)
end
end
end
function GroupEnumMissilesOfType(group, type)
if group then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
if missile.type == type then
group:insert(missile)
end
end
end
end
end
function GroupEnumMissilesOfTypeCounted(group, type, amount)
local i = 0
local j = amount
if group then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
while i <= Missiles.count and j > 0 do
local missile = Missiles.collection[i]
if missile.type == type then
group:insert(missile)
end
j = j - 1
i = i + 1
end
end
end
end
function GroupEnumMissilesOfPlayer(group, player)
if group then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
if missile.owner == player then
group:insert(missile)
end
end
end
end
end
function GroupEnumMissilesOfPlayerCounted(group, player, amount)
local i = 0
local j = amount
if group then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
while i <= Missiles.count and j > 0 do
local missile = Missiles.collection[i]
if missile.owner == player then
group:insert(missile)
end
j = j - 1
i = i + 1
end
end
end
end
function GroupEnumMissilesInRect(group, rect)
if group and rect then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
if GetRectMinX(rect) <= missile.x and missile.x <= GetRectMaxX(rect) and GetRectMinY(rect) <= missile.y and missile.y <= GetRectMaxY(rect) then
group:insert(missile)
end
end
end
end
end
function GroupEnumMissilesInRectCounted(group, rect, amount)
local i = 0
local j = amount
if group and rect then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
while i <= Missiles.count and j > 0 do
local missile = Missiles.collection[i]
if GetRectMinX(rect) <= missile.x and missile.x <= GetRectMaxX(rect) and GetRectMinY(rect) <= missile.y and missile.y <= GetRectMaxY(rect) then
group:insert(missile)
end
j = j - 1
i = i + 1
end
end
end
end
function GroupEnumMissilesInRangeOfLoc(group, location, radius)
if group and location and radius > 0 then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
local dx = missile.x - GetLocationX(location)
local dy = missile.y - GetLocationY(location)
if SquareRoot(dx*dx + dy*dy) <= radius then
group:insert(missile)
end
end
end
end
end
function GroupEnumMissilesInRangeOfLocCounted(group, location, radius, amount)
local i = 0
local j = amount
if group and location and radius > 0 then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
while i <= Missiles.count and j > 0 do
local missile = Missiles.collection[i]
local dx = missile.x - GetLocationX(location)
local dy = missile.y - GetLocationY(location)
if SquareRoot(dx*dx + dy*dy) <= radius then
group:insert(missile)
end
j = j - 1
i = i + 1
end
end
end
end
function GroupEnumMissilesInRange(group, x, y, radius)
if group and radius > 0 then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
local dx = missile.x - x
local dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
group:insert(missile)
end
end
end
end
end
function GroupEnumMissilesInRangeCounted(group, x, y, radius, amount)
local i = 0
local j = amount
if group and radius > 0 then
if Missiles.count > -1 then
if #group.group > 0 then
group:clear()
end
while i <= Missiles.count and j > 0 do
local missile = Missiles.collection[i]
local dx = missile.x - x
local dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
group:insert(missile)
end
j = j - 1
i = i + 1
end
end
end
end
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
MissileGroup = setmetatable({}, {})
local mt = getmetatable(MissileGroup)
mt.__index = mt
function mt:destroy()
self.group = nil
self.set = nil
self = nil
end
function mt:missileAt(i)
if #self.group > 0 and i <= #self.group - 1 then
return self.group[i + 1]
else
return 0
end
end
function mt:remove(missile)
for i = 1, #self.group do
if self.group[i] == missile then
self.set[missile] = nil
table.remove(self.group, i)
break
end
end
end
function mt:insert(missile)
table.insert(self.group, missile)
self.set[missile] = missile
end
function mt:clear()
local size = #self.group
for i = 1, size do
self.set[i] = nil
self.group[i] = nil
end
end
function mt:contains(missile)
return self.set[missile] ~= nil
end
function mt:addGroup(this)
for i = 1, #this.group do
if not self:contains(this.group[i]) then
self:insert(this.group[i])
end
end
end
function mt:removeGroup(this)
for i = 1, #this.group do
if self:contains(this.group[i]) then
self:remove(this.group[i])
end
end
end
function mt:create()
local this = {}
setmetatable(this, mt)
this.group = {}
this.set = {}
return this
end
end
--[[ requires MissileEffect, optional MissilesUtils
-- ---------------------------------------- Missiles v2.8 --------------------------------------- --
-- Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
-- this Missiles library. Credits and thanks to AGD and for the effect orientation ideas.
-- This version of Missiles requires patch 1.31+. Thanks to Forsakn for the first translation
-- of the vJASS version of Missiles into LUA.
--
-- How to Import:
-- 1 - Copy this, MissileEffect and optionaly the MissileUtils libraries into your map
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
-- The update period of the system
local PERIOD = 1. / 40.
-- The max amount of Missiles processed in a PERIOD
-- You can play around with both these values to find
-- your sweet spot. If equal to 0, the system will
-- process all missiles at once every period.
local SWEET_SPOT = 600
-- the avarage collision size compensation when detecting collisions
local COLLISION_SIZE = 128.
-- item size used in z collision
local ITEM_SIZE = 16.
-- Raw code of the dummy unit used for vision
local DUMMY = FourCC('dumi')
-- Needed, dont touch. Seriously, dont touch!
local location = Location(0., 0.)
local rect = Rect(0., 0., 0., 0.)
local function GetLocZ(x, y)
MoveLocation(location, x, y)
return GetLocationZ(location)
end
local function GetUnitZ(unit)
return GetLocZ(GetUnitX(unit), GetUnitY(unit)) + GetUnitFlyHeight(unit)
end
local function SetUnitZ(unit, z)
SetUnitFlyHeight(unit, z - GetLocZ(GetUnitX(unit), GetUnitY(unit)), 0)
end
local function GetMapCliffLevel()
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
end
do
Pool = setmetatable({}, {})
local mt = getmetatable(Pool)
mt.__index = mt
local player = Player(PLAYER_NEUTRAL_PASSIVE)
local group = CreateGroup()
function mt:recycle(unit)
if GetUnitTypeId(unit) == DUMMY then
GroupAddUnit(group, unit)
SetUnitX(unit, WorldBounds.maxX)
SetUnitY(unit, WorldBounds.maxY)
SetUnitOwner(unit, player, false)
PauseUnit(unit, true)
end
end
function mt:retrieve(x, y, z, face)
if BlzGroupGetSize(group) > 0 then
bj_lastCreatedUnit = FirstOfGroup(group)
PauseUnit(bj_lastCreatedUnit, false)
GroupRemoveUnit(group, bj_lastCreatedUnit)
SetUnitX(bj_lastCreatedUnit, x)
SetUnitY(bj_lastCreatedUnit, y)
SetUnitZ(bj_lastCreatedUnit, z)
BlzSetUnitFacingEx(bj_lastCreatedUnit, face)
else
bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
SetUnitZ(bj_lastCreatedUnit, z)
UnitRemoveAbility(bj_lastCreatedUnit, FourCC('Amrf'))
end
return bj_lastCreatedUnit
end
function mt:recycleTimed(unit, delay)
if GetUnitTypeId(unit) == DUMMY then
local timer = CreateTimer()
TimerStart(timer, delay, false, function()
self:recycle(unit)
PauseTimer(timer)
DestroyTimer(timer)
end)
end
end
onInit(function()
local timer = CreateTimer()
TimerStart(timer, 0, false, function()
for i = 0, SWEET_SPOT do
local unit = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
PauseUnit(unit, false)
GroupAddUnit(group, unit)
UnitRemoveAbility(unit, FourCC('Amrf'))
end
PauseTimer(timer)
DestroyTimer(timer)
end)
end)
end
do
Coordinates = setmetatable({}, {})
local mt = getmetatable(Coordinates)
mt.__index = mt
function mt:destroy()
self = nil
end
function mt:math(a, b)
local dx
local dy
while true do
dx = b.x - a.x
dy = b.y - a.y
dx = dx * dx + dy * dy
dy = SquareRoot(dx)
if dx ~= 0. and dy ~= 0. then
break
end
b.x = b.x + .01
b.z = b.z - GetLocZ(b.x - .01, b.y) + GetLocZ(b.x, b.y)
end
a.square = dx
a.distance = dy
a.angle = Atan2(b.y - a.y, b.x - a.x)
a.slope = (b.z - a.z) / dy
a.alpha = Atan(a.slope)
-- Set b.
if b.ref == a then
b.angle = a.angle + bj_PI
b.distance = dy
b.slope = -a.slope
b.alpha = -a.alpha
b.square = dx
end
end
function mt:link(a, b)
a.ref = b
b.ref = a
self:math(a, b)
end
function mt:move(toX, toY, toZ)
self.x = toX
self.y = toY
self.z = toZ + GetLocZ(toX, toY)
if self.ref ~= self then
self:math(self, self.ref)
end
end
function mt:create(x, y, z)
local c = {}
setmetatable(c, mt)
c.ref = c
c:move(x, y, z)
return c
end
end
-- -------------------------------------------------------------------------- --
-- Missiles --
-- -------------------------------------------------------------------------- --
Missiles = setmetatable({}, {})
local mt = getmetatable(Missiles)
mt.__index = mt
Missiles.collection = {}
Missiles.count = -1
local timer = CreateTimer()
local group = CreateGroup()
local id = -1
local pid = -1
local last = 0
local dilation = 1
local array = {}
local missiles = {}
local frozen = {}
local keys = {}
local index = 1
local yaw = 0
local pitch = 0
local travelled = 0
function mt:OnHit()
if self.onHit then
if self.allocated and self.collision > 0 then
GroupEnumUnitsInRange(group, self.x, self.y, self.collision + COLLISION_SIZE, nil)
local unit = FirstOfGroup(group)
while unit do
if array[self][unit] == nil then
if IsUnitInRangeXY(unit, self.x, self.y, self.collision) then
if self.collideZ then
local dx = GetLocZ(GetUnitX(unit), GetUnitY(unit)) + GetUnitFlyHeight(unit)
local dy = BlzGetUnitCollisionSize(unit)
if dx + dy >= self.z - self.collision and dx <= self.z + self.collision then
array[self][unit] = true
if self.allocated and self.onHit(unit) then
self:terminate()
break
end
end
else
array[self][unit] = true
if self.allocated and self.onHit(unit) then
self:terminate()
break
end
end
end
end
GroupRemoveUnit(group, unit)
unit = FirstOfGroup(group)
end
end
end
end
function mt:OnMissile()
if self.onMissile then
if self.allocated and self.collision > 0 then
for i = 0, Missiles.count do
local missile = Missiles.collection[i]
if missile ~= self then
if array[self][missile] == nil then
local dx = missile.x - self.x
local dy = missile.y - self.y
if SquareRoot(dx*dx + dy*dy) <= self.collision then
array[self][missile] = true
if self.allocated and self.onMissile(missile) then
self:terminate()
break
end
end
end
end
end
end
end
end
function mt:OnDestructable()
if self.onDestructable then
if self.allocated and self.collision > 0 then
local dx = self.collision
SetRect(rect, self.x - dx, self.y - dx, self.x + dx, self.y + dx)
EnumDestructablesInRect(rect, nil, function()
local destructable = GetEnumDestructable()
if array[self][destructable] == nil then
if self.collideZ then
local dz = GetLocZ(GetWidgetX(destructable), GetWidgetY(destructable))
local tz = GetDestructableOccluderHeight(destructable)
if dz + tz >= self.z - self.collision and dz <= self.z + self.collision then
array[self][destructable] = true
if self.allocated and self.onDestructable(destructable) then
self:terminate()
return
end
end
else
array[self][destructable] = true
if self.allocated and self.onDestructable(destructable) then
self:terminate()
return
end
end
end
end)
end
end
end
function mt:OnItem()
if self.onItem then
if self.allocated and self.collision > 0 then
local dx = self.collision
SetRect(rect, self.x - dx, self.y - dx, self.x + dx, self.y + dx)
EnumItemsInRect(rect, nil, function()
local item = GetEnumItem()
if array[self][item] == nil then
if self.collideZ then
local dz = GetLocZ(GetItemX(item), GetItemY(item))
if dz + ITEM_SIZE >= self.z - self.collision and dz <= self.z + self.collision then
array[self][item] = true
if self.allocated and self.onItem(item) then
self:terminate()
return
end
end
else
array[self][item] = true
if self.allocated and self.onItem(item) then
self:terminate()
return
end
end
end
end)
end
end
end
function mt:OnCliff()
if self.onCliff then
local dx = GetTerrainCliffLevel(self.nextX, self.nextY)
local dy = GetTerrainCliffLevel(self.x, self.y)
if dy < dx and self.z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if self.allocated and self.onCliff() then
self:terminate()
end
end
end
end
function mt:OnTerrain()
if self.onTerrain then
if GetLocZ(self.x, self.y) > self.z then
if self.allocated and self.onTerrain() then
self:terminate()
end
end
end
end
function mt:OnTileset()
if self.onTileset then
local type = GetTerrainType(self.x, self.y)
if type ~= self.tileset then
if self.allocated and self.onTileset(type) then
self:terminate()
end
end
self.tileset = type
end
end
function mt:OnPeriod()
if self.onPeriod then
if self.allocated and self.onPeriod() then
self:terminate()
end
end
end
function mt:OnOrient()
local a
-- Homing or not
if self.target and GetUnitTypeId(self.target) ~= 0 then
self.impact:move(GetUnitX(self.target), GetUnitY(self.target), GetUnitFlyHeight(self.target) + self.toZ)
local dx = self.impact.x - self.nextX
local dy = self.impact.y - self.nextY
a = Atan2(dy, dx)
self.travel = self.origin.distance - SquareRoot(dx*dx + dy*dy)
else
a = self.origin.angle
self.target = nil
end
-- turn rate
if self.turn ~= 0 and not (Cos(self.cA - a) >= Cos(self.turn)) then
if Sin(a - self.cA) >= 0 then
self.cA = self.cA + self.turn
else
self.cA = self.cA - self.turn
end
else
self.cA = a
end
local vel = self.veloc*dilation
yaw = self.cA
travelled = self.travel + vel
self.veloc = self.veloc + self.acceleration
self.travel = travelled
pitch = self.origin.alpha
self.prevX = self.x
self.prevY = self.y
self.prevZ = self.z
self.x = self.nextX
self.y = self.nextY
self.z = self.nextZ
self.nextX = self.x + vel*Cos(yaw)
self.nextY = self.y + vel*Sin(yaw)
-- arc calculation
local s = travelled
local d = self.origin.distance
local h = self.height
if h ~= 0 or self.origin.slope ~= 0 then
self.nextZ = 4*h*s*(d-s)/(d*d) + self.origin.slope*s + self.origin.z
pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))
end
-- curve calculation
local c = self.open
if c ~= 0 then
local dx = 4 * c * s * (d - s) / (d * d)
a = yaw + bj_PI / 2
self.x = self.x + dx * Cos(a)
self.y = self.y + dx * Sin(a)
yaw = yaw + Atan(-((4 * c) * (2 * s - d)) / (d * d))
end
end
function mt:OnFinish()
if travelled >= self.origin.distance - 0.0001 then
self.finished = true
if self.onFinish then
if self.allocated and self.onFinish() then
self:terminate()
else
if self.travel > 0 and not self.paused then
self:terminate()
end
end
else
self:terminate()
end
else
if not self.roll then
self.effect:orient(yaw, -pitch, 0)
else
self.effect:orient(yaw, -pitch, Atan2(self.open, self.height))
end
end
end
function mt:OnBoundaries()
if not self.effect:move(self.x, self.y, self.z) then
if self.onBoundaries then
if self.allocated and self.onBoundaries() then
self:terminate()
end
end
else
if self.dummy then
SetUnitX(self.dummy, self.x)
SetUnitY(self.dummy, self.y)
end
end
end
function mt:OnPause()
pid = pid + 1
self.pkey = pid
frozen[pid] = self
if self.onPause then
if self.allocated and self.onPause() then
self:terminate()
end
end
end
function mt:OnResume(flag)
local this
self.paused = flag
if not self.paused and self.pkey ~= -1 then
id = id + 1
missiles[id] = self
this = frozen[pid]
this.pkey = self.pkey
frozen[self.pkey] = frozen[pid]
pid = pid - 1
self.pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
dilation = (id + 1)/SWEET_SPOT
else
dilation = 1.
end
if id == 0 then
TimerStart(timer, PERIOD, true, function() Missiles:move() end)
end
if self.onResume then
if self.allocated and self.onResume() then
self:terminate()
else
if self.finished then
self:terminate()
end
end
else
if self.finished then
self:terminate()
end
end
end
end
function mt:OnRemove()
local this
if self.allocated and self.launched then
self.allocated = false
if self.pkey ~= -1 then
this = frozen[pid]
this.pkey = self.pkey
frozen[self.pkey] = frozen[pid]
pid = pid - 1
self.pkey = -1
end
if self.onRemove then
self.onRemove()
end
if self.dummy then
Pool:recycle(self.dummy)
end
this = Missiles.collection[Missiles.count]
this.index = self.index
Missiles.collection[self.index] = Missiles.collection[Missiles.count]
Missiles.count = Missiles.count - 1
self.index = -1
self.origin:destroy()
self.impact:destroy()
self.effect:destroy()
self:reset()
array[self] = nil
end
end
-- -------------------------- Model of the missile -------------------------- --
function mt:model(effect)
DestroyEffect(self.effect.effect)
self.effect.path = effect
self.Model = effect
self.effect.effect = AddSpecialEffect(effect, self.origin.x, self.origin.y)
BlzSetSpecialEffectZ(self.effect.effect, self.origin.z)
BlzSetSpecialEffectYaw(self.effect.effect, self.cA)
end
-- ----------------------------- Curved movement ---------------------------- --
function mt:curve(value)
self.open = Tan(value * bj_DEGTORAD) * self.origin.distance
self.Curve = value
end
-- ----------------------------- Arced Movement ----------------------------- --
function mt:arc(value)
self.height = Tan(value * bj_DEGTORAD) * self.origin.distance / 4
self.Arc = value
end
-- ------------------------------ Effect scale ------------------------------ --
function mt:scale(value)
self.effect.size = value
self.effect:scale(self.effect.effect, value)
self.Scale = value
end
-- ------------------------------ Missile Speed ----------------------------- --
function mt:speed(value)
self.veloc = value * PERIOD
self.Speed = value
local vel = self.veloc*dilation
local s = self.travel + vel
local d = self.origin.distance
self.nextX = self.x + vel*Cos(self.cA)
self.nextY = self.y + vel*Sin(self.cA)
if self.height ~= 0 or self.origin.slope ~= 0 then
self.nextZ = 4*self.height*s*(d-s)/(d*d) + self.origin.slope*s + self.origin.z
self.z = self.nextZ
end
end
-- ------------------------------- Flight Time ------------------------------ --
function mt:duration(value)
self.veloc = RMaxBJ(0.00000001, (self.origin.distance - self.travel) * PERIOD / RMaxBJ(0.00000001, value))
self.Duration = value
local vel = self.veloc*dilation
local s = self.travel + vel
local d = self.origin.distance
self.nextX = self.x + vel*Cos(self.cA)
self.nextY = self.y + vel*Sin(self.cA)
if self.height ~= 0 or self.origin.slope ~= 0 then
self.nextZ = 4*self.height*s*(d-s)/(d*d) + self.origin.slope*s + self.origin.z
self.z = self.nextZ
end
end
-- ------------------------------- Sight Range ------------------------------ --
function mt:vision(sightRange)
self.Vision = sightRange
if self.dummy then
SetUnitOwner(self.dummy, self.owner, false)
BlzSetUnitRealField(self.dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
else
if not self.owner then
if self.source then
self.dummy = Pool:retrieve(self.x, self.y, self.z, 0)
SetUnitOwner(self.dummy, GetOwningPlayer(self.source), false)
BlzSetUnitRealField(self.dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
end
else
self.dummy = Pool:retrieve(self.x, self.y, self.z, 0)
SetUnitOwner(self.dummy, self.owner, false)
BlzSetUnitRealField(self.dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
end
end
end
-- ------------------------------- Time Scale ------------------------------- --
function mt:timeScale(real)
self.TimeScale = real
self.effect:timeScale(real)
end
-- ---------------------------------- Alpha --------------------------------- --
function mt:alpha(integer)
self.Alpha = integer
self.effect:alpha(integer)
end
-- ------------------------------ Player Color ------------------------------ --
function mt:playerColor(integer)
self.playercolor = integer
self.effect:playerColor(integer)
end
-- -------------------------------- Animation ------------------------------- --
function mt:animation(integer)
self.Animation = integer
self.effect:animation(integer)
end
-- --------------------------- Bounce and Deflect --------------------------- --
function mt:bounce()
self.origin:move(self.x, self.y, self.z - GetLocZ(self.x, self.y))
travelled = 0
self.travel = 0
self.finished = false
end
function mt:deflect(tx, ty, tz)
local locZ = GetLocZ(self.x, self.y)
if self.z < locZ and self.onTerrain then
self.nextX = self.prevX
self.nextY = self.prevY
self.nextZ = self.prevZ
end
self.toZ = tz
self.target = nil
self.impact:move(tx, ty, tz)
self.origin:move(self.x, self.y, self.z - locZ)
travelled = 0
self.travel = 0
self.finished = false
end
function mt:deflectTarget(unit)
self:deflect(GetUnitX(unit), GetUnitY(unit), self.toZ)
self.target = unit
end
-- ---------------------------- Flush hit targets --------------------------- --
function mt:flushAll()
array[self] = nil
array[self] = {}
end
function mt:flush(widget)
if widget then
array[self][widget] = nil
end
end
function mt:hitted(widget)
return array[self][widget]
end
-- ----------------------- Missile attachment methods ----------------------- --
function mt:attach(model, dx, dy, dz, scale)
return self.effect:attach(model, dx, dy, dz, scale)
end
function mt:detach(effect)
if effect then
self.effect:detach(effect)
end
end
-- ------------------------------ Missile Pause ----------------------------- --
function mt:pause(flag)
self:OnResume(flag)
end
-- ---------------------------------- Color --------------------------------- --
function mt:color(red, green, blue)
self.effect:setColor(red, green, blue)
end
-- ------------------------------ Reset members ----------------------------- --
function mt:reset()
self.launched = false
self.collideZ = false
self.finished = false
self.paused = false
self.roll = false
self.source = nil
self.target = nil
self.owner = nil
self.dummy = nil
self.open = 0.
self.height = 0.
self.veloc = 0.
self.acceleration = 0.
self.collision = 0.
self.damage = 0.
self.travel = 0.
self.turn = 0.
self.data = 0.
self.type = 0
self.tileset = 0
self.pkey = -1
self.index = -1
self.Model = ""
self.Duration = 0
self.Scale = 1
self.Speed = 0
self.Arc = 0
self.Curve = 0
self.Vision = 0
self.TimeScale = 0.
self.Alpha = 0
self.playercolor = 0
self.Animation = 0
self.onHit = nil
self.onMissile = nil
self.onDestructable = nil
self.onItem = nil
self.onCliff = nil
self.onTerrain = nil
self.onTileset = nil
self.onPeriod = nil
self.onFinish = nil
self.onBoundaries = nil
self.onPause = nil
self.onResume = nil
self.onRemove = nil
end
-- -------------------------------- Terminate ------------------------------- --
function mt:terminate()
self:OnRemove()
end
-- -------------------------- Destroys the missile -------------------------- --
function mt:remove(i)
if self.paused then
self:OnPause()
else
self:OnRemove()
end
missiles[i] = missiles[id]
id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
dilation = (id + 1) / SWEET_SPOT
else
dilation = 1
end
if id == -1 then
PauseTimer(timer)
end
if not self.allocated then
table.insert(keys, self.key)
self = nil
end
return i - 1
end
-- ---------------------------- Missiles movement --------------------------- --
function mt:move()
local i = 0
local j = 0
if SWEET_SPOT > 0 then
i = last
else
i = 0
end
while not ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id) do
local this = missiles[i]
if this.allocated and not this.paused then
this:OnHit()
this:OnMissile()
this:OnDestructable()
this:OnItem()
this:OnCliff()
this:OnTerrain()
this:OnTileset()
this:OnPeriod()
this:OnOrient()
this:OnFinish()
this:OnBoundaries()
else
i = this:remove(i)
j = j - 1
end
i = i + 1
j = j + 1
if i > id and SWEET_SPOT > 0 then
i = 0
end
end
last = i
end
-- --------------------------- Launch the Missile --------------------------- --
function mt:launch()
if not self.launched and self.allocated then
self.launched = true
id = id + 1
missiles[id] = self
Missiles.count = Missiles.count + 1
self.index = Missiles.count
Missiles.collection[Missiles.count] = self
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
dilation = (id + 1) / SWEET_SPOT
else
dilation = 1.
end
if id == 0 then
TimerStart(timer, PERIOD, true, function() Missiles:move() end)
end
end
end
-- --------------------------- Main Creator method -------------------------- --
function mt:create(x, y, z, toX, toY, toZ)
local this = {}
setmetatable(this, mt)
array[this] = {}
if #keys > 0 then
this.key = keys[#keys]
keys[#keys] = nil
else
this.key = index
index = index + 1
end
this:reset()
this.origin = Coordinates:create(x, y, z)
this.impact = Coordinates:create(toX, toY, toZ)
this.effect = MissileEffect:create(x, y, this.origin.z)
Coordinates:link(this.origin, this.impact)
this.allocated = true
this.cA = this.origin.angle
this.x = x
this.y = y
this.z = this.impact.z
this.prevX = x
this.prevY = y
this.prevZ = this.impact.z
this.nextX = x
this.nextY = y
this.nextZ = this.impact.z
this.toZ = toZ
return this
end
end
--[[
-- ---------------------------------------- Tenacity v1.0 --------------------------------------- --
-- Intro
-- This library intension in to introduce to warcraft an easy way to
-- manipulate the duration of crowd control on units.
--
-- How it Works?
-- Working in conjuction with the Crowd Control Library this library allows you to control the
-- duration of disables provided in the Crowd Control library. It work similar to the Tenacity
-- status in League of Legends or the Status Resistence in Dota 2.
--
-- The are basically 3 types of tenacity: Normal (stacks multiplicatively),
-- Flat and Offset (stacks additively).The formula for calculation is:
-- newDuration = (duration - Offset) * [(1 - value1)*(1 - value2)*...] * (1 - Flat)
--
-- The system also allow negative values for Tenacity, resulting in increased
-- crowd control duration. Also note that tenacity will only work on CC applied through
-- the Crowd Control API
--
-- How to Import
-- 1. Copy the Indexer library into your map
-- 2. Copy this library into your map and you are done
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
function GetUnitTenacity(unit)
return Tenacity:get(unit, 0)
end
function GetUnitTenacityFlat(unit)
return Tenacity:get(unit, 1)
end
function GetUnitTenacityOffset(unit)
return Tenacity:get(unit, 2)
end
function SetUnitTenacity(unit, value)
Tenacity:set(unit, value, 0)
end
function SetUnitTenacityFlat(unit, value)
Tenacity:set(unit, value, 1)
end
function SetUnitTenacityOffset(unit, value)
Tenacity:set(unit, value, 2)
end
function UnitAddTenacity(unit, value)
Tenacity:add(unit, value, 0)
end
function UnitAddTenacityFlat(unit, value)
Tenacity:add(unit, value, 1)
end
function UnitAddTenacityOffset(unit, value)
Tenacity:add(unit, value, 2)
end
function UnitRemoveTenacity(unit, value)
Tenacity:remove(unit, value)
end
function GetTenacityDuration(unit, duration)
return Tenacity:calculate(unit, duration)
end
function RegisterTenacityUnit(unit)
return Tenacity:register(unit)
end
function DisplayTenacityStatus(unit)
Tenacity:print(unit)
end
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
Tenacity = setmetatable({}, {})
local mt = getmetatable(Tenacity)
mt.__index = mt
local list = {}
function mt:get(unit, type)
if list[unit] then
if type == 0 then
if (#list[unit].normal or 0) > 0 then
return 1 - list[unit].tenacity
else
return 0
end
elseif type == 1 then
return list[unit].flat
else
return list[unit].offset
end
end
return 0
end
function mt:set(unit, value, type)
if not list[unit] then
self:register(unit)
end
if type == 0 then
list[unit].tenacity = value
elseif type == 1 then
list[unit].flat = value
else
list[unit].offset = value
end
end
function mt:add(unit, value, type)
if not list[unit] then
self:register(unit)
end
if type == 0 then
table.insert(list[unit].normal, value)
self:update(unit)
elseif type == 1 then
list[unit].flat = (list[unit].flat or 0) + value
else
list[unit].offset = (list[unit].offset or 0) + value
end
end
function mt:update(unit)
if list[unit] then
for i = 1, #list[unit].normal do
if i > 1 then
list[unit].tenacity = (list[unit].tenacity or 0) * (1 - list[unit].normal[i])
else
list[unit].tenacity = 1 - list[unit].normal[i]
end
end
end
end
function mt:remove(unit, value)
if value ~= 0 and list[unit] then
for i = 1, #list[unit].normal do
if list[unit].normal[i] == value then
table.remove(list[unit].normal, i)
break
end
end
self:update(unit)
end
end
function mt:calculate(unit, duration)
if duration ~= 0 and list[unit] then
if #list[unit].normal > 0 then
duration = (duration - list[unit].offset) * list[unit].tenacity * (1 - list[unit].flat)
else
duration = (duration - list[unit].offset) * (1 - list[unit].flat)
end
if duration <= 0 then
return 0
end
end
return duration
end
function mt:print(unit)
if list[unit] then
ClearTextMessages()
print("Tenacity Status for " .. GetUnitName(unit))
print("Tenacity List [" .. (list[unit].normal[1] or 0) .. " | " .. (list[unit].normal[2] or 0) .. " | " .. (list[unit].normal[3] or 0) .. " | " .. (list[unit].normal[4] or 0) .. " | " .. (list[unit].normal[5] or 0) .. " | " .. (list[unit].normal[6] or 0) .. " | ...] = " .. (self:get(unit, 0)))
print("Tenacity Flat [" .. (self:get(unit, 1)) .. "]")
print("Tenacity Offset [" .. (self:get(unit, 2)) .. "]")
end
end
function mt:register(unit)
if not list[unit] then
list[unit] = {}
list[unit].normal = {}
list[unit].flat = 0
list[unit].offset = 0
list[unit].tenacity = 0
end
return list[unit]
end
onInit(function()
RegisterUnitDeindexEvent(function()
list[GetIndexUnit()] = nil
end)
end)
end
--[[ requires Tenacity
-- ------------------------------------- Tenacity Utils v1.0 ------------------------------------ --
-- Utility Library that include a few extra functions to deal with Tenacity
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
function UnitAddTenacityTimed(unit, value, duration)
TenacityUtils:addTimed(unit, value, duration, 0)
end
function UnitAddTenacityFlatTimed(unit, value, duration)
TenacityUtils:addTimed(unit, value, duration, 1)
end
function UnitAddTenacityOffsetTimed(unit, value, duration)
TenacityUtils:addTimed(unit, value, duration, 2)
end
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
TenacityUtils = setmetatable({}, {})
local mt = getmetatable(TenacityUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
local period = 0.03125000
function mt:remove(i)
if self.type == 0 then
Tenacity:remove(self.unit, self.value)
else
Tenacity:add(self.unit, -self.value, self.type)
end
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, value, duration, type)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.value = value
this.type = type
this.duration = duration
key = key + 1
array[key] = this
Tenacity:add(unit, value, type)
if key == 1 then
TimerStart(timer, period, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.duration <= 0 then
i = this:remove(i)
end
this.duration = this.duration - period
i = i + 1
end
end)
end
end
end
do
-- returns the local current main selected unit, using it in a sync gamestate relevant manner breaks the game.
function GetMainSelectedUnitEx()
return GetMainSelectedUnit(GetSelectedUnitIndex())
end
local containerFrame
local frames = {}
local group
local units = {}
local filter = Filter(function()
local unit = GetFilterUnit()
local prio = BlzGetUnitRealField(unit, UNIT_RF_PRIORITY)
local found = false
-- compare the current unit with allready found, to place it in the right slot
for index, value in ipairs(units) do
-- higher prio than this take it's slot
if BlzGetUnitRealField(value, UNIT_RF_PRIORITY) < prio then
table.insert(units, index, unit)
found = true
break
-- equal prio and better colisions Value
elseif BlzGetUnitRealField(value, UNIT_RF_PRIORITY) == prio and GetUnitOrderValue(value) > GetUnitOrderValue(unit) then
table.insert(units, index, unit)
found = true
break
end
end
-- not found add it at the end
if not found then
table.insert(units, unit)
end
unit = nil
return false
end)
function GetSelectedUnitIndex()
-- local player is in group selection?
if BlzFrameIsVisible(containerFrame) then
-- find the first visible yellow Background Frame
for int = 0, #frames do
if BlzFrameIsVisible(frames[int]) then
return int
end
end
end
return nil
end
function GetUnitOrderValue(unit)
--heroes use the handleId
if IsUnitType(unit, UNIT_TYPE_HERO) then
return GetHandleId(unit)
else
--units use unitCode
return GetUnitTypeId(unit)
end
end
function GetMainSelectedUnit(index)
if index then
GroupEnumUnitsSelected(group, GetLocalPlayer(), filter)
local unit = units[index + 1]
--clear table
repeat until not table.remove(units)
return unit
else
GroupEnumUnitsSelected(group, GetLocalPlayer(), nil)
return FirstOfGroup(group)
end
end
--init
do
local real = MarkGameStarted
function MarkGameStarted()
real()
local console = BlzGetFrameByName("ConsoleUI", 0)
local bottomUI = BlzFrameGetChild(console, 1)
local groupframe = BlzFrameGetChild(bottomUI, 5)
--globals
containerFrame = BlzFrameGetChild(groupframe, 0)
group = CreateGroup()
-- give this frames a handleId
for int = 0, BlzFrameGetChildrenCount(containerFrame) - 1 do
local buttonContainer = BlzFrameGetChild(containerFrame, int)
frames[int] = BlzFrameGetChild(buttonContainer, 0)
end
end
end
end
--[[ requires onInit, RegisterPlayerUnitEvent, GetMainSelectedUnit
-- --------------------------------------- Interface v1.4 --------------------------------------- --
// Credits
// - Tasyen - GetMainSelectedUnit
// - Magtheridon96 - RegisterPlayerUnitEvent
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
-- Set this to a texture to replace the default gold icon
local GOLD_ICON = ""
-- Set this to a texture to replace the default lumber icon
local LUMBER_ICON = ""
-- When true and a unit that has "Select Unit" or "Select Hero" or "Shop Purchase Item"
-- abilities is select a panel above the portrait is created to show the items/units
local DISPLAY_SHOP = true
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
MainUI = setmetatable({}, {})
local mt = getmetatable(MainUI)
mt.__index = mt
local maptrigger = CreateTrigger()
local herotrigger = CreateTrigger()
local menutrigger = CreateTrigger()
local trigger = CreateTrigger()
local timer = CreateTimer()
local key = 0
local array = {}
local struct = {}
local handle = nil
local UI = nil
local ShopSlots = nil
local HealthBar = nil
local ManaBar = nil
local HeroCheck = nil
local HPText = nil
local MPText = nil
local Gold = nil
local Lumber = nil
local CheckBL = nil
local CheckBR = nil
local Minimap = nil
local MenuCheck = nil
local LumberIcon = nil
local GoldIcon = nil
local x1 = {}
local x2 = {}
local y01 = {}
local y02 = {}
local y11 = {}
local y12 = {}
local y21 = {}
local y22 = {}
local y31 = {}
local y32 = {}
local y41 = {}
local y42 = {}
local y51 = {}
local y52 = {}
local y61 = {}
local y62 = {}
local mapX1 = {}
local mapY1 = {}
local mapX2 = {}
local mapY2 = {}
local frameX1 = {}
local frameY1 = {}
local frameX2 = {}
local frameY2 = {}
local command0X1 = {}
local command0Y1 = {}
local command0X2 = {}
local command0Y2 = {}
local command1X1 = {}
local command1Y1 = {}
local command1X2 = {}
local command1Y2 = {}
local command2X1 = {}
local command2Y1 = {}
local command2X2 = {}
local command2Y2 = {}
local command3X1 = {}
local command3Y1 = {}
local command3X2 = {}
local command3Y2 = {}
local command4X1 = {}
local command4Y1 = {}
local command4X2 = {}
local command4Y2 = {}
local command5X1 = {}
local command5Y1 = {}
local command5X2 = {}
local command5Y2 = {}
local command6X1 = {}
local command6Y1 = {}
local command6X2 = {}
local command6Y2 = {}
local command7X1 = {}
local command7Y1 = {}
local command7X2 = {}
local command7Y2 = {}
local command8X1 = {}
local command8Y1 = {}
local command8X2 = {}
local command8Y2 = {}
local command9X1 = {}
local command9Y1 = {}
local command9X2 = {}
local command9Y2 = {}
local command10X1 = {}
local command10Y1 = {}
local command10X2 = {}
local command10Y2 = {}
local command11X1 = {}
local command11Y1 = {}
local command11X2 = {}
local command11Y2 = {}
local shop = {}
local main = {}
local checkL = {}
local checkR = {}
local checkMenu = {}
function mt:remove(i)
array[i] = array[key]
key = key - 1
struct[self.id] = nil
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:onCommandButtons()
local id = GetPlayerId(GetLocalPlayer())
if shop[id] then
command0X1[id] = 0.333500
command0Y1[id] = 0.213950
command0X2[id] = 0.366760
command0Y2[id] = 0.180700
command1X1[id] = 0.370500
command1Y1[id] = 0.213950
command1X2[id] = 0.403760
command1Y2[id] = 0.180700
command2X1[id] = 0.407400
command2Y1[id] = 0.213650
command2X2[id] = 0.440660
command2Y2[id] = 0.180400
command3X1[id] = 0.444400
command3Y1[id] = 0.213650
command3X2[id] = 0.477660
command3Y2[id] = 0.180400
command4X1[id] = 0.333500
command4Y1[id] = 0.175250
command4X2[id] = 0.366760
command4Y2[id] = 0.142000
command5X1[id] = 0.370500
command5Y1[id] = 0.175250
command5X2[id] = 0.403760
command5Y2[id] = 0.142000
command6X1[id] = 0.407400
command6Y1[id] = 0.175250
command6X2[id] = 0.440660
command6Y2[id] = 0.142000
command7X1[id] = 0.444400
command7Y1[id] = 0.175250
command7X2[id] = 0.477660
command7Y2[id] = 0.142000
command8X1[id] = 0.333500
command8Y1[id] = 0.136850
command8X2[id] = 0.366760
command8Y2[id] = 0.103600
command9X1[id] = 0.370500
command9Y1[id] = 0.136850
command9X2[id] = 0.403760
command9Y2[id] = 0.103600
command10X1[id] = 0.407400
command10Y1[id] = 0.136850
command10X2[id] = 0.440660
command10Y2[id] = 0.103600
command11X1[id] = 0.444400
command11Y1[id] = 0.136850
command11X2[id] = 0.477660
command11Y2[id] = 0.103600
else
command0X1[id] = 999.0
command0Y1[id] = 999.0
command0X2[id] = 999.0
command0Y2[id] = 999.0
command1X1[id] = 999.0
command1Y1[id] = 999.0
command1X2[id] = 999.0
command1Y2[id] = 999.0
command2X1[id] = 999.0
command2Y1[id] = 999.0
command2X2[id] = 999.0
command2Y2[id] = 999.0
command3X1[id] = 999.0
command3Y1[id] = 999.0
command3X2[id] = 999.0
command3Y2[id] = 999.0
command4X1[id] = 999.0
command4Y1[id] = 999.0
command4X2[id] = 999.0
command4Y2[id] = 999.0
command5X1[id] = 0.186900
command5Y1[id] = 0.0467700
command5X2[id] = 0.216900
command5Y2[id] = 0.0150000
command6X1[id] = 0.223700
command6Y1[id] = 0.0467700
command6X2[id] = 0.254200
command6Y2[id] = 0.0150000
command7X1[id] = 0.00242900
command7Y1[id] = 0.0467700
command7X2[id] = 0.0342090
command7Y2[id] = 0.0150000
command8X1[id] = 0.0399070
command8Y1[id] = 0.0467700
command8X2[id] = 0.0716870
command8Y2[id] = 0.0150000
command9X1[id] = 0.0765555
command9Y1[id] = 0.0467700
command9X2[id] = 0.1095555
command9Y2[id] = 0.0150000
command10X1[id] = 0.113070
command10Y1[id] = 0.0467700
command10X2[id] = 0.144850
command10Y2[id] = 0.0150000
command11X1[id] = 0.150070
command11Y1[id] = 0.0467700
command11X2[id] = 0.181850
command11Y2[id] = 0.0150000
end
-- Display the 12 slot grid
BlzFrameSetVisible(ShopSlots, shop[id])
-- Reposition the Move command button
handle = BlzGetFrameByName("CommandButton_0", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command0X1[id], command0Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command0X2[id], command0Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the Stop command button
handle = BlzGetFrameByName("CommandButton_1", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command1X1[id], command1Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command1X2[id], command1Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the Hold command button
handle = BlzGetFrameByName("CommandButton_2", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command2X1[id], command2Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command2X2[id], command2Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the Attack command button
handle = BlzGetFrameByName("CommandButton_3", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command3X1[id], command3Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command3X2[id], command3Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the Patrol command button
handle = BlzGetFrameByName("CommandButton_4", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command4X1[id], command4Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command4X2[id], command4Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the D command button
handle = BlzGetFrameByName("CommandButton_5", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command5X1[id], command5Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command5X2[id], command5Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the F command button
handle = BlzGetFrameByName("CommandButton_6", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command6X1[id], command6Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command6X2[id], command6Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the + command button
handle = BlzGetFrameByName("CommandButton_7", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command7X1[id], command7Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command7X2[id], command7Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the Q command button
handle = BlzGetFrameByName("CommandButton_8", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command8X1[id], command8Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command8X2[id], command8Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the W command button
handle = BlzGetFrameByName("CommandButton_9", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command9X1[id], command9Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command9X2[id], command9Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the E command button
handle = BlzGetFrameByName("CommandButton_10", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command10X1[id], command10Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command10X2[id], command10Y2[id])
BlzFrameSetScale(handle, 0.82)
-- Reposition the R command button
handle = BlzGetFrameByName("CommandButton_11", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command11X1[id], command11Y1[id])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command11X2[id], command11Y2[id])
BlzFrameSetScale(handle, 0.82)
handle = nil
end
function mt:onInventoryButtons()
-- Reposition the 0 inventory button
handle = BlzGetFrameByName("InventoryButton_0", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.552700, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.584480, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
-- Reposition the 1 inventory button
handle = BlzGetFrameByName("InventoryButton_1", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.589100, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.621900, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
-- Reposition the 2 inventory button
handle = BlzGetFrameByName("InventoryButton_2", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.625750, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.657530, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
-- Reposition the 3 inventory button
handle = BlzGetFrameByName("InventoryButton_3", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.662999, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.694999, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
-- Reposition the 4 inventory button
handle = BlzGetFrameByName("InventoryButton_4", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.699700, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.731480, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
-- Reposition the 5 inventory button
handle = BlzGetFrameByName("InventoryButton_5", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.736555, 0.0467700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.768555, 0.0150000)
BlzFrameSetSize(handle, 0.03178, 0.03178)
handle = nil
end
function mt:onInfoPanel()
-- Reposition the Buff bar
handle = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_PANEL_BUFF_BAR, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.364600, 0.0280800)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.476200, 0.0147800)
BlzFrameSetScale(handle, 0.9)
-- Remove the Status text
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_UNIT_PANEL_BUFF_BAR_LABEL, 0), 0.00001)
-- Remove Names and Descriptions
BlzFrameSetScale(BlzGetFrameByName("SimpleNameValue", 0), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleClassValue", 0), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleBuildingNameValue", 1), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleBuildingActionLabel", 1), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleHoldNameValue", 2), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleHoldDescriptionNameValue", 2), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleItemNameValue", 3), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleItemDescriptionValue", 3), 0.00001)
BlzFrameSetScale(BlzGetFrameByName("SimpleDestructableNameValue", 4), 0.00001)
-- Reposition the Hero Main Stat
handle = BlzGetFrameByName("InfoPanelIconHeroIcon", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.449800, 0.0581100)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.474930, 0.0329900)
-- Reposition the Strength label and value
handle = BlzGetFrameByName("InfoPanelIconHeroStrengthLabel", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.476900, 0.0757800)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.530850, 0.0624800)
handle = BlzGetFrameByName("InfoPanelIconHeroStrengthValue", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480000, 0.0657200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0553800)
-- Reposition the Agility label and value
handle = BlzGetFrameByName("InfoPanelIconHeroAgilityLabel", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.477400, 0.0559200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.532090, 0.0426200)
handle = BlzGetFrameByName("InfoPanelIconHeroAgilityValue", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480300, 0.0445700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0342300)
-- Reposition the Intelligence label and value
handle = BlzGetFrameByName("InfoPanelIconHeroIntellectLabel", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.476900, 0.0346500)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.531590, 0.0213500)
handle = BlzGetFrameByName("InfoPanelIconHeroIntellectValue", 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480600, 0.0240700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0137300)
-- Reposition the Timed Life bar
handle = BlzGetFrameByName("SimpleProgressIndicator", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
BlzFrameSetSize(handle, 0.77000, 0.01000)
-- Reposition the XP bar
handle = BlzGetFrameByName("SimpleHeroLevelBar", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
BlzFrameSetSize(handle, 0.77000, 0.01000)
-- Reposition the Training bar
handle = BlzGetFrameByName("SimpleBuildTimeIndicator", 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
BlzFrameSetSize(handle, 0.77000, 0.01000)
-- Reposition the Attack 1 block
handle = BlzGetFrameByName("InfoPanelIconBackdrop", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.261800, 0.0723200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.289140, 0.0449800)
BlzFrameSetSize(handle, 0.02734, 0.02734)
-- Reposition the Armor block
handle = BlzGetFrameByName("InfoPanelIconBackdrop", 2)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.261100, 0.0439700)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.288440, 0.0166300)
BlzFrameSetSize(handle, 0.02734, 0.02734)
handle = nil
end
function mt:onPortrait()
handle = BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.373500, 0.0977600)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.431555, 0.0157400)
handle = nil
end
function mt:onHeroCheck()
local i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if GetLocalPlayer() == GetTriggerPlayer() then
x1[i] = -0.131300
x2[i] = -0.103220
y01[i] = 0.581980
y02[i] = 0.553900
y11[i] = 0.544980
y12[i] = 0.516900
y21[i] = 0.510680
y22[i] = 0.482600
y31[i] = 0.474280
y32[i] = 0.446200
y41[i] = 0.437880
y42[i] = 0.409800
y51[i] = 0.401480
y52[i] = 0.373400
y61[i] = 0.365080
y62[i] = 0.337000
end
-- Reposition the hero button 0
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y01[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y02[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 0), 0.71)
-- Reposition the hero button 1
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y11[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y12[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 1), 0.71)
-- Reposition the hero button 2
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 2)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y21[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y22[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 2), 0.71)
-- Reposition the hero button 3
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 3)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y31[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y32[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 3), 0.71)
-- Reposition the hero button 4
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 4)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y41[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y42[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 4), 0.71)
-- Reposition the hero button 5
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 5)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y51[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y52[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 5), 0.71)
-- Reposition the hero button 6
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y61[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y62[i])
BlzFrameSetScale(handle, 0.7)
BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 6), 0.71)
handle = nil
else
if GetLocalPlayer() == GetTriggerPlayer() then
x1[i] = 999.0
x2[i] = 999.0
y01[i] = 999.0
y02[i] = 999.0
y11[i] = 999.0
y12[i] = 999.0
y21[i] = 999.0
y22[i] = 999.0
y31[i] = 999.0
y32[i] = 999.0
y41[i] = 999.0
y42[i] = 999.0
y51[i] = 999.0
y52[i] = 999.0
y61[i] = 999.0
y62[i] = 999.0
end
-- Hides the hero button 0
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y01[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y02[i])
-- Hides the hero button 1
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y11[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y12[i])
-- Hides the hero button 2
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 2)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y21[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y22[i])
-- Hides the hero button 3
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 3)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y31[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y32[i])
-- Hides the hero button 4
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 4)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y41[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y42[i])
-- Hides the hero button 5
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 5)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y51[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y52[i])
-- Hides the hero button 6
handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 6)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y61[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y62[i])
handle = nil
end
end
function mt:onGroupSelection()
-- Reposistion the Group selection button 0
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 0), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.262600, 0.0776200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.285600, 0.0546200)
-- Reposistion the Group selection button 1
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 1), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.295800, 0.0731200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.318800, 0.0501200)
-- Reposistion the Group selection button 2
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 2), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.328300, 0.0731200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.351300, 0.0501200)
-- Reposistion the Group selection button 3
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 3), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.262600, 0.0414100)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.285600, 0.0184100)
-- Reposistion the Group selection button 4
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 4), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.295800, 0.0414000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.318800, 0.0184000)
-- Reposistion the Group selection button 5
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 5), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.329100, 0.0414000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.352100, 0.0184000)
-- Reposistion the Group selection button 6
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 6), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.449300, 0.0731200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.472300, 0.0501200)
-- Reposistion the Group selection button 7
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 7), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.483500, 0.0731200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.506500, 0.0501200)
-- Reposistion the Group selection button 8
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 8), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.516800, 0.0731200)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.539800, 0.0501200)
-- Reposistion the Group selection button 9
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 9), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.450300, 0.0414000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.473300, 0.0184000)
-- Reposistion the Group selection button 10
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 10), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.483500, 0.0414000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.506500, 0.0184000)
-- Reposistion the Group selection button 11
handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 11), 1)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.516800, 0.0414000)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.539800, 0.0184000)
handle = nil
end
function mt:onResources()
BlzFrameSetText(Gold, "|cffffcc00" .. I2S(GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD)) .. "|r")
BlzFrameSetText(Lumber, "|cff00ff00" .. I2S(GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_LUMBER)) .. "|r")
end
function mt:onChat()
handle = BlzGetOriginFrame(ORIGIN_FRAME_CHAT_MSG, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.000212200, 0.302800)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.400212, 0.100300)
handle = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_MSG, 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.000212200, 0.302800)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.400212, 0.100300)
handle = nil
end
function mt:onMinimap()
local i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if BlzGetTriggerFrame() == CheckBL then
if GetLocalPlayer() == GetTriggerPlayer() then
mapX1[i] = - 0.132100
mapY1[i] = 0.0986970
mapX2[i] = - 0.0351000
mapY2[i] = 0.00169700
frameX1[i] = - 0.133600
frameY1[i] = 0.100939
frameX2[i] = - 0.0338300
frameY2[i] = 0.000438700
checkL[i] = true
end
else
if GetLocalPlayer() == GetTriggerPlayer() then
mapX1[i] = 0.835800
mapY1[i] = 0.0999999
mapX2[i] = 0.933610
mapY2[i] = 0.000219400
frameX1[i] = 0.833900
frameY1[i] = 0.100939
frameX2[i] = 0.933670
frameY2[i] = 0.000438700
checkR[i] = true
end
end
else
if BlzGetTriggerFrame() == CheckBL then
if GetLocalPlayer() == GetTriggerPlayer() then
if checkR[i] then
mapX1[i] = 0.835800
mapY1[i] = 0.0999999
mapX2[i] = 0.933610
mapY2[i] = 0.000219400
frameX1[i] = 0.833900
frameY1[i] = 0.100939
frameX2[i] = 0.933670
frameY2[i] = 0.000438700
else
mapX1[i] = 999.0
mapY1[i] = 999.0
mapX2[i] = 999.0
mapY2[i] = 999.0
frameX1[i] = 999.0
frameY1[i] = 999.0
frameX2[i] = 999.0
frameY2[i] = 999.0
end
checkL[i] = false
end
else
if GetLocalPlayer() == GetTriggerPlayer() then
if checkL[i] then
mapX1[i] = - 0.132100
mapY1[i] = 0.0986970
mapX2[i] = - 0.0351000
mapY2[i] = 0.00169700
frameX1[i] = - 0.133600
frameY1[i] = 0.100939
frameX2[i] = - 0.0338300
frameY2[i] = 0.000438700
else
mapX1[i] = 999.0
mapY1[i] = 999.0
mapX2[i] = 999.0
mapY2[i] = 999.0
frameX1[i] = 999.0
frameY1[i] = 999.0
frameX2[i] = 999.0
frameY2[i] = 999.0
end
checkR[i] = false
end
end
end
handle = BlzGetFrameByName("MiniMapFrame", 0)
BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, mapX1[i], mapY1[i])
BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, mapX2[i], mapY2[i])
BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_TOPLEFT, frameX1[i], frameY1[i])
BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_BOTTOMRIGHT, frameX2[i], frameY2[i])
handle = nil
end
function mt:onMenu()
local i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if GetLocalPlayer() == GetTriggerPlayer() then
checkMenu[i] = true
end
else
if GetLocalPlayer() == GetTriggerPlayer() then
checkMenu[i] = false
end
end
BlzFrameSetVisible(BlzGetFrameByName("UpperButtonBarFrame", 0), checkMenu[i])
BlzFrameSetVisible(BlzGetFrameByName("ResourceBarFrame", 0), checkMenu[i])
end
function mt:onPeriod()
local i = 1
local newHP
local newMP
local newHPtext
local newMPtext
local this
while i <= key do
this = array[i]
if GetPlayerSlotState(this.player) ~= PLAYER_SLOT_STATE_LEFT then
this.unit = GetMainSelectedUnitEx()
if DISPLAY_SHOP then
if main[this.id] ~= this.unit then
main[this.id] = this.unit
shop[this.id] = (GetUnitAbilityLevel(this.unit, FourCC('Aneu')) > 0 or GetUnitAbilityLevel(this.unit, FourCC('Ane2')) > 0 or GetUnitAbilityLevel(this.unit, FourCC('Apit')) > 0) and not IsUnitEnemy(this.unit, this.player)
MainUI:onCommandButtons()
end
end
if not IsUnitVisible(this.unit, this.player) then
this.unit = nil
end
this.health = BlzFrameGetValue(HealthBar)
this.mana = BlzFrameGetValue(ManaBar)
newHP = GetUnitLifePercent(this.unit)
newMP = GetUnitManaPercent(this.unit)
this.hp = BlzFrameGetText(HPText)
this.mp = BlzFrameGetText(MPText)
newHPtext = I2S(R2I(GetWidgetLife(this.unit))) .. " / " .. I2S(BlzGetUnitMaxHP(this.unit))
newMPtext = I2S(R2I(GetUnitState(this.unit, UNIT_STATE_MANA))) .. " / " .. I2S(BlzGetUnitMaxMana(this.unit))
if GetLocalPlayer() == this.player then
this.health = newHP
this.mana = newMP
this.hp = newHPtext
this.mp = newMPtext
end
BlzFrameSetValue(HealthBar, this.health)
BlzFrameSetValue(ManaBar, this.mana)
BlzFrameSetText(HPText, "|cffFFFFFF" .. this.hp .. "|r")
BlzFrameSetText(MPText, "|cffFFFFFF" .. this.mp .. "|r")
else
i = this:remove(i)
end
i = i + 1
end
end
function mt:onSelect()
local id = GetPlayerId(GetTriggerPlayer())
local this
if struct[id] then
this = struct[id]
else
this = {}
setmetatable(this, mt)
this.id = id
this.unit = nil
this.player = GetTriggerPlayer()
this.health = 0
this.mana = 0
this.hp = "0 / 0"
this.mp = "0 / 0"
key = key + 1
array[key] = this
struct[id] = this
if key == 1 then
TimerStart(timer, 0.05, true, function() MainUI:onPeriod() end)
end
end
end
onInit(function()
BlzFrameSetAlpha(BlzGetFrameByName("SimpleInventoryCover", 0), 0)
BlzFrameSetScale(BlzGetFrameByName("InventoryText", 0), 0.0001)
BlzFrameSetAbsPoint(BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOPLEFT, 0.0, 0.633)
BlzFrameSetVisible(BlzGetFrameByName("ResourceBarFrame", 0), false)
BlzFrameSetVisible(BlzGetFrameByName("UpperButtonBarFrame", 0), false)
BlzFrameSetVisible(BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7), false)
BlzFrameSetVisible(BlzFrameGetChild(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 5),0), false)
BlzFrameSetParent(BlzGetFrameByName("MiniMapFrame", 0), BlzGetFrameByName("ConsoleUIBackdrop", 0))
UI = BlzCreateFrameByType("BACKDROP", "UI", BlzGetFrameByName("ConsoleUIBackdrop", 0), "", 1)
BlzFrameSetAbsPoint(UI, FRAMEPOINT_TOPLEFT, 0.00000, 0.100000)
BlzFrameSetAbsPoint(UI, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
BlzFrameSetTexture(UI, "UI.blp", 0, true)
ShopSlots = BlzCreateFrameByType("BACKDROP", "ShopSlots", BlzGetFrameByName("ConsoleUIBackdrop", 0), "", 1)
BlzFrameSetAbsPoint(ShopSlots, FRAMEPOINT_TOPLEFT, 0.330600, 0.216500)
BlzFrameSetAbsPoint(ShopSlots, FRAMEPOINT_BOTTOMRIGHT, 0.478600, 0.100700)
BlzFrameSetTexture(ShopSlots, "12Slot.blp", 0, true)
HealthBar = BlzCreateFrameByType("SIMPLESTATUSBAR", "", UI, "", 0)
BlzFrameSetTexture(HealthBar, "replaceabletextures\\teamcolor\\teamcolor00", 0, true)
BlzFrameSetAbsPoint(HealthBar, FRAMEPOINT_TOPLEFT, 0.0386400, 0.0778900)
BlzFrameSetAbsPoint(HealthBar, FRAMEPOINT_BOTTOMRIGHT, 0.255140, 0.0535100)
BlzFrameSetValue(HealthBar, 0)
ManaBar = BlzCreateFrameByType("SIMPLESTATUSBAR", "", UI, "", 0)
BlzFrameSetTexture(ManaBar, "replaceabletextures\\teamcolor\\teamcolor01", 0, true)
BlzFrameSetAbsPoint(ManaBar, FRAMEPOINT_TOPLEFT, 0.551500, 0.0778000)
BlzFrameSetAbsPoint(ManaBar, FRAMEPOINT_BOTTOMRIGHT, 0.768000, 0.0534200)
BlzFrameSetValue(ManaBar, 0)
HeroCheck = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
BlzFrameSetAbsPoint(HeroCheck, FRAMEPOINT_TOPLEFT, -0.131300, 0.600240)
BlzFrameSetAbsPoint(HeroCheck, FRAMEPOINT_BOTTOMRIGHT, -0.117260, 0.586200)
HPText = BlzCreateFrameByType("TEXT", "HPTEXT", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
BlzFrameSetAbsPoint(HPText, FRAMEPOINT_TOPLEFT, 0.108100, 0.0726300)
BlzFrameSetAbsPoint(HPText, FRAMEPOINT_BOTTOMRIGHT, 0.184960, 0.0585900)
BlzFrameSetText(HPText, "|cffFFFFFF|r")
BlzFrameSetEnable(HPText, false)
BlzFrameSetScale(HPText, 1.00)
BlzFrameSetTextAlignment(HPText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
MPText = BlzCreateFrameByType("TEXT", "MPTEXT", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
BlzFrameSetAbsPoint(MPText, FRAMEPOINT_TOPLEFT, 0.622500, 0.0726000)
BlzFrameSetAbsPoint(MPText, FRAMEPOINT_BOTTOMRIGHT, 0.699360, 0.0585600)
BlzFrameSetText(MPText, "|cffFFFFFF|r")
BlzFrameSetEnable(MPText, false)
BlzFrameSetScale(MPText, 1.00)
BlzFrameSetTextAlignment(MPText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
Lumber = BlzCreateFrameByType("TEXT", "GOLD", UI, "", 0)
BlzFrameSetAbsPoint(Lumber, FRAMEPOINT_TOPLEFT, 0.291100, 0.0970200)
BlzFrameSetAbsPoint(Lumber, FRAMEPOINT_BOTTOMRIGHT, 0.346530, 0.0815000)
BlzFrameSetText(Lumber, "|cff00ff00|r")
BlzFrameSetEnable(Lumber, false)
BlzFrameSetScale(Lumber, 1.00)
BlzFrameSetTextAlignment(Lumber, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_RIGHT)
Gold = BlzCreateFrameByType("TEXT", "LUMBER", UI, "", 0)
BlzFrameSetAbsPoint(Gold, FRAMEPOINT_TOPLEFT, 0.460600, 0.0972500)
BlzFrameSetAbsPoint(Gold, FRAMEPOINT_BOTTOMRIGHT, 0.516030, 0.0817300)
BlzFrameSetText(Gold, "|cffffcc00|r")
BlzFrameSetEnable(Gold, false)
BlzFrameSetScale(Gold, 1.00)
BlzFrameSetTextAlignment(Gold, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_LEFT)
CheckBL = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
BlzFrameSetAbsPoint(CheckBL, FRAMEPOINT_TOPLEFT, 0.269200, 0.102200)
BlzFrameSetAbsPoint(CheckBL, FRAMEPOINT_BOTTOMRIGHT, 0.292850, 0.0778100)
CheckBR = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
BlzFrameSetAbsPoint(CheckBR, FRAMEPOINT_TOPLEFT, 0.514800, 0.102200)
BlzFrameSetAbsPoint(CheckBR, FRAMEPOINT_BOTTOMRIGHT, 0.538450, 0.0778100)
Minimap = BlzCreateFrameByType("BACKDROP", "Minimap", UI, "", 1)
BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_TOPLEFT, 999.0, 999.0)
BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_BOTTOMRIGHT, 999.0, 999.0)
BlzFrameSetTexture(Minimap, "Minimap.blp", 0, true)
MenuCheck = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
BlzFrameSetAbsPoint(MenuCheck, FRAMEPOINT_TOPLEFT, 0.918800, 0.601640)
BlzFrameSetAbsPoint(MenuCheck, FRAMEPOINT_BOTTOMRIGHT, 0.932840, 0.587600)
LumberIcon = BlzCreateFrameByType("BACKDROP", "LumberIcon", UI, "", 1)
BlzFrameSetAbsPoint(LumberIcon, FRAMEPOINT_TOPLEFT, 0.347600, 0.0966800)
BlzFrameSetAbsPoint(LumberIcon, FRAMEPOINT_BOTTOMRIGHT, 0.362600, 0.0816800)
if LUMBER_ICON ~= "" then
BlzFrameSetTexture(LumberIcon, LUMBER_ICON, 0, true)
else
BlzFrameSetVisible(LumberIcon, false)
end
GoldIcon = BlzCreateFrameByType("BACKDROP", "GoldIcon", UI, "", 1)
BlzFrameSetAbsPoint(GoldIcon, FRAMEPOINT_TOPLEFT, 0.445900, 0.0966600)
BlzFrameSetAbsPoint(GoldIcon, FRAMEPOINT_BOTTOMRIGHT, 0.460900, 0.0816600)
if GOLD_ICON ~= "" then
BlzFrameSetTexture(GoldIcon, GOLD_ICON, 0, true)
else
BlzFrameSetVisible(GoldIcon, false)
end
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function() MainUI:onSelect() end)
BlzTriggerRegisterFrameEvent(herotrigger, HeroCheck, FRAMEEVENT_CHECKBOX_CHECKED)
BlzTriggerRegisterFrameEvent(herotrigger, HeroCheck, FRAMEEVENT_CHECKBOX_UNCHECKED)
TriggerAddAction(herotrigger, function() MainUI:onHeroCheck() end)
BlzTriggerRegisterFrameEvent(maptrigger, CheckBL, FRAMEEVENT_CHECKBOX_CHECKED)
BlzTriggerRegisterFrameEvent(maptrigger, CheckBL, FRAMEEVENT_CHECKBOX_UNCHECKED)
BlzTriggerRegisterFrameEvent(maptrigger, CheckBR, FRAMEEVENT_CHECKBOX_CHECKED)
BlzTriggerRegisterFrameEvent(maptrigger, CheckBR, FRAMEEVENT_CHECKBOX_UNCHECKED)
TriggerAddAction(maptrigger, function() MainUI:onMinimap() end)
BlzTriggerRegisterFrameEvent(menutrigger, MenuCheck, FRAMEEVENT_CHECKBOX_CHECKED)
BlzTriggerRegisterFrameEvent(menutrigger, MenuCheck, FRAMEEVENT_CHECKBOX_UNCHECKED)
TriggerAddAction(menutrigger, function() MainUI:onMenu() end)
TimerStart(CreateTimer(), 0.2, true, function() MainUI:onResources() end)
for i = 0, bj_MAX_PLAYER_SLOTS do
x1[i] = 999.0
x2[i] = 999.0
y01[i] = 999.0
y02[i] = 999.0
y11[i] = 999.0
y12[i] = 999.0
y21[i] = 999.0
y22[i] = 999.0
y31[i] = 999.0
y32[i] = 999.0
y41[i] = 999.0
y42[i] = 999.0
y51[i] = 999.0
y52[i] = 999.0
y61[i] = 999.0
y62[i] = 999.0
mapX1[i] = 999.0
mapY1[i] = 999.0
mapX2[i] = 999.0
mapY2[i] = 999.0
frameX1[i] = 999.0
frameY1[i] = 999.0
frameX2[i] = 999.0
frameY2[i] = 999.0
command0X1[i] = 999.0
command0Y1[i] = 999.0
command1X1[i] = 999.0
command1Y1[i] = 999.0
command2X1[i] = 999.0
command2Y1[i] = 999.0
command3X1[i] = 999.0
command3Y1[i] = 999.0
command4X1[i] = 999.0
command4Y1[i] = 999.0
command5X1[i] = 999.0
command5Y1[i] = 999.0
command6X1[i] = 999.0
command6Y1[i] = 999.0
command7X1[i] = 999.0
command7Y1[i] = 999.0
command8X1[i] = 999.0
command8Y1[i] = 999.0
command9X1[i] = 999.0
command9Y1[i] = 999.0
command10X1[i] = 999.0
command10Y1[i] = 999.0
command11X1[i] = 999.0
command11Y1[i] = 999.0
command0X2[i] = 999.0
command0Y2[i] = 999.0
command1X2[i] = 999.0
command1Y2[i] = 999.0
command2X2[i] = 999.0
command2Y2[i] = 999.0
command3X2[i] = 999.0
command3Y2[i] = 999.0
command4X2[i] = 999.0
command4Y2[i] = 999.0
command5X2[i] = 999.0
command5Y2[i] = 999.0
command6X2[i] = 999.0
command6Y2[i] = 999.0
command7X2[i] = 999.0
command7Y2[i] = 999.0
command8X2[i] = 999.0
command8Y2[i] = 999.0
command9X2[i] = 999.0
command9Y2[i] = 999.0
command10X2[i] = 999.0
command10Y2[i] = 999.0
command11X2[i] = 999.0
command11Y2[i] = 999.0
shop[i] = false
main[i] = nil
checkL[i] = false
checkR[i] = false
checkMenu[i] = false
end
MainUI:onCommandButtons()
MainUI:onInventoryButtons()
MainUI:onInfoPanel()
MainUI:onPortrait()
MainUI:onGroupSelection()
MainUI:onChat()
end)
end
--[[ requires optional DamageInterface, optional Evasion, optional CriticalStrike, optional SpellPower, optional LifeSteal, optional SpellVamp, optional CooldownReduction, optional Tenacity
-- ---------------------------------------- NewBonus v2.4 --------------------------------------- --
-- Since ObjectMerger is broken and we still have no means to edit
-- bonus values (green values) i decided to create a light weight
-- Bonus library that works in the same way that the original Bonus Mod
-- by Earth Fury did. NewBonus requires patch 1.31+.
-- Credits to Earth Fury for the original Bonus idea
-- How to Import?
-- Importing bonus mod is really simple. Just copy the abilities with the
-- prefix "NewBonus" from the Object Editor into your map and match their new raw
-- code to the bonus types in the global block below. Then create a trigger called
-- NewBonus, convert it to custom text and paste this code there. You done!
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
-- If true will use the extended version of the system.
-- Make sure you have the DamageInterface and Cooldown Reduction libraries
NewBonus_EXTENDED = true
-- This is the maximum recursion limit allowed by the system.
-- Its value must be greater than or equal to 0. When equal to 0
-- no recursion is allowed. Values too big can cause screen freezes.
local RECURSION_LIMIT = 8
-- The bonus types
BONUS_DAMAGE = 1
BONUS_ARMOR = 2
BONUS_AGILITY = 3
BONUS_STRENGTH = 4
BONUS_INTELLIGENCE = 5
BONUS_HEALTH = 6
BONUS_MANA = 7
BONUS_MOVEMENT_SPEED = 8
BONUS_SIGHT_RANGE = 9
BONUS_HEALTH_REGEN = 10
BONUS_MANA_REGEN = 11
BONUS_ATTACK_SPEED = 12
BONUS_MAGIC_RESISTANCE = 13
BONUS_EVASION_CHANCE = 14
BONUS_CRITICAL_DAMAGE = 15
BONUS_CRITICAL_CHANCE = 16
BONUS_LIFE_STEAL = 17
BONUS_MISS_CHANCE = 18
BONUS_SPELL_POWER_FLAT = 19
BONUS_SPELL_POWER_PERCENT = 20
BONUS_SPELL_VAMP = 21
BONUS_COOLDOWN_REDUCTION = 22
BONUS_COOLDOWN_REDUCTION_FLAT = 23
BONUS_COOLDOWN_OFFSET = 24
BONUS_TENACITY = 25
BONUS_TENACITY_FLAT = 26
BONUS_TENACITY_OFFSET = 27
-- The abilities codes for each bonus
-- When pasting the abilities over to your map
-- their raw code should match the bonus here
local DAMAGE_ABILITY = FourCC('Z001')
local ARMOR_ABILITY = FourCC('Z002')
local STATS_ABILITY = FourCC('Z003')
local HEALTH_ABILITY = FourCC('Z004')
local MANA_ABILITY = FourCC('Z005')
local HEALTHREGEN_ABILITY = FourCC('Z006')
local MANAREGEN_ABILITY = FourCC('Z007')
local ATTACKSPEED_ABILITY = FourCC('Z008')
local MOVEMENTSPEED_ABILITY = FourCC('Z009')
local SIGHT_RANGE_ABILITY = FourCC('Z00A')
local MAGIC_RESISTANCE_ABILITY = FourCC('Z00B')
local CRITICAL_STRIKE_ABILITY = FourCC('Z00C')
local EVASION_ABILITY = FourCC('Z00D')
local LIFE_STEAL_ABILITY = FourCC('Z00E')
-- The abilities fields that are modified. For the sake of readability
local DAMAGE_FIELD = ABILITY_ILF_ATTACK_BONUS
local ARMOR_FIELD = ABILITY_ILF_DEFENSE_BONUS_IDEF
local AGILITY_FIELD = ABILITY_ILF_AGILITY_BONUS
local STRENGTH_FIELD = ABILITY_ILF_STRENGTH_BONUS_ISTR
local INTELLIGENCE_FIELD = ABILITY_ILF_INTELLIGENCE_BONUS
local HEALTH_FIELD = ABILITY_ILF_MAX_LIFE_GAINED
local MANA_FIELD = ABILITY_ILF_MAX_MANA_GAINED
local MOVEMENTSPEED_FIELD = ABILITY_ILF_MOVEMENT_SPEED_BONUS
local SIGHT_RANGE_FIELD = ABILITY_ILF_SIGHT_RANGE_BONUS
local HEALTHREGEN_FIELD = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
local MANAREGEN_FIELD = ABILITY_RLF_AMOUNT_REGENERATED
local ATTACKSPEED_FIELD = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
local MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
local CRITICAL_CHANCE_FIELD = ABILITY_RLF_CHANCE_TO_CRITICAL_STRIKE
local CRITICAL_DAMAGE_FIELD = ABILITY_RLF_DAMAGE_MULTIPLIER_OCR2
local EVASION_FIELD = ABILITY_RLF_CHANCE_TO_EVADE_EEV1
local LIFE_STEAL_FIELD = ABILITY_RLF_LIFE_STOLEN_PER_ATTACK
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
function GetUnitBonus(unit, type)
return NewBonus:get(unit, type)
end
function SetUnitBonus(unit, type, value)
return NewBonus:set(unit, type, value, false)
end
function RemoveUnitBonus(unit, type)
if type == BONUS_CRITICAL_DAMAGE then
NewBonus:set(unit, type, 1, false)
else
NewBonus:set(unit, type, 0, false)
end
if type == BONUS_LIFE_STEAL then
UnitRemoveAbility(unit, LIFE_STEAL_ABILITY)
end
end
function AddUnitBonus(unit, type, value)
return NewBonus:add(unit, type, value)
end
function RegisterBonusEvent(code)
NewBonus:register(code, 0)
end
function RegisterBonusTypeEvent(type, code)
NewBonus:register(code, type)
end
function GetBonusUnit()
return NewBonus.unit[NewBonus.key]
end
function GetBonusType()
return NewBonus.type[NewBonus.key]
end
function SetBonusType(type)
if type >= BONUS_DAMAGE and type <= NewBonus.last then
NewBonus.type[NewBonus.key] = type
end
end
function GetBonusAmount()
return NewBonus.amount[NewBonus.key]
end
function SetBonusAmount(real)
NewBonus.amount[NewBonus.key] = real
end
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
NewBonus = setmetatable({}, {})
local mt = getmetatable(NewBonus)
mt.__index = mt
NewBonus.linkType = 0
NewBonus.last = 0
NewBonus.key = 0
NewBonus.unit = {}
NewBonus.type = {}
NewBonus.amount = {}
local trigger = {}
local event = {}
local count = 0
function mt:checkOverflow(current, value)
if value > 0 and current > 2147483647 - value then
return 2147483647 - current
elseif value < 0 and current < -2147483648 - value then
return -2147483648 - current
else
return value
end
end
function mt:onEvent(key)
local i = 0
local next = -1
local prev = -2
count = count + 1
if NewBonus.amount[key] ~= 0 and (count - NewBonus.last < RECURSION_LIMIT) then
while NewBonus.type[key] ~= next and (i - NewBonus.last < RECURSION_LIMIT) do
next = NewBonus.type[key]
if event[next] then
for j = 1, #event[next] do
event[next][j]()
end
end
if NewBonus.type[key] ~= next then
i = i + 1
else
if next ~= prev then
for j = 1, #trigger do
trigger[j]()
end
if NewBonus.type[key] ~= next then
i = i + 1
prev = next
end
end
end
end
end
count = count - 1
NewBonus.key = key
end
function mt:setAbility(unit, ability, field, value, integer, adding)
if GetUnitAbilityLevel(unit, ability) == 0 then
UnitAddAbility(unit, ability)
UnitMakeAbilityPermanent(unit, true, ability)
end
if integer then
if adding then
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ability), field, 0, BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ability), field, 0) + value) then
IncUnitAbilityLevel(unit, ability)
DecUnitAbilityLevel(unit, ability)
end
else
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ability), field, 0, value) then
IncUnitAbilityLevel(unit, ability)
DecUnitAbilityLevel(unit, ability)
end
end
NewBonus.linkType = NewBonus.type[NewBonus.key]
if NewBonus.key > 0 then
NewBonus.key = NewBonus.key - 1
end
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ability), field, 0)
else
if BlzSetAbilityRealLevelField(BlzGetUnitAbility(unit, ability), field, 0, value) then
IncUnitAbilityLevel(unit, ability)
DecUnitAbilityLevel(unit, ability)
end
NewBonus.linkType = NewBonus.type[NewBonus.key]
if NewBonus.key > 0 then
NewBonus.key = NewBonus.key - 1
end
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ability), field, 0)
end
end
function mt:get(unit, type)
if type == BONUS_DAMAGE then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, DAMAGE_ABILITY), DAMAGE_FIELD, 0)
elseif type == BONUS_ARMOR then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ARMOR_ABILITY), ARMOR_FIELD, 0)
elseif type == BONUS_HEALTH then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, HEALTH_ABILITY), HEALTH_FIELD, 0)
elseif type == BONUS_MANA then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, MANA_ABILITY), MANA_FIELD, 0)
elseif type == BONUS_AGILITY then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, STATS_ABILITY), AGILITY_FIELD, 0)
elseif type == BONUS_STRENGTH then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, STATS_ABILITY), STRENGTH_FIELD, 0)
elseif type == BONUS_INTELLIGENCE then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, STATS_ABILITY), INTELLIGENCE_FIELD, 0)
elseif type == BONUS_MOVEMENT_SPEED then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, MOVEMENTSPEED_ABILITY), MOVEMENTSPEED_FIELD, 0)
elseif type == BONUS_SIGHT_RANGE then
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, SIGHT_RANGE_ABILITY), SIGHT_RANGE_FIELD, 0)
elseif type == BONUS_HEALTH_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, HEALTHREGEN_ABILITY), HEALTHREGEN_FIELD, 0)
elseif type == BONUS_MANA_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, MANAREGEN_ABILITY), MANAREGEN_FIELD, 0)
elseif type == BONUS_ATTACK_SPEED then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ATTACKSPEED_ABILITY), ATTACKSPEED_FIELD, 0)
elseif type == BONUS_MAGIC_RESISTANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, MAGIC_RESISTANCE_ABILITY), MAGIC_RESISTANCE_FIELD, 0)
elseif type >= BONUS_EVASION_CHANCE and type <= NewBonus.last then
if NewBonus_EXTENDED and Damage and Evasion and Critical and SpellPower and LifeSteal and SpellVamp and Tenacity then
if type == BONUS_EVASION_CHANCE then
return GetUnitEvasionChance(unit)
elseif type == BONUS_MISS_CHANCE then
return GetUnitMissChance(unit)
elseif type == BONUS_CRITICAL_CHANCE then
return GetUnitCriticalChance(unit)
elseif type == BONUS_CRITICAL_DAMAGE then
return GetUnitCriticalMultiplier(unit)
elseif type == BONUS_SPELL_POWER_FLAT then
return GetUnitSpellPowerFlat(unit)
elseif type == BONUS_SPELL_POWER_PERCENT then
return GetUnitSpellPowerPercent(unit)
elseif type == BONUS_LIFE_STEAL then
return GetUnitLifeSteal(unit)
elseif type == BONUS_SPELL_VAMP then
return GetUnitSpellVamp(unit)
elseif type == BONUS_COOLDOWN_REDUCTION then
return GetUnitCooldownReduction(unit)
elseif type == BONUS_COOLDOWN_REDUCTION_FLAT then
return GetUnitCooldownReductionFlat(unit)
elseif type == BONUS_COOLDOWN_OFFSET then
return GetUnitCooldownOffset(unit)
elseif type == BONUS_TENACITY then
return GetUnitTenacity(unit)
elseif type == BONUS_TENACITY_FLAT then
return GetUnitTenacityFlat(unit)
elseif type == BONUS_TENACITY_OFFSET then
return GetUnitTenacityOffset(unit)
end
else
if type == BONUS_CRITICAL_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, CRITICAL_STRIKE_ABILITY), CRITICAL_CHANCE_FIELD, 0)
elseif type == BONUS_CRITICAL_DAMAGE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, CRITICAL_STRIKE_ABILITY), CRITICAL_DAMAGE_FIELD, 0)
elseif type == BONUS_EVASION_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, EVASION_ABILITY), EVASION_FIELD, 0)
elseif type == BONUS_LIFE_STEAL then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, LIFE_STEAL_ABILITY), LIFE_STEAL_FIELD, 0)
end
end
else
print("Invalid Bonus Type")
end
return -1
end
function mt:set(unit, type, value, adding)
if not adding then
NewBonus.key = NewBonus.key + 1
NewBonus.unit[NewBonus.key] = unit
NewBonus.type[NewBonus.key] = type
NewBonus.amount[NewBonus.key] = value
self:onEvent(NewBonus.key)
if NewBonus.amount[NewBonus.key] ~= value then
value = NewBonus.amount[NewBonus.key]
end
if NewBonus.type[NewBonus.key] ~= type then
return self:set(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key], NewBonus.amount[NewBonus.key], not adding)
end
else
NewBonus.unit[NewBonus.key] = unit
NewBonus.type[NewBonus.key] = type
NewBonus.amount[NewBonus.key] = value
end
if type == BONUS_DAMAGE then
return self:setAbility(unit, DAMAGE_ABILITY, DAMAGE_FIELD, value, true, adding)
elseif type == BONUS_ARMOR then
return self:setAbility(unit, ARMOR_ABILITY, ARMOR_FIELD, value, true, adding)
elseif type == BONUS_HEALTH then
local real = GetUnitLifePercent(unit)
if value == 0 and not adding then
BlzSetUnitMaxHP(unit, (BlzGetUnitMaxHP(unit) - self:get(unit, type)))
else
BlzSetUnitMaxHP(unit, (BlzGetUnitMaxHP(unit) + value))
end
self:setAbility(unit, HEALTH_ABILITY, HEALTH_FIELD, value, true, adding)
SetUnitLifePercentBJ(unit, real)
return value
elseif type == BONUS_MANA then
local real = GetUnitManaPercent(unit)
if value == 0 and not adding then
BlzSetUnitMaxMana(unit, (BlzGetUnitMaxMana(unit) - self:get(unit, type)))
else
BlzSetUnitMaxMana(unit, (BlzGetUnitMaxMana(unit) + value))
end
self:setAbility(unit, MANA_ABILITY, MANA_FIELD, value, true, adding)
SetUnitManaPercentBJ(unit, real)
return value
elseif type == BONUS_AGILITY then
return self:setAbility(unit, STATS_ABILITY, AGILITY_FIELD, value, true, adding)
elseif type == BONUS_STRENGTH then
return self:setAbility(unit, STATS_ABILITY, STRENGTH_FIELD, value, true, adding)
elseif type == BONUS_INTELLIGENCE then
return self:setAbility(unit, STATS_ABILITY, INTELLIGENCE_FIELD, value, true, adding)
elseif type == BONUS_MOVEMENT_SPEED then
return self:setAbility(unit, MOVEMENTSPEED_ABILITY, MOVEMENTSPEED_FIELD, value, true, adding)
elseif type == BONUS_SIGHT_RANGE then
if value == 0 and not adding then
BlzSetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS) - self:get(unit, type)))
else
BlzSetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS) + value))
end
self:setAbility(unit, SIGHT_RANGE_ABILITY, SIGHT_RANGE_FIELD, value, true, adding)
return value
elseif type == BONUS_HEALTH_REGEN then
return self:setAbility(unit, HEALTHREGEN_ABILITY, HEALTHREGEN_FIELD, value, false, adding)
elseif type == BONUS_MANA_REGEN then
return self:setAbility(unit, MANAREGEN_ABILITY, MANAREGEN_FIELD, value, false, adding)
elseif type == BONUS_ATTACK_SPEED then
return self:setAbility(unit, ATTACKSPEED_ABILITY, ATTACKSPEED_FIELD, value, false, adding)
elseif type == BONUS_MAGIC_RESISTANCE then
return self:setAbility(unit, MAGIC_RESISTANCE_ABILITY, MAGIC_RESISTANCE_FIELD, value, false, adding)
elseif type >= BONUS_EVASION_CHANCE and type <= NewBonus.last then
if NewBonus_EXTENDED and Damage and Evasion and Critical and SpellPower and LifeSteal and SpellVamp and Tenacity then
if type == BONUS_EVASION_CHANCE then
SetUnitEvasionChance(unit, value)
elseif type == BONUS_MISS_CHANCE then
SetUnitMissChance(unit, value)
elseif type == BONUS_CRITICAL_CHANCE then
SetUnitCriticalChance(unit, value)
elseif type == BONUS_CRITICAL_DAMAGE then
SetUnitCriticalMultiplier(unit, value)
elseif type == BONUS_SPELL_POWER_FLAT then
SetUnitSpellPowerFlat(unit, value)
elseif type == BONUS_SPELL_POWER_PERCENT then
SetUnitSpellPowerPercent(unit, value)
elseif type == BONUS_LIFE_STEAL then
SetUnitLifeSteal(unit, value)
elseif type == BONUS_SPELL_VAMP then
SetUnitSpellVamp(unit, value)
elseif type == BONUS_COOLDOWN_REDUCTION then
if adding then
UnitAddCooldownReduction(unit, value)
else
SetUnitCooldownReduction(unit, value)
end
elseif type == BONUS_COOLDOWN_REDUCTION_FLAT then
SetUnitCooldownReductionFlat(unit, value)
elseif type == BONUS_COOLDOWN_OFFSET then
SetUnitCooldownOffset(unit, value)
elseif type == BONUS_TENACITY then
if adding then
UnitAddTenacity(unit, value)
else
SetUnitTenacity(unit, value)
end
elseif type == BONUS_TENACITY_FLAT then
SetUnitTenacityFlat(unit, value)
elseif type == BONUS_TENACITY_OFFSET then
SetUnitTenacityOffset(unit, value)
end
NewBonus.linkType = type
if NewBonus.key > 0 then
NewBonus.key = NewBonus.key - 1
end
return value
else
if type == BONUS_CRITICAL_CHANCE then
return self:setAbility(unit, CRITICAL_STRIKE_ABILITY, CRITICAL_CHANCE_FIELD, value, false, adding)
elseif type == BONUS_CRITICAL_DAMAGE then
return self:setAbility(unit, CRITICAL_STRIKE_ABILITY, CRITICAL_DAMAGE_FIELD, value, false, adding)
elseif type == BONUS_EVASION_CHANCE then
return self:setAbility(unit, EVASION_ABILITY, EVASION_FIELD, value, false, adding)
elseif type == BONUS_LIFE_STEAL then
return self:setAbility(unit, LIFE_STEAL_ABILITY, LIFE_STEAL_FIELD, value, false, adding)
end
end
else
print("Invalid Bonus Type")
end
return -1
end
function mt:add(unit, type, value)
if value ~= 0 then
NewBonus.key = NewBonus.key + 1
NewBonus.unit[NewBonus.key] = unit
NewBonus.type[NewBonus.key] = type
NewBonus.amount[NewBonus.key] = value
if type <= BONUS_SIGHT_RANGE then
NewBonus.amount[NewBonus.key] = self:checkOverflow(self:get(unit, type), R2I(value))
end
self:onEvent(NewBonus.key)
value = NewBonus.amount[NewBonus.key]
if NewBonus.type[NewBonus.key] <= BONUS_SIGHT_RANGE then
self:set(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key], self:checkOverflow(self:get(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key]), R2I(NewBonus.amount[NewBonus.key])), true)
else
if NewBonus_EXTENDED and Damage and Evasion and Critical and SpellPower and LifeSteal and SpellVamp and Tenacity then
if NewBonus.type[NewBonus.key] == BONUS_COOLDOWN_REDUCTION or NewBonus.type[NewBonus.key] == BONUS_TENACITY then
self:set(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key], NewBonus.amount[NewBonus.key], true)
else
self:set(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key], self:get(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key]) + NewBonus.amount[NewBonus.key], true)
end
else
self:set(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key], self:get(NewBonus.unit[NewBonus.key], NewBonus.type[NewBonus.key]) + NewBonus.amount[NewBonus.key], true)
end
end
return value
end
return -1
end
function mt:register(code, bonus)
if type(code) == "function" then
if bonus >= BONUS_DAMAGE and bonus <= NewBonus.last then
if not event[bonus] then event[bonus] = {} end
table.insert(event[bonus], code)
else
table.insert(trigger, code)
end
end
end
onInit(function()
if NewBonus_EXTENDED and Damage and Evasion and Critical and SpellPower and LifeSteal and SpellVamp and Tenacity then
NewBonus.last = BONUS_TENACITY_OFFSET
else
NewBonus.last = BONUS_LIFE_STEAL
end
end)
end
--[[ requires NewBonus, RegisterPlayerUnitEvent
-- ------------------------------------- NewBonusUtils v2.4 ------------------------------------- --
-- API:
-- function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
-- -> Add the specified amount for the specified bonus type for unit for a duration
-- -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)
-- function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
-- -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
-- -> the ability represented by the parameter buffId the bonus is not removed.
-- -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
-- function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
-- -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
-- -> Note that it will work for items with the same id, because it takes as parameter the item object.
-- -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())
-- function UnitCopyBonuses takes unit source, unit target returns nothing
-- -> Copy the source unit bonuses using the Add functionality to the target unit
-- -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())
-- function UnitMirrorBonuses takes unit source, unit target returns nothing
-- -> Copy the source unit bonuses using the Set functionality to the target unit
-- -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
local PERIOD = 0.03125000
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
function AddUnitBonusTimed(unit, type, amount, duration)
NewBonusUtils:linkTimed(unit, type, amount, duration, true)
end
function LinkBonusToBuff(unit, type, amount, buff)
NewBonusUtils:linkBuff(unit, type, amount, buff, false)
end
function LinkBonusToItem(unit, type, amount, item)
NewBonusUtils:linkItem(unit, type, amount, item)
end
function UnitCopyBonuses(source, target)
NewBonusUtils:copy(source, target)
end
function UnitMirrorBonuses(source, target)
NewBonusUtils:mirror(source, target)
end
-- ---------------------------------------------------------------------------------------------- --
-- System --
-- ---------------------------------------------------------------------------------------------- --
NewBonusUtils = setmetatable({}, {})
local mt = getmetatable(NewBonusUtils)
mt.__index = mt
local array = {}
local key = 0
local items = {}
local k = 0
local timer = CreateTimer()
function mt:destroy(i, item)
if NewBonus_EXTENDED and Damage and Evasion and Critical and SpellPower and LifeSteal and SpellVamp and Tenacity then
if self.type == BONUS_COOLDOWN_REDUCTION then
UnitRemoveCooldownReduction(self.unit, self.amount)
elseif self.type == BONUS_TENACITY then
UnitRemoveTenacity(self.unit, self.amount)
else
AddUnitBonus(self.unit, self.type, -self.amount)
end
else
AddUnitBonus(self.unit, self.type, -self.amount)
end
if item then
items[i] = items[k]
k = k - 1
else
array[i] = array[key]
key = key - 1
if key == 0 then
PauseTimer(timer)
end
end
self = nil
return i - 1
end
function mt:onPeriod()
local i = 1
local this
while i <= key do
this = array[i]
if this.timed then
if this.duration <= 0 then
i = this:destroy(i, false)
end
this.duration = this.duration - PERIOD
else
if GetUnitAbilityLevel(this.unit, this.buff) == 0 then
i = this:destroy(i, false)
end
end
i = i + 1
end
end
function mt:linkItem(unit, type, amount, item)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.item = item
this.amount = AddUnitBonus(unit, type, amount)
this.type = NewBonus.linkType
k = k + 1
items[k] = this
end
function mt:linkTimed(unit, type, amount, duration, timed)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.timed = timed
this.duration = duration
this.amount = AddUnitBonus(unit, type, amount)
this.type = NewBonus.linkType
key = key + 1
array[key] = this
if key == 1 then
TimerStart(timer, PERIOD, true, function() self:onPeriod() end)
end
end
function mt:linkBuff(unit, type, amount, buff, timed)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.timed = timed
this.buff = buff
this.amount = AddUnitBonus(unit, type, amount)
this.type = NewBonus.linkType
key = key + 1
array[key] = this
if key == 1 then
TimerStart(timer, PERIOD, true, function() self:onPeriod() end)
end
end
function mt:copy(source, target)
for i = 1, NewBonus.last do
if GetUnitBonus(source, i) ~= 0 then
AddUnitBonus(target, i, GetUnitBonus(source, i))
end
end
end
function mt:mirror(source, target)
for i = 1, NewBonus.last do
SetUnitBonus(target, i, GetUnitBonus(source, i))
end
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function()
local item = GetManipulatedItem()
local i = 1
local this
while i <= k do
this = items[i]
if this.item == item then
i = this:destroy(i, true)
end
i = i + 1
end
end)
end)
end
--[[ requires Utilities, WorldBounds, Indexer, TimerUtils, RegisterPlayerUnitEvent, optional Tenacity
-- ------------------------------------- Crowd Control v1.0 ------------------------------------- --
-- How to Import:
-- 1 - Copy the Utilities library over to your map and follow its install instructions
-- 2 - Copy the WorldBounds library over to your map and follow its install instructions
-- 3 - Copy the Indexer library over to your map and follow its install instructions
-- 4 - Copy the RegisterPlayerUnitEvent library over to your map and follow its install instructions
-- 5 - Copy the Tenacity library over to your map and follow its install instructions
-- 6 - Copy this library into your map
-- 7 - Copy the 14 buffs and 15 abilities with the CC prefix and match their raw code below.
-- ---------------------------------------- By Chopinski ---------------------------------------- --
]]--
do
-- ---------------------------------------------------------------------------------------------- --
-- Configuration --
-- ---------------------------------------------------------------------------------------------- --
-- The raw code of the silence ability
local SILENCE = FourCC('U000')
-- The raw code of the stun ability
local STUN = FourCC('U001')
-- The raw code of the attack slow ability
local ATTACK_SLOW = FourCC('U002')
-- The raw code of the movement slow ability
local MOVEMENT_SLOW = FourCC('U003')
-- The raw code of the banish ability
local BANISH = FourCC('U004')
-- The raw code of the ensnare ability
local ENSNARE = FourCC('U005')
-- The raw code of the purge ability
local PURGE = FourCC('U006')
-- The raw code of the hex ability
local HEX = FourCC('U007')
-- The raw code of the sleep ability
local SLEEP = FourCC('U008')
-- The raw code of the cyclone ability
local CYCLONE = FourCC('U009')
-- The raw code of the entangle ability
local ENTANGLE = FourCC('U010')
-- The raw code of the disarm ability
local DISARM = FourCC('U011')
-- The raw code of the fear ability
local FEAR = FourCC('U012')
-- The raw code of the taunt ability
local TAUNT = FourCC('U013')
-- The raw code of the true sight ability
local TRUE_SIGHT = FourCC('U014')
-- The raw code of the silence buff
local SILENCE_BUFF = FourCC('BU00')
-- The raw code of the stun buff
local STUN_BUFF = FourCC('BU01')
-- The raw code of the attack slow buff
local ATTACK_SLOW_BUFF = FourCC('BU02')
-- The raw code of the movement slow buff
local MOVEMENT_SLOW_BUFF = FourCC('BU03')
-- The raw code of the banish buff
local BANISH_BUFF = FourCC('BU04')
-- The raw code of the ensnare buff
local ENSNARE_BUFF = FourCC('BU05')
-- The raw code of the purge buff
local PURGE_BUFF = FourCC('BU06')
-- The raw code of the hex buff
local HEX_BUFF = FourCC('BU07')
-- The raw code of the sleep buff
local SLEEP_BUFF = FourCC('BU08')
-- The raw code of the cyclone buff
local CYCLONE_BUFF = FourCC('BU09')
-- The raw code of the entangle buff
local ENTANGLE_BUFF = FourCC('BU10')
-- The raw code of the disarm buff
local DISARM_BUFF = FourCC('BU11')
-- The raw code of the fear buff
local FEAR_BUFF = FourCC('BU12')
-- The raw code of the taunt buff
local TAUNT_BUFF = FourCC('BU13')
-- This is the maximum recursion limit allowed by the system.
-- Its value must be greater than or equal to 0. When equal to 0
-- no recursion is allowed. Values too big can cause screen freezes.
local RECURSION_LIMIT = 8
-- The Crowd Control types
CROWD_CONTROL_SILENCE = 0
CROWD_CONTROL_STUN = 1
CROWD_CONTROL_SLOW = 2
CROWD_CONTROL_SLOW_ATTACK = 3
CROWD_CONTROL_BANISH = 4
CROWD_CONTROL_ENSNARE = 5
CROWD_CONTROL_PURGE = 6
CROWD_CONTROL_HEX = 7
CROWD_CONTROL_SLEEP = 8
CROWD_CONTROL_CYCLONE = 9
CROWD_CONTROL_ENTANGLE = 10
CROWD_CONTROL_DISARM = 11
CROWD_CONTROL_FEAR = 12
CROWD_CONTROL_TAUNT = 13
CROWD_CONTROL_KNOCKBACK = 14
CROWD_CONTROL_KNOCKUP = 15
-- ---------------------------------------------------------------------------------------------- --
-- LUA API --
-- ---------------------------------------------------------------------------------------------- --
-- ------------------------------------------- Disarm ------------------------------------------- --
function DisarmUnit(unit, duration, model, point, stack)
CrowdControl:disarm(unit, duration, model, point, stack)
end
function IsUnitDisarmed(unit)
return CrowdControl:disarmed(unit)
end
-- -------------------------------------------- Fear -------------------------------------------- --
function FearUnit(unit, duration, model, point, stack)
CrowdControl:fear(unit, duration, model, point, stack)
end
function IsUnitFeared(unit)
return CrowdControl:feared(unit)
end
-- -------------------------------------------- Taunt ------------------------------------------- --
function TauntUnit(source, target, duration, model, point, stack)
CrowdControl:taunt(source, target, duration, model, point, stack)
end
function IsUnitTaunted(unit)
return CrowdControl:taunted(unit)
end
-- ------------------------------------------ Knockback ----------------------------------------- --
function KnockbackUnit(unit, angle, distance, duration, model, point, onCliff, onDestructable, onUnit, stack)
CrowdControl:knockback(unit, angle, distance, duration, model, point, onCliff, onDestructable, onUnit, stack)
end
function IsUnitKnockedBack(unit)
return CrowdControl:knockedback(unit)
end
-- ------------------------------------------- Knockup ------------------------------------------ --
function KnockupUnit(unit, height, duration, model, point, stack)
CrowdControl:knockup(unit, height, duration, model, point, stack)
end
function IsUnitKnockedUp(unit)
return CrowdControl:knockedup(unit)
end
-- ------------------------------------------- Silence ------------------------------------------ --
function SilenceUnit(unit, duration, model, point, stack)
CrowdControl:silence(unit, duration, model, point, stack)
end
function IsUnitSilenced(unit)
return CrowdControl:silenced(unit)
end
-- -------------------------------------------- Stun -------------------------------------------- --
function StunUnit(unit, duration, model, point, stack)
CrowdControl:stun(unit, duration, model, point, stack)
end
function IsUnitStunned(unit)
return CrowdControl:stunned(unit)
end
-- ---------------------------------------- Movement Slow --------------------------------------- --
function SlowUnit(unit, amount, duration, model, point, stack)
CrowdControl:slow(unit, amount, duration, model, point, stack)
end
function IsUnitSlowed(unit)
return CrowdControl:slowed(unit)
end
-- ----------------------------------------- Attack Slow ---------------------------------------- --
function SlowUnitAttack(unit, amount, duration, model, point, stack)
CrowdControl:slowAttack(unit, amount, duration, model, point, stack)
end
function IsUnitAttackSlowed(unit)
return CrowdControl:attackSlowed(unit)
end
-- ------------------------------------------- Banish ------------------------------------------- --
function BanishUnit(unit, duration, model, point, stack)
CrowdControl:banish(unit, duration, model, point, stack)
end
function IsUnitBanished(unit)
return CrowdControl:banished(unit)
end
-- ------------------------------------------- Ensnare ------------------------------------------ --
function EnsnareUnit(unit, duration, model, point, stack)
CrowdControl:ensnare(unit, duration, model, point, stack)
end
function IsUnitEnsnared(unit)
return CrowdControl:ensnared(unit)
end
-- -------------------------------------------- Purge ------------------------------------------- --
function PurgeUnit(unit, duration, model, point, stack)
CrowdControl:purge(unit, duration, model, point, stack)
end
function IsUnitPurged(unit)
return CrowdControl:purged(unit)
end
-- --------------------------------------------- Hex -------------------------------------------- --
function HexUnit(unit, duration, model, point, stack)
CrowdControl:hex(unit, duration, model, point, stack)
end
function IsUnitHexed(unit)
return CrowdControl:hexed(unit)
end
-- -------------------------------------------- Sleep ------------------------------------------- --
function SleepUnit(unit, duration, model, point, stack)
CrowdControl:sleep(unit, duration, model, point, stack)
end
function IsUnitSleeping(unit)
return CrowdControl:sleeping(unit)
end
-- ------------------------------------------- Cyclone ------------------------------------------ --
function CycloneUnit(unit, duration, model, point, stack)
CrowdControl:cyclone(unit, duration, model, point, stack)
end
function IsUnitCycloned(unit)
return CrowdControl:cycloned(unit)
end
-- ------------------------------------------ Entangle ------------------------------------------ --
function EntangleUnit(unit, duration, model, point, stack)
CrowdControl:entangle(unit, duration, model, point, stack)
end
function IsUnitEntangled(unit)
return CrowdControl:entangled(unit)
end
-- ------------------------------------------- Dispel ------------------------------------------- --
function UnitDispelCrowdControl(unit, type)
CrowdControl:dispel(unit, type)
end
function UnitDispelAllCrowdControl(unit)
CrowdControl:dispelAll(unit)
end
-- ------------------------------------------- Events ------------------------------------------- --
function RegisterCrowdControlEvent(type, code)
CrowdControl:register(type, code)
end
function RegisterAnyCrowdControlEvent(code)
CrowdControl:register(-1, code)
end
function GetCrowdControlUnit()
return CrowdControl.unit[CrowdControl.key]
end
function GetCrowdControlType()
return CrowdControl.type[CrowdControl.key]
end
function GetCrowdControlDuration()
return CrowdControl.duration[CrowdControl.key]
end
function GetCrowdControlAmount()
return CrowdControl.amount[CrowdControl.key]
end
function GetCrowdControlModel()
return CrowdControl.model[CrowdControl.key]
end
function GetCrowdControlBone()
return CrowdControl.point[CrowdControl.key]
end
function GetCrowdControlStack()
return CrowdControl.stack[CrowdControl.key]
end
function GetCrowdControlRemaining(unit, type)
return CrowdControl:remaining(unit, type)
end
function GetTauntSource()
return CrowdControl.source[CrowdControl.key]
end
function GetKnockbackAngle()
return CrowdControl.angle[CrowdControl.key]
end
function GetKnockbackDistance()
return CrowdControl.distance[CrowdControl.key]
end
function GetKnockupHeight()
return CrowdControl.height[CrowdControl.key]
end
function GetKnockbackOnCliff()
return CrowdControl.cliff[CrowdControl.key]
end
function GetKnockbackOnDestructable()
return CrowdControl.destructable[CrowdControl.key]
end
function GetKnockbackOnUnit()
return CrowdControl.agent[CrowdControl.key]
end
function SetCrowdControlUnit(unit)
CrowdControl.unit[CrowdControl.key] = unit
end
function SetCrowdControlType(type)
if type >= CROWD_CONTROL_SILENCE and type <= CROWD_CONTROL_KNOCKUP then
CrowdControl.type[CrowdControl.key] = type
end
end
function SetCrowdControlDuration(duration)
CrowdControl.duration[CrowdControl.key] = duration
end
function SetCrowdControlAmount(amount)
CrowdControl.amount[CrowdControl.key] = amount
end
function SetCrowdControlModel(model)
CrowdControl.model[CrowdControl.key] = model
end
function SetCrowdControlBone(point)
CrowdControl.point[CrowdControl.key] = point
end
function SetCrowdControlStack(stack)
CrowdControl.stack[CrowdControl.key] = stack
end
function SetTauntSource(unit)
CrowdControl.source[CrowdControl.key] = unit
end
function SetKnockbackAngle(angle)
CrowdControl.angle[CrowdControl.key] = angle
end
function SetKnockbackDistance(distance)
CrowdControl.distance[CrowdControl.key] = distance
end
function SetKnockupHeight(height)
CrowdControl.height[CrowdControl.key] = height
end
function SetKnockbackOnCliff(onCliff)
CrowdControl.cliff[CrowdControl.key] = onCliff
end
function SetKnockbackOnDestructable(onDestructable)
CrowdControl.destructable[CrowdControl.key] = onDestructable
end
function SetKnockbackOnUnit(onUnit)
CrowdControl.agent[CrowdControl.key] = onUnit
end
-- ---------------------------------------------------------------------------------------------- --
-- Systems --
-- ---------------------------------------------------------------------------------------------- --
-- ------------------------------------------ Knockback ----------------------------------------- --
do
Knockback = setmetatable({}, {})
local mt = getmetatable(Knockback)
mt.__index = mt
local timer = CreateTimer()
local rect = Rect(0., 0., 0., 0.)
local period = 0.03125
local array = {}
local struct = {}
local key = 0
function mt:destroy(i)
DestroyGroup(self.group)
DestroyEffect(self.effect)
BlzPauseUnitEx(self.unit, false)
struct[self.unit] = nil
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:knocked(unit)
return struct[unit] ~= nil
end
function mt:apply(target, angle, distance, duration, model, point, cliff, dest, hit)
local this
if duration > 0 and UnitAlive(target) then
if struct[target] then
this = struct[target]
else
this = {}
setmetatable(this, mt)
this.unit = target
this.collision = 2*BlzGetUnitCollisionSize(target)
this.group = CreateGroup()
key = key + 1
array[key] = this
struct[target] = this
BlzPauseUnitEx(target, true)
if model and point then
this.effect = AddSpecialEffectTarget(model, target, point)
end
if key == 1 then
TimerStart(timer, period, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.duration > 0 and UnitAlive(this.unit) then
local x = GetUnitX(this.unit) + this.offset*Cos(this.angle)
local y = GetUnitY(this.unit) + this.offset*Sin(this.angle)
this.duration = this.duration - period
if this.onUnit and this.collision > 0 then
GroupEnumUnitsInRange(this.group, x, y, this.collision, nil)
GroupRemoveUnit(this.group, this.unit)
for j = 0, BlzGroupGetSize(this.group) - 1 do
if UnitAlive(BlzGroupUnitAt(this.group, j)) then
this.duration = 0
break
end
end
end
if this.onDestructable and this.duration > 0 and this.collision > 0 then
SetRect(rect, x - this.collision, y - this.collision, x + this.collision, y + this.collision)
EnumDestructablesInRect(rect, nil, function()
if GetDestructableLife(GetEnumDestructable()) > 0 then
this.duration = 0
return
end
end)
end
if this.onCliff and this.duration > 0 then
if GetTerrainCliffLevel(GetUnitX(this.unit), GetUnitY(this.unit)) < GetTerrainCliffLevel(x, y) and GetUnitZ(this.unit) < (GetTerrainCliffLevel(x, y) - GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY))*bj_CLIFFHEIGHT then
this.duration = 0
end
end
if this.duration > 0 then
SetUnitX(this.unit, x)
SetUnitY(this.unit, y)
end
else
i = this:destroy(i)
end
i = i + 1
end
end)
end
end
this.angle = angle
this.distance = distance
this.duration = duration
this.onCliff = cliff
this.onDestructable = dest
this.onUnit = hit
this.offset = RMaxBJ(0.00000001, distance*period/RMaxBJ(0.00000001, duration))
end
end
end
-- ------------------------------------------- Knockup ------------------------------------------ --
do
Knockup = setmetatable({}, {})
local mt = getmetatable(Knockup)
mt.__index = mt
local knocked = {}
function mt:isUnitKnocked(unit)
return (knocked[unit] or 0) > 0
end
function mt:apply(unit, duration, height, model, point)
if duration > 0 then
local timer = CreateTimer()
local rate = height/duration
local effect
knocked[unit] = (knocked[unit] or 0) + 1
if model and point then
effect = AddSpecialEffect(model, unit, point)
end
if knocked[unit] == 1 then
BlzPauseUnitEx(unit, true)
end
UnitAddAbility(unit, FourCC('Amrf'))
UnitRemoveAbility(unit, FourCC('Amrf'))
SetUnitFlyHeight(unit, (GetUnitDefaultFlyHeight(unit) + height), rate)
TimerStart(timer, duration/2, false, function()
SetUnitFlyHeight(unit, GetUnitDefaultFlyHeight(unit), rate)
TimerStart(timer, duration/2, false, function()
DestroyEffect(effect)
PauseTimer(timer)
DestroyTimer(timer)
knocked[unit] = knocked[unit] - 1
if knocked[unit] == 0 then
BlzPauseUnitEx(unit, false)
end
end)
end)
end
end
end
-- -------------------------------------------- Fear -------------------------------------------- --
do
Fear = setmetatable({}, {})
local mt = getmetatable(Fear)
mt.__index = mt
local timer = CreateTimer()
local array = {}
local struct = {}
local flag = {}
local x = {}
local y = {}
local key = 0
local UPDATE = 0.2
local DIRECTION_CHANGE = 5
local MAX_CHANGE = 200.
local dummy
local ability
function mt:feared(unit)
return GetUnitAbilityLevel(unit, FEAR_BUFF) > 0
end
function mt:destroy(i)
flag[self.target] = true
IssueImmediateOrder(self.target, "stop")
DestroyEffect(self.effect)
array[i] = array[key]
key = key - 1
struct[self.target] = nil
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:apply(target, duration, effect, attach)
local this
if duration > 0 then
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_NORMAL, 0, duration)
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_HERO, 0, duration)
IncUnitAbilityLevel(dummy, FEAR)
DecUnitAbilityLevel(dummy, FEAR)
if IssueTargetOrder(dummy, "drunkenhaze", target) then
if struct[target] then
this = struct[target]
else
this = {}
setmetatable(this, mt)
key = key + 1
array[key] = this
struct[target] = this
this.target = target
this.change = 0
if effect and attach then
this.effect = AddSpecialEffectTarget(effect, target, attach)
end
if key == 1 then
TimerStart(timer, UPDATE, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if GetUnitAbilityLevel(this.target, FEAR_BUFF) > 0 then
this.change = this.change + 1
if this.change == DIRECTION_CHANGE then
this.change = 0
flag[this.target] = true
x[this.target] = GetRandomReal(GetUnitX(this.target) - MAX_CHANGE, GetUnitX(this.target) + MAX_CHANGE)
y[this.target] = GetRandomReal(GetUnitY(this.target) - MAX_CHANGE, GetUnitY(this.target) + MAX_CHANGE)
IssuePointOrder(this.target, "move", x[this.target], y[this.target])
end
else
i = this:destroy(i)
end
i = i + 1
end
end)
end
end
flag[target] = true
x[target] = GetRandomReal(GetUnitX(target) - MAX_CHANGE, GetUnitX(target) + MAX_CHANGE)
y[target] = GetRandomReal(GetUnitY(target) - MAX_CHANGE, GetUnitY(target) + MAX_CHANGE)
IssuePointOrder(target, "move", x[target], y[target])
end
end
end
function mt:onOrder()
local unit = GetOrderedUnit()
if self:feared(unit) and GetIssuedOrderId() ~= 851973 then
if not flag[unit] then
flag[unit] = true
IssuePointOrder(unit, "move", x[unit], y[unit])
else
flag[unit] = false
end
end
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function()
Fear:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function()
Fear:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function()
Fear:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function()
Fear:onOrder()
end)
TimerStart(CreateTimer(), 0, false, function()
dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
UnitAddAbility(dummy, TRUE_SIGHT)
UnitAddAbility(dummy, FEAR)
PauseTimer(GetExpiredTimer())
DestroyTimer(GetExpiredTimer())
ability = BlzGetUnitAbility(dummy, FEAR)
end)
end)
end
-- -------------------------------------------- Taunt ------------------------------------------- --
do
Taunt = setmetatable({}, {})
local mt = getmetatable(Taunt)
mt.__index = mt
Taunt.source = {}
local timer = CreateTimer()
local PERIOD = 0.2
local key = 0
local array = {}
local struct = {}
local dummy
local ability
function mt:taunted(unit)
return GetUnitAbilityLevel(unit, TAUNT_BUFF) > 0
end
function mt:destroy(i)
UnitDispelCrowdControl(self.target, CROWD_CONTROL_TAUNT)
IssueImmediateOrder(self.target, "stop")
DestroyEffect(self.effect)
if self.selected then
SelectUnitAddForPlayer(self.target, GetOwningPlayer(self.target))
end
array[i] = array[key]
key = key - 1
struct[self.target] = nil
Taunt.source[self.target] = nil
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:apply(source, target, duration, model, point)
local this
if duration > 0 and UnitAlive(source) and UnitAlive(target) then
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_NORMAL, 0, duration)
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_HERO, 0, duration)
IncUnitAbilityLevel(dummy, TAUNT)
DecUnitAbilityLevel(dummy, TAUNT)
if IssueTargetOrder(dummy, "drunkenhaze", target) then
if struct[target] then
this = struct[target]
else
this = {}
setmetatable(this, mt)
key = key + 1
array[key] = this
struct[target] = this
this.target = target
this.selected = IsUnitSelected(target, GetOwningPlayer(target))
if this.selected then
SelectUnit(target, false)
end
if model and point then
this.effect = AddSpecialEffectTarget(model, target, point)
end
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if GetUnitAbilityLevel(this.target, TAUNT_BUFF) > 0 and UnitAlive(Taunt.source[this.target]) and UnitAlive(this.target) then
if IsUnitVisible(Taunt.source[this.target], GetOwningPlayer(this.target)) then
IssueTargetOrderById(this.target, 851983, Taunt.source[this.target])
else
IssuePointOrderById(this.target, 851986, GetUnitX(Taunt.source[this.target]), GetUnitY(Taunt.source[this.target]))
end
else
i = this:destroy(i)
end
i = i + 1
end
end)
end
end
Taunt.source[target] = source
if IsUnitVisible(source, GetOwningPlayer(target)) then
IssueTargetOrderById(target, 851983, source)
else
IssuePointOrderById(target, 851986, GetUnitX(source), GetUnitY(source))
end
end
end
end
function mt:onOrder()
local unit = GetOrderedUnit()
local order = GetIssuedOrderId()
if self:taunted(unit) and order ~= 851973 then
if order ~= 851983 and order ~= 851986 then
if IsUnitVisible(Taunt.source[unit], GetOwningPlayer(unit)) then
IssueTargetOrderById(unit, 851983, Taunt.source[unit])
else
IssuePointOrderById(unit, 851986, GetUnitX(Taunt.source[unit]), GetUnitY(Taunt.source[unit]))
end
else
if GetOrderTargetUnit() ~= Taunt.source[unit] and GetOrderTargetUnit() ~= nil then
if IsUnitVisible(source[id], GetOwningPlayer(target)) then
IssueTargetOrderById(unit, 851983, Taunt.source[unit])
else
IssuePointOrderById(unit, 851986, GetUnitX(Taunt.source[unit]), GetUnitY(Taunt.source[unit]))
end
end
end
end
end
function mt:onSelect()
local unit = GetTriggerUnit()
if self:taunted(unit) then
if IsUnitSelected(unit, GetOwningPlayer(unit)) then
SelectUnit(unit, false)
end
end
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function()
Taunt:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function()
Taunt:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function()
Taunt:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function()
Taunt:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function()
Taunt:onSelect()
end)
TimerStart(CreateTimer(), 0, false, function()
dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
UnitAddAbility(dummy, TRUE_SIGHT)
UnitAddAbility(dummy, TAUNT)
PauseTimer(GetExpiredTimer())
DestroyTimer(GetExpiredTimer())
ability = BlzGetUnitAbility(dummy, TAUNT)
end)
end)
end
-- ---------------------------------------- Crowd Control --------------------------------------- --
do
CrowdControl = setmetatable({}, {})
local mt = getmetatable(CrowdControl)
mt.__index = mt
CrowdControl.key = 0
CrowdControl.unit = {}
CrowdControl.source = {}
CrowdControl.amount = {}
CrowdControl.duration = {}
CrowdControl.angle = {}
CrowdControl.distance = {}
CrowdControl.height = {}
CrowdControl.model = {}
CrowdControl.point = {}
CrowdControl.stack = {}
CrowdControl.cliff = {}
CrowdControl.destructable = {}
CrowdControl.agent = {}
CrowdControl.type = {}
local trigger = {}
local timer = {}
local event = {}
local ability = {}
local buff = {}
local order = {}
local dummy
local count = 0
onInit(function()
local t = CreateTimer()
TimerStart(t, 0, false, function()
dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
UnitAddAbility(dummy, SILENCE)
UnitAddAbility(dummy, STUN)
UnitAddAbility(dummy, ATTACK_SLOW)
UnitAddAbility(dummy, MOVEMENT_SLOW)
UnitAddAbility(dummy, BANISH)
UnitAddAbility(dummy, ENSNARE)
UnitAddAbility(dummy, PURGE)
UnitAddAbility(dummy, HEX)
UnitAddAbility(dummy, SLEEP)
UnitAddAbility(dummy, CYCLONE)
UnitAddAbility(dummy, ENTANGLE)
UnitAddAbility(dummy, DISARM)
UnitAddAbility(dummy, TRUE_SIGHT)
BlzUnitDisableAbility(dummy, SILENCE, true, true)
BlzUnitDisableAbility(dummy, STUN, true, true)
BlzUnitDisableAbility(dummy, ATTACK_SLOW, true, true)
BlzUnitDisableAbility(dummy, MOVEMENT_SLOW, true, true)
BlzUnitDisableAbility(dummy, BANISH, true, true)
BlzUnitDisableAbility(dummy, ENSNARE, true, true)
BlzUnitDisableAbility(dummy, PURGE, true, true)
BlzUnitDisableAbility(dummy, HEX, true, true)
BlzUnitDisableAbility(dummy, SLEEP, true, true)
BlzUnitDisableAbility(dummy, CYCLONE, true, true)
BlzUnitDisableAbility(dummy, ENTANGLE, true, true)
BlzUnitDisableAbility(dummy, DISARM, true, true)
ability[CROWD_CONTROL_SILENCE] = SILENCE
ability[CROWD_CONTROL_STUN] = STUN
ability[CROWD_CONTROL_SLOW] = MOVEMENT_SLOW
ability[CROWD_CONTROL_SLOW_ATTACK] = ATTACK_SLOW
ability[CROWD_CONTROL_BANISH] = BANISH
ability[CROWD_CONTROL_ENSNARE] = ENSNARE
ability[CROWD_CONTROL_PURGE] = PURGE
ability[CROWD_CONTROL_HEX] = HEX
ability[CROWD_CONTROL_SLEEP] = SLEEP
ability[CROWD_CONTROL_CYCLONE] = CYCLONE
ability[CROWD_CONTROL_ENTANGLE] = ENTANGLE
ability[CROWD_CONTROL_DISARM] = DISARM
ability[CROWD_CONTROL_FEAR] = FEAR
ability[CROWD_CONTROL_TAUNT] = TAUNT
buff[CROWD_CONTROL_SILENCE] = SILENCE_BUFF
buff[CROWD_CONTROL_STUN] = STUN_BUFF
buff[CROWD_CONTROL_SLOW] = MOVEMENT_SLOW_BUFF
buff[CROWD_CONTROL_SLOW_ATTACK] = ATTACK_SLOW_BUFF
buff[CROWD_CONTROL_BANISH] = BANISH_BUFF
buff[CROWD_CONTROL_ENSNARE] = ENSNARE_BUFF
buff[CROWD_CONTROL_PURGE] = PURGE_BUFF
buff[CROWD_CONTROL_HEX] = HEX_BUFF
buff[CROWD_CONTROL_SLEEP] = SLEEP_BUFF
buff[CROWD_CONTROL_CYCLONE] = CYCLONE_BUFF
buff[CROWD_CONTROL_ENTANGLE] = ENTANGLE_BUFF
buff[CROWD_CONTROL_DISARM] = DISARM_BUFF
buff[CROWD_CONTROL_FEAR] = FEAR_BUFF
buff[CROWD_CONTROL_TAUNT] = TAUNT_BUFF
order[CROWD_CONTROL_SILENCE] = "drunkenhaze"
order[CROWD_CONTROL_STUN] = "thunderbolt"
order[CROWD_CONTROL_SLOW] = "cripple"
order[CROWD_CONTROL_SLOW_ATTACK] = "cripple"
order[CROWD_CONTROL_BANISH] = "banish"
order[CROWD_CONTROL_ENSNARE] = "ensnare"
order[CROWD_CONTROL_PURGE] = "purge"
order[CROWD_CONTROL_HEX] = "hex"
order[CROWD_CONTROL_SLEEP] = "sleep"
order[CROWD_CONTROL_CYCLONE] = "cyclone"
order[CROWD_CONTROL_ENTANGLE] = "entanglingroots"
order[CROWD_CONTROL_DISARM] = "drunkenhaze"
PauseTimer(t)
DestroyTimer(t)
end)
end)
function mt:onEvent(key)
local i = 0
local next = -1
local prev = -2
count = count + 1
if count - CROWD_CONTROL_KNOCKUP < RECURSION_LIMIT then
while CrowdControl.type[key] ~= next or (i - CROWD_CONTROL_KNOCKUP > RECURSION_LIMIT) do
next = CrowdControl.type[key]
if event[next] then
for j = 1, #event[next] do
event[next][j]()
end
end
if CrowdControl.type[key] ~= next then
i = i + 1
else
if next ~= prev then
for j = 1, #trigger do
trigger[j]()
end
if CrowdControl.type[key] ~= next then
i = i + 1
prev = next
end
end
end
end
end
count = count - 1
CrowdControl.key = key
end
function mt:cast(source, target, amount, angle, distance, height, duration, model, point, stack, onCliff, onDestructable, onUnit, type)
if not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) and UnitAlive(target) and duration > 0 then
CrowdControl.key = CrowdControl.key + 1
CrowdControl.unit[CrowdControl.key] = target
CrowdControl.source[CrowdControl.key] = source
CrowdControl.amount[CrowdControl.key] = amount
CrowdControl.angle[CrowdControl.key] = angle
CrowdControl.distance[CrowdControl.key] = distance
CrowdControl.height[CrowdControl.key] = height
CrowdControl.duration[CrowdControl.key] = duration
CrowdControl.model[CrowdControl.key] = model
CrowdControl.point[CrowdControl.key] = point
CrowdControl.stack[CrowdControl.key] = stack
CrowdControl.cliff[CrowdControl.key] = onCliff
CrowdControl.destructable[CrowdControl.key] = onDestructable
CrowdControl.agent[CrowdControl.key] = onUnit
CrowdControl.type[CrowdControl.key] = type
self:onEvent(CrowdControl.key)
if Tenacity then
CrowdControl.duration[CrowdControl.key] = GetTenacityDuration(CrowdControl.unit[CrowdControl.key], CrowdControl.duration[CrowdControl.key])
end
if CrowdControl.duration[CrowdControl.key] > 0 and UnitAlive(CrowdControl.unit[CrowdControl.key]) then
local i = CrowdControl.unit[CrowdControl.key]
local j = CrowdControl.type[CrowdControl.key]
if not timer[i] then timer[i] = {} end
if not timer[i][j] then
timer[i][j] = CreateTimer()
end
if CrowdControl.stack[CrowdControl.key] then
if CrowdControl.type[CrowdControl.key] ~= CROWD_CONTROL_TAUNT then
CrowdControl.duration[CrowdControl.key] = CrowdControl.duration[CrowdControl.key] + TimerGetRemaining(timer[i][j])
else
if Taunt.source[CrowdControl.unit[CrowdControl.key]] == CrowdControl.source[CrowdControl.key] then
CrowdControl.duration[CrowdControl.key] = CrowdControl.duration[CrowdControl.key] + TimerGetRemaining(timer[i][j])
end
end
end
if CrowdControl.type[CrowdControl.key] ~= CROWD_CONTROL_FEAR and CrowdControl.type[CrowdControl.key] ~= CROWD_CONTROL_TAUNT and CrowdControl.type[CrowdControl.key] ~= CROWD_CONTROL_KNOCKBACK and CrowdControl.type[CrowdControl.key] ~= CROWD_CONTROL_KNOCKUP then
local spell = BlzGetUnitAbility(dummy, ability[CrowdControl.type[CrowdControl.key]])
BlzUnitDisableAbility(dummy, ability[CrowdControl.type[CrowdControl.key]], false, false)
BlzSetAbilityRealLevelField(spell, ABILITY_RLF_DURATION_NORMAL, 0, CrowdControl.duration[CrowdControl.key])
BlzSetAbilityRealLevelField(spell, ABILITY_RLF_DURATION_HERO, 0, CrowdControl.duration[CrowdControl.key])
if CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_SLOW then
BlzSetAbilityRealLevelField(spell, ABILITY_RLF_MOVEMENT_SPEED_REDUCTION_PERCENT_CRI1, 0, CrowdControl.amount[CrowdControl.key])
elseif CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_SLOW_ATTACK then
BlzSetAbilityRealLevelField(spell, ABILITY_RLF_ATTACK_SPEED_REDUCTION_PERCENT_CRI2, 0, CrowdControl.amount[CrowdControl.key])
end
IncUnitAbilityLevel(dummy, ability[CrowdControl.type[CrowdControl.key]])
DecUnitAbilityLevel(dummy, ability[CrowdControl.type[CrowdControl.key]])
if IssueTargetOrder(dummy, order[CrowdControl.type[CrowdControl.key]], CrowdControl.unit[CrowdControl.key]) then
UnitRemoveAbility(CrowdControl.unit[CrowdControl.key], buff[CrowdControl.type[CrowdControl.key]])
IssueTargetOrder(dummy, order[CrowdControl.type[CrowdControl.key]], CrowdControl.unit[CrowdControl.key])
TimerStart(timer[i][j], CrowdControl.duration[CrowdControl.key], false, function()
PauseTimer(timer[i][j])
DestroyTimer(timer[i][j])
timer[i][j] = nil
end)
if CrowdControl.model[CrowdControl.key] then
if CrowdControl.point[CrowdControl.key] then
LinkEffectToBuff(CrowdControl.unit[CrowdControl.key], buff[CrowdControl.type[CrowdControl.key]], CrowdControl.model[CrowdControl.key], CrowdControl.point[CrowdControl.key])
else
DestroyEffect(AddSpecialEffect(CrowdControl.model[CrowdControl.key], GetUnitX(CrowdControl.unit[CrowdControl.key]), GetUnitY(CrowdControl.unit[CrowdControl.key])))
end
end
else
PauseTimer(timer[i][j])
DestroyTimer(timer[i][j])
timer[i][j] = nil
end
BlzUnitDisableAbility(dummy, ability[CrowdControl.type[CrowdControl.key]], true, true)
else
if CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_FEAR then
Fear:apply(CrowdControl.unit[CrowdControl.key], CrowdControl.duration[CrowdControl.key], CrowdControl.model[CrowdControl.key], CrowdControl.point[CrowdControl.key])
elseif CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_TAUNT then
Taunt:apply(CrowdControl.source[CrowdControl.key], CrowdControl.unit[CrowdControl.key], CrowdControl.duration[CrowdControl.key], CrowdControl.model[CrowdControl.key], CrowdControl.point[CrowdControl.key])
elseif CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_KNOCKBACK then
Knockback:apply(CrowdControl.unit[CrowdControl.key], CrowdControl.angle[CrowdControl.key], CrowdControl.distance[CrowdControl.key], CrowdControl.duration[CrowdControl.key], CrowdControl.model[CrowdControl.key], CrowdControl.point[CrowdControl.key], CrowdControl.cliff[CrowdControl.key], CrowdControl.destructable[CrowdControl.key], CrowdControl.agent[CrowdControl.key])
elseif CrowdControl.type[CrowdControl.key] == CROWD_CONTROL_KNOCKUP then
Knockup:apply(CrowdControl.unit[CrowdControl.key], CrowdControl.duration[CrowdControl.key], CrowdControl.height[CrowdControl.key], CrowdControl.model[CrowdControl.key], CrowdControl.point[CrowdControl.key])
end
TimerStart(timer[i][j], CrowdControl.duration[CrowdControl.key], false, function()
PauseTimer(timer[i][j])
DestroyTimer(timer[i][j])
timer[i][j] = nil
end)
end
end
if CrowdControl.key > 0 then
CrowdControl.key = CrowdControl.key - 1
end
end
end
function mt:silence(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SILENCE)
end
function mt:silenced(unit)
return GetUnitAbilityLevel(unit, SILENCE_BUFF) > 0
end
function mt:stun(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_STUN)
end
function mt:stunned(unit)
return GetUnitAbilityLevel(unit, STUN_BUFF) > 0
end
function mt:slow(unit, amount, duration, model, point, stack)
self:cast(nil, unit, amount, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLOW)
end
function mt:slowed(unit)
return GetUnitAbilityLevel(unit, MOVEMENT_SLOW_BUFF) > 0
end
function mt:slowAttack(unit, amount, duration, model, point, stack)
self:cast(nil, unit, amount, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLOW_ATTACK)
end
function mt:attackSlowed(unit)
return GetUnitAbilityLevel(unit, ATTACK_SLOW_BUFF) > 0
end
function mt:banish(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_BANISH)
end
function mt:banished(unit)
return GetUnitAbilityLevel(unit, BANISH_BUFF) > 0
end
function mt:ensnare(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_ENSNARE)
end
function mt:ensnared(unit)
return GetUnitAbilityLevel(unit, ENSNARE_BUFF) > 0
end
function mt:purge(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_PURGE)
end
function mt:purged(unit)
return GetUnitAbilityLevel(unit, PURGE_BUFF) > 0
end
function mt:hex(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_HEX)
end
function mt:hexed(unit)
return GetUnitAbilityLevel(unit, HEX_BUFF) > 0
end
function mt:sleep(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLEEP)
end
function mt:sleeping(unit)
return GetUnitAbilityLevel(unit, SLEEP_BUFF) > 0
end
function mt:cyclone(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_CYCLONE)
end
function mt:cycloned(unit)
return GetUnitAbilityLevel(unit, CYCLONE_BUFF) > 0
end
function mt:entangle(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_ENTANGLE)
end
function mt:entangled(unit)
return GetUnitAbilityLevel(unit, ENTANGLE_BUFF) > 0
end
function mt:knockback(unit, angle, distance, duration, model, point, onCliff, onDestructable, onUnit, stack)
self:cast(nil, unit, 0, angle, distance, 0, duration, model, point, stack, onCliff, onDestructable, onUnit, CROWD_CONTROL_KNOCKBACK)
end
function mt:knockedback(unit)
return Knockback:knocked(unit)
end
function mt:knockup(unit, height, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, height, duration, model, point, stack, false, false, false, CROWD_CONTROL_KNOCKUP)
end
function mt:knockedup(unit)
return Knockup:isUnitKnocked(unit)
end
function mt:fear(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_FEAR)
end
function mt:feared(unit)
return Fear:feared(unit)
end
function mt:disarm(unit, duration, model, point, stack)
self:cast(nil, unit, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_DISARM)
end
function mt:disarmed(unit)
return GetUnitAbilityLevel(unit, DISARM_BUFF) > 0
end
function mt:taunt(source, target, duration, model, point, stack)
self:cast(source, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_TAUNT)
end
function mt:taunted(unit)
return Taunt:taunted(unit)
end
function mt:dispel(unit, type)
if buff[type] then
UnitRemoveAbility(unit, buff[type])
if timer[unit] then
PauseTimer(timer[unit][type])
DestroyTimer(timer[unit][type])
timer[unit][type] = nil
end
end
end
function mt:dispelAll(unit)
self:dispel(unit, CROWD_CONTROL_SILENCE)
self:dispel(unit, CROWD_CONTROL_STUN)
self:dispel(unit, CROWD_CONTROL_SLOW)
self:dispel(unit, CROWD_CONTROL_SLOW_ATTACK)
self:dispel(unit, CROWD_CONTROL_BANISH)
self:dispel(unit, CROWD_CONTROL_ENSNARE)
self:dispel(unit, CROWD_CONTROL_PURGE)
self:dispel(unit, CROWD_CONTROL_HEX)
self:dispel(unit, CROWD_CONTROL_SLEEP)
self:dispel(unit, CROWD_CONTROL_CYCLONE)
self:dispel(unit, CROWD_CONTROL_ENTANGLE)
self:dispel(unit, CROWD_CONTROL_DISARM)
self:dispel(unit, CROWD_CONTROL_FEAR)
self:dispel(unit, CROWD_CONTROL_TAUNT)
end
function mt:remaining(unit, type)
if not timer[unit] then
return 0
else
return TimerGetRemaining(timer[unit][type])
end
end
function mt:register(id, code)
if type(code) == "function" then
if id >= CROWD_CONTROL_SILENCE and id <= CROWD_CONTROL_KNOCKUP then
if not event[id] then event[id] = {} end
table.insert(event[id], code)
else
table.insert(trigger, code)
end
end
end
end
end
--[[
/* --------------------- DamageInterface v2.4 by Chopinski --------------------- */
Allows for easy registration of specific damage type events like on attack
damage or on spell damage, etc...
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- This constant is used to define if the system will cache
-- extra information from a Damage Event, like the unit
-- Custom value (UnitUserData), a unit Handle Id, and more
-- Additionaly you can see the Cache function below
-- to have an idea and comment the members you want cached or not
local CACHE_EXTRA = true
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
Damage = {
source = {
unit,
player,
handle,
isHero,
isMelee,
isRanged,
isStructure,
isMagicImmune,
id,
x,
y,
z
},
target = {
unit,
player,
handle,
isHero,
isMelee,
isRanged,
isStructure,
isMagicImmune,
id,
x,
y,
z
},
damagetype,
attacktype,
isSpell,
isAttack,
isEnemy,
isAlly
}
local after = {}
local before = {}
local damage = {}
local damaging = {}
local trigger = CreateTrigger()
local location = Location(0, 0)
local function GetUnitZ(unit)
MoveLocation(location, GetUnitX(unit), GetUnitY(unit))
return GetUnitFlyHeight(unit) + GetLocationZ(location)
end
local function Cache(source, target, damagetype, attacktype)
Damage.damagetype = damagetype
Damage.attacktype = attacktype
Damage.source.unit = source
Damage.target.unit = target
Damage.isAttack = damagetype == DAMAGE_TYPE_NORMAL
Damage.isSpell = attacktype == ATTACK_TYPE_NORMAL
-- You can comment the members you dont want to be cached
-- or set CACHE_EXTRA = false to not save them at all
if CACHE_EXTRA then
Damage.source.player = GetOwningPlayer(source)
Damage.target.player = GetOwningPlayer(target)
Damage.isEnemy = IsUnitEnemy(target, Damage.source.player)
Damage.isAlly = IsUnitAlly(target, Damage.source.player)
Damage.source.isMelee = IsUnitType(source, UNIT_TYPE_MELEE_ATTACKER)
Damage.source.isRanged = IsUnitType(source, UNIT_TYPE_RANGED_ATTACKER)
Damage.target.isMelee = IsUnitType(target, UNIT_TYPE_MELEE_ATTACKER)
Damage.target.isRanged = IsUnitType(target, UNIT_TYPE_RANGED_ATTACKER)
Damage.source.isHero = IsUnitType(source, UNIT_TYPE_HERO)
Damage.target.isHero = IsUnitType(target, UNIT_TYPE_HERO)
Damage.source.isStructure = IsUnitType(source, UNIT_TYPE_STRUCTURE)
Damage.target.isStructure = IsUnitType(target, UNIT_TYPE_STRUCTURE)
Damage.source.isMagicImmune = IsUnitType(source, UNIT_TYPE_MAGIC_IMMUNE)
Damage.target.isMagicImmune = IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)
Damage.source.x = GetUnitX(source)
Damage.source.y = GetUnitY(source)
Damage.source.z = GetUnitZ(source)
Damage.target.x = GetUnitX(target)
Damage.target.y = GetUnitY(target)
Damage.target.z = GetUnitZ(target)
Damage.source.id = GetUnitUserData(source)
Damage.target.id = GetUnitUserData(target)
Damage.source.handle = GetHandleId(source)
Damage.target.handle = GetHandleId(target)
end
end
onInit(function()
for i = 1, 7 do
after[i] = {}
before[i] = {}
end
TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_DAMAGING)
TriggerAddCondition(trigger, Filter(function()
if GetTriggerEventId() == EVENT_PLAYER_UNIT_DAMAGING then
Cache(GetEventDamageSource(), BlzGetEventDamageTarget(), BlzGetEventDamageType(), BlzGetEventAttackType())
if Damage.damagetype ~= DAMAGE_TYPE_UNKNOWN then
local i = GetHandleId(Damage.attacktype) + 1
local j = GetHandleId(Damage.damagetype) + 1
if before[i][1] then
for k = 1, #before[i][1] do
before[i][1][k]()
end
end
if before[1][j] then
for k = 1, #before[1][j] do
before[1][j][k]()
end
end
if before[i][j] then
for k = 1, #before[i][j] do
before[i][j][k]()
end
end
for k = 1, #damaging do
damaging[k]()
end
end
end
end))
TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_DAMAGED)
TriggerAddCondition(trigger, Filter(function()
if GetTriggerEventId() == EVENT_PLAYER_UNIT_DAMAGED then
Cache(GetEventDamageSource(), BlzGetEventDamageTarget(), BlzGetEventDamageType(), BlzGetEventAttackType())
if Damage.damagetype ~= DAMAGE_TYPE_UNKNOWN then
local i = GetHandleId(Damage.attacktype) + 1
local j = GetHandleId(Damage.damagetype) + 1
if after[i][1] then
for k = 1, #after[i][1] do
after[i][1][k]()
end
end
if after[1][j] then
if Damage.isAttack and Evasion then
if not Evasion.evade then
for k = 1, #after[1][j] do
after[1][j][k]()
end
end
else
for k = 1, #after[1][j] do
after[1][j][k]()
end
end
end
if after[i][j] then
for k = 1, #after[i][j] do
after[i][j][k]()
end
end
for k = 1, #damage do
damage[k]()
end
end
end
end))
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function RegisterDamageEvent(attacktype, damagetype, code)
if type(code) == "function" then
local i = GetHandleId(attacktype) + 1
local j = GetHandleId(damagetype) + 1
if not after[i][j] then after[i][j] = {} end
table.insert(after[i][j], code)
end
end
function RegisterAttackDamageEvent(code)
RegisterDamageEvent(nil, DAMAGE_TYPE_NORMAL, code)
end
function RegisterSpellDamageEvent(code)
RegisterDamageEvent(ATTACK_TYPE_NORMAL, nil, code)
end
function RegisterAnyDamageEvent(code)
if type(code) == "function" then
table.insert(damage, code)
end
end
function RegisterDamagingEvent(attacktype, damagetype, code)
if type(code) == "function" then
local i = GetHandleId(attacktype) + 1
local j = GetHandleId(damagetype) + 1
if not before[i][j] then before[i][j] = {} end
table.insert(before[i][j], code)
end
end
function RegisterAttackDamagingEvent(code)
RegisterDamagingEvent(nil, DAMAGE_TYPE_NORMAL, code)
end
function RegisterSpellDamagingEvent(code)
RegisterDamagingEvent(ATTACK_TYPE_NORMAL, nil, code)
end
function RegisterAnyDamagingEvent(code)
if type(code) == "function" then
table.insert(damaging, code)
end
end
end
--[[
/* ------------------------ Evasion v2.4 by Chopinski ----------------------- */
Evasion implements an easy way to register and detect a custom evasion event.
It works by monitoring custom evasion and missing values given to units,
and nulling damage when the odds given occurs.
It will only detect custom evasion, so all evasion or miss values given to a
unit must be done so using the public API provided by this system.
*Evasion requires DamageInterface. Do not use TriggerSleepAction() with Evasion.
The API:
function RegisterEvasionEvent(function YourFunction)
-> YourFunction will run when a unit evades an attack.
function GetMissingUnit takes nothing returns unit
-> Returns the unit missing the attack
function GetEvadingUnit takes nothing returns unit
-> Returns the unit evading the attack
function GetEvadedDamage takes nothing returns real
-> Returns the amount of evaded damage
function GetUnitEvasionChance takes unit u returns real
-> Returns this system amount of evasion chance given to a unit
function GetUnitMissChance takes unit u returns real
-> Returns this system amount of miss chance given to a unit
function SetUnitEvasionChance takes unit u, real chance returns nothing
-> Sets unit evasion chance to specified amount
function SetUnitMissChance takes unit u, real chance returns nothing
-> Sets unit miss chance to specified amount
function UnitAddEvasionChance takes unit u, real chance returns nothing
-> Add to a unit Evasion chance the specified amount
function UnitAddMissChance takes unit u, real chance returns nothing
-> Add to a unit Miss chance the specified amount
function MakeUnitNeverMiss takes unit u, boolean flag returns nothing
-> Will make a unit never miss attacks no matter the evasion chance of the attacked unit
function DoUnitNeverMiss takes unit u returns boolean
-> Returns true if the unit will never miss an attack
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local TEXT_SIZE = 0.016
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
Evasion = {
evasion = {},
miss = {},
neverMiss = {},
source,
target,
damage,
evade
}
local event = {}
local function Text(unit, text, duration, red, green, blue, alpha)
local texttag = CreateTextTag()
SetTextTagText(texttag, text, TEXT_SIZE)
SetTextTagPosUnit(texttag, unit, 0)
SetTextTagColor(texttag, red, green, blue, alpha)
SetTextTagLifespan(texttag, duration)
SetTextTagVelocity(texttag, 0.0, 0.0355)
SetTextTagPermanent(texttag, false)
end
onInit(function()
RegisterAttackDamagingEvent(function()
local damage = GetEventDamage()
Evasion.evade = false
if damage > 0 and not ((Evasion.neverMiss[Damage.source.unit] or 0) > 0) then
Evasion.evade = GetRandomReal(0, 100) <= (Evasion.evasion[Damage.target.unit] or 0) or GetRandomReal(0, 100) <= (Evasion.miss[Damage.source.unit] or 0)
if Evasion.evade then
Evasion.source = Damage.source
Evasion.target = Damage.target
Evasion.damage = damage
for i = 1, #event do
event[i]()
end
BlzSetEventDamage(0)
BlzSetEventWeaponType(WEAPON_TYPE_WHOKNOWS)
Text(Evasion.source.unit, "miss", 1.5, 255, 0, 0, 255)
Evasion.damage = 0
Evasion.source = nil
Evasion.target = nil
end
end
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function RegisterEvasionEvent(code)
if type(code) == "function" then
table.insert(event, code)
end
end
function GetMissingUnit()
return Evasion.source.unit
end
function GetEvadingUnit()
return Evasion.target.unit
end
function GetEvadedDamage()
return Evasion.damage or 0
end
function GetUnitEvasionChance(unit)
return Evasion.evasion[unit] or 0
end
function GetUnitMissChance(unit)
return Evasion.miss[unit] or 0
end
function SetUnitEvasionChance(unit, real)
Evasion.evasion[unit] = real
end
function SetUnitMissChance(unit, real)
Evasion.miss[unit] = real
end
function UnitAddEvasionChance(unit, real)
if not Evasion.evasion[unit] then Evasion.evasion[unit] = 0 end
Evasion.evasion[unit] = Evasion.evasion[unit] + real
end
function UnitAddMissChance(unit, real)
if not Evasion.miss[unit] then Evasion.miss[unit] = 0 end
Evasion.miss[unit] = Evasion.miss[unit] + real
end
function MakeUnitNeverMiss(unit, flag)
if not Evasion.neverMiss[unit] then Evasion.neverMiss[unit] = 0 end
if flag then
Evasion.neverMiss[unit] = Evasion.neverMiss[unit] + 1
else
Evasion.neverMiss[unit] = Evasion.neverMiss[unit] - 1
end
end
function DoUnitNeverMiss(unit)
return Evasion.neverMiss[unit] > 0
end
end
--[[
/* ------------------------ CriticalStrike v2.4 by Chopinski ----------------------- */
CriticalStrike implements an easy way to register and detect a custom critical event.
allows the manipulation of a unit critical strike chance and multiplier, as well as
manipulating the critical damage dealt.
It works by monitoring custom critical strike chance and multiplier values given to units.
It will only detect custom critical strikes, so all critical chance given to a
unit must be done so using the public API provided by this system.
*CriticalStrike requires DamageInterface. Do not use TriggerSleepAction() with Evasion.
It also requires optional Evasion so that this library is written after the Evasion
library, so both custom events will not fire at the same time.
The API:
function RegisterCriticalStrikeEvent(function YourFunction)
-> YourFunction will run when a unit hits a critical strike.
function GetCriticalSource takes nothing returns unit
-> Returns the unit hitting a critical strike.
function GetCriticalTarget takes nothing returns unit
-> Returns the unit being hit by a critical strike.
function GetCriticalDamage takes nothing returns real
-> Returns the critical strike damage amount.
function GetUnitCriticalChance takes unit u returns real
-> Returns the chance to hit a critical strike to specified unit.
function GetUnitCriticalMultiplier takes unit u returns real
-> Returns the chance to hit a critical strike to specified unit.
function SetUnitCriticalChance takes unit u, real value returns nothing
-> Set's the unit chance to hit a critical strike to specified value.
-> 15.0 = 15%
function SetUnitCriticalMultiplier takes unit u, real value returns nothing
-> Set's the unit multiplier of damage when hitting a critical to value
-> 1.0 = increases the multiplier by 1. all units have a multiplier of 1.0
by default, so by adding 1.0, for example, the critical damage will be
2x the normal damage
function SetCriticalEventDamage takes real newValue returns nothing
-> Modify the critical damage dealt to the specified value.
function UnitAddCriticalStrike takes unit u, real chance, real multiplier returns nothing
-> Adds the specified values of chance and multiplier to a unit
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local TEXT_SIZE = 0.016
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
Critical = {
source,
target,
damage,
chance = {},
multiplier = {}
}
local event = {}
local function Text(unit, text, duration, red, green, blue, alpha)
local texttag = CreateTextTag()
SetTextTagText(texttag, text, TEXT_SIZE)
SetTextTagPosUnit(texttag, unit, 0)
SetTextTagColor(texttag, red, green, blue, alpha)
SetTextTagLifespan(texttag, duration)
SetTextTagVelocity(texttag, 0.0, 0.0355)
SetTextTagPermanent(texttag, false)
end
onInit(function()
RegisterAttackDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 and GetRandomReal(0, 100) <= (Critical.chance[Damage.source.unit] or 0) and Damage.isEnemy and not Damage.target.isStructure and (Critical.multiplier[Damage.source.unit] or 0) > 0 then
Critical.source = Damage.source
Critical.target = Damage.target
Critical.damage = damage*(1 + (Critical.multiplier[Damage.source.unit] or 0))
for i = 1, #event do
event[i]()
end
BlzSetEventDamage(Critical.damage)
if Critical.damage > 0 then
Text(Critical.target.unit, (I2S(R2I(Critical.damage)) .. "!"), 1.5, 255, 0, 0, 255)
end
Critical.source = nil
Critical.target = nil
Critical.damage = 0
end
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function RegisterCriticalStrikeEvent(code)
if type(code) == "function" then
table.insert(event, code)
end
end
function GetCriticalSource()
return Critical.source.unit
end
function GetCriticalTarget()
return Critical.target.unit
end
function GetCriticalDamage()
return Critical.damage or 0
end
function GetUnitCriticalChance(unit)
return Critical.chance[unit] or 0
end
function GetUnitCriticalMultiplier(unit)
return Critical.multiplier[unit] or 0
end
function SetUnitCriticalChance(unit, real)
Critical.chance[unit] = real
end
function SetUnitCriticalMultiplier(unit, real)
Critical.multiplier[unit] = real
end
function SetCriticalEventDamage(real)
Critical.damage = real
end
function UnitAddCriticalStrike(unit, chance, multiplier)
if not Critical.chance[unit] then Critical.chance[unit] = 0 end
if not Critical.multiplier[unit] then Critical.multiplier[unit] = 0 end
Critical.chance[unit] = Critical.chance[unit] + chance
Critical.multiplier[unit] = Critical.multiplier[unit] + multiplier
end
end
--[[
/* ------------------------ SpellPower 2.4 by Chopinski ----------------------- */
SpellPower intends to simulate a system similiar to Ability Power from LoL or
Spell Amplification from Dota 2.
Whenever a units deals Spell damage, that dealt damage will be amplified by a flat
and percentile amount that represents a unit spell power bonus.
The formula for amplification is:
final damage = (initial damage + flat bonus) * (1 + percent bonus)
for percent bonus: 0.1 = 10% bonus
*SpellPower requires DamageInterface. Do not use TriggerSleepAction() within triggers.
The API:
function GetUnitSpellPowerFlat takes unit u returns real
-> Returns the Flat bonus of spell power of a unit
function GetUnitSpellPowerPercent takes unit u returns real
-> Returns the Percent bonus of spell power of a unit
function SetUnitSpellPowerFlat takes unit u, real value returns nothing
-> Set the Flat amount of Spell Power of a unit
function SetUnitSpellPowerPercent takes unit u, real value returns nothing
-> Set the Flat amount of Spell Power of a unit
function UnitAddSpellPowerFlat takes unit u, real amount returns nothing
-> Add to the Flat amount of Spell Power of a unit
function UnitAddSpellPowerPercent takes unit u, real amount returns nothing
-> Add to the Percent amount of Spell Power of a unit
function GetSpellDamage takes real amount, unit u returns real
-> Returns the amount of spell damage that would be dealt given an initial damage
]]--
do
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
SpellPower = {
flat = {},
percent = {}
}
onInit(function()
RegisterSpellDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 then
BlzSetEventDamage((damage + (SpellPower.flat[Damage.source.unit] or 0))*(1 + (SpellPower.percent[Damage.source.unit] or 0)))
end
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function GetUnitSpellPowerFlat(unit)
return SpellPower.flat[unit] or 0
end
function GetUnitSpellPowerPercent(unit)
return SpellPower.percent[unit] or 0
end
function SetUnitSpellPowerFlat(unit, real)
SpellPower.flat[unit] = real
end
function SetUnitSpellPowerPercent(unit, real)
SpellPower.percent[unit] = real
end
function UnitAddSpellPowerFlat(unit, real)
if not SpellPower.flat[unit] then SpellPower.flat[unit] = 0 end
SpellPower.flat[unit] = SpellPower.flat[unit] + real
end
function UnitAddSpellPowerPercent(unit, real)
if not SpellPower.percent[unit] then SpellPower.percent[unit] = 0 end
SpellPower.percent[unit] = SpellPower.percent[unit] + real
end
function GetSpellDamage(unit, real)
return (real + (SpellPower.flat[unit] or 0))*(1 + (SpellPower.percent[unit] or 0))
end
end
--[[
/* ------------------------ LifeSteal v2.4 by Chopinski ----------------------- */
LifeSteal intends to simulate the Life Steal system in warcraft, and allow you
to easily change the life steal amount of any unit.
Whenever a unit deals Physical damage, and it has a value of life steal given by
this system, it will heal based of this value and the damage amount.
The formula for life steal is:
heal = damage * life steal
fror life steal: 0.1 = 10%
*LifeSteal requires DamageInterface. Do not use TriggerSleepAction() within triggers.
The API:
function SetUnitLifeSteal takes unit u, real amount returns nothing
-> Set the Life Steal amount for a unit
function GetUnitLifeSteal takes unit u returns real
-> Returns the Life Steal amount of a unit
function UnitAddLifeSteal takes unit u, real amount returns nothing
-> Add to the Life Steal amount of a unit the given amount
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local effect = "Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl"
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
LifeSteal = {}
onInit(function()
RegisterAttackDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 and (LifeSteal[Damage.source.unit] or 0) > 0 and not Damage.target.isStructure then
SetWidgetLife(Damage.source.unit, (GetWidgetLife(Damage.source.unit) + (damage * (LifeSteal[Damage.source.unit] or 0))))
DestroyEffect(AddSpecialEffectTarget(effect, Damage.source.unit, "origin"))
end
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function SetUnitLifeSteal(unit, real)
LifeSteal[unit] = real
end
function GetUnitLifeSteal(unit)
return LifeSteal[unit] or 0
end
function UnitAddLifeSteal(unit, real)
if not LifeSteal[unit] then LifeSteal[unit] = 0 end
LifeSteal[unit] = LifeSteal[unit] + real
end
end
--[[
/* ------------------------ SpellVamp v2.4 by Chopinski ----------------------- */
SpellVamp intends to introduce to warcraft a healing based on Spell damage, like
in LoL or Dota 2.
Whenever a unit deals Spell damage, and it has a value of spell vamp given by
this system, it will heal based of this value and the damage amount.
The formula for spell vamp is:
heal = damage * lspell vamp
fror spell vamp: 0.1 = 10%
*SpellVamp requires DamageInterface. Do not use TriggerSleepAction() within triggers.
The API:
function SetUnitSpellVamp takes unit u, real amount returns nothing
-> Set the Spell Vamp amount for a unit
function GetUnitSpellVamp takes unit u returns real
-> Returns the Spell Vamp amount of a unit
function UnitAddSpellVamp takes unit u, real amount returns nothing
-> Add to the Spell Vamp amount of a unit the given amount
]]--
do
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
SpellVamp = {}
onInit(function()
RegisterSpellDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 and (SpellVamp[Damage.source.unit] or 0) > 0 and not Damage.target.isStructure then
SetWidgetLife(Damage.source.unit, (GetWidgetLife(Damage.source.unit) + (damage * (SpellVamp[Damage.source.unit] or 0))))
end
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function SetUnitSpellVamp(unit, real)
SpellVamp[unit] = real
end
function GetUnitSpellVamp(unit)
return SpellVamp[unit] or 0
end
function UnitAddSpellVamp(unit, real)
if not SpellVamp[unit] then SpellVamp[unit] = 0 end
SpellVamp[unit] = SpellVamp[unit] + real
end
end
--[[
/* ------- Utility Library for all the Damage Interface Custom Events ------- */
/* ---------------------------- v2.4 by Chopinski --------------------------- */
The API:
Evasion System:
function UnitAddEvasionChanceTimed takes unit u, real amount, real duration returns nothing
-> Add to a unit Evasion chance the specified amount for a given period
function UnitAddMissChanceTimed takes unit u, real amount, real duration returns nothing
-> Add to a unit Miss chance the specified amount for a given period
Critical Strike System:
function UnitAddCriticalStrikeTimed takes unit u, real chance, real multiplier, real duration returns nothing
-> Adds the specified values of chance and multiplier to a unit for a given period
function UnitAddCriticalChanceTimed takes unit u, real chance, real duration returns nothing
-> Adds the specified values of critical chance to a unit for a given period
function UnitAddCriticalMultiplierTimed takes unit u, real multiplier, real duration returns nothing
-> Adds the specified values of critical multiplier to a unit for a given period
Spell Power System:
function UnitAddSpellPowerFlatTimed takes unit u, real amount, real duration returns nothing
-> Add to the Flat amount of Spell Power of a unit for a given period
function UnitAddSpellPowerPercentTimed takes unit u, real amount, real duration returns nothing
-> Add to the Percent amount of Spell Power of a unit for a given period
function AbilitySpellDamage takes unit u, integer abilityId, abilityreallevelfield field returns string
-> Given an ability field, will return a string that represents the damage that would be dealt
taking into consideration the spell power bonusses of a unit.
function AbilitySpellDamageEx takes real amount, unit u returns string
-> Similar to GetSpellDamage will return the damage that would be dealt but as a string
Life Steal System:
function UnitAddLifeStealTimed takes unit u, real amount, real duration returns nothing
-> Add to the Life Steal amount of a unit the given amount for a given period
Spell Vamp System:
function UnitAddSpellVampTimed takes unit u, real amount, real duration returns nothing
-> Add to the Spell Vamp amount of a unit the given amount for a given period
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local PERIOD = 0.03125000
-- -------------------------------------------------------------------------- --
-- Evasion Utils --
-- -------------------------------------------------------------------------- --
do
EvasionUtils = setmetatable({}, {})
local mt = getmetatable(EvasionUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
if self.type then
UnitAddEvasionChance(self.unit, -self.amount)
else
UnitAddMissChance(self.unit, -self.amount)
end
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, amount, duration, type)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.amount = amount
this.ticks = duration/PERIOD
this.type = type
key = key + 1
array[key] = this
if type then
UnitAddEvasionChance(unit, amount)
else
UnitAddMissChance(unit, amount)
end
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
end
-- -------------------------------------------------------------------------- --
-- Critical Strike Utils --
-- -------------------------------------------------------------------------- --
do
CriticalUtils = setmetatable({}, {})
local mt = getmetatable(CriticalUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
UnitAddCriticalStrike(self.unit, -self.chance, -self.multiplier)
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, chance, multiplier, duration, type)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.chance = chance
this.multiplier = multiplier
this.ticks = duration/PERIOD
key = key + 1
array[key] = this
UnitAddCriticalStrike(unit, chance, multiplier)
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
end
-- -------------------------------------------------------------------------- --
-- Spell Power Utils --
-- -------------------------------------------------------------------------- --
do
SpellPowerUtils = setmetatable({}, {})
local mt = getmetatable(SpellPowerUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
if self.type then
UnitAddSpellPowerFlat(self.unit, -self.amount)
else
UnitAddSpellPowerPercent(self.unit, -self.amount)
end
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, amount, duration, type)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.amount = amount
this.ticks = duration/PERIOD
this.type = type
key = key + 1
array[key] = this
if type then
UnitAddSpellPowerFlat(unit, amount)
else
UnitAddSpellPowerPercent(unit, amount)
end
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
end
-- -------------------------------------------------------------------------- --
-- Life Steal Utils --
-- -------------------------------------------------------------------------- --
do
LifeStealUtils = setmetatable({}, {})
local mt = getmetatable(LifeStealUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
UnitAddLifeSteal(self.unit, -self.amount)
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, amount, duration)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.amount = amount
this.ticks = duration/PERIOD
key = key + 1
array[key] = this
UnitAddLifeSteal(unit, amount)
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
end
-- -------------------------------------------------------------------------- --
-- Spell Vamp Utils --
-- -------------------------------------------------------------------------- --
SpellVampUtils = setmetatable({}, {})
local mt = getmetatable(SpellVampUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
UnitAddSpellVamp(self.unit, -self.amount)
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, amount, duration)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.amount = amount
this.ticks = duration/PERIOD
key = key + 1
array[key] = this
UnitAddSpellVamp(unit, amount)
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function UnitAddEvasionChanceTimed(unit, amount, duration)
EvasionUtils:addTimed(unit, amount, duration, true)
end
function UnitAddMissChanceTimed(unit, amount, duration)
EvasionUtils:addTimed(unit, amount, duration, false)
end
function UnitAddCriticalStrikeTimed(unit, chance, multiplier, duration)
CriticalUtils:addTimed(unit, chance, multiplier, duration, 0)
end
function UnitAddCriticalChanceTimed(unit, chance, duration)
CriticalUtils:addTimed(unit, chance, 0, duration, 1)
end
function UnitAddCriticalMultiplierTimed(unit, multiplier, duration)
CriticalUtils:addTimed(unit, 0, multiplier, duration, 2)
end
function UnitAddSpellPowerFlatTimed(unit, amount, duration)
SpellPowerUtils:addTimed(unit, amount, duration, true)
end
function UnitAddSpellPowerPercentTimed(unit, amount, duration)
SpellPowerUtils:addTimed(unit, amount, duration, false)
end
function AbilitySpellDamage(unit, ability, field)
return I2S(R2I((BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ability), field, GetUnitAbilityLevel(unit, ability) - 1) + (SpellPower.flat[unit] or 0)) * (1 + (SpellPower.percent[unit] or 0))))
end
function AbilitySpellDamageEx(real, unit)
return I2S(R2I((real + (SpellPower.flat[unit] or 0)) * (1 + (SpellPower.percent[unit] or 0))))
end
function UnitAddLifeStealTimed(unit, amount, duration)
LifeStealUtils:addTimed(unit, amount, duration)
end
function UnitAddSpellVampTimed(unit, amount, duration)
SpellVampUtils:addTimed(unit, amount, duration)
end
end
--[[ requires RegisterPlayerUnitEvent, Indexer
/* ------------------ Cooldown Reduction v1.9 by Chopinski ------------------ */
Intro
This library intension in to introduce to warcraft an easy way to
manipulate abilities cooldowns based on a cooldown reduction value that
is unique for each unit.
How it Works?
When casting an ability, its "new" cooldown is calculated based on the
amount of cooldown reduction of the casting unit. the formula for
calculation is:
Cooldown = (Default Cooldown - Cooldown Offset) * [(1 - source1)*(1 - source2)*...] * (1 - Cooldown Reduction Flat)
The system also allow negative values for CDR, resulting in increased
ability cooldown.
It does not acumulate because the abilities are registered automatically
on the first cast, saving its base cooldown (Object Editor values) and
always using this base value for calculation, so you can still edit
the ability via the editor and the system takes care of the rest.
How to Import
simply copy the CooldownReduction folder over to your map, and start
use the API functions
Requirements
CooldownReduction requires RegisterPlayerUnitEvent.
Credits to Magtheridon96 for RegisterPlayerUnitEvent.
It also requires patch 1.31+.
RegisterPlayerUnitEvent: www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
]]--
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- Use this function to filter out units you dont want to have abilities registered.
-- By default dummy units do not trigger the system.
local function UnitFilter(unit)
return GetUnitAbilityLevel(unit, FourCC('Aloc')) == 0
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local units = {}
local abilities = {}
local defaults = {}
local set = {}
CDR = setmetatable({}, {})
local mt = getmetatable(CDR)
mt.__index = mt
function mt:update(unit)
local real
for i = 1, #abilities[unit] do
local k = abilities[unit][i]
local ability = BlzGetUnitAbility(unit, k)
local level = BlzGetAbilityIntegerField(ability, ABILITY_IF_LEVELS)
for j = 1, level do
if (units[unit].count or 0) > 0 then
real = ((defaults[k][j] - units[unit].offset) * units[unit].cooldown * (1 - units[unit].flat))
else
real = ((defaults[k][j] - units[unit].offset) * (1 - units[unit].flat))
end
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_COOLDOWN, j-1, real)
IncUnitAbilityLevel(unit, k)
DecUnitAbilityLevel(unit, k)
end
end
end
function mt:set(unit, real, type)
if not units[unit] then self:create(unit) end
if type == 0 then
units[unit].cooldown = real
elseif type == 1 then
units[unit].flat = real
else
units[unit].offset = real
end
self:update(unit)
end
function mt:get(unit, type)
if not units[unit] then self:create(unit) end
if type == 0 then
return units[unit].cooldown or 0
elseif type == 1 then
return units[unit].flat or 0
else
return units[unit].offset or 0
end
end
function mt:calculate(unit)
local real = 0
if (#units[unit].cdr or 0) > 0 then
for i = 1, #units[unit].cdr do
if i > 1 then
real = real * (1 - units[unit].cdr[i])
else
real = 1 - units[unit].cdr[i]
end
end
end
return real
end
function mt:calculateCooldown(unit, id, level, cooldown)
if not units[unit] then
self:create(unit)
else
local ability = BlzGetUnitAbility(unit, id)
local real
if (#units[unit].cdr or 0) > 0 then
real = ((cooldown - units[unit].offset) * units[unit].cooldown * (1 - units[unit].flat))
else
real = ((cooldown - units[unit].offset) * (1 - units[unit].flat))
end
BlzSetAbilityRealLevelField(ability, ABILITY_RLF_COOLDOWN, level-1, real)
IncUnitAbilityLevel(unit, id)
DecUnitAbilityLevel(unit, id)
end
end
function mt:simulateCooldown(unit, cooldown)
if not units[unit] then
self:create(unit)
return cooldown
else
local real
if (#units[unit].cdr or 0) > 0 then
real = ((cooldown - units[unit].offset) * units[unit].cooldown * (1 - units[unit].flat))
else
real = ((cooldown - units[unit].offset) * (1 - units[unit].flat))
end
return real
end
end
function mt:add(unit, real, type)
if real ~= 0 then
if not units[unit] then self:create(unit) end
if type == 0 then
table.insert(units[unit].cdr, real)
units[unit].count = units[unit].count + 1
units[unit].cooldown = self:calculate(unit)
elseif type == 1 then
units[unit].flat = units[unit].flat + real
else
units[unit].offset = units[unit].offset + real
end
self:update(unit)
end
end
function mt:remove(unit, real)
if real ~= 0 then
if not units[unit] then
self:create(unit)
return
end
for j = 1, #units[unit].cdr do
if units[unit].cdr[j] == real then
table.remove(units[unit].cdr, j)
units[unit].count = units[unit].count - 1
units[unit].cooldown = self:calculate(unit)
break
end
end
self:update(unit)
end
end
function mt:create(unit)
abilities[unit] = {}
set[unit] = {}
units[unit] = {}
units[unit].cdr = {}
units[unit].cooldown = 0
units[unit].offset = 0
units[unit].flat = 0
units[unit].count = 0
end
function mt:destroy(unit)
if abilities[unit] then
for i = 1, #abilities[unit] do
defaults[abilities[unit][i]] = nil
end
end
abilities[unit] = nil
set[unit] = nil
units[unit] = nil
units[unit].cdr = nil
units[unit].cooldown = nil
units[unit].offset = nil
units[unit].flat = nil
units[unit].count = nil
end
function mt:register(unit, id)
if UnitFilter(unit) then
if not units[unit] then self:create(unit) end
if not set[unit][id] then
set[unit][id] = true
table.insert(abilities[unit], id)
if not defaults[id] then defaults[id] = {} end
local ability = BlzGetUnitAbility(unit, id)
local levels = BlzGetAbilityIntegerField(ability, ABILITY_IF_LEVELS)
for i = 1, levels do
defaults[id][i] = BlzGetAbilityRealLevelField(ability, ABILITY_RLF_COOLDOWN, i - 1)
end
if (units[unit].count or 0) > 0 or units[unit].cooldown or units[unit].offset or units[unit].flat then
self:update(unit)
end
end
end
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function()
CDR:register(GetTriggerUnit(), GetSpellAbilityId())
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function()
CDR:register(GetTriggerUnit(), GetLearnedSkill())
end)
RegisterUnitDeindexEvent(function()
CDR:destroy(GetIndexUnit())
end)
end)
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function GetUnitCooldownReduction(unit)
return 1 - CDR:get(unit, 0)
end
function GetUnitCooldownReductionFlat(unit)
return CDR:get(unit, 1)
end
function GetUnitCooldownOffset(unit)
return CDR:get(unit, 2)
end
function SetUnitCooldownReduction(unit, real)
CDR:set(unit, real, 0)
end
function SetUnitCooldownReductionFlat(unit, real)
CDR:set(unit, real, 1)
end
function SetUnitCooldownOffset(unit, real)
CDR:set(unit, real, 2)
end
function UnitAddCooldownReduction(unit, real)
CDR:add(unit, real, 0)
end
function UnitAddCooldownReductionFlat(unit, real)
CDR:add(unit, real, 1)
end
function UnitAddCooldownOffset(unit, real)
CDR:add(unit, real, 2)
end
function UnitRemoveCooldownReduction(unit, real)
CDR:remove(unit, real)
end
function CalculateAbilityCooldown(unit, ability, level, cooldown)
CDR:calculateCooldown(unit, ability, level, cooldown)
end
function SimulateAbilityCooldown(unit, cooldown)
return CDR:simulateCooldown(unit, cooldown)
end
function RegisterAbility(unit, ability)
CDR:register(unit, ability)
end
function GetAbilityTable()
return units
end
end
--[[
/* --------------- Cooldown Reduction Utils v1.9 by Chopinski --------------- */
Intro
Utility Library that include a few extra functions to deal with
Cooldown Reduction
The API
function UnitAddCooldownReductionTimed takes unit u, real value, real duration returns nothing
-> Add to the amount of cdr of a unit for a given duration. Accepts positive and negative values.
-> It handles removing the bonus automatically
function UnitAddCooldownReductionFlatTimed takes unit u, real value, real duration returns nothing
-> Add to the amount of cdr flat of a unit for a given period. Accepts positive and negative values.
-> It handles removing the bonus automatically
function UnitAddCooldownOffsetTimed takes unit u, real value, real duration returns nothing
-> Add to the amount of cdr offset of a unit for a given period. Accepts positive and negative values.
-> It handles removing the bonus automatically
function GetUnitCooldownReductionEx takes unit u returns string
-> Returns the amount of cdr a unit has as a string factored by 100
-> example of return: 10.50 -> 0.105 internally.
function GetUnitCooldownReductionFlatEx takes unit u returns string
-> Returns the amount of cdr flat a unit has as a string factored by 100
-> example of return: 10.50 -> 0.105 internally.
function GetUnitCooldownOffsetEx takes unit u returns string
-> Returns the amount of cdr offset a unit has as a string
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
local PERIOD = 0.03125000
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
CDRUtils = setmetatable({}, {})
local mt = getmetatable(CDRUtils)
mt.__index = mt
local array = {}
local key = 0
local timer = CreateTimer()
function mt:remove(i)
if self.type == 0 then
UnitRemoveCooldownReduction(self.unit, self.value)
elseif self.type == 1 then
UnitAddCooldownReductionFlat(self.unit, -self.value)
else
UnitAddCooldownOffset(self.unit, -self.value)
end
array[i] = array[key]
key = key - 1
self = nil
if key == 0 then
PauseTimer(timer)
end
return i - 1
end
function mt:addTimed(unit, value, duration, type)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.value = value
this.type = type
this.ticks = duration/PERIOD
key = key + 1
array[key] = this
if type == 0 then
UnitAddCooldownReduction(unit, value)
elseif type == 1 then
UnitAddCooldownReductionFlat(unit, value)
else
UnitAddCooldownOffset(unit, value)
end
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if this.ticks <= 0 then
i = this:remove(i)
end
this.ticks = this.ticks - 1
i = i + 1
end
end)
end
end
-- -------------------------------------------------------------------------- --
-- LUA API --
-- -------------------------------------------------------------------------- --
function UnitAddCooldownReductionTimed(unit, value, duration)
CDRUtils:addTimed(unit, value, duration, 0)
end
function UnitAddCooldownReductionFlatTimed(unit, value, duration)
CDRUtils:addTimed(unit, value, duration, 1)
end
function UnitAddCooldownOffsetTimed(unit, value, duration)
CDRUtils:addTimed(unit, value, duration, 2)
end
function GetUnitCooldownReductionEx(unit)
return R2SW(CDR:get(unit, 0)*100, 1, 2)
end
function GetUnitCooldownReductionFlatEx(unit)
return R2SW(CDR:get(unit, 1)*100, 1, 2)
end
function GetUnitCooldownOffsetEx(unit)
return R2SW(CDR:get(u, 2), 1, 2)
end
end
--[[ requires SpellEffectEvent, PluginSpellEffect, NewBonus, Indexer
/* -------------------- Water Elemental v1.1 by Chopinski ------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the ability
local ABILITY = FourCC('A000')
-- The raw code of the Water Elemental unit
WaterElemental_ELEMENTAL = FourCC('h001')
-- The summon effect
local MODEL = "WaterBurst.mdl"
-- The summon effect scale
local SCALE = 1
-- The unit damage
local function GetDamage(unit, level)
return 30 + R2I((BlzGetUnitBaseDamage(unit, 0) + GetUnitBonus(unit, BONUS_DAMAGE))*0.3)
end
-- The unit health
local function GetHealth(unit, level)
return 600 + R2I(BlzGetUnitMaxHP(unit)*0.4)
end
-- The unit armor
local function GetArmor(unit, level)
return 1. + GetUnitBonus(unit, BONUS_ARMOR)
end
-- The unit duration
local function GetDuration(unit, level)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
Elemental = setmetatable({}, {})
local mt = getmetatable(Elemental)
mt.__index = mt
local struct = {}
function mt:destroy()
for i = 0, self.size - 1 do
struct[BlzGroupUnitAt(self.group, i)] = nil
end
DestroyGroup(self.group)
self = nil
end
function mt:command(target, x, y, order)
if target == nil then
if order == "stop" or order == "holdposition" then
GroupImmediateOrder(self.group, order)
elseif order == "attackground" or order == "smart" or order == "move" or order == "attack" then
for i = 0, self.size - 1 do
IssuePointOrder(BlzGroupUnitAt(self.group, i), order, x + 300*Cos(i*2*bj_PI/self.size), y + 300*Sin(i*2*bj_PI/self.size))
end
end
else
if order == "smart" or order == "move" or order == "attack" then
GroupTargetOrder(self.group, order, target)
end
end
end
function mt:add(unit)
struct[unit] = self
GroupAddUnit(self.group, unit)
self.size = BlzGroupGetSize(self.group)
end
function mt:owner(unit)
if struct[unit] then
local this = struct[unit]
return this.unit
else
return nil
end
end
function mt:onOrder()
local unit = GetOrderedUnit()
if GetUnitTypeId(unit) == WaterElemental_ELEMENTAL then
if struct[unit] then
local this = struct[unit]
if GetOrderTargetUnit() == this.unit then
if not IsUnitInGroup(unit, this.group) then
GroupAddUnit(this.group, unit)
this.size = BlzGroupGetSize(this.group)
end
else
if IsUnitSelected(unit, GetOwningPlayer(unit)) and IsUnitInGroup(unit, this.group) then
GroupRemoveUnit(this.group, unit)
this.size = BlzGroupGetSize(this.group)
end
end
end
end
end
function mt:create(unit)
local this = {}
setmetatable(this, mt)
this.unit = unit
this.group = CreateGroup()
this.size = BlzGroupGetSize(this.group)
return this
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function()
local unit = GetTriggerUnit()
if GetUnitTypeId(unit) == WaterElemental_ELEMENTAL then
if struct[unit] then
local this = struct[unit]
GroupRemoveUnit(this.group, unit)
this.size = BlzGroupGetSize(this.group)
struct[unit] = nil
end
end
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function()
Elemental:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function()
Elemental:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function()
Elemental:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function()
Elemental:onOrder()
end)
end)
end
do
local Masters = setmetatable({}, {})
local mt = getmetatable(Masters)
mt.__index = mt
local struct = {}
function mt:destroy()
self.elementals:destroy()
self = nil
end
function mt:onOrder()
local unit = GetOrderedUnit()
if GetUnitAbilityLevel(unit, ABILITY) > 0 and struct[unit] then
local this = struct[unit]
this.elementals:command(GetOrderTargetUnit(), GetOrderPointX(), GetOrderPointY(), OrderId2String(GetIssuedOrderId()))
end
end
onInit(function()
RegisterSpellEffectEvent(ABILITY, function()
local angle = GetUnitFacing(Spell.source.unit)
local unit = CreateUnit(Spell.source.player, WaterElemental_ELEMENTAL, Spell.source.x + 250*Cos(Deg2Rad(angle)), Spell.source.y + 250*Sin(Deg2Rad(angle)), angle)
local this
DestroyEffect(AddSpecialEffectEx(MODEL, GetUnitX(unit), GetUnitY(unit), 0, SCALE))
if struct[Spell.source.unit] then
this = struct[Spell.source.unit]
else
this = {}
setmetatable(this, Masters)
struct[Spell.source.unit] = this
this.elementals = Elemental:create(Spell.source.unit)
end
BlzSetUnitBaseDamage(unit, GetDamage(Spell.source.unit, Spell.level), 0)
BlzSetUnitMaxHP(unit, GetHealth(Spell.source.unit, Spell.level))
SetUnitLifePercentBJ(unit, 100)
BlzSetUnitArmor(unit, GetArmor(Spell.source.unit, Spell.level))
SetUnitAnimation(unit, "Birth")
UnitApplyTimedLife(unit, FourCC('BTLF'), GetDuration(Spell.source.unit, Spell.level))
this.elementals:add(unit)
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function()
Masters:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function()
Masters:onOrder()
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function()
Masters:onOrder()
end)
RegisterUnitDeindexEvent(function()
local unit = GetIndexUnit()
if struct[unit] then
local this = struct[unit]
this:destroy()
struct[unit] = nil
end
end)
end)
end
end
--[[ requires SpellEffectEvent, PluginSpellEffect, Missiles, Utilities, CrowdControl optional WaterElemental
/* --------------------- Crushing Wave v1.1 by Chopinski -------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the ability
local ABILITY = FourCC('A001')
-- The Wave model
local MODEL = "LivingTide.mdl"
-- The Wave speed
local SPEED = 1250
-- The wave model scale
local SCALE = 0.8
-- The wave damage
local function GetDamage(unit, level)
return 50. + 50.*level
end
-- The Wave collision
local function GetCollision(unit, level)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_RLF_AREA_OF_EFFECT, level - 1)
end
-- The water elemental search range
local function GetAoE(unit, level)
return 1000. + 0.*level
end
-- The wave travel distance
local function GetTravelDistance(unit, level)
return 1000. + 0.*level
end
-- The Wave slow amount
local function GetSlowAmount(unit, level)
return 0.1 + 0.1*level
end
-- The Slow duration
local function GetSlowDuration(unit, level)
return 1. + 0.25*level
end
-- The damae filter
local function UnitFilter(player, target)
return UnitAlive(target) and IsUnitEnemy(target, player) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local function launch(x, y, z, tx, ty, tz, source, player, level, elemental)
local this = Missiles:create(x, y, z, tx, ty, tz)
this:model(MODEL)
this:scale(SCALE)
this:speed(SPEED)
this.source = source
this.owner = player
this.unit = elemental
this.damage = GetDamage(source, level)
this.collision = GetCollision(source, level)
this.slow = GetSlowAmount(source, level)
this.timeout = GetSlowDuration(source, level)
if elemental then
BlzSetUnitFacingEx(elemental, AngleBetweenCoordinates(x, y, tx, ty)*bj_RADTODEG)
PauseUnit(elemental, true)
SetUnitAnimationByIndex(elemental, 8)
SetUnitInvulnerable(elemental, true)
end
this.onPeriod = function()
if this.unit then
SetUnitX(this.unit, this.x)
SetUnitY(this.unit, this.y)
end
return false
end
this.onHit = function(unit)
if UnitFilter(this.owner, unit) then
if UnitDamageTarget(this.source, unit, this.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, nil) then
SlowUnit(unit, this.slow, this.timeout, nil, nil, false)
end
end
return false
end
this.onRemove = function()
if this.unit then
PauseUnit(this.unit, false)
SetUnitAnimation(this.unit, "Stand")
SetUnitInvulnerable(this.unit, false)
end
end
this:launch()
end
onInit(function()
RegisterSpellEffectEvent(ABILITY, function()
local angle = AngleBetweenCoordinates(Spell.source.x, Spell.source.y, Spell.x, Spell.y)
local offset = GetTravelDistance(Spell.source.unit, Spell.level)
launch(Spell.source.x, Spell.source.y, 0, Spell.source.x + offset*Cos(angle), Spell.source.y + offset*Sin(angle), 0, Spell.source.unit, Spell.source.player, Spell.level, nil)
if Elemental then
local group = CreateGroup()
GroupEnumUnitsInRange(group, Spell.source.x, Spell.source.y, GetAoE(Spell.source.unit, Spell.level), nil)
for i = 0, BlzGroupGetSize(group) - 1 do
local unit = BlzGroupUnitAt(group, i)
if UnitAlive(unit) and GetUnitTypeId(unit) == WaterElemental_ELEMENTAL then
if Elemental:owner(unit) == Spell.source.unit then
launch(GetUnitX(unit), GetUnitY(unit), 0, Spell.x, Spell.y, 0, Spell.source.unit, Spell.source.player, Spell.level, unit)
end
end
end
DestroyGroup(group)
end
end)
end)
end
end
--[[requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, DamageInterface, Missiles, Utilities, TimerUtils
/* --------------------- Water Shield v1.1 by Chopinski --------------------- */
-- Credits:
-- Darkfang - Icon
-- Bribe - SpellEffectEvent
-- Vexorian - TimerUtils
-- Magtheridon96 - RegisterPlayerUnitEvent
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the ability
local ABILITY = FourCC('A002')
-- The shield model
local MODEL = "WaterShield.mdl"
-- The shield attachement point
local ATTACH = "origin"
-- The explosion model
local EXPLOSION_MODEL = "LivingTide.mdl"
-- The scale of the explosion model
local EXPLOSION_SCALE = 0.6
-- The water bolt model
local BOLT_MODEL = "Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl"
-- The water bolt scal
local BOLT_SCALE = 1.
-- The water bolt speed
local BOLT_SPEED = 1000.
-- The shield amount
local function GetAmount(unit, level)
return 100.*level + (0.5 + 0.5*level)*GetHeroInt(unit, true)
end
-- The water bolt damage
local function GetBoltDamage(unit, level)
return 25. + 25.*level
end
-- The range at which units can be selected by water bolt
local function GetAoE(unit, level)
return 400. + 0.*level
end
-- The aoe of the explosion when there is a remaining shield amount
local function GetExplosionAoE(unit, level)
return 400. + 0.*level
end
-- The angle in degrees at which units can be selected
local function GetAngle(unit, level)
return 90. + 0.*level
end
-- The Shield duration
local function GetDuration(unit, level)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
end
-- The unit filter
local function UnitFilter(player, target)
return IsUnitEnemy(target, player) and UnitAlive(target) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local WaterShield = setmetatable({}, {})
local mt = getmetatable(WaterShield)
mt.__index = mt
local offense = {}
local defense = {}
local effect = {}
function mt:allocate()
local this = {}
setmetatable(this, mt)
return this
end
function mt:destroy()
if self.defensive then
defense[self.target] = nil
if offense[self.target] == nil then
DestroyEffect(effect[self.target])
effect[self.target] = nil
end
else
offense[self.target] = nil
if defense[self.target] == nil then
DestroyEffect(effect[self.target])
effect[self.target] = nil
end
end
DestroyGroup(self.group)
PauseTimer(self.timer)
DestroyTimer(self.timer)
self = nil
end
function mt:onExpire()
if self.defensive and self.amount > 0 then
GroupEnumUnitsInRange(self.group, GetUnitX(self.target), GetUnitY(self.target), self.aoe, nil)
for i = 0, BlzGroupGetSize(self.group) - 1 do
local unit = BlzGroupUnitAt(self.group, i)
if UnitFilter(self.player, unit) then
UnitDamageTarget(self.source, unit, self.amount, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, nil)
end
end
DestroyEffect(AddSpecialEffectEx(EXPLOSION_MODEL, GetUnitX(self.target), GetUnitY(self.target), 0, EXPLOSION_SCALE))
end
self:destroy()
end
onInit(function()
RegisterSpellEffectEvent(ABILITY, function()
local this
if effect[Spell.target.unit] == nil then
effect[Spell.target.unit] = AddSpecialEffectTarget(MODEL, Spell.target.unit, ATTACH)
end
if IsUnitEnemy(Spell.target.unit, Spell.source.player) then
if offense[Spell.target.unit] then
this = offense[Spell.target.unit]
else
this = WaterShield:allocate()
this.timer = CreateTimer()
this.target = Spell.target.unit
this.group = CreateGroup()
this.defensive = false
offense[this.target] = this
end
this.source = Spell.source.unit
this.player = Spell.source.player
this.level = Spell.level
this.amount = GetBoltDamage(this.source, this.level)
this.angle = GetAngle(this.source, this.level)
this.aoe = GetAoE(this.source, this.level)
else
if defense[Spell.target.unit] then
this = defense[Spell.target.unit]
else
this = WaterShield:allocate()
this.timer = CreateTimer()
this.target = Spell.target.unit
this.group = CreateGroup()
this.defensive = true
defense[this.target] = this
end
this.source = Spell.source.unit
this.player = Spell.source.player
this.level = Spell.level
this.amount = (this.amount or 0) + GetAmount(this.source, this.level)
this.aoe = GetExplosionAoE(this.source, this.level)
end
TimerStart(this.timer, GetDuration(this.source, this.level), false, function() this:onExpire() end)
end)
RegisterAnyDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 and defense[Damage.target.unit] then
local this = defense[Damage.target.unit]
if damage <= this.amount then
this.amount = this.amount - damage
BlzSetEventDamage(0)
else
damage = damage - this.amount
this.amount = 0
BlzSetEventDamage(damage)
this:destroy()
end
end
end)
RegisterAttackDamageEvent(function()
if Damage.isEnemy and offense[Damage.target.unit] then
local this = offense[Damage.target.unit]
GroupEnumUnitsInRange(this.group, Damage.target.x, Damage.target.y, this.aoe, nil)
GroupRemoveUnit(this.group, Damage.target.unit)
for i = 0, BlzGroupGetSize(this.group) - 1 do
local unit = BlzGroupUnitAt(this.group, i)
if UnitFilter(this.player, unit) and IsUnitInCone(unit, Damage.target.x, Damage.target.y, this.aoe, AngleBetweenCoordinates(Damage.source.x, Damage.source.y, Damage.target.x, Damage.target.y)*bj_RADTODEG, this.angle) then
local bolt = Missiles:create(Damage.target.x, Damage.target.y, 50, GetUnitX(unit), GetUnitY(unit), 50)
bolt:model(BOLT_MODEL)
bolt:speed(BOLT_SPEED)
bolt:scale(BOLT_SCALE)
bolt.source = this.source
bolt.target = unit
bolt.damage = this.amount
bolt.onFinish = function()
if UnitAlive(bolt.target) then
UnitDamageTarget(bolt.source, bolt.target, bolt.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, nil)
end
return true
end
bolt:launch()
end
end
end
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function()
local unit = GetTriggerUnit()
if offense[unit] then
local this = offense[unit]
this:destroy()
end
if defense[unit] then
local this = defense[unit]
this:destroy()
end
end)
end)
end
end
--[[ requires RegisterPlayerUnitEvent, TimerUtils
/* -------------------- Brilliance Aure v1.1 by Chopinski ------------------- */
// Credits
// Vexorian - TimerUtils
// Magtheridon96 - RegisterPlayerUnitEvent
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the ability
local ABILITY = FourCC('A003')
-- If true the bonus regen will stack with each cast
local STACK = false
-- The bonus mana regen when an ability is cast
local function GetBonusManaRegen(unit, level)
return 1.5 * level
end
-- The duration of the bonus regen
local function GetDuration(unit, level)
return 2.5 * level
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local BrillianceAura = setmetatable({}, {})
local mt = getmetatable(BrillianceAura)
mt.__index = mt
local struct = {}
function mt:allocate()
local this = {}
setmetatable(this, mt)
return this
end
function mt:onExpire()
for i = 0, self.levels - 1 do
BlzSetAbilityRealLevelField(self.ability, self.field, i, BlzGetAbilityRealLevelField(self.ability, self.field, i) - self.bonus)
IncUnitAbilityLevel(self.unit, ABILITY)
DecUnitAbilityLevel(self.unit, ABILITY)
end
PauseTimer(self.timer)
DestroyTimer(self.timer)
struct[self.unit] = nil
self = nil
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function()
local unit = GetTriggerUnit()
local level = GetUnitAbilityLevel(unit, ABILITY)
local this
if level > 0 then
if STACK then
this = BrillianceAura:allocate()
this.timer = CreateTimer()
this.unit = unit
this.field = ABILITY_RLF_MANA_REGENERATION_INCREASE
this.ability = BlzGetUnitAbility(unit, ABILITY)
this.levels = BlzGetAbilityIntegerField(this.ability, ABILITY_IF_LEVELS)
this.bonus = GetBonusManaRegen(unit, level)
for i = 0, this.levels - 1 do
BlzSetAbilityRealLevelField(this.ability, this.field, i, BlzGetAbilityRealLevelField(this.ability, this.field, i) + this.bonus)
IncUnitAbilityLevel(unit, ABILITY)
DecUnitAbilityLevel(unit, ABILITY)
end
else
if struct[unit] then
this = struct[unit]
else
this = BrillianceAura:allocate()
this.timer = CreateTimer()
this.unit = unit
this.field = ABILITY_RLF_MANA_REGENERATION_INCREASE
this.ability = BlzGetUnitAbility(unit, ABILITY)
this.levels = BlzGetAbilityIntegerField(this.ability, ABILITY_IF_LEVELS)
this.bonus = 0
struct[unit] = this
end
if this.bonus == 0 then
this.bonus = GetBonusManaRegen(unit, level)
for i = 0, this.levels - 1 do
BlzSetAbilityRealLevelField(this.ability, this.field, i, BlzGetAbilityRealLevelField(this.ability, this.field, i) + this.bonus)
IncUnitAbilityLevel(unit, ABILITY)
DecUnitAbilityLevel(unit, ABILITY)
end
end
end
TimerStart(this.timer, GetDuration(unit, level), false, function() this:onExpire() end)
end
end)
end)
end
end
--[[ requires RegisterPlayerUnitEvent, Utilities, NewBonus, DamageInterface
/* ----------------------- Water Orb v1.0 by Chopinski ---------------------- */
// Credits:
// Darkfang - Icon
// Magtheridon96 - RegisterPlayerUnitEvent
// General Frank - Model
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the level 1 buff
local BUFF_1 = FourCC('B002')
-- The raw code of the level 2 buff
local BUFF_2 = FourCC('B003')
-- The raw code of the level 3 buff
local BUFF_3 = FourCC('B004')
-- The raw code of the level 4 buff
local BUFF_4 = FourCC('B005')
-- The orb model
local MODEL = "OrbWaterX.mdl"
-- The orb model scale
local SCALE = 1.
-- The pickup effect model
local EFFECT = "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"
-- The pickup effect model attach point
local ATTACH = "origin"
-- The update period
local PERIOD = 0.25
-- The orb duration
local function GetDuratoin(buff)
if buff == BUFF_1 then
return 20.
elseif buff == BUFF_2 then
return 20.
elseif buff == BUFF_3 then
return 20.
else
return 20.
end
end
-- The max mana bonus
local function GetManaBonus(buff)
if buff == BUFF_1 then
return 20.
elseif buff == BUFF_2 then
return 30.
elseif buff == BUFF_3 then
return 40.
else
return 50.
end
end
-- The chance to drop an orb
local function GetDropChance(unit, buff)
if IsUnitType(unit, UNIT_TYPE_HERO) then
return 100
else
if buff == BUFF_1 then
return 20
elseif buff == BUFF_2 then
return 20
elseif buff == BUFF_3 then
return 20
else
return 20
end
end
end
-- The orb pickup range
local function GetPickupRange(buff)
if buff == BUFF_1 then
return 100.
elseif buff == BUFF_2 then
return 100.
elseif buff == BUFF_3 then
return 100.
else
return 100.
end
end
-- The unit drop filter
local function UnitDropFilter(unit)
return not IsUnitType(unit, UNIT_TYPE_STRUCTURE)
end
-- The unit pickup filter
local function UnitPickupFilter(player, target)
return UnitAlive(target) and IsUnitType(target, UNIT_TYPE_HERO) and IsUnitEnemy(target, player)
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local WaterOrb = setmetatable({}, {})
local mt = getmetatable(WaterOrb)
mt.__index = mt
local timer = CreateTimer()
local key = 0
local array = {}
local flag = {}
function mt:allocate()
local this = {}
setmetatable(this, mt)
return this
end
function mt:remove(i)
DestroyGroup(self.group)
DestroyEffect(self.effect)
array[i] = array[key]
key = key - 1
if key == 0 then
PauseTimer(timer)
end
self = nil
return i - 1
end
function mt:onPeriod()
local i = 1
local this
while i <= key do
this = array[i]
if this.duration > 0 then
this.duration = this.duration - PERIOD
GroupEnumUnitsInRange(this.group, this.x, this.y, this.range, nil)
for j = 0, BlzGroupGetSize(this.group) - 1 do
local unit = BlzGroupUnitAt(this.group, j)
if UnitPickupFilter(this.player, unit) then
AddUnitBonus(unit, BONUS_MANA, this.bonus)
DestroyEffect(AddSpecialEffectTarget(EFFECT, unit, ATTACH))
i = this:remove(i)
break
end
end
else
i = this:remove(i)
end
i = i + 1
end
end
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function()
local unit = GetTriggerUnit()
if flag[unit] then
local this = WaterOrb:allocate()
key = key + 1
array[key] = this
this.x = GetUnitX(unit)
this.y = GetUnitY(unit)
this.group = CreateGroup()
this.player = GetOwningPlayer(unit)
this.effect = AddSpecialEffectEx(MODEL, this.x, this.y, 0, SCALE)
this.duration = GetDuratoin(flag[unit])
this.range = GetPickupRange(flag[unit])
this.bonus = GetManaBonus(flag[unit])
if key == 1 then
TimerStart(timer, PERIOD, true, function() WaterOrb:onPeriod() end)
end
end
end)
RegisterAnyDamageEvent(function()
local damage = GetEventDamage()
if damage > 0 then
flag[Damage.target.unit] = nil
if damage >= GetWidgetLife(Damage.target.unit) and UnitDropFilter(Damage.target.unit) then
if GetUnitAbilityLevel(Damage.target.unit, BUFF_4) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_4) then
flag[Damage.target.unit] = BUFF_4
end
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_3) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_3) then
flag[Damage.target.unit] = BUFF_3
end
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_2) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_2) then
flag[Damage.target.unit] = BUFF_2
end
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_1) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_1) then
flag[Damage.target.unit] = BUFF_1
end
end
end
end
end)
end)
end
end
--[[ requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, Missiles, Utilities, MouseUtils
/* ---------------------- Living Tide v1.0 by Chopinski --------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
// Vexorian - TimerUtils
// Magtheridon96 - RegisterPlayerUnitEvent
// MyPad - MouseUtils
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the ability
local ABILITY = FourCC('A004')
-- The Living Tide model
local MODEL = "LivingTide.mdl"
-- The Living Tide scale
local SCALE = 1.
-- The Living Tide speed
local SPEED = 550.
-- The update period
local PERIOD = 0.03125000
-- The amount of damage dealt in a second
local function GetDamagePerSecond(unit, level)
return 100. * level
end
-- The living tide collision size
local function GetCollision(unit, level)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_RLF_AREA_OF_EFFECT, level - 1)
end
-- The living tide sight range
local function GetVisionRange(unit, level)
return 1000. + 0.*level
end
-- The base mana cost per second
local function GetBaseManaCostPerSecond(unit, level)
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_ILF_MANA_COST, level - 1)
end
-- The range step to change the amount of mana consumed
local function GetManaCostRangeIncrement(unit, level)
return 100.
end
-- The mana cost amount per range increment
local function GetManaCostPerIncrement(unit, level)
return 5.
end
-- The unit filter for damage
local function UnitFilter(player, target)
return UnitAlive(target) and IsUnitEnemy(target, player) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
local LivingTide = setmetatable({}, {})
local mt = getmetatable(LivingTide)
mt.__index = mt
local timer = CreateTimer()
local key = 0
local array = {}
local struct = {}
function mt:allocate()
local this = {}
setmetatable(this, mt)
return this
end
function mt:remove(i)
self.tide:terminate()
array[i] = array[key]
key = key - 1
if key == 0 then
PauseTimer(timer)
end
self = nil
return i - 1
end
onInit(function()
RegisterSpellEffectEvent(ABILITY, function()
if struct[Spell.source.unit] == nil then
local this = LivingTide:allocate()
this.unit = Spell.source.unit
this.player = Spell.source.player
this.level = Spell.level
this.mana = GetBaseManaCostPerSecond(this.unit, this.level)
this.range = GetManaCostRangeIncrement(this.unit, this.level)
this.step = GetManaCostPerIncrement(this.unit, this.level)
key = key + 1
array[key] = this
struct[this.unit] = this
this.tide = Missiles:create(Spell.x, Spell.y, 0, Spell.source.x, Spell.source.y, 0)
this.tide:model(MODEL)
this.tide:scale(SCALE)
this.tide:speed(SPEED)
this.tide.source = this.unit
this.tide.owner = this.player
this.tide:vision(GetVisionRange(this.unit, this.level))
this.tide.damage = GetDamagePerSecond(this.unit, this.level) / (1/0.025)
this.tide.collision = GetCollision(this.unit, this.level)
this.tide.onHit = function(unit)
if UnitFilter(this.tide.owner, unit) then
if UnitDamageTarget(this.tide.source, unit, this.tide.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, nil) then
this.tide:flush(unit)
end
end
return false
end
this.tide.onFinish = function()
this.tide:pause(true)
return false
end
this.tide:launch()
if key == 1 then
TimerStart(timer, PERIOD, true, function()
local i = 1
local this
while i <= key do
this = array[i]
if struct[this.unit] then
local x = GetUnitX(this.unit)
local y = GetUnitY(this.unit)
local cost = (this.mana + this.step*(DistanceBetweenCoordinates(x, y, this.tide.x, this.tide.y)/this.range)) * PERIOD
if cost > GetUnitState(this.unit, UNIT_STATE_MANA) then
IssueImmediateOrder(this.unit, "stop")
struct[this.unit] = nil
i = this:remove(i)
else
AddUnitMana(this.unit, -cost)
this.tide:deflect(GetPlayerMouseX(this.player), GetPlayerMouseY(this.player), 0)
BlzSetUnitFacingEx(this.unit, AngleBetweenCoordinates(x, y, this.tide.x, this.tide.y)*bj_RADTODEG)
if this.tide.paused then
this.tide:pause(false)
end
end
else
i = this:remove(i)
end
i = i + 1
end
end)
end
end
end)
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_ENDCAST, function()
if GetSpellAbilityId() == ABILITY then
struct[GetTriggerUnit()] = nil
end
end)
end)
end
end
--[[ requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, TimerUtils, Utilities, DamageInterface
/* ---------------------- Bad Weather v1.0 by Chopinski --------------------- */
// Credits:
// Bribe - SpellEffectEvent
// Magtheridon96 - RegisterPlayerUnitEvent
// Vexorian - TimerUtils
/* ----------------------------------- END ---------------------------------- */
]]--
do
-- -------------------------------------------------------------------------- --
-- Configuration --
-- -------------------------------------------------------------------------- --
-- The raw code of the Ability
local ABILITY = FourCC('A005')
-- The raw code of the debuff Ability
local DEBUFF = FourCC('A007')
-- The raw code of the debuff buff
local BUFF = FourCC('B001')
-- The rain model
local MODEL = "Rain.mdl"
-- The rain model scale
local SCALE = 2.5
-- The raw code of the Jaina unit in the editor
local JAINA_ID = FourCC('H000')
-- The GAIN_AT_LEVEL is greater than 0
-- Jaina will gain Bad Weather at this level
local GAIN_AT_LEVEL = 20
-- The rain duration
local function GetDuratoin(unit, level)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(unit, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
end
-- The bonus damage dealt (use different buffs per level in the debuff ability)
local function GetDamageBonus(buff)
if buff == BUFF then
return 0.2
else
return 0.2
end
end
-- -------------------------------------------------------------------------- --
-- System --
-- -------------------------------------------------------------------------- --
do
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_LEVEL, function()
local unit = GetTriggerUnit()
if GAIN_AT_LEVEL > 0 then
if GetUnitTypeId(unit) == JAINA_ID and GetHeroLevel(unit) == GAIN_AT_LEVEL then
UnitAddAbility(unit, ABILITY)
UnitMakeAbilityPermanent(unit, true, ABILITY)
end
end
end)
RegisterSpellEffectEvent(ABILITY, function()
local timer = CreateTimer()
local unit = DummyRetrieve(Spell.source.player, Spell.x, Spell.y, 0, 0)
local effect = AddSpecialEffectEx(MODEL, Spell.x, Spell.y, 0, SCALE)
UnitAddAbility(unit, DEBUFF)
TimerStart(timer, GetDuratoin(Spell.source.unit, Spell.level), false, function()
UnitRemoveAbility(unit, DEBUFF)
DestroyEffect(effect)
DummyRecycle(unit)
PauseTimer(timer)
DestroyTimer(timer)
end)
end)
RegisterSpellDamageEvent(function()
if GetUnitAbilityLevel(Damage.target.unit, BUFF) > 0 and Damage.isEnemy then
BlzSetEventDamage(GetEventDamage()*(1 + GetDamageBonus(BUFF)))
end
end)
end)
end
end
do
onInit(function()
RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function()
local unit = GetTriggerUnit()
if GetOwningPlayer(unit) == Player(0) and IsUnitType(unit, UNIT_TYPE_HERO) then
ReviveHero(unit, GetUnitX(unit), GetUnitY(unit), true)
end
end)
end)
end
do
local centerX = GetRectCenterX(gg_rct_Attack)
local centerY = GetRectCenterY(gg_rct_Attack)
local function Spawn(x, y, melee, ranged)
local unit
for i = 0, 3 do
if i < 3 then
unit = CreateUnit(Player(1), melee, x, y, 0)
else
unit = CreateUnit(Player(1), ranged, x, y, 0)
end
IssuePointOrderById(unit, 851983, centerX, centerY)
end
end
onInit(function()
local trigger = CreateTrigger()
TriggerRegisterTimerEventPeriodic(trigger, 45.00)
TriggerAddAction(trigger, function()
for i = 0, 3 do
if i == 0 then
Spawn(GetRectCenterX(gg_rct_Human), GetRectCenterY(gg_rct_Human), FourCC('hfoo'), FourCC('hrif'))
elseif i == 1 then
Spawn(GetRectCenterX(gg_rct_NightElf), GetRectCenterY(gg_rct_NightElf), FourCC('esen'), FourCC('earc'))
elseif i == 2 then
Spawn(GetRectCenterX(gg_rct_Undead), GetRectCenterY(gg_rct_Undead), FourCC('ugho'), FourCC('ucry'))
elseif i == 3 then
Spawn(GetRectCenterX(gg_rct_Orc), GetRectCenterY(gg_rct_Orc), FourCC('ogru'), FourCC('ohun'))
end
end
end)
end)
end
do
onInit(function()
local trigger = CreateTrigger()
BlzTriggerRegisterPlayerKeyEvent(trigger, Player(0), OSKEY_HOME, 0, false)
BlzTriggerRegisterPlayerKeyEvent(trigger, Player(0), OSKEY_END, 0, false)
TriggerAddCondition(trigger, Condition(function()
local real = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
local pKey = BlzGetTriggerPlayerKey()
if pKey == OSKEY_HOME then
SetCameraFieldForPlayer(Player(0), CAMERA_FIELD_TARGET_DISTANCE, real + 25, 0.00)
ClearTextMessages()
print("Camera Distance: " .. (real + 25))
elseif pKey == OSKEY_END then
SetCameraFieldForPlayer(Player(0), CAMERA_FIELD_TARGET_DISTANCE, real - 25, 0.00)
ClearTextMessages()
print("Camera Distance: " .. (real - 25))
end
end))
Cheat("iseedeadpeople")
end)
end
do
onInit(function()
local trigger = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_DAMAGED)
TriggerAddCondition(trigger, Condition(function()
local source = GetEventDamageSource()
local target = BlzGetEventDamageTarget()
local damage = GetEventDamage()
local text = I2S(R2I(damage))
local damagetype
local attacktype
if damage > 0 then
damagetype = BlzGetEventDamageType()
attacktype = BlzGetEventAttackType()
if damagetype == DAMAGE_TYPE_NORMAL then
ArcingTextTag("|cffff0000" .. text .. "|r", target)
elseif attacktype == ATTACK_TYPE_NORMAL then
ArcingTextTag("|cff00ffff" .. text .. "|r", target)
elseif damagetype == DAMAGE_TYPE_ENHANCED then
ArcingTextTag("|cff00ff00" .. text .. "|r", target)
elseif damagetype == DAMAGE_TYPE_UNIVERSAL then
ArcingTextTag(text, target)
else
ArcingTextTag("|cffe4fd00" .. text .. "|r", target)
end
elseif damage < 0 then
ArcingTextTag("|cff00ff00 +" .. text .. "|r", target)
end
end))
end)
end