- Joined
- May 9, 2014
- Messages
- 1,820
A (not-so) simple snippet that will allow one to get more out of existing Blz natives related to special effects.
Lua:
--[[-----------------------------------------------------------------------------------------
|
|
| EffectUtils
| v.1.1
| - MyPad
|
|---------------------------------------------------------------
|
| Credits:
| - Bribe for Global Initialization and Hook
| - Trokkin for the out of bounds hiding trick.
|
|---------------------------------------------------------------
| Requires:
| - Global Initialization:
| - Hook:
|---------------------------------------------------------------
|
| Empowers the usage of natives related to special effects
| by wrapping the natives such that their behavior is
| best attuned to what the user expects without significant flaws.
|
|---------------------------------------------------------------
|
| API:
|
| ---------------
| Natives
| ---------------
|
| ---@param fx effect
| ---@param dur? number
| - DestroyEffect(fx[, dur])
| - If "dur" is supplied and is greater than 0, a timer
| will be created internally to fully destroy the effect.
| - The effect cannot be directly destroyed while the
| timer is running.
| - Not supplying "dur" will make it behave like the original
| native.
|
| ---@param fx effect
| ---@param alpha integer
| - BlzSetSpecialEffectAlpha(fx, alpha)
| - When the fx is not visible (according to its visibility property),
| this function will only update its alpha value.
| - When the fx is visible (according to the same property),
| this function will behave as expected.
|
| ---@param fx effect
| ---@param value number
| ---@param x number
| ---@param y number
| ---@param z number
| - BlzSetSpecialEffectX(fx, value[, ignore])
| - BlzSetSpecialEffectY(fx, value[, ignore])
| - BlzSetSpecialEffectZ(fx, value[, ignore])
| - BlzSetSpecialEffectPosition(fx, x, y, z[, ignore])
| - Works just like their regular equivalents.
| - When "ignore" is specified and evaluated as true,
| the information about the new location of the effect
| is not updated.
|
| ---@param fx effect
| ---@return number
| - BlzGetLocalSpecialEffectX(fx)
| - BlzGetLocalSpecialEffectY(fx)
| - BlzGetLocalSpecialEffectZ(fx)
| - When not hidden, these work just like their regular equivalents.
| - When hidden, these will return their last known coordinates.
| - While hidden, the effect is moved away to the map bounds.
|
| ---@param fx effect
| - BlzGetSpecialEffectHeight(fx)
| - QUASI-NATIVE
| - Returns the height of a special effect or 0 if the effect is nil.
|
| ---@param fx effect
| - BlzGetSpecialEffectAlpha(fx)
| - QUASI-NATIVE
| - Returns the alpha color of a special effect or 255 if the effect is nil.
|
| ---@param fx effect
| ---@param red integer
| ---@param green integer
| ---@param blue integer
| - BlzSetSpecialEffectColor(fx, red, green, blue)
| - Sets the rgb-values of the special effect's color attribute to the
| parameters provided.
|
| ---@param fx effect
| ---@param whichPlayer player
| - BlzSetSpecialEffectPColor(fx, whichPlayer)
| - Sets the rgb-values of the special effect's color attribute to the
| color mapping assigned to the specified player.
|
| ----------------
| Wrappers
| ----------------
|
| SetEffectX -> BlzSetSpecialEffectX(fx, value)
| SetEffectY -> BlzSetSpecialEffectY(fx, value)
| SetEffectZ -> BlzSetSpecialEffectZ(fx, value)
| SetEffectHeight -> BlzSetSpecialEffectHeight(fx, height)
| SetEffectAlpha -> BlzSetSpecialEffectAlpha(fx, height)
| SetEffectColor -> BlzSetSpecialEffectColor(fx, red, green, blue)
| SetEffectPColor -> BlzSetSpecialEffectColorByPlayer(fx, whichPlayer)
|
| GetEffectX -> BlzGetLocalSpecialEffectX(fx)
| GetEffectY -> BlzGetLocalSpecialEffectY(fx)
| GetEffectZ -> BlzGetLocalSpecialEffectZ(fx)
| GetEffectHeight -> BlzGetSpecialEffectHeight(fx)
| GetEffectAlpha -> BlzGetSpecialEffectAlpha(fx)
|
| ------------------------
| Unique Functions
| ------------------------
|
| ---@param fx effect
| ---@param vis boolean
| - ShowEffect(fx, vis)
| - Shows or hides a special effect.
| - When hidden, the special effect's alpha color is set to 0, making it transparent.
| - As of 1.1, the special effect is moved out of bounds as well when hidden.
|
| ---@param fx effect
| ---@return boolean
| - IsEffectShown(fx)
| - Checks if the effect is shown or not (via ShowEffect).
|
]]-------------------------------------------------------------------------------------------
do
---@alias handle userdata
---@alias effect handle
-- Embedding GetZ into EffectUtils
do
if not GetZ then
local _LOC
OnMainInit(function()
_LOC = Location(0, 0)
end)
--- Returns the z-coordinate of the ground at the specified location.
--- Only use in a manner that does not require "synchronous" behavior.
---@param x number
---@param y number
---@return number
function GetZ(x, y)
MoveLocation(_LOC, x, y)
return GetLocationZ(_LOC)
end
end
GetCoordinateZ = GetZ
GetPointZ = GetZ
end
-- For garbage collection purposes
local weakTable = {__mode = 'k'}
local world = {}
local broken = (BlzStartUnitAbilityCooldown and "1.32") or "1.31"
local attr = {
height = setmetatable({}, weakTable),
alpha = setmetatable({}, weakTable),
vis = setmetatable({}, weakTable),
x = setmetatable({}, weakTable),
y = setmetatable({}, weakTable),
z = setmetatable({}, weakTable)
}
local dest_flag = {}
-- Hook all relevant natives.
OnMainInit(function()
-- Obtain the world bounds
do
world.rect = GetWorldBounds()
world.x = GetRectMaxX(world.rect) + 8192.0
world.y = GetRectMaxY(world.rect) + 8192.0
world.z = 0.0
RemoveRect(world.rect)
world.rect = nil
end
local function const_factory(funcName)
AddHook(funcName,
function(...)
local fx = _G[funcName].old(...)
if (fx ~= nil) then
attr.height[fx] = 0.0
attr.alpha[fx] = 255
attr.vis[fx] = 0
attr.x[fx] = BlzGetLocalSpecialEffectX(fx)
attr.y[fx] = BlzGetLocalSpecialEffectY(fx)
attr.z[fx] = BlzGetLocalSpecialEffectZ(fx)
end
return fx
end)
end
const_factory("AddSpecialEffect")
const_factory("AddSpecialEffectLoc")
const_factory("AddSpecialEffectTarget")
const_factory("AddSpellEffect")
const_factory("AddSpellEffectById")
const_factory("AddSpellEffectLoc")
const_factory("AddSpellEffectByIdLoc")
const_factory("AddSpellEffectTarget")
const_factory("AddSpellEffectTargetById")
AddHook("DestroyEffect",
function(fx)
if dest_flag[fx] then return
end
DestroyEffect.old(fx)
attr.height[fx] = nil
attr.alpha[fx] = nil
attr.vis[fx] = nil
attr.x[fx] = nil
attr.y[fx] = nil
attr.z[fx] = nil
dest_flag[fx] = nil
end)
AddHook("DestroyEffect",
function(fx, dur)
if (not dur) or (dur <= 0) then
DestroyEffect.old(fx)
return
end
if dest_flag[fx] then return;
end
dest_flag[fx] = true
TimerStart(CreateTimer(), dur, false, function()
dest_flag[fx] = false
DestroyEffect.old(fx)
end)
end, 1)
AddHook("BlzSetSpecialEffectHeight",
function(fx, height)
attr.height[fx] = height
if broken then
height = height + GetPointZ(BlzGetLocalSpecialEffectX(fx), BlzGetLocalSpecialEffectY(fx))
end
BlzSetSpecialEffectHeight.old(fx, height)
end)
local toInt = R2I
AddHook("BlzSetSpecialEffectAlpha",
function(fx, alpha)
alpha = ((alpha > 0xff) and 0xff) or ((alpha < 0) and 0) or toInt(alpha)
attr.alpha[fx] = alpha
if attr.vis[fx] >= 0 then
BlzSetSpecialEffectAlpha.old(fx, alpha)
else
BlzSetSpecialEffectAlpha.old(fx, 0)
end
end)
AddHook("BlzSetSpecialEffectX",
function(fx, value, ignore)
if (attr.vis[fx] >= 0) or (not attr.vis[fx]) then
BlzSetSpecialEffectX.old(fx, value)
end
if (not ignore) and (attr.x[fx]) then
attr.x[fx] = value
end
end)
AddHook("BlzSetSpecialEffectY",
function(fx, value, ignore)
if (attr.vis[fx] >= 0) or (not attr.vis[fx]) then
BlzSetSpecialEffectY.old(fx, value)
end
if (not ignore) and (attr.y[fx]) then
attr.y[fx] = value
end
end)
AddHook("BlzSetSpecialEffectZ",
function(fx, value, ignore)
if (attr.vis[fx] >= 0) or (not attr.vis[fx]) then
BlzSetSpecialEffectZ.old(fx, value)
end
if (not ignore) and (attr.z[fx]) then
attr.z[fx] = value
end
end)
AddHook("BlzSetSpecialEffectPosition",
function(fx, x, y, z, ignore)
if (attr.vis[fx] >= 0) or (not attr.vis[fx]) then
BlzSetSpecialEffectPosition.old(fx, x, y, z)
end
if not ignore then
attr.x[fx] = ((attr.x[fx] ~= nil) and x) or nil
attr.y[fx] = ((attr.y[fx] ~= nil) and y) or nil
attr.z[fx] = ((attr.z[fx] ~= nil) and z) or nil
end
end)
AddHook("BlzGetLocalSpecialEffectX",
function(fx)
local result = BlzGetLocalSpecialEffectX.old(fx)
return ((attr.vis[fx] < 0) and (attr.z[fx])) or result
end)
AddHook("BlzGetLocalSpecialEffectY",
function(fx)
local result = BlzGetLocalSpecialEffectY.old(fx)
return ((attr.vis[fx] < 0) and (attr.y[fx])) or result
end)
AddHook("BlzGetLocalSpecialEffectZ",
function(fx)
local result = BlzGetLocalSpecialEffectZ.old(fx)
return ((attr.vis[fx] < 0) and (attr.z[fx])) or result
end)
SetEffectX = BlzSetSpecialEffectX
SetEffectY = BlzSetSpecialEffectY
SetEffectZ = BlzSetSpecialEffectZ
SetEffectHeight = BlzSetSpecialEffectHeight
SetEffectAlpha = BlzSetSpecialEffectAlpha
SetEffectColor = BlzSetSpecialEffectColor
SetEffectPColor = BlzSetSpecialEffectColorByPlayer
GetEffectX = BlzGetLocalSpecialEffectX
GetEffectY = BlzGetLocalSpecialEffectY
GetEffectZ = BlzGetLocalSpecialEffectZ
GetEffectHeight = BlzGetSpecialEffectHeight
GetEffectAlpha = BlzGetSpecialEffectAlpha
end)
if not BlzGetSpecialEffectHeight then
--- Gets the height of a special effect, relative to the ground.
---@param fx effect
---@return number
function BlzGetSpecialEffectHeight(fx)
return attr.height[fx] or 0
end
end
if not BlzGetSpecialEffectAlpha then
--- Gets the Alpha color of a special effect.
---@param fx effect
---@return integer
function BlzGetSpecialEffectAlpha(fx)
return attr.alpha[fx] or 255
end
end
---Shows or hides an effect, depending on its internal visibility counter.
---This is separate from GetSpecialEffectAlpha.
---The behavior of the internal visibility counter is as follows:
---1. For any integer greater than or equal to 0 (n), the number of times the function must be called to hide the effect is (n + 1).
---2. For any negative integer "n", the number of times the function must be called to show the effect is |n|.
---@param fx effect
---@param vis boolean
function ShowEffect(fx, vis)
if (not attr.vis[fx]) then
return
end
local inc = (vis and 1) or (-1)
attr.vis[fx] = attr.vis[fx] + inc
BlzSetSpecialEffectAlpha(fx, attr.alpha[fx])
if (attr.vis[fx] == -1) and (not vis) then
attr.vis[fx] = 0
BlzSetSpecialEffectX(fx, world.x, false)
BlzSetSpecialEffectY(fx, world.y, false)
BlzSetSpecialEffectZ(fx, world.z, false)
attr.vis[fx] = -1
elseif (attr.vis[fx] == 0) and (vis) then
BlzSetSpecialEffectX(fx, attr.x[fx], false)
BlzSetSpecialEffectY(fx, attr.y[fx], false)
BlzSetSpecialEffectZ(fx, attr.z[fx], false)
end
end
---Checks whether an effect is visible or not.
---This is separate from GetSpecialEffectAlpha.
---Defaults to false for already destroyed effects.
---@param fx effect
---@return boolean
function IsEffectShown(fx)
if (attr.vis[fx] == nil) then return false end
return attr.vis[fx] >= 0
end
end
- v.1.0
- Release
- Release
- v.1.1
- Updated to take advantage of the following resources:
- Hook
- Global Initialization
- Documentation has been provided for most of the newly hooked functions. New functions have also been documented in accordance with Lua EmmyAnnotation.
IsEffectShown(fx: effect)[/code] introduced. [*]In addition to setting the alpha color value of the special effect to 0 when hiding the effect, the special effect is moved out of bounds as well. Special credits to Trokkin for that. [*][icode=lua]GetPointZ(x:number, y:number)[/code] snippet now included within the script itself. [/LIST] [/LIST] [/spoiler]
- Updated to take advantage of the following resources:
Last edited: