From 1514ad12cab00619183ea64c2a80356c0e79930e Mon Sep 17 00:00:00 2001 From: neckrat Date: Sat, 25 Apr 2026 18:12:35 +0300 Subject: [PATCH] make php semantic real add new property to aversion to death effect fix beforeTurn function call in turnOrder --- lib/character/behaviors/effects.lua | 29 +++++++++-- lib/effectbook.lua | 22 +++++++- lib/level/turn_order.lua | 13 +++-- lib/spell/effect.lua | 78 ++++++++++++++++------------- lib/spell/spell.lua | 11 ++-- 5 files changed, 103 insertions(+), 50 deletions(-) diff --git a/lib/character/behaviors/effects.lua b/lib/character/behaviors/effects.lua index 1912295..6fa7581 100644 --- a/lib/character/behaviors/effects.lua +++ b/lib/character/behaviors/effects.lua @@ -26,10 +26,11 @@ end --- @param effect Effect --- @param stacks integer function behavior:addEffect(effect, stacks, intensity) - local task1 = effect:beforeBirth(self.owner, intensity) + local task1, birthStatement = effect:beforeBirth(self.owner, intensity) if task1 then task1(function() end) end + if birthStatement == false then return end -- избегаем значения nil -- проверяем эффект на возможности суммирования (aka противоречия) for i, ef in ipairs(self.effectsPriority) do if ef == effect then @@ -81,14 +82,19 @@ function behavior:deleteStacks(effect, amount) end end ---- должна вызываться перед смертью персонажа +--- должна вызываться перед смертью персонажа; +--- +--- возвращает, убивать ли персонажа +--- @return boolean function behavior:beforeDeath() for i, ef in ipairs(self.effectsPriority) do - local task1 = ef:beforeDeath(self.owner, self.effectsProperties[ef].intensity) + local task1, deathStatement = ef:beforeDeath(self.owner, self.effectsProperties[ef].intensity) if task1 then task1(function() end) end + if deathStatement == false then return false end end + return true end --- должна вызываться после смерти персонажа (может ли такая ситуация возникнуть вообще?) @@ -102,13 +108,18 @@ function behavior:afterDeath() end --- должен вызываться в начале хода +--- +--- возвращает, может ли персонаж сделать ход? +--- @return boolean function behavior:beforeTurn() for i, ef in ipairs(self.effectsPriority) do - local task1 = ef:beforeTurn(self.owner, self.effectsProperties[ef].intensity) + local task1, turnStatement = ef:beforeTurn(self.owner, self.effectsProperties[ef].intensity) if task1 then task1(function() end) end + if turnStatement == false then return false end end + return true end --- должен вызываться в конце хода @@ -122,13 +133,18 @@ function behavior:afterTurn() end --- должен вызываться перед кастом спелла +--- +--- возвращает, может ли персонаж скастовать спелл? +--- @return boolean function behavior:beforeCast() for i, ef in ipairs(self.effectsPriority) do - local task1 = ef:beforeCast(self.owner, self.effectsProperties[ef].intensity) + local task1, castStatement = ef:beforeCast(self.owner, self.effectsProperties[ef].intensity) if task1 then task1(function() end) end + if castStatement == false then return false end end + return true end --- должен вызываться после каста спелла @@ -142,6 +158,9 @@ function behavior:afterCast() end --- должен вызываться перед получением урона +--- +--- возвращает получаемый урон +--- @return integer function behavior:beforeDamage(damage) local totalDamage = damage for i, ef in ipairs(self.effectsPriority) do diff --git a/lib/effectbook.lua b/lib/effectbook.lua index aa3270c..1f39409 100644 --- a/lib/effectbook.lua +++ b/lib/effectbook.lua @@ -2,6 +2,9 @@ local task = require "lib.utils.task" local effect = require "lib.spell.effect" local easing = require "lib.utils.easing" +--- Кровотечение. +--- +--- Наносит `intensity` урона перед началом каждого хода. local bleeding = effect.new({ tag = "bleeding", afterBirth = function(owner, intensity) @@ -15,7 +18,7 @@ local bleeding = effect.new({ { intensity = 1, color = Vec3 { 0, 0., 0. } }, 800, easing.easeInCubic), function() light:die() return task.fromValue() - end) }) + end) }), true end }) @@ -24,7 +27,7 @@ function bleeding:beforeTurn(owner, intensity) local sprite = owner:has(Tree.behaviors.sprite) if not stats or not sprite then return end stats:dealDamage(intensity) - return task.wait({ sprite:animate("hurt") }) + return task.wait({ sprite:animate("hurt") }), true end function bleeding:afterTurn(owner, intensity) @@ -43,8 +46,12 @@ end function bleeding:beforeCast(owner, intensity) Tree.audio:play(Tree.assets.files.audio.sounds.meow) + return task.wait {}, true end +--- Отвращение к смерти. +--- +--- Спасает от смертельного урона, оставляя одно очко здоровья. Персонаж не может ходить до тех пор, пока эффект не сработает. local aversionToDeath = effect.new { tag = "dev_aversion_to_death" } @@ -58,6 +65,17 @@ function aversionToDeath:beforeDamage(owner, intensity, damage) -- тут должен быть какой-нибудь классный спецэффект, но я не умею в шейдеры return task.wait({}), stats.hp - 1 end + return task.wait {}, damage +end + +function aversionToDeath:beforeTurn(owner, intensity) + local sprite = owner:has(Tree.behaviors.sprite) + if not sprite then + return task.wait {}, false + end + return task.wait { + sprite:animate("hurt") + }, false end local effectbook = { diff --git a/lib/level/turn_order.lua b/lib/level/turn_order.lua index cea44cf..a166e62 100644 --- a/lib/level/turn_order.lua +++ b/lib/level/turn_order.lua @@ -43,16 +43,21 @@ function turnOrder:next() char:try(Tree.behaviors.positioned, function(positioned) Tree.level.camera:animateTo(positioned.position, 1500, easing.easeInOutCubic)( function() + -- проверяем, позволяют ли эффекты нам сходить + if char:try(Tree.behaviors.effects, function(effects) + -- print("[TurnOrder]: ну мы пытаемся применить эффект к", char.id) + return effects:beforeTurn() + end) == false then + self:next() + return + end + if char:has(Tree.behaviors.ai) then char:has(Tree.behaviors.ai):makeTurn()( function() self:next() end) else - char:try(Tree.behaviors.effects, function(effects) - -- print("[TurnOrder]: ну мы пытаемся применить эффект к", char.id) - effects:beforeTurn() - end) Tree.level.selector:unlock() Tree.level.selector:select(self.current) end diff --git a/lib/spell/effect.lua b/lib/spell/effect.lua index b8304cd..0816584 100644 --- a/lib/spell/effect.lua +++ b/lib/spell/effect.lua @@ -1,4 +1,5 @@ local utils = require "lib.utils.utils" +local task = require "lib.utils.task" --- @class Effect --- @field tag string @@ -6,83 +7,84 @@ local effect = {} effect.__index = effect --- Предполагается, что в каждую функцию будет передаваться `Character` и параметр `intensity`, который отвечает за силу спелла ---- @alias EffectFunc fun(owner: Character, intensity: integer): Task? ---- @alias EffectDamageFunc fun(owner: Character, intensity: integer, damage: integer): Task?, integer? ---- @alias EffectRegenFunc fun(owner: Character, intensity: integer, amountHp: integer): Task?, integer? ---- @alias EffectData { tag: string, [string]: EffectFunc|EffectDamageFunc|EffectRegenFunc } +--- @alias EffectFunc fun(owner: Character, intensity: integer): Task +--- @alias EffectStatementFunc fun(owner: Character, intensity: integer): Task, boolean +--- @alias EffectDamageFunc fun(owner: Character, intensity: integer, damage: integer): Task, integer +--- @alias EffectRegenFunc fun(owner: Character, intensity: integer, amountHp: integer): Task, integer +--- @alias EffectData { tag: string, [string]: EffectFunc|EffectStatementFunc|EffectDamageFunc|EffectRegenFunc } --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:beforeBirth(owner, intensity) end +--- @return Task, boolean +function effect:beforeBirth(owner, intensity) return task.wait {}, true end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterBirth(owner, intensity) end +--- @return Task +function effect:afterBirth(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:beforeDeath(owner, intensity) end +--- @return Task, boolean +function effect:beforeDeath(owner, intensity) return task.wait {}, true end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterDeath(owner, intensity) end +--- @return Task +function effect:afterDeath(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:beforeTurn(owner, intensity) end +--- @return Task, boolean +function effect:beforeTurn(owner, intensity) return task.wait {}, true end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterTurn(owner, intensity) end +--- @return Task +function effect:afterTurn(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:beforeCast(owner, intensity) end +--- @return Task, boolean +function effect:beforeCast(owner, intensity) return task.wait {}, true end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterCast(owner, intensity) end +--- @return Task +function effect:afterCast(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer --- @param damage integer ---- @return Task|nil, integer? -function effect:beforeAttack(owner, intensity, damage) end +--- @return Task, integer +function effect:beforeAttack(owner, intensity, damage) return task.wait {}, damage end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterAttack(owner, intensity) end +--- @return Task +function effect:afterAttack(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer --- @param damage integer ---- @return Task|nil, integer? -function effect:beforeDamage(owner, intensity, damage) end +--- @return Task, integer +function effect:beforeDamage(owner, intensity, damage) return task.wait {}, damage end --- @param owner Character --- @param intensity integer ---- @return Task|nil -function effect:afterDamage(owner, intensity) end +--- @return Task +function effect:afterDamage(owner, intensity) return task.wait {} end --- @param owner Character --- @param intensity integer --- @param amountHp integer кол-во хп для регена ---- @return Task|nil -function effect:beforeRegeneration(owner, intensity, amountHp) end +--- @return Task, integer +function effect:beforeRegeneration(owner, intensity, amountHp) return task.wait {}, amountHp end --- @param owner Character --- @param intensity integer ---- @return Task|nil, integer|nil -function effect:afterRegeneration(owner, intensity) end +--- @return Task +function effect:afterRegeneration(owner, intensity) return task.wait {} end --- @param other Effect --- @return Effect|nil @@ -110,7 +112,8 @@ local function new(data) function newEffect:beforeBirth(owner, intensity) if not data.beforeBirth then return end - return data.beforeBirth(owner, intensity) + local task, statement = data.beforeBirth(owner, intensity) + return task, statement end function newEffect:afterBirth(owner, intensity) @@ -120,7 +123,8 @@ local function new(data) function newEffect:beforeDeath(owner, intensity) if not data.beforeDeath then return end - return data.beforeDeath(owner, intensity) + local task, statement = data.beforeBirth(owner, intensity) + return task, statement end function newEffect:afterDeath(owner, intensity) @@ -130,7 +134,8 @@ local function new(data) function newEffect:beforeTurn(owner, intensity) if not data.beforeTurn then return end - return data.beforeTurn(owner, intensity) + local task, statement = data.beforeBirth(owner, intensity) + return task, statement end function newEffect:afterTurn(owner, intensity) @@ -140,7 +145,8 @@ local function new(data) function newEffect:beforeCast(owner, intensity) if not data.beforeCast then return end - return data.beforeCast(owner, intensity) + local task, statement = data.beforeBirth(owner, intensity) + return task, statement end function newEffect:afterCast(owner, intensity) diff --git a/lib/spell/spell.lua b/lib/spell/spell.lua index c033d16..11e3e45 100644 --- a/lib/spell/spell.lua +++ b/lib/spell/spell.lua @@ -123,6 +123,13 @@ function spell.new(data) return end + -- проверка на возможность каста + if not caster:try(Tree.behaviors.effects, function(effects) + return effects:beforeCast() + end) then + return + end + caster:try(Tree.behaviors.stats, function(stats) stats.mana = stats.mana - self.baseCost end) @@ -131,9 +138,7 @@ function spell.new(data) spellcaster.cooldowns[self.tag] = self.baseCooldown end) - caster:try(Tree.behaviors.effects, function(effects) - effects:beforeCast() - end) + return data.onCast(caster, target) end