PeaAshMeter 2e96ec821d Add cooldown handling for spells and display in UI
- Implement cooldown tracking in SpellcasterBehavior
- Decrease cooldowns at end of each round in turn order
- Prevent casting spells on cooldown in spell.cast
- Show cooldown overlay and block click on skill buttons
- Adjust font sizes for better UI consistency
2026-03-18 05:09:35 +03:00

105 lines
4.3 KiB
Lua
Raw Permalink 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.

local Query = require "lib.spell.target_query"
local targetTest = require "lib.spell.target_test"
local task = require "lib.utils.task"
--- @alias SpellPreview "default" Подсветка возможных целей
--- | "path" Подсветка пути до цели
--- @class Spell
--- @field tag string
--- @field baseCost integer Базовые затраты маны на каст
--- @field baseCooldown integer Базовый кулдаун в ходах
--- @field targetQuery SpellTargetQuery Селектор возможных целей
--- @field previewType SpellPreview Вид превью во время каста
--- @field distance? integer Сторона квадрата с центром в позиции кастера, в пределах которого должна находиться цель, либо отсутствие ограничения
--- @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): Task<nil>? Вызывается в момент каста, изменяет мир.
local spell = {}
spell.__index = spell
spell.tag = "spell_base"
spell.baseCost = 1
spell.baseCooldown = 1
spell.targetQuery = Query(targetTest.any)
spell.previewType = "default"
function spell:update(caster, dt)
if self.previewType == "path" then
local charPos = caster:has(Tree.behaviors.positioned).position:floor()
--- @type Vec3
local mpos = Tree.level.camera:toWorldPosition(Vec3 { love.mouse.getX(), love.mouse.getY() }):floor()
if self.targetQuery.test(caster, mpos) then
self.path = require "lib.pathfinder" (charPos, mpos)
else
self.path = nil
end
end
end
function spell:draw()
if self.previewType == "path" then
local path = self.path --[[@as Deque?]]
if not path then return end
--- Это отрисовка пути персонажа к мышке
Tree.level.camera:attach()
love.graphics.setCanvas(Tree.level.render.textures.overlayLayer)
love.graphics.setColor(0.6, 0.75, 0.5)
for p in path:values() do
love.graphics.circle("fill", p.x + 0.45, p.y + 0.45, 0.1)
end
love.graphics.setCanvas()
Tree.level.camera:detach()
love.graphics.setColor(1, 1, 1)
end
end
function spell:cast(caster, target) return task.fromValue() end
--- Конструктор [Spell]
--- @param data {tag: string, baseCost: integer, baseCooldown: integer, targetQuery: SpellTargetQuery?, previewType: SpellPreview?, distance: integer?, onCast: fun(caster: Character, target: Vec3): Task<nil>?}
--- @return Spell
function spell.new(data)
local newSpell = setmetatable({
tag = data.tag,
baseCost = data.baseCost,
baseCooldown = data.baseCooldown,
targetQuery = data.targetQuery,
previewType = data.previewType,
distance = data.distance
}, spell)
newSpell.targetQuery = newSpell.distance
and newSpell.targetQuery:intersect(Query(targetTest.distance(newSpell.distance)))
or newSpell.targetQuery
function newSpell:cast(caster, target)
if caster:try(Tree.behaviors.spellcaster, function(spellcaster) -- проверка на кулдаун
return (spellcaster.cooldowns[self.tag] or 0) > 0
end) then
return
end
if not self.targetQuery.test(caster, target) then return end -- проверка корректности цели
-- проверка на достаточное количество маны
if caster:try(Tree.behaviors.stats, function(stats)
return stats.mana < self.baseCost
end) then
return
end
caster:try(Tree.behaviors.stats, function(stats)
stats.mana = stats.mana - self.baseCost
end)
caster:try(Tree.behaviors.spellcaster, function(spellcaster)
spellcaster.cooldowns[self.tag] = self.baseCooldown
end)
return data.onCast(caster, target)
end
return newSpell
end
return spell