Compare commits
No commits in common. "4431934e6b0ec71e54dc352b84a3e9f0d9501b47" and "2e6155aea4c59ac302c76ff59d50f718bf3f452d" have entirely different histories.
4431934e6b
...
2e6155aea4
@ -1,15 +1,14 @@
|
|||||||
local Query = require "lib.spell.target_query"
|
--- @alias SpellTarget "any" Любой тайл
|
||||||
local targetTest = require "lib.spell.target_test"
|
--- | "caster" Сам кастующий
|
||||||
|
--- | "enemy" Противники
|
||||||
|
--- | "ally" Союзники
|
||||||
|
--- | "character" Любой персонаж
|
||||||
|
|
||||||
--- @alias SpellPreview "default" Подсветка возможных целей
|
--- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell
|
||||||
--- | "path" Подсветка пути до цели
|
|
||||||
|
|
||||||
--- @class Spell
|
|
||||||
--- @field tag string
|
--- @field tag string
|
||||||
--- @field baseCost integer Базовые затраты маны на каст
|
--- @field baseCost integer Базовые затраты маны на каст
|
||||||
--- @field baseCooldown integer Базовый кулдаун в ходах
|
--- @field baseCooldown integer Базовый кулдаун в ходах
|
||||||
--- @field targetQuery SpellTargetQuery Селектор возможных целей
|
--- @field possibleTarget SpellTarget Возможная цель
|
||||||
--- @field previewType SpellPreview Вид превью во время каста
|
|
||||||
--- @field distance? integer Сторона квадрата с центром в позиции кастера, в пределах которого должна находиться цель, либо отсутствие ограничения
|
--- @field distance? integer Сторона квадрата с центром в позиции кастера, в пределах которого должна находиться цель, либо отсутствие ограничения
|
||||||
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
|
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
|
||||||
--- @field draw fun(self: Spell): nil Рисует превью каста, ничего не должна изменять в идеальном мире
|
--- @field draw fun(self: Spell): nil Рисует превью каста, ничего не должна изменять в идеальном мире
|
||||||
@ -19,8 +18,7 @@ spell.__index = spell
|
|||||||
spell.tag = "spell_base"
|
spell.tag = "spell_base"
|
||||||
spell.baseCost = 1
|
spell.baseCost = 1
|
||||||
spell.baseCooldown = 1
|
spell.baseCooldown = 1
|
||||||
spell.targetQuery = Query(targetTest.any)
|
spell.possibleTarget = "any"
|
||||||
spell.previewType = "default"
|
|
||||||
|
|
||||||
function spell:update(caster, dt) end
|
function spell:update(caster, dt) end
|
||||||
|
|
||||||
@ -28,15 +26,34 @@ function spell:draw() end
|
|||||||
|
|
||||||
function spell:cast(caster, target) return 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]
|
--- Конструктор [Spell]
|
||||||
--- @param data {tag: string, baseCost: integer, baseCooldown: integer, targetQuery: SpellTargetQuery, distance: integer?, onCast: fun(caster: Character, target: Vec3): Task}
|
--- @param data {tag: string, baseCost: integer, baseCooldown: integer, possibleTarget: SpellTarget, distance: integer?, onCast: fun(caster: Character, target: Vec3): Task}
|
||||||
--- @return Spell
|
--- @return Spell
|
||||||
function spell.new(data)
|
function spell.new(data)
|
||||||
local newSpell = {
|
local newSpell = {
|
||||||
tag = data.tag,
|
tag = data.tag,
|
||||||
baseCost = data.baseCost,
|
baseCost = data.baseCost,
|
||||||
baseCooldown = data.baseCooldown,
|
baseCooldown = data.baseCooldown,
|
||||||
targetQuery = data.targetQuery,
|
possibleTarget = data.possibleTarget,
|
||||||
distance = data.distance
|
distance = data.distance
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +67,8 @@ function spell.new(data)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.targetQuery.test(caster, target) then return end -- проверка корректности цели
|
-- проверка корректности цели
|
||||||
|
if not checkTarget(caster, self.possibleTarget, target) then return end
|
||||||
|
|
||||||
-- проверка на достаточное количество маны
|
-- проверка на достаточное количество маны
|
||||||
if caster:try(Tree.behaviors.stats, function(stats)
|
if caster:try(Tree.behaviors.stats, function(stats)
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
--- Тип, отвечающий за выбор и фильтрацию подходящих тайлов как цели спелла
|
|
||||||
--- теория множеств my beloved?
|
|
||||||
--- @class SpellTargetQuery
|
|
||||||
local query = {}
|
|
||||||
query.__index = query
|
|
||||||
|
|
||||||
--- Проверяет координаты на соответствие внутреннему условию
|
|
||||||
--- @param caster Character
|
|
||||||
--- @param position Vec3
|
|
||||||
--- @return boolean
|
|
||||||
function query.test(caster, position)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Объединение
|
|
||||||
--- @param q SpellTargetQuery
|
|
||||||
function query:join(q)
|
|
||||||
return setmetatable({
|
|
||||||
test = function(caster, pos)
|
|
||||||
return self.test(caster, pos) or q.test(caster, pos)
|
|
||||||
end
|
|
||||||
}, q)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Пересечение
|
|
||||||
--- @param q SpellTargetQuery
|
|
||||||
function query:intersect(q)
|
|
||||||
return setmetatable({
|
|
||||||
test = function(caster, pos)
|
|
||||||
return self.test(caster, pos) and q.test(caster, pos)
|
|
||||||
end
|
|
||||||
}, q)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Исключение (не коммутативное, "те, что есть в query, но нет в q")
|
|
||||||
--- @param q SpellTargetQuery
|
|
||||||
function query:exclude(q)
|
|
||||||
return setmetatable({
|
|
||||||
test = function(caster, pos)
|
|
||||||
return self.test(caster, pos) and not q.test(caster, pos)
|
|
||||||
end
|
|
||||||
}, q)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Находит все соответствующие условиям координаты тайлов и возвращает их в виде списка
|
|
||||||
--- @param caster Character
|
|
||||||
--- @return Vec3[]
|
|
||||||
function query:asSet(caster)
|
|
||||||
--- @TODO: оптимизировать и брать не всю карту для выборки
|
|
||||||
local res = {}
|
|
||||||
for _, tile in pairs(Tree.level.tileGrid) do
|
|
||||||
if self.test(caster, tile.position) then
|
|
||||||
table.insert(res, tile.position)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @param test SpellTargetTest
|
|
||||||
local function new(test)
|
|
||||||
return setmetatable({
|
|
||||||
test = test
|
|
||||||
}, query)
|
|
||||||
end
|
|
||||||
|
|
||||||
return new
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
--- @alias SpellTargetTest fun(caster: Character, targetPosition: Vec3) : boolean
|
|
||||||
|
|
||||||
return {
|
|
||||||
any = function() return true end,
|
|
||||||
caster = function(caster, targetPosition)
|
|
||||||
local targetCharacterId = Tree.level.characterGrid:get(targetPosition)
|
|
||||||
return caster.id == targetCharacterId
|
|
||||||
end,
|
|
||||||
character = function(caster, targetPosition)
|
|
||||||
local targetCharacterId = Tree.level.characterGrid:get(targetPosition)
|
|
||||||
return not not targetCharacterId
|
|
||||||
end
|
|
||||||
}
|
|
||||||
@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
local task = require 'lib.utils.task'
|
local task = require 'lib.utils.task'
|
||||||
local spell = require 'lib.spell.spell'
|
local spell = require 'lib.spell.spell'
|
||||||
local targetTest = require 'lib.spell.target_test'
|
|
||||||
local Query = require "lib.spell.target_query"
|
|
||||||
|
|
||||||
local walk = setmetatable({
|
local walk = setmetatable({
|
||||||
--- @type Deque
|
--- @type Deque
|
||||||
@ -71,7 +69,7 @@ local regenerateMana = spell.new {
|
|||||||
tag = "dev_mana",
|
tag = "dev_mana",
|
||||||
baseCooldown = 2,
|
baseCooldown = 2,
|
||||||
baseCost = 0,
|
baseCost = 0,
|
||||||
targetQuery = Query(targetTest.caster),
|
possibleTarget = "caster",
|
||||||
distance = 0,
|
distance = 0,
|
||||||
onCast = function(caster, target)
|
onCast = function(caster, target)
|
||||||
caster:try(Tree.behaviors.stats, function(stats)
|
caster:try(Tree.behaviors.stats, function(stats)
|
||||||
@ -86,6 +84,7 @@ local regenerateMana = spell.new {
|
|||||||
local light = require "lib/character/character".spawn("Light Effect")
|
local light = require "lib/character/character".spawn("Light Effect")
|
||||||
light:addBehavior {
|
light:addBehavior {
|
||||||
Tree.behaviors.light.new { color = Vec3 { 0.6, 0.3, 0.3 }, intensity = 4 },
|
Tree.behaviors.light.new { color = Vec3 { 0.6, 0.3, 0.3 }, intensity = 4 },
|
||||||
|
Tree.behaviors.residentsleeper.new(),
|
||||||
Tree.behaviors.positioned.new(caster:has(Tree.behaviors.positioned).position + Vec3 { 0.5, 0.5 }),
|
Tree.behaviors.positioned.new(caster:has(Tree.behaviors.positioned).position + Vec3 { 0.5, 0.5 }),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ local attack = spell.new {
|
|||||||
tag = "dev_attack",
|
tag = "dev_attack",
|
||||||
baseCooldown = 1,
|
baseCooldown = 1,
|
||||||
baseCost = 2,
|
baseCost = 2,
|
||||||
targetQuery = Query(targetTest.character):exclude(Query(targetTest.caster)),
|
possibleTarget = "enemy",
|
||||||
distance = 1,
|
distance = 1,
|
||||||
onCast = function(caster, target)
|
onCast = function(caster, target)
|
||||||
--- @type Character
|
--- @type Character
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user