clean the slate! Old code will be brought back as it's needed.

This commit is contained in:
FaceDeer 2019-08-17 01:47:16 -06:00
parent b394214ffa
commit 6a38e68433
33 changed files with 350 additions and 7455 deletions

@ -1,38 +0,0 @@
# Modular Tunnel Boring Machine
## aka The Almighty Digtron
This mod contains a set of blocks that can be used to construct highly customizable and modular tunnel-boring machines, bridge-builders, road-pavers, wall-o-matics, and other such construction/destruction contraptions.
A digging machine's components must be connected to the control block via a path leading through the faces of the blocks - diagonal connections across edges and corners don't count.
The basic block types that can be assembled into a functioning digging machine are:
* Digger heads, which excavate material in front of them when the machine is triggered
* Builder heads, which build a user-configured node in the direction they're facing
* Inventory modules, which hold material produced by the digger and provide material to the builders
* Fuel modules, which holds flammable materials to feed the beast
* Control block, used to trigger the machine and move it in a particular direction.
Diggers mine out blocks and shunt them into the Digtron's inventory, or drop them on the ground if there isn't room in the inventory to store them.
Builder heads can be used to lay down a solid surface as the Digtron moves, useful for situations where a tunnel-borer intersects a cavern. Builder heads can be set to construct their target block "intermittently", allowing for regularly-spaced structures to be constructed. Common uses include building support arches at regular intervals in a tunnel, adding a torch on the wall at regular intervals, laying rails with regularly-spaced powered rails interspersed, and adding stairs to vertical shafts.
The auto-controller block is able to trigger automatically for a user-selected number of cycles. A player can ride their Digtron as it goes.
Other specialized Digtron blocks include:
* An "axle" block that allows an assembled Digtron to be rotated into new orientations without needing to be rebuilt block-by-block
* A crate that can store an assembled Digtron and allow the player to transport it to a new location
* A duplicator that can create a copy of an existing Digtron (if provided with enough spare parts)
* An item ejector to clear Digtron's inventory of excavated materials and inject it into pipeworks tubes if that mod is installed.
* A light that can be mounted on a Digtron to illuminate the workspace as it moves
* Structural components to make it look cool
The Digtron mod only depends on the default mod, but includes optional support for several other mods:
* [https://forum.minetest.net/viewtopic.php?t=15912](doc), an in-game documentation mod. Detailed documentation for all of the Digtron's individual blocks are included as well as pages of general concepts and design tips.
* [https://forum.minetest.net/viewtopic.php?id=2155](pipeworks), a set of pneumatic tubes that allows inventory items to be extracted from or inserted into Digtron inventories.
* [https://forum.minetest.net/viewtopic.php?&t=12379](hopper), a different mod for inserting into and extracting from Digtron inventories. Note that only [https://github.com/minetest-mods/hopper](the most recent version of hopper is Digtron-capable,) earlier versions lack a suitable API.
* [https://forum.minetest.net/viewtopic.php?&t=4870](awards), a mod that adds achievements to the game. Over thirty Digtron-specific achievements are included.
* [https://forum.minetest.net/viewtopic.php?f=11&t=2538](technic), which adds rechargeable batteries and power cables to the game that Digtron can use instead of fuel.

@ -1,436 +0,0 @@
if not minetest.get_modpath("awards") then
digtron.award_item_dug = function (items, name, count) end
digtron.award_layout = function (layout, name) end
digtron.award_item_built = function(item_name, name) end
digtron.award_crate = function (layout, name) end
return
end
---------------------------------------------------------------------------
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
awards.register_trigger("digtron_dig", {
type = "counted_key",
progress = "@1/@2 excavated",
auto_description = {"Excavate 1 @2 using a Digtron.", "Excavate @1 @2 using a Digtron."},
auto_description_total = {"Excavate @1 block using a Digtron.", "Excavate @1 blocks using a Digtron."},
get_key = function(self, def)
return minetest.registered_aliases[def.trigger.node] or def.trigger.node
end,
key_is_item = true,
})
digtron.award_item_dug = function(items_dropped, player)
if #items_dropped == 0 or not player then
return
end
for _, item in pairs(items_dropped) do
awards.notify_digtron_dig(player, item)
end
end
awards.register_trigger("digtron_build", {
type = "counted_key",
progress = "@1/@2 built",
auto_description = {"Build 1 @2 using a Digtron.", "Build @1 @2 using a Digtron."},
auto_description_total = {"Build @1 block using a Digtron.", "Build @1 blocks using a Digtron."},
get_key = function(self, def)
return minetest.registered_aliases[def.trigger.node] or def.trigger.node
end,
key_is_item = true,
})
digtron.award_item_built = function(item_name, player)
if not player then
return
end
awards.notify_digtron_build(player, item_name)
end
digtron.award_layout = function(layout, player)
if layout == nil or not player then
return
end
local name = player:get_player_name()
if layout.water_touching then
awards.unlock(name, "digtron_water")
end
if layout.lava_touching then
awards.unlock(name, "digtron_lava")
end
if table.getn(layout.all) > 9 then
awards.unlock(name, "digtron_size10")
if table.getn(layout.all) > 99 then
awards.unlock(name, "digtron_size100")
end
end
if layout.diggers ~= nil and table.getn(layout.diggers) > 24 then
awards.unlock(name, "digtron_digger25")
end
if layout.builders ~= nil and table.getn(layout.builders) > 24 then
awards.unlock(name, "digtron_builder25")
end
if layout.controller.y > 100 then
awards.unlock(name, "digtron_height100")
if layout.controller.y > 1000 then
awards.unlock(name, "digtron_height1000")
end
elseif layout.controller.y < -100 then
awards.unlock(name, "digtron_depth100")
if layout.controller.y < -1000 then
awards.unlock(name, "digtron_depth1000")
if layout.controller.y < -2000 then
awards.unlock(name, "digtron_depth2000")
if layout.controller.y < -4000 then
awards.unlock(name, "digtron_depth4000")
if layout.controller.y < -8000 then
awards.unlock(name, "digtron_depth8000")
if layout.controller.y < -16000 then
awards.unlock(name, "digtron_depth16000")
if layout.controller.y < -30000 then
awards.unlock(name, "digtron_depth30000")
end
end
end
end
end
end
end
end
digtron.award_crate = function(layout, name)
if layout == nil or not name or name == "" then
return
end
-- Note that we're testing >10 rather than >9 because this layout includes the crate node
if table.getn(layout.all) > 10 then
awards.unlock(name, "digtron_crate10")
if table.getn(layout.all) > 100 then
awards.unlock(name, "digtron_crate100")
end
end
end
awards.register_award("digtron_water",{
title = S("Deep Blue Digtron"),
description = S("Encounter water while operating a Digtron."),
background = "awards_bg_mining.png",
icon = "default_water.png^digtron_digger_yb_frame.png",
})
awards.register_award("digtron_lava",{
title = S("Digtrons of Fire"),
description = S("Encounter lava while operating a Digtron."),
background = "awards_bg_mining.png",
icon = "default_lava.png^digtron_digger_yb_frame.png",
})
awards.register_award("digtron_size10",{
title = S("Bigtron"),
description = S("Operate a Digtron with 10 or more component blocks."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_crate.png",
})
awards.register_award("digtron_size100",{
title = S("Really Bigtron"),
description = S("Operate a Digtron with 100 or more component blocks."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_crate.png", -- TODO: Visually distinguish this from Bigtron
})
awards.register_award("digtron_builder25",{
title = S("Buildtron"),
description = S("Operate a Digtron with 25 or more builder modules."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_builder.png^digtron_crate.png",
})
awards.register_award("digtron_digger25",{
title = S("Digging Leviathan"),
description = S("Operate a Digtron with 25 or more digger heads."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_motor.png^digtron_crate.png",
})
awards.register_award("digtron_height1000",{
title = S("Digtron In The Sky"),
description = S("Operate a Digtron above 1000m elevation"),
background = "awards_bg_mining.png",
icon = "default_river_water.png^default_snow_side.png^[transformR180^digtron_digger_yb_frame.png",
})
awards.register_award("digtron_height100",{
title = S("Digtron High"),
description = S("Operate a Digtron above 100m elevation"),
background = "awards_bg_mining.png",
icon = "default_river_water.png^default_snow_side.png^digtron_digger_yb_frame.png",
})
awards.register_award("digtron_depth100",{
title = S("Scratching the Surface"),
description = S("Operate a Digtron 100m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^digtron_digger_yb_frame.png^awards_level1.png",
})
awards.register_award("digtron_depth1000",{
title = S("Digging Deeper"),
description = S("Operate a Digtron 1,000m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#0002^digtron_digger_yb_frame.png^awards_level2.png",
})
awards.register_award("digtron_depth2000",{
title = S("More Than a Mile"),
description = S("Operate a Digtron 2,000m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#0004^digtron_digger_yb_frame.png^awards_level3.png",
})
awards.register_award("digtron_depth4000",{
title = S("Digging Below Plausibility"),
description = S("The deepest mine in the world is only 3.9 km deep, you operated a Digtron below 4km"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#0006^digtron_digger_yb_frame.png^awards_level4.png",
})
awards.register_award("digtron_depth8000",{
title = S("Double Depth"),
description = S("Operate a Digtron 8,000m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#0008^digtron_digger_yb_frame.png^awards_level5.png",
})
awards.register_award("digtron_depth16000",{
title = S("Halfway to the Core"),
description = S("Operate a Digtron 16,000m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#000A^digtron_digger_yb_frame.png^awards_level6.png",
})
awards.register_award("digtron_depth30000",{
title = S("Nowhere To Go But Up"),
description = S("Operate a Digtron 30,000m underground"),
background = "awards_bg_mining.png",
icon = "default_cobble.png^[colorize:#000C^digtron_digger_yb_frame.png^awards_level7.png",
})
awards.register_award("digtron_100mese_dug",{
title = S("Mese Master"),
description = S("Mine 100 Mese crystals with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_mese_crystal.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:mese_crystal",
target = 100,
}
})
awards.register_award("digtron_100diamond_dug",{
title = S("Diamond Vs. Diamond"),
description = S("Mine 100 diamonds with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_diamond.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:diamond",
target = 100,
}
})
awards.register_award("digtron_1000dirt_dug",{
title = S("Strip Mining"),
description = S("Excavate 1000 units of dirt with a Digtron"),
background = "awards_bg_mining.png",
icon = "default_dirt.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:dirt",
target = 1000,
}
})
awards.register_award("digtron_1000_dug",{
title = S("Digtron Miner"),
description = S("Excavate 1000 blocks using a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_tool_bronzepick.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
target = 1000,
}
})
awards.register_award("digtron_10000_dug",{
title = S("Digtron Expert Miner"),
description = S("Excavate 10,000 blocks using a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_tool_steelpick.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
target = 10000,
}
})
awards.register_award("digtron_100000_dug",{
title = S("Digtron Master Miner"),
description = S("Excavate 100,000 blocks using a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_tool_diamondpick.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
target = 100000,
}
})
awards.register_award("digtron_1000000_dug",{
title = S("DIGTRON MEGAMINER"),
description = S("Excavate over a million blocks using a Digtron!"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_tool_mesepick.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
target = 1000000,
}
})
awards.register_award("digtron_1000wood_dug",{
title = S("Clear Cutting"),
description = S("Chop down 1000 units of tree with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_sapling.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "group:tree",
target = 1000,
}
})
awards.register_award("digtron_10000wood_dug",{
title = S("Digtron Deforestation"),
description = S("Chop down 10,000 units of tree with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_sapling.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "group:tree",
target = 10000,
}
})
awards.register_award("digtron_1000grass_dug",{
title = S("Lawnmower"),
description = S("Harvest 1000 units of grass with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_grass_5.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "group:grass",
target = 1000,
}
})
awards.register_award("digtron_1000iron_dug",{
title = S("Iron Digtron"),
description = S("Excavate 1000 units of iron ore with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_steel_ingot.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:iron_lump",
target = 1000,
}
})
awards.register_award("digtron_1000copper_dug",{
title = S("Copper Digtron"),
description = S("Excavate 1000 units of copper ore with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_copper_ingot.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:copper_lump",
target = 1000,
}
})
awards.register_award("digtron_1000coal_dug",{
title = S("Coal Digtron"),
description = S("Excavate 1,000 units if coal with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_coal_lump.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:coal_lump",
target = 1000,
}
})
awards.register_award("digtron_10000coal_dug",{
title = S("Bagger 288"),
description = S("Excavate 10,000 units of coal with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_coal_block.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:coal_lump",
target = 10000,
}
})
awards.register_award("digtron_100gold_dug",{
title = S("Digtron 49er"),
description = S("Excavate 100 units of gold with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^default_gold_ingot.png^digtron_digger_yb_frame.png",
trigger = {
type = "digtron_dig",
node = "default:gold_lump",
target = 100,
}
})
awards.register_award("digtron_1000_built",{
title = S("Constructive Digging"),
description = S("Build 1,000 blocks with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_builder.png",
trigger = {
type = "digtron_build",
target = 1000,
}
})
awards.register_award("digtron_10000_built",{
title = S("Highly Constructive Digging"),
description = S("Build 10,000 blocks with a Digtron"),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_axel_side.png^[transformR90^digtron_builder.png",
trigger = {
type = "digtron_build",
target = 10000,
}
})
awards.register_award("digtron_crate10",{
title = S("Digtron Packrat"),
description = S("Stored 10 or more Digtron blocks in one crate."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_crate.png", -- TODO: Visually distinguish this from Bigtron
})
awards.register_award("digtron_crate100",{
title = S("Digtron Hoarder"),
description = S("Stored 100 or more Digtron blocks in one crate."),
background = "awards_bg_mining.png",
icon = "digtron_plate.png^digtron_crate.png", -- TODO: Visually distinguish this from Bigtron
})

@ -1,145 +0,0 @@
-- The purpose of this class is to have something that can be passed into callbacks that
-- demand a "Player" object as a parameter and hopefully prevent the mods that have
-- registered with those callbacks from crashing on a nil dereference or bad function
-- call. This is not supposed to be a remotely functional thing, it's just supposed
-- to provide dummy methods and return values of the correct data type for anything that
-- might ignore the false "is_player()" return and go ahead and try to use this thing
-- anyway.
-- I'm trying to patch holes in bad mod programming, essentially. If a mod is so badly
-- programmed that it crashes anyway there's not a lot else I can do on my end of things.
DigtronFakePlayer = {}
DigtronFakePlayer.__index = DigtronFakePlayer
local function return_value(x)
return (function() return x end)
end
local function return_nil()
return nil
end
local function return_empty_string()
return ""
end
local function return_zero()
return 0
end
local function return_empty_table()
return {}
end
function DigtronFakePlayer.update(self, pos, player_name)
self.is_fake_player = ":digtron " .. player_name
self.get_pos = return_value(pos)
end
function DigtronFakePlayer.create(pos, player_name)
local self = {}
setmetatable(self, DigtronFakePlayer)
self.is_fake_player = ":digtron " .. player_name
-- ObjectRef
self.get_pos = return_value(pos)
self.set_pos = return_nil
self.move_to = return_nil
self.punch = return_nil
self.right_click = return_nil
self.get_hp = return_value(10)
self.set_hp = return_nil
self.get_inventory = return_nil -- returns an `InvRef`
self.get_wield_list = return_empty_string
self.get_wield_index = return_value(1)
self.get_wielded_item = return_value(ItemStack(nil))
self.set_wielded_item = return_value(false)
self.set_armor_groups = return_nil
self.get_armor_groups = return_empty_table
self.set_animation = return_nil
self.get_animation = return_nil -- a set of values, maybe important?
self.set_attach = return_nil
self.get_attach = return_nil
self.set_detach = return_nil
self.set_bone_position = return_nil
self.get_bone_position = return_nil
self.set_properties = return_nil
self.get_properties = return_empty_table
self.is_player = return_value(false)
self.get_nametag_attributes = return_empty_table
self.set_nametag_attributes = return_nil
--LuaEntitySAO
self.set_velocity = return_nil
self.get_velocity = return_value({x=0,y=0,z=0})
self.set_acceleration = return_nil
self.get_acceleration = return_value({x=0,y=0,z=0})
self.set_yaw = return_nil
self.get_yaw = return_zero
self.set_texture_mod = return_nil
self.get_texture_mod = return_nil -- maybe important?
self.set_sprite = return_nil
--self.get_entity_name` (**Deprecated**: Will be removed in a future version)
self.get_luaentity = return_nil
-- Player object
self.get_player_name = return_empty_string
self.get_player_velocity = return_nil
self.get_look_dir = return_value({x=0,y=1,z=0})
self.get_look_horizontal = return_zero
self.set_look_horizontal = return_nil
self.get_look_vertical = return_zero
self.set_look_vertical = return_nil
--self.get_look_pitch`: pitch in radians - Deprecated as broken. Use `get_look_vertical`
--self.get_look_yaw`: yaw in radians - Deprecated as broken. Use `get_look_horizontal`
--self.set_look_pitch(radians)`: sets look pitch - Deprecated. Use `set_look_vertical`.
--self.set_look_yaw(radians)`: sets look yaw - Deprecated. Use `set_look_horizontal`.
self.get_breath = return_value(10)
self.set_breath = return_nil
self.get_attribute = return_nil
self.set_attribute = return_nil
self.set_inventory_formspec = return_nil
self.get_inventory_formspec = return_empty_string
self.get_player_control = return_value({jump=false, right=false, left=false, LMB=false, RMB=false, sneak=false, aux1=false, down=false, up=false} )
self.get_player_control_bits = return_zero
self.set_physics_override = return_nil
self.get_physics_override = return_value({speed = 1, jump = 1, gravity = 1, sneak = true, sneak_glitch = false, new_move = true,})
self.hud_add = return_nil
self.hud_remove = return_nil
self.hud_change = return_nil
self.hud_get = return_nil -- possibly important return value?
self.hud_set_flags = return_nil
self.hud_get_flags = return_value({ hotbar=true, healthbar=true, crosshair=true, wielditem=true, breathbar=true, minimap=true })
self.hud_set_hotbar_itemcount = return_nil
self.hud_get_hotbar_itemcount = return_zero
self.hud_set_hotbar_image = return_nil
self.hud_get_hotbar_image = return_empty_string
self.hud_set_hotbar_selected_image = return_nil
self.hud_get_hotbar_selected_image = return_empty_string
self.set_sky = return_nil
self.get_sky = return_empty_table -- may need members on this table
self.set_clouds = return_nil
self.get_clouds = return_value({density = 0, color = "#fff0f0e5", ambient = "#000000", height = 120, thickness = 16, speed = {x=0, y=-2}})
self.override_day_night_ratio = return_nil
self.get_day_night_ratio = return_nil
self.set_local_animation = return_nil
self.get_local_animation = return_empty_table
self.set_eye_offset = return_nil
self.get_eye_offset = return_value({x=0,y=0,z=0},{x=0,y=0,z=0})
return self
end

@ -1,532 +0,0 @@
DigtronLayout = {}
DigtronLayout.__index = DigtronLayout
local modpath_awards = minetest.get_modpath("awards")
-------------------------------------------------------------------------
-- Creation
local get_node_image = function(pos, node)
local node_image = {node=node, pos={x=pos.x, y=pos.y, z=pos.z}}
local node_def = minetest.registered_nodes[node.name]
node_image.paramtype2 = node_def.paramtype2
local meta = minetest.get_meta(pos)
node_image.meta = meta:to_table()
if node_image.meta ~= nil and node_def._digtron_formspec ~= nil then
node_image.meta.fields.formspec = node_def._digtron_formspec(pos, meta) -- causes formspec to be automatically upgraded whenever Digtron moves
end
local group = minetest.get_item_group(node.name, "digtron")
-- group 1 has no special metadata
if group > 1 and group < 10 then
assert(node_image ~= nil and node_image.meta ~= nil, "[Digtron] Digtron failed to get a metadata table for a Digtron node in group "
.. tostring(group) .. ". This error should not be possible. Please see https://github.com/minetest/minetest/issues/8067")
-- These groups have inventories
if group == 2 or (group > 3 and group < 8) then
assert(node_image.meta.inventory ~= nil, "[Digtron] Digtron failed to get a metadata inventory table for a Digtron node in group "
.. tostring(group) .. ". This error should not be possible. Please see https://github.com/minetest/minetest/issues/8067")
end
end
-- Record what kind of thing we've got in a builder node so its facing can be rotated properly
if group == 4 then
local build_item = ""
if node_image.meta.inventory.main then
build_item = node_image.meta.inventory.main[1]
end
if build_item ~= "" then
local build_item_def = minetest.registered_nodes[ItemStack(build_item):get_name()]
if build_item_def ~= nil then
node_image.build_item_paramtype2 = build_item_def.paramtype2
end
end
end
return node_image
end
-- temporary pointsets used while searching
local to_test = Pointset.create()
local tested = Pointset.create()
function DigtronLayout.create(pos, player)
local self = {}
setmetatable(self, DigtronLayout)
--initialize. We're assuming that the start position is a controller digtron, should be a safe assumption since only the controller node should call this
self.traction = 0
self.all = {}
self.water_touching = false
self.lava_touching = false
self.protected = Pointset.create() -- if any nodes we look at are protected, make note of that. That way we don't need to keep re-testing protection state later.
self.old_pos_pointset = Pointset.create() -- For tracking original location of nodes if we do transformations on the Digtron
self.nodes_dug = Pointset.create() -- For tracking adjacent nodes that will have been dug by digger heads in future
self.contains_protected_node = false -- used to indicate if at least one node in this digtron array is protected from the player.
self.controller = {x=pos.x, y=pos.y, z=pos.z} --Make a deep copy of the pos parameter just in case the calling code wants to play silly buggers with it
table.insert(self.all, get_node_image(pos, minetest.get_node(pos))) -- We never visit the source node, so insert it into the all table a priori. Revisit this design decision if a controller node is created that contains fuel or inventory or whatever.
self.extents_max_x = pos.x
self.extents_min_x = pos.x
self.extents_max_y = pos.y
self.extents_min_y = pos.y
self.extents_max_z = pos.z
self.extents_min_z = pos.z
tested:set(pos.x, pos.y, pos.z, true)
to_test:set(pos.x + 1, pos.y, pos.z, true)
to_test:set(pos.x - 1, pos.y, pos.z, true)
to_test:set(pos.x, pos.y + 1, pos.z, true)
to_test:set(pos.x, pos.y - 1, pos.z, true)
to_test:set(pos.x, pos.y, pos.z + 1, true)
to_test:set(pos.x, pos.y, pos.z - 1, true)
if minetest.is_protected(pos, player:get_player_name()) and not minetest.check_player_privs(player, "protection_bypass") then
self.protected:set(pos.x, pos.y, pos.z, true)
self.contains_protected_node = true
end
-- Do a loop on to_test positions, adding new to_test positions as we find digtron nodes. This is a flood fill operation
-- that follows node faces (no diagonals)
local testpos, _ = to_test:pop()
while testpos ~= nil do
tested:set(testpos.x, testpos.y, testpos.z, true) -- track nodes we've looked at to prevent infinite loops
local node = minetest.get_node(testpos)
if node.name == "ignore" then
--digtron array is next to unloaded nodes, too dangerous to do anything. Abort.
self.ignore_touching = true
end
if minetest.get_item_group(node.name, "water") ~= 0 then
self.water_touching = true
elseif minetest.get_item_group(node.name, "lava") ~= 0 then
self.lava_touching = true
if digtron.config.lava_impassible then
self.protected:set(testpos.x, testpos.y, testpos.z, true)
end
end
local is_protected = false
if minetest.is_protected(testpos, player:get_player_name()) and not minetest.check_player_privs(player, "protection_bypass") then
self.protected:set(testpos.x, testpos.y, testpos.z, true)
is_protected = true
end
local group_number = minetest.get_item_group(node.name, "digtron")
if group_number > 0 then
--found one. Add it to the digtrons output
local node_image = get_node_image(testpos, node)
table.insert(self.all, node_image)
-- add a reference to this node's position to special node lists
if group_number == 2 then
self.inventories = self.inventories or {}
table.insert(self.inventories, node_image)
elseif group_number == 3 then
self.diggers = self.diggers or {}
table.insert(self.diggers, node_image)
elseif group_number == 4 then
self.builders = self.builders or {}
table.insert(self.builders, node_image)
elseif group_number == 5 then
self.fuelstores = self.fuelstores or {}
table.insert(self.fuelstores, node_image)
elseif group_number == 6 then
self.inventories = self.inventories or {}
self.fuelstores = self.fuelstores or {}
table.insert(self.inventories, node_image)
table.insert(self.fuelstores, node_image)
elseif group_number == 7 then -- technic batteries
self.battery_holders = self.battery_holders or {}
table.insert(self.battery_holders, node_image)
elseif group_number == 8 then
self.power_connectors = self.power_connectors or {}
table.insert(self.power_connectors, node_image) -- technic power connectors
elseif group_number == 9 and node_image.meta.fields["autoeject"] == "true" then
self.auto_ejectors = self.auto_ejectors or {}
table.insert(self.auto_ejectors, node_image)
end
if is_protected then
self.contains_protected_node = true
end
-- update extents
self.extents_max_x = math.max(self.extents_max_x, testpos.x)
self.extents_min_x = math.min(self.extents_min_x, testpos.x)
self.extents_max_y = math.max(self.extents_max_y, testpos.y)
self.extents_min_y = math.min(self.extents_min_y, testpos.y)
self.extents_max_z = math.max(self.extents_max_z, testpos.z)
self.extents_min_z = math.min(self.extents_min_z, testpos.z)
--queue up potential new test points adjacent to this digtron node
to_test:set_if_not_in(tested, testpos.x + 1, testpos.y, testpos.z, true)
to_test:set_if_not_in(tested, testpos.x - 1, testpos.y, testpos.z, true)
to_test:set_if_not_in(tested, testpos.x, testpos.y + 1, testpos.z, true)
to_test:set_if_not_in(tested, testpos.x, testpos.y - 1, testpos.z, true)
to_test:set_if_not_in(tested, testpos.x, testpos.y, testpos.z + 1, true)
to_test:set_if_not_in(tested, testpos.x, testpos.y, testpos.z - 1, true)
elseif not minetest.registered_nodes[node.name] or minetest.registered_nodes[node.name].buildable_to ~= true then
-- Tracks whether the digtron is hovering in mid-air. If any part of the digtron array touches something solid it gains traction.
-- Allowing unknown nodes to provide traction, since they're not buildable_to either
self.traction = self.traction + 1
end
testpos, _ = to_test:pop()
end
digtron.award_layout(self, player) -- hook for achievements mod
to_test:clear()
tested:clear()
return self
end
------------------------------------------------------------------------
-- Rotation
local facedir_rotate = {
['x'] = {
[-1] = {[0]=4, 5, 6, 7, 22, 23, 20, 21, 0, 1, 2, 3, 13, 14, 15, 12, 19, 16, 17, 18, 10, 11, 8, 9}, -- 270 degrees
[1] = {[0]=8, 9, 10, 11, 0, 1, 2, 3, 22, 23, 20, 21, 15, 12, 13, 14, 17, 18, 19, 16, 6, 7, 4, 5}, -- 90 degrees
},
['y'] = {
[-1] = {[0]=3, 0, 1, 2, 19, 16, 17, 18, 15, 12, 13, 14, 7, 4, 5, 6, 11, 8, 9, 10, 21, 22, 23, 20}, -- 270 degrees
[1] = {[0]=1, 2, 3, 0, 13, 14, 15, 12, 17, 18, 19, 16, 9, 10, 11, 8, 5, 6, 7, 4, 23, 20, 21, 22}, -- 90 degrees
},
['z'] = {
[-1] = {[0]=16, 17, 18, 19, 5, 6, 7, 4, 11, 8, 9, 10, 0, 1, 2, 3, 20, 21, 22, 23, 12, 13, 14, 15}, -- 270 degrees
[1] = {[0]=12, 13, 14, 15, 7, 4, 5, 6, 9, 10, 11, 8, 20, 21, 22, 23, 0, 1, 2, 3, 16, 17, 18, 19}, -- 90 degrees
}
}
local wallmounted_rotate = {
['x'] = {
[-1] = {[0]=4, 5, 2, 3, 1, 0}, -- 270 degrees
[1] = {[0]=5, 4, 2, 3, 0, 1}, -- 90 degrees
},
['y'] = {
[-1] = {[0]=0, 1, 4, 5, 3, 2}, -- 270 degrees
[1] = {[0]=0, 1, 5, 4, 2, 3}, -- 90 degrees
},
['z'] = {
[-1] = {[0]=3, 2, 0, 1, 4, 5}, -- 270 degrees
[1] = {[0]=2, 3, 1, 0, 4, 5}, -- 90 degrees
}
}
--90 degrees CW about x-axis: (x, y, z) -> (x, -z, y)
--90 degrees CCW about x-axis: (x, y, z) -> (x, z, -y)
--90 degrees CW about y-axis: (x, y, z) -> (-z, y, x)
--90 degrees CCW about y-axis: (x, y, z) -> (z, y, -x)
--90 degrees CW about z-axis: (x, y, z) -> (y, -x, z)
--90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z)
-- operates directly on the pos vector
local rotate_pos = function(axis, direction, pos)
if axis == "x" then
if direction < 0 then
local temp_z = pos.z
pos.z = pos.y
pos.y = -temp_z
else
local temp_z = pos.z
pos.z = -pos.y
pos.y = temp_z
end
elseif axis == "y" then
if direction < 0 then
local temp_x = pos.x
pos.x = -pos.z
pos.z = temp_x
else
local temp_x = pos.x
pos.x = pos.z
pos.z = -temp_x
end
else
if direction < 0 then
local temp_x = pos.x
pos.x = -pos.y
pos.y = temp_x
else
local temp_x = pos.x
pos.x = pos.y
pos.y = -temp_x
end
end
return pos
end
-- operates directly on the pos vector
local subtract_in_place = function(pos, subtract)
pos.x = pos.x - subtract.x
pos.y = pos.y - subtract.y
pos.z = pos.z - subtract.z
return pos
end
local add_in_place = function(pos, add)
pos.x = pos.x + add.x
pos.y = pos.y + add.y
pos.z = pos.z + add.z
return pos
end
local rotate_node_image = function(node_image, origin, axis, direction, old_pos_pointset)
-- Facings
if node_image.paramtype2 == "wallmounted" then
node_image.node.param2 = wallmounted_rotate[axis][direction][node_image.node.param2]
elseif node_image.paramtype2 == "facedir" then
node_image.node.param2 = facedir_rotate[axis][direction][node_image.node.param2]
end
if node_image.build_item_paramtype2 == "wallmounted" then
node_image.meta.fields.build_facing = wallmounted_rotate[axis][direction][tonumber(node_image.meta.fields.build_facing)]
elseif node_image.build_item_paramtype2 == "facedir" then
node_image.meta.fields.build_facing = facedir_rotate[axis][direction][tonumber(node_image.meta.fields.build_facing)]
end
node_image.meta.fields.waiting = nil -- If we're rotating a controller that's in the "waiting" state, clear it. Otherwise it may stick like that.
-- record the old location so we can destroy the old node if the rotation operation is possible
old_pos_pointset:set(node_image.pos.x, node_image.pos.y, node_image.pos.z, true)
-- position in space relative to origin
local pos = subtract_in_place(node_image.pos, origin)
pos = rotate_pos(axis, direction, pos)
-- Move back to original reference frame
node_image.pos = add_in_place(pos, origin)
return node_image
end
local top = {
[0]={axis="y", dir=-1},
{axis="z", dir=1},
{axis="z", dir=-1},
{axis="x", dir=1},
{axis="x", dir=-1},
{axis="y", dir=1},
}
-- Rotates 90 degrees widdershins around the axis defined by facedir (which in this case is pointing out the front of the node, so it needs to be converted into an upward-pointing axis internally)
function DigtronLayout.rotate_layout_image(self, facedir)
if self == nil or self.all == nil or self.controller == nil or self.old_pos_pointset == nil then
-- this should not be possible, but if it is then abort.
return false
end
-- To convert this into the direction the "top" of the axle node is pointing in:
-- 0, 1, 2, 3 == (0,1,0)
-- 4, 5, 6, 7 == (0,0,1)
-- 8, 9, 10, 11 == (0,0,-1)
-- 12, 13, 14, 15 == (1,0,0)
-- 16, 17, 18, 19 == (-1,0,0)
-- 20, 21, 22, 23== (0,-1,0)
local params = top[math.floor(facedir/4)]
for k, node_image in pairs(self.all) do
rotate_node_image(node_image, self.controller, params.axis, params.dir, self.old_pos_pointset)
end
return self
end
-----------------------------------------------------------------------------------------------
-- Translation
function DigtronLayout.move_layout_image(self, dir)
self.extents_max_x = self.extents_max_x + dir.x
self.extents_min_x = self.extents_min_x + dir.x
self.extents_max_y = self.extents_max_y + dir.y
self.extents_min_y = self.extents_min_y + dir.y
self.extents_max_z = self.extents_max_z + dir.z
self.extents_min_z = self.extents_min_z + dir.z
for k, node_image in pairs(self.all) do
self.old_pos_pointset:set(node_image.pos.x, node_image.pos.y, node_image.pos.z, true)
node_image.pos = add_in_place(node_image.pos, dir)
self.nodes_dug:set(node_image.pos.x, node_image.pos.y, node_image.pos.z, false) -- we've moved a digtron node into this space, mark it so that we don't dig it.
end
end
-----------------------------------------------------------------------------------------------
-- Writing to world
function DigtronLayout.can_write_layout_image(self)
for k, node_image in pairs(self.all) do
--check if we're moving into a protected node
if self.protected:get(node_image.pos.x, node_image.pos.y, node_image.pos.z) then
return false
end
-- check if the target node is buildable_to or is marked as part of the digtron that's moving
if not (
self.old_pos_pointset:get(node_image.pos.x, node_image.pos.y, node_image.pos.z)
or minetest.registered_nodes[minetest.get_node(node_image.pos).name].buildable_to
) then
return false
end
end
return true
end
-- We need to call on_dignode and on_placenode for dug and placed nodes,
-- but that triggers falling nodes (sand and whatnot) and destroys Digtrons
-- if done during mid-write. So we need to defer the calls until after the
-- Digtron has been fully written.
-- using local counters and shared tables like this allows us to avoid some needless allocating and garbage-collecting of tables
local dug_nodes_count = 0
local dug_node_pos = {}
local dug_node = {}
local dug_node_meta = {}
local placed_nodes_count = 0
local placed_node_pos = {}
local placed_new_node = {}
local placed_old_node = {}
local node_callbacks = function(player)
if dug_nodes_count > 0 then
for i = 1, dug_nodes_count do
local old_pos = dug_node_pos[i]
local old_node = dug_node[i]
local old_meta = dug_node_meta[i]
for _, callback in ipairs(minetest.registered_on_dignodes) do
-- Copy pos and node because callback can modify them
local pos_copy = {x=old_pos.x, y=old_pos.y, z=old_pos.z}
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
callback(pos_copy, oldnode_copy, digtron.fake_player)
end
local old_def = minetest.registered_nodes[old_node.name]
if old_def ~= nil and old_def.after_dig_node ~= nil then
old_def.after_dig_node(old_pos, old_node, old_meta, player)
end
end
end
if placed_nodes_count > 0 then
for i = 1, placed_nodes_count do
local new_pos = placed_node_pos[i]
local new_node = placed_new_node[i]
local old_node = placed_old_node[i]
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Copy pos and node because callback can modify them
local pos_copy = {x=new_pos.x, y=new_pos.y, z=new_pos.z}
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
local newnode_copy = {name=new_node.name, param1=new_node.param1, param2=new_node.param2}
callback(pos_copy, newnode_copy, digtron.fake_player, oldnode_copy)
end
local new_def = minetest.registered_nodes[new_node.name]
if new_def ~= nil and new_def.after_place_node ~= nil then
new_def.after_place_node(new_pos, player)
end
end
end
end
local set_node_with_retry = function(pos, node)
local start_time = minetest.get_us_time()
while not minetest.set_node(pos, node) do
if minetest.get_us_time() - start_time > 1000000 then -- 1 second in useconds
return false
end
end
return true
end
local set_meta_with_retry = function(meta, meta_table)
local start_time = minetest.get_us_time()
while not meta:from_table(meta_table) do
if minetest.get_us_time() - start_time > 1000000 then -- 1 second in useconds
return false
end
end
return true
end
local air_node = {name="air"}
function DigtronLayout.write_layout_image(self, player)
-- destroy the old digtron
local oldpos, _ = self.old_pos_pointset:pop()
while oldpos ~= nil do
local old_node = minetest.get_node(oldpos)
local old_meta = minetest.get_meta(oldpos)
if not set_node_with_retry(oldpos, air_node) then
minetest.log("error", "DigtronLayout.write_layout_image failed to destroy old Digtron node, aborting write.")
return false
end
dug_nodes_count = dug_nodes_count + 1
dug_node_pos[dug_nodes_count] = oldpos
dug_node[dug_nodes_count] = old_node
dug_node_meta[dug_nodes_count] = old_meta
oldpos, _ = self.old_pos_pointset:pop()
end
-- create the new one
for k, node_image in pairs(self.all) do
local new_pos = node_image.pos
local new_node = node_image.node
local old_node = minetest.get_node(new_pos)
if not (set_node_with_retry(new_pos, new_node) and set_meta_with_retry(minetest.get_meta(new_pos), node_image.meta)) then
minetest.log("error", "DigtronLayout.write_layout_image failed to write a Digtron node, aborting write.")
return false
end
placed_nodes_count = placed_nodes_count + 1
placed_node_pos[placed_nodes_count] = new_pos
placed_new_node[placed_nodes_count] = new_node
placed_old_node[placed_nodes_count] = old_node
end
-- fake_player will be passed to callbacks to prevent actual player from "taking the blame" for this action.
-- For example, the hunger mod shouldn't be making the player hungry when he moves Digtron.
digtron.fake_player:update(self.controller, player:get_player_name())
-- note that the actual player is still passed to the per-node after_place_node and after_dig_node, should they exist.
node_callbacks(player)
dug_nodes_count = 0
placed_nodes_count = 0
return true
end
---------------------------------------------------------------------------------------------
-- Serialization. Currently only serializes the data that is needed by the crate, upgrade this function if more is needed
function DigtronLayout.serialize(self)
-- serialize can't handle ItemStack objects, convert them to strings.
for _, node_image in pairs(self.all) do
for k, inv in pairs(node_image.meta.inventory) do
for index, item in pairs(inv) do
inv[index] = item:to_string()
end
end
end
return minetest.serialize({controller=self.controller, all=self.all})
end
function DigtronLayout.deserialize(layout_string)
local self = {}
setmetatable(self, DigtronLayout)
if not layout_string or layout_string == "" then
return nil
end
local deserialized_layout = minetest.deserialize(layout_string)
self.all = deserialized_layout.all
self.controller = deserialized_layout.controller
self.old_pos_pointset = Pointset.create() -- needed by the write_layout method, leave empty
return self
end

@ -1,77 +0,0 @@
-- A simple special-purpose class, this is used for building up sets of three-dimensional points for fast reference
Pointset = {}
Pointset.__index = Pointset
-- from builtin\game\misc.lua, modified to take values directly to avoid creating an intermediate vector
local hash_node_position_values = function(x, y, z)
return (z + 32768) * 65536 * 65536
+ (y + 32768) * 65536
+ x + 32768
end
function Pointset.create()
local set = {}
setmetatable(set,Pointset)
set.points = {}
return set
end
function Pointset:clear()
local points = self.points
for k, v in pairs(points) do
points[k] = nil
end
end
function Pointset:set(x, y, z, value)
-- sets a value in the 3D array "points".
self.points[hash_node_position_values(x,y,z)] = value
end
function Pointset:set_if_not_in(excluded, x, y, z, value)
-- If a value is not already set for this point in the 3D array "excluded", set it in "points"
if excluded:get(x, y, z) ~= nil then
return
end
self:set(x, y, z, value)
end
function Pointset:get(x, y, z)
-- return a value from the 3D array "points"
return self.points[hash_node_position_values(x,y,z)]
end
function Pointset:set_pos(pos, value)
self:set(pos.x, pos.y, pos.z, value)
end
function Pointset:set_pos_if_not_in(excluded, pos, value)
self:set_if_not_in(excluded, pos.x, pos.y, pos.z, value)
end
function Pointset:get_pos(pos)
return self:get(pos.x, pos.y, pos.z)
end
function Pointset:pop()
-- returns a point that's in the 3D array, and then removes it.
local hash, value = next(self.points)
if hash == nil then return nil end
local pos = minetest.get_position_from_hash(hash)
self.points[hash] = nil
return pos, value
end
function Pointset:get_pos_list(value)
-- Returns a list of all points with the given value in standard Minetest vector format. If no value is provided, returns all points
local outlist = {}
for hash, pointsval in pairs(self.points) do
if value == nil or pointsval == value then
table.insert(outlist, minetest.get_position_from_hash(hash))
end
end
return outlist
end

@ -1,69 +0,0 @@
local CONFIG_FILE_PREFIX = "digtron_"
digtron.config = {}
local print_settingtypes = false
local function setting(stype, name, default, description)
local value
if stype == "bool" then
value = minetest.settings:get_bool(CONFIG_FILE_PREFIX..name)
elseif stype == "string" then
value = minetest.settings:get(CONFIG_FILE_PREFIX..name)
elseif stype == "int" or stype == "float" then
value = tonumber(minetest.settings:get(CONFIG_FILE_PREFIX..name))
end
if value == nil then
value = default
end
digtron.config[name] = value
if print_settingtypes then
minetest.debug(CONFIG_FILE_PREFIX..name.." ("..description..") "..stype.." "..tostring(default))
end
end
setting("bool", "uses_resources", true, "Digtron uses resources when active")
setting("bool", "lava_impassible", true, "Lava counts as a protected node")
setting("bool", "damage_creatures", true, "Diggers damage creatures") -- TODO: legacy setting, remove eventually
setting("int", "damage_hp", 8, "Damage diggers do")
setting("int", "size_limit", 1000, "Digtron size limit in nodes per moving digtron")
if digtron.config.damage_creatures == false then digtron.config.damage_hp = 0 end -- TODO: remove when damage_creatures is removed
-- Enables the spray of particles out the back of a digger head and puffs of smoke from the controller
local particle_effects = minetest.settings:get_bool("enable_particles")
digtron.config.particle_effects = particle_effects or particle_effects == nil -- default true
setting("int", "maximum_extrusion", 25, "Maximum builder extrusion distance")
setting("float", "cycle_time", 1.0, "Minimum Digtron cycle time")
setting("float", "traction_factor", 3.0, "Traction factor")
-- fuel costs. For comparison, in the default game:
-- one default tree block is 30 units
-- one coal lump is 40 units
-- one coal block is 370 units (apparently it's slightly more productive making your coal lumps into blocks before burning)
-- one book is 3 units
-- how much fuel is required to dig a node if not in one of the following groups.
setting("float", "dig_cost_default", 3.0, "Default dig cost")
-- eg, stone
setting("float", "dig_cost_cracky", 1.0, "Cracky dig cost")
-- eg, dirt, sand
setting("float", "dig_cost_crumbly", 0.5, "Crumbly dig cost")
-- eg, wood
setting("float", "dig_cost_choppy", 0.75, "Choppy dig cost")
-- how much fuel is required to build a node
setting("float", "build_cost", 1.0, "Build cost")
-- How much charge (an RE battery holds 10000 EU) is equivalent to 1 unit of heat produced by burning coal
-- With 100, the battery is 2.5 better than a coal lump, yet 3.7 less powerful than a coal block
-- Being rechargeable should pay off for this "average" performance.
setting("int", "power_ratio", 100, "The electrical charge to 1 coal heat unit conversion ratio")
setting("float", "marker_crate_good_duration", 3.0, "Duration that 'good' crate markers last")
setting("float", "marker_crate_bad_duration", 9.0, "Duration that 'bad' crate markers last")
setting("bool", "emerge_unloaded_mapblocks", true, "When Digtron encounters unloaded map blocks, emerge them.")

200
controller.lua Normal file

@ -0,0 +1,200 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local controller_nodebox = {
type = "fixed",
fixed = {
{-0.3125, -0.3125, -0.3125, 0.3125, 0.3125, 0.3125}, -- Core
{-0.1875, 0.3125, -0.1875, 0.1875, 0.5, 0.1875}, -- +y_connector
{-0.1875, -0.5, -0.1875, 0.1875, -0.3125, 0.1875}, -- -y_Connector
{0.3125, -0.1875, -0.1875, 0.5, 0.1875, 0.1875}, -- +x_connector
{-0.5, -0.1875, -0.1875, -0.3125, 0.1875, 0.1875}, -- -x_connector
{-0.1875, -0.1875, 0.3125, 0.1875, 0.1875, 0.5}, -- +z_connector
{-0.5, 0.125, -0.5, -0.125, 0.5, -0.3125}, -- back_connector_3
{0.125, 0.125, -0.5, 0.5, 0.5, -0.3125}, -- back_connector_1
{0.125, -0.5, -0.5, 0.5, -0.125, -0.3125}, -- back_connector_2
{-0.5, -0.5, -0.5, -0.125, -0.125, -0.3125}, -- back_connector_4
},
}
local get_controller_unconstructed_formspec = function(pos, player_name)
return "size[8,8]button[1,1;1,1;construct;Construct]"
end
local get_controller_constructed_formspec = function(pos, digtron_id, player_name)
return "size[9,9]button[1,1;1,1;deconstruct;Deconstruct]"
end
minetest.register_node("digtron:controller", {
description = S("Digtron Control Module"),
_doc_items_longdesc = nil,
_doc_items_usagehelp = nil,
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90",
"digtron_plate.png^[transformR270",
"digtron_plate.png",
"digtron_plate.png^[transformR180",
"digtron_plate.png",
"digtron_plate.png^digtron_control.png",
},
drawtype = "nodebox",
node_box = controller_nodebox,
-- on_construct = function(pos)
-- end,
on_dig = function(pos, node, digger)
local meta = minetest.get_meta(pos)
if meta:get("digtron_id") ~= nil then
return
else
return minetest.node_dig(pos, node, digger)
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local digtron_id = meta:get("digtron_id")
local player_name = clicker:get_player_name()
if digtron_id ~= "" then
minetest.show_formspec(player_name,
"digtron_controller_unconstructed:"..minetest.pos_to_string(pos)..":"..player_name,
get_controller_unconstructed_formspec(pos, player_name))
else
-- initialized
minetest.show_formspec(player_name,
"digtron_controller_constructed:"..minetest.pos_to_string(pos)..":"..player_name..":"..digtron_id,
get_controller_construted_formspec(pos, digtron_id, player_name))
end
end,
on_timer = function(pos, elapsed)
end,
})
local cardinal_directions = {
{x=1,y=0,z=0},
{x=-1,y=0,z=0},
{x=0,y=1,z=0},
{x=0,y=-1,z=0},
{x=0,y=0,z=1},
{x=0,y=0,z=-1},
}
local origin_hash = minetest.hash_node_position({x=0,y=0,z=0})
local get_all_adjacent_digtron_nodes
get_all_adjacent_digtron_nodes = function(pos, digtron_nodes, not_digtron)
for _, dir in ipairs(cardinal_directions) do
local test_pos = vector.add(pos, dir)
local test_hash = minetest.hash_node_position(test_pos)
if not (digtron_nodes[test_hash] or not_digtron[test_hash]) then -- don't test twice
local test_node = minetest.get_node(test_pos)
local group_value = minetest.get_item_group(test_node.name, "digtron")
if group_value > 0 then
digtron_nodes[test_hash] = test_node
get_all_adjacent_digtron_nodes(test_pos, digtron_nodes, not_digtron) -- recurse
else
not_digtron[test_hash] = test_node
end
end
end
end
digtron.construct = function(pos, player_name)
local node = minetest.get_node(pos)
if node.name ~= "digtron:controller" then
-- Called on an incorrect node
minetest.log("error", "[Digtron] digtron.construct called with pos " .. minetest.pos_to_string(pos) .. " but the node at this location was " .. node.name)
return nil
end
local meta = minetest.get_meta(pos)
if meta:get("digtron_id") ~= nil then
-- Already constructed. TODO: validate that the digtron_id actually exists as well
minetest.log("error", "[Digtron] digtron.construct called with pos " .. minetest.pos_to_string(pos) .. " but the controller at this location was already part of a constructed Digtron.")
return nil
end
local root_hash = minetest.hash_node_position(pos)
local digtron_nodes = {[root_hash] = node}
local not_digtron = {}
get_all_adjacent_digtron_nodes(pos, digtron_nodes, not_digtron)
for hash, node in pairs(digtron_nodes) do
local relative_hash = hash - root_hash + origin_hash
minetest.chat_send_all("constructing " .. minetest.pos_to_string(minetest.get_position_from_hash(relative_hash)))
local digtron_meta
if hash == root_hash then
digtron_meta = meta -- we're processing the controller, we already have a reference to its meta
else
digtron_meta = minetest.get_meta(minetest.get_position_from_hash(hash))
end
local meta_table = digtron_meta:to_table()
meta_table.node = node
-- Process inventories specially
-- Builder inventory gets turned into an itemname in a special key in the builder's meta
-- fuel and main get added to corresponding detached inventory lists
-- then wipe them from the meta_table. They'll be re-added in digtron.deconstruct.
--meta_table.inventory = nil
node.param1 = nil -- we don't care about param1, wipe it to save space
minetest.chat_send_all(dump(meta_table))
end
end
-- Dealing with an unconstructed Digtron controller
minetest.register_on_player_receive_fields(function(player, formname, fields)
local formname_split = formname:split(":")
if #formname_split ~= 3 or formname_split[1] ~= "digtron_controller_unconstructed" then
return
end
local pos = minetest.string_to_pos(formname_split[2])
if pos == nil then
minetest.log("error", "[Digtron] Unable to parse position from formspec name " .. formname)
return
end
local name = formname_split[3]
if player:get_player_name() ~= name then
return
end
if fields.construct then
local digtron_id = digtron.construct(pos, name)
if digtron_id then
minetest.show_formspec(name,
"digtron_controller_constructed:"..minetest.pos_to_string(pos)..":"..name..":"..digtron_id,
get_controller_construted_formspec(pos, digtron_id, name))
end
end
end)
-- Controlling a fully armed and operational Digtron
minetest.register_on_player_receive_fields(function(player, formname, fields)
local formname_split = formname:split(":")
if #formname_split ~= 4 or formname_split[1] ~= "digtron_controller_constructed" then
return
end
local pos = minetest.string_to_pos(formname_split[2])
if pos == nil then
minetest.log("error", "[Digtron] Unable to parse position from formspec name " .. formname)
return
end
local name = formname_split[3]
if player:get_player_name() ~= name then
return
end
local digtron_id = formname_splot[4]
if fields.deconstruct then
minetest.chat_send_all("Deconstructing " .. digtron_id)
end
end)

@ -1,8 +1,2 @@
default
pipeworks?
doc?
hopper?
awards?
catacomb?
intllib?
technic?
intllib?

@ -1,5 +0,0 @@
digtron - a modular tunnel boring/building machine for minetest, v0.7.6 - 2017-01-22
Forum : https://forum.minetest.net/viewtopic.php?t=16295
Github: https://github.com/FaceDeer/digtron/
Wiki: http://wiki.minetest.net/Mods/digtron

311
doc.lua

@ -1,311 +0,0 @@
digtron.doc = {}
if not minetest.get_modpath("doc") then
return
end
local coal_fuel = minetest.get_craft_result({method="fuel", width=1, items={"default:coal_lump"}}).time
local dig_stone_count = coal_fuel/digtron.config.dig_cost_cracky
local dig_dirt_count = coal_fuel/digtron.config.dig_cost_crumbly
local dig_wood_count = coal_fuel/digtron.config.dig_cost_choppy
local build_count = coal_fuel/digtron.config.build_cost
local battery_ratio = (10000/digtron.config.power_ratio) / coal_fuel
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil
local hoppers_enabled = minetest.get_modpath("hopper") and hopper ~= nil and hopper.add_container ~= nil
digtron.doc.core_longdesc = S("A crafting component used in the manufacture of all Digtron block types.")
digtron.doc.core_usagehelp = S("Place the Digtron Core in the center of the crafting grid. All Digtron recipes consist of arranging various other materials around the central Digtron Core.")
--------------------------------------------------------------------
digtron.doc.builder_longdesc = S("A 'builder' module for a Digtron. By itself it does nothing, but as part of a Digtron it is used to construct user-defined blocks.")
digtron.doc.builder_usagehelp = S("A builder head is the most complex component of this system. It has period and offset properties, and also an inventory slot where you \"program\" it by placing an example of the block type that you want it to build."
.."\n\n"..
"When the \"Save & Show\" button is clicked the properties for period and offset will be saved, and markers will briefly be shown to indicate where the nearest spots corresponding to those values are. The builder will build its output at those locations provided it is moving along the matching axis."
.."\n\n"..
"There is also an \"Extrusion\" setting. This allows your builder to extrude a line of identical blocks from the builder output, in the direction the output side is facing, until it reaches an obstruction or until it reaches the extrusion limit. This can be useful for placing columns below a bridge, or for filling a large volume with a uniform block type without requiring a large number of builder heads."
.."\n\n"..
"The \"output\" side of a builder is the side with a black crosshair on it."
.."\n\n"..
"Builders also have a \"facing\" setting. If you haven't memorized the meaning of the 24 facing values yet, builder heads have a helpful \"Read & Save\" button to fill this value in for you. Simply build a temporary instance of the block in the output location in front of the builder, adjust it to the orientation you want using the screwdriver tool, and then when you click the \"Read & Save\" button the block's facing will be read and saved."
.."\n\n"..
"Note: if more than one builder tries to build into the same space simultaneously, it is not predictable which builder will take priority. One will succeed and the other will fail. You should arrange your builders to avoid this for consistent results.")
--------------------------------------------------------------------
digtron.doc.inventory_longdesc = S("Stores building materials for use by builder heads and materials dug up by digger heads.")
digtron.doc.inventory_usagehelp = S("Inventory modules have the same capacity as a chest. They're used both for storing the products of the digger heads and as the source of materials used by the builder heads. A digging machine whose builder heads are laying down cobble can automatically self-replenish in this way, but note that an inventory module is still required as buffer space even if the digger heads produced everything needed by the builder heads in a given cycle."
.."\n\n"..
"Inventory modules are not required for a digging-only machine. If there's not enough storage space to hold the materials produced by the digging heads the excess material will be ejected out the back of the control block. They're handy for accumulating ores and other building materials, though."
.."\n\n"..
"Digging machines can have multiple inventory modules added to expand their capacity.")
if hoppers_enabled then
digtron.doc.inventory_usagehelp = digtron.doc.inventory_usagehelp
.."\n\n"..
S("Digtron inventory modules are compatible with hoppers, adjacent hoppers will add to or take from their inventories. Hoppers are not part of the Digtron and will not move with it, however. They may be useful for creating a \"docking station\" for a Digtron.")
end
if pipeworks_enabled then
digtron.doc.inventory_usagehelp = digtron.doc.inventory_usagehelp
.."\n\n"..
S("Inventory modules are compatible with Pipeworks blocks. When a Digtron moves one of the inventory modules adjacent to a pipe it will automatically hook up to it, and disconnect again when it moves on.")
end
local standard_fuel_doc = S("When a control unit is triggered, it will tally up how much fuel is required for the next cycle and then burn items from the fuel hopper until a sufficient amount of heat has been generated to power the operation. Any leftover heat will be retained by the control unit for use in the next cycle; this is the \"heat remaining in controller furnace\". This means you don't have to worry too much about what kinds of fuel you put in the fuel store, none will be wasted (unless you dig away a control unit with some heat remaining in it, that heat does get wasted)."
.."\n\n"..
"By using one lump of coal as fuel a digtron can:\n"..
"\tBuild @1 blocks\n"..
"\tDig @2 stone blocks\n"..
"\tDig @3 wood blocks\n"..
"\tDig @4 dirt or sand blocks", math.floor(build_count), math.floor(dig_stone_count), math.floor(dig_wood_count), math.floor(dig_dirt_count))
digtron.doc.fuelstore_longdesc = S("Stores fuel to run a Digtron")
digtron.doc.fuelstore_usagehelp = S("Digtrons have an appetite. Build operations and dig operations require a certain amount of fuel, and that fuel comes from fuel store modules. Note that movement does not require fuel, only digging and building.")
.."\n\n".. standard_fuel_doc
if hoppers_enabled then
digtron.doc.fuelstore_usagehelp = digtron.doc.fuelstore_usagehelp
.."\n\n"..
S("Digtron fuel store modules are compatible with hoppers, adjacent hoppers will add to or take from their inventories. Hoppers are not part of the Digtron and will not move with it, however. They may be useful for creating a \"docking station\" for a Digtron.")
end
if pipeworks_enabled then
digtron.doc.fuelstore_usagehelp = digtron.doc.fuelstore_usagehelp
.."\n\n"..
S("Fuel modules are compatible with Pipeworks blocks. When a Digtron moves one of the inventory modules adjacent to a pipe it will automatically hook up to it, and disconnect again when it moves on.")
end
-- Battery holders
digtron.doc.battery_holder_longdesc = S("Holds RE batteries to run a Digtron")
digtron.doc.battery_holder_usagehelp = S("Digtrons have an appetite, and it can be satisfied by electricity as well. Build operations and dig operations require a certain amount of power, and that power comes from the batteries place in the holder. Note that movement does not consume charge, only digging and building."
.."\n\n"..
"When a control unit is triggered, it will tally up how much power is required for the next cycle and then discharge the batteries in the battery holder until a sufficient amount of heat has been generated to power the operation. Any leftover heat will be retained by the control unit for use in the next cycle; this is the \"heat remaining in controller furnace\". Thus no power is wasted (unless you dig away a control unit with some heat remaining in it, that heat does get wasted), and the discharged batteries can be taken away to be recharged."
.."\n\n"..
"One fully charged battery can:\n"..
"\tBuild @1 blocks\n"..
"\tDig @2 stone blocks\n"..
"\tDig @3 wood blocks\n"..
"\tDig @4 dirt or sand blocks", math.floor(build_count*battery_ratio), math.floor(dig_stone_count*battery_ratio), math.floor(dig_wood_count*battery_ratio), math.floor(dig_dirt_count*battery_ratio))
if pipeworks_enabled then
digtron.doc.battery_holder_usagehelp = digtron.doc.battery_holder_usagehelp
.."\n\n"..
S("Fuel modules are compatible with Pipeworks blocks. When a Digtron moves one of the inventory modules adjacent to a pipe it will automatically hook up to it, and disconnect again when it moves on.")
end
digtron.doc.combined_storage_longdesc = S("Stores fuel for a Digtron and also has an inventory for building materials")
digtron.doc.combined_storage_usagehelp = S("For smaller jobs the two dedicated modules may simply be too much of a good thing, wasting precious Digtron space to give unneeded capacity. The combined storage module is the best of both worlds, splitting its internal space between building material inventory and fuel storage. It has 3/4 building material capacity and 1/4 fuel storage capacity.") .. "\n\n" .. standard_fuel_doc
if hoppers_enabled then
digtron.doc.combined_storage_usagehelp = digtron.doc.combined_storage_usagehelp
.."\n\n"..
S("Digtron inventory modules are compatible with hoppers, adjacent hoppers will add to or take from their inventories. A hopper on top of a combined inventory module will insert items into its general inventory, a side hopper will insert items into its fuel inventory, and a hopper on the bottom of a combined inventory module will take items from its general inventory. Hoppers are not part of the Digtron and will not move with it, however. They may be useful for creating a \"docking station\" for a Digtron.")
end
if pipeworks_enabled then
digtron.doc.combined_storage_usagehelp = digtron.doc.combined_storage_usagehelp
.."\n\n"..
S("Combination modules are compatible with Pipeworks blocks. When a Digtron moves one of the inventory modules adjacent to a pipe it will automatically hook up to it, and disconnect again when it moves on. Items are extracted from the \"main\" inventory, and items coming into the combination module from any direction except the underside are inserted into \"main\". However, a pipe entering the combination module from the underside will attempt to insert items into the \"fuel\" inventory instead.")
end
---------------------------------------------------------------------
local locked_suffix = "\n\n" .. S("This is the \"locked\" version of the Digtron crate. It can only be used by the player who placed it.")
digtron.doc.empty_crate_longdesc = S("An empty crate that a Digtron can be stored in")
digtron.doc.empty_crate_usagehelp = S("Digtrons can be pushed around and rotated, and that may be enough for getting them perfectly positioned for the start of a run. But once your digger is a kilometer down under a shaft filled with stairs, how to get it back to the surface to run another pass?"
.."\n\n"..
"Place an empty Digtron crate next to a Digtron and right-click it to pack the Digtron (and all its inventory and settings) into the crate. You can then collect the crate, bring it somewhere else, build the crate, and then unpack the Digtron from it again. The Digtron will appear in the same relative location and orientation to the crate as when it was packed away inside it.")
digtron.doc.loaded_crate_longdesc = S("A crate containing a Digtron array")
digtron.doc.loaded_crate_usagehelp = S("This crate contains a Digtron assembly that was stored in it earlier. Place it somewhere and right-click on it to access the label text that was applied to it. There's also a button that causes it to display the shape the deployed Digtron would take if you unpacked the crate, marking unbuildable blocks with a warning marker. And finally there's a button to actually deploy the Digtron, replacing this loaded crate with an empty that can be reused later.")
digtron.doc.empty_locked_crate_longdesc = digtron.doc.empty_crate_longdesc
digtron.doc.empty_locked_crate_usagehelp = digtron.doc.empty_crate_usagehelp .. locked_suffix
digtron.doc.loaded_locked_crate_longdesc = digtron.doc.loaded_crate_longdesc
digtron.doc.loaded_locked_crate_usagehelp = digtron.doc.loaded_crate_usagehelp .. locked_suffix
----------------------------------------------------------------------
digtron.doc.controller_longdesc = S("A basic controller to make a Digtron array move and operate.")
digtron.doc.controller_usagehelp = S("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."
.."\n\n"..
"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)."
.."\n\n"..
"If you're standing within the digging machine's volume, or in a block adjacent to it, you will be pulled along with the machine when it moves.")
digtron.doc.auto_controller_longdesc = S("A more sophisticated controller that includes the ability to set the number of cycles it will run for, as well as diagonal movement.")
digtron.doc.auto_controller_usagehelp = S("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."
.."\n\n"..
"The digging machine will go in the direction that the control module is oriented."
.."\n\n"..
"Auto-controllers can also be set to move diagonally by setting the \"Slope\" parameter to a non-zero value. The controller will then shunt the Digtron in the direction of the arrows painted on its sides every X steps it moves. The Digtron will trigger dig heads when it shunts to the side, but will not trigger builder modules or intermittent dig heads. The \"Offset\" setting determines at what point the lateral motion will take place."
.."\n\n"..
"The \"Stop block\" inventory slot in an auto-controller allows you to program an auto-controller to treat certain block types as impenetrable obstructions. This can allow you to fence a Digtron in with something so you don't have to carefully count exactly how many steps it should take, for example."
.."\n\n"..
"Note that the Digtron detects an undiggable block by the item that would be produced when digging it. Setting cobble as the stop block will make both cobble and regular stone undiggable, but setting a block of regular stone (produced from cobble in a furnace) as the stop block will *not* stop a Digtron from digging regular stone (since digging regular stone produces cobble, not stone).")
digtron.doc.pusher_longdesc = S("A simplified controller that merely moves a Digtron around without triggering its builder or digger modules")
digtron.doc.pusher_usagehelp = S("Aka the \"can you rebuild it six inches to the left\" module. This is a much simplified control module that does not trigger the digger or builder heads when right-clicked, it only moves the digging machine. It's up to you to ensure there's space for it to move into."
.."\n\n"..
"Since movement alone does not require fuel, a pusher module has no internal furnace. Pushers also don't require traction, since their primary purpose is repositioning Digtrons let's say they have a built-in crane or something.")
digtron.doc.axle_longdesc = S("A device that allows one to rotate their Digtron into new orientations")
digtron.doc.axle_usagehelp = S("This magical module can rotate a Digtron array in place around itself. Right-clicking on it will rotate the Digtron 90 degrees in the direction the orange arrows on its sides indicate (widdershins around the Y axis by default, use the screwdriver to change this) assuming there's space for the Digtron in its new orientation. Builders and diggers will not trigger on rotation.")
---------------------------------------------------------------------
digtron.doc.digger_longdesc = S("A standard Digtron digger head")
digtron.doc.digger_usagehelp = S("Facing of a digger head is significant; it will excavate material from the block on the spinning grinder wheel face of the digger head. Generally speaking, you'll want these to face forward - though having them aimed to the sides can also be useful.")
digtron.doc.dual_digger_longdesc = S("Two standard Digtron digger heads merged at 90 degrees to each other")
digtron.doc.dual_digger_usagehelp = S("This digger head is mainly of use when you want to build a Digtron capable of digging diagonal paths. A normal one-direction dig head would be unable to clear blocks in both of the directions it would be called upon to move, resulting in a stuck Digtron."
.."\n\n"..
"One can also make use of dual dig heads to simplify the size and layout of a Digtron, though this is generally not of practical use.")
digtron.doc.dual_soft_digger_longdesc = S("Two standard soft-material Digtron digger heads merged at 90 degrees to each other")
digtron.doc.dual_soft_digger_usagehelp = S("This digger head is mainly of use when you want to build a Digtron capable of digging diagonal paths. A normal one-direction dig head would be unable to clear blocks in both of the directions it would be called upon to move, resulting in a stuck Digtron."
.."\n\n"..
"Like a normal single-direction soft digger head, this digger only excavates material belonging to groups softer than stone."
.."\n\n"..
"One can make use of dual dig heads to simplify the size and layout of a Digtron.")
digtron.doc.intermittent_digger_longdesc = S("A standard Digtron digger head that only triggers periodically")
digtron.doc.intermittent_digger_usagehelp = S("This is a standard digger head capable of digging any material, but it will only trigger periodically as the Digtron moves. This can be useful for punching regularly-spaced holes in a tunnel wall, for example.")
digtron.doc.intermittent_soft_digger_longdesc = S("A standard soft-material Digtron digger head that only triggers periodically")
digtron.doc.intermittent_soft_digger_usagehelp = S("This is a standard soft-material digger head capable of digging any material, but it will only trigger periodically as the Digtron moves. This can be useful for punching regularly-spaced holes in a tunnel wall, for example.")
digtron.doc.soft_digger_longdesc = S("A Digtron digger head that only excavates soft materials")
digtron.doc.soft_digger_usagehelp = S("This specialized digger head is designed to excavate only softer material such as sand or gravel. In technical terms, this digger digs blocks belonging to the \"crumbly\", \"choppy\", \"snappy\", \"oddly_diggable_by_hand\" and \"fleshy\" groups."
.."\n\n"..
"The intended purpose of this digger is to be aimed at the ceiling or walls of a tunnel being dug, making spaces to allow shoring blocks to be inserted into unstable roofs but leaving the wall alone if it's composed of a more stable material."
.."\n\n"..
"It can also serve as part of a lawnmower or tree-harvester.")
---------------------------------------------------------------------
digtron.doc.power_connector_longdesc = S("High-voltage power connector allowing a Digtron to be powered from a Technic power network.")
digtron.doc.power_connector_usagehelp = S("A power connector node automatically hooks into adjacent high-voltage (HV) power cables, but it must be configured to set how much power it will draw from the attached network. Right-click on the power connector to bring up a form that shows the current estimated maximum power usage of the Digtron the power connector is part of and a field where a power value can be entered. The estimated maximum power usage is the amount of power this Digtron will use in the worst case situation, with all of its digger heads digging the toughest material and all of its builder heads building a block simultaneously."
.."\n\n"..
"You can set the power connector's usage lower than this, and if the Digtron is unable to get sufficient power from the network it will use on-board batteries or burnable fuel to make up the shortfall.")
---------------------------------------------------------------------
digtron.doc.inventory_ejector_longdesc = S("An outlet that can be used to eject accumulated detritus from a Digtron's inventory.")
digtron.doc.inventory_ejector_usagehelp = S("When this block is punched it will search the entire inventory of the Digtron and will eject a stack of items taken from it, provided the items are not set for use by any of the Digtron's builders. It will not eject if the destination block is occupied.")
if pipeworks_enabled then
digtron.doc.inventory_ejector_usagehelp = digtron.doc.inventory_ejector_usagehelp
.."\n\n"..
S("Item ejectors are compatible with pipeworks and will automatically connect to a pipeworks tube if one is adjacent in the output location.")
end
---------------------------------------------------------------------
digtron.doc.duplicator_longdesc = S("A device for duplicating an adjacent Digtron using parts from its inventory.")
digtron.doc.duplicator_usagehelp = S("Place the duplicator block adjacent to a Digtron, and then fill the duplicator's inventory with enough parts to recreate the adjacent Digtron. Then place an empty Digtron crate at the duplicator's output (the side with the black \"+\") and click the \"Duplicate\" button in the duplicator's right-click GUI. If enough parts are available the Digtron will be duplicated and packed into the crate, along with all of its programming but with empty inventories.")
---------------------------------------------------------------------
digtron.doc.structure_longdesc = S("Structural component for a Digtron array")
digtron.doc.structure_usagehelp = S("These blocks allow otherwise-disconnected sections of digtron blocks to be linked together. They are not usually necessary for simple diggers but more elaborate builder arrays might have builder blocks that can't be placed directly adjacent to other digtron blocks and these blocks can serve to keep them connected to the controller."
.."\n\n"..
"They may also be used for providing additional traction if your digtron array is very tall compared to the terrain surface that it's touching."
.."\n\n"..
"You can also use them decoratively, or to build a platform to stand on as you ride your mighty mechanical leviathan through the landscape.")
digtron.doc.light_longdesc = S("Digtron light source")
digtron.doc.light_usagehelp = S("A light source that moves along with the digging machine. Convenient if you're digging a tunnel that you don't intend to outfit with torches or other permanent light fixtures. Not quite as bright as a torch since the protective lens tends to get grimy while burrowing through the earth.")
digtron.doc.panel_longdesc = S("Digtron panel")
digtron.doc.panel_usagehelp = S("A structural panel that can be made part of a Digtron to provide shelter for an operator, keep sand out of the Digtron's innards, or just to look cool.")
digtron.doc.edge_panel_longdesc = S("Digtron edge panel")
digtron.doc.edge_panel_usagehelp = S("A pair of structural panels that can be made part of a Digtron to provide shelter for an operator, keep sand out of the Digtron's innards, or just to look cool.")
digtron.doc.corner_panel_longdesc = S("Digtron corner panel")
digtron.doc.corner_panel_usagehelp = S("A trio of structural panels that can be made part of a Digtron to provide shelter for an operator, keep sand out of the Digtron's innards, or just to look cool.")
doc.add_category("digtron",
{
name = S("Digtron"),
description = S("The Digtron system is a set of blocks used to construct tunnel-boring and construction machines."),
sorting = "custom",
sorting_data = {"summary", "concepts", "noises", "tips"},
build_formspec = doc.entry_builders.text_and_gallery,
})
doc.add_entry("digtron", "summary", {
name = S("Summary"),
data = { text = S("Digtron blocks can be used to construct highly customizable and modular tunnel-boring machines, bridge-builders, road-pavers, wall-o-matics, and other such construction/destruction contraptions."
.."\n\n"..
"The basic blocks that can be assembled into a functioning digging machine are:"
.."\n\n"..
"* Diggers, which excavate material in front of them when the machine is triggered\n"..
"* Builders, which build a user-configured block in front of them\n"..
"* Inventory modules, which hold material produced by the digger and provide material to the builders\n"..
"* Control block, used to trigger the machine and move it in a particular direction."
.."\n\n"..
"A digging machine's components must be connected to the control block via a path leading through the faces of the blocks - diagonal connections across edges and corners don't count.")
}})
doc.add_entry("digtron", "concepts", {
name = S("Concepts"),
data = { text =
S("Several general concepts are important when building more sophisticated diggers."
.."\n\n"..
"Facing - a number between 0-23 that determines which direction a block is facing and what orientation it has. Not all blocks make use of facing (basic blocks such as cobble or sand have no facing, for example) so it's not always necessary to set this when configuring a builder head. The facing of already-placed blocks can be altered through the use of the screwdriver tool."
.."\n\n"..
"Period - Builder and digger heads can be made periodic by changing the period value to something other than 1. This determines how frequently they trigger. A period of 1 triggers on every block, a period of 2 triggers once every second block, a period of 3 triggers once every third block, etc. These are useful when setting up a machine to place regularly-spaced features as it goes. For example, you could have a builder head that places a torch every 8 steps, or a digger block that punches a landing in the side of a vertical stairwell at every level."
.."\n\n"..
"Offset - The location at which a periodic module triggers is globally uniform. This is handy if you want to line up the blocks you're building (for example, placing pillars and a crosspiece every 4 blocks in a tunnel, or punching alcoves in a wall to place glass windows). If you wish to change how the pattern lines up, modify the \"offset\" setting."
.."\n\n"..
"Shift-right-clicking - since most of the blocks of the digging machine have control screens associated with right-clicking, building additional blocks on top of them or rotating them with the screwdriver requires the shift key to be held down when right-clicking on them."
.."\n\n"..
"Traction - Digtrons cannot fly. By default, they need to be touching one block of solid ground for every three blocks of Digtron in order to move. Digtrons can fall, though - traction is never needed when a Digtron is moving downward. \"Pusher\" controllers can ignore the need for traction when moving in any direction.")
}})
doc.add_entry("digtron", "noises", {
name = S("Audio cues"),
data = { text =
S("When a digging machine is unable to complete a cycle it will make one of several noises to indicate what the problem is. It will also set its mouseover text to explain what went wrong."
.."\n\n"..
"Squealing traction wheels indicates a mobility problem. If the squealing is accompanied by a buzzer, the digging machine has encountered an obstruction it can't dig through. This could be a protected region (the digging machine has only the priviledges of the player triggering it), a chest containing items, or perhaps the digger was incorrectly designed and can't dig the correctly sized and shaped cavity for it to move forward into. There are many possibilities."
.."\n\n"..
"Squealing traction wheels with no accompanying buzzer indicates that the digging machine doesn't have enough solid adjacent blocks to push off of. Tunnel boring machines cannot fly or swim, not even through lava, and they don't dig fast enough to \"catch sick air\" when they emerge from a cliffside. If you wish to cross a chasm you'll need to ensure that there are builder heads placing a solid surface as you go. If you've built a very tall digtron with a small surface footprint you may need to improve its traction by adding structural modules that touch the ground."
.."\n\n"..
"A buzzer by itself indicates that the Digtron has run out of fuel. There may be traces remaining in the hopper, but they're not enough to execute the next dig/build cycle."
.."\n\n"..
"A ringing bell indicates that there are insufficient materials in inventory to supply all the builder heads for this cycle."
.."\n\n"..
"A short high-pitched honk means that one or more of the builder heads don't have an item set. A common oversight, especially with large and elaborate digging machines, that might be hard to notice and annoying to fix if not noticed right away."
.."\n\n"..
"Splashing water sounds means your Digtron is digging adjacent to (or through) water-containing blocks. Digtrons are waterproof, but this might be a useful indication that you should take care when installing doors in the tunnel walls you've placed here."
.."\n\n"..
"A triple \"voop voop voop!\" alarm indicates that there is lava adjacent to your Digtron. Digtrons can't penetrate lava by default, and this alarm indicates that a non-lava-proof Digtron operator may wish to exercise caution when opening the door to clear the obstruction.")
}})
doc.add_entry("digtron", "tips", {
name = S("Tips and Tricks"),
data = { text =
S("To more easily visualize the operation of a Digtron, imagine that its cycle of operation follows these steps in order:"
.."\n\n"..
"* Dig\n* Move\n* Build\n* Allow dust to settle (ie, sand and gravel fall)"
.."\n\n"..
"If you're building a repeating pattern of blocks, your periodicity should be one larger than your largest offset. For example, if you've laid out builders to create a set of spiral stairs and the offsets are from 0 to 11, you'll want to use periodicity 12."
.."\n\n"..
"A good way to program a set of builders is to build a complete example of the structure you want them to create, then place builders against the structure and have them \"read\" all of its facings. This also lets you more easily visualize the tricks that might be needed to allow the digtron to pass through the structure as it's being built.")
}})

@ -1,146 +0,0 @@
minetest.register_entity("digtron:marker", {
initial_properties = {
visual = "cube",
visual_size = {x=1.05, y=1.05},
textures = {"digtron_marker_side.png","digtron_marker_side.png","digtron_marker.png","digtron_marker.png","digtron_marker_side.png","digtron_marker_side.png"},
collisionbox = {-0.525, -0.525, -0.525, 0.525, 0.525, 0.525},
physical = false,
},
on_activate = function(self, staticdata)
minetest.after(5.0,
function(self)
self.object:remove()
end,
self)
end,
on_rightclick=function(self, clicker)
self.object:remove()
end,
on_punch = function(self, hitter)
self.object:remove()
end,
})
minetest.register_entity("digtron:marker_vertical", {
initial_properties = {
visual = "cube",
visual_size = {x=1.05, y=1.05},
textures = {"digtron_marker.png","digtron_marker.png","digtron_marker_side.png^[transformR90","digtron_marker_side.png^[transformR90","digtron_marker_side.png^[transformR90","digtron_marker_side.png^[transformR90"},
collisionbox = {-0.525, -0.525, -0.525, 0.525, 0.525, 0.525},
physical = false,
},
on_activate = function(self, staticdata)
minetest.after(5.0,
function(self)
self.object:remove()
end,
self)
end,
on_rightclick=function(self, clicker)
self.object:remove()
end,
on_punch = function(self, hitter)
self.object:remove()
end,
})
minetest.register_entity("digtron:marker_crate_good", {
initial_properties = {
visual = "cube",
visual_size = {x=1.05, y=1.05},
textures = {"digtron_crate.png", "digtron_crate.png", "digtron_crate.png", "digtron_crate.png", "digtron_crate.png", "digtron_crate.png"},
collisionbox = {-0.525, -0.525, -0.525, 0.525, 0.525, 0.525},
physical = false,
},
on_activate = function(self, staticdata)
minetest.after(digtron.config.marker_crate_good_duration,
function(self)
self.object:remove()
end,
self)
end,
on_rightclick=function(self, clicker)
self.object:remove()
end,
on_punch = function(self, hitter)
self.object:remove()
end,
})
minetest.register_entity("digtron:marker_crate_bad", {
initial_properties = {
visual = "cube",
visual_size = {x=1.05, y=1.05},
textures = {"digtron_no_entry.png", "digtron_no_entry.png", "digtron_no_entry.png", "digtron_no_entry.png", "digtron_no_entry.png", "digtron_no_entry.png"},
collisionbox = {-0.525, -0.525, -0.525, 0.525, 0.525, 0.525},
physical = false,
},
on_activate = function(self, staticdata)
minetest.after(digtron.config.marker_crate_bad_duration,
function(self)
self.object:remove()
end,
self)
end,
on_rightclick=function(self, clicker)
self.object:remove()
end,
on_punch = function(self, hitter)
self.object:remove()
end,
})
minetest.register_entity("digtron:builder_item", {
initial_properties = {
hp_max = 1,
is_visible = true,
visual = "wielditem",
visual_size = {x=0.25, y=0.25},
collisionbox = {0,0,0,0,0,0},
physical = false,
textures = {""},
automatic_rotate = math.pi * 0.25,
},
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
props.textures = {digtron.create_builder_item}
self.object:set_properties(props)
digtron.create_builder_item = nil
else
self.object:remove()
end
end,
get_staticdata = function(self)
local props = self.object:get_properties()
if props ~= nil and props.textures ~= nil and props.textures[1] ~= nil then
return props.textures[1]
end
return ""
end,
})

118
init.lua

@ -1,116 +1,8 @@
digtron = {}
digtron.doc = {}
digtron.auto_controller_colorize = "#88000030"
digtron.pusher_controller_colorize = "#00880030"
digtron.soft_digger_colorize = "#88880030"
local modpath = minetest.get_modpath(minetest.get_current_modname())
-- A global dictionary is used here so that other substitutions can be added easily by other mods, if necessary
digtron.builder_read_item_substitutions = {
["default:torch_ceiling"] = "default:torch",
["default:torch_wall"] = "default:torch",
["default:dirt_with_grass"] = "default:dirt",
["default:dirt_with_grass_footsteps"] = "default:dirt",
["default:dirt_with_dry_grass"] = "default:dirt",
["default:dirt_with_rainforest_litter"] = "default:dirt",
["default:dirt_with_snow"] = "default:dirt",
["default:furnace_active"] = "default:furnace",
["farming:soil"] = "default:dirt",
["farming:soil_wet"] = "default:dirt",
["farming:desert_sand_soil"] = "default:desert_sand",
["farming:desert_sand_soil_wet"] = "default:desert_sand",
}
-- Sometimes we want builder heads to call an item's "on_place" method, other times we
-- don't want them to. There's no way to tell which situation is best programmatically
-- so we have to rely on whitelists to be on the safe side.
--first exact matches are tested, and the value given in this global table is returned
digtron.builder_on_place_items = {
["default:torch"] = true,
}
-- Then a string prefix is checked, returning this value. Useful for enabling on_placed on a mod-wide basis.
digtron.builder_on_place_prefixes = {
["farming:"] = true,
["farming_plus:"] = true,
["crops:"] = true,
}
-- Finally, items belonging to group "digtron_on_place" will have their on_place methods called.
local digtron_modpath = minetest.get_modpath( "digtron" )
dofile( digtron_modpath .. "/class_fakeplayer.lua")
digtron.fake_player = DigtronFakePlayer.create({x=0,y=0,z=0}, "fake_player") -- since we only need one fake player at a time and it doesn't retain useful state, create a global one and just update it as needed.
dofile( digtron_modpath .. "/config.lua" )
dofile( digtron_modpath .. "/util.lua" )
dofile( digtron_modpath .. "/doc.lua" )
dofile( digtron_modpath .. "/awards.lua" )
dofile( digtron_modpath .. "/class_pointset.lua" )
dofile( digtron_modpath .. "/class_layout.lua" )
dofile( digtron_modpath .. "/entities.lua" )
dofile( digtron_modpath .. "/nodes/node_misc.lua" ) -- contains structure and light nodes
dofile( digtron_modpath .. "/nodes/node_storage.lua" ) -- contains inventory and fuel storage nodes
dofile( digtron_modpath .. "/nodes/node_diggers.lua" ) -- contains all diggers
dofile( digtron_modpath .. "/nodes/node_builders.lua" ) -- contains all builders (there's just one currently)
dofile( digtron_modpath .. "/nodes/node_controllers.lua" ) -- controllers
dofile( digtron_modpath .. "/nodes/node_axle.lua" ) -- Rotation controller
dofile( digtron_modpath .. "/nodes/node_crate.lua" ) -- Digtron portability support
dofile( digtron_modpath .. "/nodes/node_item_ejector.lua" ) -- ejects non-building, non-fuel items from inventories
dofile( digtron_modpath .. "/nodes/node_duplicator.lua" ) -- constructs copies of existing Digtrons
--Technic
dofile( digtron_modpath .. "/nodes/node_battery_holder.lua" ) -- holds rechargeable batteries from the technic mod
dofile( digtron_modpath .. "/nodes/node_power_connector.lua")
dofile( digtron_modpath .. "/nodes/recipes.lua" )
dofile( digtron_modpath .. "/upgrades.lua" ) -- various LBMs for upgrading older versions of Digtron.
-- digtron group numbers:
-- 1 - generic digtron node, nothing special is done with these. They're just dragged along.
-- 2 - inventory-holding digtron, has a "main" inventory that the digtron can add to and take from.
-- 3 - digger head, has an "execute_dig" method in its definition
-- 4 - builder head, has a "test_build" and "execute_build" method in its definition
-- 5 - fuel-holding digtron, has a "fuel" invetory that the control node can draw fuel items from. Separate from general inventory, nothing gets put here automatically.
-- 6 - holds both fuel and main inventories
-- 7 - holds batteries (RE Battery from technic) to provide clean renewable power
-- 8 - connects to adjacent HV technic cable
-- 9 - connects to pipeworks, auto-ejects mined items
-- This code was added for use with FaceDeer's fork of the [catacomb] mod. Paramat's version doesn't support customized protected nodes, which causes
-- it to "eat" Digtrons sometimes.
if minetest.get_modpath("catacomb") and catacomb ~= nil and catacomb.chamber_protected_nodes ~= nil and catacomb.passage_protected_nodes ~= nil then
local digtron_nodes = {
minetest.get_content_id("digtron:inventory"),
minetest.get_content_id("digtron:fuelstore"),
minetest.get_content_id("digtron:battery_holder"),
minetest.get_content_id("digtron:combined_storage"),
minetest.get_content_id("digtron:axle"),
minetest.get_content_id("digtron:builder"),
minetest.get_content_id("digtron:controller"),
minetest.get_content_id("digtron:auto_controller"),
minetest.get_content_id("digtron:pusher"),
minetest.get_content_id("digtron:loaded_crate"),
minetest.get_content_id("digtron:digger"),
minetest.get_content_id("digtron:intermittent_digger"),
minetest.get_content_id("digtron:soft_digger"),
minetest.get_content_id("digtron:intermittent_soft_digger"),
minetest.get_content_id("digtron:dual_digger"),
minetest.get_content_id("digtron:dual_soft_digger"),
minetest.get_content_id("digtron:structure"),
minetest.get_content_id("digtron:light"),
minetest.get_content_id("digtron:panel"),
minetest.get_content_id("digtron:edge_panel"),
minetest.get_content_id("digtron:corner_panel"),
minetest.get_content_id("digtron:battery_holder"),
minetest.get_content_id("digtron:inventory_ejector"),
minetest.get_content_id("digtron:power_connector"),
}
for _, node_id in pairs(digtron_nodes) do
catacomb.chamber_protected_nodes[node_id] = true
catacomb.passage_protected_nodes[node_id] = true
end
end
dofile(modpath.."/controller.lua")
dofile(modpath.."/nodes/node_misc.lua")
dofile(modpath.."/nodes/node_storage.lua")

File diff suppressed because it is too large Load Diff

@ -1,6 +0,0 @@
@echo off
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
cd ..
set LIST=
for /r %%X in (*.lua) do set LIST=!LIST! %%X
..\intllib\tools\xgettext.bat %LIST%

@ -1,7 +0,0 @@
name = digtron
title = Digtron
author = FaceDeer
description = Adds components for building modular tunnel boring machines
license = MIT, LGPL 2.1 or later
forum = https://forum.minetest.net/viewtopic.php?t=16295
version = 0.8

@ -1,69 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
minetest.register_node("digtron:axle", {
description = S("Digtron Rotation Axle"),
_doc_items_longdesc = digtron.doc.axle_longdesc,
_doc_items_usagehelp = digtron.doc.axle_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:axle",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^digtron_axel_top.png",
"digtron_plate.png^digtron_axel_top.png",
"digtron_plate.png^digtron_axel_side.png",
"digtron_plate.png^digtron_axel_side.png",
"digtron_plate.png^digtron_axel_side.png",
"digtron_plate.png^digtron_axel_side.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, 0.3125, -0.3125, 0.5, 0.5, 0.3125}, -- Uppercap
{-0.5, -0.5, -0.3125, 0.5, -0.3125, 0.3125}, -- Lowercap
{-0.3125, 0.3125, -0.5, 0.3125, 0.5, -0.3125}, -- Uppercap_edge2
{-0.3125, 0.3125, 0.3125, 0.3125, 0.5, 0.5}, -- Uppercap_edge1
{-0.3125, -0.5, -0.5, 0.3125, -0.3125, -0.3125}, -- Lowercap_edge1
{-0.3125, -0.5, 0.3125, 0.3125, -0.3125, 0.5}, -- Lowercap_edge2
{-0.25, -0.3125, -0.25, 0.25, 0.3125, 0.25}, -- Axle
}
},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
if meta:get_string("waiting") == "true" then
-- Been too soon since last time the digtron rotated.
return
end
local image = DigtronLayout.create(pos, clicker)
if image:rotate_layout_image(node.param2) == false then
-- This should be impossible, but if self-validation fails abort.
return
end
if image:can_write_layout_image() then
if image:write_layout_image(clicker) then
minetest.sound_play("whirr", {gain=1.0, pos=pos})
meta = minetest.get_meta(pos)
meta:set_string("waiting", "true")
meta:set_string("infotext", nil)
minetest.get_node_timer(pos):start(digtron.config.cycle_time*2)
else
meta:set_string("infotext", "unrecoverable write_layout_image error")
end
else
minetest.sound_play("buzzer", {gain=1.0, pos=pos})
meta:set_string("infotext", S("Digtron is obstructed."))
end
end,
on_timer = function(pos, elapsed)
minetest.get_meta(pos):set_string("waiting", nil)
end,
})

@ -1,125 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
-- Battery storage. Controller node draws electrical power from here.
-- Note that batttery boxes are digtron group 7.
local battery_holder_formspec_string = "size[8,9.3]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[0,0;" .. S("Batteries") .. "]" ..
"list[current_name;batteries;0,0.6;8,4;]" ..
"list[current_player;main;0,5.15;8,1;]" ..
"list[current_player;main;0,6.38;8,3;8]" ..
"listring[current_name;batteries]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,5.15)
local battery_holder_formspec = function(pos, meta)
return battery_holder_formspec_string
end
local holder_groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 7, tubedevice = 1, tubedevice_receiver = 1}
if not minetest.get_modpath("technic") then
-- if technic isn't installed there's no point in offering battery holders.
-- leave them registered, though, in case technic is being removed from an existing server.
holder_groups.not_in_creative_inventory = 1
end
minetest.register_node("digtron:battery_holder", {
description = S("Digtron Battery Holder"),
_doc_items_longdesc = digtron.doc.battery_holder_longdesc,
_doc_items_usagehelp = digtron.doc.battery_holder_usagehelp,
_digtron_formspec = battery_holder_formspec,
groups = holder_groups,
drop = "digtron:battery_holder",
sounds = digtron.metal_sounds,
paramtype2= "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
},
paramtype = "light",
is_ground_content = false,
tiles = {
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png",
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png",
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png^digtron_storage.png",
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png^digtron_storage.png",
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png^digtron_storage.png",
"digtron_plate.png^digtron_crossbrace.png^digtron_battery.png^digtron_storage.png",
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", battery_holder_formspec(pos, meta))
local inv = meta:get_inventory()
inv:set_size("batteries", 8*4)
end,
-- Allow all items with energy storage to be placed in the inventory
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "batteries" then
local node_name = stack:get_name()
-- Allow all items with energy storage from technic mod
if technic.power_tools[node_name] ~= nil then
local meta = stack:get_metadata()
local md = minetest.deserialize(meta)
-- And specifically if they hold any charge
-- Disregard empty batteries, the player should know better
if md and md.charge > 0 then
return stack:get_count()
else
return 0
end
else
return 0
end
end
return 0
end,
can_dig = function(pos,player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("batteries")
end,
-- Pipeworks compatibility
-- Because who wouldn't send batteries through pipes if he could?
-----------------------------------------------------------------
tube = (function() if minetest.get_modpath("pipeworks") then return {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("batteries", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = stack:get_metadata()
local md = minetest.deserialize(meta)
-- And specifically if they hold any charge
-- Disregard empty batteries, the player should know better
if md and md.charge > 0 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:room_for_item("batteries", stack)
end
return false
end,
input_inventory = "batteries",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
} end end)(),
after_place_node = (function() if minetest.get_modpath("pipeworks") then return pipeworks.after_place end end)(),
after_dig_node = (function() if minetest.get_modpath("pipeworks")then return pipeworks.after_dig end end)()
})

@ -1,357 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
-- Note: builders go in group 4 and have both test_build and execute_build methods.
local node_inventory_table = {type="node"} -- a reusable parameter for get_inventory calls, set the pos parameter before using.
local displace_due_to_help_button = 1.0
if minetest.get_modpath("doc") then
displace_due_to_help_button = 0.0
end
local builder_formspec_string =
"size[8,5.2]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"list[current_name;main;".. tostring(displace_due_to_help_button/2) ..",0;1,1;]" ..
"label[" .. tostring(displace_due_to_help_button/2).. ",0.8;" .. S("Block to build") .. "]" ..
"field[" .. tostring(displace_due_to_help_button + 1.3) ..",0.8;1,0.1;extrusion;" .. S("Extrusion") .. ";${extrusion}]" ..
"tooltip[extrusion;" .. S("Builder will extrude this many blocks in the direction it is facing.\nCan be set from 1 to @1.\nNote that Digtron won't build into unloaded map regions.", digtron.config.maximum_extrusion) .. "]" ..
"field[" .. tostring(displace_due_to_help_button + 2.3) ..",0.8;1,0.1;period;" .. S("Periodicity") .. ";${period}]" ..
"tooltip[period;" .. S("Builder will build once every n steps.\nThese steps are globally aligned, so all builders with the\nsame period and offset will build on the same location.") .. "]" ..
"field[" .. tostring(displace_due_to_help_button + 3.3) ..",0.8;1,0.1;offset;" .. S("Offset") .. ";${offset}]" ..
"tooltip[offset;" .. S("Offsets the start of periodicity counting by this amount.\nFor example, a builder with period 2 and offset 0 builds\nevery even-numbered block and one with period 2 and\noffset 1 builds every odd-numbered block.") .. "]" ..
"button_exit[" .. tostring(displace_due_to_help_button + 4.0) ..",0.5;1,0.1;set;" .. S("Save &\nShow") .. "]" ..
"tooltip[set;" .. S("Saves settings") .. "]" ..
"field[" .. tostring(displace_due_to_help_button + 5.3) .. ",0.8;1,0.1;build_facing;" .. S("Facing") .. ";${build_facing}]" ..
"tooltip[build_facing;" .. S("Value from 0-23. Not all block types make use of this.\nUse the 'Read & Save' button to copy the facing of the block\ncurrently in the builder output location.") .. "]" ..
"button_exit[" .. tostring(displace_due_to_help_button + 6.0) ..",0.5;1,0.1;read;" .. S("Read &\nSave") .. "]" ..
"tooltip[read;" .. S("Reads the facing of the block currently in the build location,\nthen saves all settings.") .. "]" ..
"list[current_player;main;0,1.3;8,1;]" ..
default.get_hotbar_bg(0,1.3) ..
"list[current_player;main;0,2.5;8,3;8]" ..
"listring[current_player;main]" ..
"listring[current_name;main]"
if minetest.get_modpath("doc") then
builder_formspec_string = builder_formspec_string ..
"button_exit[7.0,0.5;1,0.1;help;" .. S("Help") .. "]" ..
"tooltip[help;" .. S("Show documentation about this block") .. "]"
end
local builder_formspec = function(pos, meta)
local nodemeta = "nodemeta:"..pos.x .. "," .. pos.y .. "," ..pos.z
return builder_formspec_string
:gsub("${extrusion}", meta:get_int("extrusion"), 1)
:gsub("${period}", meta:get_int("period"), 1)
:gsub("${offset}", meta:get_int("offset"), 1)
:gsub("${build_facing}", meta:get_int("build_facing"), 1)
:gsub("current_name", "nodemeta:"..pos.x .. "," .. pos.y .. "," ..pos.z, 2)
end
local builder_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local item_def = itemstack:get_definition()
if item_def.type == "node" and minetest.get_item_group(itemstack:get_name(), "digtron") > 0 then
local returnstack, success = minetest.item_place_node(itemstack, clicker, pointed_thing)
if success and item_def.sounds and item_def.sounds.place and item_def.sounds.place.name then
minetest.sound_play(item_def.sounds.place, {pos = pos})
end
return returnstack, success
end
local meta = minetest.get_meta(pos)
minetest.show_formspec(clicker:get_player_name(),
"digtron:builder"..minetest.pos_to_string(pos),
builder_formspec(pos, meta))
end
minetest.register_on_player_receive_fields(function(sender, formname, fields)
if formname:sub(1, 15) ~= "digtron:builder" then
return
end
local pos = minetest.string_to_pos(formname:sub(16, -1))
local meta = minetest.get_meta(pos)
local period = tonumber(fields.period)
local offset = tonumber(fields.offset)
local build_facing = tonumber(fields.build_facing)
local extrusion = tonumber(fields.extrusion)
if period and period > 0 then
meta:set_int("period", math.floor(tonumber(fields.period)))
else
period = meta:get_int("period")
end
if offset then
meta:set_int("offset", math.floor(tonumber(fields.offset)))
else
offset = meta:get_int("offset")
end
if build_facing and build_facing >= 0 and build_facing < 24 then
local inv = meta:get_inventory()
local target_item = inv:get_stack("main",1)
if target_item:get_definition().paramtype2 == "wallmounted" then
if build_facing < 6 then
meta:set_int("build_facing", math.floor(build_facing))
-- wallmounted facings only run from 0-5
end
else
meta:set_int("build_facing", math.floor(build_facing))
end
end
if extrusion and extrusion > 0 and extrusion <= digtron.config.maximum_extrusion then
meta:set_int("extrusion", math.floor(tonumber(fields.extrusion)))
else
extrusion = meta:get_int("extrusion")
end
if fields.set then
digtron.show_offset_markers(pos, offset, period)
elseif fields.read then
local facing = minetest.get_node(pos).param2
local buildpos = digtron.find_new_pos(pos, facing)
local target_node = minetest.get_node(buildpos)
if target_node.name ~= "air" and minetest.get_item_group(target_node.name, "digtron") == 0 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local target_name = digtron.builder_read_item_substitutions[target_node.name] or target_node.name
inv:set_stack("main", 1, target_name)
meta:set_int("build_facing", target_node.param2)
end
end
if fields.help and minetest.get_modpath("doc") then --check for mod in case someone disabled it after this digger was built
minetest.after(0.5, doc.show_entry, sender:get_player_name(), "nodes", "digtron:builder", true)
end
digtron.update_builder_item(pos)
end)
-- Builds objects in the targeted node. This is a complicated beastie.
minetest.register_node("digtron:builder", {
description = S("Digtron Builder Module"),
_doc_items_longdesc = digtron.doc.builder_longdesc,
_doc_items_usagehelp = digtron.doc.builder_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 4},
drop = "digtron:builder",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
tiles = {
"digtron_plate.png^[transformR90",
"digtron_plate.png^[transformR270",
"digtron_plate.png",
"digtron_plate.png^[transformR180",
"digtron_plate.png^digtron_builder.png",
"digtron_plate.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.25, 0.3125, 0.3125, 0.25, 0.5, 0.5}, -- FrontFrame_top
{-0.25, -0.5, 0.3125, 0.25, -0.3125, 0.5}, -- FrontFrame_bottom
{0.3125, -0.25, 0.3125, 0.5, 0.25, 0.5}, -- FrontFrame_right
{-0.5, -0.25, 0.3125, -0.3125, 0.25, 0.5}, -- FrontFrame_left
{-0.5, 0.25, -0.5, -0.25, 0.5, 0.5}, -- edge_topright
{-0.5, -0.5, -0.5, -0.25, -0.25, 0.5}, -- edge_bottomright
{0.25, 0.25, -0.5, 0.5, 0.5, 0.5}, -- edge_topleft
{0.25, -0.5, -0.5, 0.5, -0.25, 0.5}, -- edge_bottomleft
{-0.25, 0.4375, -0.5, 0.25, 0.5, -0.4375}, -- backframe_top
{-0.25, -0.5, -0.5, 0.25, -0.4375, -0.4375}, -- backframe_bottom
{-0.5, -0.25, -0.5, -0.4375, 0.25, -0.4375}, -- backframe_left
{0.4375, -0.25, -0.5, 0.5, 0.25, -0.4375}, -- Backframe_right
{-0.0625, -0.3125, 0.3125, 0.0625, 0.3125, 0.375}, -- frontcross_vertical
{-0.3125, -0.0625, 0.3125, 0.3125, 0.0625, 0.375}, -- frontcross_horizontal
}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("period", 1)
meta:set_int("offset", 0)
meta:set_int("build_facing", 0)
meta:set_int("extrusion", 1)
local inv = meta:get_inventory()
inv:set_size("main", 1)
end,
on_rightclick = builder_on_rightclick,
on_destruct = function(pos)
digtron.remove_builder_item(pos)
end,
after_place_node = function(pos)
digtron.update_builder_item(pos)
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local stack_name = stack:get_name()
if minetest.get_item_group(stack_name, "digtron") ~= 0 then
return 0 -- don't allow builders to be set to build Digtron nodes, they'll just clog the output.
end
local stack_def = minetest.registered_nodes[stack_name]
if not stack_def and not digtron.whitelisted_on_place(stack_name) then
return 0 -- don't allow craft items unless their on_place is whitelisted.
end
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
inv:set_stack(listname, index, stack:take_item(1))
-- If we're adding a wallmounted item and the build facing is greater than 5, reset it to 0
local meta = minetest.get_meta(pos)
if stack_def ~= nil and stack_def.paramtype2 == "wallmounted" and tonumber(meta:get_int("build_facing")) > 5 then
meta:set_int("build_facing", 0)
end
return 0
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
inv:set_stack(listname, index, ItemStack(""))
return 0
end,
-- "builder at pos, imagine that you're in test_pos. If you're willing and able to build from there, take the item you need from inventory.
-- return the item you took and the inventory location you took it from so it can be put back after all the other builders have been tested.
-- If you couldn't get the item from inventory, return an error code so we can abort the cycle.
-- If you're not supposed to build at all, or the location is obstructed, return 0 to let us know you're okay and we shouldn't abort."
--return code and accompanying value:
-- 0, {} -- not supposed to build, no error
-- 1, {{itemstack, source inventory pos}, ...} -- can build, took items from inventory
-- 2, {{itemstack, source inventory pos}, ...}, itemstack -- was supposed to build, but couldn't get the item from inventory
-- 3, {} -- builder configuration error
test_build = function(pos, test_pos, inventory_positions, protected_nodes, nodes_dug, controlling_coordinate, controller_pos)
local meta = minetest.get_meta(pos)
local facing = minetest.get_node(pos).param2
local buildpos = digtron.find_new_pos(test_pos, facing)
if (buildpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") ~= 0 then
--It's not the builder's turn to build right now.
return 0, {}
end
local extrusion_count = 0
local extrusion_target = meta:get_int("extrusion")
if extrusion_target == nil or extrusion_target < 1 or extrusion_target > 100 then
extrusion_target = 1 -- failsafe
end
local return_items = {}
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
local item_stack = inv:get_stack("main", 1)
if item_stack:is_empty() then
return 3, {} -- error code for "this builder's item slot is unset"
end
while extrusion_count < extrusion_target do
if not digtron.can_move_to(buildpos, protected_nodes, nodes_dug) then
--using "can_move_to" instead of "can_build_to" test case in case the builder is pointed "backward", and will thus
--be building into the space that it's currently in and will be vacating after moving, or in case the builder is aimed
--sideways and a fellow digtron node was ahead of it (will also be moving out of the way).
--If the player has built his digtron stupid (eg has another digtron node in the place the builder wants to build) this
--assumption is wrong, but I can't hold the player's hand through *every* possible bad design decision. Worst case,
--the digtron will think its inventory can't handle the next build step and abort the build when it actually could have
--managed one more cycle. That's not a bad outcome for a digtron array that was built stupidly to begin with.
return 1, return_items
end
local source_location = digtron.take_from_inventory(item_stack:get_name(), inventory_positions)
if source_location ~= nil then
table.insert(return_items, {item=item_stack, location=source_location})
else
return 2, return_items, item_stack -- error code for "needed an item but couldn't get it from inventory"
end
extrusion_count = extrusion_count + 1
buildpos = digtron.find_new_pos(buildpos, facing)
end
return 1, return_items
end,
execute_build = function(pos, player, inventory_positions, protected_nodes, nodes_dug, controlling_coordinate, controller_pos)
local meta = minetest.get_meta(pos)
local build_facing = tonumber(meta:get_int("build_facing"))
local facing = minetest.get_node(pos).param2
local buildpos = digtron.find_new_pos(pos, facing)
if (buildpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") ~= 0 then
return 0
end
local extrusion_count = 0
local extrusion_target = meta:get_int("extrusion")
if extrusion_target == nil or extrusion_target < 1 or extrusion_target > 100 then
extrusion_target = 1 -- failsafe
end
local built_count = 0
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
local item_stack = inv:get_stack("main", 1)
if item_stack:is_empty() then
return built_count
end
while extrusion_count < extrusion_target do
if not digtron.can_build_to(buildpos, protected_nodes, nodes_dug) then
return built_count
end
local oldnode = minetest.get_node(buildpos)
if not digtron.config.uses_resources then
local returned_stack, success = digtron.item_place_node(item_stack, player, buildpos, build_facing)
if success == true then
minetest.log("action", string.format("%s uses Digtron to build %s at (%d, %d, %d), displacing %s", player:get_player_name(), item_stack:get_name(), buildpos.x, buildpos.y, buildpos.z, oldnode.name))
nodes_dug:set(buildpos.x, buildpos.y, buildpos.z, false)
built_count = built_count + 1
else
return built_count
end
end
local sourcepos = digtron.take_from_inventory(item_stack:get_name(), inventory_positions)
if sourcepos == nil then
-- item not in inventory! Need to sound the angry buzzer to let the player know, so return a negative number.
return (built_count + 1) * -1
end
local returned_stack, success = digtron.item_place_node(ItemStack(item_stack), player, buildpos, build_facing)
if success == true then
minetest.log("action", string.format("%s uses Digtron to build %s at (%d, %d, %d), displacing %s", player:get_player_name(), item_stack:get_name(), buildpos.x, buildpos.y, buildpos.z, oldnode.name))
--flag this node as *not* to be dug.
nodes_dug:set(buildpos.x, buildpos.y, buildpos.z, false)
digtron.award_item_built(item_stack:get_name(), player)
built_count = built_count + 1
else
--failed to build, target node probably obstructed. Put the item back in inventory.
--Should probably never reach this since we're guarding against can_build_to, above, but this makes things safe if we somehow do.
digtron.place_in_specific_inventory(item_stack, sourcepos, inventory_positions, controller_pos)
return built_count
end
extrusion_count = extrusion_count + 1
buildpos = digtron.find_new_pos(buildpos, facing)
end
return built_count
end,
})

@ -1,350 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local controller_nodebox ={
{-0.3125, -0.3125, -0.3125, 0.3125, 0.3125, 0.3125}, -- Core
{-0.1875, 0.3125, -0.1875, 0.1875, 0.5, 0.1875}, -- +y_connector
{-0.1875, -0.5, -0.1875, 0.1875, -0.3125, 0.1875}, -- -y_Connector
{0.3125, -0.1875, -0.1875, 0.5, 0.1875, 0.1875}, -- +x_connector
{-0.5, -0.1875, -0.1875, -0.3125, 0.1875, 0.1875}, -- -x_connector
{-0.1875, -0.1875, 0.3125, 0.1875, 0.1875, 0.5}, -- +z_connector
{-0.5, 0.125, -0.5, -0.125, 0.5, -0.3125}, -- back_connector_3
{0.125, 0.125, -0.5, 0.5, 0.5, -0.3125}, -- back_connector_1
{0.125, -0.5, -0.5, 0.5, -0.125, -0.3125}, -- back_connector_2
{-0.5, -0.5, -0.5, -0.125, -0.125, -0.3125}, -- back_connector_4
}
local node_inventory_table = {type="node"} -- a reusable parameter for get_inventory calls, set the pos parameter before using.
-- 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:controller", {
description = S("Digtron Control Module"),
_doc_items_longdesc = digtron.doc.controller_longdesc,
_doc_items_usagehelp = digtron.doc.controller_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
drop = "digtron:controller",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90",
"digtron_plate.png^[transformR270",
"digtron_plate.png",
"digtron_plate.png^[transformR180",
"digtron_plate.png",
"digtron_plate.png^digtron_control.png",
},
drawtype = "nodebox",
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", S("Heat remaining in controller furnace: @1", 0))
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
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
local newpos, status, return_code = digtron.execute_dig_cycle(pos, clicker)
meta = minetest.get_meta(newpos)
if status ~= nil then
meta:set_string("infotext", status)
end
-- Start the delay before digtron can run again.
minetest.get_meta(newpos):set_string("waiting", "true")
minetest.get_node_timer(newpos):start(digtron.config.cycle_time)
end,
on_timer = function(pos, elapsed)
minetest.get_meta(pos):set_string("waiting", nil)
end,
})
-- Auto-controller
---------------------------------------------------------------------------------------------------------------
local auto_formspec = "size[8,6.2]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"container[2.0,0]" ..
"field[0.0,0.8;1,0.1;cycles;" .. S("Cycles").. ";${cycles}]" ..
"tooltip[cycles;" .. S("When triggered, this controller will try to run for the given number of cycles.\nThe cycle count will decrement as it runs, so if it gets halted by a problem\nyou can fix the problem and restart.").. "]" ..
"button_exit[0.7,0.5;1,0.1;set;" .. S("Set").. "]" ..
"tooltip[set;" .. S("Saves the cycle setting without starting the controller running").. "]" ..
"button_exit[1.7,0.5;1,0.1;execute;" .. S("Set &\nExecute").. "]" ..
"tooltip[execute;" .. S("Begins executing the given number of cycles").. "]" ..
"field[0.0,2.0;1,0.1;slope;" .. S("Slope").. ";${slope}]" ..
"tooltip[slope;" .. S("For diagonal digging. After moving forward this number of nodes the auto controller\nwill add an additional cycle moving the digtron laterally in the\ndirection of the arrows on the side of this controller.\nSet to 0 for no lateral digging.").. "]" ..
"field[1.0,2.0;1,0.1;offset;" .. S("Offset").. ";${offset}]" ..
"tooltip[offset;" .. S("Sets the offset of the lateral motion defined in the Slope field.\nNote: this offset is relative to the controller's location.\nThe controller will move laterally when it reaches the indicated point.").. "]" ..
"field[2.0,2.0;1,0.1;period;" .. S("Delay").. ";${period}]" ..
"tooltip[period;" .. S("Number of seconds to wait between each cycle").. "]" ..
"list[current_name;stop;3.0,0.7;1,1;]" ..
"label[3.0,1.5;" .. S("Stop block").. "]" ..
"container_end[]" ..
"list[current_player;main;0,2.3;8,1;]" ..
default.get_hotbar_bg(0,2.3) ..
"list[current_player;main;0,3.5;8,3;8]" ..
"listring[current_player;main]" ..
"listring[current_name;stop]"
if minetest.get_modpath("doc") then
auto_formspec = auto_formspec ..
"button_exit[7.0,0.5;1,0.1;help;" .. S("Help") .. "]" ..
"tooltip[help;" .. S("Show documentation about this block").. "]"
end
local function auto_cycle(pos)
local node = minetest.get_node(pos)
local controlling_coordinate = digtron.get_controlling_coordinate(pos, node.param2)
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 cycle = meta:get_int("cycles")
local slope = meta:get_int("slope")
if meta:get_string("lateral_done") ~= "true" and slope ~= 0 and (pos[controlling_coordinate] + meta:get_int("offset")) % slope == 0 then
--Do a downward dig cycle. Don't update the "cycles" count, these don't count towards that.
local newpos, status, return_code = digtron.execute_downward_dig_cycle(pos, player)
if vector.equals(pos, newpos) then
status = status .. "\n" .. S("Cycles remaining: @1", cycle) .. "\n" .. S("Halted!")
meta:set_string("infotext", status)
if return_code == 1 then --return code 1 happens when there's unloaded nodes adjacent, just keep trying.
if digtron.config.emerge_unloaded_mapblocks then
minetest.emerge_area(vector.add(pos, -80), vector.add(pos, 80))
end
minetest.after(meta:get_int("period"), auto_cycle, newpos)
else
meta:set_string("formspec", auto_formspec)
end
else
meta = minetest.get_meta(newpos)
minetest.after(meta:get_int("period"), auto_cycle, newpos)
meta:set_string("infotext", status)
meta:set_string("lateral_done", "true")
end
return
end
local newpos, status, return_code = digtron.execute_dig_cycle(pos, player)
if vector.equals(pos, newpos) then
status = status .. "\n" .. S("Cycles remaining: @1", cycle) .. "\n" .. S("Halted!")
meta:set_string("infotext", status)
if return_code == 1 then --return code 1 happens when there's unloaded nodes adjacent, call emerge and keep trying.
if digtron.config.emerge_unloaded_mapblocks then
minetest.emerge_area(vector.add(pos, -80), vector.add(pos, 80))
end
minetest.after(meta:get_int("period"), auto_cycle, newpos)
else
meta:set_string("formspec", auto_formspec)
end
return
end
meta = minetest.get_meta(newpos)
cycle = meta:get_int("cycles") - 1
meta:set_int("cycles", cycle)
status = status .. "\n" .. S("Cycles remaining: @1", cycle)
meta:set_string("infotext", status)
meta:set_string("lateral_done", nil)
if cycle > 0 then
minetest.after(meta:get_int("period"), auto_cycle, newpos)
else
meta:set_string("formspec", auto_formspec)
end
end
minetest.register_node("digtron:auto_controller", {
description = S("Digtron Automatic Control Module"),
_doc_items_longdesc = digtron.doc.auto_controller_longdesc,
_doc_items_usagehelp = digtron.doc.auto_controller_usagehelp,
--Don't set a _digtron_formspec for this node_def.
--Auto-controller has special formspec handling, while active it has no formspec and right-clicking interrupts it.
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
drop = "digtron:auto_controller",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90^[colorize:" .. digtron.auto_controller_colorize,
"digtron_plate.png^[transformR270^[colorize:" .. digtron.auto_controller_colorize,
"digtron_plate.png^digtron_axel_side.png^[transformR270^[colorize:" .. digtron.auto_controller_colorize,
"digtron_plate.png^digtron_axel_side.png^[transformR270^[colorize:" .. digtron.auto_controller_colorize,
"digtron_plate.png^[colorize:" .. digtron.auto_controller_colorize,
"digtron_plate.png^digtron_control.png^[colorize:" .. digtron.auto_controller_colorize,
},
drawtype = "nodebox",
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", S("Heat remaining in controller furnace: @1", 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", digtron.config.cycle_time)
meta:set_int("offset", 0)
meta:set_int("cycles", 0)
meta:set_int("slope", 0)
local inv = meta:get_inventory()
inv:set_size("stop", 1)
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if minetest.get_item_group(stack:get_name(), "digtron") ~= 0 then
return 0 -- pointless setting a Digtron node as a stop block
end
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
inv:set_stack(listname, index, stack:take_item(1))
return 0
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
inv:set_stack(listname, index, ItemStack(""))
return 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)
local slope = tonumber(fields.slope)
local cycles = tonumber(fields.cycles)
if period and period > 0 then
meta:set_int("period", math.max(digtron.config.cycle_time, math.floor(period)))
end
if offset then
meta:set_int("offset", offset)
end
if slope and slope >= 0 then
meta:set_int("slope", slope)
end
if cycles and cycles >= 0 then
meta:set_int("cycles", math.floor(cycles))
if sender:is_player() and cycles > 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)
auto_cycle(pos)
end
end
end
if fields.set and slope and slope > 0 then
local node = minetest.get_node(pos)
local controlling_coordinate = digtron.get_controlling_coordinate(pos, node.param2)
local newpos = pos
local markerpos = {x=newpos.x, y=newpos.y, z=newpos.z}
local x_pos = math.floor((newpos[controlling_coordinate]+offset)/slope)*slope - offset
markerpos[controlling_coordinate] = x_pos
minetest.add_entity(markerpos, "digtron:marker_vertical")
if x_pos >= newpos[controlling_coordinate] then
markerpos[controlling_coordinate] = x_pos - slope
minetest.add_entity(markerpos, "digtron:marker_vertical")
end
if x_pos <= newpos[controlling_coordinate] then
markerpos[controlling_coordinate] = x_pos + slope
minetest.add_entity(markerpos, "digtron:marker_vertical")
end
end
if fields.help and minetest.get_modpath("doc") then --check for mod in case someone disabled it after this digger was built
minetest.after(0.5, doc.show_entry, sender:get_player_name(), "nodes", "digtron:auto_controller", true)
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") .. "\n" .. S("Interrupted!"))
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", {
description = S("Digtron Pusher Module"),
_doc_items_longdesc = digtron.doc.pusher_longdesc,
_doc_items_usagehelp = digtron.doc.pusher_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:pusher",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90^[colorize:" .. digtron.pusher_controller_colorize,
"digtron_plate.png^[transformR270^[colorize:" .. digtron.pusher_controller_colorize,
"digtron_plate.png^[colorize:" .. digtron.pusher_controller_colorize,
"digtron_plate.png^[transformR180^[colorize:" .. digtron.pusher_controller_colorize,
"digtron_plate.png^[colorize:" .. digtron.pusher_controller_colorize,
"digtron_plate.png^digtron_control.png^[colorize:" .. digtron.pusher_controller_colorize,
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = controller_nodebox,
},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
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
local newpos, status_text, return_code = digtron.execute_move_cycle(pos, clicker)
meta = minetest.get_meta(newpos)
meta:set_string("infotext", status_text)
-- Start the delay before digtron can run again.
minetest.get_meta(newpos):set_string("waiting", "true")
minetest.get_node_timer(newpos):start(digtron.config.cycle_time)
end,
on_timer = function(pos, elapsed)
minetest.get_meta(pos):set_string("waiting", nil)
end,
})

@ -1,385 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local modpath_awards = minetest.get_modpath("awards")
local player_permitted = function(pos, player)
if player then
if minetest.check_player_privs(player, "protection_bypass") then
return true
end
else
return false
end
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if not owner or owner == "" or owner == player:get_player_name() then
return true
end
end
local store_digtron = function(pos, clicker, loaded_node_name, protected)
local layout = DigtronLayout.create(pos, clicker)
local protection_prefix = ""
local protection_suffix = ""
if protected then
protection_prefix = S("Digtron Crate") .. "\n" .. S("Owned by @1", clicker:get_player_name() or "")
protection_suffix = S("Owned by @1", clicker:get_player_name() or "")
end
if layout.contains_protected_node then
local meta = minetest.get_meta(pos)
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
meta:set_string("infotext", protection_prefix .. "\n" .. S("Digtron can't be packaged, it contains protected blocks"))
-- no stealing other peoples' digtrons
return
end
if #layout.all == 1 then
local meta = minetest.get_meta(pos)
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
meta:set_string("infotext", protection_prefix .. "\n" .. S("No Digtron components adjacent to package"))
return
end
digtron.award_crate(layout, clicker:get_player_name())
local layout_string = layout:serialize()
-- destroy everything. Note that this includes the empty crate, which will be bundled up with the layout.
for _, node_image in pairs(layout.all) do
local old_pos = node_image.pos
local old_node = node_image.node
minetest.remove_node(old_pos)
if modpath_awards then
-- We're about to tell the awards mod that we're digging a node, but we
-- don't want it to count toward any actual awards. Pre-decrement.
local data = awards.player(clicker:get_player_name())
awards.increment_item_counter(data, "dig", old_node.name, -1)
end
for _, callback in ipairs(minetest.registered_on_dignodes) do
-- Copy pos and node because callback can modify them
local pos_copy = {x=old_pos.x, y=old_pos.y, z=old_pos.z}
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
callback(pos_copy, oldnode_copy, clicker)
end
end
-- Create the loaded crate node
minetest.set_node(pos, {name=loaded_node_name})
minetest.sound_play("machine1", {gain=1.0, pos=pos})
local meta = minetest.get_meta(pos)
meta:set_string("crated_layout", layout_string)
if protected then
-- only set owner if protected
meta:set_string("owner", clicker:get_player_name() or "")
end
local titlestring = S("Crated @1-block Digtron", tostring(#layout.all-1))
meta:set_string("title", titlestring )
meta:set_string("infotext", titlestring .. "\n" .. protection_suffix)
end
minetest.register_node("digtron:empty_crate", {
description = S("Digtron Crate (Empty)"),
_doc_items_longdesc = digtron.doc.empty_crate_longdesc,
_doc_items_usagehelp = digtron.doc.empty_crate_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3},
sounds = default.node_sound_wood_defaults(),
tiles = {"digtron_crate.png"},
is_ground_content = false,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
},
paramtype = "light",
can_dig = function(pos, player)
return player and not minetest.is_protected(pos, player:get_player_name())
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
store_digtron(pos, clicker, "digtron:loaded_crate")
end
})
minetest.register_node("digtron:empty_locked_crate", {
description = S("Digtron Locked Crate (Empty)"),
_doc_items_longdesc = digtron.doc.empty_locked_crate_longdesc,
_doc_items_usagehelp = digtron.doc.empty_locked_crate_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3},
sounds = default.node_sound_wood_defaults(),
tiles = {"digtron_crate.png","digtron_crate.png","digtron_crate.png^digtron_lock.png","digtron_crate.png^digtron_lock.png","digtron_crate.png^digtron_lock.png","digtron_crate.png^digtron_lock.png"},
is_ground_content = false,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
},
paramtype = "light",
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("owner", "")
meta:set_string("infotext", "")
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name() or "")
meta:set_string("infotext", S("Digtron Crate") .. "\n" .. S("Owned by @1", placer:get_player_name() or ""))
end,
can_dig = function(pos,player)
return player and not minetest.is_protected(pos, player:get_player_name()) and player_permitted(pos, player)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if player_permitted(pos,clicker) then
store_digtron(pos, clicker, "digtron:loaded_locked_crate", true)
end
end,
})
local modpath_doc = minetest.get_modpath("doc")
local loaded_formspec_string
if modpath_doc then
loaded_formspec_string =
"size[4.1,1.5]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"field[0.3,0.5;4,0.5;title;" .. S("Digtron Name") .. ";${title}]" ..
"button_exit[0.0,1.2;1,0.1;save;" .. S("Save\nTitle") .. "]" ..
"tooltip[save;" .. S("Saves the title of this Digtron") .. "]" ..
"button_exit[1.0,1.2;1,0.1;show;" .. S("Show\nBlocks") .. "]" ..
"tooltip[show;" .. S("Shows which blocks the packed Digtron will occupy if unpacked") .. "]" ..
"button_exit[2.0,1.2;1,0.1;unpack;" .. S("Unpack") .. "]" ..
"tooltip[unpack;" .. S("Attempts to unpack the Digtron on this location") .. "]" ..
"button_exit[3.0,1.2;1,0.1;help;" .. S("Help") .. "]" ..
"tooltip[help;" .. S("Show documentation about this block") .. "]"
else
loaded_formspec_string =
"size[4,1.5]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"field[0.3,0.5;4,0.5;title;" .. S("Digtron Name") .. ";${title}]" ..
"button_exit[0.5,1.2;1,0.1;save;" .. S("Save\nTitle") .. "]" ..
"tooltip[show;" .. S("Saves the title of this Digtron") .. "]" ..
"button_exit[1.5,1.2;1,0.1;show;" .. S("Show\nBlocks") .. "]" ..
"tooltip[save;" .. S("Shows which blocks the packed Digtron will occupy if unpacked") .. "]" ..
"button_exit[2.5,1.2;1,0.1;unpack;" .. S("Unpack") .. "]" ..
"tooltip[unpack;" .. S("Attempts to unpack the Digtron on this location") .. "]"
end
local loaded_formspec = function(pos, meta)
return loaded_formspec_string
end
local loaded_on_recieve = function(pos, fields, sender, protected)
local meta = minetest.get_meta(pos)
if fields.unpack or fields.save or fields.show or fields.key_enter then
meta:set_string("title", minetest.formspec_escape(fields.title))
end
local title = meta:get_string("title")
local infotext
if protected then
infotext = title .. "\n" .. S("Owned by @1", sender:get_player_name())
else
infotext = title
end
meta:set_string("infotext", infotext)
if fields.help and minetest.get_modpath("doc") then --check for mod in case someone disabled it after this digger was built
minetest.after(0.5, doc.show_entry, sender:get_player_name(), "nodes", "digtron:loaded_crate", true)
end
if not (fields.unpack or fields.show) then
return
end
local layout_string = meta:get_string("crated_layout")
local layout = DigtronLayout.deserialize(layout_string)
if layout == nil then
meta:set_string("infotext", infotext .. "\n" .. S("Unable to read layout from crate metadata, regrettably this Digtron may be corrupted."))
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
-- Something went horribly wrong
return
end
local protected_node = false
local obstructed_node = false
local pos_diff = vector.subtract(pos, layout.controller)
layout.controller = pos
for _, node_image in pairs(layout.all) do
node_image.pos = vector.add(pos_diff, node_image.pos)
if not vector.equals(pos, node_image.pos) then
if minetest.is_protected(node_image.pos, sender:get_player_name()) and not minetest.check_player_privs(sender, "protection_bypass") then
protected_node = true
minetest.add_entity(node_image.pos, "digtron:marker_crate_bad")
elseif not minetest.registered_nodes[minetest.get_node(node_image.pos).name].buildable_to then
obstructed_node = true
minetest.add_entity(node_image.pos, "digtron:marker_crate_bad")
else
minetest.add_entity(node_image.pos, "digtron:marker_crate_good")
end
end
end
if not fields.unpack then
return
end
if protected_node then
meta:set_string("infotext", infotext .. "\n" .. S("Unable to deploy Digtron due to protected blocks in target area"))
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return
end
if obstructed_node then
meta:set_string("infotext", infotext .. "\n" .. S("Unable to deploy Digtron due to obstruction in target area"))
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return
end
-- build digtron. Since the empty crate was included in the layout, that will overwrite this loaded crate and destroy it.
minetest.sound_play("machine2", {gain=1.0, pos=pos})
layout:write_layout_image(sender)
end
local loaded_on_dig = function(pos, player, loaded_node_name)
local meta = minetest.get_meta(pos)
local stack = ItemStack({name=loaded_node_name, count=1, wear=0})
local stack_meta = stack:get_meta()
stack_meta:set_string("crated_layout", meta:get_string("crated_layout"))
stack_meta:set_string("description", meta:get_string("title"))
local inv = player:get_inventory()
local stack = inv:add_item("main", stack)
if stack:get_count() > 0 then
minetest.add_item(pos, stack)
end
-- call on_dignodes callback
minetest.remove_node(pos)
end
local loaded_after_place = function(pos, itemstack)
-- Older versions of Digtron used this deprecated method for saving layout data on items.
-- Maintain backward compatibility here.
local deprecated_metadata = itemstack:get_metadata()
if deprecated_metadata ~= "" then
deprecated_metadata = minetest.deserialize(deprecated_metadata)
local meta = minetest.get_meta(pos)
meta:set_string("crated_layout", deprecated_metadata.layout)
meta:set_string("title", deprecated_metadata.title)
meta:set_string("infotext", deprecated_metadata.title)
return
end
local stack_meta = itemstack:get_meta()
local layout = stack_meta:get_string("crated_layout")
local title = stack_meta:get_string("description")
if layout ~= "" then
local meta = minetest.get_meta(pos)
meta:set_string("crated_layout", layout)
meta:set_string("title", title)
meta:set_string("infotext", title)
--meta:set_string("formspec", loaded_formspec(pos, meta)) -- not needed, on_construct handles this
end
end
minetest.register_node("digtron:loaded_crate", {
description = S("Digtron Crate (Loaded)"),
_doc_items_longdesc = digtron.doc.loaded_crate_longdesc,
_doc_items_usagehelp = digtron.doc.loaded_crate_usagehelp,
_digtron_formspec = loaded_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, not_in_creative_inventory=1, digtron_protected=1},
stack_max = 1,
sounds = default.node_sound_wood_defaults(),
tiles = {"digtron_plate.png^digtron_crate.png"},
is_ground_content = false,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", loaded_formspec(pos, meta))
end,
on_receive_fields = function(pos, formname, fields, sender)
return loaded_on_recieve(pos, fields, sender)
end,
on_dig = function(pos, node, player)
if player and not minetest.is_protected(pos, player:get_player_name()) then
return loaded_on_dig(pos, player, "digtron:loaded_crate")
end
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
loaded_after_place(pos, itemstack)
end,
})
minetest.register_node("digtron:loaded_locked_crate", {
description = S("Digtron Locked Crate (Loaded)"),
_doc_items_longdesc = digtron.doc.loaded_locked_crate_longdesc,
_doc_items_usagehelp = digtron.doc.loaded_locked_crate_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, not_in_creative_inventory=1, digtron_protected=1},
stack_max = 1,
sounds = default.node_sound_wood_defaults(),
tiles = {"digtron_plate.png^digtron_crate.png","digtron_plate.png^digtron_crate.png","digtron_plate.png^digtron_crate.png^digtron_lock.png","digtron_plate.png^digtron_crate.png^digtron_lock.png","digtron_plate.png^digtron_crate.png^digtron_lock.png","digtron_plate.png^digtron_crate.png^digtron_lock.png"},
is_ground_content = false,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("owner", "")
end,
on_dig = function(pos, node, player)
if player and not minetest.is_protected(pos, player:get_player_name()) and player_permitted(pos,player) then
return loaded_on_dig(pos, player, "digtron:loaded_locked_crate")
else
return false
end
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name() or "")
loaded_after_place(pos, itemstack)
meta:set_string("infotext", meta:get_string("infotext") .. "\n" .. S("Owned by @1", meta:get_string("owner")))
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if player_permitted(pos,clicker) then
local meta = minetest.get_meta(pos)
minetest.show_formspec(
clicker:get_player_name(),
"digtron:loaded_locked_crate"..minetest.pos_to_string(pos),
loaded_formspec_string:gsub("${title}", meta:get_string("title"), 1))
end
end,
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:sub(1, 27) == "digtron:loaded_locked_crate" then
local pos = minetest.string_to_pos(formname:sub(28, -1))
loaded_on_recieve(pos, fields, player, true)
return true
end
end)

@ -1,515 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
-- Note: diggers go in group 3 and have an execute_dig method.
local damage_hp = digtron.config.damage_hp
local damage_hp_half = damage_hp/2
local digger_nodebox = {
{-0.5, -0.5, 0, 0.5, 0.5, 0.4375}, -- Block
{-0.4375, -0.3125, 0.4375, 0.4375, 0.3125, 0.5}, -- Cutter1
{-0.3125, -0.4375, 0.4375, 0.3125, 0.4375, 0.5}, -- Cutter2
{-0.5, -0.125, -0.125, 0.5, 0.125, 0}, -- BackFrame1
{-0.125, -0.5, -0.125, 0.125, 0.5, 0}, -- BackFrame2
{-0.25, -0.25, -0.5, 0.25, 0.25, 0}, -- Drive
}
local dual_digger_nodebox = {
{-0.5, -0.4375, 0, 0.5, 0.5, 0.4375}, -- Block
{-0.4375, -0.3125, 0.4375, 0.4375, 0.3125, 0.5}, -- Cutter1
{-0.3125, -0.4375, 0.4375, 0.3125, 0.4375, 0.5}, -- Cutter2
{-0.5, 0, -0.125, 0.5, 0.125, 0}, -- BackFrame1
{-0.25, 0, -0.5, 0.25, 0.25, 0}, -- Drive
{-0.25, 0.25, -0.25, 0.25, 0.5, 0}, -- Upper_Drive
{-0.5, -0.4375, -0.5, 0.5, 0, 0.4375}, -- Lower_Block
{-0.3125, -0.5, -0.4375, 0.3125, -0.4375, 0.4375}, -- Lower_Cutter_1
{-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125}, -- Lower_Cutter_2
}
local modpath_doc = minetest.get_modpath("doc")
local intermittent_formspec_string = default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"field[0.5,0.8;1,0.1;period;" .. S("Periodicity") .. ";${period}]" ..
"tooltip[period;" .. S("Digger will dig once every n steps.\nThese steps are globally aligned, all diggers with\nthe same period and offset will dig on the same location.") .. "]" ..
"field[1.5,0.8;1,0.1;offset;" .. S("Offset") .. ";${offset}]" ..
"tooltip[offset;" .. S("Offsets the start of periodicity counting by this amount.\nFor example, a digger with period 2 and offset 0 digs\nevery even-numbered block and one with period 2 and\noffset 1 digs every odd-numbered block.") .. "]" ..
"button_exit[2.2,0.5;1,0.1;set;" .. S("Save &\nShow") .. "]" ..
"tooltip[set;" .. S("Saves settings") .. "]"
if modpath_doc then
intermittent_formspec_string = "size[4.5,1]" .. intermittent_formspec_string ..
"button_exit[3.2,0.5;1,0.1;help;" .. S("Help") .. "]" ..
"tooltip[help;" .. S("Show documentation about this block") .. "]"
else
intermittent_formspec_string = "size[3.5,1]" .. intermittent_formspec_string
end
local intermittent_formspec = function(pos, meta)
return intermittent_formspec_string
:gsub("${period}", meta:get_int("period"), 1)
:gsub("${offset}", meta:get_int("offset"), 1)
end
local intermittent_on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("period", 1)
meta:set_int("offset", 0)
end
local intermittent_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local item_def = itemstack:get_definition()
if item_def.type == "node" and minetest.get_item_group(itemstack:get_name(), "digtron") > 0 then
local returnstack, success = minetest.item_place_node(itemstack, clicker, pointed_thing)
if success and item_def.sounds and item_def.sounds.place and item_def.sounds.place.name then
minetest.sound_play(item_def.sounds.place, {pos = pos})
end
return returnstack, success
end
local meta = minetest.get_meta(pos)
minetest.show_formspec(clicker:get_player_name(),
"digtron:intermittent_digger"..minetest.pos_to_string(pos),
intermittent_formspec(pos, meta))
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:sub(1, 27) == "digtron:intermittent_digger" then
local pos = minetest.string_to_pos(formname:sub(28, -1))
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
if fields.help and minetest.get_modpath("doc") then --check for mod in case someone disabled it after this digger was built
local node_name = minetest.get_node(pos).name
minetest.after(0.5, doc.show_entry, player:get_player_name(), "nodes", node_name, true)
end
if fields.set then
digtron.show_offset_markers(pos, offset, period)
end
return true
end
end)
-- Digs out nodes that are "in front" of the digger head.
minetest.register_node("digtron:digger", {
description = S("Digtron Digger Head"),
_doc_items_longdesc = digtron.doc.digger_longdesc,
_doc_items_usagehelp = digtron.doc.digger_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = digger_nodebox,
},
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90",
"digtron_plate.png^[transformR270",
"digtron_plate.png",
"digtron_plate.png^[transformR180",
{
name = "digtron_digger_yb.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_motor.png",
},
-- returns fuel_cost, item_produced
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
if protected_nodes:get(digpos.x, digpos.y, digpos.z) then
return 0
end
return digtron.mark_diggable(digpos, nodes_dug, player)
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local facing = minetest.get_node(pos).param2
digtron.damage_creatures(player, pos, digtron.find_new_pos(pos, facing), damage_hp, items_dropped)
end,
})
-- Digs out nodes that are "in front" of the digger head.
minetest.register_node("digtron:intermittent_digger", {
description = S("Digtron Intermittent Digger Head"),
_doc_items_longdesc = digtron.doc.intermittent_digger_longdesc,
_doc_items_usagehelp = digtron.doc.intermittent_digger_usagehelp,
_digtron_formspec = intermittent_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:intermittent_digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = digger_nodebox,
},
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90",
"digtron_plate.png^[transformR270",
"digtron_plate.png",
"digtron_plate.png^[transformR180",
{
name = "digtron_digger_yb.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_intermittent.png^digtron_motor.png",
},
on_construct = intermittent_on_construct,
on_rightclick = intermittent_on_rightclick,
-- returns fuel_cost, item_produced (a table or nil)
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
if lateral_dig == true then
return 0
end
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
if protected_nodes:get(digpos.x, digpos.y, digpos.z) then
return 0
end
local meta = minetest.get_meta(pos)
if (digpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") ~= 0 then
return 0
end
return digtron.mark_diggable(digpos, nodes_dug, player)
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local facing = minetest.get_node(pos).param2
local targetpos = digtron.find_new_pos(pos, facing)
local meta = minetest.get_meta(pos)
if (targetpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") == 0 then
digtron.damage_creatures(player, pos, targetpos, damage_hp, items_dropped)
end
end
})
-- A special-purpose digger to deal with stuff like sand and gravel in the ceiling. It always digs (no periodicity or offset), but it only digs falling_block nodes
minetest.register_node("digtron:soft_digger", {
description = S("Digtron Soft Material Digger Head"),
_doc_items_longdesc = digtron.doc.soft_digger_longdesc,
_doc_items_usagehelp = digtron.doc.soft_digger_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:soft_digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = digger_nodebox,
},
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[transformR270^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[transformR180^[colorize:" .. digtron.soft_digger_colorize,
{
name = "digtron_digger_yb.png^[colorize:" .. digtron.soft_digger_colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_motor.png^[colorize:" .. digtron.soft_digger_colorize,
},
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
if protected_nodes:get(digpos.x, digpos.y, digpos.z) then
return 0
end
if digtron.is_soft_material(digpos) then
return digtron.mark_diggable(digpos, nodes_dug, player)
end
return 0
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local facing = minetest.get_node(pos).param2
digtron.damage_creatures(player, pos, digtron.find_new_pos(pos, facing), damage_hp_half, items_dropped)
end,
})
minetest.register_node("digtron:intermittent_soft_digger", {
description = S("Digtron Intermittent Soft Material Digger Head"),
_doc_items_longdesc = digtron.doc.intermittent_soft_digger_longdesc,
_doc_items_usagehelp = digtron.doc.intermittent_soft_digger_usagehelp,
_digtron_formspec = intermittent_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:intermittent_soft_digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = digger_nodebox,
},
-- Aims in the +Z direction by default
tiles = {
"digtron_plate.png^[transformR90^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[transformR270^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[transformR180^[colorize:" .. digtron.soft_digger_colorize,
{
name = "digtron_digger_yb.png^[colorize:" .. digtron.soft_digger_colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_intermittent.png^digtron_motor.png^[colorize:" .. digtron.soft_digger_colorize,
},
on_construct = intermittent_on_construct,
on_rightclick = intermittent_on_rightclick,
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
if lateral_dig == true then
return 0
end
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
if protected_nodes:get(digpos.x, digpos.y, digpos.z) then
return 0
end
local meta = minetest.get_meta(pos)
if (digpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") ~= 0 then
return 0
end
if digtron.is_soft_material(digpos) then
return digtron.mark_diggable(digpos, nodes_dug, player)
end
return 0
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local meta = minetest.get_meta(pos)
local facing = minetest.get_node(pos).param2
local targetpos = digtron.find_new_pos(pos, facing)
if (targetpos[controlling_coordinate] + meta:get_int("offset")) % meta:get_int("period") == 0 then
digtron.damage_creatures(player, pos, targetpos, damage_hp_half, items_dropped)
end
end,
})
-- Digs out nodes that are "in front" of the digger head and "below" the digger head (can be rotated).
minetest.register_node("digtron:dual_digger", {
description = S("Digtron Dual Digger Head"),
_doc_items_longdesc = digtron.doc.dual_digger_longdesc,
_doc_items_usagehelp = digtron.doc.dual_digger_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:dual_digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = dual_digger_nodebox,
},
-- Aims in the +Z and -Y direction by default
tiles = {
"digtron_plate.png^digtron_motor.png",
{
name = "digtron_digger_yb.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png",
"digtron_plate.png^[transformR180",
{
name = "digtron_digger_yb.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_motor.png",
},
-- returns fuel_cost, items_produced
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
local digdown = digtron.find_new_pos_downward(pos, facing)
local items = {}
local cost = 0
if protected_nodes:get(digpos.x, digpos.y, digpos.z) ~= true then
local forward_cost, forward_items = digtron.mark_diggable(digpos, nodes_dug, player)
if forward_items ~= nil then
for _, item in pairs(forward_items) do
table.insert(items, item)
end
end
cost = cost + forward_cost
end
if protected_nodes:get(digdown.x, digdown.y, digdown.z) ~= true then
local down_cost, down_items = digtron.mark_diggable(digdown, nodes_dug, player)
if down_items ~= nil then
for _, item in pairs(down_items) do
table.insert(items, item)
end
end
cost = cost + down_cost
end
return cost, items
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local facing = minetest.get_node(pos).param2
digtron.damage_creatures(player, pos, digtron.find_new_pos(pos, facing), damage_hp, items_dropped)
digtron.damage_creatures(player, pos, digtron.find_new_pos_downward(pos, facing), damage_hp, items_dropped)
end,
})
-- Digs out soft nodes that are "in front" of the digger head and "below" the digger head (can be rotated).
minetest.register_node("digtron:dual_soft_digger", {
description = S("Digtron Dual Soft Material Digger Head"),
_doc_items_longdesc = digtron.doc.dual_soft_digger_longdesc,
_doc_items_usagehelp = digtron.doc.dual_soft_digger_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 3},
drop = "digtron:dual_soft_digger",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = dual_digger_nodebox,
},
-- Aims in the +Z and -Y direction by default
tiles = {
"digtron_plate.png^digtron_motor.png^[colorize:" .. digtron.soft_digger_colorize,
{
name = "digtron_digger_yb.png^[colorize:" .. digtron.soft_digger_colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^[colorize:" .. digtron.soft_digger_colorize,
"digtron_plate.png^[transformR180^[colorize:" .. digtron.soft_digger_colorize,
{
name = "digtron_digger_yb.png^[colorize:" .. digtron.soft_digger_colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
"digtron_plate.png^digtron_motor.png^[colorize:" .. digtron.soft_digger_colorize,
},
-- returns fuel_cost, items_produced
execute_dig = function(pos, protected_nodes, nodes_dug, controlling_coordinate, lateral_dig, player)
local facing = minetest.get_node(pos).param2
local digpos = digtron.find_new_pos(pos, facing)
local digdown = digtron.find_new_pos_downward(pos, facing)
local items = {}
local cost = 0
if protected_nodes:get(digpos.x, digpos.y, digpos.z) ~= true and digtron.is_soft_material(digpos) then
local forward_cost, forward_items = digtron.mark_diggable(digpos, nodes_dug, player)
if forward_items ~= nil then
for _, item in pairs(forward_items) do
table.insert(items, item)
end
end
cost = cost + forward_cost
end
if protected_nodes:get(digdown.x, digdown.y, digdown.z) ~= true and digtron.is_soft_material(digdown) then
local down_cost, down_items = digtron.mark_diggable(digdown, nodes_dug, player)
if down_items ~= nil then
for _, item in pairs(down_items) do
table.insert(items, item)
end
end
cost = cost + down_cost
end
return cost, items
end,
damage_creatures = function(player, pos, controlling_coordinate, items_dropped)
local facing = minetest.get_node(pos).param2
digtron.damage_creatures(player, pos, digtron.find_new_pos(pos, facing), damage_hp_half, items_dropped)
digtron.damage_creatures(player, pos, digtron.find_new_pos_downward(pos, facing), damage_hp_half, items_dropped)
end,
})

@ -1,189 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local inventory_formspec_string =
"size[9,9.3]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[0,0;" .. S("Digtron components") .. "]" ..
"list[current_name;main;0,0.6;8,4;]" ..
"list[current_player;main;0,5.15;8,1;]" ..
"list[current_player;main;0,6.38;8,3;8]" ..
"listring[current_name;main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,5.15)..
"button_exit[8,3.5;1,1;duplicate;"..S("Duplicate").."]" ..
"tooltip[duplicate;" .. S("Puts a copy of the adjacent Digtron into an empty crate\nlocated at the output side of the duplicator,\nusing components from the duplicator's inventory.") .. "]"
if minetest.get_modpath("doc") then
inventory_formspec_string = inventory_formspec_string ..
"button_exit[8,4.5;1,1;help;"..S("Help").."]" ..
"tooltip[help;" .. S("Show documentation about this block") .. "]"
end
minetest.register_node("digtron:duplicator", {
description = S("Digtron Duplicator"),
_doc_items_longdesc = digtron.doc.duplicator_longdesc,
_doc_items_usagehelp = digtron.doc.duplicator_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3},
sounds = digtron.metal_sounds,
tiles = {"digtron_plate.png^(digtron_axel_side.png^[transformR90)",
"digtron_plate.png^(digtron_axel_side.png^[transformR270)",
"digtron_plate.png^digtron_axel_side.png",
"digtron_plate.png^(digtron_axel_side.png^[transformR180)",
"digtron_plate.png^digtron_builder.png",
"digtron_plate.png",
},
paramtype = "light",
paramtype2= "facedir",
is_ground_content = false,
drawtype="nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, 0.3125, 0.3125, 0.5, 0.5, 0.5}, -- FrontFrame_top
{-0.5, -0.5, 0.3125, 0.5, -0.3125, 0.5}, -- FrontFrame_bottom
{0.3125, -0.3125, 0.3125, 0.5, 0.3125, 0.5}, -- FrontFrame_right
{-0.5, -0.3125, 0.3125, -0.3125, 0.3125, 0.5}, -- FrontFrame_left
{-0.0625, -0.3125, 0.3125, 0.0625, 0.3125, 0.375}, -- frontcross_vertical
{-0.3125, -0.0625, 0.3125, 0.3125, 0.0625, 0.375}, -- frontcross_horizontal
{-0.4375, -0.4375, -0.4375, 0.4375, 0.4375, 0.3125}, -- Body
{-0.5, -0.3125, -0.5, -0.3125, 0.3125, -0.3125}, -- backframe_vertical
{0.3125, -0.3125, -0.5, 0.5, 0.3125, -0.3125}, -- backframe_left
{-0.5, 0.3125, -0.5, 0.5, 0.5, -0.3125}, -- backframe_top
{-0.5, -0.5, -0.5, 0.5, -0.3125, -0.3125}, -- backframe_bottom
{-0.0625, -0.0625, -0.5625, 0.0625, 0.0625, -0.4375}, -- back_probe
},
},
selection_box = {
type = "regular"
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", inventory_formspec_string)
local inv = meta:get_inventory()
inv:set_size("main", 8*4)
end,
can_dig = function(pos,player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("main")
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if minetest.get_item_group(stack:get_name(), "digtron") > 0 then
return stack:get_count()
else
return 0
end
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.help then
minetest.after(0.5, doc.show_entry, sender:get_player_name(), "nodes", "digtron:duplicator", true)
end
if fields.duplicate then
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local target_pos = vector.add(pos, minetest.facedir_to_dir(node.param2))
local target_node = minetest.get_node(target_pos)
if target_node.name ~= "digtron:empty_crate" then
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
meta:set_string("infotext", S("Needs an empty crate in output position to store duplicate"))
return
end
local layout = DigtronLayout.create(pos, sender)
if layout.contains_protected_node then
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
meta:set_string("infotext", S("Digtron can't be duplicated, it contains protected blocks"))
return
end
if #layout.all == 1 then
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
meta:set_string("infotext", S("No Digtron components adjacent to duplicate"))
return
end
layout.all[1] = {node={name="digtron:empty_crate"}, meta={fields = {}, inventory = {}}, pos={x=pos.x, y=pos.y, z=pos.z}} -- replace the duplicator's image with the empty crate image
-- count required nodes, skipping node 1 since it's the crate and we already know it's present in-world
local required_count = {}
for i = 2, #layout.all do
local nodename = layout.all[i].node.name
required_count[nodename] = (required_count[nodename] or 0) + 1
end
-- check that there's enough in the duplicator's inventory
local unsatisfied = {}
for name, count in pairs(required_count) do
if not inv:contains_item("main", ItemStack({name=name, count=count})) then
table.insert(unsatisfied, tostring(count) .. " " .. minetest.registered_nodes[name].description)
end
end
if #unsatisfied > 0 then
minetest.sound_play("dingding", {gain=1.0, pos=pos}) -- Insufficient inventory
meta:set_string("infotext", S("Duplicator requires:\n@1", table.concat(unsatisfied, "\n")))
return
end
meta:set_string("infotext", "") -- clear infotext, we're good to go.
-- deduct nodes from duplicator inventory
for name, count in pairs(required_count) do
inv:remove_item("main", ItemStack({name=name, count=count}))
end
-- clear inventories of image's nodes
if layout.inventories ~= nil then
for _, node_image in pairs(layout.inventories) do
local main_inventory = node_image.meta.inventory.main
if type(main_inventory) ~= "table" then
main_inventory = {}
end
for index, _ in pairs(main_inventory) do
main_inventory[index] = ItemStack(nil)
end
end
end
if layout.fuelstores ~= nil then
for _, node_image in pairs(layout.fuelstores) do
local fuel_inventory = node_image.meta.inventory.fuel
for index, _ in pairs(fuel_inventory) do
fuel_inventory[index] = ItemStack(nil)
end
end
end
if layout.battery_holders ~= nil then
for _, node_image in pairs(layout.battery_holders) do
local battery_inventory = node_image.meta.inventory.batteries
for index, _ in pairs(battery_inventory) do
battery_inventory[index] = ItemStack(nil)
end
end
end
-- replace empty crate with loaded crate and write image to its metadata
local layout_string = layout:serialize()
minetest.set_node(target_pos, {name="digtron:loaded_crate", param1=node.param1, param2=node.param2})
local target_meta = minetest.get_meta(target_pos)
target_meta:set_string("crated_layout", layout_string)
local titlestring = S("Crated @1-block Digtron", tostring(#layout.all-1))
target_meta:set_string("title", titlestring)
target_meta:set_string("infotext", titlestring)
minetest.sound_play("machine1", {gain=1.0, pos=pos})
end
end,
})

@ -1,174 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
--Build up the formspec, somewhat complicated due to multiple mod options
local pipeworks_path = minetest.get_modpath("pipeworks")
local doc_path = minetest.get_modpath("doc")
local formspec_width = 1.5
local ejector_formspec_string =
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots
if doc_path then
ejector_formspec_string = ejector_formspec_string ..
"button_exit[".. 0.2 + formspec_width ..",0.5;1,0.1;help;" .. S("Help") .. "]" ..
"tooltip[help;" .. S("Show documentation about this block") .. "]"
formspec_width = formspec_width + 1.5
end
local ejector_formspec_string = "size[".. formspec_width .. ",1]" .. ejector_formspec_string
local ejector_formspec = function(pos, meta)
local return_string = ejector_formspec_string
if pipeworks_path then
return_string = return_string .. "checkbox[0,0.5;nonpipe;"..S("Eject into world")..";"..meta:get_string("nonpipe").."]" ..
"tooltip[nonpipe;" .. S("When checked, will eject items even if there's no pipe to accept it") .. "]"
end
return return_string .. "checkbox[0,0;autoeject;"..S("Automatic")..";"..meta:get_string("autoeject").."]" ..
"tooltip[autoeject;" .. S("When checked, will eject items automatically with every Digtron cycle.\nItem ejectors can always be operated manually by punching them.") .. "]"
end
local function eject_items(pos, node, player, eject_even_without_pipeworks, layout)
local dir = minetest.facedir_to_dir(node.param2)
local destination_pos = vector.add(pos, dir)
local destination_node_name = minetest.get_node(destination_pos).name
local destination_node_def = minetest.registered_nodes[destination_node_name]
if not pipeworks_path then eject_even_without_pipeworks = true end -- if pipeworks is not installed, always eject into world (there's no other option)
local insert_into_pipe = false
local eject_into_world = false
if pipeworks_path and minetest.get_node_group(destination_node_name, "tubedevice") > 0 then
insert_into_pipe = true
elseif eject_even_without_pipeworks then
if destination_node_def and not destination_node_def.walkable then
eject_into_world = true
else
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return false
end
else
return false
end
if layout == nil then
layout = DigtronLayout.create(pos, player)
end
-- Build a list of all the items that builder nodes want to use.
local filter_items = {}
if layout.builders ~= nil then
for _, node_image in pairs(layout.builders) do
filter_items[node_image.meta.inventory.main[1]:get_name()] = true
end
end
-- Look through the inventories and find an item that's not on that list.
local source_node = nil
local source_index = nil
local source_stack = nil
for _, node_image in pairs(layout.inventories or {}) do
if type(node_image.meta.inventory.main) ~= "table" then
node_image.meta.inventory.main = {}
end
for index, item_stack in pairs(node_image.meta.inventory.main) do
if item_stack:get_count() > 0 and not filter_items[item_stack:get_name()] then
source_node = node_image
source_index = index
source_stack = item_stack
node_image.meta.inventory.main[index] = nil
break
end
end
if source_node then break end
end
if source_node then
local meta = minetest.get_meta(source_node.pos)
local inv = meta:get_inventory()
if insert_into_pipe then
local from_pos = vector.add(pos, vector.multiply(dir, 0.5))
local start_pos = pos
inv:set_stack("main", source_index, nil)
pipeworks.tube_inject_item(from_pos, start_pos, vector.multiply(dir, 1), source_stack, player:get_player_name())
minetest.sound_play("steam_puff", {gain=0.5, pos=pos})
return true
elseif eject_into_world then
minetest.add_item(destination_pos, source_stack)
inv:set_stack("main", source_index, nil)
minetest.sound_play("steam_puff", {gain=0.5, pos=pos})
return true
end
end
-- couldn't find an item to eject
return false
end
minetest.register_node("digtron:inventory_ejector", {
description = S("Digtron Inventory Ejector"),
_doc_items_longdesc = digtron.doc.inventory_ejector_longdesc,
_doc_items_usagehelp = digtron.doc.inventory_ejector_usagehelp,
_digtron_formspec = ejector_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 9, tubedevice = 1},
tiles = {"digtron_plate.png", "digtron_plate.png", "digtron_plate.png", "digtron_plate.png", "digtron_plate.png^digtron_output.png", "digtron_plate.png^digtron_output_back.png"},
drawtype = "nodebox",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.1875}, -- NodeBox1
{-0.3125, -0.3125, 0.1875, 0.3125, 0.3125, 0.3125}, -- NodeBox2
{-0.1875, -0.1875, 0.3125, 0.1875, 0.1875, 0.5}, -- NodeBox3
}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("autoeject", "true")
meta:set_string("formspec", ejector_formspec(pos, meta))
end,
tube = (function() if pipeworks_path then return {
connect_sides = {back = 1}
} end end)(),
on_punch = function(pos, node, player)
eject_items(pos, node, player, true)
end,
execute_eject = function(pos, node, player, layout)
local meta = minetest.get_meta(pos)
eject_items(pos, node, player, meta:get_string("nonpipe") == "true", layout)
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
if fields.help and minetest.get_modpath("doc") then --check for mod in case someone disabled it after this digger was built
local node_name = minetest.get_node(pos).name
minetest.after(0.5, doc.show_entry, sender:get_player_name(), "nodes", node_name, true)
end
if fields.nonpipe then
meta:set_string("nonpipe", fields.nonpipe)
end
if fields.autoeject then
meta:set_string("autoeject", fields.autoeject)
end
meta:set_string("formspec", ejector_formspec(pos, meta))
end,
after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
})

@ -8,7 +8,6 @@ minetest.register_node("digtron:structure", {
_doc_items_longdesc = digtron.doc.structure_longdesc,
_doc_items_usagehelp = digtron.doc.structure_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:structure",
tiles = {"digtron_plate.png"},
drawtype = "nodebox",
sounds = digtron.metal_sounds,
@ -41,7 +40,6 @@ minetest.register_node("digtron:light", {
_doc_items_longdesc = digtron.doc.light_longdesc,
_doc_items_usagehelp = digtron.doc.light_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:light",
tiles = {"digtron_plate.png^digtron_light.png"},
drawtype = "nodebox",
paramtype = "light",
@ -63,7 +61,6 @@ minetest.register_node("digtron:panel", {
_doc_items_longdesc = digtron.doc.panel_longdesc,
_doc_items_usagehelp = digtron.doc.panel_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:panel",
tiles = {"digtron_plate.png"},
drawtype = "nodebox",
paramtype = "light",
@ -86,7 +83,6 @@ minetest.register_node("digtron:edge_panel", {
_doc_items_longdesc = digtron.doc.edge_panel_longdesc,
_doc_items_usagehelp = digtron.doc.edge_panel_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:edge_panel",
tiles = {"digtron_plate.png"},
drawtype = "nodebox",
paramtype = "light",
@ -115,7 +111,6 @@ minetest.register_node("digtron:corner_panel", {
_doc_items_longdesc = digtron.doc.corner_panel_longdesc,
_doc_items_usagehelp = digtron.doc.corner_panel_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 1},
drop = "digtron:corner_panel",
tiles = {"digtron_plate.png"},
drawtype = "nodebox",
paramtype = "light",

@ -1,100 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local size = 3/16
local max_dig_cost = math.max(digtron.config.dig_cost_cracky, digtron.config.dig_cost_crumbly, digtron.config.dig_cost_choppy, digtron.config.dig_cost_default)
local get_formspec_string = function(current_val, current_max)
return "size[4.5,0.6]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"field[0.2,0.3;1,1;value;;".. current_val .. "]" ..
"button[1,0;1,1;maximize;" .. S("Maximize\nPower") .."]" ..
"label[2,0;"..S("Maximum Power\nRequired: @1", current_max) .."]"..
"button[3.5,0;1,1;refresh;" .. S("Refresh\nMax") .."]"
end
local connector_groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 8, technic_machine=1, technic_hv=1}
if not minetest.get_modpath("technic") then
-- Technic is not installed, hide this away.
connector_groups.not_in_creative_inventory = 1
end
minetest.register_node("digtron:power_connector", {
description = S("Digtron HV Power Connector"),
_doc_items_longdesc = digtron.doc.power_connector_longdesc,
_doc_items_usagehelp = digtron.doc.power_connector_usagehelp,
groups = connector_groups,
tiles = {"digtron_plate.png^digtron_power_connector_top.png^digtron_digger_yb_frame.png", "digtron_plate.png^digtron_digger_yb_frame.png",
"digtron_plate.png^digtron_digger_yb_frame.png^digtron_power_connector_side.png", "digtron_plate.png^digtron_digger_yb_frame.png^digtron_power_connector_side.png",
"digtron_plate.png^digtron_digger_yb_frame.png^digtron_power_connector_side.png", "digtron_plate.png^digtron_digger_yb_frame.png^digtron_power_connector_side.png",
},
connect_sides = {"bottom", "top", "left", "right", "front", "back"},
drawtype = "nodebox",
sounds = digtron.metal_sounds,
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
connects_to = {"group:technic_hv_cable"},
node_box = {
type = "connected",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5}, -- Main body
{-0.1875, 0, -0.1875, 0.1875, 0.5, 0.1875}, -- post
{-0.3125, 0.0625, -0.3125, 0.3125, 0.1875, 0.3125}, -- vane
{-0.3125, 0.25, -0.3125, 0.3125, 0.375, 0.3125}, -- vane
},
connect_front = {-size, -size, -0.5, size, size, size}, -- z-
connect_back = {-size, -size, size, size, size, 0.5 }, -- z+
connect_left = {-0.5, -size, -size, size, size, size}, -- x-
connect_right = {-size, -size, -size, 0.5, size, size}, -- x+
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", get_formspec_string(0,0))
end,
technic_run = function(pos, node)
local meta = minetest.get_meta(pos)
local eu_input = meta:get_int("HV_EU_input")
local demand = meta:get_int("HV_EU_demand")
meta:set_string("infotext", S("Digtron Power @1/@2", eu_input, demand))
end,
on_receive_fields = function(pos, formname, fields, sender)
local layout = DigtronLayout.create(pos, sender)
local max_cost = 0
if layout.builders ~= nil then
for _, node_image in pairs(layout.builders) do
max_cost = max_cost + (digtron.config.build_cost * (node_image.meta.fields.extrusion or 1))
end
end
if layout.diggers ~= nil then
for _, node_image in pairs(layout.diggers) do
max_cost = max_cost + max_dig_cost
end
end
local current_max = max_cost * digtron.config.power_ratio
local meta = minetest.get_meta(pos)
if fields.maximize then
meta:set_int("HV_EU_demand", current_max)
elseif fields.value ~= nil then
local number = tonumber(fields.value) or 0
local number = math.min(math.max(number, 0), current_max)
meta:set_int("HV_EU_demand", number)
end
meta:set_string("formspec", get_formspec_string(meta:get_int("HV_EU_demand"), current_max))
end,
})
if minetest.get_modpath("technic") then
technic.register_machine("HV", "digtron:power_connector", technic.receiver)
end

@ -2,23 +2,19 @@
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local pipeworks_path = minetest.get_modpath("pipeworks")
--local pipeworks_path = minetest.get_modpath("pipeworks")
local inventory_formspec_string =
"size[8,9.3]" ..
local get_inventory_formspec = function(pos, player_name)
return "size[8,9.3]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[0,0;" .. S("Inventory items") .. "]" ..
"list[current_name;main;0,0.6;8,4;]" ..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.6;8,4;]" ..
"list[current_player;main;0,5.15;8,1;]" ..
"listring[]" ..
"list[current_player;main;0,6.38;8,3;8]" ..
"listring[current_name;main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,5.15)
local inventory_formspec = function(pos, meta)
return inventory_formspec_string
end
-- Storage buffer. Builder nodes draw from this inventory and digger nodes deposit into it.
@ -27,9 +23,7 @@ minetest.register_node("digtron:inventory", {
description = S("Digtron Inventory Storage"),
_doc_items_longdesc = digtron.doc.inventory_longdesc,
_doc_items_usagehelp = digtron.doc.inventory_usagehelp,
_digtron_formspec = inventory_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 2, tubedevice = 1, tubedevice_receiver = 1},
drop = "digtron:inventory",
sounds = digtron.metal_sounds,
paramtype2= "facedir",
drawtype = "nodebox",
@ -52,7 +46,6 @@ minetest.register_node("digtron:inventory", {
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", inventory_formspec(pos, meta))
local inv = meta:get_inventory()
inv:set_size("main", 8*4)
end,
@ -63,54 +56,62 @@ minetest.register_node("digtron:inventory", {
return inv:is_empty("main")
end,
-- Pipeworks compatibility
----------------------------------------------------------------
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local digtron_id = meta:get("digtron_id")
local player_name = clicker:get_player_name()
if digtron_id == nil then
minetest.show_formspec(player_name,
"digtron_inventory:"..minetest.pos_to_string(pos)..":"..player_name,
get_inventory_formspec(pos, player_name))
else
minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with its inventory via the controller node.")
end
end,
tube = (function() if pipeworks_path then return {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("main", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:room_for_item("main", stack)
end,
input_inventory = "main",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
} end end)(),
after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
-- -- Pipeworks compatibility
-- ----------------------------------------------------------------
--
-- tube = (function() if pipeworks_path then return {
-- insert_object = function(pos, node, stack, direction)
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- return inv:add_item("main", stack)
-- end,
-- can_insert = function(pos, node, stack, direction)
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- return inv:room_for_item("main", stack)
-- end,
-- input_inventory = "main",
-- connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
-- } end end)(),
--
-- after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
-- after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
})
local fuelstore_formspec_string =
"size[8,9.3]" ..
local get_fuelstore_formspec = function(pos, player_name)
return "size[8,9.3]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[0,0;" .. S("Fuel items") .. "]" ..
"list[current_name;fuel;0,0.6;8,4;]" ..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";fuel;0,0.6;8,4;]" ..
"list[current_player;main;0,5.15;8,1;]" ..
"listring[]" ..
"list[current_player;main;0,6.38;8,3;8]" ..
"listring[current_name;fuel]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,5.15)
local fuelstore_formspec = function(pos, meta)
return fuelstore_formspec_string
end
-- Fuel storage. Controller node draws fuel from here.
-- Note that fuel stores are digtron group 5.
minetest.register_node("digtron:fuelstore", {
description = S("Digtron Fuel Storage"),
_doc_items_longdesc = digtron.doc.fuelstore_longdesc,
_doc_items_usagehelp = digtron.doc.fuelstore_usagehelp,
_digtron_formspec = fuelstore_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 5, tubedevice = 1, tubedevice_receiver = 1},
drop = "digtron:fuelstore",
sounds = digtron.metal_sounds,
paramtype2= "facedir",
drawtype = "nodebox",
@ -133,7 +134,6 @@ minetest.register_node("digtron:fuelstore", {
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", fuelstore_formspec(pos, meta))
local inv = meta:get_inventory()
inv:set_size("fuel", 8*4)
end,
@ -155,52 +155,63 @@ minetest.register_node("digtron:fuelstore", {
local inv = meta:get_inventory()
return inv:is_empty("fuel")
end,
-- Pipeworks compatibility
----------------------------------------------------------------
tube = (function() if pipeworks_path then return {
insert_object = function(pos, node, stack, direction)
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("fuel", stack)
end
return stack
end,
can_insert = function(pos, node, stack, direction)
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:room_for_item("fuel", stack)
end
return false
end,
input_inventory = "fuel",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
} end end)(),
after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
})
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local digtron_id = meta:get("digtron_id")
local player_name = clicker:get_player_name()
if digtron_id == nil then
minetest.show_formspec(player_name,
"digtron_fuelstore:"..minetest.pos_to_string(pos)..":"..player_name,
get_fuelstore_formspec(pos, player_name))
else
minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with its inventory via the controller node.")
end
end,
local combined_storage_formspec_string =
"size[8,9.9]" ..
--
-- -- Pipeworks compatibility
-- ----------------------------------------------------------------
--
-- tube = (function() if pipeworks_path then return {
-- insert_object = function(pos, node, stack, direction)
-- if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- return inv:add_item("fuel", stack)
-- end
-- return stack
-- end,
-- can_insert = function(pos, node, stack, direction)
-- if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- return inv:room_for_item("fuel", stack)
-- end
-- return false
-- end,
-- input_inventory = "fuel",
-- connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
-- } end end)(),
--
-- after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
-- after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
})
--
local get_combined_formspec = function(pos, player_name)
return "size[8,9.9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[0,0;" .. S("Inventory items") .. "]" ..
"list[current_name;main;0,0.6;8,3;]" ..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.6;8,3;]" ..
"label[0,3.5;" .. S("Fuel items") .. "]" ..
"list[current_name;fuel;0,4.1;8,1;]" ..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";fuel;0,4.1;8,1;]" ..
"list[current_player;main;0,5.75;8,1;]" ..
"list[current_player;main;0,6.98;8,3;8]" ..
"listring[current_name;main]" ..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,5.75)
local combined_storage_formspec = function(pos, meta)
return combined_storage_formspec_string
end
-- Combined storage. Group 6 has both an inventory and a fuel store
@ -208,9 +219,7 @@ minetest.register_node("digtron:combined_storage", {
description = S("Digtron Combined Storage"),
_doc_items_longdesc = digtron.doc.combined_storage_longdesc,
_doc_items_usagehelp = digtron.doc.combined_storage_usagehelp,
_digtron_formspec = combined_storage_formspec,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 6, tubedevice = 1, tubedevice_receiver = 1},
drop = "digtron:combined_storage",
sounds = digtron.metal_sounds,
paramtype2= "facedir",
drawtype = "nodebox",
@ -231,7 +240,6 @@ minetest.register_node("digtron:combined_storage", {
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", combined_storage_formspec(pos, meta))
local inv = meta:get_inventory()
inv:set_size("main", 8*3)
inv:set_size("fuel", 8*1)
@ -268,47 +276,60 @@ minetest.register_node("digtron:combined_storage", {
local inv = meta:get_inventory()
return inv:is_empty("fuel") and inv:is_empty("main")
end,
-- Pipeworks compatibility
----------------------------------------------------------------
tube = (function() if pipeworks_path then return {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 and direction.y == 1 then
return inv:add_item("fuel", stack)
end
return inv:add_item("main", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 and direction.y == 1 then
return inv:room_for_item("fuel", stack)
end
return inv:room_for_item("main", stack)
end,
input_inventory = "main",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
} end end)(),
after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local digtron_id = meta:get("digtron_id")
local player_name = clicker:get_player_name()
if digtron_id == nil then
minetest.show_formspec(player_name,
"digtron_combined_storage:"..minetest.pos_to_string(pos)..":"..player_name,
get_combined_formspec(pos, player_name))
else
minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with its inventory via the controller node.")
end
end,
--
-- -- Pipeworks compatibility
-- ----------------------------------------------------------------
-- tube = (function() if pipeworks_path then return {
-- insert_object = function(pos, node, stack, direction)
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 and direction.y == 1 then
-- return inv:add_item("fuel", stack)
-- end
-- return inv:add_item("main", stack)
-- end,
-- can_insert = function(pos, node, stack, direction)
-- local meta = minetest.get_meta(pos)
-- local inv = meta:get_inventory()
-- if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 and direction.y == 1 then
-- return inv:room_for_item("fuel", stack)
-- end
-- return inv:room_for_item("main", stack)
-- end,
-- input_inventory = "main",
-- connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
-- } end end)(),
--
-- after_place_node = (function() if pipeworks_path then return pipeworks.after_place end end)(),
-- after_dig_node = (function() if pipeworks_path then return pipeworks.after_dig end end)()
})
-- Hopper compatibility
if minetest.get_modpath("hopper") and hopper ~= nil and hopper.add_container ~= nil then
hopper:add_container({
{"top", "digtron:inventory", "main"},
{"bottom", "digtron:inventory", "main"},
{"side", "digtron:inventory", "main"},
{"top", "digtron:fuelstore", "fuel"},
{"bottom", "digtron:fuelstore", "fuel"},
{"side", "digtron:fuelstore", "fuel"},
{"top", "digtron:combined_storage", "main"},
{"bottom", "digtron:combined_storage", "main"},
{"side", "digtron:combined_storage", "fuel"},
})
end
--
---- Hopper compatibility
--if minetest.get_modpath("hopper") and hopper ~= nil and hopper.add_container ~= nil then
-- hopper:add_container({
-- {"top", "digtron:inventory", "main"},
-- {"bottom", "digtron:inventory", "main"},
-- {"side", "digtron:inventory", "main"},
--
-- {"top", "digtron:fuelstore", "fuel"},
-- {"bottom", "digtron:fuelstore", "fuel"},
-- {"side", "digtron:fuelstore", "fuel"},
--
-- {"top", "digtron:combined_storage", "main"},
-- {"bottom", "digtron:combined_storage", "main"},
-- {"side", "digtron:combined_storage", "fuel"},
-- })
--end

@ -1,334 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
minetest.register_craftitem("digtron:digtron_core", {
description = S("Digtron Core"),
inventory_image = "digtron_core.png",
_doc_items_longdesc = digtron.doc.core_longdesc,
_doc_items_usagehelp = digtron.doc.core_usagehelp,
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"","default:steel_ingot",""},
{"default:steel_ingot","default:mese_crystal_fragment","default:steel_ingot"},
{"","default:steel_ingot",""}
}
})
minetest.register_craft({
output = "digtron:controller",
recipe = {
{"","default:mese_crystal",""},
{"default:mese_crystal","digtron:digtron_core","default:mese_crystal"},
{"","default:mese_crystal",""}
}
})
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 = {
{"","default:mese_crystal_fragment",""},
{"default:mese_crystal_fragment","digtron:digtron_core","default:mese_crystal_fragment"},
{"","default:mese_crystal_fragment",""}
}
})
minetest.register_craft({
output = "digtron:light",
recipe = {
{"","default:torch",""},
{"","digtron:digtron_core",""},
{"","",""}
}
})
minetest.register_craft({
output = "digtron:digger",
recipe = {
{"","default:diamond",""},
{"default:diamond","digtron:digtron_core","default:diamond"},
{"","default:diamond",""}
}
})
minetest.register_craft({
output = "digtron:soft_digger",
recipe = {
{"","default:steel_ingot",""},
{"default:steel_ingot","digtron:digtron_core","default:steel_ingot"},
{"","default:steel_ingot",""}
}
})
minetest.register_craft({
output = "digtron:inventory",
recipe = {
{"","default:chest",""},
{"","digtron:digtron_core",""},
{"","",""}
}
})
minetest.register_craft({
output = "digtron:fuelstore",
recipe = {
{"","default:furnace",""},
{"","digtron:digtron_core",""},
{"","",""}
}
})
if minetest.get_modpath("technic") then
-- no need for this recipe if technic is not installed, avoid cluttering crafting guides
minetest.register_craft({
output = "digtron:battery_holder",
recipe = {
{"","default:chest",""},
{"","digtron:digtron_core",""},
{"","default:steel_ingot",""}
}
})
minetest.register_craft({
output = "digtron:power_connector",
recipe = {
{"","technic:hv_cable",""},
{"technic:hv_cable","digtron:digtron_core","technic:hv_cable"},
{"","technic:hv_cable",""}
}
})
end
minetest.register_craft({
output = "digtron:combined_storage",
recipe = {
{"","default:furnace",""},
{"","digtron:digtron_core",""},
{"","default:chest",""}
}
})
minetest.register_craft({
output = "digtron:pusher",
recipe = {
{"","default:coal_lump",""},
{"default:coal_lump","digtron:digtron_core","default:coal_lump"},
{"","default:coal_lump",""}
}
})
minetest.register_craft({
output = "digtron:axle",
recipe = {
{"default:coal_lump","default:coal_lump","default:coal_lump"},
{"default:coal_lump","digtron:digtron_core","default:coal_lump"},
{"default:coal_lump","default:coal_lump","default:coal_lump"}
}
})
minetest.register_craft({
output = "digtron:empty_crate",
recipe = {
{"","default:chest",""},
{"","digtron:digtron_core",""},
{"","default:mese_crystal",""}
}
})
minetest.register_craft({
output = "digtron:empty_locked_crate",
type = "shapeless",
recipe = {"default:steel_ingot", "digtron:empty_crate"},
})
minetest.register_craft({
output = "digtron:empty_crate",
type = "shapeless",
recipe = {"digtron:empty_locked_crate"},
})
minetest.register_craft({
output = "digtron:duplicator",
recipe = {
{"default:mese_crystal","default:mese_crystal","default:mese_crystal"},
{"default:chest","digtron:digtron_core","default:chest"},
{"default:mese_crystal","default:mese_crystal","default:mese_crystal"}
}
})
minetest.register_craft({
output = "digtron:inventory_ejector",
recipe = {
{"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
{"","digtron:digtron_core",""},
{"","default:steel_ingot",""}
}
})
-- Structural
minetest.register_craft({
output = "digtron:structure",
recipe = {
{"group:stick","","group:stick"},
{"","digtron:digtron_core",""},
{"group:stick","","group:stick"}
}
})
minetest.register_craft({
output = "digtron:panel",
recipe = {
{"","",""},
{"","digtron:digtron_core",""},
{"","default:steel_ingot",""}
}
})
minetest.register_craft({
output = "digtron:edge_panel",
recipe = {
{"","",""},
{"","digtron:digtron_core","default:steel_ingot"},
{"","default:steel_ingot",""}
}
})
minetest.register_craft({
output = "digtron:corner_panel",
recipe = {
{"","",""},
{"","digtron:digtron_core","default:steel_ingot"},
{"","default:steel_ingot","default:steel_ingot"}
}
})
-- For swapping digger types
minetest.register_craft({
output = "digtron:digger",
recipe = {
{"digtron:intermittent_digger"},
}
})
minetest.register_craft({
output = "digtron:intermittent_digger",
recipe = {
{"digtron:digger"},
}
})
minetest.register_craft({
output = "digtron:soft_digger",
recipe = {
{"digtron:intermittent_soft_digger"},
}
})
minetest.register_craft({
output = "digtron:intermittent_soft_digger",
recipe = {
{"digtron:soft_digger"},
}
})
minetest.register_craft({
output = "digtron:dual_soft_digger",
type = "shapeless",
recipe = {"digtron:soft_digger", "digtron:soft_digger"},
})
minetest.register_craft({
output = "digtron:dual_digger",
type = "shapeless",
recipe = {"digtron:digger", "digtron:digger"},
})
minetest.register_craft({
output = "digtron:soft_digger 2",
recipe = {
{"digtron:dual_soft_digger"},
}
})
minetest.register_craft({
output = "digtron:digger 2",
recipe = {
{"digtron:dual_digger"},
}
})
-- And some recycling reactions to get digtron cores out of the "cheap" parts:
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:structure"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:panel"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:corner_panel"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:edge_panel"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:inventory"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:fuelstore"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:combined_storage"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:light"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:pusher"},
}
})
minetest.register_craft({
output = "digtron:digtron_core",
recipe = {
{"digtron:axle"},
}
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

@ -1,51 +0,0 @@
#This can cause digtrons to operate without consuming fuel or building materials,
#though they still check whether they have enough in inventory.
#It's a separate setting from regular creative mode.
digtron_uses_resources (Digtron uses resources) bool true
#When true, lava counts as protected blocks.
digtron_lava_impassible (Lava is impassible to Digtrons) bool true
#Sets how much HP damage a digger does. Soft material diggers do half this.
#Set to 0 to disable damage entirely.
digtron_damage_hp (Diggers damage this many hp) int 8
#How many seconds a digtron waits between cycles.
#Auto-controllers can make this wait longer, but cannot make it shorter.
digtron_cycle_time (Minimum Digtron cycle time in seconds) float 1.0 0.0 60.0
#How many Digtron blocks can be moved for each adjacent
#solid block that the Digtron has traction against
digtron_traction_factor (Digtron traction factor) float 3.0 0.0 1000.0
#The maximum extrusion setting permitted for a Digtron builder module.
digtron_maximum_extrusion (Digtron maximum extrusion) int 25 1 100
digtron_marker_crate_good_duration (Duration that 'good' crate markers last) float 3.0 0.0 100.0
digtron_marker_crate_bad_duration (Duration that 'bad' crate markers last) float 9.0 0.0 100.0
#When a Digtron encounters unloaded map blocks, cause them to load
#so that the Digtron can continue moving.
digtron_emerge_unloaded_mapblocks (Emerge unloaded map blocks) bool true
[Fuel costs]
#eg, stone.
#In a default Minetest game one lump of coal provides 40.0 units of fuel.
digtron_dig_cost_cracky (Fuel cost for digging cracky blocks) float 1.0 0.0 100.0
# eg, dirt, sand.
#In a default Minetest game one lump of coal provides 40.0 units of fuel.
digtron_dig_cost_crumbly (Fuel cost for digging crumbly blocks) float 0.5 0.0 100.0
#eg, wood.
#In a default Minetest game one lump of coal provides 40.0 units of fuel.
digtron_dig_cost_choppy (Fuel cost for digging choppy blocks) float 0.75 0.0 100.0
#Fuel cost to dig a block that doesn't fall into one of the other categories.
#In a default Minetest game one lump of coal provides 40.0 units of fuel.
digtron_dig_cost_default (Fuel cost for digging other block types) float 0.5 0.0 100.0
#How much fuel is required to build a block
digtron_build_cost (Fuel cost to build one block) float 1.0 0.0 100.0
#If the [technic] mod is installed Digtron can draw power from technic batteries.
#A full battery holds 10000 electrical units. This is divided by the power ratio
#setting to convert it into fuel units.
digtron_power_ratio (Electrical charge to coal heat conversion ratio) int 1 1000 100

@ -1,59 +0,0 @@
-- re-applies the "_digtron_formspec" property from all digtron node defs to the digtron node's metadata.
minetest.register_lbm({
name = "digtron:generic_formspec_sanitizer",
nodenames = {"group:digtron"},
action = function(pos, node)
local node_def = minetest.registered_nodes[node.name]
if node_def._digtron_formspec then
local meta = minetest.get_meta(pos)
meta:set_string("formspec", node_def._digtron_formspec(pos, meta))
end
end
})
minetest.register_lbm({
name = "digtron:sand_digger_upgrade",
nodenames = {"digtron:sand_digger"},
action = function(pos, node)
local meta = minetest.get_meta(pos)
local offset = meta:get_string("offset")
local period = meta:get_string("period")
minetest.set_node(pos, {name = "digtron:soft_digger",
param2 = node.param2})
meta:set_string("offset", offset)
meta:set_string("period", period)
end
})
minetest.register_lbm({
name = "digtron:fuelstore_upgrade",
nodenames = {"digtron:fuelstore"},
action = function(pos, node)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local list = inv:get_list("main")
inv:set_list("main", {})
inv:set_list("fuel", list)
end
})
minetest.register_lbm({
name = "digtron:autocontroller_lateral_upgrade",
nodenames = {"digtron:auto_controller"},
action = function(pos, node)
local meta = minetest.get_meta(pos)
local cycles = meta:get_int("offset")
meta:set_int("cycles", cycles)
meta:set_int("offset", 0)
meta:set_int("slope", 0)
end
})
minetest.register_lbm({
name = "digtron:builder_extrusion_upgrade",
nodenames = {"digtron:builder"},
action = function(pos, node)
local meta = minetest.get_meta(pos)
meta:set_int("extrusion", 1)
end
})

435
util.lua

@ -1,435 +0,0 @@
-- A random assortment of methods used in various places in this mod.
dofile( minetest.get_modpath( "digtron" ) .. "/util_item_place_node.lua" ) -- separated out to avoid potential for license complexity
dofile( minetest.get_modpath( "digtron" ) .. "/util_execute_cycle.lua" ) -- separated out simply for tidiness, there's some big code in there
local node_inventory_table = {type="node"} -- a reusable parameter for get_inventory calls, set the pos parameter before using.
-- Apparently node_sound_metal_defaults is a newer thing, I ran into games using an older version of the default mod without it.
if default.node_sound_metal_defaults ~= nil then
digtron.metal_sounds = default.node_sound_metal_defaults()
else
digtron.metal_sounds = default.node_sound_stone_defaults()
end
digtron.find_new_pos = function(pos, facing)
-- finds the point one node "forward", based on facing
local dir = minetest.facedir_to_dir(facing)
return vector.add(pos, dir)
end
local facedir_to_down_dir_table = {
[0]={x=0, y=-1, z=0},
{x=0, y=0, z=-1},
{x=0, y=0, z=1},
{x=-1, y=0, z=0},
{x=1, y=0, z=0},
{x=0, y=1, z=0}
}
digtron.facedir_to_down_dir = function(facing)
return facedir_to_down_dir_table[math.floor(facing/4)]
end
digtron.find_new_pos_downward = function(pos, facing)
return vector.add(pos, digtron.facedir_to_down_dir(facing))
end
digtron.mark_diggable = function(pos, nodes_dug, player)
-- mark the node as dug, if the player provided would have been able to dig it.
-- Don't *actually* dig the node yet, though, because if we dig a node with sand over it the sand will start falling
-- and then destroy whatever node we place there subsequently (either by a builder head or by moving a digtron node)
-- I don't like sand. It's coarse and rough and irritating and it gets everywhere. And it necessitates complicated dig routines.
-- returns fuel cost and what will be dropped by digging these nodes.
local target = minetest.get_node(pos)
-- prevent digtrons from being marked for digging.
if minetest.get_item_group(target.name, "digtron") ~= 0 or
minetest.get_item_group(target.name, "digtron_protected") ~= 0 or
minetest.get_item_group(target.name, "immortal") ~= 0 then
return 0
end
local targetdef = minetest.registered_nodes[target.name]
if targetdef == nil or targetdef.can_dig == nil or targetdef.can_dig(pos, player) then
nodes_dug:set(pos.x, pos.y, pos.z, true)
if target.name ~= "air" then
local in_known_group = false
local material_cost = 0
if digtron.config.uses_resources then
if minetest.get_item_group(target.name, "cracky") ~= 0 then
in_known_group = true
material_cost = math.max(material_cost, digtron.config.dig_cost_cracky)
end
if minetest.get_item_group(target.name, "crumbly") ~= 0 then
in_known_group = true
material_cost = math.max(material_cost, digtron.config.dig_cost_crumbly)
end
if minetest.get_item_group(target.name, "choppy") ~= 0 then
in_known_group = true
material_cost = math.max(material_cost, digtron.config.dig_cost_choppy)
end
if not in_known_group then
material_cost = digtron.config.dig_cost_default
end
end
return material_cost, minetest.get_node_drops(target.name, "")
end
end
return 0
end
digtron.can_build_to = function(pos, protected_nodes, dug_nodes)
-- Returns whether a space is clear to have something put into it
if protected_nodes:get(pos.x, pos.y, pos.z) then
return false
end
-- tests if the location pointed to is clear to move something into
local target = minetest.get_node(pos)
if target.name == "air" or
dug_nodes:get(pos.x, pos.y, pos.z) == true or
minetest.registered_nodes[target.name].buildable_to == true
then
return true
end
return false
end
digtron.can_move_to = function(pos, protected_nodes, dug_nodes)
-- Same as can_build_to, but also checks if the current node is part of the digtron.
-- this allows us to disregard obstructions that *will* move out of the way.
if digtron.can_build_to(pos, protected_nodes, dug_nodes) == true or
minetest.get_item_group(minetest.get_node(pos).name, "digtron") ~= 0 then
return true
end
return false
end
digtron.place_in_inventory = function(itemname, inventory_positions, fallback_pos)
--tries placing the item in each inventory node in turn. If there's no room, drop it at fallback_pos
local itemstack = ItemStack(itemname)
if inventory_positions ~= nil then
for k, location in pairs(inventory_positions) do
node_inventory_table.pos = location.pos
local inv = minetest.get_inventory(node_inventory_table)
itemstack = inv:add_item("main", itemstack)
if itemstack:is_empty() then
return nil
end
end
end
minetest.add_item(fallback_pos, itemstack)
end
digtron.place_in_specific_inventory = function(itemname, pos, inventory_positions, fallback_pos)
--tries placing the item in a specific inventory. Other parameters are used as fallbacks on failure
--Use this method for putting stuff back after testing and failed builds so that if the player
--is trying to keep various inventories organized manually stuff will go back where it came from,
--probably.
local itemstack = ItemStack(itemname)
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
local returned_stack = inv:add_item("main", itemstack)
if not returned_stack:is_empty() then
-- we weren't able to put the item back into that particular inventory for some reason.
-- try putting it *anywhere.*
digtron.place_in_inventory(returned_stack, inventory_positions, fallback_pos)
end
end
digtron.take_from_inventory = function(itemname, inventory_positions)
if inventory_positions == nil then return nil end
--tries to take an item from each inventory node in turn. Returns location of inventory item was taken from on success, nil on failure
local itemstack = ItemStack(itemname)
for k, location in pairs(inventory_positions) do
node_inventory_table.pos = location.pos
local inv = minetest.get_inventory(node_inventory_table)
local output = inv:remove_item("main", itemstack)
if not output:is_empty() then
return location.pos
end
end
return nil
end
-- Used to determine which coordinate is being checked for periodicity. eg, if the digtron is moving in the z direction, then periodicity is checked for every n nodes in the z axis.
digtron.get_controlling_coordinate = function(pos, facedir)
-- used for determining builder period and offset
local dir = digtron.facedir_to_dir_map[facedir]
if dir == 1 or dir == 3 then
return "z"
elseif dir == 2 or dir == 4 then
return "x"
else
return "y"
end
end
local fuel_craft = {method="fuel", width=1, items={}} -- reusable crafting recipe table for get_craft_result calls below
-- Searches fuel store inventories for burnable items and burns them until target is reached or surpassed
-- (or there's nothing left to burn). Returns the total fuel value burned
-- if the "test" parameter is set to true, doesn't actually take anything out of inventories.
-- We can get away with this sort of thing for fuel but not for builder inventory because there's just one
-- controller node burning stuff, not multiple build heads drawing from inventories in turn. Much simpler.
digtron.burn = function(fuelstore_positions, target, test)
if fuelstore_positions == nil then
return 0
end
local current_burned = 0
for k, location in pairs(fuelstore_positions) do
if current_burned > target then
break
end
node_inventory_table.pos = location.pos
local inv = minetest.get_inventory(node_inventory_table)
local invlist = inv:get_list("fuel")
if invlist == nil then -- This check shouldn't be needed, it's yet another guard against https://github.com/minetest/minetest/issues/8067
break
end
for i, itemstack in pairs(invlist) do
fuel_craft.items[1] = itemstack:peek_item(1)
local fuel_per_item = minetest.get_craft_result(fuel_craft).time
if fuel_per_item ~= 0 then
local actual_burned = math.min(
math.ceil((target - current_burned)/fuel_per_item), -- burn this many, if we can.
itemstack:get_count() -- how many we have at most.
)
if test ~= true then
-- don't bother recording the items if we're just testing, nothing is actually being removed.
itemstack:set_count(itemstack:get_count() - actual_burned)
end
current_burned = current_burned + actual_burned * fuel_per_item
end
if current_burned > target then
break
end
end
if test ~= true then
-- only update the list if we're doing this for real.
inv:set_list("fuel", invlist)
end
end
return current_burned
end
-- Consume energy from the batteries
-- The same as burning coal, except that instead of destroying the items in the inventory, we merely drain
-- the charge in them, leaving them empty. The charge is converted into "coal heat units" by a downscaling
-- factor, since if taken at face value (10000 EU), the batteries would be the ultimate power source barely
-- ever needing replacement.
digtron.tap_batteries = function(battery_positions, target, test)
if (battery_positions == nil) then
return 0
end
local current_burned = 0
-- 1 coal block is 370 PU
-- 1 coal lump is 40 PU
-- An RE battery holds 10000 EU of charge
-- local power_ratio = 100 -- How much charge equals 1 unit of PU from coal
-- setting Moved to digtron.config.power_ratio
for k, location in pairs(battery_positions) do
if current_burned > target then
break
end
node_inventory_table.pos = location.pos
local inv = minetest.get_inventory(node_inventory_table)
local invlist = inv:get_list("batteries")
if (invlist == nil) then -- This check shouldn't be needed, it's yet another guard against https://github.com/minetest/minetest/issues/8067
break
end
for i, itemstack in pairs(invlist) do
local meta = minetest.deserialize(itemstack:get_metadata())
if (meta ~= nil) then
local power_available = math.floor(meta.charge / digtron.config.power_ratio)
if power_available ~= 0 then
local actual_burned = power_available -- we just take all we have from the battery, since they aren't stackable
if test ~= true then
-- don't bother recording the items if we're just testing, nothing is actually being removed.
local charge_left = meta.charge - power_available * digtron.config.power_ratio
local properties = itemstack:get_tool_capabilities()
-- itemstack = technic.set_RE_wear(itemstack, charge_left, properties.groupcaps.fleshy.uses)
-- we only need half the function, so why bother using it in the first place
-- Charge is stored separately, but shown as wear level
-- This calls for recalculating the value.
local charge_level
if charge_left == 0 then
charge_level = 0
else
charge_level = 65536 - math.floor(charge_left / properties.groupcaps.fleshy.uses * 65535)
if charge_level > 65535 then charge_level = 65535 end
if charge_level < 1 then charge_level = 1 end
end
itemstack:set_wear(charge_level)
meta.charge = charge_left
itemstack:set_metadata(minetest.serialize(meta))
end
current_burned = current_burned + actual_burned
end
end
if current_burned > target then
break
end
end
if test ~= true then
-- only update the list if we're doing this for real.
inv:set_list("batteries", invlist)
end
end
return current_burned
end
digtron.remove_builder_item = function(pos)
local objects = minetest.env:get_objects_inside_radius(pos, 0.5)
if objects ~= nil then
for _, obj in ipairs(objects) do
if obj and obj:get_luaentity() and obj:get_luaentity().name == "digtron:builder_item" then
obj:remove()
end
end
end
end
digtron.update_builder_item = function(pos)
digtron.remove_builder_item(pos)
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
local item_stack = inv:get_stack("main", 1)
if not item_stack:is_empty() then
digtron.create_builder_item = item_stack:get_name()
minetest.add_entity(pos,"digtron:builder_item")
end
end
local damage_def = {
full_punch_interval = 1.0,
damage_groups = {},
}
digtron.damage_creatures = function(player, source_pos, target_pos, amount, items_dropped)
local objects = minetest.env:get_objects_inside_radius(target_pos, 1.0)
if objects ~= nil then
damage_def.damage_groups.fleshy = amount
local velocity = {
x = target_pos.x-source_pos.x,
y = target_pos.y-source_pos.y + 0.2,
z = target_pos.z-source_pos.z,
}
for _, obj in ipairs(objects) do
if obj:is_player() then
-- See issue #2960 for status of a "set player velocity" method
-- instead, knock the player back
local newpos = {
x = target_pos.x + velocity.x,
y = target_pos.y + velocity.y,
z = target_pos.z + velocity.z,
}
obj:set_pos(newpos)
obj:punch(player, 1.0, damage_def, nil)
else
local lua_entity = obj:get_luaentity()
if lua_entity ~= nil then
if lua_entity.name == "__builtin:item" then
table.insert(items_dropped, lua_entity.itemstring)
lua_entity.itemstring = ""
obj:remove()
else
if obj.add_velocity ~= nil then
obj:add_velocity(velocity)
else
local vel = obj:get_velocity()
obj:set_velocity(vector.add(vel, velocity))
end
obj:punch(player, 1.0, damage_def, nil)
end
end
end
end
end
-- If we killed any mobs they might have dropped some stuff, vacuum that up now too.
objects = minetest.env:get_objects_inside_radius(target_pos, 1.0)
if objects ~= nil then
for _, obj in ipairs(objects) do
if not obj:is_player() then
local lua_entity = obj:get_luaentity()
if lua_entity ~= nil and lua_entity.name == "__builtin:item" then
table.insert(items_dropped, lua_entity.itemstring)
lua_entity.itemstring = ""
obj:remove()
end
end
end
end
end
digtron.is_soft_material = function(target)
local target_node = minetest.get_node(target)
if minetest.get_item_group(target_node.name, "crumbly") ~= 0 or
minetest.get_item_group(target_node.name, "choppy") ~= 0 or
minetest.get_item_group(target_node.name, "snappy") ~= 0 or
minetest.get_item_group(target_node.name, "oddly_breakable_by_hand") ~= 0 or
minetest.get_item_group(target_node.name, "fleshy") ~= 0 then
return true
end
return false
end
-- If someone sets very large offsets or intervals for the offset markers they might be added too far
-- away. safe_add_entity causes these attempts to be ignored rather than crashing the game.
-- returns the entity if successful, nil otherwise
function safe_add_entity(pos, name)
success, ret = pcall(minetest.add_entity, pos, name)
if success then return ret else return nil end
end
digtron.show_offset_markers = function(pos, offset, period)
local buildpos = digtron.find_new_pos(pos, minetest.get_node(pos).param2)
local x_pos = math.floor((buildpos.x+offset)/period)*period - offset
safe_add_entity({x=x_pos, y=buildpos.y, z=buildpos.z}, "digtron:marker")
if x_pos >= buildpos.x then
safe_add_entity({x=x_pos - period, y=buildpos.y, z=buildpos.z}, "digtron:marker")
end
if x_pos <= buildpos.x then
safe_add_entity({x=x_pos + period, y=buildpos.y, z=buildpos.z}, "digtron:marker")
end
local y_pos = math.floor((buildpos.y+offset)/period)*period - offset
safe_add_entity({x=buildpos.x, y=y_pos, z=buildpos.z}, "digtron:marker_vertical")
if y_pos >= buildpos.y then
safe_add_entity({x=buildpos.x, y=y_pos - period, z=buildpos.z}, "digtron:marker_vertical")
end
if y_pos <= buildpos.y then
safe_add_entity({x=buildpos.x, y=y_pos + period, z=buildpos.z}, "digtron:marker_vertical")
end
local z_pos = math.floor((buildpos.z+offset)/period)*period - offset
local entity = safe_add_entity({x=buildpos.x, y=buildpos.y, z=z_pos}, "digtron:marker")
if entity ~= nil then entity:setyaw(1.5708) end
if z_pos >= buildpos.z then
local entity = safe_add_entity({x=buildpos.x, y=buildpos.y, z=z_pos - period}, "digtron:marker")
if entity ~= nil then entity:setyaw(1.5708) end
end
if z_pos <= buildpos.z then
local entity = safe_add_entity({x=buildpos.x, y=buildpos.y, z=z_pos + period}, "digtron:marker")
if entity ~= nil then entity:setyaw(1.5708) end
end
end

@ -1,617 +0,0 @@
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local dig_dust = function(pos, facing)
local direction = minetest.facedir_to_dir(facing)
return {
amount = 10,
time = 1.0,
minpos = vector.subtract(pos, vector.new(0.5,0.5,0.5)),
maxpos = vector.add(pos, vector.new(0.5,0.5,0.5)),
minvel = vector.multiply(direction, -10),
maxvel = vector.multiply(direction, -20),
minacc = {x=0, y=-40, z=0},
maxacc = {x=0, y=-40, z=0},
minexptime = 0.25,
maxexptime = 0.5,
minsize = 2,
maxsize = 5,
collisiondetection = false,
vertical = false,
texture = "default_item_smoke.png^[colorize:#9F817080",
}
end
local burn_smoke = function(pos, amount)
return {
amount = math.min(amount, 40),
time = 1.0,
minpos = vector.subtract(pos, vector.new(0.5,0.5,0.5)),
maxpos = vector.add(pos, vector.new(0.5,0.5,0.5)),
minvel = {x=0, y=2, z=0},
maxvel = {x=0, y=5, z=0},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 0.5,
maxexptime = 1.5,
minsize = 8,
maxsize = 12,
collisiondetection = false,
vertical = false,
texture = "default_item_smoke.png^[colorize:#000000DD",
}
end
--Performs various tests on a layout to play warning noises and see if Digtron can move at all.
local function neighbour_test(layout, status_text, dir)
if layout.ignore_touching == true then
-- if the digtron array touches unloaded nodes, too dangerous to do anything in that situation. Abort.
minetest.sound_play("buzzer", {gain=0.25, pos=layout.controller})
return S("Digtron is adjacent to unloaded nodes.") .. "\n" .. status_text, 1
end
if layout.water_touching == true then
minetest.sound_play("sploosh", {gain=1.0, pos=layout.controller})
end
if layout.lava_touching == true then
minetest.sound_play("woopwoopwoop", {gain=1.0, pos=layout.controller})
end
if dir and dir.y ~= -1 and layout.traction * digtron.config.traction_factor < table.getn(layout.all) then
-- digtrons can't fly, though they can fall
minetest.sound_play("squeal", {gain=1.0, pos=layout.controller})
return S("Digtron has @1 blocks but only enough traction to move @2 blocks.\n", table.getn(layout.all), layout.traction * digtron.config.traction_factor)
.. status_text, 2
end
return status_text, 0
end
-- Checks if a player is within a layout's extents.
local function move_player_test(layout, player)
local player_pos = player:getpos()
if player_pos.x >= layout.extents_min_x - 1 and player_pos.x <= layout.extents_max_x + 1 and
player_pos.y >= layout.extents_min_y - 1 and player_pos.y <= layout.extents_max_y + 1 and
player_pos.z >= layout.extents_min_z - 1 and player_pos.z <= layout.extents_max_z + 1 then
return true
end
return false
end
local node_inventory_table = {type="node"} -- a reusable parameter for get_inventory calls, set the pos parameter before using.
local function test_stop_block(pos, items)
node_inventory_table.pos = pos
local inv = minetest.get_inventory(node_inventory_table)
local item_stack = inv:get_stack("stop", 1)
if not item_stack:is_empty() then
for _, item in pairs(items) do
if item == item_stack:get_name() then
return true
end
end
end
return false
end
local function check_digtron_size(layout)
if #layout.all > digtron.config.size_limit then
return S("Size limit of @1 reached with @2 nodes!", digtron.config.size_limit, #layout.all)
end
end
-- returns newpos, status string, and a return code indicating why the method returned (so the auto-controller can keep trying if it's due to unloaded nodes)
-- 0 - success
-- 1 - failed due to unloaded nodes
-- 2 - failed due to insufficient traction
-- 3 - obstructed by undiggable node
-- 4 - insufficient fuel
-- 5 - unknown builder error during testing
-- 6 - builder with unset output
-- 7 - insufficient builder materials in inventory
-- 8 - size/node limit reached
digtron.execute_dig_cycle = function(pos, clicker)
local meta = minetest.get_meta(pos)
local facing = minetest.get_node(pos).param2
local dir = minetest.facedir_to_dir(facing)
local fuel_burning = meta:get_float("fuel_burning") -- get amount of burned fuel left over from last cycle
local status_text = S("Heat remaining in controller furnace: @1", math.floor(math.max(0, fuel_burning)))
local exhaust = meta:get_int("on_coal")
local layout = DigtronLayout.create(pos, clicker)
local status_text, return_code = neighbour_test(layout, status_text, dir)
if return_code ~= 0 then
return pos, status_text, return_code
end
local size_check_error = check_digtron_size(layout)
if size_check_error then
return pos, size_check_error, 8
end
local controlling_coordinate = digtron.get_controlling_coordinate(pos, facing)
----------------------------------------------------------------------------------------------------------------------
local items_dropped = {}
local digging_fuel_cost = 0
local particle_systems = {}
-- execute the execute_dig method on all digtron components that have one
-- This builds a set of nodes that will be dug and returns a list of products that will be generated
-- but doesn't actually dig the nodes yet. That comes later.
-- If we dug them now, sand would fall and some digtron nodes would die.
if layout.diggers ~= nil then
for k, location in pairs(layout.diggers) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.execute_dig ~= nil then
local fuel_cost, dropped = targetdef.execute_dig(location.pos, layout.protected, layout.nodes_dug, controlling_coordinate, false, clicker)
if dropped ~= nil then
for _, itemname in pairs(dropped) do
table.insert(items_dropped, itemname)
end
if digtron.config.particle_effects then
table.insert(particle_systems, dig_dust(vector.add(location.pos, dir), target.param2))
end
end
digging_fuel_cost = digging_fuel_cost + fuel_cost
else
minetest.log(string.format("%s has digger group but is missing execute_dig method! This is an error in mod programming, file a bug.", targetdef.name))
end
end
end
----------------------------------------------------------------------------------------------------------------------
-- test if any digtrons are obstructed by non-digtron nodes that haven't been marked
-- as having been dug.
local can_move = true
for _, location in pairs(layout.all) do
local newpos = vector.add(location.pos, dir)
if not digtron.can_move_to(newpos, layout.protected, layout.nodes_dug) then
can_move = false
end
end
if test_stop_block(pos, items_dropped) then
can_move = false
end
if not can_move then
-- mark this node as waiting, will clear this flag in digtron.config.cycle_time seconds
minetest.get_meta(pos):set_string("waiting", "true")
minetest.get_node_timer(pos):start(digtron.config.cycle_time)
minetest.sound_play("squeal", {gain=1.0, pos=pos})
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, S("Digtron is obstructed.") .. "\n" .. status_text, 3 --Abort, don't dig and don't build.
end
----------------------------------------------------------------------------------------------------------------------
-- ask each builder node if it can get what it needs from inventory to build this cycle.
-- This is a complicated test because each builder needs to actually *take* the item it'll
-- need from inventory, and then we put it all back afterward.
-- Note that this test may overestimate the amount of work that will actually need to be done so don't treat its fuel cost as authoritative.
local can_build = true
local test_build_return_code = nil
local test_build_return_items = nil
local failed_to_find = nil
local test_items = {}
local test_fuel_items = {}
local test_build_fuel_cost = 0
if layout.builders ~= nil then
for k, location in pairs(layout.builders) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
local test_location = vector.add(location.pos, dir)
if targetdef.test_build ~= nil then
test_build_return_code, test_build_return_items, failed_to_find = targetdef.test_build(location.pos, test_location, layout.inventories, layout.protected, layout.nodes_dug, controlling_coordinate, layout.controller)
for k, return_item in pairs(test_build_return_items) do
table.insert(test_items, return_item)
test_build_fuel_cost = test_build_fuel_cost + digtron.config.build_cost
end
if test_build_return_code > 1 then
can_build = false
break
end
else
minetest.log(string.format("%s has builder group but is missing test_build method! This is an error in mod programming, file a bug.", targetdef.name))
end
end
end
local test_fuel_needed = test_build_fuel_cost + digging_fuel_cost - fuel_burning
local test_fuel_burned = 0
local power_from_cables = 0
if minetest.get_modpath("technic") then
if layout.power_connectors ~= nil then
local power_inputs = {}
for _, power_connector in pairs(layout.power_connectors) do
if power_connector.meta.fields.HV_network and power_connector.meta.fields.HV_EU_input then
power_inputs[power_connector.meta.fields.HV_network] = tonumber(power_connector.meta.fields.HV_EU_input)
end
end
for _, power in pairs(power_inputs) do
power_from_cables = power_from_cables + power
end
power_from_cables = power_from_cables / digtron.config.power_ratio
test_fuel_burned = power_from_cables
end
if test_fuel_needed - test_fuel_burned > 0 then
-- check for the available electrical power
test_fuel_burned = test_fuel_burned + digtron.tap_batteries(layout.battery_holders, test_fuel_needed, true)
end
end
if (test_fuel_needed < test_fuel_burned) then
exhaust = 0 -- all power needs met by electricity, don't blow smoke
else
-- burn combustible fuel if not enough power
test_fuel_burned = test_fuel_burned + digtron.burn(layout.fuelstores, test_fuel_needed - test_fuel_burned, true)
exhaust = 1 -- burning fuel produces smoke
end
--Put everything back where it came from
for k, item_return in pairs(test_items) do
digtron.place_in_specific_inventory(item_return.item, item_return.location, layout.inventories, layout.controller)
end
if test_fuel_needed > fuel_burning + test_fuel_burned then
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, S("Digtron needs more fuel."), 4 -- abort, don't dig and don't build.
end
if not can_build then
minetest.get_meta(pos):set_string("waiting", "true")
minetest.get_node_timer(pos):start(digtron.config.cycle_time)
local return_string = nil
local return_code = 5
if test_build_return_code == 3 then
minetest.sound_play("honk", {gain=0.5, pos=pos}) -- A builder is not configured
return_string = S("Digtron connected to at least one builder with no output material assigned.") .. "\n"
return_code = 6
elseif test_build_return_code == 2 then
minetest.sound_play("dingding", {gain=1.0, pos=pos}) -- Insufficient inventory
return_string = S("Digtron has insufficient building materials. Needed: @1", failed_to_find:get_name()) .. "\n"
return_code = 7
end
return pos, return_string .. status_text, return_code --Abort, don't dig and don't build.
end
----------------------------------------------------------------------------------------------------------------------
-- All tests passed, ready to go for real!
minetest.sound_play("construction", {gain=1.0, pos=pos})
-- if the player is standing within the array or next to it, move him too.
local move_player = move_player_test(layout, clicker)
-- damage the weak flesh
if digtron.config.damage_hp > 0 and layout.diggers ~= nil then
for k, location in pairs(layout.diggers) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.damage_creatures ~= nil then
targetdef.damage_creatures(clicker, location.pos, controlling_coordinate, items_dropped)
end
end
end
--move the array
layout:move_layout_image(dir)
if not layout:write_layout_image(clicker) then
return pos, "unrecoverable write_layout_image error", 1
end
local oldpos = {x=pos.x, y=pos.y, z=pos.z}
pos = vector.add(pos, dir)
meta = minetest.get_meta(pos)
if move_player then
clicker:moveto(vector.add(dir, clicker:getpos()), true)
end
-- store or drop the products of the digger heads
for _, itemname in pairs(items_dropped) do
digtron.place_in_inventory(itemname, layout.inventories, oldpos)
end
digtron.award_item_dug(items_dropped, clicker) -- Achievements mod hook
local building_fuel_cost = 0
local strange_failure = false
-- execute_build on all digtron components that have one
if layout.builders ~= nil then
for k, location in pairs(layout.builders) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.execute_build ~= nil then
--using the old location of the controller as fallback so that any leftovers land with the rest of the digger output. Not that there should be any.
local build_return = targetdef.execute_build(location.pos, clicker, layout.inventories, layout.protected, layout.nodes_dug, controlling_coordinate, oldpos)
if build_return < 0 then
-- This happens if there's insufficient inventory, but we should have confirmed there was sufficient inventory during test phase.
-- So this should never happen. However, "should never happens" happen sometimes. So
-- don't interrupt the build cycle as a whole, we've already moved so might as well try to complete as much as possible.
strange_failure = true
build_return = (build_return * -1) - 1
elseif digtron.config.uses_resources then
building_fuel_cost = building_fuel_cost + (digtron.config.build_cost * build_return)
end
else
minetest.log(string.format("%s has builder group but is missing execute_build method! This is an error in mod programming, file a bug.", targetdef.name))
end
end
end
if layout.auto_ejectors ~= nil then
for k, location in pairs(layout.auto_ejectors) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.execute_eject ~= nil then
targetdef.execute_eject(location.pos, target, clicker, layout)
else
minetest.log(string.format("%s has an ejector group but is missing execute_eject method! This is an error in mod programming, file a bug.", targetdef.name))
end
end
end
local status_text = ""
if strange_failure then
-- We weren't able to detect this build failure ahead of time, so make a big noise now. This is strange, shouldn't happen.
minetest.sound_play("dingding", {gain=1.0, pos=pos})
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
status_text = S("Digtron unexpectedly failed to execute one or more build operations, likely due to an inventory error.") .. "\n"
end
local total_fuel_cost = math.max(digging_fuel_cost + building_fuel_cost - power_from_cables, 0)
-- actually burn the fuel needed
fuel_burning = fuel_burning - total_fuel_cost
if digtron.config.particle_effects and exhaust == 1 then
table.insert(particle_systems, burn_smoke(pos, total_fuel_cost))
end
if fuel_burning < 0 then
-- we tap into the batteries either way
fuel_burning = fuel_burning + digtron.tap_batteries(layout.battery_holders, -fuel_burning, false)
if exhaust == 1 then
-- but we burn coal only if we must (exhaust = flag)
fuel_burning = fuel_burning + digtron.burn(layout.fuelstores, -fuel_burning, false)
end
end
meta:set_float("fuel_burning", fuel_burning)
meta:set_int("on_coal", exhaust)
status_text = status_text .. S("Heat remaining in controller furnace: @1", math.floor(math.max(0, fuel_burning)))
-- Eyecandy
for _, particles in pairs(particle_systems) do
minetest.add_particlespawner(particles)
end
-- finally, dig out any nodes remaining to be dug. Some of these will have had their flag revoked because
-- a builder put something there or because they're another digtron node.
local node_to_dig, whether_to_dig = layout.nodes_dug:pop()
while node_to_dig ~= nil do
if whether_to_dig == true then
minetest.log("action", string.format("%s uses Digtron to dig %s at (%d, %d, %d)", clicker:get_player_name(), minetest.get_node(node_to_dig).name, node_to_dig.x, node_to_dig.y, node_to_dig.z))
minetest.remove_node(node_to_dig)
end
-- all of the digtron's nodes wind up in nodes_dug, so this is an ideal place to stick
-- a check to make sand fall after the digtron has passed.
minetest.check_for_falling({x=node_to_dig.x, y=node_to_dig.y+1, z=node_to_dig.z})
node_to_dig, whether_to_dig = layout.nodes_dug:pop()
end
return pos, status_text, 0
end
-- Simplified version of the above method that only moves, and doesn't execute diggers or builders.
digtron.execute_move_cycle = function(pos, clicker)
local meta = minetest.get_meta(pos)
local layout = DigtronLayout.create(pos, clicker)
local status_text = ""
local status_text, return_code = neighbour_test(layout, status_text, nil) -- skip traction check for pusher by passing nil for direction
if return_code ~= 0 then
return pos, status_text, return_code
end
local size_check_error = check_digtron_size(layout)
if size_check_error then
return pos, size_check_error, 8
end
local facing = minetest.get_node(pos).param2
local dir = minetest.facedir_to_dir(facing)
local controlling_coordinate = digtron.get_controlling_coordinate(pos, facing)
-- if the player is standing within the array or next to it, move him too.
local move_player = move_player_test(layout, clicker)
-- test if any digtrons are obstructed by non-digtron nodes
layout:move_layout_image(dir)
if not layout:can_write_layout_image() then
-- mark this node as waiting, will clear this flag in digtron.config.cycle_time seconds
minetest.get_meta(pos):set_string("waiting", "true")
minetest.get_node_timer(pos):start(digtron.config.cycle_time)
minetest.sound_play("squeal", {gain=1.0, pos=pos})
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, S("Digtron is obstructed.") .. "\n" .. status_text, 3 --Abort, don't dig and don't build.
end
minetest.sound_play("truck", {gain=1.0, pos=pos})
--move the array
if not layout:write_layout_image(clicker) then
return pos, "unrecoverable write_layout_image error", 1
end
pos = vector.add(pos, dir)
if move_player then
clicker:moveto(vector.add(clicker:getpos(), dir), true)
end
return pos, "", 0
end
-- Simplified version of the dig cycle that moves laterally relative to the controller's orientation ("downward")
-- Does the dig portion of the cycle, but skips the build portion.
-- returns newpos, status string, and a return code indicating why the method returned (so the auto-controller can keep trying if it's due to unloaded nodes)
-- 0 - success
-- 1 - failed due to unloaded nodes
-- 2 - failed due to insufficient traction
-- 3 - obstructed by undiggable node
-- 4 - insufficient fuel
digtron.execute_downward_dig_cycle = function(pos, clicker)
local meta = minetest.get_meta(pos)
local facing = minetest.get_node(pos).param2
local dir = digtron.facedir_to_down_dir(facing)
local fuel_burning = meta:get_float("fuel_burning") -- get amount of burned fuel left over from last cycle
local status_text = S("Heat remaining in controller furnace: @1", math.floor(math.max(0, fuel_burning)))
local exhaust = meta:get_int("on_coal")
local layout = DigtronLayout.create(pos, clicker)
local status_text, return_code = neighbour_test(layout, status_text, dir)
if return_code ~= 0 then
return pos, status_text, return_code
end
local size_check_error = check_digtron_size(layout)
if size_check_error then
return pos, size_check_error, 8
end
local controlling_coordinate = digtron.get_controlling_coordinate(pos, facing)
----------------------------------------------------------------------------------------------------------------------
local items_dropped = {}
local digging_fuel_cost = 0
local particle_systems = {}
-- execute the execute_dig method on all digtron components that have one
-- This builds a set of nodes that will be dug and returns a list of products that will be generated
-- but doesn't actually dig the nodes yet. That comes later.
-- If we dug them now, sand would fall and some digtron nodes would die.
if layout.diggers ~= nil then
for k, location in pairs(layout.diggers) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.execute_dig ~= nil then
local fuel_cost, dropped = targetdef.execute_dig(location.pos, layout.protected, layout.nodes_dug, controlling_coordinate, true, clicker)
if dropped ~= nil then
for _, itemname in pairs(dropped) do
table.insert(items_dropped, itemname)
end
if digtron.config.particle_effects then
table.insert(particle_systems, dig_dust(vector.add(location.pos, dir), target.param2))
end
end
digging_fuel_cost = digging_fuel_cost + fuel_cost
else
minetest.log(string.format("%s has digger group but is missing execute_dig method! This is an error in mod programming, file a bug.", targetdef.name))
end
end
end
----------------------------------------------------------------------------------------------------------------------
-- test if any digtrons are obstructed by non-digtron nodes that haven't been marked
-- as having been dug.
local can_move = true
for _, location in pairs(layout.all) do
local newpos = vector.add(location.pos, dir)
if not digtron.can_move_to(newpos, layout.protected, layout.nodes_dug) then
can_move = false
end
end
if test_stop_block(pos, items_dropped) then
can_move = false
end
if not can_move then
-- mark this node as waiting, will clear this flag in digtron.config.cycle_time seconds
minetest.get_meta(pos):set_string("waiting", "true")
minetest.get_node_timer(pos):start(digtron.config.cycle_time)
minetest.sound_play("squeal", {gain=1.0, pos=pos})
minetest.sound_play("buzzer", {gain=0.5, pos=pos})
return pos, S("Digtron is obstructed.") .. "\n" .. status_text, 3 --Abort, don't dig and don't build.
end
----------------------------------------------------------------------------------------------------------------------
-- All tests passed, ready to go for real!
minetest.sound_play("construction", {gain=1.0, pos=pos})
-- if the player is standing within the array or next to it, move him too.
local move_player = move_player_test(layout, clicker)
-- damage the weak flesh
if digtron.config.damage_hp > 0 and layout.diggers ~= nil then
for k, location in pairs(layout.diggers) do
local target = minetest.get_node(location.pos)
local targetdef = minetest.registered_nodes[target.name]
if targetdef.damage_creatures ~= nil then
targetdef.damage_creatures(clicker, location.pos, controlling_coordinate, items_dropped)
end
end
end
--move the array
layout:move_layout_image(digtron.facedir_to_down_dir(facing))
if not layout:write_layout_image(clicker) then
return pos, "unrecoverable write_layout_image error", 1
end
local oldpos = {x=pos.x, y=pos.y, z=pos.z}
pos = vector.add(pos, dir)
meta = minetest.get_meta(pos)
if move_player then
clicker:moveto(vector.add(clicker:getpos(), dir), true)
end
-- store or drop the products of the digger heads
for _, itemname in pairs(items_dropped) do
digtron.place_in_inventory(itemname, layout.inventories, oldpos)
end
digtron.award_item_dug(items_dropped, clicker) -- Achievements mod hook
local status_text = ""
-- actually burn the fuel needed
fuel_burning = fuel_burning - digging_fuel_cost
if digtron.config.particle_effects and exhaust == 1 then
table.insert(particle_systems, burn_smoke(pos, digging_fuel_cost))
end
if fuel_burning < 0 then
-- we tap into the batteries either way
fuel_burning = fuel_burning + digtron.tap_batteries(layout.battery_holders, -fuel_burning, false)
if exhaust == 1 then
-- but we burn coal only if we must (exhaust = flag)
fuel_burning = fuel_burning + digtron.burn(layout.fuelstores, -fuel_burning, false)
end
end
meta:set_float("fuel_burning", fuel_burning)
meta:set_int("on_coal", exhaust)
status_text = status_text .. S("Heat remaining in controller furnace: @1", math.floor(math.max(0, fuel_burning)))
-- Eyecandy
for _, particles in pairs(particle_systems) do
minetest.add_particlespawner(particles)
end
-- finally, dig out any nodes remaining to be dug. Some of these will have had their flag revoked because
-- a builder put something there or because they're another digtron node.
local node_to_dig, whether_to_dig = layout.nodes_dug:pop()
while node_to_dig ~= nil do
if whether_to_dig == true then
minetest.log("action", string.format("%s uses Digtron to dig %s at (%d, %d, %d)", clicker:get_player_name(), minetest.get_node(node_to_dig).name, node_to_dig.x, node_to_dig.y, node_to_dig.z))
minetest.remove_node(node_to_dig)
end
node_to_dig, whether_to_dig = layout.nodes_dug:pop()
end
return pos, status_text, 0
end

@ -1,181 +0,0 @@
-- The default minetest.item_place_node from item.lua was hard to work with given some of the details
-- of how it handled pointed_thing. It also didn't work right with default:torch and seeds. It was simpler to
-- just copy it here and chop out the special cases that were causing problems, and add some special handling.
-- for nodes that define on_place
-- This specific file is therefore licensed under the LGPL 2.1
--GNU Lesser General Public License, version 2.1
--Copyright (C) 2011-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
--Copyright (C) 2011-2016 Various Minetest developers and contributors
--This program is free software; you can redistribute it and/or modify it under the terms
--of the GNU Lesser General Public License as published by the Free Software Foundation;
--either version 2.1 of the License, or (at your option) any later version.
--This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
--without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--See the GNU Lesser General Public License for more details:
--https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
-- Mapping from facedir value to index in facedir_to_dir.
digtron.facedir_to_dir_map = {
[0]=1, 2, 3, 4,
5, 2, 6, 4,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2,
}
local function has_prefix(str, prefix)
return str:sub(1, string.len(prefix)) == prefix
end
digtron.whitelisted_on_place = function (item_name)
for listed_item, value in pairs(digtron.builder_on_place_items) do
if item_name == listed_item then return value end
end
for prefix, value in pairs(digtron.builder_on_place_prefixes) do
if has_prefix(item_name, prefix) then return value end
end
if minetest.get_item_group(item_name, "digtron_on_place") > 0 then return true end
return false
end
local function copy_pointed_thing(pointed_thing)
return {
type = pointed_thing.type,
above = vector.new(pointed_thing.above),
under = vector.new(pointed_thing.under),
}
end
local function check_attached_node(p, n)
local def = minetest.registered_nodes[n.name]
local d = {x = 0, y = 0, z = 0}
if def.paramtype2 == "wallmounted" then
-- The fallback vector here is in case 'wallmounted to dir' is nil due
-- to voxelmanip placing a wallmounted node without resetting a
-- pre-existing param2 value that is out-of-range for wallmounted.
-- The fallback vector corresponds to param2 = 0.
d = minetest.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
else
d.y = -1
end
local p2 = vector.add(p, d)
local nn = minetest.get_node(p2).name
local def2 = minetest.registered_nodes[nn]
if def2 and not def2.walkable then
return false
end
return true
end
digtron.item_place_node = function(itemstack, placer, place_to, param2)
local item_name = itemstack:get_name()
local def = itemstack:get_definition()
if (not def) or (param2 < 0) or (def.paramtype2 == "wallmounted" and param2 > 5) or (param2 > 23) then -- validate parameters
return itemstack, false
end
local pointed_thing = {}
pointed_thing.type = "node"
pointed_thing.above = {x=place_to.x, y=place_to.y, z=place_to.z}
pointed_thing.under = {x=place_to.x, y=place_to.y - 1, z=place_to.z}
-- Handle node-specific on_place calls as best we can.
if def.on_place and def.on_place ~= minetest.nodedef_default.on_place and digtron.whitelisted_on_place(item_name) then
if def.paramtype2 == "facedir" then
pointed_thing.under = vector.add(place_to, minetest.facedir_to_dir(param2))
elseif def.paramtype2 == "wallmounted" then
pointed_thing.under = vector.add(place_to, minetest.wallmounted_to_dir(param2))
end
-- pass a copy of the item stack parameter because on_place might modify it directly and then we can't tell if we succeeded or not
-- though note that some mods do "creative_mode" handling within their own on_place methods, which makes it impossible for Digtron
-- to know what to do in that case - if you're in creative_mode Digtron will place such items but it will think it failed and not
-- deduct them from inventory no matter what Digtron's settings are. Unfortunate, but not very harmful and I have no workaround.
local returnstack, success = def.on_place(ItemStack(itemstack), placer, pointed_thing)
if returnstack and returnstack:get_count() < itemstack:get_count() then success = true end -- some mods neglect to return a success condition
if success then
-- Override the param2 value to force it to be what Digtron wants
local placed_node = minetest.get_node(place_to)
placed_node.param2 = param2
minetest.set_node(place_to, placed_node)
end
return returnstack, success
end
if minetest.registered_nodes[item_name] == nil then
-- Permitted craft items are handled by the node-specific on_place call, above.
-- if we are a craft item and we get here then we're not whitelisted and we should fail.
-- Note that builder settings should be filtering out craft items like this before we get here,
-- but this will protect us just in case.
return itemstack, false
end
local oldnode = minetest.get_node_or_nil(place_to)
--this should never happen, digtron is testing for adjacent unloaded nodes before getting here.
if not oldnode then
minetest.log("info", placer:get_player_name() .. " tried to place"
.. " node in unloaded position " .. minetest.pos_to_string(place_to)
.. " using a digtron.")
return itemstack, false
end
local newnode = {name = def.name, param1 = 0, param2 = param2}
if def.place_param2 ~= nil then
newnode.param2 = def.place_param2
end
-- Check if the node is attached and if it can be placed there
if minetest.get_item_group(def.name, "attached_node") ~= 0 and
not check_attached_node(place_to, newnode) then
minetest.log("action", "attached node " .. def.name ..
" can not be placed at " .. minetest.pos_to_string(place_to))
return itemstack, false
end
-- Add node and update
minetest.add_node(place_to, newnode)
local take_item = true
-- Run callback, using genuine player for per-node definition.
if def.after_place_node then
-- Deepcopy place_to and pointed_thing because callback can modify it
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
if def.after_place_node(place_to_copy, placer, itemstack,
pointed_thing_copy) then
take_item = false
end
end
-- Run script hook, using fake_player to take the blame.
-- Note that fake_player:update is called in the DigtronLayout class's "create" function,
-- which is called before Digtron does any of this building stuff, so it's not necessary
-- to update it here.
local _, callback
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
if callback(place_to_copy, newnode_copy, digtron.fake_player, oldnode_copy, itemstack, pointed_thing_copy) then
take_item = false
end
end
if take_item then
itemstack:take_item()
end
return itemstack, true
end