diff --git a/controller.lua b/controller.lua index 18c3c90..ef8282e 100644 --- a/controller.lua +++ b/controller.lua @@ -173,7 +173,13 @@ minetest.register_node("digtron:controller", { end, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local returnstack, success = digtron.on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if returnstack then + return returnstack, success + end + if clicker == nil then return end + local meta = minetest.get_meta(pos) local digtron_id = meta:get_string("digtron_id") local player_name = clicker:get_player_name() diff --git a/entities.lua b/entities.lua index ba1e954..26ba9c0 100644 --- a/entities.lua +++ b/entities.lua @@ -160,11 +160,10 @@ 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() + local meta = minetest.get_meta(pos) + local item = meta:get_string("builder_item") + if item ~= "" then + digtron.create_builder_item = item minetest.add_entity(pos,"digtron:builder_item") end end diff --git a/functions.lua b/functions.lua index c0f5a4f..c212ff1 100644 --- a/functions.lua +++ b/functions.lua @@ -394,7 +394,7 @@ digtron.disassemble = function(digtron_id, player_name) local bbox = retrieve_bounding_box(digtron_id) local root_pos = retrieve_pos(digtron_id) if not root_pos then - minetest.log("error", "digtron.disassemble was unable to find a position for " .. digtron_id + minetest.log("error", "[Digtron] digtron.disassemble was unable to find a position for " .. digtron_id .. ", disassembly was impossible. Has the digtron been removed from world?") return end @@ -406,7 +406,7 @@ digtron.disassemble = function(digtron_id, player_name) local inv = digtron.retrieve_inventory(digtron_id) if not (layout and inv) then - minetest.log("error", "digtron.disassemble was unable to find either layout or inventory record for " .. digtron_id + minetest.log("error", "[Digtron] digtron.disassemble was unable to find either layout or inventory record for " .. digtron_id .. ", disassembly was impossible. Clearing any other remaining data for this id.") dispose_id(digtron_id) return @@ -470,7 +470,7 @@ digtron.remove_from_world = function(digtron_id, player_name) local root_pos = retrieve_pos(digtron_id) if not layout then - minetest.log("error", "digtron.remove_from_world Unable to find layout record for " .. digtron_id + minetest.log("error", "[Digtron] digtron.remove_from_world Unable to find layout record for " .. digtron_id .. ", wiping any remaining metadata for this id to prevent corruption. Sorry!") if root_pos then local meta = minetest.get_meta(root_pos) @@ -481,7 +481,7 @@ digtron.remove_from_world = function(digtron_id, player_name) end if not root_pos then - minetest.log("error", "digtron.remove_from_world Unable to find position for " .. digtron_id + minetest.log("error", "[Digtron] digtron.remove_from_world Unable to find position for " .. digtron_id .. ", it may have already been removed from the world.") return {} end @@ -826,6 +826,19 @@ digtron.on_blast = function(pos, intensity) return drops end +-- Use this inside other on_rightclicks for configuring Digtron nodes, this +-- overrides if you're right-clicking with another Digtron node and assumes +-- that you're trying to build it. +digtron.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 +end ------------------------------------------------------------------------------------ -- Creative trash diff --git a/init.lua b/init.lua index 52393aa..61ad2ab 100644 --- a/init.lua +++ b/init.lua @@ -15,4 +15,5 @@ dofile(modpath.."/functions.lua") dofile(modpath.."/controller.lua") dofile(modpath.."/nodes/node_misc.lua") dofile(modpath.."/nodes/node_storage.lua") -dofile(modpath.."/nodes/node_digger.lua") \ No newline at end of file +dofile(modpath.."/nodes/node_digger.lua") +dofile(modpath.."/nodes/node_builder.lua") \ No newline at end of file diff --git a/nodes/node_builder.lua b/nodes/node_builder.lua new file mode 100644 index 0000000..9f1eea4 --- /dev/null +++ b/nodes/node_builder.lua @@ -0,0 +1,254 @@ +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + + +-- Note: builders go in group 4 + +-- TODO make this global +local player_interacting_with_builder_pos = {} + +local get_formspec = function(pos) + local meta = minetest.get_meta(pos) + + local period = meta:get_int("period") + if period < 1 then period = 1 end + local offset = meta:get_int("offset") + local extrusion = meta:get_int("extrusion") + local build_facing = meta:get_int("build_facing") + local item_name = meta:get_string("build_item") + + return "size[8,5.2]" .. + "item_image[0,0;1,1;" .. item_name .. "]".. + "listcolors[#00000069;#5A5A5A00;#141318;#30434C;#FFF]" .. + "list[detached:digtron:builder_item;main;0,0;1,1;]" .. + "field[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[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[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[4.0,0.5;1,0.1;set;" .. S("Save &\nShow") .. "]" .. + "tooltip[set;" .. S("Saves settings") .. "]" .. + "field[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[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[detached:digtron:builder_item;main]" +end + +---------------------------------------------------------------------- +-- Detached inventory for setting the builder item + +local inv = minetest.create_detached_inventory("digtron:builder_item", { + allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) + return 0 + end, + allow_put = function(inv, listname, index, stack, player) + -- Always disallow put, but use this to read what the player *tried* adding and set the builder appropriately + local item = stack:get_name() + + -- Ignore unknown items + if minetest.registered_items[item] == nil then return 0 end + + local player_name = player:get_player_name() + local pos = player_interacting_with_builder_pos[player_name] + if pos == nil then + return 0 + end + + local node = minetest.get_node(pos) + if node.name ~= "digtron:builder" then + minetest.log("warning", "[Digtron] builder detached inventory had player " .. player_name + .. " attempt to set " .. item .. " at " .. minetest.pos_to_string(pos) .. + " but the node at that location was a " .. node.name) + return 0 + end + + local meta = minetest.get_meta(pos) + local digtron_id = meta:get_string("digtron_id") + if digtron_id ~= "" then + minetest.log("warning", "[Digtron] builder detached inventory had player " .. player_name + .. " attempt to set " .. item .. " at " .. minetest.pos_to_string(pos) .. + " but the builder node at that location was already assembled into " .. digtron_id) + return 0 + end + + meta:set_string("build_item", item) + minetest.show_formspec(player_name, "digtron:builder", get_formspec(pos)) + + return 0 + end, + allow_take = function(inv, listname, index, stack, player) + return 0 + end, +-- on_move = function(inv, from_list, from_index, to_list, to_index, count, player) +-- end, +-- on_take = function(inv, listname, index, stack, player) +-- end, +-- on_put = function(inv, listname, index, stack, player) +-- end +}) +inv:set_size("main", 1) + +local builder_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local returnstack, success = digtron.on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if returnstack then + return returnstack, success + end + + if clicker == nil then return end + local player_name = clicker:get_player_name() + + local meta = minetest.get_meta(pos) + + local digtron_id = meta:get_string("digtron_id") + if digtron_id ~= "" then + minetest.sound_play({name = "digtron_error", gain = 0.1}, {to_player=account.name}) + minetest.chat_send_player(player_name, "This Digtron is active, interact with it via the controller node.") + return + end + + player_interacting_with_builder_pos[player_name] = pos + minetest.show_formspec(player_name, + "digtron:builder", + get_formspec(pos)) +end + +minetest.register_on_player_receive_fields(function(sender, formname, fields) + if formname ~= "digtron:builder" then + return + end + + local player_name = sender:get_player_name() + local pos = player_interacting_with_builder_pos[player_name] + if pos == nil then + minetest.log("error", "[Digtron] ".. player_name .. " tried interacting with a Digtron builder but" + .. " no position was recorded.") + return + end + + 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 then + 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 = default.node_sound_metal_defaults(), + 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) + 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, + + can_dig = digtron.can_dig, + on_blast = digtron.on_blast, +}) \ No newline at end of file diff --git a/nodes/node_digger.lua b/nodes/node_digger.lua index c33de51..24bdbdc 100644 --- a/nodes/node_digger.lua +++ b/nodes/node_digger.lua @@ -2,6 +2,7 @@ local MP = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(MP.."/intllib.lua") +-- TODO: make global local player_interacting_with_digtron_pos = {} local get_formspec = function(pos, player_name) diff --git a/nodes/node_storage.lua b/nodes/node_storage.lua index 56ba22f..9a28347 100644 --- a/nodes/node_storage.lua +++ b/nodes/node_storage.lua @@ -6,9 +6,6 @@ local S, NS = dofile(MP.."/intllib.lua") 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[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.6;8,4;]" .. "list[current_player;main;0,5.15;8,1;]" .. @@ -57,6 +54,13 @@ minetest.register_node("digtron:inventory", { on_blast = digtron.on_blast, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local returnstack, success = digtron.on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if returnstack then + return returnstack, success + end + + if clicker == nil then return end + local meta = minetest.get_meta(pos) local digtron_id = meta:get("digtron_id") local player_name = clicker:get_player_name() @@ -65,7 +69,8 @@ minetest.register_node("digtron:inventory", { "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.") + minetest.sound_play({name = "digtron_error", gain = 0.1}, {to_player=account.name}) + minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with it via the controller node.") end end, @@ -94,9 +99,6 @@ minetest.register_node("digtron:inventory", { 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[nodemeta:"..pos.x..","..pos.y..","..pos.z..";fuel;0,0.6;8,4;]" .. "list[current_player;main;0,5.15;8,1;]" .. @@ -157,6 +159,13 @@ minetest.register_node("digtron:fuelstore", { on_blast = digtron.on_blast, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local returnstack, success = digtron.on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if returnstack then + return returnstack, success + end + + if clicker == nil then return end + local meta = minetest.get_meta(pos) local digtron_id = meta:get("digtron_id") local player_name = clicker:get_player_name() @@ -165,7 +174,8 @@ minetest.register_node("digtron:fuelstore", { "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.") + minetest.sound_play({name = "digtron_error", gain = 0.1}, {to_player=account.name}) + minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with it via the controller node.") end end, @@ -200,9 +210,6 @@ minetest.register_node("digtron:fuelstore", { -- 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[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.6;8,3;]" .. "label[0,3.5;" .. S("Fuel items") .. "]" .. @@ -279,6 +286,13 @@ minetest.register_node("digtron:combined_storage", { on_blast = digtron.on_blast, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local returnstack, success = digtron.on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if returnstack then + return returnstack, success + end + + if clicker == nil then return end + local meta = minetest.get_meta(pos) local digtron_id = meta:get("digtron_id") local player_name = clicker:get_player_name() @@ -287,7 +301,8 @@ minetest.register_node("digtron:combined_storage", { "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.") + minetest.sound_play({name = "digtron_error", gain = 0.1}, {to_player=account.name}) + minetest.chat_send_player(clicker:get_player_name(), "This Digtron is active, interact with it via the controller node.") end end, -- diff --git a/sounds/digtron_error.ogg b/sounds/digtron_error.ogg new file mode 100644 index 0000000..d1ae7c9 Binary files /dev/null and b/sounds/digtron_error.ogg differ