summaryrefslogtreecommitdiff
path: root/railtrack/railtrack.lua
diff options
context:
space:
mode:
authorstujones11 <stujones111@gmail.com>2016-01-10 17:47:02 +0000
committerstujones11 <stujones111@gmail.com>2016-01-10 17:47:02 +0000
commit6dfdaf78522a9c92e4323fa5bb77eb3a7c11aa30 (patch)
tree4f932364c6688275ab7128aa69ace9e387200809 /railtrack/railtrack.lua
Initial commit
Diffstat (limited to 'railtrack/railtrack.lua')
-rw-r--r--railtrack/railtrack.lua284
1 files changed, 284 insertions, 0 deletions
diff --git a/railtrack/railtrack.lua b/railtrack/railtrack.lua
new file mode 100644
index 0000000..3a1f714
--- /dev/null
+++ b/railtrack/railtrack.lua
@@ -0,0 +1,284 @@
+RAILTRACK_WARN_SECTION_LEN = 20
+RAILTRACK_ROTATIONS = "FLR"
+RAILTRACK_ACCEL_FLAT = -0.5
+RAILTRACK_ACCEL_UP = -2
+RAILTRACK_ACCEL_DOWN = 2
+
+railtrack = {}
+
+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",
+ on_place = function(itemstack, placer, pointed_thing)
+ local name = placer:get_player_name()
+ if not name or pointed_thing.type ~= "node" then
+ return
+ end
+ if not minetest.is_singleplayer() then
+ if not minetest.check_player_privs(name, {rails=true}) then
+ minetest.chat_send_player(name, "Requires rails privilege")
+ return
+ end
+ end
+ end,
+ 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:warn_section_len(placer, pos, meta)
+ elseif s_cons ~= "" then
+ local cons = minetest.deserialize(s_cons)
+ for _, con in pairs(cons) do
+ if railtrack:warn_section_len(placer, con) then
+ break
+ end
+ end
+ end
+ end,
+ on_construct = function(pos)
+ railtrack:update_rails(pos)
+ end,
+ after_destruct = function(pos)
+ local cons = railtrack:get_connections(pos)
+ for _, p in pairs(cons) do
+ railtrack:update_rails(p)
+ end
+ end,
+}
+
+function railtrack:register_rail(name, def)
+ for k, v in pairs(railtrack.default_rail) do
+ if not def[k] then
+ def[k] = v
+ end
+ 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)
+end
+
+function railtrack:warn_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 > RAILTRACK_WARN_SECTION_LEN then
+ local name = player:get_player_name()
+ if name then
+ minetest.chat_send_player(name, "Warning, section"
+ .." length "..dist.." exceeds the recommended"
+ .." maximum of "..RAILTRACK_WARN_SECTION_LEN)
+ return true
+ 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 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
+