346 lines
12 KiB
Lua
346 lines
12 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.tunnel = function(state)
|
|
|
|
if type(state.action.distance) ~= "number" then
|
|
dbg.v1(state.ent.name.." has invalid distance for tunnel action")
|
|
return true, false
|
|
end
|
|
if type(state.action.dir) ~= "table" then
|
|
dbg.v1(state.ent.name.." has invalid dir for tunnel action")
|
|
return true, false
|
|
end
|
|
if math.abs(state.action.dir.y) > 1 then
|
|
dbg.v1(state.ent.name.." has invalid y component of dir for tunnel 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 tunnel action")
|
|
return true, false
|
|
end
|
|
|
|
-- On starting, keep the original position and distance. This will allow
|
|
-- us to break off and resume if, for example, we run out of materials or
|
|
-- room to carry the spoils.
|
|
if not state.action.startpos then
|
|
state.action.startpos = vector.round(state.pos)
|
|
state.action.startdist = state.action.distance
|
|
end
|
|
|
|
if state.action.distance <= 0 then
|
|
if state.action.endface then
|
|
local endoff = {y=0, z=-1}
|
|
local endface = {y=0, z=-1}
|
|
if state.action.endface.left and state.action.endface.right then
|
|
if math.random() < 0.5 then
|
|
endoff.x = -1
|
|
else
|
|
endoff.x = 1
|
|
end
|
|
elseif state.action.endface.left then
|
|
endoff.x = -1
|
|
elseif state.action.endface.right then
|
|
endoff.x = 1
|
|
end
|
|
endface.x = 2 * endoff.x
|
|
endoff = rotate(endoff, state.action.dir)
|
|
endface = rotate(endface, state.action.dir)
|
|
state.action.endface = nil
|
|
state.action = {"go", rel=endoff, successaction={"face",
|
|
pos=vector.add(state.pos, endface),
|
|
successaction=state.action}}
|
|
return false
|
|
end
|
|
|
|
dbg.v1(state.ent.name.." completed tunnelling")
|
|
return true, true
|
|
end
|
|
|
|
-- digpos will be the base centre of the new cross-sectional area
|
|
-- we're going to dig.
|
|
local digpos = vector.add(vector.round(state.pos), state.action.dir)
|
|
|
|
-- Tweak (hack) because if we're laying steps, we're standing on them as
|
|
-- we go down. This sucks, and even more so because we might want to
|
|
-- skip the steps until another time if we don't have the materials
|
|
if state.action.dir.y == -1 and state.action.steps and state.action.distance ~= state.action.startdist then
|
|
digpos.y = digpos.y - 1
|
|
end
|
|
|
|
local height = 2
|
|
if state.action.dir.y ~= 0 then
|
|
if state.action.steps then
|
|
height = 4
|
|
else
|
|
height = 3
|
|
end
|
|
end
|
|
|
|
-- Work out if either or both sides of the tunnel should be open at
|
|
-- this point...
|
|
local leftopen = false
|
|
local rightopen = false
|
|
if state.action.distance < 4 and state.action.openside then
|
|
if state.action.openside.left then leftopen = true end
|
|
if state.action.openside.right then rightopen = true end
|
|
end
|
|
|
|
-- Make it so we dig from top to bottom when tunnelling downwards, and
|
|
-- bottom to top otherwise.
|
|
local yfrom, yto, ydir
|
|
if state.action.dir.y < 0 then
|
|
yfrom = height
|
|
yto = 0
|
|
ydir = -1
|
|
else
|
|
yfrom = 0
|
|
yto = height
|
|
ydir = 1
|
|
end
|
|
|
|
-- "Special" positions are those where supports and lighting are placed
|
|
local sdist = 0
|
|
if state.action.sdist then
|
|
sdist = state.action.sdist
|
|
end
|
|
local special_sup = (state.action.startdist - state.action.distance - sdist + 2) % 8 == 7
|
|
local special_light = (state.action.startdist - state.action.distance - sdist) % 4 == 3
|
|
|
|
-- TODO - the following is all a bit ineffecient, because we look at the
|
|
-- whole cross-section every time through. We could keep track of
|
|
-- where we've got to during a run and skip some.
|
|
-- On the other hand, there are things like falling gravel and
|
|
-- sand to take into account.
|
|
|
|
for y = yfrom, yto, ydir do
|
|
for x = -1, 1 do
|
|
local thisoff = rotate({x=x, y=y, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
|
|
local openside = false
|
|
if (x == -1 and leftopen) or
|
|
(x == 1 and rightopen) then
|
|
openside = true
|
|
end
|
|
|
|
-- Steps at the bottom row if needed.
|
|
if y == 0 and state.action.steps and state.action.dir.y ~= 0 then
|
|
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=state.action.steps, successaction=state.action,
|
|
param2=minetest.dir_to_facedir({x=-state.action.dir.x,y=0,z=-state.action.dir.z}, false)}
|
|
return false
|
|
elseif dignode.name ~= state.action.steps then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
|
|
elseif y == 2 and x ~= 0 and not openside and state.action.lighting
|
|
and special_light then
|
|
|
|
-- We don't actually place lighting (e.g. torches) here,
|
|
-- because we do walls later and that would disturb them.
|
|
-- But we need to make sure we don't remove existing ones.
|
|
if dignode.name ~= "air" and
|
|
dignode.name ~= state.action.lighting then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
|
|
elseif y == height and not openside and state.action.support_top
|
|
and special_sup then
|
|
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=state.action.support_top, successaction=state.action}
|
|
return false
|
|
elseif dignode.name ~= state.action.support_top then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
|
|
elseif x ~= 0 and not openside and state.action.support_side
|
|
and special_sup then
|
|
|
|
-- As with lighting, we don't actually put in the side supports
|
|
-- now, because they're placed against the wall which we might
|
|
-- not have done yet.
|
|
if dignode.name ~= "air" and dignode.name ~= state.action.support_side then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
|
|
else
|
|
|
|
if dignode.name ~= "air" then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
if state.action.floor and state.action.dir.y == 0 then
|
|
for x = -1, 1 do
|
|
local thisoff = rotate({x=x, y=-1, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=state.action.floor, successaction=state.action}
|
|
return false
|
|
elseif dignode.name ~= state.action.floor then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
local wall = state.action.wall
|
|
if special_sup and state.action.support_wall then
|
|
wall = state.action.support_wall
|
|
end
|
|
|
|
if wall and not (leftopen and rightopen) then
|
|
local sx = -2
|
|
local fx = 2
|
|
if leftopen then
|
|
sx = fx
|
|
elseif rightopen then
|
|
fx = sx
|
|
end
|
|
|
|
for y = 0, height + 1 do
|
|
for x = sx, fx, 4 do
|
|
thisoff = rotate({x=x, y=y, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=wall, successaction=state.action}
|
|
return false
|
|
elseif dignode.name ~= wall then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if state.action.lighting and special_light and
|
|
not (leftopen and rightopen) and
|
|
people.is_carrying(state.ent, state.action.lighting) > 0 then
|
|
local sx = -1
|
|
local fx = 1
|
|
if leftopen then
|
|
sx = fx
|
|
elseif rightopen then
|
|
fx = sx
|
|
end
|
|
|
|
for x = sx, fx, 2 do
|
|
local thisoff = rotate({x=x, y=2, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name ~= state.action.lighting then
|
|
local againstdir = rotate({x=x, y=0, z=0}, state.action.dir)
|
|
state.action = {"place", pos=thispos, item=state.action.lighting, successaction=state.action,
|
|
againstdir=againstdir}
|
|
return false
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
if state.action.support_side and special_sup and
|
|
not (leftopen and rightopen) and
|
|
people.is_carrying(state.ent, state.action.support_side) > 0 then
|
|
local sx = -1
|
|
local fx = 1
|
|
if leftopen then
|
|
sx = fx
|
|
elseif rightopen then
|
|
fx = sx
|
|
end
|
|
local sy = 0
|
|
if state.action.steps then
|
|
sy = 1
|
|
end
|
|
for y = sy, height do
|
|
for x = sx, fx, 2 do
|
|
thisoff = rotate({x=x, y=y, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name ~= state.action.support_side then
|
|
local param2
|
|
if state.action.support_side_facein then
|
|
local facevec = rotate({x=-x, y=0, z=0},
|
|
state.action.dir)
|
|
if facevec.x > 0 then
|
|
param2 = 4 * 3
|
|
elseif facevec.x < 0 then
|
|
param2 = 4 * 4
|
|
elseif facevec.z > 0 then
|
|
param2 = 4 * 1
|
|
else
|
|
param2 = 4 * 2
|
|
end
|
|
end
|
|
state.action = {"place", pos=thispos,
|
|
item=state.action.support_side,
|
|
successaction=state.action,
|
|
param2=param2}
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local ceiling = state.action.ceiling
|
|
if special_sup and state.action.support_ceiling then
|
|
ceiling = state.action.support_ceiling
|
|
end
|
|
|
|
if ceiling then
|
|
for x = -1, 1 do
|
|
local thisoff = rotate({x=x, y=height+1, z=0}, state.action.dir)
|
|
local thispos = vector.add(digpos, thisoff)
|
|
local dignode = minetest.get_node(thispos)
|
|
if dignode.name == "air" then
|
|
state.action = {"place", pos=thispos, item=ceiling,
|
|
successaction=state.action}
|
|
return false
|
|
elseif dignode.name ~= ceiling then
|
|
state.action = {"dig", pos=thispos, successaction=state.action}
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
-- We've cleared the cross-section at the next position, so we can move
|
|
-- forward a step...
|
|
state.action.distance = state.action.distance - 1
|
|
state.action = {"go", pos=digpos, successaction=state.action}
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|