- Joined
- Mar 29, 2016
- Messages
- 688
Overview
API & Documentation
Code
Example Usage
Credits
Version History
SpecialEffect v1.0.1
Special effect library for Lua
Description
This library provides the
This is supposed to replace the dummy + sfx method that is widely used before but has become obsolete since patch 1.31 due to the new additions to effect manipulation natives.
Dependencies
Special effect library for Lua
Description
This library provides the
SpecialEffect
class which allows you to conveniently cluster together multiple effect handles and control it as a single entity.This is supposed to replace the dummy + sfx method that is widely used before but has become obsolete since patch 1.31 due to the new additions to effect manipulation natives.
Dependencies
- N/A
Lua:
--[[
API:
Constructors:
SpecialEffect(x, y, z)
Destructor:
function SpecialEffect:destroy()
Getters:
function SpecialEffect:alive() -> boolean
function SpecialEffect:visible() -> boolean
function SpecialEffect:x() -> number
function SpecialEffect:y() -> number
function SpecialEffect:z() -> number - absolute z
function SpecialEffect:height() -> number - height relative to ground
function SpecialEffect:position() - returns position x, y, & z
function SpecialEffect:yaw() -> number
function SpecialEffect:pitch() -> number
function SpecialEffect:roll() -> number
function SpecialEffect:orientation() - returns yaw, pitch, & roll
Iterators:
function SpecialEffect:__pairs()
- Returns an iterator for all effect handles, NOT including ones
from attached SpecialEffect objects
- Returns an empty iterator if this SpecialEffect is dead (i.e. has
been killed using SpecialEffect:kill())
function SpecialEffect:attachedIter()
- Returns an iterator for all attached SpecialEffect objects
Methods:
function SpecialEffect:add(arg:string|SpecialEffect) -> effect|nil
- Adds a special effect model to this SpecialEffect object if <arg>
is a string. Otherwise, it attaches the input SpecialEffect object
to this one.
function SpecialEffect:remove(arg:string|SpecialEffect)
- Removes the special effect model from this SpecialEffect if <arg>
is a valid model string, else, dettaches the input SpecialEffect
object from this one.
function SpecialEffect:scatter(chainScatter:boolean)
- Dettaches all attached SpecialEffects
- If <chainScatter> is true, recursively scatters all connected
SpecialEffect objects
function SpecialEffect:clear(scatter:boolean, chainClear:boolean)
- Removes all the special effect models of this SpecialEffect object
- If <scatter> is true, also scatters all attached SpecialEffects
- If <chainClear> is true, the clear operation is recursively
applied to all connected SpecialEffect objects
function SpecialEffect:kill(deathDuration:number, chainKill:boolean)
- Plays the death animation of this SpecialEffect and schedules it
for destruction after <deathDuration> seconds
- If <chainKill> is true, recursively kills all connected
SpecialEffects
function SpecialEffect:move(x:number, y:number, z:number)
- Moves this SpecialEffect including all attached SpecialEffects
while keeping their relative spacing from each other
- All parameters are optional
function SpecialEffect:orient(yaw:number, pitch:number, roll:number)
- Changes this SpecialEffect's orientation
- All parameters are optional
function SpecialEffect:animate(whichAnim:animtype, timeScale:number, chainAnimate:boolean)
- Makes this SpecialEffect play the given animation <whichAnim>,
with an animation speed specified by <timeScale>
- If <timeScale> is nil, animation plays at default effect time
scale
- If <chainAnimate> is true, this method is called recursively for
all connected SpecialEffect objects
function SpecialEffect:show(force:boolean)
function SpecialEffect:hide(force:boolean)
- Hides/Shows the SpecialEffect object
- If <force> is false, each call to show/hide increments/decrements
a visibility flag counter internally, of which a counter value of
0 causes SpecialEffect object to be hidden
- If <force> is true, the show/hide command ignores the counter and
resets its value
- Can be safely used inside local-code blocks
Method Interfaces:
function SpecialEffect:onAttach(to:SpecialEffect)
- If this method is present, it will be called whenever a
SpecialEffect is attached into another SpecialEffect using the
SpecialEffect:add() method
- <self> is the one being attached and <to> is where <self> is being
attached to
function SpecialEffect:onDettach(from:SpecialEffect)
- If this method is present, it will be called whenever a
SpecialEffect is dettached from another SpecialEffect using the
SpecialEffect:remove() method
- <self> is the one being dettached and <from> is where <self> is
being dettached from
- NOTE: Everytime a recursive scatter is performed using one of the
methods above, the order of scatter operation is always from the
'parent' SpecialEffect all the way through the 'descendants'
]]--
Lua:
-- Resource Link: https://www.hiveworkshop.com/threads/lua-specialeffect.331757/
---@class SpecialEffect
SpecialEffect = setmetatable({HIDDEN_PLACE_X = 0., HIDDEN_PLACE_Y = 10000.}, {__name = 'SpecialEffect'})
do
local specialeffect = getmetatable(SpecialEffect)
specialeffect.__index = specialeffect
local function is_a(o, class)
if o and type(o) == 'table' then
local mt = getmetatable(o)
while (mt) do
if mt == class then return true end
mt = getmetatable(mt)
end
return false
end
end
local loc = Location(0., 0.)
local function get_terrain_z(x, y)
MoveLocation(loc, x, y)
return GetLocationZ(loc)
end
local function vanish_effect(e)
BlzSetSpecialEffectX(e, SpecialEffect.HIDDEN_PLACE_X)
BlzSetSpecialEffectY(e, SpecialEffect.HIDDEN_PLACE_Y)
DestroyEffect(e)
end
-- Constructors/Destructor
---@param x number
---@param y number
---@param z number
---@return SpecialEffect
function specialeffect:__call(x, y, z)
local e = setmetatable(
{
_x = x, _y = y, _z = z,
_yaw = 0., _pitch = 0., _roll = 0.,
_visibility_count = 1,
_alive = true,
_handles = {}, _attached = {}
},
specialeffect
)
return e
end
function specialeffect:__gc()
self:destroy()
end
-- Gettters
---@return boolean
function specialeffect:alive() return self._alive end
---@return boolean
function specialeffect:visible() return self._visibility_count > 0 end
---@return number
function specialeffect:x() return self._x end
---@return number
function specialeffect:y() return self._y end
---@return number
function specialeffect:z() return self._z end
---@return number
function specialeffect:height() return self._z - get_terrain_z(self._x, self._y) end
---@return number, number, number
function specialeffect:position() return self._x, self._y, self._z end
---@return number
function specialeffect:yaw() return self._yaw end
---@return number
function specialeffect:pitch() return self._pitch end
---@return number
function specialeffect:roll() return self._roll end
---@return number, number, number
function specialeffect:orientation() return self._yaw, self._pitch, self._roll end
-- Iterators
local empty_t = {}
function specialeffect:__pairs()
return next, self._alive and self._handles or empty_t, nil
end
function specialeffect:attachedIter()
return ipairs(self._attached)
end
--- Methods
---@param arg string|SpecialEffect
---@return effect|nil
function specialeffect:add(arg)
if type(arg) == 'string' then
if self._alive then
local e = AddSpecialEffect(arg, self._x, self._y)
BlzSetSpecialEffectPosition(e, self._x, self._y, self._z)
BlzSetSpecialEffectOrientation(e, self._yaw, self._pitch, self._roll)
self._handles[arg] = e
return e
end
elseif is_a(arg, specialeffect) then
if arg.onAttach then
arg:onAttach(self)
end
self._attached[#self._attached + 1] = arg
end
end
---@param arg string|SpecialEffect
function specialeffect:remove(arg)
if type(arg) == 'string' then
if self._alive then
local e = self._handles[arg]
if e then
vanish_effect(e)
end
end
elseif is_a(arg, specialeffect) then
local n = #self._attached
for i = 1, n do
if self._attached[i] == arg then
if arg.onDettach then
arg:onDettach(self)
end
self._attached[i] = nil
end
end
end
end
---@param chainScatter boolean
function specialeffect:scatter(chainScatter)
for i = #self._attached, 1, -1 do
local a = self._attached[i]
if a.onDettach then
a:onDettach(self)
end
self._attached[i] = nil
if chainScatter then
a:scatter(true)
end
end
end
---@param x number
---@param y number
---@param z number
---@param relativeZ boolean
function specialeffect:move(x, y, z, relativeZ)
if relativeZ and z then
z = z + get_terrain_z(x, y)
end
x, y, z = x or self._x, y or self._y, z or self._z
local dx, dy, dz = x - self._x, y - self._y, z - self._z
if self:visible() then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectPosition(e, x, y, z)
end
end
self._x, self._y, self._z = x, y, z
for _, v in ipairs(self._attached) do
v:move(v._x + dx, v._y + dy, v._z + dz)
end
end
---@param yaw number
---@param pitch number
---@param roll number
function specialeffect:orient(yaw, pitch, roll)
yaw, pitch, roll = yaw or self._yaw, pitch or self._pitch, roll or self._roll
for _, v in pairs(self._handles) do
BlzSetSpecialEffectOrientation(v, yaw, pitch, roll)
end
self._yaw, self._pitch, self._roll = yaw, pitch, roll
end
---@param whichAnim animtype
---@param timeScale number
---@param chainAnimate boolean
function specialeffect:animate(whichAnim, timeScale, chainAnimate)
if self._alive then
for _, v in pairs(self._handles) do
if timeScale then
BlzPlaySpecialEffectWithTimeScale(v, whichAnim, timeScale)
else
BlzPlaySpecialEffect(v, whichAnim)
end
end
if chainAnimate then
for _, v in ipairs(self._attached) do
v:animate(whichAnim, nil, true)
end
end
end
end
---@param force boolean
function specialeffect:show(force)
if force then self._visibility_count = 0 end
if self._visibility_count == 0 then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectPosition(e, self._x, self._y, self._z)
end
end
self._visibility_count = self._visibility_count + 1
end
---@param force boolean
function specialeffect:hide(force)
if force then self._visibility_count = 1 end
self._visibility_count = self._visibility_count - 1
if self._visibility_count == 0 then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectX(e, SpecialEffect.HIDDEN_PLACE_X)
BlzSetSpecialEffectY(e, SpecialEffect.HIDDEN_PLACE_Y)
end
end
end
local timer_t = {}
local function on_kill()
local t = GetExpiredTimer()
timer_t[t]:destroy()
DestroyTimer(t)
end
---@param deathDuration number
---@param chainKill boolean
function specialeffect:kill(deathDuration, chainKill)
if self._alive then
self:animate(ANIM_TYPE_DEATH)
local t = CreateTimer()
timer_t[t] = self
TimerStart(t, deathDuration, false, on_kill)
self._alive = false
if chainKill then
for _, v in ipairs(self._attached) do
v:kill(deathDuration, true)
end
end
end
end
---@param scatter boolean
---@param chainClear boolean
function specialeffect:clear(scatter, chainClear)
local t = {table.unpack(self._attached)}
if scatter then
self:scatter()
end
if self._alive then
for _, v in pairs(self._handles) do
vanish_effect(v)
end
end
if chainClear then
for _, v in ipairs(t) do
v:clear(scatter, true)
end
end
end
function specialeffect:destroy()
self:clear(true, false)
setmetatable(self, nil)
end
end
Lua:
v1.0.1
- Small fixes on the SpecialEffect:add() and SpecialEffect:remove() functions
v1.0.0
- Initial Release
- Small fixes on the SpecialEffect:add() and SpecialEffect:remove() functions
v1.0.0
- Initial Release
specialeffect.lua
Lua:
--[[ specialeffect.lua v1.0.1 by AGD | https://www.hiveworkshop.com/threads/331757/
Special effect library for Lua.
Based on: https://www.hiveworkshop.com/threads/325954/
Description:
This library provides the SpecialEffect class which allows you to
conveniently cluster together multiple effect handles and control it as
a single entity.
This is supposed to replace the dummy + sfx method that is widely used
before but has become obsolete since patch 1.31 due to the new additions
to effect manipulation natives.
Requirements:
- None
]]--
--[[
API:
Constructors:
SpecialEffect(x, y, z)
Destructor:
function SpecialEffect:destroy()
Getters:
function SpecialEffect:alive() -> boolean
function SpecialEffect:visible() -> boolean
function SpecialEffect:x() -> number
function SpecialEffect:y() -> number
function SpecialEffect:z() -> number - absolute z
function SpecialEffect:height() -> number - height relative to ground
function SpecialEffect:position() - returns position x, y, & z
function SpecialEffect:yaw() -> number
function SpecialEffect:pitch() -> number
function SpecialEffect:roll() -> number
function SpecialEffect:orientation() - returns yaw, pitch, & roll
Iterators:
function SpecialEffect:__pairs()
- Returns an iterator for all effect handles, NOT including ones
from attached SpecialEffect objects
- Returns an empty iterator if this SpecialEffect is dead (i.e. has
been killed using SpecialEffect:kill())
function SpecialEffect:attachedIter()
- Returns an iterator for all attached SpecialEffect objects
Methods:
function SpecialEffect:add(arg:string|SpecialEffect) -> effect|nil
- Adds a special effect model to this SpecialEffect object if <arg>
is a string. Otherwise, it attaches the input SpecialEffect object
to this one.
function SpecialEffect:remove(arg:string|SpecialEffect)
- Removes the special effect model from this SpecialEffect if <arg>
is a valid model string, else, dettaches the input SpecialEffect
object from this one.
function SpecialEffect:scatter(chainScatter:boolean)
- Dettaches all attached SpecialEffects
- If <chainScatter> is true, recursively scatters all connected
SpecialEffect objects
function SpecialEffect:clear(scatter:boolean, chainClear:boolean)
- Removes all the special effect models of this SpecialEffect object
- If <scatter> is true, also scatters all attached SpecialEffects
- If <chainClear> is true, the clear operation is recursively
applied to all connected SpecialEffect objects
function SpecialEffect:kill(deathDuration:number, chainKill:boolean)
- Plays the death animation of this SpecialEffect and schedules it
for destruction after <deathDuration> seconds
- If <chainKill> is true, recursively kills all connected
SpecialEffects
function SpecialEffect:move(x:number, y:number, z:number)
- Moves this SpecialEffect including all attached SpecialEffects
while keeping their relative spacing from each other
- All parameters are optional
function SpecialEffect:orient(yaw:number, pitch:number, roll:number)
- Changes this SpecialEffect's orientation
- All parameters are optional
function SpecialEffect:animate(whichAnim:animtype, timeScale:number, chainAnimate:boolean)
- Makes this SpecialEffect play the given animation <whichAnim>,
with an animation speed specified by <timeScale>
- If <timeScale> is nil, animation plays at default effect time
scale
- If <chainAnimate> is true, this method is called recursively for
all connected SpecialEffect objects
function SpecialEffect:show(force:boolean)
function SpecialEffect:hide(force:boolean)
- Hides/Shows the SpecialEffect object
- If <force> is false, each call to show/hide increments/decrements
a visibility flag counter internally, of which a counter value of
0 causes SpecialEffect object to be hidden
- If <force> is true, the show/hide command ignores the counter and
resets its value
- Can be safely used inside local-code blocks
Method Interfaces:
function SpecialEffect:onAttach(to:SpecialEffect)
- If this method is present, it will be called whenever a
SpecialEffect is attached into another SpecialEffect using the
SpecialEffect:add() method
- <self> is the one being attached and <to> is where <self> is being
attached to
function SpecialEffect:onDettach(from:SpecialEffect)
- If this method is present, it will be called whenever a
SpecialEffect is dettached from another SpecialEffect using the
SpecialEffect:remove() method
- <self> is the one being dettached and <from> is where <self> is
being dettached from
- NOTE: Everytime a recursive scatter is performed using one of the
methods above, the order of scatter operation is always from the
'parent' SpecialEffect all the way through the 'descendants'
]]--
---@class SpecialEffect
SpecialEffect = setmetatable({HIDDEN_PLACE_X = 0., HIDDEN_PLACE_Y = 10000.}, {__name = 'SpecialEffect'})
do
local specialeffect = getmetatable(SpecialEffect)
specialeffect.__index = specialeffect
local function is_a(o, class)
if o and type(o) == 'table' then
local mt = getmetatable(o)
while (mt) do
if mt == class then return true end
mt = getmetatable(mt)
end
return false
end
end
local loc = Location(0., 0.)
local function get_terrain_z(x, y)
MoveLocation(loc, x, y)
return GetLocationZ(loc)
end
local function vanish_effect(e)
BlzSetSpecialEffectX(e, SpecialEffect.HIDDEN_PLACE_X)
BlzSetSpecialEffectY(e, SpecialEffect.HIDDEN_PLACE_Y)
DestroyEffect(e)
end
-- Constructors/Destructor
---@param x number
---@param y number
---@param z number
---@return SpecialEffect
function specialeffect:__call(x, y, z)
local e = setmetatable(
{
_x = x, _y = y, _z = z,
_yaw = 0., _pitch = 0., _roll = 0.,
_visibility_count = 1,
_alive = true,
_handles = {}, _attached = {}
},
specialeffect
)
return e
end
function specialeffect:__gc()
self:destroy()
end
-- Gettters
---@return boolean
function specialeffect:alive() return self._alive end
---@return boolean
function specialeffect:visible() return self._visibility_count > 0 end
---@return number
function specialeffect:x() return self._x end
---@return number
function specialeffect:y() return self._y end
---@return number
function specialeffect:z() return self._z end
---@return number
function specialeffect:height() return self._z - get_terrain_z(self._x, self._y) end
---@return number, number, number
function specialeffect:position() return self._x, self._y, self._z end
---@return number
function specialeffect:yaw() return self._yaw end
---@return number
function specialeffect:pitch() return self._pitch end
---@return number
function specialeffect:roll() return self._roll end
---@return number, number, number
function specialeffect:orientation() return self._yaw, self._pitch, self._roll end
-- Iterators
local empty_t = {}
function specialeffect:__pairs()
return next, self._alive and self._handles or empty_t, nil
end
function specialeffect:attachedIter()
return ipairs(self._attached)
end
--- Methods
---@param arg string|SpecialEffect
---@return effect|nil
function specialeffect:add(arg)
if type(arg) == 'string' then
if self._alive then
local e = AddSpecialEffect(arg, self._x, self._y)
BlzSetSpecialEffectPosition(e, self._x, self._y, self._z)
BlzSetSpecialEffectOrientation(e, self._yaw, self._pitch, self._roll)
self._handles[arg] = e
return e
end
elseif is_a(arg, specialeffect) then
if arg.onAttach then
arg:onAttach(self)
end
self._attached[#self._attached + 1] = arg
end
end
---@param arg string|SpecialEffect
function specialeffect:remove(arg)
if type(arg) == 'string' then
if self._alive then
local e = self._handles[arg]
if e then
vanish_effect(e)
end
end
elseif is_a(arg, specialeffect) then
local n = #self._attached
for i = 1, n do
if self._attached[i] == arg then
if arg.onDettach then
arg:onDettach(self)
end
self._attached[i] = nil
end
end
end
end
---@param chainScatter boolean
function specialeffect:scatter(chainScatter)
for i = #self._attached, 1, -1 do
local a = self._attached[i]
if a.onDettach then
a:onDettach(self)
end
self._attached[i] = nil
if chainScatter then
a:scatter(true)
end
end
end
---@param x number
---@param y number
---@param z number
---@param relativeZ boolean
function specialeffect:move(x, y, z, relativeZ)
if relativeZ and z then
z = z + get_terrain_z(x, y)
end
x, y, z = x or self._x, y or self._y, z or self._z
local dx, dy, dz = x - self._x, y - self._y, z - self._z
if self:visible() then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectPosition(e, x, y, z)
end
end
self._x, self._y, self._z = x, y, z
for _, v in ipairs(self._attached) do
v:move(v._x + dx, v._y + dy, v._z + dz)
end
end
---@param yaw number
---@param pitch number
---@param roll number
function specialeffect:orient(yaw, pitch, roll)
yaw, pitch, roll = yaw or self._yaw, pitch or self._pitch, roll or self._roll
for _, v in pairs(self._handles) do
BlzSetSpecialEffectOrientation(v, yaw, pitch, roll)
end
self._yaw, self._pitch, self._roll = yaw, pitch, roll
end
---@param whichAnim animtype
---@param timeScale number
---@param chainAnimate boolean
function specialeffect:animate(whichAnim, timeScale, chainAnimate)
if self._alive then
for _, v in pairs(self._handles) do
if timeScale then
BlzPlaySpecialEffectWithTimeScale(v, whichAnim, timeScale)
else
BlzPlaySpecialEffect(v, whichAnim)
end
end
if chainAnimate then
for _, v in ipairs(self._attached) do
v:animate(whichAnim, nil, true)
end
end
end
end
---@param force boolean
function specialeffect:show(force)
if force then self._visibility_count = 0 end
if self._visibility_count == 0 then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectPosition(e, self._x, self._y, self._z)
end
end
self._visibility_count = self._visibility_count + 1
end
---@param force boolean
function specialeffect:hide(force)
if force then self._visibility_count = 1 end
self._visibility_count = self._visibility_count - 1
if self._visibility_count == 0 then
for _, e in pairs(self._handles) do
BlzSetSpecialEffectX(e, SpecialEffect.HIDDEN_PLACE_X)
BlzSetSpecialEffectY(e, SpecialEffect.HIDDEN_PLACE_Y)
end
end
end
local timer_t = {}
local function on_kill()
local t = GetExpiredTimer()
timer_t[t]:destroy()
DestroyTimer(t)
end
---@param deathDuration number
---@param chainKill boolean
function specialeffect:kill(deathDuration, chainKill)
if self._alive then
self:animate(ANIM_TYPE_DEATH)
local t = CreateTimer()
timer_t[t] = self
TimerStart(t, deathDuration, false, on_kill)
self._alive = false
if chainKill then
for _, v in ipairs(self._attached) do
v:kill(deathDuration, true)
end
end
end
end
---@param scatter boolean
---@param chainClear boolean
function specialeffect:clear(scatter, chainClear)
local t = {table.unpack(self._attached)}
if scatter then
self:scatter()
end
if self._alive then
for _, v in pairs(self._handles) do
vanish_effect(v)
end
end
if chainClear then
for _, v in ipairs(t) do
v:clear(scatter, true)
end
end
end
function specialeffect:destroy()
self:clear(true, false)
setmetatable(self, nil)
end
end
Last edited: