stasis/core.lua

187 lines
5.8 KiB
Lua

--
-- Minetest stasis mod - The 'secure cloaking' stasis system
--
stasis.frozen_players = {}
stasis.freeze_player = function(player, pos, previous_node)
if type(player) == 'string' then
player = cloaking.get_player_by_name(player)
end
local victim = player:get_player_name()
if stasis.frozen_players[victim] then
return
end
-- Cloak player
minetest.chat_send_player(victim, 'You fall into a magical sleep, so deep that the game no longer acknowledges your existence!')
cloaking.cloak(player)
-- Stop player from moving
player:set_detach()
player:set_physics_override({
speed = 0,
jump = 0,
gravity = 0,
sneak = false,
})
-- Teleport player into stasis chamber and record the previous position
local orig_pos = player:get_pos()
local meta = {
pos = orig_pos,
current_pos = orig_pos,
previous = previous_node,
}
if pos then
player:set_pos(pos)
meta.current_pos = pos
end
stasis.frozen_players[victim] = meta
end
-- Unfreezing
stasis.unfreeze_player = cloaking.uncloak
minetest.register_on_joinplayer(function(player)
local victim = player:get_player_name()
-- Was the player in stasis?
if not stasis.frozen_players[victim] then
return
end
-- Allow player to move
player:set_detach()
player:set_physics_override({
speed = 1,
jump = 1,
gravity = 1,
sneak = true,
})
-- Teleport player out of stasis chamber
player:set_pos(stasis.frozen_players[victim].pos)
-- Replace stasis chamber with empty one
local previous_node = stasis.frozen_players[victim].previous
if previous_node then
local pos = stasis.frozen_players[victim].current_pos
if minetest.get_node(pos).name == previous_node .. '_active' then
local meta = minetest.get_meta(pos)
if meta:get_string('victim') == victim then
local p2 = minetest.get_node(pos).param2
minetest.swap_node(pos, {name = previous_node, param2 = p2})
end
end
end
-- Hide formspec
if minetest.close_formspec then
minetest.close_formspec(victim, 'stasis:end_transit')
end
-- Send chat message and remove table entry
stasis.frozen_players[victim] = nil
minetest.chat_send_player(victim, 'You slowly wake up from your time in stasis.')
end)
-- "Empty" all chambers before shutdown
minetest.register_on_shutdown(function()
for _, meta in pairs(stasis.frozen_players) do
if meta.previous then
local p2 = minetest.get_node(meta.current_pos).param2
minetest.swap_node(meta.current_pos, {name = meta.previous, p2})
end
end
end)
-- Allow players to be put in transit
local formspec_transit_start = 'size[4,2.5]no_prepend[]bgcolor[#000;true]'
.. 'label[0,0;You are in transit.]'
.. 'button_exit[0,0.5;4,1;quit;Leave stasis chamber]'
local formspec_transit_end = 'size[4,2.5]'
.. 'label[0,0;You have arrived.]'
.. 'button_exit[0,0.5;4,1;leave_chamber;Leave stasis chamber]'
.. 'button_exit[0,1.5;4,1;quit;Remain in stasis]'
stasis.begin_transit = function(victim, chamber, active_chamber)
if victim and type(victim) ~= 'string' then
victim = victim:get_player_name()
end
if not stasis.frozen_players[victim] or not cloaking.is_cloaked(victim) then
return {name = chamber or 'stasis:chamber'}
end
if not active_chamber then
active_chamber = chamber .. '_active'
end
minetest.show_formspec(victim, 'stasis:in_transit', formspec_transit_start)
return {
name = 'stasis:player',
metadata = minetest.serialize({
player_in_transit = victim,
stasis_chamber = chamber,
active_chamber = active_chamber,
}),
}
end
stasis.end_transit = function(victim, new_pos)
if not stasis.frozen_players[victim] then return false end
local exit_pos = {x = new_pos.x, y = new_pos.y + 1, z = new_pos.z}
stasis.frozen_players[victim].pos = exit_pos
stasis.frozen_players[victim].current_pos = new_pos
if not cloaking.is_cloaked(victim) then
stasis.frozen_players[victim] = nil
return false
end
cloaking.get_player_by_name(victim):set_pos(new_pos)
minetest.show_formspec(victim, 'stasis:end_transit', formspec_transit_end)
return true
end
minetest.register_node('stasis:player', {
description = 'Player in stasis',
stack_max = 1,
tiles = {'player.png^default_glass.png'},
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
paramtype2 = 'facedir',
after_place_node = function(pos, placer, itemstack)
local metadata = minetest.deserialize(itemstack:get_metadata()) or {}
local victim = metadata.player_in_transit or 'singleplayer'
local chamber = metadata.stasis_chamber or 'stasis:chamber'
local active_chamber = metadata.active_chamber or chamber .. '_active'
local p2 = minetest.get_node(pos).param2
minetest.set_node(pos, {name = chamber, param2 = p2})
if minetest.registered_nodes[chamber].on_construct then
minetest.registered_nodes[chamber].on_construct(pos)
end
local meta = minetest.get_meta(pos)
meta:set_string('victim', victim)
if stasis.end_transit(victim, pos) then
minetest.swap_node(pos, {name = active_chamber, param2 = p2})
end
end,
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
if (formname == 'stasis:in_transit' and fields.quit)
or (formname == 'stasis:end_transit' and fields.leave_chamber) then
stasis.unfreeze_player(player)
end
end)