281 lines
7.8 KiB
Lua
281 lines
7.8 KiB
Lua
--[[
|
|
|
|
Hyperloop Mod
|
|
=============
|
|
|
|
Copyright (C) 2017 Joachim Stolberg
|
|
|
|
LGPLv2.1+
|
|
See LICENSE.txt for more information
|
|
|
|
History:
|
|
see init.lua
|
|
|
|
]]--
|
|
|
|
-- Tube chain arrangement:
|
|
-- [0] = tube0 (single node)
|
|
-- [1] = tube1 (head node)
|
|
-- [2] = tube2 (link node)
|
|
-- [J] = junction
|
|
--
|
|
-- [0] [1]-[1] [1]-[2]-[1] [J]-[1]-[2]-...-[2]-[1]-[J]
|
|
|
|
|
|
-- Scan all 8 neighbor positions for tube nodes.
|
|
-- Return:
|
|
-- 0, nodes - no node available
|
|
-- 1, nodes - one head/single node available
|
|
-- 3, nodes - two head nodes available
|
|
-- 4, nodes - one link node available
|
|
-- 5, nodes - invalid position
|
|
-- 12, nodes - two link nodes available
|
|
function hyperloop.scan_neighbours(pos)
|
|
local nodes = {}
|
|
local node, npos, idx
|
|
local res = 0
|
|
for _,dir in ipairs(hyperloop.NeighborPos) do
|
|
npos = vector.add(pos, dir)
|
|
node = minetest.get_node(npos)
|
|
if string.find(node.name, "hyperloop:tube") then
|
|
node.pos = npos
|
|
table.insert(nodes, node)
|
|
-- tubes on invalid level?
|
|
if not hyperloop.free_tube_placement_enabled and npos.y ~= pos.y then
|
|
return 5, nodes
|
|
end
|
|
idx = string.byte(node.name, -1) - 48
|
|
if idx == 0 then -- single node?
|
|
idx = 1
|
|
elseif idx == 2 then -- link node?
|
|
idx = 4
|
|
end
|
|
res = res * 2 + idx
|
|
end
|
|
end
|
|
if res > 4 and res ~= 12 then
|
|
res = 5
|
|
end
|
|
return res, nodes
|
|
end
|
|
|
|
-- update head tube meta data
|
|
-- param pos: position as string
|
|
-- param peer_pos: position as string
|
|
function hyperloop.update_head_node(pos, peer_pos)
|
|
if hyperloop.debugging then
|
|
print("update head node(pos="..pos.." peer_pos="..peer_pos..")")
|
|
end
|
|
pos = minetest.string_to_pos(pos)
|
|
if pos ~= nil then
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("peer", peer_pos)
|
|
meta:set_string("infotext", peer_pos)
|
|
hyperloop.update_junction(pos)
|
|
end
|
|
end
|
|
|
|
|
|
-- Degrade one node.
|
|
-- Needed when a new node is placed nearby.
|
|
function hyperloop.degrade_tupe_node(node, new_node_pos)
|
|
if node.name == "hyperloop:tube0" then
|
|
node.name = "hyperloop:tube1"
|
|
elseif node.name == "hyperloop:tube1" then
|
|
node.name = "hyperloop:tube2"
|
|
node.diggable = false
|
|
minetest.get_meta(node.pos):from_table(nil)
|
|
else
|
|
return
|
|
end
|
|
-- determine the correct tube facedir
|
|
local dir = vector.subtract(node.pos, new_node_pos)
|
|
node.param2 = minetest.dir_to_facedir(dir)
|
|
minetest.swap_node(node.pos, node)
|
|
end
|
|
|
|
-- Remove the given node
|
|
function hyperloop.remove_node(pos, node)
|
|
-- can't call "remove_node(pos)" because subsequently "on_destruct" will be called
|
|
node.name = "air"
|
|
node.diggable = true
|
|
minetest.swap_node(pos, node)
|
|
end
|
|
|
|
-- Upgrade the tube and add meta data
|
|
-- param node: node to be replaced
|
|
-- param peer_pos: peer node position as string
|
|
function hyperloop.swap_tube_node(node, peer_pos)
|
|
local pos = minetest.pos_to_string(node.pos)
|
|
hyperloop.update_head_node(pos, peer_pos)
|
|
hyperloop.update_head_node(peer_pos, pos)
|
|
-- upgrade
|
|
node.diggable = true
|
|
if node.name == "hyperloop:tube2" then -- 2 connections?
|
|
node.name = "hyperloop:tube1"
|
|
elseif node.name == "hyperloop:tube1" then -- 1 connection?
|
|
node.name = "hyperloop:tube0"
|
|
end
|
|
minetest.get_meta(node.pos):set_string("infotext", peer_pos)
|
|
minetest.swap_node(node.pos, node)
|
|
end
|
|
|
|
-- Upgrade one node.
|
|
-- Needed when a tube node is digged.
|
|
function hyperloop.upgrade_node(digged_node_pos)
|
|
local res, nodes = hyperloop.scan_neighbours(digged_node_pos)
|
|
if res == 1 or res == 4 then
|
|
local new_head_node = nodes[1]
|
|
-- copy peer pos first
|
|
local peer_pos = minetest.get_meta(digged_node_pos):get_string("peer")
|
|
hyperloop.swap_tube_node(new_head_node, peer_pos)
|
|
end
|
|
end
|
|
|
|
-- Place a node without neighbours
|
|
local function single_node(node)
|
|
local meta = minetest.get_meta(node.pos)
|
|
local str_pos = minetest.pos_to_string(node.pos)
|
|
meta:set_string("peer", str_pos)
|
|
minetest.get_meta(node.pos):set_string("infotext", str_pos)
|
|
-- upgrade self to single node
|
|
node.name = "hyperloop:tube0"
|
|
minetest.swap_node(node.pos, node)
|
|
return true
|
|
end
|
|
|
|
-- Place a node with one neighbor
|
|
local function head_node(node, old_head)
|
|
-- determine peer pos
|
|
local peer_pos = minetest.get_meta(old_head.pos):get_string("peer")
|
|
-- update self
|
|
local str_pos = minetest.pos_to_string(node.pos)
|
|
hyperloop.update_head_node(str_pos, peer_pos)
|
|
-- update peer
|
|
hyperloop.update_head_node(peer_pos, str_pos)
|
|
-- upgrade self
|
|
minetest.get_meta(node.pos):set_string("infotext", peer_pos)
|
|
node.name = "hyperloop:tube1"
|
|
-- determine the correct tube facedir
|
|
local dir = vector.subtract(node.pos, old_head.pos)
|
|
node.param2 = minetest.dir_to_facedir(dir)
|
|
minetest.swap_node(node.pos, node)
|
|
-- degrade old head
|
|
hyperloop.degrade_tupe_node(old_head, node.pos)
|
|
return true
|
|
end
|
|
|
|
local function link_node(node, node1, node2)
|
|
-- both nodes on the same level?
|
|
if node1.pos.y == node2.pos.y then
|
|
-- determine the meta data from both head nodes
|
|
local pos1 = minetest.get_meta(node1.pos):get_string("peer")
|
|
local pos2 = minetest.get_meta(node2.pos):get_string("peer")
|
|
if minetest.pos_to_string(node1.pos) == pos2 then -- closed tube ring?
|
|
return false
|
|
end
|
|
-- exchange position data
|
|
hyperloop.update_head_node(pos1, pos2)
|
|
hyperloop.update_head_node(pos2, pos1)
|
|
-- set to tube2
|
|
node.name = "hyperloop:tube2"
|
|
node.diggable = true
|
|
minetest.swap_node(node.pos, node)
|
|
-- degrade both nodes
|
|
hyperloop.degrade_tupe_node(node1, node.pos)
|
|
hyperloop.degrade_tupe_node(node2, node.pos)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- called when a new node is placed
|
|
local function node_placed(pos, itemstack, placer)
|
|
local res, nodes = hyperloop.scan_neighbours(pos)
|
|
local node = minetest.get_node(pos)
|
|
local placed = false
|
|
node.pos = pos
|
|
if res == 0 then -- no neighbor available?
|
|
hyperloop.check_network_level(node.pos, placer)
|
|
placed = single_node(node)
|
|
elseif res == 1 then -- one neighbor available?
|
|
placed = head_node(node, nodes[1])
|
|
elseif res == 3 then -- two neighbours available?
|
|
placed = link_node(node, nodes[1], nodes[2])
|
|
end
|
|
if not placed then
|
|
hyperloop.remove_node(pos, node)
|
|
return itemstack
|
|
end
|
|
hyperloop.update_junction(pos)
|
|
end
|
|
|
|
-- simple tube without logic or "memory"
|
|
minetest.register_node("hyperloop:tube2", {
|
|
description = "Hyperloop Tube",
|
|
tiles = {
|
|
-- up, down, right, left, back, front
|
|
"hyperloop_tube_locked.png^[transformR90]",
|
|
"hyperloop_tube_locked.png^[transformR90]",
|
|
"hyperloop_tube_locked.png",
|
|
},
|
|
|
|
diggable = false,
|
|
paramtype2 = "facedir",
|
|
groups = {cracky=1, not_in_creative_inventory=1},
|
|
is_ground_content = false,
|
|
sounds = default.node_sound_metal_defaults(),
|
|
})
|
|
|
|
-- single-node and head-node with meta data about the peer head node position
|
|
for idx = 0,1 do
|
|
minetest.register_node("hyperloop:tube"..idx, {
|
|
description = "Hyperloop Tube",
|
|
tiles = {
|
|
-- up, down, right, left, back, front
|
|
"hyperloop_tube_locked.png^[transformR90]",
|
|
"hyperloop_tube_locked.png^[transformR90]",
|
|
'hyperloop_tube_closed.png',
|
|
'hyperloop_tube_closed.png',
|
|
'hyperloop_tube_open.png',
|
|
'hyperloop_tube_open.png',
|
|
},
|
|
|
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
|
return node_placed(pos, itemstack, placer)
|
|
end,
|
|
|
|
on_destruct = function(pos)
|
|
hyperloop.upgrade_node(pos)
|
|
hyperloop.update_junction(pos)
|
|
end,
|
|
|
|
paramtype2 = "facedir",
|
|
groups = {cracky=2, not_in_creative_inventory=idx},
|
|
is_ground_content = false,
|
|
drop = "hyperloop:tube0",
|
|
sounds = default.node_sound_metal_defaults(),
|
|
})
|
|
end
|
|
|
|
-- for tube viaducts
|
|
minetest.register_node("hyperloop:pillar", {
|
|
description = "Hyperloop Pillar",
|
|
tiles = {"hyperloop_tube_locked.png^[transformR90]"},
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{ -3/8, -4/8, -3/8, 3/8, 4/8, 3/8},
|
|
},
|
|
},
|
|
is_ground_content = false,
|
|
groups = {cracky = 2, stone = 2},
|
|
sounds = default.node_sound_metal_defaults(),
|
|
})
|
|
|
|
|
|
function hyperloop.after_tube_placed(pos, itemstack)
|
|
return node_placed(pos, itemstack) == nil
|
|
end
|