Add counter utility and chain async animations in spell cast Introduce a Counter module to coordinate multiple asynchronous animation callbacks and update spellbook cast to run chained animations sequentially. Also lock selector during AI turns.
121 lines
4.5 KiB
Lua
121 lines
4.5 KiB
Lua
local PriorityQueue = require "lib.utils.priority_queue"
|
|
|
|
local initiativeComparator = function(id_a, id_b)
|
|
local res = Tree.level.characters[id_a]:try(Tree.behaviors.stats, function(astats)
|
|
local res = Tree.level.characters[id_b]:try(Tree.behaviors.stats, function(bstats)
|
|
return astats.initiative > bstats.initiative
|
|
end)
|
|
return res
|
|
end)
|
|
return res or false
|
|
end
|
|
|
|
--- @class TurnOrder
|
|
--- @field actedQueue PriorityQueue Очередь тех, кто сделал ход в текущем раунде
|
|
--- @field pendingQueue PriorityQueue Очередь тех, кто ждет своего хода в текущем раунде
|
|
--- @field current? Id Считаем того, кто сейчас ходит, отдельно, т.к. он ВСЕГДА первый в списке
|
|
--- @field isTurnsEnabled boolean
|
|
local turnOrder = {}
|
|
turnOrder.__index = turnOrder
|
|
|
|
local function new()
|
|
return setmetatable({
|
|
actedQueue = PriorityQueue.new(initiativeComparator),
|
|
pendingQueue = PriorityQueue.new(initiativeComparator),
|
|
isTurnsEnabled = true,
|
|
}, turnOrder)
|
|
end
|
|
|
|
--- Перемещаем активного персонажа в очередь сходивших
|
|
---
|
|
--- Если в очереди на ход больше никого нет, заканчиваем раунд
|
|
function turnOrder:next()
|
|
self.actedQueue:insert(self.current)
|
|
local next = self.pendingQueue:peek()
|
|
if not next then return self:endRound() end
|
|
self.current = self.pendingQueue:pop()
|
|
|
|
local char = Tree.level.characters[self.current]
|
|
char:try(Tree.behaviors.ai, function(ai)
|
|
Tree.level.selector:lock()
|
|
ai:makeTurn()(function()
|
|
Tree.level.selector:unlock()
|
|
self:next()
|
|
end)
|
|
end)
|
|
end
|
|
|
|
--- Меняем местами очередь сходивших и не сходивших (пустую)
|
|
function turnOrder:endRound()
|
|
assert(self.pendingQueue:size() == 0, "[TurnOrder]: tried to end the round before everyone had a turn")
|
|
print("[TurnOrder]: end of the round")
|
|
self.actedQueue, self.pendingQueue = self.pendingQueue, self.actedQueue
|
|
self.current = self.pendingQueue:pop()
|
|
end
|
|
|
|
--- Пересчитать очередность хода
|
|
function turnOrder:reorder()
|
|
local _acted, _pending = PriorityQueue.new(initiativeComparator), PriorityQueue.new(initiativeComparator)
|
|
|
|
--- сортировка отдельно кучи не ходивших и ходивших
|
|
while self.pendingQueue:peek() do
|
|
_pending:insert(self.pendingQueue:pop())
|
|
end
|
|
|
|
while self.actedQueue:peek() do
|
|
_acted:insert(self.actedQueue:pop())
|
|
end
|
|
|
|
self.actedQueue, self.pendingQueue = _acted, _pending
|
|
|
|
local t = {}
|
|
for id in self:getOrder(10) do
|
|
table.insert(t, id)
|
|
end
|
|
print("[TurnOrder]: next 10 turns")
|
|
print(table.concat(t, ", "))
|
|
end
|
|
|
|
--- Итератор по бесконечной цикличной очереди хода
|
|
--- @param count integer?
|
|
function turnOrder:getOrder(count)
|
|
local order = { self.current }
|
|
local _acted, _pending = self.actedQueue:copy(), self.pendingQueue:copy()
|
|
|
|
local i, j = 0, 0
|
|
local nextTurn = false -- если вышли за пределы текущего хода, то сортируем список, чтобы поставить активного персонажа на свое место
|
|
return function()
|
|
-------------------- Очередь этого хода: активный + не сходившие
|
|
i = i + 1
|
|
if count and count < 1 then return nil end
|
|
if count and i > count then return nil end
|
|
if i == 1 then return self.current end
|
|
|
|
if _pending:peek() then
|
|
local next = _pending:pop()
|
|
table.insert(order, next)
|
|
return next
|
|
end
|
|
|
|
-------------------- Очередь следующих ходов: цикл по всем персонажам в порядке инициативы
|
|
if not nextTurn then
|
|
while _acted:peek() do
|
|
table.insert(order, _acted:pop())
|
|
end
|
|
table.sort(order, initiativeComparator)
|
|
nextTurn = true
|
|
end
|
|
|
|
j = j + 1
|
|
if j % #order == 0 then return order[#order] end
|
|
return order[j % #order]
|
|
end
|
|
end
|
|
|
|
--- @param id Id
|
|
function turnOrder:add(id)
|
|
self.actedQueue:insert(id) -- новые персонажи по умолчанию попадают в очередь следующего хода
|
|
end
|
|
|
|
return { new = new }
|