artifact_one/mods/artifact_mechanisms/doors.lua

266 lines
8.5 KiB
Lua

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_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")