heroes-of-nerevelon/lib/spellbook.lua

104 lines
5.3 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- Алгоритм обработки заклинания (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
path:pop_front()
if path:is_empty() then return false end
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