minetest_mobehaviour/behavior.lua

373 lines
5.5 KiB
Lua

bt = {
reset={},
tick={},
}
function tprint (tbl, indent)
local formatting = ""
if not indent then indent = 0 end
if tbl == nil then
print(formatting .. "nil")
return
end
for k, v in pairs(tbl) do
formatting = string.rep(" ", indent) .. k .. ": "
if type(v) == "table" then
print(formatting)
tprint(v, indent+1)
elseif type(v) == 'boolean' then
print(formatting .. tostring(v))
elseif type(v) == 'function' then
print(formatting .. "[function]")
elseif type(v) == 'userdata' then
print(formatting .. "[userdata]")
else
print(formatting .. v)
end
end
end
function mkSelector(name, list)
return {
name=name,
kind="selector",
current_kid=-1,
kids=list,
}
end
function mkSequence(name, list)
return {
name=name,
kind="sequence",
current_kid=-1,
kids=list,
}
end
function mkRepeat(name, what)
return {
name=name,
kind="repeat",
kids = what,
}
end
bt.reset.selector = function(node, data)
node.current_kid = -1
end
bt.reset.sequence = function(node, data)
node.current_kid = -1
end
bt.reset["repeat"] = function(node, data)
end
bt.tick["repeat"] = function(node, data)
--tprint(node)
local ret = bt.tick[node.kids[1].kind](node.kids[1], data)
if ret ~= "running" then
print("repeat resetting")
bt.reset[node.kids[1].kind](node.kids[1], data)
end
print("repeat ending\n&&&&&")
return "success"
end
-- nodes never call :reset() on themselves
bt.tick.selector = function(node, data)
local ret
if node.current_kid == -1 then
node.current_kid = 1
ret = "failed" -- trick reset into being run
end
while node.current_kid <= table.getn(node.kids) do
local cn = node.kids[node.current_kid]
-- reset fresh nodes
if ret == "failed" then
bt.reset[cn.kind](cn, data)
end
-- tick the current node
ret = bt.tick[cn.kind](cn, data)
print(" selector got status ["..ret.."] from kid "..node.current_kid)
if ret == "running" or ret == "success" then
return ret
end
node.current_kid = node.current_kid + 1
end
return "failed"
end
bt.tick.sequence = function(node, data)
local ret
if node.current_kid == -1 then
node.current_kid = 1
ret = "failed" -- trick reset into being run
end
while node.current_kid <= table.getn(node.kids) do
local cn = node.kids[node.current_kid]
-- reset fresh nodes
if ret == "failed" then
bt.reset[cn.kind](cn, data)
end
-- tick the current node
ret = bt.tick[cn.kind](cn, data)
print(" selector got status ["..ret.."] from kid "..node.current_kid)
if ret == "running" or ret == "failed" then
return ret
end
node.current_kid = node.current_kid + 1
end
return "success"
end
-- distance on x-z plane
function distance(a,b)
local x = a.x - b.x
local z = a.z - b.z
return math.abs(math.sqrt(x*x + z*z))
end
bt.reset.find_node_near = function(node, data)
local targetpos = minetest.find_node_near(data.pos, node.dist, node.sel)
data.targetPos = targetpos
end
bt.tick.find_node_near = function(node, data)
if data.targetPos == nil then
print("could not find node near")
return "failed"
end
return "success"
end
function mkFindNodeNear(sel, dist)
return {
name="find node near",
kind="find_node_near",
dist = dist,
sel = sel,
}
end
bt.reset.approach = function(node, data)
if data.targetPos ~= nil then
print("Approaching target ("..data.targetPos.x..","..data.targetPos.y..","..data.targetPos.z..")")
data.mob.destination = data.targetPos
else
print("Approach: targetPos is nil")
end
end
bt.tick.approach = function(node, data)
if data.targetPos == nil then
return "failed"
end
local d = distance(data.pos, data.targetPos)
print("dist: "..d)
if d <= node.dist then
print("arrived at target")
return "success"
end
return "running"
end
function mkApproach(dist)
return {
name="go to",
kind="approach",
dist=dist,
}
end
function mkTryApproach(dist)
return {
name="try to go to",
kind="try_approach",
dist=dist,
}
end
bt.reset.try_approach = function(node, data)
node.last_d = nil
if data.targetPos ~= nil then
print("Approaching target ("..data.targetPos.x..","..data.targetPos.y..","..data.targetPos.z..")")
data.mob.destination = data.targetPos
else
print("Approach: targetPos is nil")
end
end
bt.tick.try_approach = function(node, data)
if data.targetPos == nil then
return "failed"
end
local d = distance(data.pos, data.targetPos)
if d <= node.dist then
print("arrived at target")
node.last_d = nil
return "success"
end
if node.last_d == nil then
node.last_d = d
else
local dd = math.abs(node.last_d - d)
print("dist: ".. dd)
if dd < .02 then
-- we're stuck
node.last_d = nil
return "failed"
end
end
print("dist: ".. math.abs(node.last_d - d))
return "running"
end
bt.reset.destroy = function(node, data)
end
bt.tick.destroy = function(node, data)
print("Destroying target")
if data.targetPos == nil then
return "failed"
end
minetest.set_node(data.targetPos, {name="air"})
return "success"
end
function mkDestroy()
return {
name="destroy",
kind="destroy",
}
end
bt.reset.bash_walls = function(node, data)
end
bt.tick.bash_walls = function(node, data)
local pos = minetest.find_node_near(data.pos, 2, {"default:wood"})
if pos == nil then
return "failed"
end
minetest.set_node(pos, {name="air"})
return "success"
end
function mkBashWalls()
return {
name="destroy",
kind="bash_walls",
}
end