insidethebox/mods/boxes/nodes.lua

982 lines
28 KiB
Lua

local function register_teleport(name, def)
local function teleport_update_particles(pos, pname)
local tm = math.random(10, 50) / 10
minetest.add_particlespawner({
amount = tm * 3,
time = tm,
minpos = {x = pos.x - 7/16, y = pos.y - 5/16, z = pos.z - 7/16},
maxpos = {x = pos.x + 7/16, y = pos.y - 5/16, z = pos.z + 7/16},
minvel = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
--collisiondetection = true,
--collision_removal = true,
texture = def.tiles[1],
playername = pname,
})
minetest.get_node_timer(pos):start(tm)
end
def.drawtype = "nodebox"
def.node_box = {
type = "fixed",
fixed = {{-7/16, -1/2, -7/16, 7/16, -7/16, 7/16}},
}
def.paramtype = "light"
def.groups = def.groups or {}
def.sounds = def.sounds or sounds.metal
def.on_construct = function(pos)
teleport_update_particles(pos, nil)
end
def.on_timer = function(pos)
teleport_update_particles(pos, nil)
end
def.after_box_construct = function(pos)
teleport_update_particles(pos, nil)
end
-- on_teleport: return true to nudge
-- player back off the teleport
local on_teleport = def.on_teleport
def.on_walk_over = function(pos, node, player)
if on_teleport(pos, node, player) then
local dir = player:get_look_dir()
dir.y = 0
player:setpos(vector.subtract(pos, vector.normalize(dir)))
end
end
minetest.register_node(name, def)
end
local context = {}
local function series_progress_reset(player, id)
-- show a formspec to the user where they can explicitly reset
-- series progress, and explain why they might not want to do so
local name = player:get_player_name()
context[name] = id
--FIXME change this to a bunch of labels.
minetest.show_formspec(name, "series:reset",
"size[10,7]" ..
"textlist[0.5,0.5;8.7,4.5;restettext;You have already completed this series.,," ..
"If you want\\, you can reset your progress for this series," ..
"and start it again from the start.,," ..
"Or\\, you can wait for more boxes to get added to this," ..
"series later\\, and come back regularly to check if that," ..
"has happened.;0;0]" ..
"button[0.6,5.5;4.4,1.5;btn_cancel;I'll come back later]" ..
"button[5.0,5.5;4.4,1.5;btn_reset;Reset progress]"
)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "series:reset" then
return false
end
local name = player:get_player_name()
minetest.close_formspec(name, "")
if not context[name] then
log.fs_data(player, name, formname, fields)
return true
end
if not fields.btn_reset then
context[name] = nil
return true
end
-- reset series progress
local id = context[name]
local pmeta = db.player_get_meta(name)
pmeta.series_progress[id] = nil
db.player_set_meta(name, pmeta)
minetest.chat_send_player(player:get_player_name(),
"Reset progress for series " .. id)
context[name] = nil
return true
end)
local function series_enter_choice(player, id)
-- Show a formspec allowing the user to choose what box they want to enter
local name = player:get_player_name()
local f = "size[6,9]"
f = f .. "textlist[0.2,0.5;5.4,7.4;in_series;"
local boxes = db.series_get_boxes(id)
local player_id = db.player_get_id(name)
local completed = db.player_get_series_boxes(player_id, id)
local complete = {}
for _, v in ipairs(completed) do
complete[v] = true
end
for k, box_id in pairs(boxes) do
local bmeta = db.box_get_meta(box_id)
local bname = bmeta.meta.box_name or "[unnamed]"
local color = "#c0c0c0"
if complete[box_id] then
color = "#00ff00"
end
f = f .. color
f = f .. minetest.formspec_escape("[" .. box_id .. "] " .. bname)
if k ~= #boxes then
f = f .. ","
end
end
f = f .. ";]"
f = f .. "button[1.4,8.1;3.4,1;enter;Play]"
minetest.show_formspec(name, "series:enter_choice", f)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "series:enter_choice" then
return false
end
local name = player:get_player_name()
if not context[name] then
log.fs_data(player, name, formname, fields)
return true
end
if fields.in_series then
local i = tonumber(string.match(fields.in_series, ":(%d+)", 1))
context[name].b_sel = i
series_enter_choice(player, context[name].id)
return true
end
if fields.enter then
if not context[name].id or not context[name].b_sel then
return true
end
minetest.close_formspec(name, "")
local i = context[name].b_sel
local id = context[name].id
local pmeta = db.player_get_meta(name)
pmeta.series_progress[id] = i
db.player_set_meta(name, pmeta)
boxes.next_series(player, id, true)
context[name] = nil
return true
end
context[name] = nil
return true
end)
register_teleport("boxes:enter_teleport", {
description = "Enter teleport",
tiles = {"diamond.png"},
on_teleport = function(pos, node, player)
local meta = minetest.get_meta(pos)
local id = meta:get_int("box")
if meta:get_int("is_series") == 1 then
local smeta = db.series_get_meta(id)
if not smeta then
return
end
if smeta.meta.type == db.SEQUENTIAL_TYPE then
if not boxes.next_series(player, id, true) then
series_progress_reset(player, id)
return true
end
elseif smeta.meta.type == db.RANDOM_ACCESS_TYPE then
context[player:get_player_name()] = {id = id}
series_enter_choice(player, id)
return true
end
return
end
local bmeta = db.box_get_meta(id)
if bmeta.type ~= db.BOX_TYPE then
return
end
boxes.open_box(player, {0, id, 1})
end,
on_punch = function(pos, node, puncher, pointed_thing)
if not puncher or not minetest.check_player_privs(puncher, "server") then
return
end
local meta = minetest.get_meta(pos)
if puncher:get_player_control().sneak then
local is_series = meta:get_int("is_series")
meta:set_int("is_series", 1 - is_series)
minetest.chat_send_player(puncher:get_player_name(), "Destination is" ..
((is_series == 0) and " " or " not ") .. "a series")
return
end
local id = meta:get_int("box")
local newid = id + 1
if not db.box_exists(newid) then
newid = 0
end
meta:set_int("box", newid)
minetest.chat_send_player(puncher:get_player_name(), "Destination set to " .. newid)
end,
on_rightclick = function(pos, node, puncher, pointed_thing)
if not puncher or not minetest.check_player_privs(puncher, "server") then
return
end
local meta = minetest.get_meta(pos)
local id = meta:get_int("box")
local newid = id - 1
if not db.box_exists(newid) then
newid = db.get_last_box_id()
end
meta:set_int("box", newid)
minetest.chat_send_player(puncher:get_player_name(), "Destination set to " .. newid)
end,
})
register_teleport("boxes:exit_teleport", {
description = "Exit teleport",
tiles = {"diamond.png"},
on_teleport = function(pos, node, player)
local name = player:get_player_name()
if not boxes.players_in_boxes[name] then
return
end
local bx = boxes.players_in_boxes[name]
local stars = 0
for _, p in ipairs(bx.star_positions) do
local star_node = minetest.get_node(p)
local nodedef = minetest.registered_nodes[star_node.name]
if nodedef and nodedef.groups and nodedef.groups.star and nodedef.groups.star > 0 then
stars = stars + 1
end
end
local icons = {}
local icon_ids = {}
for _, p in ipairs(bx.category_positions) do
local sign_node = minetest.get_node(p)
local nodedef = minetest.registered_nodes[sign_node.name]
if nodedef and nodedef.groups and nodedef.groups.icon and nodedef.groups.icon > 0 and
nodedef.icon_name and nodedef.icon_name ~= "nil" then
icons[#icons + 1] = nodedef.icon_name
-- omit "nil" icon - nothing selected
if nodedef.icon_id > 1 then
icon_ids[#icon_ids + 1] = nodedef.icon_id
end
end
end
local ic = ""
for i, iname in ipairs(icons) do
if i > 1 then
ic = ic .. ", "
end
ic = ic .. iname
end
-- record rating/icons if needed
if stars > 0 then
boxes.score(name, bx.box_id, "rating", {stars})
end
if #icon_ids > 0 then
boxes.score(name, bx.box_id, "category", icon_ids)
end
local sid = boxes.players_in_boxes[name].in_series
boxes.close_box(player)
if sid then
boxes.next_series(player, sid)
else
players.return_to_lobby(player)
end
end,
})
register_teleport("boxes:lobby_teleport", {
description = "Lobby teleport",
tiles = {"blocks_tiles.png^[sheet:8x8:1,2"},
on_teleport = function(pos, node, player)
local name = player:get_player_name()
if not boxes.players_in_boxes[name] then
return
end
boxes.close_box(player)
players.return_to_lobby(player)
end,
})
local get_boxes = function(name)
local is_admin = minetest.check_player_privs(name, "server")
local boxes = {}
for id = 0, db.get_last_box_id() do
local meta = db.box_get_meta(id)
if (meta.type == db.BOX_TYPE and meta.meta and
meta.meta.builder and meta.meta.builder == name) or
(is_admin and meta.type == db.BOX_TYPE) then
table.insert(boxes, {id = id,
name = meta.meta.box_name or "[Unnamed]",
status = meta.meta.status,
builder = meta.meta.builder})
end
end
table.sort(boxes, function(box1, box2)
return box1.status < box2.status or
(box1.status == box2.status and box1.id > box2.id)
end)
return boxes
end
local get_sizes = function(player)
--FIXME link to scoring and limit box sizes for novice builders
return {20, 25, 30, 35, 40}
end
local do_series_if = function(player)
local name = player:get_player_name()
assert(context[name])
local f =
"size[12,9]"
if context[name].exc_sel then
f = f .. "button[5.6,3;1,1;add;<<]"
end
if context[name].inc_sel then
f = f .. "button[5.6,4;1,1;remove;>>]"
end
local showall = context[name].showall == "true"
if showall then
f = f .. "checkbox[6.5,1;showall;Show all boxes;true]"
else
f = f .. "checkbox[6.5,1;showall;Show all boxes;false]"
end
f = f .. "dropdown[0.5,1;5.45;series;"
local series = db.series_get_series()
local s_sel = ""
for k, v in pairs(series) do
f = f .. "{" .. v.id .. "} " .. minetest.formspec_escape(v.name)
if k ~= #series then
f = f .. ","
end
if context[name].series_id and context[name].series_id == v then
s_sel = k
end
end
f = f .. ";" .. s_sel .. "]"
local series_id = context[name].series_id
if series_id then
local smeta = db.series_get_meta(series_id)
f = f .. "field[0.8,2.35;5.2,1;series_name;Name;" ..
minetest.formspec_escape(smeta.name) .. "]" ..
"field_close_on_enter[series_name;false]"
f = f .. "dropdown[6.5,2;5.45;series_type;" ..
"Sequential,Random access" ..
";" .. (1 + smeta.meta.type) .. "]"
f = f .. "textlist[0.5,3;5,6;list_included;"
local boxes = db.series_get_boxes(series_id)
context[name].inc = boxes
for k, box_id in pairs(boxes) do
local bmeta = db.box_get_meta(box_id)
local bname = bmeta.meta.box_name or "[unnamed]"
if bmeta.meta.status == db.STATUS_SUBMITTED then
f = f .. "#FF8800"
elseif bmeta.meta.status == db.STATUS_ACCEPTED then
f = f .. "#00FF00"
elseif bmeta.meta.builder ~= name then
f = f .. "#FFFFAA"
end
f = f .. minetest.formspec_escape("[" .. box_id .. "] " .. bname)
if k ~= #boxes then
f = f .. ","
end
end
f = f .. ";]"
f = f .. "textlist[6.5,3;5,6;list_excluded;"
local b_all
if showall then
-- list all boxes not in current series
b_all = db.series_get_boxes_not_in(series_id)
else
-- list boxes not in any series (unreachable)
b_all = db.series_get_boxes_not_in()
end
-- don't show non-accepted boxes here, at all
local b = {}
local b_size = 1
for k, box_id in ipairs(b_all) do
local bmeta = db.box_get_meta(box_id)
if bmeta.meta.status == db.STATUS_ACCEPTED then
b[b_size] = box_id
b_size = b_size + 1
end
end
context[name].exc = b
for k, box_id in ipairs(b) do
local bmeta = db.box_get_meta(box_id)
if bmeta.meta.status == db.STATUS_SUBMITTED then
f = f .. "#FF8800"
elseif bmeta.meta.status == db.STATUS_ACCEPTED then
f = f .. "#00FF00"
elseif bmeta.meta.builder ~= name then
f = f .. "#FFFFAA"
end
local bname = bmeta.meta.box_name or "[unnamed]"
f = f .. minetest.formspec_escape("[" .. box_id .. "] " .. bname)
if k ~= #b then
f = f .. ","
end
end
f = f .. ";]"
end
minetest.show_formspec(player:get_player_name(), "boxes:series", f)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "boxes:series" then
return false
end
local name = player:get_player_name()
if fields.quit then
context[name] = nil
return true
end
-- minimum required permissions
if not minetest.check_player_privs(name, "server") then
log.fs_data(player, name, formname, fields)
context[name] = nil
return true
end
if not context[name] then
log.fs_data(player, name, formname, fields)
context[name] = nil
return true
end
if fields.showall then
context[name].showall = fields.showall
do_series_if(player)
return true
end
if fields.list_included then
local i = tonumber(string.match(fields.list_included, ":(%d+)", 1))
context[name].inc_sel = context[name].inc[i]
do_series_if(player)
return true
end
if fields.list_excluded then
local i = tonumber(string.match(fields.list_excluded, ":(%d+)", 1))
context[name].exc_sel = context[name].exc[i]
do_series_if(player)
return true
end
if fields.add then
if context[name].exc_sel and context[name].series_id then
db.series_add_at_end(context[name].series_id, context[name].exc_sel)
minetest.log("action", name .. " added box " .. context[name].exc_sel ..
" to series " .. context[name].series_id)
minetest.chat_send_player(name, " Added box " .. context[name].exc_sel ..
" to series " .. context[name].series_id)
context[name].exc_sel = nil
end
do_series_if(player)
return true
end
if fields.remove then
if context[name].inc_sel and context[name].series_id then
db.series_delete_box(context[name].series_id, context[name].inc_sel)
minetest.log("action", name .. " removed box " .. context[name].inc_sel ..
" from series " .. context[name].series_id)
minetest.chat_send_player(name, " Removed box " .. context[name].inc_sel ..
" from series " .. context[name].series_id)
context[name].inc_sel = nil
end
do_series_if(player)
return true
end
-- These three fields are dropdowns or text fields, and sent every time
-- We need to handle every one of them
if fields.series then
context[name].series_id = tonumber(string.match(fields.series, "{(%d+)}", 1))
end
if fields.series_type then
if context[name].series_id then
local smeta = db.series_get_meta(context[name].series_id)
local ntype = smeta.meta.type
if fields.series_type == "Sequential" then
ntype = db.SEQUENTIAL_TYPE
elseif fields.series_type == "Random access" then
ntype = db.RANDOM_ACCESS_TYPE
end
smeta.meta.type = ntype
db.series_set_meta(context[name].series_id, smeta)
end
end
if fields.series_name then
if context[name].series_id then
local smeta = db.series_get_meta(context[name].series_id)
smeta.name = fields.series_name
db.series_set_meta(context[name].series_id, smeta)
end
end
if fields.series or fields.series_type or fields.series_name then
do_series_if(player)
return true
end
log.fs_data(player, name, formname, fields)
context[name] = nil
return true
end)
do_creator_if = function(player)
local name = player:get_player_name()
if not context[name] then
context[name] = {}
context[name].boxes = get_boxes(name)
context[name].sizes = get_sizes(name)
end
local counts = {
accepted = 0,
submitted = 0,
editing = 0
}
local f =
"size[12, 8]" ..
"field_close_on_enter[input;false]" ..
"textlist[0.4,0.5;7.2,7.3;boxes;"
--list of boxes owned, or all in case of admin
for i, v in ipairs(context[name].boxes) do
if i > 1 then f = f .. "," end
local text = ""
if v.status == db.STATUS_SUBMITTED then
text = "#FF8800"
counts.submitted = counts.submitted + 1
elseif v.status == db.STATUS_ACCEPTED then
text = "#00FF00"
counts.accepted = counts.accepted + 1
else
if v.builder ~= name then
text = "#FFFFAA"
end
counts.editing = counts.editing + 1
end
text = text .. v.id .. " - " .. minetest.formspec_escape(v.name)
if v.builder ~= name then
text = text .. " (" .. minetest.formspec_escape(v.builder or "") .. ")"
end
f = f .. text
end
f = f .. "]"
if minetest.check_player_privs(name, "server") then
f = f .. "button[8.4,0;3.4,1;series;Manage Series]"
end
local limit = tonumber(player:get_attribute("box_create_limit") or "3")
if (minetest.check_player_privs(name, "create") and counts.editing + counts.submitted <= limit) or
minetest.check_player_privs(name, "server") then
context[name].cancreate = true
f = f .. "button[8.4,1;3.4,1;new;Create new]"
elseif not context[name].limitreached then
context[name].limitreached = true
minetest.chat_send_player(name, "You have too many unfinished boxes. Box creation will " ..
"become available again once your boxes get accepted.")
end
if context[name].box and context[name].box.status == db.STATUS_EDITING then
f = f .. "button[8.4,3;3.4,1;submit;Submit]"
elseif minetest.check_player_privs(name, "server") and context[name].box and
context[name].box.status == db.STATUS_SUBMITTED then
f = f .. "button[8.4,3;3.4,1;reject;Reject]"
f = f .. "button[8.4,4;3.4,1;accept;Accept]"
elseif context[name].box and context[name].box.status == db.STATUS_SUBMITTED then
f = f .. "button[8.4,3;3.4,1;retract;Retract]"
end
if not context[name].box or context[name].box.status == db.STATUS_EDITING then
f = f .. "button[8.4,7;3.4,1;edit;Edit]"
elseif minetest.check_player_privs(name, "server") then
f = f .. "button[8.4,7;3.4,1;edit;Force edit]"
end
if context[name].box then
f = f .. "button[8.4,6;3.4,1;play;Play]"
end
minetest.show_formspec(player:get_player_name(), "boxes:create", f)
end
local do_creator_size_if = function(player)
local name = player:get_player_name()
assert(context[name])
local f =
"size[6.2, 6]" ..
"field_close_on_enter[input;false]" ..
"textlist[0.4,0.5;5.2,4.3;sizes;"
for i, v in ipairs(context[name].sizes) do
if i > 1 then f = f .. "," end
f = f .. tostring(v)
end
f = f ..
"]" ..
"button[0.4,5;5.4,1;create;Choose selected size]"
minetest.show_formspec(player:get_player_name(), "boxes:create", f)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "boxes:create" then
return false
end
local name = player:get_player_name()
if fields.quit then
return true
end
-- minimum required permissions
if not minetest.check_player_privs(name, "create") and
not minetest.check_player_privs(name, "server") then
log.fs_data(player, name, formname, fields)
context[name] = nil
return true
end
if not context[name] then
log.fs_data(player, name, formname, fields)
return true
end
local meta = nil
-- makes reading the code below a bit easier
local function box_set_status(id, status)
if not meta then
meta = db.box_get_meta(id)
assert(meta.meta)
end
meta.meta.status = status
db.box_set_meta(id, meta)
end
local function box_get_status(id)
if not meta then
meta = db.box_get_meta(id)
assert(meta.meta)
end
return meta.meta.status
end
local is_admin = minetest.check_player_privs(name, "server")
-- sadly a function, because meta may be nil
local function is_builder(id)
if not meta then
meta = db.box_get_meta(id)
assert(meta.meta)
end
return meta.meta.builder == name
end
if fields.boxes and fields.boxes ~= "INV" then
local s, _ = fields.boxes:gsub(".*:(.*)", "%1")
if not s then
log.fs_data(player, name, formname, fields)
return true
end
local n = tonumber(s, 10)
if n and context[name].boxes[n] then
context[name].box = context[name].boxes[n]
do_creator_if(player)
else
log.fs_data(player, name, formname, fields)
end
elseif fields.play and context[name].box then
local id = context[name].box.id
if is_admin or box_get_status(id) == db.STATUS_ACCEPTED or is_builder(id) then
minetest.chat_send_player(name, "Playing box " .. tostring(id))
minetest.registered_chatcommands["enter"].func(name, tostring(id))
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.edit and context[name].box then
local id = context[name].box.id
if is_admin or (box_get_status(id) == db.STATUS_EDITING and is_builder(id)) then
minetest.chat_send_player(name, "Editing box " .. tostring(id))
minetest.registered_chatcommands["edite"].func(name, tostring(id))
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.submit and context[name].box then
local id = context[name].box.id
if is_admin or (box_get_status(id) == db.STATUS_EDITING and is_builder(id)) then
minetest.chat_send_player(name, "Submitting box " .. tostring(id))
minetest.log("action", name .. " submits box " .. tostring(id))
if irc then
irc.say(name .. " has submitted a box for review")
end
box_set_status(id, db.STATUS_SUBMITTED)
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.accept and context[name].box then
local id = context[name].box.id
if is_admin and box_get_status(id) == db.STATUS_SUBMITTED then
minetest.chat_send_player(name, "Accepting box " .. tostring(id))
minetest.log("action", name .. " accepts box " .. tostring(id))
box_set_status(id, db.STATUS_ACCEPTED)
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.retract and context[name].box then
local id = context[name].box.id
if is_builder(id) and box_get_status(id) == db.STATUS_SUBMITTED then
minetest.chat_send_player(name, "Retracted box " .. tostring(id))
minetest.log("action", name .. " retracts box " .. tostring(id))
box_set_status(id, db.STATUS_EDITING)
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.reject and context[name].box then
local id = context[name].box.id
if is_admin and box_get_status(id) == db.STATUS_SUBMITTED then
minetest.chat_send_player(name, "Rejecting box " .. tostring(id))
minetest.log("action", name .. " rejects box " .. tostring(id))
box_set_status(id, db.STATUS_EDITING)
else
log.fs_data(player, name, formname, fields)
end
minetest.close_formspec(name, "")
context[name] = nil
elseif fields.new and context[name].cancreate then
do_creator_size_if(player)
elseif fields.series and is_admin then
context[name] = {}
do_series_if(player)
elseif fields.sizes then
local s, _ = fields.sizes:gsub(".*:(.*)", "%1")
context[name].size = context[name].sizes[tonumber(s, 10)]
elseif fields.create and context[name] and context[name].size and context[name].cancreate then
minetest.close_formspec(name, "")
minetest.chat_send_player(name, "Creating a new box with size " .. context[name].size)
minetest.log("action", name .. " creates a new box with size " .. context[name].size)
boxes.make_new(player, context[name].size)
context[name] = nil
else
log.fs_data(player, name, formname, fields)
context[name] = nil
end
return true
end)
register_teleport("boxes:creator_teleport", {
description = "Creator teleport",
tiles = {"blocks_tiles.png^[sheet:8x8:2,2"},
on_teleport = function(pos, node, player)
context[player:get_player_name()] = nil
do_creator_if(player)
return true
end,
})
minetest.register_node("boxes:nexus", {
description = "Nexus",
drawtype = "mesh",
mesh = "nexus.obj",
paramtype = "light",
paramtype2 = "facedir",
light_source = 6,
tiles = {
{
name = "nexus.png",
animation = {
type = "vertical_frames",
aspect_w = 48,
aspect_h = 16,
length = 6.25,
}
},
},
selection_box = {
type = "fixed",
fixed = {-3/8, -3/8, -3/8, 3/8, 3/8, 3/8},
},
collision_box = {
type = "fixed",
fixed = {-3/8, -3/8, -3/8, 3/8, 3/8, 3/8},
},
group = {node = 0, nexus = 1},
node_placement_prediction = "",
on_place = function(itemstack, placer, pointed_thing, param2)
-- Can't be placed, will only trigger on_rightclick if defined
if pointed_thing.type == "node" then
local n = minetest.get_node(pointed_thing.under)
local nn = n.name
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n,
placer, itemstack, pointed_thing) or itemstack, false
end
end
return itemstack
end,
on_trigger = function() end,
on_untrigger = function() end,
groups = {not_in_creative_inventory = 1},
})
minetest.register_node("boxes:nexus_large", {
description = "Nexus",
drawtype = "mesh",
mesh = "nexus.obj",
paramtype = "light",
paramtype2 = "facedir",
visual_scale = 4.0,
tiles = {
{
name = "nexus.png",
animation = {
type = "vertical_frames",
aspect_w = 48,
aspect_h = 16,
length = 6.25,
}
},
},
selection_box = {
type = "fixed",
fixed = {-3/8, -3/8, -3/8, 3/8, 3/8, 3/8},
},
collision_box = {
type = "fixed",
fixed = {-3/8, -3/8, -3/8, 3/8, 3/8, 3/8},
},
group = {node = 0},
on_construct = function(pos)
-- flip after 2 cycles
minetest.get_node_timer(pos):start(12.5)
end,
on_timer = function(pos, node)
-- make it self-rotate randomly
minetest.swap_node(pos, {name = "boxes:nexus_large", param2 = math.random(24) - 1})
end,
groups = {not_in_creative_inventory = 1},
})
minetest.register_craftitem("boxes:set_door", {
description = "Place or move entry and exit doors\nEntry door must be on the west wall.\n" ..
"Exit door must be on the east wall.",
inventory_image = "set_door_tool.png",
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" or not placer then
return
end
local name = placer:get_player_name()
local pos = pointed_thing.under
if not boxes.players_editing_boxes[name] then
return
end
local box = boxes.players_editing_boxes[name]
local pos1
local pos2
local dir
local wallnode = {name = "nodes:marbleb"}
if pos.x == box.minp.x then
if pos.y <= box.minp.y or pos.y >= box.maxp.y - 2
or pos.z <= box.minp.z or pos.z >= box.maxp.z - 2
then
return
end
pos1 = pos
pos2 = {x = pos.x, y = pos.y, z = pos.z + 1}
dir = 3
for y = box.entry.y, box.entry.y + 1 do
for z = box.entry.z, box.entry.z + 1 do
minetest.set_node({x = pos.x, y = y, z = z}, wallnode)
end
end
box.entry = {x = pos.x, y = pos.y, z = pos.z}
elseif pos.x == box.maxp.x then
if pos.y <= box.minp.y or pos.y >= box.maxp.y - 2
or pos.z <= box.minp.z + 1 or pos.z >= box.maxp.z - 1
then
return
end
pos1 = pos
pos2 = {x = pos.x, y = pos.y, z = pos.z - 1}
dir = 1
for y = box.exit.y, box.exit.y + 1 do
for z = box.exit.z, box.exit.z + 1 do
minetest.set_node({x = pos.x, y = y, z = z}, wallnode)
end
end
box.exit = {x = pos.x + 1, y = pos.y, z = pos.z - 1}
elseif pos.z == box.minp.z then
pos.x = math.min(pos.x, box.maxp.x - ((string.len(box.box_id) * 4) - 1))
pos.y = math.min(pos.y, box.maxp.y - 5)
boxes.move_digits(placer, pos)
return
else
return
end
local door_name = "doors:door_steel"
local state1 = 0
local state2 = 2
local meta1 = minetest.get_meta(pos1)
local meta2 = minetest.get_meta(pos2)
local above1 = vector.add(pos1, {x = 0, y = 1, z = 0})
local above2 = vector.add(pos2, {x = 0, y = 1, z = 0})
minetest.set_node(pos1, {name = door_name .. "_a", param2 = dir})
minetest.set_node(above1, {name = "doors:hidden", param2 = dir})
meta1:set_int("state", state1)
meta1:set_string("doors_owner", "boxes:door owner")
minetest.set_node(pos2, {name = door_name .. "_b", param2 = dir})
minetest.set_node(above2, {name = "doors:hidden", param2 = (dir + 3) % 4})
meta2:set_int("state", state2)
meta2:set_string("doors_owner", "boxes:door owner")
end,
})
frame.register("boxes:set_door")