Added the auto-controller.

This commit is contained in:
FaceDeer 2017-01-03 23:03:41 -07:00
parent 3600a745be
commit cfd6071ee6
6 changed files with 193 additions and 39 deletions

@ -34,12 +34,19 @@ Detailed module guide
Control Module
--------------
Right-click on this module to make the digging machine go. The digging machine will go in the direction that the control module is oriented.
Right-click on this module to make the digging machine go one step. The digging machine will go in the direction that the control module is oriented.
A control module can only trigger once per second. Gives you time to enjoy the scenery and smell the flowers (or their mulched remains, at any rate).
If you're standing within the digging machine's volume, or in a node adjacent to it, you will be pulled along with the machine when it moves.
Automatic Control Module
--------------
An Auto-control module can be set to run for an arbitrary number of cycles. Once it's running, right-click on it again to interrupt its rampage. If anything interrupts it - the player's click, an undiggable obstruction, running out of fuel - it will remember the number of remaining cycles so that you can fix the problem and set it running again to complete the original plan.
The digging machine will go in the direction that the control module is oriented.
Pusher Module
-------------
@ -160,12 +167,18 @@ Builder heads:
[mese fragment, core , mese fragment]
[ , mese fragment, ]
Controller heads:
Controller:
[ , mese crystal, ]
[mese crystal, core , mese crystal]
[ , mese crystal, ]
Automatic Controller:
[mese crystal, mese crystal, mese crystal]
[mese crystal, core , mese crystal]
[mese crystal, mese crystal, mese crystal]
Inventory modules:
[chest,]

@ -66,6 +66,13 @@ minetest.register_entity("digtron:builder_item", {
on_activate = function(self, staticdata)
local props = self.object:get_properties()
if staticdata ~= nil and staticdata ~= "" then
local pos = self.object:getpos()
local node = minetest.get_node(pos)
if minetest.get_node_group(node.name, "digtron") ~= 4 then
-- We were reactivated without a builder node on our location, self-destruct
self.object:remove()
return
end
props.textures = {staticdata}
self.object:set_properties(props)
elseif digtron.create_builder_item ~= nil then

@ -1,21 +1,21 @@
digtron.execute_cycle = function(pos, node, clicker)
-- returns newpos, status string
local execute_cycle = function(pos, clicker)
local meta = minetest.get_meta(pos)
if meta:get_string("waiting") == "true" then
-- Been too soon since last time the digtron did a cycle.
return pos, nil
end
local fuel_burning = meta:get_float("fuel_burning") -- get amount of burned fuel left over from last cycle
local status_text = string.format("Heat remaining in controller furnace: %d", fuel_burning)
local layout = digtron.get_all_digtron_neighbours(pos, clicker)
if layout.all == nil then
-- get_all_digtron_neighbours returns nil if the digtron array touches unloaded nodes, too dangerous to do anything in that situation. Abort.
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, "Digtron is adjacent to unloaded nodes."
return pos, "Digtron is adjacent to unloaded nodes.\n" .. status_text
end
if layout.traction * digtron.traction_factor < table.getn(layout.all) then
-- digtrons can't fly
minetest.sound_play("squeal", {gain=1.0, pos=pos})
return pos, string.format("Digtron has %d nodes but only enough traction to move %d nodes.", table.getn(layout.all), layout.traction * digtron.traction_factor)
return pos, string.format("Digtron has %d nodes but only enough traction to move %d nodes.\n", table.getn(layout.all), layout.traction * digtron.traction_factor)
.. status_text
end
local facing = minetest.get_node(pos).param2
@ -69,7 +69,7 @@ digtron.execute_cycle = function(pos, node, clicker)
)
minetest.sound_play("squeal", {gain=1.0, pos=pos})
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, "Digtron is obstructed." --Abort, don't dig and don't build.
return pos, "Digtron is obstructed.\n" .. status_text --Abort, don't dig and don't build.
end
----------------------------------------------------------------------------------------------------------------------
@ -103,7 +103,6 @@ digtron.execute_cycle = function(pos, node, clicker)
end
end
local fuel_burning = meta:get_float("fuel_burning") -- get amount of burned fuel left over from last cycle
local test_fuel_needed = test_build_fuel_cost + digging_fuel_cost - fuel_burning
local test_fuel_burned = 0
if test_fuel_needed > 0 then
@ -117,7 +116,7 @@ digtron.execute_cycle = function(pos, node, clicker)
if test_fuel_needed > fuel_burning + test_fuel_burned then
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, "Digtron needs more fuel" -- abort, don't dig and don't build.
return pos, "Digtron needs more fuel." -- abort, don't dig and don't build.
end
if not can_build then
@ -130,13 +129,13 @@ digtron.execute_cycle = function(pos, node, clicker)
local return_string = nil
if test_build_return_code == 3 then
minetest.sound_play("honk", {gain=0.5, pos=pos}) -- A builder is not configured
return_string = "Digtron connected to at least one builder node that hasn't had an output material assigned."
return_string = "Digtron connected to at least one builder node that hasn't had an output material assigned.\n"
elseif test_build_return_code == 2 then
minetest.sound_play("dingding", {gain=1.0, pos=pos}) -- Insufficient inventory
return_string = string.format("Digtron has insufficient materials in inventory to execute all build operations.\nNeeded: %s",
return_string = string.format("Digtron has insufficient materials in inventory to execute all build operations.\nNeeded: %s\n",
test_build_return_item:get_name())
end
return pos, return_string --Abort, don't dig and don't build.
return pos, return_string .. status_text --Abort, don't dig and don't build.
end
----------------------------------------------------------------------------------------------------------------------
@ -166,15 +165,7 @@ digtron.execute_cycle = function(pos, node, clicker)
if move_player then
clicker:moveto(digtron.find_new_pos(player_pos, facing), true)
end
-- Start the delay before digtron can run again. Do this after moving the array or pos will be wrong.
minetest.get_meta(pos):set_string("waiting", "true")
minetest.after(digtron.cycle_time,
function (pos)
minetest.get_meta(pos):set_string("waiting", nil)
end, pos
)
local building_fuel_cost = 0
local strange_failure = false
-- execute_build on all digtron components that have one
@ -273,14 +264,142 @@ minetest.register_node("digtron:controller", {
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
newpos, status = digtron.execute_cycle(pos, node, clicker)
local meta = minetest.get_meta(pos)
if meta:get_string("waiting") == "true" then
-- Been too soon since last time the digtron did a cycle.
return
end
newpos, status = execute_cycle(pos, clicker)
meta = minetest.get_meta(newpos)
if status ~= nil then
local meta = minetest.get_meta(newpos)
meta:set_string("infotext", status)
end
-- Start the delay before digtron can run again. Do this after moving the array or pos will be wrong.
minetest.get_meta(newpos):set_string("waiting", "true")
minetest.after(digtron.cycle_time,
function (pos)
minetest.get_meta(pos):set_string("waiting", nil)
end, newpos
)
end,
})
---------------------------------------------------------------------------------------------------------------
local auto_formspec = "size[4.5,1]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"field[0.5,0.8;1,0.1;offset;Cycles;${offset}]" ..
"tooltip[offset;When triggered, this controller will try to run for the given number of cycles. The cycle count will decrement as it runs, so if it gets halted by a problem you can fix the problem and restart.]" ..
"field[1.5,0.8;1,0.1;period;Period;${period}]" ..
"tooltip[period;Number of seconds to wait between each cycle]" ..
"button_exit[2.2,0.5;1,0.1;set;Set]" ..
"tooltip[set;Saves the cycle setting without starting the controller running]" ..
"button_exit[3.2,0.5;1,0.1;execute;Set &\nExecute]" ..
"tooltip[execute;Begins executing the given number of cycles]"
-- Needed to make this global so that it could recurse into minetest.after
digtron.auto_cycle = function(pos)
local meta = minetest.get_meta(pos)
local player = minetest.get_player_by_name(meta:get_string("triggering_player"))
if player == nil or meta:get_string("waiting") == "true" then
return
end
local newpos, status = execute_cycle(pos, player)
local cycle = 0
if vector.equals(pos, newpos) then
cycle = meta:get_int("offset")
status = status .. string.format("\nCycles remaining: %d\nHalted!", cycle)
meta:set_string("infotext", status)
meta:set_string("formspec", auto_formspec)
return
end
meta = minetest.get_meta(newpos)
cycle = meta:get_int("offset") - 1
meta:set_int("offset", cycle)
status = status .. string.format("\nCycles remaining: %d", cycle)
meta:set_string("infotext", status)
if cycle > 0 then
minetest.after(math.max(digtron.cycle_time, meta:get_int("period")), digtron.auto_cycle, newpos)
else
meta:set_string("formspec", auto_formspec)
end
end
-- Master controller. Most complicated part of the whole system. Determines which direction a digtron moves and triggers all of its component parts.
minetest.register_node("digtron:auto_controller", {
description = "Digtron Automatic Control Unit",
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
drop = "digtron:auto_controller",
sounds = default.node_sound_metal_defaults(),
paramtype2= "facedir",
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90^[colorize:#88000030",
"digtron_plate.png^[transformR270^[colorize:#88000030",
"digtron_plate.png^[colorize:#88000030",
"digtron_plate.png^[transformR180^[colorize:#88000030",
"digtron_plate.png^[colorize:#88000030",
"digtron_control.png^[colorize:#88000030",
},
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = controller_nodebox,
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_float("fuel_burning", 0.0)
meta:set_string("infotext", "Heat remaining in controller furnace: 0")
meta:set_string("formspec", auto_formspec)
-- Reusing offset and period to keep the digtron node-moving code simple, and the names still fit well
meta:set_int("period", 1)
meta:set_int("offset", 0)
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
local offset = tonumber(fields.offset)
local period = tonumber(fields.period)
if period and period > 0 then
meta:set_int("period", math.floor(period))
end
if offset and offset >= 0 then
meta:set_int("offset", math.floor(offset))
if sender:is_player() and offset > 0 then
meta:set_string("triggering_player", sender:get_player_name())
if fields.execute then
meta:set_string("waiting", nil)
meta:set_string("formspec", nil)
digtron.auto_cycle(pos)
end
end
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", meta:get_string("infotext") .. "\nInterrupted!")
meta:set_string("waiting", "true")
meta:set_string("formspec", auto_formspec)
end,
})
---------------------------------------------------------------------------------------------------------------
-- A much simplified control unit that only moves the digtron, and doesn't trigger the diggers or builders.
-- Handy for shoving a digtron to the side if it's been built a bit off.
minetest.register_node("digtron:pusher", {

@ -27,6 +27,18 @@ local intermittent_on_construct = function(pos)
meta:set_int("offset", 0)
end
local intermittent_on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
local period = tonumber(fields.period)
local offset = tonumber(fields.offset)
if period and period > 0 then
meta:set_int("period", math.floor(period))
end
if offset then
meta:set_int("offset", math.floor(offset))
end
end,
-- Digs out nodes that are "in front" of the digger head.
minetest.register_node("digtron:digger", {
description = "Digger Head",
@ -108,17 +120,7 @@ minetest.register_node("digtron:intermittent_digger", {
on_construct = intermittent_on_construct,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
local period = tonumber(fields.period)
local offset = tonumber(fields.offset)
if period and period > 0 then
meta:set_int("period", math.floor(tonumber(fields.period)))
end
if offset then
meta:set_int("offset", math.floor(tonumber(fields.offset)))
end
end,
on_receive_fields = intermittent_on_receive_fields,
-- returns fuel_cost, item_produced
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate)
@ -225,7 +227,9 @@ minetest.register_node("digtron:intermittent_soft_digger", {
},
on_construct = intermittent_on_construct,
on_receive_fields = intermittent_on_receive_fields,
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate)
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)

@ -21,6 +21,15 @@ minetest.register_craft({
}
})
minetest.register_craft({
output = "digtron:auto_controller",
recipe = {
{"default:mese_crystal","default:mese_crystal","default:mese_crystal"},
{"default:mese_crystal","digtron:digtron_core","default:mese_crystal"},
{"default:mese_crystal","default:mese_crystal","default:mese_crystal"}
}
})
minetest.register_craft({
output = "digtron:builder",
recipe = {

@ -99,6 +99,8 @@ digtron.move_node = function(pos, newpos)
newinv:set_list("main", list)
newmeta:set_string("formspec", oldformspec)
newmeta:set_string("triggering_player", oldmeta:get_string("triggering_player")) -- for auto-controllers
newmeta:set_int("offset", oldmeta:get_int("offset"))
newmeta:set_int("period", oldmeta:get_int("period"))
newmeta:set_int("build_facing", oldmeta:get_int("build_facing"))