local doors = {} function artifact.rotate_selectionbox(box, rot) local a = vector.new(box[1], box[2], box[3]):rotate(rot) local b = vector.new(box[4], box[5], box[6]):rotate(rot) return { a.x, a.y, a.z, b.x, b.y, b.z } end minetest.register_entity(":artifact:door", { initial_properties = { visual = "mesh", mesh = "artifact_door.gltf", textures = {"artifact_door_wood.png"}, selectionbox = { -0.5, -0.5, -0.5, 0.5, 1.5, -6/16 }, physical = true }, _interact_time = 0.2, _interact_marker_offset = function(e) return (e._open and vector.new(e.inverted and 0.5 or -0.5, 0.5, 0) or vector.new(0, 0.5, 0.5)):rotate(e.object:get_rotation()) end, box_open_normal = { -0.5, -0.5, -0.5, -6/16, 1.5, 0.5 }, box_open_inverted = { 0.5, -0.5, -0.5, 6/16, 1.5, 0.5 }, box_closed_normal = { -0.5, -0.5, 0.5, 0.5, 1.5, 6/16 }, on_activate = function(e, data) local node = minetest.get_node(e.object:get_pos()) if not node.name:find "door" then e.object:remove() return end e.object:set_armor_groups{immortal = 1} extend(e, minetest.deserialize(data) or {}) if e.type == "iron" then if e._locked == nil then e._locked = true end e.object:set_properties { textures = {"artifact_door_iron.png"}, } end if e.rotation then e:rotate(e.rotation) else e:rotate(vector.zero()) end e._name = ""..math.random() local nm = minetest.get_meta(e.object:get_pos()) local open = nm:get("open") == "true" if open and not e._open then e:open(true) elseif not open and e._open then e:close(true) end if nm:get_string("locked") == "true" then e._locked = true end if e._locked then e._no_interact = true end if e.inverted then e:invert() end doors[e.object:get_pos():round():to_string()] = e end, on_deactivate = function(e) doors[e.object:get_pos():round():to_string()] = nil end, on_interact = function(e) if e._locked then return end if e._open then e:close() else e:open() end end, open = function(e, snap) if e._open then return end e._open = true e._no_interact = true e._name = ""..math.random() e.object:set_animation({x=snap and 0.5 or 0,y=0.5}, 1.5, 0.1, false) minetest.after(snap and 0 or 0.1, function() local pos = e.object:get_pos():round() minetest.get_meta(pos):set_string("open", "true") local box = artifact.rotate_selectionbox(e.inverted and e.box_open_inverted or e.box_open_normal, e.rotation) e.object:set_properties { selectionbox = box, collisionbox = table.copy(box) } end) if not e._locked then minetest.after(snap and 0 or 0.25, function() e._no_interact = nil end) end end, close = function(e, snap) if not e._open then return end e._open = nil e._no_interact = true e._name = ""..math.random() e.object:set_animation({x=snap and 1 or 0.5,y=1}, 1.5, 0.1, false) minetest.after(snap and 0 or 0.1, function() local pos = e.object:get_pos():round() minetest.get_meta(pos):set_string("open", "false") local box = artifact.rotate_selectionbox(e.box_closed_normal, e.rotation) e.object:set_properties { selectionbox = box, collisionbox = box } end) if not e._locked then minetest.after(snap and 0 or 0.25, function() e._no_interact = nil end) end end, invert = function(e) e.inverted = true local box = artifact.rotate_selectionbox(e.box_closed_normal, e.rotation) e.object:set_properties { mesh = "artifact_door_inverted.gltf", selectionbox = box, collisionbox = box } end, get_staticdata = function(e) return minetest.serialize{type = e.type, _locked = e._locked, rotation = e.rotation, inverted = e.inverted} end, on_punch = artifact.debug and function(e) local nm = minetest.get_meta(e.object:get_pos()) if nm:get_string("locked") == "true" then e._locked = true end if e._locked then e._no_interact = true end end or nil, unlock = function(e) if e._locked then e._locked = false e._no_interact = nil end end, rotate = function(e, rot) e.object:set_rotation(rot) e.rotation = rot local box = artifact.rotate_selectionbox(e._open and (e.inverted and e.box_open_inverted or e.box_open_normal) or e.box_closed_normal, e.rotation) e.object:set_properties { selectionbox = box, collisionbox = box } end, on_hover = function(e, m) if e.type == "wood" and e._locked then m._whack_hud = m.object:hud_add { type = "image_waypoint", world_pos = e.object:get_pos():offset(0, 0.5, 0), scale = {x=3,y=3}, text = "artifact_icon_whack.png" } end end, on_unhover = function(e, m) if m._whack_hud then m.object:hud_remove(m._whack_hud) m._whack_hud = nil end end, on_whack = function(e) if e.type == "wood" then local pos = e.object:get_pos():round() minetest.remove_node(pos) minetest.add_particlespawner { pos = { min = pos:offset(-0.5, -0.5, -0.5), max = pos:offset(0.5, 1.5, 0.5) }, vel = { min = vector.new(-1, 0, -1) *1.5, max = vector.new(1, 2, 1) *1.5 }, acc = vector.new(0,-9.81,0), collisiondetection = true, amount = 50, texture = "artifact_door_wood.png^[sheet:2x8:0,3", time = 0.1 } return true end end }) local function register_basic_door(type) local function onload(pos) local m = minetest.get_meta(pos) -- Dynamically initialize doors that were mapgen'd in. if not m:contains("initialized") then m:set_string("initialized", "true") local rot = artifact.facedir_to_rotation(minetest.get_node(pos).param2) minetest.add_entity(pos, "artifact:door", minetest.serialize{type = type, rotation = rot}) end end local function ondestruct(pos, reason) doors[pos:to_string()].object:remove() doors[pos:to_string()] = nil end local function onsignal(pos, event) local door = doors[vector.to_string(pos)] if event.type == "on" then if door then door:open() else local node = minetest.get_node(pos) node.name = "door_"..e.type.."_open" minetest.swap_node(pos, node) end elseif event.type == "off" then if door then door:close() else local node = minetest.get_node(pos) node.name = "door_"..e.type.."_open" minetest.swap_node(pos, node) end end end artifact.register_node("door_"..type, { drawtype = "airlike", walkable = false, selection_box = { type = "fixed", fixed = { -0.5, -0.5, 0.5, 0.5, 1.5, 6/16 } }, paramtype2 = "facedir", tiles = {"artifact_door_"..type..".png"}, use_texture_alpha = "clip", paramtype = "light", pointable = false, groups = {call_on_load = 1, whackable = type == "wood" and 1 or nil}, on_construct = onload, on_destruct = ondestruct, on_load = onload, on_signal = onsignal, on_place = function(s, p, pt) local out, pos = minetest.item_place_node(s, p, pt) if artifact.players[p:get_player_name()].ctl.sneak then minetest.get_meta(pos):set_string("inverted", "true") doors[pos:to_string()]:invert() end return out end, on_rotate = function(pos, node, p, click, param2) node.param2 = param2 minetest.swap_node(pos, node) local rot = artifact.facedir_to_rotation(param2) doors[pos:to_string()]:rotate(rot) return true end }) end register_basic_door("wood") register_basic_door("iron")