feature/spell-constraints #32

Merged
PeaAshMeter merged 11 commits from feature/spell-constraints into main 2026-03-18 05:11:55 +03:00
2 changed files with 60 additions and 34 deletions
Showing only changes of commit 2e6155aea4 - Show all commits

View File

@ -26,6 +26,25 @@ 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, possibleTarget: SpellTarget, 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
@ -39,9 +58,6 @@ function spell.new(data)
} }
function newSpell:cast(caster, target) function newSpell:cast(caster, target)
-- проверка корректности цели
--- @TODO имплементировать все варианты SpellTarget
-- проверка на расстояние до цели -- проверка на расстояние до цели
if self.distance and caster:try(Tree.behaviors.positioned, function(p) 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)) local dist = math.max(math.abs(p.position.x - target.x), math.abs(p.position.y - target.y))
@ -51,6 +67,9 @@ function spell.new(data)
return return
end 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)
return stats.mana < self.baseCost return stats.mana < self.baseCost
@ -58,6 +77,10 @@ function spell.new(data)
return return
end end
caster:try(Tree.behaviors.stats, function(stats)
stats.mana = stats.mana - self.baseCost
end)
return data.onCast(caster, target) return data.onCast(caster, target)
end end

View File

@ -65,51 +65,54 @@ function walk:draw()
love.graphics.setColor(1, 1, 1) love.graphics.setColor(1, 1, 1)
end end
local regenerateMana = setmetatable({}, spell) local regenerateMana = spell.new {
regenerateMana.tag = "dev_mana" tag = "dev_mana",
baseCooldown = 2,
baseCost = 0,
possibleTarget = "caster",
distance = 0,
onCast = function(caster, target)
caster:try(Tree.behaviors.stats, function(stats)
stats.mana = 10
stats.initiative = stats.initiative + 10
end)
function regenerateMana:cast(caster, target) local sprite = caster:has(Tree.behaviors.sprite)
caster:try(Tree.behaviors.stats, function(stats) if not sprite then return task.fromValue() end
stats.mana = 10 print(caster.id, "has regenerated mana and gained initiative")
stats.initiative = stats.initiative + 10
end)
local sprite = caster:has(Tree.behaviors.sprite) local light = require "lib/character/character".spawn("Light Effect")
if not sprite then return nil end light:addBehavior {
print(caster.id, "has regenerated mana and gained initiative") 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 }),
}
local light = require "lib/character/character".spawn("Light Effect") local flash = function(callback)
light:addBehavior { light:has(Tree.behaviors.light):animateColor(Vec3 {})(
Tree.behaviors.light.new { color = Vec3 { 0.6, 0.3, 0.3 }, intensity = 4 }, function()
Tree.behaviors.residentsleeper.new(), light:die()
Tree.behaviors.positioned.new(caster:has(Tree.behaviors.positioned).position + Vec3 { 0.5, 0.5 }), callback()
} end
)
end
local flash = function(callback) return task.wait {
light:has(Tree.behaviors.light):animateColor(Vec3 {})( flash,
function() sprite:animate("hurt")
light:die() }
callback()
end
)
end end
}
return task.wait {
flash,
sprite:animate("hurt")
}
end
local attack = spell.new { local attack = spell.new {
tag = "dev_attack", tag = "dev_attack",
baseCooldown = 1, baseCooldown = 1,
baseCost = 2, baseCost = 2,
possibleTarget = "enemy", possibleTarget = "enemy",
distance = 2, distance = 1,
onCast = function(caster, target) onCast = function(caster, target)
--- @type Character --- @type Character
local targetCharacterId = Tree.level.characterGrid:get(target) local targetCharacterId = Tree.level.characterGrid:get(target)
if not targetCharacterId or targetCharacterId == caster.id then return task.fromValue() end
local targetCharacter = Tree.level.characters[targetCharacterId] local targetCharacter = Tree.level.characters[targetCharacterId]
targetCharacter:try(Tree.behaviors.stats, function(stats) targetCharacter:try(Tree.behaviors.stats, function(stats)
stats.hp = stats.hp - 4 stats.hp = stats.hp - 4