Compare commits

..

No commits in common. "main" and "rework/rendering" have entirely different histories.

44 changed files with 44 additions and 610 deletions

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
*.ogg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text

View File

@ -6,6 +6,5 @@
"love.filesystem.load": "loadfile"
},
"workspace.ignoreDir": ["dev_utils"],
"diagnostics.ignoredFiles": "Disable",
"hint.enable": true
"diagnostics.ignoredFiles": "Disable"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/audio/sounds/meow.ogg (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -9,6 +9,5 @@ Tree.behaviors.positioned = require "character.behaviors.positioned"
Tree.behaviors.tiled = require "character.behaviors.tiled"
Tree.behaviors.cursor = require "character.behaviors.cursor"
Tree.behaviors.ai = require "lib.character.behaviors.ai"
Tree.behaviors.effects = require "lib.character.behaviors.effects"
--- @alias voidCallback fun(): nil

View File

@ -1,7 +1,6 @@
local easing = require "lib.utils.easing"
local pf = require "lib.pathfinder"
local utils = require "lib.utils.utils"
local task = require "lib.utils.task"
local pf = require "lib.pathfinder"
local utils = require "lib.utils.utils"
--- @alias AIAction fun(self: AIBehavior): Task<nil>
@ -157,16 +156,6 @@ local behavior = {}
behavior.__index = behavior
behavior.id = "ai"
--- Заставляет ИИ сделать ход
---
--- По умолчанию ничего не делает
--- @return Task<nil>
function behavior:makeTurn()
return function(callback)
callback()
end
end
--- @param class Class
function behavior.new(class)
return setmetatable({

View File

@ -1,187 +0,0 @@
local task = require "lib.utils.task"
local efb = require "lib.effectbook"
local book = efb.book
--- ===========ЛОГИКА ЭФФЕКТОВ И ЧТО С ЭТИМ ЕДЯТ===========
--- читать здесь: https://docs.google.com/document/d/1Hxa5dOLaeRpLQOs5H-oIDDuLLhKbDw40lR9d62Zb4Tg/edit?usp=sharing
--- и здесь: https://docs.google.com/document/d/1jvhuM3mxqYSQTEM8m-WL-uUSie9QRsZOCCUEiw9ZqzM/edit?tab=t.0
--- behavior thats holds all effects that we applied
--- @class EffectsBehavior : Behavior
--- @field effectsPriority EffectTag[] хранит эффекты в порядке их применения
--- @field effectsProperties table<EffectTag, { stacks: integer, intensity: integer }> хранит характеристики эффектов
local behavior = {}
behavior.__index = behavior
behavior.id = "effects"
--- @return EffectsBehavior
function behavior.new()
return setmetatable({
effectsPriority = {},
effectsProperties = {},
}, behavior)
end
--- проверяет, можно ли наложить эффект и при наложении его применяет
--- @param effect EffectTag
--- @param stacks integer
--- @param intensity integer
function behavior:addEffect(effect, stacks, intensity)
local task1, birthStatement = book[effect]:beforeBirth(self.owner, intensity)
if task1 then
task1(function() end)
end
if not birthStatement then return end
-- проверка на сумму, и её применение
for i, ef in ipairs(self.effectsPriority) do
if efb.sums[effect] then
if efb.sums[effect][ef] then
if not efb.sums[effect][ef](self.owner, effect, ef) then return end
end
elseif efb.sums[ef] then
if efb.sums[ef][effect] then
if not efb.sums[ef][effect](self.owner, ef, effect) then return end
end
end
end
book[effect]:onBirth(self.owner, stacks, intensity)
local task3 = book[effect]:afterBirth(self.owner, intensity)
if task3 then
task3(function()
print("[Effects]: мы применили эффект!!")
end)
end
end
--- Удаляет один эффект по порядку
--- @param effect EffectTag
function behavior:deleteEffect(effect)
self.effectsProperties[effect] = nil
for i, ef in ipairs(self.effectsPriority) do
if ef == effect then
table.remove(self.effectsPriority, i)
return
end
end
end
--- О ДААА ЭТА ФУНКЦИЯ МЕНЯЕТ СОСТОЯНИЕ О ДАААААА О ДАААААААААА
--- @param effect EffectTag
--- @param amount integer
function behavior:deleteStacks(effect, amount)
print("[Effects]: удаляем стаки!!")
self.effectsProperties[effect].stacks = self.effectsProperties[effect].stacks -
amount -- !!!!!!!!!!!!!!!! <<<<< 21+ only
if self.effectsProperties[effect].stacks <= 0 then
print("[Effects]:", effect, "ДОЛЖЕН БЫТЬ СТЁРТ")
self:deleteEffect(effect)
print("[Effects]:", effect, "СТЁРТ")
end
end
--- должна вызываться перед смертью персонажа;
---
--- возвращает, убивать ли персонажа
--- @return boolean
function behavior:beforeDeath()
for i, ef in ipairs(self.effectsPriority) do
local task1, deathStatement = book[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
--- должна вызываться после смерти персонажа (может ли такая ситуация возникнуть вообще?)
function behavior:afterDeath()
for i, ef in ipairs(self.effectsPriority) do
local task1 = book[ef]:afterDeath(self.owner, self.effectsProperties[ef].intensity)
if task1 then
task1(function() end)
end
end
end
--- должен вызываться в начале хода
---
--- возвращает, может ли персонаж сделать ход?
--- @return boolean
function behavior:beforeTurn()
for i, ef in ipairs(self.effectsPriority) do
local task1, turnStatement = book[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
--- должен вызываться в конце хода
function behavior:afterTurn()
for i, ef in ipairs(self.effectsPriority) do
local task1 = book[ef]:afterTurn(self.owner, self.effectsProperties[ef].intensity)
if task1 then
task1(function() end)
end
end
end
--- должен вызываться перед кастом спелла
---
--- возвращает, может ли персонаж скастовать спелл?
--- @return boolean
function behavior:beforeCast()
for i, ef in ipairs(self.effectsPriority) do
local task1, castStatement = book[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
--- должен вызываться после каста спелла
function behavior:afterCast()
for i, ef in ipairs(self.effectsPriority) do
local task1 = book[ef]:afterCast(self.owner, self.effectsProperties[ef].intensity)
if task1 then
task1(function() end)
end
end
end
--- должен вызываться перед получением урона
---
--- возвращает получаемый урон
--- @return integer
function behavior:beforeDamage(damage)
local totalDamage = damage
for i, ef in ipairs(self.effectsPriority) do
local task1
task1, totalDamage = book[ef]:beforeDamage(self.owner, self.effectsProperties[ef].intensity,
totalDamage or damage)
if task1 then
task1(function() end)
end
end
return totalDamage or damage
end
--- должен вызываться после получения урона
function behavior:afterDamage()
for i, ef in ipairs(self.effectsPriority) do
local task1 = book[ef]:afterDamage(self.owner, self.effectsProperties[ef].intensity)
if task1 then
task1(function() end)
end
end
end
return behavior

View File

@ -20,9 +20,6 @@ function behavior.new(spellbook)
end
function behavior:endCast()
self.owner:try(Tree.behaviors.effects, function(effects)
effects:afterCast()
end)
self.state = "idle"
self.cast = nil
Tree.level.turnOrder:reorder()

View File

@ -6,27 +6,10 @@
--- @field initiative integer
--- @field class Class
--- @field isInTurnOrder boolean
--- @field amIAlive boolean
local behavior = {}
behavior.__index = behavior
behavior.id = "stats"
--- план прост, если что-то не так, то мы просто убиваем бехавиор (по крайней мере так должно было быть, но пиаш мне запретил :sob:)
function behavior:checkStats()
-- if self.hp <= 0 then behavior:die() end
if self.hp <= 0 then
self.amIAlive = false
end
end
--- @param damage integer
function behavior:dealDamage(damage)
local effects = self.owner:has(Tree.behaviors.effects)
if effects then damage = effects:beforeDamage(damage) end
self.hp = self.hp - damage
self:checkStats()
end
--- @param hp? integer
--- @param mana? integer
--- @param initiative? integer
@ -39,7 +22,6 @@ function behavior.new(hp, mana, initiative, class, isInTurnOrder)
initiative = initiative or 10,
class = class or "dev_warrior",
isInTurnOrder = isInTurnOrder or true,
amIAlive = true
}, behavior)
end

View File

@ -1,123 +0,0 @@
local task = require "lib.utils.task"
local effect = require "lib.spell.effect"
local easing = require "lib.utils.easing"
--- некое уникальное строковое значение
--- @alias EffectTag string
--- Кровотечение.
---
--- Наносит `intensity` урона перед началом каждого хода.
local bleeding = effect.new({
tag = "bleeding"
})
function bleeding:afterBirth(owner, intensity)
local light = require "lib/character/character".spawn("Bleeding Light Effect")
light:addBehavior {
Tree.behaviors.light.new { color = Vec3 { 1, 0., 0. }, intensity = 4 },
Tree.behaviors.positioned.new(owner:has(Tree.behaviors.positioned).position + Vec3 { 0.5, 0.5 }),
}
return task.wait({ task.chain(task.tween(light:has(Tree.behaviors.light) --[[@as LightBehavior]],
{ intensity = 1, color = Vec3 { 0, 0., 0. } }, 800, easing.easeInCubic), function()
light:die()
return task.fromValue()
end) })
end
function bleeding:beforeTurn(owner, intensity)
local stats = owner:has(Tree.behaviors.stats)
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") }), true
end
function bleeding:afterTurn(owner, intensity)
local behavior = owner:has(Tree.behaviors.effects)
if not behavior then
print('[EffectBook]: yo man what the hell wheres your behavior how thats possible please stop thats not normal')
else
behavior:deleteStacks("bleeding", 1)
end
return task.wait {}
end
--- meow
function bleeding:afterCast(owner, intensity)
Tree.audio:play(Tree.assets.files.audio.sounds.meow)
return task.wait {}
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 = "aversionToDeath"
}
function aversionToDeath:beforeDamage(owner, intensity, damage)
local stats = owner:has(Tree.behaviors.stats)
local effects = owner:has(Tree.behaviors.effects)
if not stats or not effects then return end
if stats.hp <= damage then
effects:deleteStacks("aversionToDeath", 1)
-- тут должен быть какой-нибудь классный спецэффект, но я не умею в шейдеры
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
----------------- Effectbook & Sum -----------------
--- @alias EffectSumFunc fun(owner: Character, effect1: EffectTag, effect2: EffectTag): boolean
--- Принимает таблицу, в ключах которых тэги эффектов, которые мы хотим просуммировать, и в значениях которых функция,
--- возвращающая булево значение: применять ли эффект после суммирования.
--- @type table<EffectTag, table<EffectTag, EffectSumFunc>>
local sums = {}
--- Сумма кровотечения и отвращения к смерти, (в целях разработки) удаляет оба эффекта, не позволяя дальше применять эффект
sums.bleeding = {
aversionToDeath = function(owner, effect1, effect2)
print("[EffectBook]: применяем сумму, удаляем оба эффекта")
local behaviorEffect = owner:has(Tree.behaviors.effects)
if not behaviorEffect then
print(
"[EffectBook]: yo man what the hell wheres your behavior how thats possible please stop thats not normal")
return true
end
behaviorEffect:deleteEffect(effect1)
behaviorEffect:deleteEffect(effect2)
return false
end
}
--- @class EffectBook
--- @field sums table<EffectTag, table<EffectTag, EffectSumFunc>>
--- @field book table<EffectTag, Effect>
local effectbook = {
sums = sums,
book = {
bleeding = bleeding,
aversionToDeath = aversionToDeath
}
}
return effectbook

View File

@ -1,6 +1,8 @@
local utils = require "lib.utils.utils"
local pQueue = require "lib.utils.priority_queue"
--- @class CharacterGrid : Grid
--- @field __grid {string: Id|nil}
--- @field yOrderQueue PriorityQueue<Character> очередь отрисовки сверху вниз
local grid = setmetatable({}, require "lib.level.grid.base")
grid.__index = grid
@ -27,13 +29,22 @@ function grid:add(id)
end
end
--- @param a Character
--- @param b Character
local function drawCmp(a, b)
--- @TODO: это захардкожено, надо разделить поведения
return a:has(Tree.behaviors.positioned).position.y < b:has(Tree.behaviors.positioned).position.y
end
--- fills the grid with the actual data
---
--- should be called as early as possible during every tick
function grid:reload()
self:reset()
self.yOrderQueue = pQueue.new(drawCmp)
utils.each(Tree.level.characters, function(c)
self:add(c.id)
self.yOrderQueue:insert(c)
end)
end

View File

@ -20,7 +20,7 @@ local function new(type, template)
local size = Vec3 { 30, 30 } -- magic numbers for testing purposes only
print(type, template, size)
Tree.audio:play(Tree.assets.files.audio.music.level1.progressive_plains)
Tree.audio:play(Tree.assets.files.audio.music.level1.battle)
return setmetatable({
size = size,

View File

@ -43,15 +43,6 @@ 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()
@ -78,9 +69,6 @@ function turnOrder:endRound()
char:try(Tree.behaviors.spellcaster, function(spellcaster)
spellcaster:processCooldowns()
end)
char:try(Tree.behaviors.effects, function(effects)
effects:afterTurn()
end)
end
self.actedQueue, self.pendingQueue = self.pendingQueue, self.actedQueue

View File

@ -1,169 +0,0 @@
local utils = require "lib.utils.utils"
local taskUtils = require "lib.utils.task"
--- Некоторое свойство, что можно наложить на персонажа. Позволяет реализовать такие вещи как DOT'ы
--- и вообще, что душа поживает.
---
--- У каждого эффекта есть тэг и функции триггеры (например, `beforeTurn`, что срабатывает перед началом хода персонажа и так далее).
--- Каждая функция триггер делится на два типа, `before...` и `after...`. Каждая из них возвращает `task`, для того чтобы
--- проиграть анимацию, например. Функции типа `before...` также возвращают по мимо таска некоторое значение, зависящее от
--- конкретной функции.
--- @class Effect
--- @field tag string
local effect = {}
effect.__index = effect
--- Предполагается, что в каждую функцию будет передаваться `Character` (владелец эффекта) и параметр `intensity`, который отвечает за силу эффекта
--- @alias EffectFunc fun(owner: Character, intensity: integer): Task<nil>, nil бред конечно, но иначе всё в жёлтом
--- @alias EffectStatementFunc fun(owner: Character, intensity: integer): Task<nil>, boolean
--- @alias EffectDamageFunc fun(owner: Character, intensity: integer, damage: integer): Task<nil>, integer
--- @alias EffectRegenFunc fun(owner: Character, intensity: integer, amountHp: integer): Task<nil>, integer
--- @alias EffectData { tag: string }
--- Срабатывает перед применением эффекта
---
--- Возвращает, а можно ли применить эффект?
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>, boolean
function effect:beforeBirth(owner, intensity) return taskUtils.fromValue(), true end
--- Срабатывает после применения эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterBirth(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед смертью владельца эффекта
---
--- Возвращает, умирает ли персонаж?
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>, boolean
function effect:beforeDeath(owner, intensity) return taskUtils.fromValue(), true end
--- Срабатывает после смерти владельца эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterDeath(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед ходом владельца эффекта
---
--- Возвращает, будет ли персонаж ходить?
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>, boolean
function effect:beforeTurn(owner, intensity) return taskUtils.fromValue(), true end
--- Срабатывает после хода владельца эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterTurn(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед кастом заклинания владельцем эффекта
---
--- Возвращает, произойдёт ли каст?
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>, boolean
function effect:beforeCast(owner, intensity) return taskUtils.fromValue(), true end
--- Срабатывает после каста заклинания владельцем эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterCast(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед нанесением урона владельцем эффекта
---
--- Возвращает урон, который собираются нанести
--- @param owner Character
--- @param intensity integer
--- @param damage integer
--- @return Task<nil>, integer
function effect:beforeAttack(owner, intensity, damage) return taskUtils.fromValue(), damage end
--- Срабатывает после нанесения урона владельцем эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterAttack(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед получением урона владельцем эффекта
---
--- Возвращает урон, который должны получить
--- @param owner Character
--- @param intensity integer
--- @param damage integer
--- @return Task<nil>, integer
function effect:beforeDamage(owner, intensity, damage) return taskUtils.fromValue(), damage end
--- Срабатывает после получения урона владельцем эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterDamage(owner, intensity) return taskUtils.fromValue() end
--- Срабатывает перед регенерацией здоровья владельцем эффекта
---
--- Возвращает количество здоровья, которое должно быть восстановлено
--- @param owner Character
--- @param intensity integer
--- @param amountHp integer кол-во хп для регена
--- @return Task<nil>, integer
function effect:beforeRegeneration(owner, intensity, amountHp) return taskUtils.fromValue(), amountHp end
--- Срабатывает после регенерации здоровья владельцем эффекта
--- @param owner Character
--- @param intensity integer
--- @return Task<nil>
function effect:afterRegeneration(owner, intensity) return taskUtils.fromValue() end
--- Функция, что задаёт правила присвоения эффекта
--- @param owner Character
--- @param stacks integer
--- @param intensity integer
function effect:onBirth(owner, stacks, intensity)
local effects = owner:has(Tree.behaviors.effects)
if not effects then return end
-- проверяем на наличие такого же эффекта
if effects.effectsProperties[self.tag] then
local i = 1
while i < #effects.effectsPriority and effects.effectsPriority[i] ~= self.tag do
i = i + 1
end
local ef = table.remove(effects.effectsPriority, i)
effects.effectsPriority[#effects.effectsPriority + 1] = ef
else
effects.effectsPriority[#effects.effectsPriority + 1] = self.tag
end
effects.effectsProperties[self.tag] = {
stacks = stacks,
intensity = intensity
}
end
function effect:update(dt) end
function effect:draw() end
--- дип сравнение эффектов
--- @param other Effect
--- @return boolean
function effect:__eq(other)
return utils.deepComparison(self, other)
end
--- @param data EffectData
--- @return Effect
local function new(data)
local newEffect = setmetatable({
tag = data.tag,
}, effect)
return newEffect
end
return { new = new }

View File

@ -123,13 +123,6 @@ 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)
@ -137,8 +130,6 @@ function spell.new(data)
caster:try(Tree.behaviors.spellcaster, function(spellcaster)
spellcaster.cooldowns[self.tag] = self.baseCooldown
end)
return data.onCast(caster, target)
end

View File

@ -52,8 +52,7 @@ local regenerateMana = spell.new {
end)
local sprite = caster:has(Tree.behaviors.sprite)
local effects = caster:has(Tree.behaviors.effects)
if not sprite or not effects then return end -- и тут возможно на эффекты проверять не стоит
if not sprite then return end
print(caster.id, "has regenerated mana and gained initiative")
local light = require "lib/character/character".spawn("Light Effect")
@ -68,8 +67,7 @@ local regenerateMana = spell.new {
light:die()
return task.fromValue()
end),
sprite:animate("hurt"),
effects:addEffect("aversionToDeath", 1, 1),
sprite:animate("hurt")
}
end
}
@ -88,10 +86,9 @@ local attack = spell.new {
stats.hp = stats.hp - 4
end)
local targetEffects = targetCharacter:has(Tree.behaviors.effects)
local sprite = caster:has(Tree.behaviors.sprite)
local targetSprite = targetCharacter:has(Tree.behaviors.sprite)
if not sprite or not targetSprite or not targetEffects then return end -- проверять на эффект может и не стоит
if not sprite or not targetSprite then return end
caster:try(Tree.behaviors.positioned, function(b) b:lookAt(target) end)
@ -106,7 +103,6 @@ local attack = spell.new {
Tree.behaviors.light.new { color = Vec3 { 0.6, 0.3, 0.3 }, intensity = 4 },
Tree.behaviors.positioned.new(targetCharacter:has(Tree.behaviors.positioned).position + Vec3 { 0.5, 0.5 }),
}
Tree.audio:play(Tree.assets.files.audio.sounds.hurt)
return
task.wait {
task.chain(task.tween(light:has(Tree.behaviors.light) --[[@as LightBehavior]],
@ -114,11 +110,12 @@ local attack = spell.new {
light:die()
return task.fromValue()
end),
targetSprite:animate("hurt"),
targetEffects:addEffect("bleeding", 3, 3)
targetSprite:animate("hurt")
}
end
),
Tree.audio:play(Tree.assets.files.audio.sounds.hurt)
}
}
end

View File

@ -74,19 +74,4 @@ function P.lerp(from, to, t)
return from + (to - from) * t
end
--- Compares two tables by their fields
--- @param t1 table
--- @param t2 table
--- @return boolean
function P.deepComparison(t1, t2)
for k, v in pairs(t1) do
if type(v) == "table" and type(t2[k]) == "table" then
if not P.deepComparison(v, t2[k]) then return false end
elseif t2[k] ~= v then
return false
end
end
return true
end
return P

View File

@ -15,17 +15,16 @@ function love.load()
testLayout = require "lib.simple_ui.level.layout"
local chars = {
-- character.spawn("Foodor")
-- :addBehavior {
-- Tree.behaviors.residentsleeper.new(),
-- Tree.behaviors.stats.new(nil, nil, 1),
-- Tree.behaviors.positioned.new(Vec3 { 3, 3 }),
-- Tree.behaviors.tiled.new(),
-- Tree.behaviors.sprite.new(Tree.assets.files.sprites.character),
-- Tree.behaviors.shadowcaster.new(),
-- Tree.behaviors.spellcaster.new(),
-- Tree.behaviors.effects.new()
-- },
character.spawn("Foodor")
:addBehavior {
Tree.behaviors.residentsleeper.new(),
Tree.behaviors.stats.new(nil, nil, 1),
Tree.behaviors.positioned.new(Vec3 { 1, 1 }),
Tree.behaviors.tiled.new(),
Tree.behaviors.sprite.new(Tree.assets.files.sprites.character),
Tree.behaviors.shadowcaster.new(),
Tree.behaviors.spellcaster.new()
},
character.spawn("Foodor")
:addBehavior {
Tree.behaviors.residentsleeper.new(),
@ -34,8 +33,7 @@ function love.load()
Tree.behaviors.tiled.new(),
Tree.behaviors.sprite.new(Tree.assets.files.sprites.character),
Tree.behaviors.shadowcaster.new(),
Tree.behaviors.spellcaster.new(),
Tree.behaviors.effects.new()
Tree.behaviors.spellcaster.new()
},
character.spawn("Foodor")
:addBehavior {
@ -45,33 +43,19 @@ function love.load()
Tree.behaviors.tiled.new(),
Tree.behaviors.sprite.new(Tree.assets.files.sprites.character),
Tree.behaviors.shadowcaster.new(),
Tree.behaviors.spellcaster.new(),
Tree.behaviors.effects.new()
Tree.behaviors.spellcaster.new()
},
character.spawn("BOAR")
:addBehavior {
Tree.behaviors.residentsleeper.new(),
Tree.behaviors.stats.new(nil, nil, 2),
Tree.behaviors.positioned.new(Vec3 { 5, 5 }),
Tree.behaviors.tiled.new(),
Tree.behaviors.sprite.new(Tree.assets.files.sprites.boar),
Tree.behaviors.shadowcaster.new(),
Tree.behaviors.spellcaster.new(),
Tree.behaviors.ai.new("dev_warrior")
},
-- character.spawn("Baris")
-- :addBehavior {
-- Tree.behaviors.residentsleeper.new(),
-- Tree.behaviors.stats.new(nil, nil, 2),
-- Tree.behaviors.positioned.new(Vec3 { 5, 5 }),
-- Tree.behaviors.tiled.new(),
-- Tree.behaviors.sprite.new(Tree.assets.files.sprites.character),
-- Tree.behaviors.shadowcaster.new(),
-- Tree.behaviors.spellcaster.new(),
-- Tree.behaviors.ai.new(),
-- Tree.behaviors.effects.new()
-- },
-- character.spawn("BOAR")
-- :addBehavior {
-- Tree.behaviors.residentsleeper.new(),
-- Tree.behaviors.stats.new(nil, nil, 2),
-- Tree.behaviors.positioned.new(Vec3 { 7, 7 }),
-- Tree.behaviors.tiled.new(),
-- Tree.behaviors.sprite.new(Tree.assets.files.sprites.boar),
-- Tree.behaviors.shadowcaster.new(),
-- Tree.behaviors.spellcaster.new(),
-- Tree.behaviors.ai.new(),
-- Tree.behaviors.effects.new()
-- },
}
for id, _ in pairs(chars) do