101 lines
5.3 KiB
Lua
101 lines
5.3 KiB
Lua
--- Алгоритм обработки заклинания (for dummies):
|
||
--- 1) ПОКА выделен персонаж И он находится в режиме каста, вызывать spell:update() и spell:draw() каждый кадр (это отвечает за обработку и отрисовку превьюшки каста, например, превью пути или зоны поражения; реализуется через установку spellcaster.cast, см. код в кнопке)
|
||
--- ЕСЛИ выбран тайл, ТО вызвать spell:cast() (это запрос на обработку последствий применения заклинания, например, старт анимации ходьбы, выпуск снаряда и т.д.; реализовано в selector)
|
||
--- ЕСЛИ spell:cast() ИСТИНА, ТО вызвать selector:lock() (отключить обработку выделения всего на уровне; реализовано в selector)
|
||
---
|
||
--- 2) ПОКА анимация каста НЕ завершена, ничего не делать, ИНАЧЕ вызвать behaviors.spellcaster:endCast() (вот это сейчас нужно вызывать самостоятельно, т.к. нет возможности обобщенно отследить завершение анимаций)
|
||
--- --TODO: каждый каст должен возвращать объект, который позволит отследить момент завершения анимации спелла
|
||
--- Да, это Future/Promise/await/async
|
||
|
||
--- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell
|
||
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
|
||
--- @field draw fun(self: Spell): nil Рисует превью каста, ничего не должна изменять в идеальном мире
|
||
--- @field cast fun(self: Spell, caster: Character, target: Vec3): boolean Вызывается в момент каста, изменяет мир. Возвращает bool в зависимости от того, получилось ли скастовать
|
||
local spell = {}
|
||
spell.__index = spell
|
||
|
||
function spell:update(caster, dt) end
|
||
|
||
function spell:draw() end
|
||
|
||
function spell:cast(caster, target) return true end
|
||
|
||
local walk = setmetatable({
|
||
--- @type Deque
|
||
path = nil
|
||
}, spell)
|
||
|
||
function walk:cast(caster, target)
|
||
if not caster:try(Tree.behaviors.stats, function (stats)
|
||
return stats.mana >= 2
|
||
end) then return false end
|
||
|
||
local path = self.path
|
||
if path:is_empty() then return false end
|
||
path:pop_front()
|
||
for p in path:values() do print(p) end
|
||
caster:has(Tree.behaviors.map):followPath(path, function()
|
||
caster:has(Tree.behaviors.spellcaster):endCast()
|
||
end)
|
||
-- TODO: списать деньги за каст (антиутопия какая-то)
|
||
-- TODO: привязка тинькоффа
|
||
caster:try(Tree.behaviors.stats, function (stats)
|
||
stats.mana = stats.mana - 2
|
||
print(stats.mana)
|
||
end)
|
||
return true
|
||
end
|
||
|
||
function walk:update(caster, dt)
|
||
local charPos = caster:has(Tree.behaviors.map).position:floor()
|
||
--- @type Vec3
|
||
local mpos = Tree.level.camera:toWorldPosition(Vec3 { love.mouse.getX(), love.mouse.getY() }):floor()
|
||
self.path = require "lib.pathfinder" (charPos, mpos)
|
||
end
|
||
|
||
function walk:draw()
|
||
if not self.path then return end
|
||
--- Это отрисовка пути персонажа к мышке
|
||
love.graphics.setColor(0.6, 0.75, 0.5)
|
||
for p in self.path:values() do
|
||
love.graphics.circle("fill", p.x + 0.45, p.y + 0.45, 0.1)
|
||
end
|
||
love.graphics.setColor(1, 1, 1)
|
||
end
|
||
|
||
local regenerateMana = setmetatable({}, spell)
|
||
|
||
function regenerateMana:cast(caster, target)
|
||
caster:try(Tree.behaviors.stats, function (stats)
|
||
stats.mana = 10
|
||
end)
|
||
print(caster.id, "has regenerated mana")
|
||
caster:try(Tree.behaviors.sprite, function (sprite) -- бойлерплейт (временный)
|
||
-- В данный момент заклинание не позволяет отслеживать состояние последствий своего применения, так что надо повесить хоть какую-то анимашку просто для того, чтобы отложить завершение каста куда-то в будущее
|
||
-- См. также https://learn.javascript.ru/settimeout-setinterval
|
||
sprite:play("hurt", function ()
|
||
sprite:play("idle")
|
||
caster:has(Tree.behaviors.spellcaster):endCast()
|
||
end)
|
||
end)
|
||
return true
|
||
end
|
||
|
||
----------------------------------------
|
||
local spellbook = {
|
||
walk = walk,
|
||
regenerateMana = regenerateMana
|
||
}
|
||
|
||
--- Создает новый спеллбук с уникальными спеллами (а не ссылками на шаблоны)
|
||
--- @param list Spell[]
|
||
function spellbook.of(list)
|
||
local spb = {}
|
||
for i, sp in ipairs(list) do
|
||
spb[i] = setmetatable({}, { __index = sp })
|
||
end
|
||
return spb
|
||
end
|
||
|
||
return spellbook
|