In quarry, skip past undiggable nodes

The quarry used to get stuck when it encountered an undiggable node.
Change it to skip past that node, digging whatever later stuff it can.
Necessarily, the current digging position becomes semantically-significant
state: it is no longer sufficient to search the quarry cuboid from the top
on each iteration.  The current digging height is reported in the quarry's
interaction form, and can be reset to the top using a button on the form.

Where there is a non-air node within the quarry directly above the
next node to dig, it blocks the quarry's access to that node, even if
everything involved is diggable.  Thus an undiggable node casts a shadow
of undug nodes below it.  Resolving undiggability of a node is a major
reason to use the restart button.
This commit is contained in:
Zefram 2014-08-17 19:19:11 +01:00
parent 390ade6e54
commit d0efa15b98
5 changed files with 126 additions and 123 deletions

View File

@ -115,6 +115,10 @@ Slim Elements half / normal height: = Schmale Elemente von halber / normaler Hoe
Current track %s = Aktueller Titel %s Current track %s = Aktueller Titel %s
Stopped = Stopped =
Keeping %d/%d map blocks loaded = Keeping %d/%d map blocks loaded =
Digging not started =
Digging finished =
Digging %d m above machine =
Digging %d m below machine =
## CNC ## CNC
Cylinder = Zylinder Cylinder = Zylinder

View File

@ -109,6 +109,10 @@ Power level = Nivel de Poder
Production at %d%% = Produccion en %d%% Production at %d%% = Produccion en %d%%
Stopped = Stopped =
Keeping %d/%d map blocks loaded = Keeping %d/%d map blocks loaded =
Digging not started =
Digging finished =
Digging %d m above machine =
Digging %d m below machine =
## CNC Machine ## CNC Machine
Element Edge = Elemento Borde Element Edge = Elemento Borde

View File

@ -112,6 +112,10 @@ Slim Elements half / normal height: = Metà elementi sottili / altezza normale:
Current track %s = Traccia corrente %s Current track %s = Traccia corrente %s
Stopped = Stopped =
Keeping %d/%d map blocks loaded = Keeping %d/%d map blocks loaded =
Digging not started =
Digging finished =
Digging %d m above machine =
Digging %d m below machine =
## CNC ## CNC
Cylinder = Cilindro Cylinder = Cilindro

View File

@ -120,6 +120,10 @@ Slim Elements half / normal height: =
Current track %s = Current track %s =
Stopped = Stopped =
Keeping %d/%d map blocks loaded = Keeping %d/%d map blocks loaded =
Digging not started =
Digging finished =
Digging %d m above machine =
Digging %d m below machine =
## CNC ## CNC
Cylinder = Cylinder =

View File

@ -11,146 +11,133 @@ minetest.register_craft({
local quarry_dig_above_nodes = 3 -- How far above the quarry we will dig nodes local quarry_dig_above_nodes = 3 -- How far above the quarry we will dig nodes
local quarry_max_depth = 100 local quarry_max_depth = 100
local quarry_demand = 10000
local function set_quarry_formspec(meta) local function set_quarry_formspec(meta)
local formspec = "size[3,1.5]".. local radius = meta:get_int("size")
"field[1,0.5;2,1;size;Radius;"..meta:get_int("size").."]" local formspec = "size[6,2.5]"..
"item_image[0,0;1,1;technic:quarry]"..
"label[1,0;"..S("%s Quarry"):format("HV").."]"..
"field[0.3,1.5;2,1;size;"..S("Radius:")..";"..radius.."]"
if meta:get_int("enabled") == 0 then if meta:get_int("enabled") == 0 then
formspec = formspec.."button[0,1;3,1;enable;"..S("%s Disabled"):format(S("%s Quarry"):format("HV")).."]" formspec = formspec.."button[4,1.2;2,1;enable;"..S("Disabled").."]"
else else
formspec = formspec.."button[0,1;3,1;disable;"..S("%s Enabled"):format(S("%s Quarry"):format("HV")).."]" formspec = formspec.."button[4,1.2;2,1;disable;"..S("Enabled").."]"
end end
local diameter = radius*2 + 1
local nd = meta:get_int("dug")
local rel_y = quarry_dig_above_nodes - math.floor(nd / (diameter*diameter))
formspec = formspec.."label[0,2;"..minetest.formspec_escape(
nd == 0 and S("Digging not started") or
(rel_y < -quarry_max_depth and S("Digging finished") or
S("Digging %d m "..(rel_y > 0 and "above" or "below").." machine")
:format(math.abs(rel_y)))
).."]"
formspec = formspec.."button[4,2;2,1;restart;"..S("Restart").."]"
meta:set_string("formspec", formspec) meta:set_string("formspec", formspec)
end end
local function set_quarry_demand(meta)
local radius = meta:get_int("size")
local diameter = radius*2 + 1
local machine_name = S("%s Quarry"):format("HV")
if meta:get_int("enabled") == 0 then
meta:set_string("infotext", S("%s Disabled"):format(machine_name))
meta:set_int("HV_EU_demand", 0)
elseif meta:get_int("dug") == diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) then
meta:set_string("infotext", S("%s Finished"):format(machine_name))
meta:set_int("HV_EU_demand", 0)
else
meta:set_string("infotext", S(meta:get_int("HV_EU_input") >= quarry_demand and "%s Active" or "%s Unpowered"):format(machine_name))
meta:set_int("HV_EU_demand", quarry_demand)
end
end
local function quarry_receive_fields(pos, formname, fields, sender) local function quarry_receive_fields(pos, formname, fields, sender)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if fields.size then if fields.size and string.find(fields.size, "^[0-9]+$") then
local size = tonumber(fields.size) or 0 local size = tonumber(fields.size)
size = math.max(size, 2) if size >= 2 and size <= 8 and size ~= meta:get_int("size") then
size = math.min(size, 8) meta:set_int("size", size)
meta:set_int("size", size) meta:set_int("dug", 0)
end
end end
if fields.enable then meta:set_int("enabled", 1) end if fields.enable then meta:set_int("enabled", 1) end
if fields.disable then meta:set_int("enabled", 0) end if fields.disable then meta:set_int("enabled", 0) end
if fields.restart then meta:set_int("dug", 0) end
set_quarry_formspec(meta) set_quarry_formspec(meta)
set_quarry_demand(meta)
end end
local function get_quarry_center(pos, size) local function quarry_run(pos, node)
local node = minetest.get_node(pos)
local back_dir = minetest.facedir_to_dir(node.param2)
local relative_center = vector.multiply(back_dir, size + 1)
local center = vector.add(pos, relative_center)
return center
end
local function gen_next_digpos(center, digpos, size)
digpos.x = digpos.x + 1
if digpos.x > center.x + size then
digpos.x = center.x - size
digpos.z = digpos.z + 1
end
if digpos.z > center.z + size then
digpos.x = center.x - size
digpos.z = center.z - size
digpos.y = digpos.y - 1
end
end
local function find_next_digpos(data, area, center, dig_y, size)
local c_air = minetest.get_content_id("air")
for y = center.y + quarry_dig_above_nodes, dig_y - 1, -1 do
for z = center.z - size, center.z + size do
for x = center.x - size, center.x + size do
if data[area:index(x, y, z)] ~= c_air then
return vector.new(x, y, z)
end
end
end
end
end
local function quarry_dig(pos, center, size)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local drops = {} if meta:get_int("enabled") and meta:get_int("HV_EU_input") >= quarry_demand then
local dig_y = meta:get_int("dig_y") local pdir = minetest.facedir_to_dir(node.param2)
local owner = meta:get_string("owner") local qdir = pdir.x == 1 and vector.new(0,0,-1) or
(pdir.z == -1 and vector.new(-1,0,0) or
local vm = VoxelManip() (pdir.x == -1 and vector.new(0,0,1) or
local p1 = vector.new( vector.new(1,0,0)))
center.x - size, local radius = meta:get_int("size")
center.y + quarry_dig_above_nodes, local diameter = radius*2 + 1
center.z - size) local startpos = vector.add(vector.add(vector.add(pos,
local p2 = vector.new( vector.new(0, quarry_dig_above_nodes, 0)),
center.x + size, pdir),
dig_y - 1, -- One node lower in case we have finished the current layer vector.multiply(qdir, -radius))
center.z + size) local endpos = vector.add(vector.add(vector.add(startpos,
local e1, e2 = vm:read_from_map(p1, p2) vector.new(0, -quarry_dig_above_nodes-quarry_max_depth, 0)),
local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2}) vector.multiply(pdir, diameter-1)),
local data = vm:get_data() vector.multiply(qdir, diameter-1))
local vm = VoxelManip()
local digpos = find_next_digpos(data, area, center, dig_y, size) local minpos, maxpos = vm:read_from_map(startpos, endpos)
local area = VoxelArea:new({MinEdge=minpos, MaxEdge=maxpos})
if digpos then local data = vm:get_data()
if digpos.y < pos.y - quarry_max_depth then local c_air = minetest.get_content_id("air")
meta:set_int("dig_y", digpos.y) local owner = meta:get_string("owner")
return drops local nd = meta:get_int("dug")
while nd ~= diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) do
local ry = math.floor(nd / (diameter*diameter))
local ndl = nd % (diameter*diameter)
if ry % 2 == 1 then
ndl = diameter*diameter - 1 - ndl
end
local rq = math.floor(ndl / diameter)
local rp = ndl % diameter
if rq % 2 == 1 then rp = diameter - 1 - rp end
local digpos = vector.add(vector.add(vector.add(startpos,
vector.new(0, -ry, 0)),
vector.multiply(pdir, rp)),
vector.multiply(qdir, rq))
local can_dig = true
for ay = startpos.y, digpos.y+1, -1 do
if data[area:index(digpos.x, ay, digpos.z)] ~= c_air then
can_dig = false
break
end
end
if can_dig and minetest.is_protected and minetest.is_protected(digpos, owner) then
can_dig = false
end
local dignode
if can_dig then
dignode = minetest.get_node(digpos)
local dignodedef = minetest.registered_nodes[dignode.name] or {diggable=false}
if not dignodedef.diggable or (dignodedef.can_dig and not dignodedef.can_dig(digpos, nil)) then
can_dig = false
end
end
nd = nd + 1
if can_dig then
minetest.remove_node(digpos)
for _, item in ipairs(minetest.get_node_drops(dignode.name, "")) do
technic.tube_inject_item(pos, pos, vector.new(0, 1, 0), item)
end
break
end
end end
if minetest.is_protected and minetest.is_protected(digpos, owner) then meta:set_int("dug", nd)
meta:set_int("enabled", 0)
set_quarry_formspec(meta)
return {}
end
dig_y = digpos.y
local node = minetest.get_node(digpos)
local node_def = minetest.registered_nodes[node.name] or { diggable = false }
if node_def.diggable and ((not node_def.can_dig) or node_def.can_dig(digpos, nil)) then
minetest.remove_node(digpos)
drops = minetest.get_node_drops(node.name, "")
end
elseif not (dig_y < pos.y - quarry_max_depth) then
dig_y = dig_y - 16
end end
set_quarry_formspec(meta)
meta:set_int("dig_y", dig_y) set_quarry_demand(meta)
return drops
end
local function send_items(items, pos, node)
for _, item in pairs(items) do
technic.tube_inject_item(pos, pos, vector.new(0, 1, 0), item)
end
end
local run = function(pos, node)
local meta = minetest.get_meta(pos)
local size = meta:get_int("size")
local eu_input = meta:get_int("HV_EU_input")
local demand = 10000
local center = get_quarry_center(pos, size)
local dig_y = meta:get_int("dig_y")
local machine_name = S("%s Quarry"):format("HV")
if meta:get_int("enabled") == 0 then
meta:set_string("infotext", S("%s Disabled"):format(machine_name))
meta:set_int("HV_EU_demand", 0)
return
end
if eu_input < demand then
meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
elseif eu_input >= demand then
meta:set_string("infotext", S("%s Active"):format(machine_name))
local items = quarry_dig(pos, center, size)
send_items(items, pos, node)
if dig_y < pos.y - quarry_max_depth then
meta:set_string("infotext", S("%s Finished"):format(machine_name))
end
end
meta:set_int("HV_EU_demand", demand)
end end
minetest.register_node("technic:quarry", { minetest.register_node("technic:quarry", {
@ -168,7 +155,7 @@ minetest.register_node("technic:quarry", {
meta:set_string("infotext", S("%s Quarry"):format("HV")) meta:set_string("infotext", S("%s Quarry"):format("HV"))
meta:set_int("size", 4) meta:set_int("size", 4)
set_quarry_formspec(meta) set_quarry_formspec(meta)
meta:set_int("dig_y", pos.y) set_quarry_demand(meta)
end, end,
after_place_node = function(pos, placer, itemstack) after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -177,7 +164,7 @@ minetest.register_node("technic:quarry", {
end, end,
after_dig_node = pipeworks.scan_for_tube_objects, after_dig_node = pipeworks.scan_for_tube_objects,
on_receive_fields = quarry_receive_fields, on_receive_fields = quarry_receive_fields,
technic_run = run, technic_run = quarry_run,
}) })
technic.register_machine("HV", "technic:quarry", technic.receiver) technic.register_machine("HV", "technic:quarry", technic.receiver)