Replace manual distance check with combined targetQuery and distance query intersection for cleaner spell targeting logic Fix query combinators to correctly reference self in closures
64 lines
2.7 KiB
Lua
64 lines
2.7 KiB
Lua
local Query = require "lib.spell.target_query"
|
||
local targetTest = require "lib.spell.target_test"
|
||
|
||
--- @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> | 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) end
|
||
|
||
function spell:draw() end
|
||
|
||
function spell:cast(caster, target) return end
|
||
|
||
--- Конструктор [Spell]
|
||
--- @param data {tag: string, baseCost: integer, baseCooldown: integer, targetQuery: SpellTargetQuery, distance: integer?, onCast: fun(caster: Character, target: Vec3): Task}
|
||
--- @return Spell
|
||
function spell.new(data)
|
||
local newSpell = {
|
||
tag = data.tag,
|
||
baseCost = data.baseCost,
|
||
baseCooldown = data.baseCooldown,
|
||
targetQuery = data.targetQuery,
|
||
distance = data.distance
|
||
}
|
||
|
||
function newSpell:cast(caster, target)
|
||
if not self.targetQuery:intersect(Query(targetTest.distance(self.distance))).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)
|
||
|
||
return data.onCast(caster, target)
|
||
end
|
||
|
||
return setmetatable(newSpell, spell)
|
||
end
|
||
|
||
return spell
|