Maksim Gamarnik 239198172f Merge default
Thanks, friend :)
2016-03-04 19:43:29 +02:00

289 lines
6.9 KiB
Lua

local MAX_SECTION_LEN = 20
railtrack = {
rotations = "FLR",
accel_flat = -0.5,
accel_up = -2,
accel_down = 2,
}
railtrack.default_rail = {
description = "Rail",
drawtype = "raillike",
tiles = {"default_rail.png", "default_rail_curved.png",
"default_rail_t_junction.png", "default_rail_crossing.png"},
paramtype = "light",
sunlight_propagates = true,
walkable = false,
is_ground_content = false,
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
groups = {bendy = 2, dig_immediate = 2, attached_node = 1,
connect_to_raillike = minetest.raillike_group("rail")},
railtype = "rail",
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
local def = itemstack:get_definition() or {}
if def.acceleration then
meta:set_string("acceleration", def.acceleration)
end
local junc = {}
local contype = meta:get_string("contype") or ""
local s_cons = meta:get_string("connections") or ""
if contype == "section" then
railtrack:limit_section_len(placer, pos, meta)
elseif s_cons ~= "" then
local cons = minetest.deserialize(s_cons)
for _, con in pairs(cons) do
if railtrack:limit_section_len(placer, con) then
break
end
end
end
end,
on_construct = function(pos)
railtrack:update_rails(pos)
end,
after_destruct = function(pos, oldnode)
local cons = railtrack:get_connections(pos)
for _, p in pairs(cons) do
railtrack:update_rails(p)
end
end,
}
function railtrack:copy(t)
if type(t) ~= "table" then
return t
end
local copy = {}
for k, v in pairs(t) do
copy[k] = v
end
return copy
end
function railtrack:register_rail(name, def)
local udef = {}
for k, v in pairs(railtrack.default_rail) do
if not def[k] then
def[k] = railtrack:copy(v)
end
udef[k] = railtrack:copy(def[k])
end
def.inventory_image = def.inventory_image or def.tiles[1]
def.wield_image = def.wield_image or def.tiles[1]
minetest.register_node(name, def)
udef.drop = name
udef.railtype = udef.railtype.."_union"
udef.groups.not_in_creative_inventory=1
minetest.register_node(name.."_union", udef)
end
function railtrack:limit_section_len(player, pos, meta)
meta = meta or minetest.get_meta(pos)
local contype = meta:get_string("contype") or ""
if contype == "section" then
local s_junc = meta:get_string("junctions") or ""
if s_junc ~= "" then
local junc = minetest.deserialize(s_junc)
if #junc == 2 then
local dist = railtrack:get_distance(junc[1], junc[2])
if dist > MAX_SECTION_LEN then
local node = minetest.get_node(pos) or {}
if node.name then
minetest.swap_node(pos, {name=node.name.."_union"})
railtrack:update_rails(pos)
end
end
end
end
end
end
function railtrack:is_railnode(pos)
local node = minetest.get_node(pos)
if node then
return minetest.get_item_group(node.name, "connect_to_raillike") > 0
end
end
function railtrack:get_sign(z)
if z == 0 then
return 0
else
return z / math.abs(z)
end
end
function railtrack:get_rotations(s_rots, dir)
local rots = {}
for i = 1, string.len(s_rots) do
local r = string.sub(s_rots, i, i)
local rot = nil
if r == "F" then
rot = {x=dir.x, z=dir.z}
elseif r == "L" then
rot = {x=-dir.z, z=dir.x}
elseif r == "R" then
rot = {x=dir.z, z=-dir.x}
elseif r == "B" then
rot = {x=-dir.x, z=-dir.z}
end
if rot then
table.insert(rots, rot)
end
end
return rots
end
function railtrack:get_acceleration(pos)
local meta = minetest.get_meta(pos)
local accel = meta:get_string("acceleration") or ""
if accel ~= "" then
return tonumber(accel)
end
end
function railtrack:get_direction(p1, p2)
local v = vector.subtract(p1, p2)
return {
x = railtrack:get_sign(v.x),
y = railtrack:get_sign(v.y),
z = railtrack:get_sign(v.z),
}
end
function railtrack:get_distance(p1, p2)
local dx = p1.x - p2.x
local dz = p1.z - p2.z
return math.abs(dx) + math.abs(dz)
end
function railtrack:get_railtype(pos)
local node = minetest.get_node(pos) or {}
if node.name then
local ref = minetest.registered_items[node.name] or {}
return ref.railtype
end
end
function railtrack:get_connection_type(pos, cons)
local railtype = railtrack:get_railtype(pos)
if #cons == 0 then
return "single"
elseif #cons == 1 then
return "junction"
elseif #cons == 2 then
if cons[1].x == cons[2].x or cons[1].z == cons[2].z then
if (cons[1].y == cons[2].y and cons[1].y == pos.y) or
(math.abs(cons[1].y - cons[2].y) == 2) then
if railtype == railtrack:get_railtype(cons[1]) and
railtype == railtrack:get_railtype(cons[2]) then
return "section"
end
end
end
end
return "junction"
end
function railtrack:get_connections(pos)
local connections = {}
for y = 1, -1, -1 do
for x = -1, 1 do
for z = -1, 1 do
if math.abs(x) ~= math.abs(z) then
local p = vector.add(pos, {x=x, y=y, z=z})
if railtrack:is_railnode(p) then
table.insert(connections, p)
end
end
end
end
end
return connections
end
function railtrack:get_junctions(pos, last_pos, junctions)
junctions = junctions or {}
local cons = railtrack:get_connections(pos)
local contype = railtrack:get_connection_type(pos, cons)
if contype == "junction" then
table.insert(junctions, pos)
elseif contype == "section" then
if last_pos then
for i, p in pairs(cons) do
if vector.equals(p, last_pos) then
cons[i] = nil
end
end
end
for _, p in pairs(cons) do
railtrack:get_junctions(p, pos, junctions)
end
end
return junctions
end
function railtrack:set_acceleration(pos, accel)
local meta = minetest.get_meta(pos)
local contype = meta:get_string("contype")
if contype == "section" then
local s_junc = meta:get_string("junctions") or ""
local junc = minetest.deserialize(s_junc) or {}
if #junc == 2 then
local p = vector.new(junc[2])
local dir = railtrack:get_direction(junc[1], junc[2])
local dist = railtrack:get_distance(junc[1], junc[2])
for i = 0, dist do
local m = minetest.get_meta(p)
if m then
m:set_string("acceleration", tostring(accel))
end
p = vector.add(dir, p)
end
end
else
meta:set_string("acceleration", tostring(accel))
end
end
function railtrack:update_rails(pos, last_pos, level)
local connections = {}
local junctions = {}
local meta = minetest.get_meta(pos)
local cons = railtrack:get_connections(pos)
local contype = railtrack:get_connection_type(pos, cons)
level = level or 0
for i, p in pairs(cons) do
connections[i] = p
end
if contype == "junction" then
level = level + 1
end
if contype == "section" or level < 2 then
if last_pos then
for i, p in pairs(cons) do
if vector.equals(p, last_pos) then
cons[i] = nil
end
end
end
for _, p in pairs(cons) do
railtrack:update_rails(p, pos, level)
end
end
if contype == "section" then
junctions = railtrack:get_junctions(pos)
connections = {}
end
meta:set_string("connections", minetest.serialize(connections))
meta:set_string("junctions", minetest.serialize(junctions))
meta:set_string("contype", contype)
end