120 lines
4.2 KiB
Lua
120 lines
4.2 KiB
Lua
local easing = require "lib.utils.easing"
|
||
local pf = require "lib.pathfinder"
|
||
local utils = require "lib.utils.utils"
|
||
|
||
EPSILON = 0.01
|
||
|
||
--- @return Character
|
||
local function closestCharacter(char)
|
||
local caster = Vec3 {}
|
||
char:try(Tree.behaviors.positioned, function(b)
|
||
caster = b.position
|
||
end)
|
||
local charTarget
|
||
local minDist = 88005553535 -- spooky magic number
|
||
for k, v in pairs(Tree.level.characters) do
|
||
v:try(Tree.behaviors.positioned, function(b)
|
||
local dist = ((caster.x - b.position.x) ^ 2 + (caster.y - b.position.y) ^ 2) ^ 0.5
|
||
if dist < minDist and dist ~= 0 then
|
||
minDist = dist
|
||
charTarget = v
|
||
end
|
||
-- print(k, b.position)
|
||
end)
|
||
end
|
||
return charTarget
|
||
end
|
||
|
||
--- Возвращает все точки в радиусе в виде векторов
|
||
--- @param radius integer
|
||
local function circleVectors(radius)
|
||
local cam = Tree.level.camera
|
||
local vecs = {}
|
||
for t = 0, 2 * math.pi, EPSILON do
|
||
local x = math.sin(t) * radius
|
||
local y = math.cos(t) * radius
|
||
vecs[cam:toWorldPosition(Vec3 { x, y })] = true
|
||
end
|
||
return utils.keys(vecs)
|
||
end
|
||
|
||
--- @param owner Character
|
||
--- @param space integer здесь мы должны сами определять, сколько должны не доходить до персонажа (1 <= n)
|
||
--- @return Vec3|nil
|
||
local function pathToClosestCharacter(owner, space)
|
||
local charTarget = closestCharacter(owner)
|
||
local targetPosition, ownerPosition = charTarget:has(Tree.behaviors.positioned), owner:has(Tree.behaviors.positioned)
|
||
if not targetPosition or not ownerPosition then return end
|
||
local target = Vec3 {}
|
||
print(ownerPosition.position, targetPosition.position)
|
||
local path = pf(ownerPosition.position, targetPosition.position)
|
||
for c in path:values() do
|
||
print(c)
|
||
end
|
||
print(path)
|
||
space = math.min(space, path:size())
|
||
print(space, path:size())
|
||
for _ = 0, space - 1 do
|
||
path:pop_back()
|
||
end
|
||
if path:size() ~= 0 then
|
||
target = path:pop_back()
|
||
else
|
||
target = ownerPosition.position
|
||
end
|
||
print(target, targetPosition.position)
|
||
--- @todo тут захардкожено + 1, но мы должны как-то хитро определять с какой стороны обойти
|
||
return target
|
||
end
|
||
|
||
---@type {[Class]: fun(self: AIBehavior): Task<nil>} возможно где-то здесь на объявлении типа сломается типизация
|
||
local aiNature = {
|
||
["dev_warrior"] = function(self)
|
||
return function(callback) -- почему так, описано в Task
|
||
self.owner:try(Tree.behaviors.spellcaster, function(spellB)
|
||
self.target = pathToClosestCharacter(self.owner, 2)
|
||
local task1 = spellB.spellbook[1]:cast(self.owner, self.target)
|
||
if task1 then
|
||
task1(
|
||
function()
|
||
-- здесь мы оказываемся после того, как сходили в первый раз
|
||
local newTarget = Vec3 { 1, 1 }
|
||
local task2 = spellB.spellbook[1]:cast(self.owner, newTarget)
|
||
if task2 then
|
||
-- дергаем функцию после завершения хода
|
||
task2(callback)
|
||
else
|
||
callback()
|
||
end
|
||
end
|
||
)
|
||
else
|
||
print('рот этого казино')
|
||
callback()
|
||
end
|
||
end)
|
||
end
|
||
end,
|
||
["dev_mage"] = function(self)
|
||
return function(callback)
|
||
print("etoh... bleh")
|
||
callback()
|
||
end
|
||
end
|
||
}
|
||
|
||
--- @class AIBehavior : Behavior
|
||
--- @field target Vec3?
|
||
local behavior = {}
|
||
behavior.__index = behavior
|
||
behavior.id = "ai"
|
||
|
||
--- @param class Class
|
||
function behavior.new(class)
|
||
return setmetatable({
|
||
makeTurn = aiNature[class]
|
||
}, behavior)
|
||
end
|
||
|
||
return behavior
|