diff --git a/entities.lua b/entities.lua new file mode 100644 index 0000000..568ad75 --- /dev/null +++ b/entities.lua @@ -0,0 +1,201 @@ +-- The default minetest.add_entity crashes with an exception if you try adding an entity in an unloaded area +-- this wrapper catches that exception and just ignores it. +digtron.safe_add_entity = function(pos, name) + success, ret = pcall(minetest.add_entity, pos, name) + if success then return ret else return nil end +end + +local safe_add_entity = digtron.safe_add_entity + +------------------------------------------------------------------------------------------------- +-- For displaying where things get built under which periodicities + +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, +}) + +local vertical = {x=1.5708, y=0, z=0} +-- TODO: update to new method of finding buildpos? +-- TODO: add item indicator entity as well +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 + local entity = safe_add_entity({x=buildpos.x, y=y_pos, z=buildpos.z}, "digtron:marker") + if entity ~= nil then entity:set_rotation(vertical) end + if y_pos >= buildpos.y then + local entity = safe_add_entity({x=buildpos.x, y=y_pos - period, z=buildpos.z}, "digtron:marker") + if entity ~= nil then entity:set_rotation(vertical) end + end + if y_pos <= buildpos.y then + local entity = safe_add_entity({x=buildpos.x, y=y_pos + period, z=buildpos.z}, "digtron:marker") + if entity ~= nil then entity:set_rotation(vertical) end + 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 + +----------------------------------------------------------------------------------------------- +-- For displaying whether nodes are part of a digtron or are obstructed + +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, + glow = minetest.LIGHT_MAX, + }, + + 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, + glow = minetest.LIGHT_MAX, + }, + + 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, +}) + +----------------------------------------------------------------------------------------------------------------- +-- Builder items + +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 + +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, +}) diff --git a/functions.lua b/functions.lua index 0c487a6..be8b712 100644 --- a/functions.lua +++ b/functions.lua @@ -469,10 +469,10 @@ digtron.remove_from_world = function(digtron_id, root_pos, player_name) minetest.bulk_set_node(nodes_to_destroy, {name="air"}) end -digtron.build_to_world = function(digtron_id, root_pos, player_name) +-- Tests if a Digtron can be built at the designated location +digtron.is_buildable_to = function(digtron_id, root_pos, player_name, show_visualization) local layout = retrieve_layout(digtron_id) local root_hash = minetest.hash_node_position(root_pos) - local nodes_to_create = {} local permitted = true for hash, data in pairs(layout) do @@ -482,34 +482,49 @@ digtron.build_to_world = function(digtron_id, root_pos, player_name) -- TODO: lots of testing needed here if not (node_def and node_def.buildable_to) then minetest.chat_send_all("not permitted due to " .. node.name .. " at " .. minetest.pos_to_string(node_pos)) - permitted = false - break - end - end - - if permitted then - -- TODO: voxelmanip might be better here, less likely than with destroy though since metadata needs to be written - for hash, data in pairs(layout) do - local node_pos = minetest.get_position_from_hash(hash + root_hash - origin_hash) - minetest.set_node(node_pos, data.node) - local meta = minetest.get_meta(node_pos) - for field, value in pairs(data.meta.fields) do - meta:set_string(field, value) + if not show_visualization then + return false + else + permitted = false + digtron.safe_add_entity(node_pos, "digtron:marker_crate_bad") end - meta:set_string("digtron_id", digtron_id) - meta:mark_as_private("digtron_id") - -- Not needed - local inventories not used by active digtron, will be restored if disassembled --- local inv = meta:get_inventory() --- for listname, size in pairs(data.meta.inventory) do --- inv:set_size(listname, size) --- end + elseif show_visualization then + digtron.safe_add_entity(node_pos, "digtron:marker_crate_good") end - local bbox = retrieve_bounding_box(digtron_id) - persist_bounding_box(digtron_id, bbox) - persist_pos(digtron_id, root_pos) + end + return permitted +end + +-- Places the Digtron into the world. +digtron.build_to_world = function(digtron_id, root_pos, player_name) + local layout = retrieve_layout(digtron_id) + local root_hash = minetest.hash_node_position(root_pos) + + if not digtron.is_buildable_to(digtron_id, root_pos, player_name, true) then + return false end - return permitted + -- TODO: voxelmanip might be better here, less likely than with destroy though since metadata needs to be written + for hash, data in pairs(layout) do + local node_pos = minetest.get_position_from_hash(hash + root_hash - origin_hash) + minetest.set_node(node_pos, data.node) + local meta = minetest.get_meta(node_pos) + for field, value in pairs(data.meta.fields) do + meta:set_string(field, value) + end + meta:set_string("digtron_id", digtron_id) + meta:mark_as_private("digtron_id") + -- Not needed - local inventories not used by active digtron, will be restored if disassembled +-- local inv = meta:get_inventory() +-- for listname, size in pairs(data.meta.inventory) do +-- inv:set_size(listname, size) +-- end + end + local bbox = retrieve_bounding_box(digtron_id) + persist_bounding_box(digtron_id, bbox) + persist_pos(digtron_id, root_pos) + + return true end --------------------------------------------------------------------------------- diff --git a/init.lua b/init.lua index c7c5765..9287770 100644 --- a/init.lua +++ b/init.lua @@ -1,8 +1,14 @@ digtron = {} digtron.doc = {} +digtron.config = {} + +digtron.config.marker_crate_bad_duration = 5 +digtron.config.marker_crate_good_duration = 5 + local modpath = minetest.get_modpath(minetest.get_current_modname()) +dofile(modpath.."/entities.lua") dofile(modpath.."/functions.lua") dofile(modpath.."/controller.lua") dofile(modpath.."/nodes/node_misc.lua")