- Joined
- Jun 26, 2020
- Messages
- 1,928
Hello I made a Dummy Cast system in Lua, it cast an spell and is recycled 1 second after it ends the spell or didn't issued the order, it works fine:
But sometimes the dummy is not being recycled and stays there (and I don't why it appears in the minimap when I set the option of not appearing in the minimap to true), this happens when I'm emulating the cluster rockets spell:
And in case you are wondering, the problem is not the missile system, I checked that is the dummy caster, what's wrong?
Lua:
if Debug then Debug.beginFile("DummyCaster") end
OnInit("DummyCaster", function ()
Require "WorldBounds"
Require "Timed"
-- System based on MUI DummyCaster
-- Import the dummy from the object editor
local DummyID = FourCC('n000')
local MAX_DUMMIES = 99
-- WARNING: Do not touch anything below this line!
-- Default 3 values you may use, pick one as desired
---@enum CastType
CastType = {
IMMEDIATE = 0,
POINT = 1,
TARGET = 2
}
local Dummies = {}
local Recycled = __jarray(false)
local Abilities = __jarray(0)
local Neutral = Player(PLAYER_NEUTRAL_PASSIVE)
local function GetDummy(player, x, y, angle)
local dummy = table.remove(Dummies)
if not dummy then
dummy = CreateUnit(player, DummyID, x, y, angle)
else
ShowUnitShow(dummy)
SetUnitOwner(dummy, player, false)
SetUnitPosition(dummy, x, y)
BlzSetUnitFacingEx(dummy, angle)
end
Recycled[dummy] = false
return dummy
end
local function RefreshDummy(dummy)
if Recycled[dummy] then
return
end
Recycled[dummy] = true
if #Dummies == MAX_DUMMIES then
RemoveUnit(dummy)
else
SetUnitOwner(dummy, Neutral, false)
ShowUnitHide(dummy)
SetUnitPosition(dummy, WorldBounds.maxX, WorldBounds.maxY)
UnitRemoveAbility(dummy, Abilities[dummy])
Abilities[dummy] = nil
table.insert(Dummies, dummy)
end
end
---Casts a spell from a dummy caster, returns if the spell was successfully casted
---@param owner player
---@param x number
---@param y number
---@param abilId integer
---@param orderId integer
---@param level integer
---@param castType CastType
---@param tx? number | unit
---@param ty? number
---@return boolean
function DummyCast(owner, x, y, abilId, orderId, level, castType, tx, ty)
local angle = 0
if castType == CastType.IMMEDIATE then
if tx then
error("Too much arguments", 2)
end
elseif castType == CastType.POINT then
if not tx or not ty then
error("You didn't set a target point", 2)
elseif not type(tx) == "number" or not type(ty) == "number" then
error("Invalid target", 2)
end
angle = math.atan(ty - y, tx - x)
elseif castType == CastType.TARGET then
if Wc3Type(tx) ~= "unit" then
error("Invalid target", 2)
end
angle = math.atan(GetUnitX(tx) - y, GetUnitX(tx) - x)
else
error("Invalid target-type", 2)
end
local dummy = GetDummy(owner, x, y, angle)
UnitAddAbility(dummy, abilId)
SetUnitAbilityLevel(dummy, abilId, level)
Abilities[dummy] = abilId
local success = false
if castType == CastType.IMMEDIATE then
success = IssueImmediateOrderById(dummy, orderId)
elseif castType == CastType.POINT then
success = IssuePointOrderById(dummy, orderId, tx, ty)
elseif castType == CastType.TARGET then
success = IssueTargetOrderById(dummy, orderId, tx)
end
if not success then
Timed.call(1., function ()
RefreshDummy(dummy)
end)
end
return success
end
local t = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH)
TriggerAddAction(t, function ()
if GetUnitTypeId(GetSpellAbilityUnit()) == DummyID then
local u = GetSpellAbilityUnit()
Timed.call(1., function ()
RefreshDummy(u)
end)
end
end)
end)
if Debug then Debug.endFile() end
Lua:
OnInit(function ()
Require "AbilityUtils"
local Spell = FourCC('A05E')
local StrDmgFactor = 0.1
local AgiDmgFactor = 0.65
local IntDmgFactor = 0.65
local AttackFactor = 1.3
local MissieModel = "Abilities\\Weapons\\HarpyMissile\\HarpyMissile.mdl"
-- The same as it is in the object editor
local Area = 100.
local Order = Orders.clusterrockets
RegisterSpellEffectEvent(Spell, function ()
local caster = GetSpellAbilityUnit()
local owner = GetOwningPlayer(caster)
local cx = GetUnitX(caster)
local cy = GetUnitY(caster)
local x = GetSpellTargetX()
local y = GetSpellTargetY()
-- Calculating the damage
local damage = (GetAttributeDamage(caster, StrDmgFactor, AgiDmgFactor, IntDmgFactor) +
GetAvarageAttack(caster) * AttackFactor)
-- --
damage = damage / 4
local counter = 8
Timed.echo(function ()
if counter == 0 or GetUnitCurrentOrder(caster) ~= Order then return true end
local angle = 2 * math.pi * math.random()
local dist = Area * math.random()
local tx = x + dist * math.cos(angle)
local ty = y + dist * math.sin(angle)
local missile = Missiles:create(cx, cy, 150, tx, ty, 0)
missile.source = caster
missile.owner = owner
missile.damage = damage
missile:scale(0.5)
missile:model(MissieModel)
missile:speed(700.)
missile:arc(30.)
missile.onFinish = function ()
ForUnitsInRange(missile.x, missile.y, Area, function (u)
if IsUnitEnemy(u, missile.owner) then
Damage.apply(caster, u, damage, true, false, udg_Air, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
-- Stun
DummyCast(
owner,
GetUnitX(caster), GetUnitY(caster),
STUN_SPELL,
STUN_ORDER,
2,
CastType.TARGET,
u
)
end
end)
end
missile:launch()
counter = counter - 1
end, 0.125)
end)
end)