304 lines
10 KiB
Lua
304 lines
10 KiB
Lua
|
|
local large_doors = {}
|
|
artifact.large_doors = large_doors
|
|
|
|
minetest.register_entity(":artifact:large_door_display", {
|
|
initial_properties = {
|
|
visual = "mesh",
|
|
mesh = "artifact_door_large.gltf",
|
|
textures = {"artifact_door_large.png"},
|
|
selectionbox = {
|
|
-1.5, -0.5, -2/16,
|
|
1.5, 2.5, 2/16
|
|
},
|
|
pointable = artifact.debug
|
|
},
|
|
on_activate = function(e, data)
|
|
local pos = e.object:get_pos():round()
|
|
local node = minetest.get_node(pos)
|
|
if not node.name:find "large_door" then
|
|
e.object:remove()
|
|
return
|
|
end
|
|
e.object:set_armor_groups{immortal = 1}
|
|
extend(e, minetest.deserialize(data) or {})
|
|
if e.rotation then
|
|
e.rotation.y = e.rotation.y +math.pi
|
|
e:rotate(e.rotation)
|
|
else
|
|
e.rotation = vector.zero()
|
|
end
|
|
e._name = ""..math.random()
|
|
|
|
if e._locked == nil then
|
|
e._locked = true
|
|
end
|
|
|
|
local nm = minetest.get_meta(e.object:get_pos())
|
|
if (node.name:find "_open") and not e._open then
|
|
e:open(true)
|
|
elseif not (node.name:find "_open") and e._open then
|
|
e:close(true)
|
|
end
|
|
-- In case our saved state differs from the node's stored state, e.g. if a trigger
|
|
-- updated an effector in an unloaded area and couldn't get at the display entity,
|
|
-- we should always be sure to match the node meta.
|
|
if nm:get_string("locked") == "true" then
|
|
e._locked = true
|
|
end
|
|
|
|
if nm:contains("locks") then
|
|
e.locks = minetest.deserialize(nm:get_string("locks"))
|
|
end
|
|
|
|
if e.locks then
|
|
e:set_locks(e.locks)
|
|
end
|
|
|
|
e.collider_a = minetest.add_entity(pos, "display")
|
|
e.collider_a:set_properties {
|
|
physical = true,
|
|
collisionbox = artifact.rotate_selectionbox({
|
|
-0.75, -1.5, -2/16,
|
|
0.75, 1.5, 2/16
|
|
}, e.rotation)
|
|
}
|
|
e.collider_a:set_attach(e.object, "a")
|
|
|
|
e.collider_b = minetest.add_entity(pos, "display")
|
|
e.collider_b:set_properties {
|
|
physical = true,
|
|
collisionbox = artifact.rotate_selectionbox({
|
|
-0.75, -1.5, -2/16,
|
|
0.75, 1.5, 2/16
|
|
}, e.rotation)
|
|
}
|
|
e.collider_b:set_attach(e.object, "b")
|
|
|
|
large_doors[e.object:get_pos():round():to_string()] = e
|
|
end,
|
|
on_deactivate = function(e)
|
|
large_doors[e.object:get_pos():round():to_string()] = nil
|
|
if e.collider_a then
|
|
e.collider_a:remove()
|
|
e.collider_a = nil
|
|
end
|
|
if e.collider_b then
|
|
e.collider_b:remove()
|
|
e.collider_b = nil
|
|
end
|
|
end,
|
|
get_staticdata = function(e)
|
|
return minetest.serialize{type = e.type, _locked = e._locked, rotation = e.rotation, locks = e.locks}
|
|
end,
|
|
open = function(e)
|
|
-- We're already open, so there's nothing to do.
|
|
if e._open then return end
|
|
e._open = true
|
|
e._animating = true
|
|
e.object:set_animation({x=0,y=1}, 1.25, 0.1, false)
|
|
local pos = e.object:get_pos():round()
|
|
minetest.get_meta(pos):set_string("open", "true")
|
|
|
|
artifact.play_sound {
|
|
name = "artifact_large_door_open",
|
|
pos = e.object:get_pos(),
|
|
range = 10,
|
|
}
|
|
|
|
local m = minetest.get_meta(pos)
|
|
local on_open = m:get("on_open")
|
|
if not artifact.debug and on_open then
|
|
if on_open == "play_final_scene" then
|
|
artifact.story.play_final_scene()
|
|
elseif on_open == "play_end_scene" then
|
|
artifact.story.play_end_scene()
|
|
end
|
|
m:set_string("on_open", "")
|
|
end
|
|
|
|
minetest.after(0.75, function()
|
|
e._animating = nil
|
|
end)
|
|
end,
|
|
close = function(e)
|
|
if not e._open then return end
|
|
e._open = false
|
|
e._animating = true
|
|
e.object:set_animation({x=1,y=2}, 1.25, 0.1, false)
|
|
local pos = e.object:get_pos():round()
|
|
minetest.get_meta(pos):set_string("open", "false")
|
|
|
|
artifact.play_sound {
|
|
name = "artifact_large_door_close",
|
|
pos = e.object:get_pos(),
|
|
range = 10,
|
|
}
|
|
|
|
minetest.after(0.75, function()
|
|
e._animating = nil
|
|
end)
|
|
end,
|
|
on_step = function(e)
|
|
-- If we're locked or in a transition state, there's no need to run these checks.
|
|
if e._locked or e._animating then return end
|
|
-- We don't use objects_inside_radius to avoid wasting time finding and ignoring display entities.
|
|
-- Instead, we just do a radius check on each player.
|
|
local pos = e.object:get_pos()
|
|
local found = artifact.sidekick.pos and artifact.sidekick.pos:distance(pos) < 4
|
|
for _, m in pairs(artifact.players) do
|
|
if m.object:get_pos():distance(pos) < 4 then
|
|
found = true
|
|
break
|
|
end
|
|
end
|
|
if found and not e._open then
|
|
e:open()
|
|
elseif not found and e._open then
|
|
e:close()
|
|
end
|
|
end,
|
|
rotate = function(e, rot)
|
|
e.object:set_rotation(rot)
|
|
e.rotation = rot
|
|
e.object:set_properties {
|
|
selectionbox = artifact.rotate_selectionbox({
|
|
-1.5, -0.5, -2/16,
|
|
1.5, 2.5, 2/16
|
|
}, e.rotation)
|
|
}
|
|
if e.collider_a then
|
|
e.collider_a:set_properties {
|
|
collisionbox = artifact.rotate_selectionbox({
|
|
-0.75, -1.5, -2/16,
|
|
0.75, 1.5, 2/16
|
|
}, e.rotation)
|
|
}
|
|
end
|
|
if e.collider_b then
|
|
e.collider_b:set_properties {
|
|
collisionbox = artifact.rotate_selectionbox({
|
|
-0.75, -1.5, -2/16,
|
|
0.75, 1.5, 2/16
|
|
}, e.rotation)
|
|
}
|
|
end
|
|
end,
|
|
-- We include this so we can update the entity's locks without having to unload and reload them.
|
|
on_punch = function(e)
|
|
local locks = minetest.deserialize(minetest.get_meta(e.object:get_pos():round()):get_string("locks"))
|
|
e:set_locks(locks)
|
|
end,
|
|
set_locks = function(e, locks)
|
|
e.locks = locks
|
|
local mod = ""
|
|
local locked = false
|
|
for i, color in ipairs(locks) do
|
|
if not locks[color] then locked = true end
|
|
mod = mod..":"..((i -1) *5 +74)..",0=artifact_lock_"..color.."_"..(locks[color] and "on" or "off")..".png"
|
|
end
|
|
e._locked = locked
|
|
e.object:set_properties {
|
|
textures = {"[combine:128x128:0,0=artifact_door_large.png"..mod}
|
|
}
|
|
end,
|
|
})
|
|
|
|
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)
|
|
local locks = minetest.deserialize(m:get("locks") or "return nil") or {red = false, blue = false, green = false, "red", "green", "blue"}
|
|
minetest.add_entity(pos, "artifact:large_door_display", minetest.serialize{locks = locks}):get_luaentity():rotate(rot)
|
|
m:set_string("locks", minetest.serialize(locks))
|
|
end
|
|
end
|
|
|
|
local function ondestruct(pos)
|
|
large_doors[pos:to_string()].object:remove()
|
|
large_doors[pos:to_string()] = nil
|
|
end
|
|
|
|
local function onsignal(pos, event, channel)
|
|
if event.type == "on" or event.type == "pulse" then
|
|
local e = large_doors[vector.to_string(pos)]
|
|
if e then
|
|
local locks = e.locks
|
|
if locks[channel] ~= nil then
|
|
locks[channel] = true
|
|
end
|
|
artifact.play_sound {
|
|
name = "artifact_lock_light",
|
|
pos = e.object:get_pos(),
|
|
range = 10,
|
|
}
|
|
local idx = table.indexof(locks, channel)
|
|
local rot = artifact.facedir_to_rotation(minetest.get_node(pos).param2)
|
|
minetest.add_particlespawner {
|
|
pos = pos +vector.new(-0.6 +(idx *0.3), 2.25, -0.2):rotate(rot),
|
|
vel = {
|
|
min = vector.new(-1, 0, -1):rotate(rot),
|
|
max = vector.new(1, 2, -0.2):rotate(rot),
|
|
},
|
|
acc = vector.new(0, -9.81, 0),
|
|
texture = {
|
|
name = "[fill:1x1:0,0:"..artifact.colors[channel],
|
|
alpha_tween = {1, 0}
|
|
},
|
|
glow = 8,
|
|
time = 0.1,
|
|
size = 0.25,
|
|
amount = 20,
|
|
exptime = 0.3
|
|
}
|
|
minetest.add_particlespawner {
|
|
pos = pos +vector.new(-0.6 +(idx *0.3), 2.25, 0.2):rotate(rot),
|
|
vel = {
|
|
min = vector.new(-1, 0, 0.2):rotate(rot),
|
|
max = vector.new(1, 2, 1):rotate(rot),
|
|
},
|
|
acc = vector.new(0, -8, 0),
|
|
texture = {
|
|
name = "[fill:1x1:0,0:"..artifact.colors[channel],
|
|
alpha_tween = {1, 0}
|
|
},
|
|
glow = 8,
|
|
time = 0.1,
|
|
size = 0.25,
|
|
amount = 20,
|
|
exptime = 0.3
|
|
}
|
|
e:set_locks(locks)
|
|
minetest.get_meta(pos):set_string("locks", minetest.serialize(locks))
|
|
else
|
|
local m = minetest.get_meta(pos)
|
|
local locks = minetest.deserialize(m:get_string("locks"))
|
|
if locks[channel] ~= nil then
|
|
locks[channel] = true
|
|
end
|
|
e:set_locks(locks)
|
|
m:set_string("locks", minetest.serialize(locks))
|
|
end
|
|
end
|
|
end
|
|
|
|
artifact.register_node("large_door", {
|
|
drawtype = "airlike",
|
|
paramtype = "light",
|
|
walkable = false,
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
-1.5, -0.5, -2/16,
|
|
1.5, 3.5, 2/16
|
|
}
|
|
},
|
|
paramtype2 = "facedir",
|
|
groups = {call_on_load = 1},
|
|
on_construct = onload,
|
|
on_load = onload,
|
|
on_destruct = ondestruct,
|
|
on_signal = onsignal
|
|
})
|