135 lines
4.1 KiB
Lua
135 lines
4.1 KiB
Lua
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}
|
||
--- @field spellbook Spell[] собственный набор спеллов персонажа
|
||
--- @field cast Spell | nil ссылка на активный спелл из спеллбука
|
||
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:
|
||
--- addModules( {logic.new(), graphics.new(), ...} )
|
||
---
|
||
--- or you may chain this if you are a wannabe haskell kiddo
|
||
function character:addBehavior(modules)
|
||
for _, module in ipairs(modules) do
|
||
if module.dependencies then
|
||
for _, dep in ipairs(module.dependencies) do
|
||
if not self:has(dep) then
|
||
return print("[Character]: cannot add \"" .. module.id ..
|
||
"\" for a character (Id = " .. self.id .. "): needs \"" .. dep.id .. "\"!")
|
||
end
|
||
end
|
||
end
|
||
module.owner = self
|
||
table.insert(self.behaviors, module)
|
||
self._behaviorsIdx[module.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 }
|