214 lines
8.9 KiB
Lua
214 lines
8.9 KiB
Lua
|
|
local dbg
|
|
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
|
|
|
local function rotate(rel, dir)
|
|
if dir.z < 0 then
|
|
return {x=-rel.x, y=rel.y, z=-rel.z}
|
|
elseif dir.z > 0 then
|
|
return {x=rel.x, y=rel.y, z=rel.z}
|
|
elseif dir.x > 0 then
|
|
return {x=rel.z, y=rel.y, z=-rel.x}
|
|
else
|
|
return {x=-rel.z, y=rel.y, z=rel.x}
|
|
end
|
|
end
|
|
|
|
people.actions.building = function(state)
|
|
|
|
if type(state.action.dir) ~= "table" then
|
|
dbg.v1(state.ent.name.." has invalid dir for building action")
|
|
return true, false
|
|
end
|
|
if state.action.dir.y ~= 0 then
|
|
dbg.v1(state.ent.name.." has invalid y component of dir for building action")
|
|
return true, false
|
|
end
|
|
if math.abs(state.action.dir.x) + math.abs(state.action.dir.z) ~= 1 then
|
|
dbg.v1(state.ent.name.." has invalid x/z components of dir for building action")
|
|
return true, false
|
|
end
|
|
if type(state.action.height) ~= "number" or state.action.height < 1
|
|
or state.action.height > 5 then
|
|
dbg.v1(state.ent.name.." has invalid height for building action")
|
|
return true, false
|
|
end
|
|
if type(state.action.width) ~= "number" or state.action.width < 1
|
|
or state.action.width > 15 or state.action.width % 2 == 0 then
|
|
dbg.v1(state.ent.name.." has invalid width for building action")
|
|
return true, false
|
|
end
|
|
if type(state.action.depth) ~= "number" or state.action.depth < 1
|
|
or state.action.depth > 15 then
|
|
dbg.v1(state.ent.name.." has invalid depth for building action")
|
|
return true, false
|
|
end
|
|
|
|
if not state.action.startpos then
|
|
state.action.startpos = vector.round(state.pos)
|
|
end
|
|
|
|
if not state.action.cpos then
|
|
state.action.cpos = 0
|
|
end
|
|
|
|
-- The following only pans out if the width is an odd
|
|
-- number! TODO
|
|
local toleft = math.ceil(state.action.width / 2)
|
|
local toback = state.action.depth + 1
|
|
local toright = state.action.width + 1
|
|
local tofront = toback
|
|
local toleft2 = toleft
|
|
|
|
if state.action.atcpos then
|
|
|
|
-- So we're at a position, cpos...
|
|
-- 0 = in front of the entrance
|
|
-- 1 - (toleft - 1) = along front wall, including corner
|
|
|
|
if state.action.wall then
|
|
local wallpos
|
|
local starty = 0
|
|
if state.action.cpos > 0 and state.action.cpos < toleft then
|
|
wallpos = {x=0, z=1}
|
|
elseif state.action.cpos > toleft and state.action.cpos < toleft + toback - 1 then
|
|
-- Wall down left side of building...
|
|
wallpos = {x=1, z=0}
|
|
elseif state.action.cpos > toleft + toback and state.action.cpos < toleft + toback + toright then
|
|
-- Back wall
|
|
wallpos = {x=0, z=-1}
|
|
elseif state.action.cpos > toleft + toback + toright and state.action.cpos < toleft + toback + toright + tofront then
|
|
-- Wall down right side of building...
|
|
wallpos = {x=-1, z=0}
|
|
elseif state.action.cpos >= toleft + toback + toright + tofront + 1 and state.action.cpos < toleft + toback + toright + tofront + toleft2 then
|
|
wallpos = {x=0, z=1}
|
|
elseif state.action.cpos == toleft + toback + toright + tofront + toleft2 then
|
|
-- This should be the very last point on the circuit, which is
|
|
-- in front of the door!
|
|
wallpos = {x=0, z=1}
|
|
starty = 2
|
|
end
|
|
|
|
if wallpos then
|
|
|
|
for y = 0, state.action.height - 1 do
|
|
local thisoff = {x=wallpos.x, y=y, z=wallpos.z}
|
|
local woff = rotate(thisoff, state.action.dir)
|
|
local thispos = vector.add(state.pos, woff)
|
|
local dignode = minetest.get_node(thispos)
|
|
-- Note that we have to substring the dignode, because
|
|
-- the placed bottom half of the door doesn't have the
|
|
-- same name as the item it came from.
|
|
if y == 0 and starty == 2 and state.action.door and
|
|
dignode.name:sub(1, state.action.door:len())
|
|
~= state.action.door then
|
|
-- We place the door against the side, just to allow for
|
|
-- there being a right-click handling node (e.g.
|
|
-- junction) below it.
|
|
todir = {x=-1,y=0,z=0}
|
|
todir = rotate(todir, state.action.dir)
|
|
state.action = {"place", pos=thispos,
|
|
item=state.action.door,
|
|
successaction=state.action,
|
|
againstdir=todir}
|
|
return false
|
|
elseif y == starty and starty > 0 and dignode.name == "air" then
|
|
-- Similarly, we have to watch out if we're placing
|
|
-- above a door (it will open/shut!), or above a hole
|
|
-- where a door would go. Maybe the auto-against-dir
|
|
-- code in the place action should just be detecting
|
|
-- right-clickable things and avoiding them, to save
|
|
-- all this. Or 'holding shift'??
|
|
todir = {x=-1,y=0,z=0}
|
|
todir = rotate(todir, state.action.dir)
|
|
state.action = {"place", pos=thispos,
|
|
item=state.action.wall,
|
|
successaction=state.action,
|
|
againstdir=todir}
|
|
return false
|
|
elseif y >= starty and dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=state.action.wall, successaction=state.action}
|
|
return false
|
|
elseif (y >= starty and dignode.name ~= state.action.wall)
|
|
or (y < starty and dignode.name ~= "air" and
|
|
dignode.name:sub(1, state.action.door:len())
|
|
~= state.action.door) then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
state.action.atcpos = false
|
|
state.action.cpos = state.action.cpos + 1
|
|
if state.action.cpos > toleft + toback + toright + tofront + toleft2 then
|
|
dbg.v1(state.ent.name.." has completed outer circuit of walls")
|
|
return true, true
|
|
end
|
|
|
|
end
|
|
|
|
-- Calculate RELATIVE direction to move
|
|
local movedir
|
|
if state.action.cpos == 0 then
|
|
movedir = {x=0, z=-1}
|
|
elseif state.action.cpos <= toleft then
|
|
movedir = {x=-1, z=0}
|
|
elseif state.action.cpos <= toleft + toback then
|
|
movedir = {x=0, z=1}
|
|
elseif state.action.cpos <= toleft + toback + toright then
|
|
movedir = {x=1, z=0}
|
|
elseif state.action.cpos <= toleft + toback + toright + tofront then
|
|
movedir = {x=0, z=-1}
|
|
else
|
|
movedir = {x=-1, z=0}
|
|
end
|
|
movedir.y = 0
|
|
|
|
-- Rotate the movement direction to world orientation...
|
|
local wmovedir = rotate(movedir, state.action.dir)
|
|
|
|
local newdest = vector.add(vector.round(state.pos), wmovedir)
|
|
|
|
if state.action.outside_floor and state.action.cpos > 1 and
|
|
state.action.cpos < toleft + toback + toright + tofront + toleft2 then
|
|
|
|
local floor = state.action.outside_floor
|
|
local altfloor = nil
|
|
if type(floor) == "table" then
|
|
floor = state.action.outside_floor[1]
|
|
altfloor = state.action.outside_floor[2]
|
|
end
|
|
|
|
local thispos = {x=newdest.x, y=newdest.y - 1, z=newdest.z}
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=floor, successaction=state.action}
|
|
return false
|
|
elseif dignode.name ~= floor and dignode.name ~= altfloor then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Make sure the area outside the walls is clear as we go round
|
|
for y = 0, state.action.height - 1 do
|
|
local thispos = {x=newdest.x, y=newdest.y + y, z=newdest.z}
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name ~= "air" then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
|
|
dbg.v3(state.ent.name.." circling to "..minetest.pos_to_string(newdest)..
|
|
", cpos="..state.action.cpos..", movedir="..minetest.pos_to_string(movedir)..
|
|
", wmovedir="..minetest.pos_to_string(wmovedir))
|
|
state.action.atcpos = true
|
|
state.action = {"go", pos=newdest, successaction=state.action}
|
|
return false
|
|
|
|
end
|
|
|