diff --git a/functions.lua b/functions.lua index 635030d..f296394 100644 --- a/functions.lua +++ b/functions.lua @@ -37,37 +37,261 @@ function streetlights.rightclick_pointed_thing(pos, placer, itemstack, pointed_t return def.on_rightclick(pos, node, placer, itemstack, pointed_thing) or itemstack end -function streetlights.check_and_place(itemstack, placer, pointed_thing, def) +local function can_build(target_pos, fdir, model_def, player_name, controls) + local main_node, node3, node4 + local main_def, def3, def4 - local pole = def.pole - local base = def.base or def.pole - local light = def.light - local height = def.height or 5 - local needs_digiline_wire = def.needs_digiline_wire - local distributor_node = def.distributor_node - local poletop = (def.topnodes and (type(def.topnodes) == "table") and def.topnodes.poletop) or pole - local overhang = (def.topnodes and (type(def.topnodes) == "table") and def.topnodes.overhang) or pole - local copy_pole_fdir = def.copy_pole_fdir - local light_fdir = def.light_fdir + local main_pos, pos3, pos4 + for i = 1, model_def.height do + main_pos = { x=target_pos.x, y = target_pos.y+i, z=target_pos.z } + main_node = minetest.get_node(main_pos) + main_def = minetest.registered_items[main_node.name] + if minetest.is_protected(main_pos, player_name) or not (main_def and main_def.buildable_to) then return end + end + + pos3 = { + x = target_pos.x+fdir_to_right[fdir+1][1], + y = target_pos.y+model_def.height, + z = target_pos.z+fdir_to_right[fdir+1][2] + } + node3 = minetest.get_node(pos3) + def3 = minetest.registered_items[node3.name] + if minetest.is_protected(pos3, player_name) or not (def3 and def3.buildable_to) then return end + + if def.topnodes ~= false then + pos4 = { + x = target_pos.x+fdir_to_right[fdir+1][1], + y = target_pos.y+model_def.height-1, + z = target_pos.z+fdir_to_right[fdir+1][2] + } + node4 = minetest.get_node(pos4) + def4 = minetest.registered_items[node4.name] + if minetest.is_protected(pos4, player_name) or not (def4 and def4.buildable_to) then return end + end + + local dist_pos = { x = target_pos.x, y = target_pos.y-1, z = target_pos.z } + + if controls.sneak and minetest.is_protected(target_pos, player_name) then return end + if model_def.distributor_node and minetest.is_protected(dist_pos, player_name) then return end + return true +end + +local function has_materials(model_def, inv, player_name, controls) + -- if main_extends_base, then the base node is one of two pieces + -- and the upper piece is not usually directly available to the player, + -- as with streets:pole_[top|bottom] (the thin one) + -- + -- if it's that sort of thing, there could be some waste here when the player digs a pole, + -- if you use an odd number for the pole height along with main_extends_base + + local num_main = model_def.height + 1 + + if model_def.poletop ~= model_def.pole and not model_def.main_extends_base then + num_main = num_main - 1 + if not inv:contains_item("main", model_def.poletop) then + minetest.chat_send_player(player_name, "*** You don't have any "..model_def.poletop.." in your inventory!") + return + end + end + + if model_def.overhang ~= model_def.pole and not model_def.main_extends_base then + num_main = num_main - 1 + if not inv:contains_item("main", model_def.overhang) then + minetest.chat_send_player(player_name, "*** You don't have any "..model_def.overhang.." in your inventory!") + return + end + end + + if model_def.base ~= model_def.pole then + num_main = num_main - 1 + if model_def.main_extends_base then + if not inv:contains_item("main", model_def.base.." "..math.floor(num_main/2)) then + minetest.chat_send_player(player_name, "*** You don't have enough "..model_def.base.." in your inventory!") + return + end + else + if not inv:contains_item("main", model_def.base) then + minetest.chat_send_player(player_name, "*** You don't have any "..model_def.base.." in your inventory!") + return + end + + if not inv:contains_item("main", model_def.pole.." "..num_main) then + minetest.chat_send_player(player_name, "*** You don't have enough "..model_def.pole.." in your inventory!") + return + end + end + else + if not inv:contains_item("main", model_def.pole.." "..num_main) then + minetest.chat_send_player(player_name, "*** You don't have enough "..model_def.pole.." in your inventory!") + return + end + end + + if not inv:contains_item("main", model_def.light) then + minetest.chat_send_player(player_name, "*** You don't have any "..model_def.light.." in your inventory!") + return + end + + if model_def.needs_digiline_wire and not inv:contains_item("main", model_def.digiline_wire_node.." "..model_def.height + (model_def.has_top and 1 or 0)) then + minetest.chat_send_player(player_name, "*** You don't have enough Digiline wires in your inventory!") + return + end + + if model_def.distributor_node and model_def.needs_digiline_wire then + if not inv:contains_item("main", model_def.distributor_node) then + minetest.chat_send_player(player_name, "*** You don't have any "..model_def.distributor_node.." in your inventory!") + return + else + inv:remove_item("main", model_def.distributor_node) + end + end + + if controls.sneak then + if not inv:contains_item("main", streetlights.concrete) then + minetest.chat_send_player(player_name, "*** You don't have any concrete in your inventory!") + return + else + inv:remove_item("main", streetlights.concrete) + end + end + return num_main +end + +local function take_materials(model_def, inv, num_main, controls) + if model_def.poletop ~= model_def.pole and not model_def.main_extends_base then + inv:remove_item("main", model_def.poletop) + end + + if model_def.overhang ~= pole and not model_def.main_extends_base then + inv:remove_item("main", model_def.overhang) + end + + if model_def.base ~= model_def.pole then + if model_def.main_extends_base then + inv:remove_item("main", model_def.base.." "..math.floor(num_main/2)) + end + else + inv:remove_item("main", model_def.pole.." "..num_main) + end + + inv:remove_item("main", model_def.light) + + if model_def.needs_digiline_wire then + inv:remove_item("main", model_def.digiline_wire_node.." "..num_main) + end + + if model_def.distributor_node and model_def.needs_digiline_wire then + inv:remove_item("main", model_def.distributor_node) + end + + if controls.sneak then + inv:remove_item("main", streetlights.concrete) + end + +end + +local function build_streetlight(target_pos, target_node, target_dir, fdir, model_def, controls) + + if controls.sneak then + minetest.set_node(target_pos, { name = streetlights.concrete }) + end + + if model_def.needs_digiline_wire then + model_def.base = model_def.base.."_digilines" + model_def.pole = model_def.pole.."_digilines" + model_def.poletop = model_def.poletop.."_digilines" + model_def.overhang = model_def.overhang.."_digilines" + end + + local target_fdir + + if model_def.copy_pole_fdir == true then + if model_def.node_rotation then + target_fdir = minetest.dir_to_facedir(vector.rotate(target_dir, {x=0, y=model_def.node_rotation, z=0})) + else + target_fdir = fdir + end + + if model_def.light_fdir == "auto" then -- the light should use the same fdir as the pole + model_def.light_fdir = target_fdir + end + end + + local base_pos = {x=target_pos.x, y = target_pos.y+1, z=target_pos.z} + minetest.set_node(base_pos, {name = model_def.base, param2 = target_fdir }) + + for i = 2, model_def.height - 1 do + local main_pos = {x=target_pos.x, y = target_pos.y+i, z=target_pos.z} + minetest.set_node(main_pos, {name = model_def.pole, param2 = target_fdir }) + end + + local top_pos = {x=target_pos.x, y = target_pos.y+model_def.height, z=target_pos.z} + minetest.set_node(top_pos, {name = model_def.poletop, param2 = target_fdir }) + + + + local pos2, pos3, pos4 + + pos3 = { + x = target_pos.x+fdir_to_right[fdir+1][1], + y = target_pos.y+model_def.height, + z = target_pos.z+fdir_to_right[fdir+1][2] + } + + if model_def.topnodes ~= false then + pos4 = { + x = target_pos.x+fdir_to_right[fdir+1][1], + y = target_pos.y+model_def.height-1, + z = target_pos.z+fdir_to_right[fdir+1][2] + } + minetest.set_node(pos3, { name = model_def.overhang }) + minetest.set_node(pos4, { name = model_def.light, param2 = model_def.light_fdir }) + else + minetest.set_node(pos3, { name = model_def.light, param2 = model_def.light_fdir }) + end + + if model_def.needs_digiline_wire and ilights.player_channels[player_name] then + minetest.get_meta(pos4):set_string("channel", ilights.player_channels[player_name]) + end + + if model_def.distributor_node and model_def.needs_digiline_wire then + local dist_pos = { x = target_pos.x, y = target_pos.y-1, z = target_pos.z } + + minetest.set_node(dist_pos, { name = model_def.distributor_node }) + digilines.update_autoconnect(dist_pos) + end +end + +function streetlights.check_and_place(itemstack, placer, pointed_thing, model_def) + if not placer then return end + + model_def.base = model_def.base or model_def.pole + model_def.light = model_def.light + model_def.height = model_def.height or 5 + model_def.needs_digiline_wire = model_def.needs_digiline_wire + model_def.distributor_node = model_def.distributor_node + model_def.poletop = (model_def.topnodes and (type(model_def.topnodes) == "table") and model_def.topnodes.poletop) or model_def.pole + model_def.overhang = (model_def.topnodes and (type(model_def.topnodes) == "table") and model_def.topnodes.overhang) or model_def.pole + model_def.copy_pole_fdir = model_def.copy_pole_fdir + model_def.light_fdir = model_def.light_fdir local controls = placer:get_player_control() - if not placer then return end local player_name = placer:get_player_name() local placer_pos = placer:get_pos() -- this bit borrowed from builtin/game/item.lua local target_dir = vector.subtract(pointed_thing.above, placer_pos) local fdir = minetest.dir_to_facedir(target_dir) - local pos1 = minetest.get_pointed_thing_position(pointed_thing) - local node1 = minetest.get_node(pos1) - if not node1 or node1.name == "ignore" then return end - local def1 = minetest.registered_items[node1.name] + local target_pos = minetest.get_pointed_thing_position(pointed_thing) + local target_node = minetest.get_node(target_pos) + if not target_node or target_node.name == "ignore" then return end + local target_def = minetest.registered_items[target_node.name] - if (def1 and def1.buildable_to) then - pos1.y = pos1.y-1 + if (target_def and target_def.buildable_to) then + target_pos.y = target_pos.y-1 end - local rc = streetlights.rightclick_pointed_thing(pos1, placer, itemstack, pointed_thing) + local rc = streetlights.rightclick_pointed_thing(target_pos, placer, itemstack, pointed_thing) if rc then return rc end if not minetest.check_player_privs(placer, "streetlight") then @@ -75,201 +299,22 @@ function streetlights.check_and_place(itemstack, placer, pointed_thing, def) return end - local node1 = minetest.get_node(pos1) - - local node2, node3, node4 - local def1 = minetest.registered_items[node1.name] - local def2, def3, def4 - - local pos2, pos3, pos4 - for i = 1, height do - pos2 = { x=pos1.x, y = pos1.y+i, z=pos1.z } - node2 = minetest.get_node(pos2) - def2 = minetest.registered_items[node2.name] - if minetest.is_protected(pos2, player_name) or not (def2 and def2.buildable_to) then return end + if not can_build(target_pos, fdir, model_def, player_name, controls) then + minetest.chat_send_player(player_name, "*** You can't build there, something's in the way or it's protected!") + return end - pos3 = { x = pos1.x+fdir_to_right[fdir+1][1], y = pos1.y+height, z = pos1.z+fdir_to_right[fdir+1][2] } - node3 = minetest.get_node(pos3) - def3 = minetest.registered_items[node3.name] - if minetest.is_protected(pos3, player_name) or not (def3 and def3.buildable_to) then return end - - if def.topnodes ~= false then - pos4 = { x = pos1.x+fdir_to_right[fdir+1][1], y = pos1.y+height-1, z = pos1.z+fdir_to_right[fdir+1][2] } - node4 = minetest.get_node(pos4) - def4 = minetest.registered_items[node4.name] - if minetest.is_protected(pos4, player_name) or not (def4 and def4.buildable_to) then return end - end - - local pos0 = { x = pos1.x, y = pos1.y-1, z = pos1.z } - - if controls.sneak and minetest.is_protected(pos1, player_name) then return end - if distributor_node and minetest.is_protected(pos0, player_name) then return end - if not creative.is_enabled_for(player_name) then local inv = placer:get_inventory() - -- first, make sure the player has items in the inventory to build with - - -- if main_extends_base, then the base node is one of two pieces - -- and the upper piece is not usually directly available to the player, - -- as with streets:pole_[top|bottom] (the thin one) - -- - -- if it's that sort of thing, there could be some waste here when the player digs a pole, - -- if you use an odd number for the pole height along with main_extends_base - - local num_main = height + 1 - - if poletop ~= pole and not def.main_extends_base then - num_main = num_main - 1 - if not inv:contains_item("main", poletop) then - minetest.chat_send_player(player_name, "*** You don't have any "..poletop.." in your inventory!") - return - end - end - - if overhang ~= pole and not def.main_extends_base then - num_main = num_main - 1 - if not inv:contains_item("main", overhang) then - minetest.chat_send_player(player_name, "*** You don't have any "..overhang.." in your inventory!") - return - end - end - - if base ~= pole then - num_main = num_main - 1 - if def.main_extends_base then - if not inv:contains_item("main", base.." "..math.floor(num_main/2)) then - minetest.chat_send_player(player_name, "*** You don't have enough "..base.." in your inventory!") - return - end - else - if not inv:contains_item("main", base) then - minetest.chat_send_player(player_name, "*** You don't have any "..base.." in your inventory!") - return - end - - if not inv:contains_item("main", pole.." "..num_main) then - minetest.chat_send_player(player_name, "*** You don't have enough "..pole.." in your inventory!") - return - end - end + if has_materials(model_def, inv, player_name, controls) then + take_materials(model_def, inv, num_main, controls) else - if not inv:contains_item("main", pole.." "..num_main) then - minetest.chat_send_player(player_name, "*** You don't have enough "..pole.." in your inventory!") - return - end - end - - if not inv:contains_item("main", light) then - minetest.chat_send_player(player_name, "*** You don't have any "..light.." in your inventory!") return end - - if needs_digiline_wire and not inv:contains_item("main", digiline_wire_node.." "..height + (has_top and 1 or 0)) then - minetest.chat_send_player(player_name, "*** You don't have enough Digiline wires in your inventory!") - return - end - - if distributor_node and needs_digiline_wire then - if not inv:contains_item("main", distributor_node) then - minetest.chat_send_player(player_name, "*** You don't have any "..distributor_node.." in your inventory!") - return - else - inv:remove_item("main", distributor_node) - end - end - - if controls.sneak then - if not inv:contains_item("main", streetlights.concrete) then - minetest.chat_send_player(player_name, "*** You don't have any concrete in your inventory!") - return - else - inv:remove_item("main", streetlights.concrete) - end - end - - -- If we got this far, the player has everything, so now deduct items - - if poletop ~= pole and not def.main_extends_base then - inv:remove_item("main", poletop) - end - - if overhang ~= pole and not def.main_extends_base then - inv:remove_item("main", overhang) - end - - if base ~= pole then - if def.main_extends_base then - inv:remove_item("main", base.." "..math.floor(num_main/2)) - end - else - inv:remove_item("main", pole.." "..num_main) - end - - inv:remove_item("main", light) - - if needs_digiline_wire then - inv:remove_item("main", digiline_wire_node.." "..num_main) - end - end - -- and place them in the world - - if controls.sneak then - minetest.set_node(pos1, { name = streetlights.concrete }) - end - - local pole2 = pole - - if needs_digiline_wire then - base = base.."_digilines" - pole2 = pole.."_digilines" - poletop = poletop.."_digilines" - overhang = overhang.."_digilines" - end - - local target_fdir - - if copy_pole_fdir == true then - if def.node_rotation then - target_fdir = minetest.dir_to_facedir(vector.rotate(target_dir, {x=0, y=def.node_rotation, z=0})) - else - target_fdir = fdir - end - - if def.light_fdir == "auto" then -- the light should use the same fdir as the pole - light_fdir = target_fdir - end - end - - local pos2b = {x=pos1.x, y = pos1.y+1, z=pos1.z} - minetest.set_node(pos2b, {name = base, param2 = target_fdir }) - - for i = 2, height-1 do - pos2 = {x=pos1.x, y = pos1.y+i, z=pos1.z} - minetest.set_node(pos2, {name = pole2, param2 = target_fdir }) - end - - local pos2t = {x=pos1.x, y = pos1.y+height, z=pos1.z} - minetest.set_node(pos2t, {name = poletop, param2 = target_fdir }) - - if def.topnodes ~= false then - minetest.set_node(pos3, { name = overhang }) - minetest.set_node(pos4, { name = light, param2 = light_fdir }) - else - minetest.set_node(pos3, { name = light, param2 = light_fdir }) - end - - if needs_digiline_wire and ilights.player_channels[player_name] then - minetest.get_meta(pos4):set_string("channel", ilights.player_channels[player_name]) - end - - if distributor_node and needs_digiline_wire then - minetest.set_node(pos0, { name = distributor_node }) - digilines.update_autoconnect(pos0) - end + build_streetlight(target_pos, target_node, target_dir, fdir, model_def, controls) end diff --git a/simple.lua b/simple.lua index 6a70391..93a565d 100644 --- a/simple.lua +++ b/simple.lua @@ -33,7 +33,7 @@ local poles_tab = { -- material name, mod name, node name, optional base, optional height, top section { "wood", "default", "default:fence_wood" }, { "junglewood", "default", "default:fence_junglewood" }, - { "brass", "homedecor_fences", "homedecor:fence_brass", "basic_materials:brass_block", nil, {poletop="default:cobble", overhang="default:dirt"} }, + { "brass", "homedecor_fences", "homedecor:fence_brass"}, { "wrought_iron", "homedecor_fences", "homedecor:fence_wrought_iron" }, { "steel", "gloopblocks", "gloopblocks:fence_steel"} }