91 lines
3.7 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.

--- @alias SpellTarget "any" Любой тайл
--- | "caster" Сам кастующий
--- | "enemy" Противники
--- | "ally" Союзники
--- | "character" Любой персонаж
--- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell
--- @field tag string
--- @field baseCost integer Базовые затраты маны на каст
--- @field baseCooldown integer Базовый кулдаун в ходах
--- @field possibleTarget SpellTarget Возможная цель
--- @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.possibleTarget = "any"
function spell:update(caster, dt) end
function spell:draw() end
function spell:cast(caster, target) return end
--- @param caster Character
--- @param spellTarget SpellTarget
--- @param targetPosition Vec3
local function checkTarget(caster, spellTarget, targetPosition)
--- @TODO имплементировать все варианты SpellTarget
local targetCharacterId = Tree.level.characterGrid:get(targetPosition)
if spellTarget == "caster" then
return targetCharacterId == caster.id
end
if spellTarget == "character" then
return not not targetCharacterId
end
if spellTarget == "enemy" then
return targetCharacterId and targetCharacterId ~= caster.id
end
return true
end
--- Конструктор [Spell]
--- @param data {tag: string, baseCost: integer, baseCooldown: integer, possibleTarget: SpellTarget, 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,
possibleTarget = data.possibleTarget,
distance = data.distance
}
function newSpell:cast(caster, target)
-- проверка на расстояние до цели
if self.distance and caster:try(Tree.behaviors.positioned, function(p)
local dist = math.max(math.abs(p.position.x - target.x), math.abs(p.position.y - target.y))
print("dist:", dist)
return dist > self.distance
end) then
return
end
-- проверка корректности цели
if not checkTarget(caster, self.possibleTarget, 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