135 lines
3.9 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.

require 'lib.utils.vec3'
--- @alias CharacterState "idle"|"run"|"attack"|"hurt"
--- @alias Id integer
--- @type Id
local characterId = 1
--- @todo Композиция лучше наследования, но не до такой же степени! Надо отрефакторить и избавиться от сотни полей в таблице
--- @class Character
--- @field id Id
--- @field behaviors Behavior[]
--- @field _behaviorsIdx {string: integer}
local character = {}
character.__index = character
--- Создаёт персонажа, которым будет управлять или игрок или компьютер
--- @param name string
--- @param template ClassTemplate
--- @param spriteDir table
--- @param position? Vec3
--- @param size? Vec3
--- @param level? integer
local function spawn(name, template, spriteDir, position, size, level)
local char = {}
char = setmetatable(char, character)
char.id = characterId
characterId = characterId + 1
char.behaviors = {}
char._behaviorsIdx = {}
char:addBehavior {
Tree.behaviors.map.new(position, size),
Tree.behaviors.render.new(spriteDir),
Tree.behaviors.spellcaster.new()
}
char:setState("idle") --- @todo сделать это отдельным модулем
Tree.level.characters[char.id] = char
return char
end
--- Проверяет, есть ли у персонажа поведение [behavior].
--- @generic T : Behavior
--- @param behavior T
--- @return T | nil
function character:has(behavior)
--- @cast behavior Behavior
local idx = self._behaviorsIdx[behavior.id]
if not idx then return nil end
return self.behaviors[idx] or nil
end
--- Если у персонажа есть поведение [behavior], применяет к нему [fn]
---
--- Дальше meme для интеллектуалов
---
--- *Я: мам купи мне >>=*
---
--- *Мама: у нас дома есть >>=*
---
--- *Дома:*
--- @generic T : Behavior
--- @generic V
--- @param behavior T
--- @param fn fun(behavior: T) : V | nil
--- @return V | nil
function character:try(behavior, fn)
local b = self:has(behavior)
if not b then return end
return fn(b)
end
--- usage:
--- addBehavior( {logic.new(), graphics.new(), ...} )
---
--- or you may chain this if you are a wannabe haskell kiddo
--- @param behaviors Behavior[]
--- @return Character | nil
function character:addBehavior(behaviors)
for _, b in ipairs(behaviors) do
if b.dependencies then
for _, dep in ipairs(b.dependencies) do
if not self:has(dep) then
return print("[Character]: cannot add \"" .. b.id ..
"\" for a character (Id = " .. self.id .. "): needs \"" .. dep.id .. "\"!")
end
end
end
b.owner = self
table.insert(self.behaviors, b)
self._behaviorsIdx[b.id] = #self.behaviors
end
return self
end
--- геттеры и сеттеры для "внешних" данных
--- забей, это в поведения
--- @deprecated
--- @return CharacterState
function character:getState()
return self.state or "idle"
end
--- @param state CharacterState
--- @deprecated
function character:setState(state) --- @todo это вообще должно быть отдельное поведение
self.state = state
self:has(Tree.behaviors.render).animation:setState(state, (state ~= "idle" and state ~= "run") and function()
self:setState("idle")
end or nil)
end
--- @param path Deque
function character:followPath(path)
self:has(Tree.behaviors.map):followPath(path)
end
function character:update(dt)
--- @todo ну ты понел
for _, b in ipairs(self.behaviors) do
if b.update then b:update(dt) end
end
end
function character:draw()
for _, b in ipairs(self.behaviors) do
if b.draw then b:draw() end
end
end
return { spawn = spawn }