local current = 0
Timed.echo(0.5, function ()
current = current + 0.5
if UnitAlive(data.boss) then
if dead then
dead = false
end
local whoAlreadyAre = playersOnField:copy()
local whoWereHere = unitsInTheField:copy()
unitsInTheField:clear()
playersOnField:clear()
local isInBattlefield = false
-- Check if are units in the battlefield
for i = 1, numRect do
ForUnitsInRect(battlefield[data.boss][i], function (u)
if u ~= data.boss and UnitAlive(u) and IsPlayerInGame(GetOwningPlayer(u)) then
unitsInTheField:addSingle(u)
playersOnField:addSingle(GetOwningPlayer(u))
end
end)
isInBattlefield = isInBattlefield or RectContainsUnit(battlefield[data.boss][i], data.boss)
end
if playersOnField:contains(LocalPlayer) then
if not playing then
playing = true
ChangeMusic(MUSIC)
end
end
if whoAlreadyAre:except(playersOnField):contains(LocalPlayer) then
if playing then
playing = false
RestartMusic()
end
end
if unitsInTheField:isEmpty() then
-- Reset the boss
reset()
IssuePointOrderById(data.boss, Orders.smart, initialPosX, initialPosY)
else
if playersOnField:size() >= data.maxPlayers then
if playersOnField:size() > data.maxPlayers then
whoAlreadyAre = playersOnField:except(whoAlreadyAre)
for _ = 1, (playersOnField:size() - data.maxPlayers) do
local p = whoAlreadyAre:random()
if p then
playersOnField:removeSingle(p)
whoAlreadyAre:removeSingle(p)
for u in unitsInTheField:elements() do
if GetOwningPlayer(u) == p then
SetUnitPosition(u, GetRectCenterX(data.entrance), GetRectCenterY(data.entrance))
elseif whoAlreadyAre:contains(GetOwningPlayer(u)) then
SetUnitPosition(u, GetRectCenterX(data.inner), GetRectCenterY(data.inner))
end
unitsInTheField:removeSingle(u)
end
end
end
end
for _, d in ipairs(data.forceWall) do
ModifyGateBJ(bj_GATEOPERATION_CLOSE, d)
end
elseif playersOnField:size() < data.maxPlayers then
if IsDestructableAliveBJ(data.forceWall[1]) then
for _, d in ipairs(data.forceWall) do
ModifyGateBJ(bj_GATEOPERATION_OPEN, d)
end
end
end
-- Reset aggro for units that left the battlefield
for u in whoWereHere:except(unitsInTheField):elements() do
ZTS_RemovePlayerUnit(u)
ZTS_AddPlayerUnit(u)
end
-- The chances of casting increases when has low hp
interval = getInterval(playersOnField:size(), GetUnitHPRatio(data.boss) < 0.5)
if current >= interval then
returned = false
local u = nil
local maxThreat = -1
for u2 in unitsInTheField:elements() do
if ignored[data.boss][u2] then
ZTS_RemovePlayerUnit(u2)
ZTS_AddPlayerUnit(u2)
else
local threat = ZTS_GetThreatUnitAmount(data.boss, u2)
if threat > maxThreat then
u = u2
maxThreat = threat
end
end
end
if u then
if not attacking then
attacking = true
local x, y = GetUnitX(u), GetUnitY(u)
Timed.call(2., function ()
if UnitCanAttack(data.boss) then
IssuePointOrderById(data.boss, Orders.attack, x, y)
end
end)
else
if data.spells then
if not isCasting[data.boss] then
if spellsCasted >= 0
and not BlzIsUnitInvulnerable(u)
and (GetUnitCurrentOrder(data.boss) == Orders.attack or GetUnitCurrentOrder(data.boss) == Orders.smart or GetUnitCurrentOrder(data.boss) == 0)
and (not data.castCondition or data.castCondition()) then
local chances = {}
local options = {}
for spell, stats in pairs(spells) do
if GetUnitAbilityLevel(data.boss, spell) > 0
and BlzGetUnitAbilityCooldownRemaining(data.boss, spell) <= 0
and BlzGetUnitAbilityManaCost(data.boss, spell, GetUnitAbilityLevel(data.boss, spell) - 1) <= GetUnitState(data.boss, UNIT_STATE_MANA) then
table.insert(options, stats)
chances[#options] = (chances[#options-1] or 0) + stats.weight
print(GetObjectName(spell), chances[#options])
end
end
if options[1] then
spellsCasted = 0
local r = chances[#chances] * math.random()
print(r)
for i = 1, #options do
if r < chances[i] then
local stats = options[i]
if stats.ttype == CastType.IMMEDIATE then
print("immediate", IssueImmediateOrderById(data.boss, stats.order))
elseif stats.ttype == CastType.POINT then
print("point", IssuePointOrderById(data.boss, stats.order, GetUnitX(u), GetUnitY(u)))
elseif stats.ttype == CastType.TARGET then
print("target", IssueTargetOrderById(data.boss, stats.order, u))
end
break
end
end
end
PauseSpellAI(data.boss, false)
end
end
end
end
else
IssuePointOrderById(data.boss, Orders.move, initialPosX, initialPosY)
end
data.actions(u, unitsInTheField)
end
end
if not isInBattlefield and not canLeave[data.boss] then
--reset()
IssuePointOrderById(data.boss, Orders.smart, initialPosX, initialPosY)
Timed.echo(0.5, 10., function ()
for i = 1, numRect do
isInBattlefield = RectContainsUnit(battlefield[data.boss][i], data.boss)
if isInBattlefield then
return true
end
end
end, function ()
reset()
SetUnitPosition(data.boss, initialPosX, initialPosY)
DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", initialPosX, initialPosY))
DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", data.boss, "origin"))
end)
end
-- If the boss is not doing anything, set attacking state to false
if GetUnitCurrentOrder(data.boss) == 0 then
attacking = false
end
else
if not dead then
dead = true
if playersOnField:contains(LocalPlayer) then
if playing then
playing = false
RestartMusic()
end
end
isCasting[data.boss] = false
if data.returnPlace then
local tm = CreateTimer()
local window = CreateTimerDialog(tm)
TimerDialogSetTitle(window, "Digimons returning in:")
ForUnitsInRect(data.toTeleport, function (u)
TimerDialogDisplay(window, GetOwningPlayer(u) == LocalPlayer)
end)
TimerStart(tm, 15., false, function ()
TimerDialogDisplay(window, false)
DestroyTimerDialog(window)
PauseTimer(tm)
DestroyTimer(tm)
ForUnitsInRect(data.toTeleport, function (u)
local p = GetOwningPlayer(u)
if IsPlayerInGame(p) then
local l = GetRandomLocInRect(data.returnPlace)
DestroyEffect(AddSpecialEffectLoc("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", l))
DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", GetUnitX(u), GetUnitY(u)))
SetUnitPositionLoc(u, l)
RemoveLocation(l)
if data.returnEnv then
local d = Digimon.getInstance(u)
if d then
d.environment = Environment.get(data.returnEnv)
coroutine.wrap(function ()
SyncSelections()
if IsUnitSelected(u, p) then
d.environment:apply(p, true)
if p == LocalPlayer then
PanCameraToTimed(GetUnitX(u), GetUnitY(u), 0.)
end
end
end)()
end
end
end
end)
end)
end
if data.forceWall then
for _, d in ipairs(data.forceWall) do
ModifyGateBJ(bj_GATEOPERATION_OPEN, d)
end
end
unitsInTheField:clear()
playersOnField:clear()
SetTextTagVisibility(advice, IsVisibleToPlayer(initialPosX, initialPosY, LocalPlayer))
if not data.manualRevive then
local remaining = 360.
Timed.echo(0.02, 360., function ()
remaining = remaining - 0.02
SetTextTagText(advice, "Revive in: " .. R2I(remaining), 0.023)
SetTextTagVisibility(advice, dead and IsVisibleToPlayer(initialPosX, initialPosY, LocalPlayer))
-- In case the boss revived for another reason
if UnitAlive(data.boss) then
onFinish()
return true
end
end, onFinish)
else
Timed.echo(1., function ()
if UnitAlive(data.boss) then
onFinish()
return true
end
end)
end
if data.onDeath then
data.onDeath()
end
end
end
if current >= interval then
current = 0
end
end)