From 202fc3c03afebd0ec0f8c044f19b4375de224ba0 Mon Sep 17 00:00:00 2001 From: sys4-fr Date: Thu, 6 Sep 2018 21:56:38 +0200 Subject: [PATCH] Version MFF. --- README.txt | 19 +- depends.txt | 4 +- detector.lua | 58 +++ functions.lua | 261 +++++++++---- init.lua | 436 ++++++++++++++++------ rails.lua | 150 +++++++- textures/carts_rail_brk.png | Bin 0 -> 577 bytes textures/carts_rail_cp.png | Bin 0 -> 522 bytes textures/carts_rail_crossing_brk.png | Bin 0 -> 549 bytes textures/carts_rail_crossing_cp.png | Bin 0 -> 495 bytes textures/carts_rail_crossing_dtc.png | Bin 0 -> 621 bytes textures/carts_rail_crossing_dtc_on.png | Bin 0 -> 654 bytes textures/carts_rail_crossing_pwr.png | Bin 0 -> 458 bytes textures/carts_rail_crossing_ss.png | Bin 0 -> 463 bytes textures/carts_rail_curved_brk.png | Bin 0 -> 537 bytes textures/carts_rail_curved_cp.png | Bin 0 -> 488 bytes textures/carts_rail_curved_dtc.png | Bin 0 -> 578 bytes textures/carts_rail_curved_dtc_on.png | Bin 0 -> 575 bytes textures/carts_rail_curved_pwr.png | Bin 0 -> 443 bytes textures/carts_rail_curved_ss.png | Bin 0 -> 450 bytes textures/carts_rail_dtc.png | Bin 0 -> 542 bytes textures/carts_rail_dtc_on.png | Bin 0 -> 559 bytes textures/carts_rail_pwr.png | Bin 0 -> 498 bytes textures/carts_rail_ss.png | Bin 0 -> 514 bytes textures/carts_rail_t_junction_brk.png | Bin 0 -> 538 bytes textures/carts_rail_t_junction_cp.png | Bin 0 -> 496 bytes textures/carts_rail_t_junction_dtc.png | Bin 0 -> 607 bytes textures/carts_rail_t_junction_dtc_on.png | Bin 0 -> 621 bytes textures/carts_rail_t_junction_pwr.png | Bin 0 -> 539 bytes textures/carts_rail_t_junction_ss.png | Bin 0 -> 439 bytes textures/default_rail_t_junction.png | Bin 0 -> 476 bytes 31 files changed, 735 insertions(+), 193 deletions(-) create mode 100644 detector.lua create mode 100644 textures/carts_rail_brk.png create mode 100644 textures/carts_rail_cp.png create mode 100644 textures/carts_rail_crossing_brk.png create mode 100644 textures/carts_rail_crossing_cp.png create mode 100644 textures/carts_rail_crossing_dtc.png create mode 100644 textures/carts_rail_crossing_dtc_on.png create mode 100644 textures/carts_rail_crossing_pwr.png create mode 100644 textures/carts_rail_crossing_ss.png create mode 100644 textures/carts_rail_curved_brk.png create mode 100644 textures/carts_rail_curved_cp.png create mode 100644 textures/carts_rail_curved_dtc.png create mode 100644 textures/carts_rail_curved_dtc_on.png create mode 100644 textures/carts_rail_curved_pwr.png create mode 100644 textures/carts_rail_curved_ss.png create mode 100644 textures/carts_rail_dtc.png create mode 100644 textures/carts_rail_dtc_on.png create mode 100644 textures/carts_rail_pwr.png create mode 100644 textures/carts_rail_ss.png create mode 100644 textures/carts_rail_t_junction_brk.png create mode 100644 textures/carts_rail_t_junction_cp.png create mode 100644 textures/carts_rail_t_junction_dtc.png create mode 100644 textures/carts_rail_t_junction_dtc_on.png create mode 100644 textures/carts_rail_t_junction_pwr.png create mode 100644 textures/carts_rail_t_junction_ss.png create mode 100644 textures/default_rail_t_junction.png diff --git a/README.txt b/README.txt index 4ec9bb8..7440b15 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,19 @@ -Minetest mod: boost_cart -======================= -Based on the mod "carts" by PilzAdam +Minetest mod: carts for MFF +=========================== + +Based on boost_cart and modified to fully *replace* carts (@Coethium) + - desactivate mesecons + - power_rail: accelerate, max_speed set in init.lua + - brake_rail: deccelerate, min_speed set in init.lua (so the cart doesn't stop and runs at very low speed) + - default:rail / rail_cooper : no friction, keep the current speed + - no collision (avoid the "walled_in" bug) + + + +Boost_cart +========== + +Based on (and fully compatible with) the mod "carts" by PilzAdam Target: Run smoothly and do not use too much CPU License of source code: diff --git a/depends.txt b/depends.txt index 331d858..bfb43df 100644 --- a/depends.txt +++ b/depends.txt @@ -1 +1,3 @@ -default \ No newline at end of file +default +mesecons? +moreores? \ No newline at end of file diff --git a/detector.lua b/detector.lua new file mode 100644 index 0000000..a218254 --- /dev/null +++ b/detector.lua @@ -0,0 +1,58 @@ +local mesecons_rules = mesecon.rules.flat + +function carts:turnoff_detector_rail(pos) + local node = minetest.get_node(pos) + if minetest.get_item_group(node.name, "detector_rail") == 1 then + if node.name == "carts:detectorrail_on" then --has not been dug + minetest.swap_node(pos, {name = "carts:detectorrail", param2=node.param2}) + end + mesecon.receptor_off(pos, mesecons_rules) + end +end + +function carts:signal_detector_rail(pos) + local node = minetest.get_node(pos) + if minetest.get_item_group(node.name, "detector_rail") ~= 1 then + return + end + + if node.name == "carts:detectorrail" then + minetest.swap_node(pos, {name = "carts:detectorrail_on", param2=node.param2}) + end + mesecon.receptor_on(pos, mesecons_rules) + minetest.after(0.5, carts.turnoff_detector_rail, carts, pos) +end + +carts:register_rail("carts:detectorrail", { + description = "Detector rail", + tiles = { + "carts_rail_dtc.png", "carts_rail_curved_dtc.png", + "carts_rail_t_junction_dtc.png", "carts_rail_crossing_dtc.png" + }, + groups = carts:get_rail_groups({detector_rail = 1}), + + mesecons = {receptor = {state = "off", rules = mesecons_rules}}, +}) + +carts:register_rail("carts:detectorrail_on", { + description = "Detector rail ON (you hacker you)", + tiles = { + "carts_rail_dtc_on.png", "carts_rail_curved_dtc_on.png", + "carts_rail_t_junction_dtc_on.png", "carts_rail_crossing_dtc_on.png" + }, + groups = carts:get_rail_groups({ + detector_rail = 1, not_in_creative_inventory = 1 + }), + drop = "carts:detectorrail", + + mesecons = {receptor = {state = "on", rules = mesecons_rules}}, +}) + +minetest.register_craft({ + output = "carts:detectorrail 6", + recipe = { + {"default:steel_ingot", "mesecons:wire_00000000_off", "default:steel_ingot"}, + {"default:steel_ingot", "group:stick", "default:steel_ingot"}, + {"default:steel_ingot", "mesecons:wire_00000000_off", "default:steel_ingot"}, + }, +}) diff --git a/functions.lua b/functions.lua index b6bab4e..6d8a972 100644 --- a/functions.lua +++ b/functions.lua @@ -1,4 +1,4 @@ -function boost_cart:get_sign(z) +function carts:get_sign(z) if z == 0 then return 0 else @@ -6,98 +6,221 @@ function boost_cart:get_sign(z) end end -function boost_cart:velocity_to_dir(v) - if math.abs(v.x) > math.abs(v.z) then - return {x=boost_cart:get_sign(v.x), y=boost_cart:get_sign(v.y), z=0} +function carts:manage_attachment(player, status, obj) + if not player then + return + end + local player_name = player:get_player_name() + if default.player_attached[player_name] == status then + return + end + default.player_attached[player_name] = status + + if status then + player:set_attach(obj, "", {x=0, y=6, z=0}, {x=0, y=0, z=0}) + player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0}) else - return {x=0, y=boost_cart:get_sign(v.y), z=boost_cart:get_sign(v.z)} + player:set_detach() + player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0}) end end -function boost_cart:is_rail(pos) - local node = minetest.get_node(pos).name - return minetest.get_item_group(node, "rail") ~= 0 +function carts:velocity_to_dir(v) + if math.abs(v.x) > math.abs(v.z) then + return {x=carts:get_sign(v.x), y=carts:get_sign(v.y), z=0} + else + return {x=0, y=carts:get_sign(v.y), z=carts:get_sign(v.z)} + end end -function boost_cart:get_rail_direction(pos_, dir_) - local pos = vector.round(pos_) +function carts:is_rail(pos, railtype) + local node = minetest.get_node(pos).name + if node == "ignore" then + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map(pos, pos) + local area = VoxelArea:new{ + MinEdge = emin, + MaxEdge = emax, + } + local data = vm:get_data() + local vi = area:indexp(pos) + node = minetest.get_name_from_content_id(data[vi]) + end + if minetest.get_item_group(node, "rail") == 0 then + return false + end + if not railtype then + return true + end + return minetest.get_item_group(node, "connect_to_raillike") == railtype +end + +function carts:check_front_up_down(pos, dir_, check_up, railtype) local dir = vector.new(dir_) local cur = nil - + -- Front dir.y = 0 cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then + if carts:is_rail(cur, railtype) then return dir end - - -- Down - dir.y = -1 - cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then - return dir - end - -- Up - dir.y = 1 + if check_up then + dir.y = 1 + cur = vector.add(pos, dir) + if carts:is_rail(cur, railtype) then + return dir + end + end + -- Down + dir.y = -1 cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then + if carts:is_rail(cur, railtype) then return dir end - - -- Left, right - dir.y = 0 - + return nil +end + +function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) + local pos = vector.round(pos_) + local cur = nil + local left_check, right_check = true, true + -- Check left and right - local view, opposite, val - - if dir.x == 0 and dir.z ~= 0 then - view = "z" - other = "x" - if dir.z < 0 then - val = {1, -1} - else - val = {-1, 1} + local left = {x=0, y=0, z=0} + local right = {x=0, y=0, z=0} + if dir.z ~= 0 and dir.x == 0 then + left.x = -dir.z + right.x = dir.z + elseif dir.x ~= 0 and dir.z == 0 then + left.z = dir.x + right.z = -dir.x + end + + if ctrl then + if old_switch == 1 then + left_check = false + elseif old_switch == 2 then + right_check = false end - elseif dir.z == 0 and dir.x ~= 0 then - view = "x" - other = "z" - if dir.x > 0 then - val = {1, -1} - else - val = {-1, 1} + if ctrl.left and left_check then + cur = carts:check_front_up_down(pos, left, false, railtype) + if cur then + return cur, 1 + end + left_check = false + end + if ctrl.right and right_check then + cur = carts:check_front_up_down(pos, right, false, railtype) + if cur then + return cur, 2 + end + right_check = true end - else - return {x=0, y=0, z=0} end - - dir[view] = 0 - dir[other] = val[1] - cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then - return dir + + -- Normal + cur = carts:check_front_up_down(pos, dir, true, railtype) + if cur then + return cur end - - -- Down - dir.y = -1 - cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then - return dir + + -- Left, if not already checked + if left_check then + cur = carts:check_front_up_down(pos, left, false, railtype) + if cur then + return cur + end end - dir.y = 0 - - dir[other] = val[2] - cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then - return dir + + -- Right, if not already checked + if right_check then + cur = carts:check_front_up_down(pos, right, false, railtype) + if cur then + return cur + end end - - -- Down - dir.y = -1 - cur = vector.add(pos, dir) - if boost_cart:is_rail(cur) then - return dir + + -- Backwards + if not old_switch then + cur = carts:check_front_up_down(pos, { + x = -dir.x, + y = dir.y, + z = -dir.z + }, true, railtype) + if cur then + return cur + end end - + return {x=0, y=0, z=0} end + +function carts:pathfinder(pos_, expected_pos, old_dir, ctrl, pf_switch, railtype) + local pos = vector.round(pos_) + local pf_pos = vector.round(expected_pos) + local pf_dir = vector.new(old_dir) + + for i = 1, 3 do + if vector.equals(pf_pos, pos) then + -- Success! Cart moved on correctly + return true + end + + pf_dir, pf_switch = carts:get_rail_direction(pf_pos, pf_dir, ctrl, pf_switch, railtype) + if vector.equals(pf_dir, {x=0, y=0, z=0}) then + -- No way forwards + return false + end + + pf_pos = vector.add(pf_pos, pf_dir) + end + -- Cart not found + return false +end + +function carts:boost_rail(pos, amount) + minetest.get_meta(pos):set_string("cart_acceleration", tostring(amount)) + for _,obj_ in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do + if not obj_:is_player() and + obj_:get_luaentity() and + obj_:get_luaentity().name == "carts:cart" then + obj_:get_luaentity():on_punch() + end + end +end + +function carts:register_rail(name, def) + local def_default = { + drawtype = "raillike", + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + } + } + for k, v in pairs(def_default) do + def[k] = v + end + if not def.inventory_image then + def.wield_image = def.tiles[1] + def.inventory_image = def.tiles[1] + end + + minetest.register_node(name, def) +end + +function carts:get_rail_groups(additional_groups) + -- Get the default rail groups and add more when a table is given + local groups = {dig_immediate = 2, attached_node = 1, rail = 1, connect_to_raillike = 1} + if type(additional_groups) == "table" then + for k, v in pairs(additional_groups) do + groups[k] = v + end + end + return groups +end diff --git a/init.lua b/init.lua index ca4adbb..e5e7c22 100644 --- a/init.lua +++ b/init.lua @@ -1,208 +1,410 @@ --- TODO: --- Fix way-up --- Add rail-cross switching --- Prevent from floating carts --- Speed up and brake rails -boost_cart = {} -boost_cart.modpath = minetest.get_modpath("boost_cart") -boost_cart.speed_max = 8 +carts = {} +carts.modpath = minetest.get_modpath("carts") -dofile(boost_cart.modpath.."/functions.lua") -dofile(boost_cart.modpath.."/rails.lua") +-- Maximal speed of the cart in m/s +carts.speed_max = minetest.setting_get("movement_speed_walk")*3*0.9 +-- Minimal speed of the cart on brake rail +carts.brake_speed_min = minetest.setting_get("movement_speed_walk")/2 +-- Set to nil to disable punching the cart from inside (min = -1) +carts.punch_speed_min = 7 +-- 1 disable mesecons / 0 enable mesecons +carts.mesecon_disabled = 1 -boost_cart.cart = { + +if not carts.modpath then + error("\nWrong mod directory name! Please change it to 'carts'.\n" .. + "See also: http://dev.minetest.net/Installing_Mods") +end + +function vector.floor(v) + return { + x = math.floor(v.x), + y = math.floor(v.y), + z = math.floor(v.z) + } +end + +dofile(carts.modpath.."/functions.lua") +dofile(carts.modpath.."/rails.lua") + +if not carts.mesecon_disabled and mesecon then + dofile(carts.modpath.."/detector.lua") +end + +-- Support for non-default games +if not default.player_attached then + default.player_attached = {} +end + +carts.cart = { physical = false, collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, visual = "mesh", mesh = "cart.x", visual_size = {x=1, y=1}, textures = {"cart.png"}, - + driver = nil, - punch = false, -- used to re-send velocity and position + punched = false, -- used to re-send velocity and position velocity = {x=0, y=0, z=0}, -- only used on punch - old_dir = {x=0, y=0, z=0}, - old_pos = nil + old_dir = {x=1, y=0, z=0}, -- random value to start the cart on punch + old_pos = nil, + old_switch = 0, + railtype = nil, + attached_items = {} } -function boost_cart.cart:on_rightclick(clicker) +function carts.cart:on_rightclick(clicker) if not clicker or not clicker:is_player() then return end local player_name = clicker:get_player_name() if self.driver and player_name == self.driver then self.driver = nil - clicker:set_detach() + carts:manage_attachment(clicker, false) + self.object:setacceleration({x=0, y=0, z=0}) -- Stops the cart when we leave it + self.object:setvelocity({x=0, y=0, z=0}) elseif not self.driver then self.driver = player_name - clicker:set_attach(self.object, "", {x=0,y=5,z=0}, {x=0,y=0,z=0}) + carts:manage_attachment(clicker, true, self.object) end end -function boost_cart.cart:on_activate(staticdata, dtime_s) +function carts.cart:on_activate(staticdata, dtime_s) self.object:set_armor_groups({immortal=1}) - self.old_pos = self.object:getpos() + if string.sub(staticdata, 1, string.len("return")) ~= "return" then + return + end + local data = minetest.deserialize(staticdata) + if not data or type(data) ~= "table" then + return + end + self.railtype = data.railtype + if data.old_dir then + self.old_dir = data.old_dir + end end -function boost_cart.cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) +function carts.cart:get_staticdata() + return minetest.serialize({ + railtype = self.railtype, + old_dir = self.old_dir + }) +end + +function carts.cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) + local pos = self.object:getpos() + if not self.railtype then + local bar = vector.floor(vector.add(pos, 0.1)) + local node = minetest.get_node(bar).name + self.railtype = minetest.get_item_group(node, "connect_to_raillike") + end + if not puncher or not puncher:is_player() then + local cart_dir = carts:get_rail_direction(pos, self.old_dir, nil, nil, self.railtype) + if vector.equals(cart_dir, {x=0, y=0, z=0}) then + return + end + self.velocity = vector.multiply(cart_dir, 3) + self.old_pos = nil + self.punched = true return end if puncher:get_player_control().sneak then + -- Pick up cart: Drop all attachments if self.driver then + if self.old_pos then + self.object:setpos(self.old_pos) + end local player = minetest.get_player_by_name(self.driver) - if player then - player:set_detach() + carts:manage_attachment(player, false) + end + for _,obj_ in ipairs(self.attached_items) do + if obj_ then + obj_:set_detach() end end - self.object:remove() - puncher:get_inventory():add_item("main", "boost_cart:cart") + + local leftover = puncher:get_inventory():add_item("main", "carts:cart") + if not leftover:is_empty() then + minetest.add_item(self.object:getpos(), leftover) + end + self.object:remove() return end - - local vel = self.velocity + + local vel = self.object:getvelocity() if puncher:get_player_name() == self.driver then - if math.abs(vel.x) > 2 or math.abs(vel.z) > 2 then + if math.abs(vel.x + vel.z) > carts.punch_speed_min then + return + end + --end --Only the driver can punch + + local punch_dir = carts:velocity_to_dir(puncher:get_look_dir()) + punch_dir.y = 0 + local cart_dir = carts:get_rail_direction(pos, punch_dir, nil, nil, self.railtype) + if vector.equals(cart_dir, {x=0, y=0, z=0}) then + return + end + + local punch_interval = 1 + if tool_capabilities and tool_capabilities.full_punch_interval then + punch_interval = tool_capabilities.full_punch_interval + end + time_from_last_punch = math.min(time_from_last_punch or punch_interval, punch_interval) + local f = 3 * (time_from_last_punch / punch_interval) + + self.velocity = vector.multiply(cart_dir, f) + self.old_dir = cart_dir + self.old_pos = nil + self.punched = true + end +end + +function carts.cart:on_step(dtime) + local vel = self.object:getvelocity() + local update = {} + if self.punched then + vel = vector.add(vel, self.velocity) + self.object:setvelocity(vel) + self.old_dir.y = 0 + elseif vector.equals(vel, {x=0, y=0, z=0}) then + return + end + + -- dir: New moving direction of the cart + -- last_switch: Currently pressed L/R key, used to ignore the key on the next rail node + local dir, last_switch + local pos = self.object:getpos() + local is_slow = ((vel.x ~= 0 and math.abs(vel.x) <= carts.brake_speed_min) or + (vel.y ~= 0 and math.abs(vel.y) <= carts.brake_speed_min) or + (vel.z ~= 0 and math.abs(vel.z) <= carts.brake_speed_min)) and + string.match(minetest.get_node(pos).name, "brake") + + if self.old_pos and not self.punched then + local flo_pos = vector.round(pos) + local flo_old = vector.round(self.old_pos) + if vector.equals(flo_pos, flo_old) and not is_slow then -- Do not check one node multiple times (but check if low speed) return end end - - local cart_dir = boost_cart:velocity_to_dir(direction) - if cart_dir.x == 0 and cart_dir.z == 0 then - local fd = minetest.dir_to_facedir(puncher:get_look_dir()) - if fd == 0 then - cart_dir.x = 1 - elseif fd == 1 then - cart_dir.z = -1 - elseif fd == 2 then - cart_dir.x = -1 - elseif fd == 3 then - cart_dir.z = 1 + + + local ctrl, player + + -- Get player controls + if self.driver then + player = minetest.get_player_by_name(self.driver) + if player then + ctrl = player:get_player_control() end end - if time_from_last_punch > tool_capabilities.full_punch_interval then - time_from_last_punch = tool_capabilities.full_punch_interval - end - local dir = boost_cart:get_rail_direction(self.object:getpos(), cart_dir) - - local f = 3 * (time_from_last_punch / tool_capabilities.full_punch_interval) - vel.x = dir.x * f - vel.z = dir.y * f - vel.z = dir.z * f - self.velocity = vel - self.punch = true -end + if self.old_pos then + -- Detection for "skipping" nodes + local expected_pos = vector.add(self.old_pos, self.old_dir) + local found_path = carts:pathfinder( + pos, expected_pos, self.old_dir, ctrl, self.old_switch, self.railtype + ) -function boost_cart.cart:on_step(dtime) - local vel = self.object:getvelocity() - if self.punch then - vel = vector.add(vel, self.velocity) - self.velocity = {x=0,y=0,z=0} - elseif vector.equals(vel, {x=0,y=0,z=0}) then - return + if not found_path and not is_slow then + -- No rail found: reset back to the expected position + pos = expected_pos + update.pos = true + end end - - local pos = self.object:getpos() - local fpos, fold_pos = vector.round(pos), vector.round(self.old_pos) - if vector.equals(fpos, fold_pos) and not self.punch then - return + + local cart_dir = carts:velocity_to_dir(vel) + local max_vel = carts.speed_max + if not dir then + dir, last_switch = carts:get_rail_direction( + pos, cart_dir, ctrl, self.old_switch, self.railtype + ) end - self.old_pos = vector.new(pos) - - local cart_dir = { - x = boost_cart:get_sign(vel.x), - y = boost_cart:get_sign(vel.y), - z = boost_cart:get_sign(vel.z) - } - local dir = boost_cart:get_rail_direction(pos, cart_dir) + + local new_acc = {x=0, y=0, z=0} + local speed_mod = 0 if vector.equals(dir, {x=0, y=0, z=0}) then vel = {x=0, y=0, z=0} - self.object:setacceleration({x=0, y=0, z=0}) - self.punch = true + pos = vector.round(pos) + update.pos = true + update.vel = true else -- If the direction changed if dir.x ~= 0 and self.old_dir.z ~= 0 then vel.x = dir.x * math.abs(vel.z) vel.z = 0 pos.z = math.floor(pos.z + 0.5) - self.punch = true + update.pos = true end if dir.z ~= 0 and self.old_dir.x ~= 0 then vel.z = dir.z * math.abs(vel.x) vel.x = 0 pos.x = math.floor(pos.x + 0.5) - self.punch = true + update.pos = true end -- Up, down? if dir.y ~= self.old_dir.y then - vel.y = dir.y * (math.abs(vel.x) + math.abs(vel.z)) - pos.y = math.floor(pos.y + 0.5) - self.punch = true + vel.y = dir.y * math.abs(vel.x + vel.z) + pos = vector.round(pos) + update.pos = true + end + + -- Slow down or speed up in slopes.. + local acc = dir.y * -1.8 + + -- MFF : Some rails have bad acceleration property, reinit them ! + -- this code would be commented when all rails will be corrected + local rail = minetest.get_node(pos) + if string.match(rail.name, "power") + then minetest.get_meta(pos):set_string("cart_acceleration", "1") + elseif string.match(rail.name, "brake") then minetest.get_meta(pos):set_string("cart_acceleration", "-1") + else minetest.get_meta(pos):set_string("cart_acceleration", "0") + end + + -- Change acceleration by rail (power/brake) + local speed_mod_string = minetest.get_meta(pos):get_string("cart_acceleration") + if speed_mod_string and speed_mod_string ~= "" + then speed_mod = tonumber(speed_mod_string) + else speed_mod = 0 end - -- Slow down or speed up.. - local acc = -2 * dir.y - 0.4 - self.object:setacceleration({ - x = dir.x * acc, - y = dir.y * (math.abs(dir.x) + math.abs(dir.z)) * acc, - z = dir.z * acc - }) + if speed_mod > 0 then speed_mod = 2 + elseif speed_mod < 0 then speed_mod = -2 + else speed_mod = 0 + end + + + --[[if speed_mod_string == "halt" then --stop rail, not used in MFF + vel = {x=0, y=0, z=0} + acc = 0 + pos = vector.round(pos) + update.pos = true + update.vel = true + else--]]if speed_mod and speed_mod ~= 0 then + acc = acc + (speed_mod * 10) + else + --acc = acc - 0.4 --No friction (to be set as an option) + -- Handbrake + if ctrl and ctrl.down then + acc = acc - 1.2 + end + end + + if self.old_dir.y == 0 and not self.punched then + -- Stop the cart swing between two rail parts (handbrake) + if vector.equals(vector.multiply(self.old_dir, -1), dir) then + vel = {x=0, y=0, z=0} + acc = 0 + if self.old_pos then + pos = vector.new(self.old_pos) + update.pos = true + end + dir = vector.new(self.old_dir) + update.vel = true + end + end + + new_acc = vector.multiply(dir, acc) + end + + if not carts.mesecon_disabled and mesecon then + carts:signal_detector_rail(vector.round(pos)) end - self.old_dir = vector.new(dir) - + -- Limits for _,v in ipairs({"x","y","z"}) do - if math.abs(vel[v]) > boost_cart.speed_max then - vel[v] = boost_cart:get_sign(vel[v]) * boost_cart.speed_max - self.punch = true + if speed_mod > 0 and math.abs(vel[v]) > max_vel then + vel[v] = carts:get_sign(vel[v]) * max_vel + new_acc[v] = 0 + update.vel = true + elseif speed_mod < 0 and vel[v] ~= 0 and math.abs(vel[v]) <= carts.brake_speed_min then + vel[v] = carts:get_sign(vel[v]) * carts.brake_speed_min + new_acc[v] = 0 + update.vel = true end end - - if dir.x < 0 then - self.object:setyaw(math.pi / 2) - elseif dir.x > 0 then - self.object:setyaw(3 * math.pi / 2) - elseif dir.z < 0 then - self.object:setyaw(math.pi) - elseif dir.z > 0 then - self.object:setyaw(0) + + self.object:setacceleration(new_acc) + self.old_pos = vector.new(pos) + if not vector.equals(dir, {x=0, y=0, z=0}) then + self.old_dir = vector.new(dir) + end + self.old_switch = last_switch + + + if self.punched then + -- Collect dropped items + for _,obj_ in ipairs(minetest.get_objects_inside_radius(pos, 1)) do + if not obj_:is_player() and + obj_:get_luaentity() and + not obj_:get_luaentity().physical_state and + obj_:get_luaentity().name == "__builtin:item" then + + obj_:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}) + self.attached_items[#self.attached_items + 1] = obj_ + end + end + self.punched = false + update.vel = true -- update player animation end + if not (update.vel or update.pos) then + return + end + + local yaw = 0 + if self.old_dir.x < 0 then + yaw = 0.5 + elseif self.old_dir.x > 0 then + yaw = 1.5 + elseif self.old_dir.z < 0 then + yaw = 1 + end + self.object:setyaw(yaw * math.pi) + + local anim = {x=0, y=0} if dir.y == -1 then - self.object:set_animation({x=1, y=1}, 1, 0) + anim = {x=1, y=1} elseif dir.y == 1 then - self.object:set_animation({x=2, y=2}, 1, 0) - else - self.object:set_animation({x=0, y=0}, 1, 0) + anim = {x=2, y=2} end - if self.punch then - self.object:setvelocity(vel) + self.object:set_animation(anim, 1, 0) + + self.object:setvelocity(vel) + if update.pos then self.object:setpos(pos) - self.old_pos = {x=0, y=0, z=0} end - self.punch = false + update = nil end -minetest.register_entity("boost_cart:cart", boost_cart.cart) -minetest.register_craftitem("boost_cart:cart", { - description = "Cart", +minetest.register_entity(":carts:cart", carts.cart) +minetest.register_craftitem(":carts:cart", { + description = "Cart (Sneak+Click to pick up)", inventory_image = minetest.inventorycube("cart_top.png", "cart_side.png", "cart_side.png"), wield_image = "cart_side.png", on_place = function(itemstack, placer, pointed_thing) if not pointed_thing.type == "node" then return end - if boost_cart:is_rail(pointed_thing.under) then - minetest.add_entity(pointed_thing.under, "boost_cart:cart") - elseif boost_cart:is_rail(pointed_thing.above) then - minetest.add_entity(pointed_thing.above, "boost_cart:cart") + if carts:is_rail(pointed_thing.under) then + minetest.add_entity(pointed_thing.under, "carts:cart") + elseif carts:is_rail(pointed_thing.above) then + minetest.add_entity(pointed_thing.above, "carts:cart") else return end - + itemstack:take_item() return itemstack end, -}) \ No newline at end of file +}) + +minetest.register_craft({ + output = "carts:cart", + recipe = { + {"default:steel_ingot", "", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, +}) diff --git a/rails.lua b/rails.lua index 0cdac7a..bf70abe 100644 --- a/rails.lua +++ b/rails.lua @@ -1,7 +1,10 @@ minetest.register_node(":default:rail", { description = "Rail", drawtype = "raillike", - tiles = {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"}, + tiles = { + "default_rail.png", "default_rail_curved.png", + "default_rail_t_junction.png", "default_rail_crossing.png" + }, inventory_image = "default_rail.png", wield_image = "default_rail.png", paramtype = "light", @@ -12,5 +15,146 @@ minetest.register_node(":default:rail", { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, - groups = {dig_immediate = 2, attached_node = 1, rail = 1, connect_to_raillike = 1}, -}) \ No newline at end of file + groups = carts:get_rail_groups(), +}) + + +-- Copper rail + +if minetest.get_modpath("moreores") then + -- Moreores' copper rail + minetest.register_alias("carts:rail_copper", "moreores:copper_rail") +else + carts:register_rail(":carts:rail_copper", { + description = "Copper rail", + tiles = { + "carts_rail_cp.png", "carts_rail_curved_cp.png", + "carts_rail_t_junction_cp.png", "carts_rail_crossing_cp.png" + }, + groups = carts:get_rail_groups(), + }) + + minetest.register_craft({ + output = "carts:rail_copper 16", + recipe = { + {"default:copper_ingot", "group:stick", "default:copper_ingot"}, + {"default:copper_ingot", "group:stick", "default:copper_ingot"}, + {"default:copper_ingot", "group:stick", "default:copper_ingot"}, + } + }) +end + +-- Speed up + +-- Rail Power + +carts:register_rail(":carts:rail_power", { + description = "Powered rail", + tiles = { + "carts_rail_pwr.png", "carts_rail_curved_pwr.png", + "carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png" + }, + groups = carts:get_rail_groups(), + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.get_meta(pos):set_string("cart_acceleration", "1") + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + carts:boost_rail(pos, 1) + end, + + action_off = function(pos, node) + minetest.get_meta(pos):set_string("cart_acceleration", "0") + end, + }, + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "carts:rail_power", + recipe = {"group:rail", "default:mese_crystal_fragment"}, +}) + + +-- Rail Brake + +carts:register_rail(":carts:rail_brake", { + description = "Brake rail", + tiles = { + "carts_rail_brk.png", "carts_rail_curved_brk.png", + "carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png" + }, + groups = carts:get_rail_groups(), + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.get_meta(pos):set_string("cart_acceleration", "-1") + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + minetest.get_meta(pos):set_string("cart_acceleration", "-1") + end, + + action_off = function(pos, node) + minetest.get_meta(pos):set_string("cart_acceleration", "0") + end, + }, + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "carts:rail_brake", + recipe = {"group:rail", "default:coal_lump"}, +}) + +-- Start stop rail (temporary removed for mff) + +--[[carts:register_rail("carts:startstoprail", { + description = "Start-stop rail", + tiles = { + "carts_rail_ss.png", "carts_rail_curved_ss.png", + "carts_rail_t_junction_ss.png", "carts_rail_crossing_ss.png" + }, + groups = carts:get_rail_groups(), + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.get_meta(pos):set_string("cart_acceleration", "halt") + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + carts:boost_rail(pos, 0.5) + end, + + action_off = function(pos, node) + minetest.get_meta(pos):set_string("cart_acceleration", "halt") + end, + }, + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "carts:startstoprail 2", + recipe = {"carts:powerrail", "carts:brakerail"}, +})--]] + +--Alias + +minetest.register_alias("carts:powerrail", "carts:rail_power") +minetest.register_alias("carts:power_rail", "carts:rail_power") +minetest.register_alias("carts:brakerail", "carts:rail_brake") +minetest.register_alias("carts:brake_rail", "carts:rail_brake") diff --git a/textures/carts_rail_brk.png b/textures/carts_rail_brk.png new file mode 100644 index 0000000000000000000000000000000000000000..2717bd5a30b53acc572db8050d97a961e89de748 GIT binary patch literal 577 zcmV-H0>1r;P)Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vGf5&!@T5&_cPe*6Fc00(qQO+^RY0SOc}I$aLa!vFvP z8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^7j^FlWO00D7HL_t(IPtB9dO9D|8 z#{DxQ$I;wYWaBHXO{>BlR;Dg=mk}yDzMnmmLWwp-C}o9IMn#K)!XW5x`#N`MuDEDr z3ol&moSDPN{J!&DjplcKeRtvYdq5@Ie=Vhl_4YM<*5{O$?BiK<3fCDkIt454@>V?U z*_HYtDWSGC&IQ_8OHU-SByfSEPmj>zD6$?s@?Jes>mp>gh$Nkrppgs2R(1V>(Tk#<)PnBO>e)klxTE zLp~J9hvb@w=(2z~ajR3P1dPMv!9&T$5t{Ne+F3KsV6!6Ih&i?*ph~Q{P09oLkf5!45O!&Y$%7WnUJcS~)qzgY2F7@@Gl`e| z89bKl${lHtFDe47xd)6<6=19-zd@OOna-lmpv<4$htPtS3k2s!{>OtKYi3&%2dDL5 P00000NkvXXu0mjfCJX2I literal 0 HcmV?d00001 diff --git a/textures/carts_rail_cp.png b/textures/carts_rail_cp.png new file mode 100644 index 0000000000000000000000000000000000000000..119461f6e688a86747a2585aa8362da4a9d539c6 GIT binary patch literal 522 zcmV+l0`>igP)H;LN@>a0dq-2K~y+T&6C?p0znkU{WBuh zUGuezw%)CmASmo&W!ZziWrT{Z=5@7;QYg_&5lUGRl~K_{K~aC+*O{dq>7^HYa9}t) zGiN^b_nk8a!_O#3gP8V=frjC)$#Ph(eou>EjY(~j9iAqvxXRhlDLHXhbmD2(t*y^9 zGU^+{S`N#-$ve6t@i~DDs38f_*+Jxk5{hdQwwFaH0TCIB)rf@)Bo|G;|Dq=ZhS8J2 zz3Su$7uzzLDI4Anym&wK;WBH-^Nt(01qY5cM>xVq-Pc9f4-avHTu?;JFCe=jAxA!x z$cN05h{U{r6mjb&R>PKl^5CKD;s`BeoN8>xS<;4fR>o&z0xiWxy&&TxZsiEq)Em5+ z(g70}Q0SZS$B8+)AfQI9g;nYY@*z!A_aNps_LB!~s=eMwuQe|^stb(qcxx0ddmcPi z+}ayyk}o;}TXPQ>qb|T$%j;&X_7#e1$gI_$y@%+Gkqbno2L8u`Z*CvpMD?+1uK)l5 M07*qoM6N<$f~+3c3;+NC literal 0 HcmV?d00001 diff --git a/textures/carts_rail_crossing_brk.png b/textures/carts_rail_crossing_brk.png new file mode 100644 index 0000000000000000000000000000000000000000..f9ce303a36fc09ad1dadb55c916c9b91f1aa7205 GIT binary patch literal 549 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=d3- zBeIx*fm;ZK886+f`vVkYFY)wsWxvbFDPk)6?f$!2Kq09T*NBqf{Irtt#G+J&fW*wa z5hJyShHL-)^4=0I14db&7V_dh+){hrGyvo=Z>NWP|7vAguMkND-r>mdKI;Vst097Q)dH?_b literal 0 HcmV?d00001 diff --git a/textures/carts_rail_crossing_cp.png b/textures/carts_rail_crossing_cp.png new file mode 100644 index 0000000000000000000000000000000000000000..b04aa638245ea9d5d691114c13a679cbf3a00218 GIT binary patch literal 495 zcmVH;LN@>a0a!^yK~y+TrBiKA!axx1DYPG4 z0Y88O2k?&}T0{j8V3b5Lv{ES0-~sT5CPpQoMn#FnJB~9eyIp88ByBS3c4zkWy*IOp zGJQJ7`>>T?1AO>a=uJ7Qq1sSV256OZ`0SXXs8&$%JIlaB0CbQCPs)4q>-idn7$+2> zMIlS5Zm+=TGR-Jc_+&{522M)y;3)8*duRX! zx!x>k&@CsJ2e){*v8M}wCift!jg%ZrDO29IG0YxPcbKi?pk!b40QxFsnO468{7f}O6D3PKq1;LXL$w?5a z^(6!7lxk^qUm}%OL`s`vGafek65B-t2Ohk6-#6dPoA(9)17H+O z1x}_CEHtotwtfi>oJ=LSSSm=40uQ?s5A)!tW!z)GLzrzU;&(0C4p|giXX=2B=9_a@*tFT+%JyZZ-Vz~3h)BREG(ZWywObkako8HU8;4ZAz zZ9F`(PX^w~L|6)xzjk_H%vzXVs6q7+-hDRlV`&*?brA%>6pNBKH(zrq5E^m%l_`ON zw-y>UV`a_8pkBqm8xw1d7PbdAA@iY=Xiygr8u5RBBytABvD;(gID78QUjsZi8>ew7 z9^&igd*#GsPKNl=l|$?`jjC6c?3AExKbIGj%L78A4cGk*{$BxbSS``T00000NkvXX Hu0mjfX+911 literal 0 HcmV?d00001 diff --git a/textures/carts_rail_crossing_dtc_on.png b/textures/carts_rail_crossing_dtc_on.png new file mode 100644 index 0000000000000000000000000000000000000000..b6f5b87e5da983cadcbfaae3272ff87d347758ac GIT binary patch literal 654 zcmV;90&)F`P)aN7U!C&$Ji-P-8E-aD9v&Lu`Oz0#eOHgOc^_Td!T{Wg+BkBk zk;^q7xES-$-P1+KR3`uyrHOi)cbSe47Fua zqUEp+3ozQ}68{yu)YsRM%@w$pahSrv-Zn7};@{VE5S>XeJ2#KDN)h>zYC%|DDKKD9)8CwAWp$06wVUxf)(;x6>xiagMC}l oe_U6k>%fGr0uvyb`scZS0Ch#+fZHTH^8f$<07*qoM6N<$f{;8RI{*Lx literal 0 HcmV?d00001 diff --git a/textures/carts_rail_crossing_pwr.png b/textures/carts_rail_crossing_pwr.png new file mode 100644 index 0000000000000000000000000000000000000000..dc317cfb2c58a6d0e05023ddc4521a1171af8242 GIT binary patch literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJXMsm#F#`j)FbFd;%$g$s6l5>) z^mS#w%gD*CqB!})-6EjSx&WULS0Ei49-QGRmg6m+>n%~>D^chtS?DiW?3Bvlb2T^%Z29VSx~CS4OQQwKy5GTmvq-5I()>ADlL z^(SWQPsufymS;G7ojg#TBMY zDuKvsX_eWsD$`|EX3J~LR@RxXsxx0xZ?S9dw*UVb{{R19X)3e>=wil_AirP+hi5m^ zK%69RcNfd+3{xF|oT;8Jjv*44Q_mj{V`7wWekg6FVbmnT%HrB}h0*)p_j)5S<8I3d zsb=v^5sVCq%n3(7OKMGDvqAUy#M}~Lr8OFBm4CHQP=0WH*3$a>x9?YKy>DFj^@5f8 z>ARu6b*H8t)Hd12l~c-mxPOmDxgh*G1N>_);)Pzab zgv-DD67Xy*;oMNLn#l~|> zP3Dyv&o4DuSZ=zg!enuU>5@tyGFw_@wyer@S(VxH8ncyk=Bw(=*VJ3=+Pm%lf1ryQ zW_CT!22zYAL4Lsu4$p3+fjCLt?k)@+tg;?J4rhT!WHAE+w=f7ZGR&GI0Tg5}@$_|N zf50xnt}l7yv-TyR&@4|E#}J9jss1;GnjCnt_a5aw7`-Q7BzDiH-~a8?QYG6b?%6Uq zb5={ofmuQsZbq#yj=3z|t;%2!R3rY#e!?{+O_`pT?n)OwyFVdQ&MBb@09X^MuK)l5 literal 0 HcmV?d00001 diff --git a/textures/carts_rail_curved_brk.png b/textures/carts_rail_curved_brk.png new file mode 100644 index 0000000000000000000000000000000000000000..c55183d5f247ef3616862e00b6d471159fc1caa0 GIT binary patch literal 537 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l;AAz zh%9Dc;1&X5#!GkW{s0BpOFVsD+3zxPikR^$OmI;K3Q3i?MwA5Sru2dY{T;1l8sq=6tbJUGKkCfi3Q#}|lXbA4s<{ABa}WeWm; zNUktYwkSZZC{V6ANWLUkzBE{_EJVH{6o?e6BUNf673*SD>tfWJW0jlZ)mswOTN1U~ zlQcS0G<(xEdo%SWWb04N)}NFEL?avX3J~LSJarVt}|a#XR)TiV%OenmOs1QfDUCW3GxeOaCmkj4an*6ba4!k zkYqi`uH?)pzwVBck!kb7jOQ)e})IBVn+=#L(lHrj2GsrFzlNAa2=P$uNO}w4;}p2^l;YXZoh-)-t4_5_NM&b zwDkrtchz3-T)z5#x_;@5yppc3Q+wwh|8h-eF4JShzfa`ZRk$BZU#(aNw2{Hn)z4*} HQ$iB}Ts645 literal 0 HcmV?d00001 diff --git a/textures/carts_rail_curved_cp.png b/textures/carts_rail_curved_cp.png new file mode 100644 index 0000000000000000000000000000000000000000..004ef56675e2e9610081cf3dce642e5d742b3e35 GIT binary patch literal 488 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstUx|zfk$L9 z0|PfuA-4eITIIc^Ktc8rPhVH|yNsM7X8Z~hT$F)AQYEetCBgY=CFO}lsSE*$nRz98 zey$-3WyX4@dWMGXpPkHss#XX1gt!9f|NsBHSm>GMJNy{RHX!0N2=6DD%QoQ*2Snb$0|3+ ztG6VmwpyV!V6iSgVL<+k7t!xFah z4we=kR!y^B)^2D0uy|#0!^-@ndb2ls9A3FEZjxupdhg{&V`UoVl<#`PxRZxd^glP7 QG0zopr0C8}tRsaA1 literal 0 HcmV?d00001 diff --git a/textures/carts_rail_curved_dtc.png b/textures/carts_rail_curved_dtc.png new file mode 100644 index 0000000000000000000000000000000000000000..8117c27a92edcb03681101eea2468cfebc35b8f6 GIT binary patch literal 578 zcmV-I0=@l-P)T2Y6N*5{bA0%Hzu(Wp^ZZ~Z>*mEn zGCOiaN_(#D7<^kd2%eiJb_&}>{jWH-FfRa+aI~ziwkvEl+G0y+3C4rFB$3>*-#RK8bY6KxBpfAB`+-+y zkK1B^>yJOH&18yj=&)2Yh%L;Em7MsIVd?u%W`+V~t6SeR$>s~y39P#NbXk2(q)DcJ z5giW7A8bV~Cx36DG`$pi^t4a38jYrXbzHvlRsn>%TEyG9yGSr`UYE(yy zX%i!zVRrPWtm=rF6FhELG39EvPfiX#BodBtrtJ$xCQm^M^iI7gBMf!5$o{<^YTX(y z*ILU*u<)DBI3Bl?jZ~Hs0WX=YJnkANJ(I81s*cJ%=P)}v~N{2d1C`Cn+YOnd<%j04E|82BIUV4rXzwh_^d3c^5{Li{Id_ZO< z4oi8@wiAOdn`wLl_lcgwG*SO5jxH?-KsXes=&PLyJMf{Q=+5|>De6^uI$1@~Szle<9ixjnnC(ixp} zCd_|7o;8b`(XkO0pPc1jciZ1T)8qM%CZSS@)uKRi1JJX-l{0r@Y8yo~w>R^d-2(ss N002ovPDHLkV1l%W`) z^mS#w%gD*CVkBNRXAMwjb%0NZE07Ki56W+^(W;3k-^k_gBgWJvx&(~GS*&TW*tK`t|NjjC|Npl-^!NhMxr`-2e!&b5&u*lFI7!~_ zE*1;emtF&MIz3$+LnI_w53(ycGYYUCh|~?V3tYtQc;&^Oz5mai0jg*?ZO(AO!joY_ zNGPMnsF|52d>+Hr#{w25W-88l?o{%LYqc5?} za;Jysn{)T7YY*1F%KyoA_-d|b(BYD|zn^-`hc$(4-e~lza!ro@#4H0jE&qRv`p5aQ U-@mq*4z!ZN)78&qol`;+0K$HqGXMYp literal 0 HcmV?d00001 diff --git a/textures/carts_rail_curved_ss.png b/textures/carts_rail_curved_ss.png new file mode 100644 index 0000000000000000000000000000000000000000..504e31f13535afcf3da7b3e32457a07c694d9b68 GIT binary patch literal 450 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf>Hwb**Z=?jhlU4dc*$h@$mI9} zk!-H7OrD=?zQ1fi01(L)2Fex%$Q1?36$if_h7$c6*XWXNqQTx@K>t-h^!ZiP`#-a)8KSYQDjYLZewlMzf2J=ad-F zEis;7YBImfcwxEeqH>c(6{bsosM2hCjroci^VN0cYw9f4G+6A~yY2sfpmP~EEUB9S zq!>$r{DK)Ap4~_Tagw~Fdh=fL(-L zUuTlT`;S1O37#&FArhBs`>zWfGT>qH|B_bqLZv0niT&pP|EUq2=NS0!bZ^z}bz}RN zQuIeqb=%K`v`s&qwi>7{e0OuvwVU19<};T(KYOWC%Jzxu8rj!f^0yZ4@nMxZEE~Xm zUuXC2y`l@47TEi-y!z+)d~J@Q?c!z$)49jn4K?-4Z^tKEiOkp24m=_9Uiwkila@ce cg83hrjKlegEJWp(1Kq~p>FVdQ&MBb@06SEmYXATM literal 0 HcmV?d00001 diff --git a/textures/carts_rail_dtc.png b/textures/carts_rail_dtc.png new file mode 100644 index 0000000000000000000000000000000000000000..5e2ccef19787501f0c469ea1d93a8e0c8a82e580 GIT binary patch literal 542 zcmV+(0^$9MP)95dMe;1u5bdrEhxe%Jsh8_r3Q$@6&K@FEq52gWvHyAHF>2!#U8*-2AKz zj||Cr7s6k%-h~X049VR5Y{nRXmv;xUgQsV^d3eD{tI?zazOSj)5)vysuEbDv+{CS3 zxpHq&8GxDBMK1NZL9n&MR;58(p#`m>kq9;gt>I9?WZNvSegAX4f4zd{KVtwUZ=cE< zX9jy1Pf|H{G>@kgK{@7N-VoI-ljR61j(c&ZUj|3tI0qlUlxS}jeE3`Y)@E z4RJ%LCn=s*kayhTO0b_COpo?ujnB`WVB(^dYGldznvNrRib06qqIvSu!nWfc-8?B* z$CjLfg_RA?pK*h=VhQ7EYITdJU?cDeV@r|orq^z!KUNxU+b3Z literal 0 HcmV?d00001 diff --git a/textures/carts_rail_dtc_on.png b/textures/carts_rail_dtc_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e81dbe1bee83389e3236d08506b2728bd2a25eb0 GIT binary patch literal 559 zcmV+~0?_@5P) zK~y-)&62@OR8bVhfA_xU8>fLRC|uM+=nt^0grZ%oqD3I)I$A|w5W3LStP;!?1{O%+ zBHOtT3Ijn}6m2x4g@zO|TH@0g8&Mzg-psr2xOmfz7H(?eSzYdTzK?T$9H`gy%#?I? zb%^8<4k*bZon0L=Ju_u{T!6O&SM0}=Vk^&kTxoPQiGb&6_9`*45e9xlHf*f-g4}*I zr(A&79}3)TPX)iYO>w8j@mvF1LoF6e0$M{;&b0yaOB;WW_pd8x{+`yN4Lh+`oE$kZ7u9x4W-587) z^mS#w%gD*Cs@t5p03`G#e5kz9elY(aorArJ-16$Qu@1Y zFFBsA$AFwJPZ!4!iOaobT!juXFt8kqjcH~p=gm8K*Zlu~0sa%MuS32v2*@%p$Z#?2 zTa+sQJ-qtX!fgyqNk_vqQhQ6fyO{DGaj_SgRqdO$J$8B(b4JI`hMD@y4;ilddHu1D zpIP(K^gXYFvl%!I^V*c&CaHP;{9kqE=<&?EyW`g=rZQ@D&5T+V*DD!!>am)A34_GN Ug5Z^#fUaWjboFyt=akR{01REOYXATM literal 0 HcmV?d00001 diff --git a/textures/carts_rail_ss.png b/textures/carts_rail_ss.png new file mode 100644 index 0000000000000000000000000000000000000000..489e7fe59b19d303e47b08a4ba09605883a6f5df GIT binary patch literal 514 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf!vLQU*Z=?jhlU5oI7+0rOQ(29 zWqL_xddXyY%Vhb;Wc$eE`pV?`$>#aV=KBMYT!FuAL4aH#5CzH=1;`Zz$`uF6mjug| z1k0BO%a?`7mxsz%gvwWj0g*ygxI%TfLVdJiL$p#uj8bE?Qd_ciXR1zjy6%K5{fXK7 zlXDHG0#Tm9w0s~koKa{rv&d)`5EUEEE;gQ1Vl=13cy5XD{8At?Sy*PWsN8gMrRkCi z(HD6g{zPiq0eWT@uX3NbjR$JPvwzXStZ@1aCciaE}Ku9LG zVE%IYju}vBmZytjh{WaIbI19b7z9`Xj>T(T>4X3F9up=%d=zI^dGq8N z1&$WYn&T{Uzp9zk?zeqC*=)x)MV~3mtx0AxGn)#Zw`{o6@zl*`gYvS&zmp4ZmK<2l zTdE`;^hs4ytBKeAQ}pXbWy83y&(~kv#4csFq@zWsb8CntFWdiL$!>S}+`d;`Vq1{b m>~$h^WtiaPx(mbe{N literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_brk.png b/textures/carts_rail_t_junction_brk.png new file mode 100644 index 0000000000000000000000000000000000000000..5689ffe93115c90e129f9af44c6fb8abb5879afc GIT binary patch literal 538 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l;AAz zh%9Dc;1&X5#!GkW{s0BpOFVsD+3zxQ2})}GwD|4-6p|`&jVKAuPb(=;EJ|evNX*PD z(erZ+Q7ALkGu1ORbpPyR4pcQiz$e5NNdN!;A4rCV2gf){q_|6`ct~Y>NoRS>WckQs z`^e<^$>#gZ75K{*2FMi#$`u936$Q!_2g#QP%a?`7mxsz%h5?a6Rk%WRxI%rjVnei2 zLyS^evUYd6?u0D;iP`#7a}8z`8qF#)no|Nq#&b)I=a-r+DmPtRX}YAsbV;Sz(kip% z)#fW|%~#i1tZ%g3&}_M-&1!qQ&91%Mrk=EG13HeWB*+gKl4X<6S^#+yJzX3_Brd1+ zAJ1cA6k%>p=dhg+z^rm*>GvQ1_xB#w<2ZP6+MA7x+6)RQ4fWZRa;_gw`KG>CZx=#QA literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_cp.png b/textures/carts_rail_t_junction_cp.png new file mode 100644 index 0000000000000000000000000000000000000000..3da909432540ca562f514278fe55cc7a10a79642 GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstUx|zfk$L9 z0|PfuA-4eITIIc^Ktc8rPhVH|yUbjIk{UlPzB>Sgq)J>PN`mv#O3D+9QW*jgGxJLH z{9Hp6%8d0)^$ZQ&KRcNNRjmu~32_C||NsAYvCxZglt^)xPVtb+^peiEeMb+1foE>q5!#~K)K=|`O;wdvJm<5Q2B~b`N}XLQm6`7s7eX04p*p; zR&0n?YKT#4OV;j8)#*;xosgwJFnzqcT5f2z+|p*Xt=)QiyG{D6Q!9ZkW-1Bt1BOr8 zz2zoC!hnD1WuO0dyRLr>mdKI;Vst0Hv;`asU7T literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_dtc.png b/textures/carts_rail_t_junction_dtc.png new file mode 100644 index 0000000000000000000000000000000000000000..b154f4363cd6942531c686a22866c86f2a6e0c4b GIT binary patch literal 607 zcmV-l0-*hgP)Y=6Hyd~zk40i(k!YV6jY>8nUzq|YQf@8g&IVJP`YrVh6LOgl(=Xi8&O<{ zXf_Iy42sr`lH!X9f#Sjk6hpJI3MC7zGzRL6K4@Yxxh|$N(^TuGp3Q}G&-u^!|NmZC ziQITr4Gx7=Nk_3xlyubKP)Oy*vu=$B@chaFH}UXrH|b-VYSknS1wNl-ak)<2QrwxZ z!lGSw`@&vz>S|tS08d|i?}UwYtJ;fRxbg*W7J(3|u5PfD)@I zqzsc}A;b1*#MECRWY%nCi z{gFNw@!hSgO(7a476?(&Q6(Lfj`yeshq~QHGv2FQ5#LUIA$ZWfNEs%(YIz=ApCEG1 zAZFP4EX>l{B3Z6BXls#7{#anC tVj+ZJsbayFE&%RcI?d>dvS6d%`8WRK@(dl8G*$or002ovPDHLkV1ft(5KsUB literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_dtc_on.png b/textures/carts_rail_t_junction_dtc_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9fda111b95284cbc6e210c3e6de9f9cd87a4e251 GIT binary patch literal 621 zcmV-z0+RiSP))a=%7fUE}bf^1}r+MP=kXIn$8*$5JXVokb)3IC@950 zLxz_GLE}>dpY-<@7(YE4y;9X zG9!aSK9MNG79mk&aL6aw$&6ED06ZT#>Ll)#dPsx~X*D!80hdejbEQhv5=Q3B4%odb zhve+doH78Oy!^-+kNr?AeW&!J!fy9=w1!Gmuxg++w7U%lVDG>+vIB@}rVuxijCH3` zQPjro*S{S%lk4)v#zKGI2c-Yn7z_nCIqhu#Jct}#CtM=jCwtmmwDn(g8ppcRO#|SW ztDn=uuWb!x3t#AHLXVqCf~V}W-gqImk8N7P4!bTlQ~Z---Nvmf-ONVKKZXW)IP7r{ zUmVNW6hZ;~c^?u*B#I=$y>jPskJFe8_lYCo+nG;zkJ}G%Gs*r+j)_}u2wpPrn>0k+ z39l9p*cyB&He9&400000NkvXX Hu0mjf@sSL= literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_pwr.png b/textures/carts_rail_t_junction_pwr.png new file mode 100644 index 0000000000000000000000000000000000000000..d7edaf1dc3dafda2eea9edd38aefc2c677ba2635 GIT binary patch literal 539 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l;AAz zh%9Dc;1&X5#!GkW{s0BpOFVsD+3zxQ35xUT?C0wQ3Q3i?MwA5Sru2dbJM;1l8sr2qf_9~vGU<0z5hE}h~bmFXp&xtBa`hT zljkR!?=M&2FIyNOR~RT)6d+d=C|4XLUm7f579w9BDqk4}L<&{m3f18X_0ftA(Mk<5 zN^Qy7-RZg$vh*ir>rc%!m{DjntH@|h2@o02Eis;7YO<)@baAEWk_yu$m1aw;%$8T1 zuc$R&U1zbr(Q-qx<(4+9?d>+Z_HO(CpTS4tkUh|eOeH~nz>qAPeAWWUo8;-@7$R{w zwf}e?6Qc+-yKq&z%9lwSwg{}c|G!?kJyxJ;vF^=e<}e0_6Aab^u))AH~>$=}r}mXpIB z?glNNGga(zN5wI_eRtabMlIie^~(?Y_$8OC!&cvys0q)OFOrLUf1km!N90ii--39c P>li#;{an^LB{Ts5{lm9t literal 0 HcmV?d00001 diff --git a/textures/carts_rail_t_junction_ss.png b/textures/carts_rail_t_junction_ss.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a2cb1d034719c86880029c7960e54c04c5489a GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf`~aU2R}lt=(D2|GM~M`7=@bvC zOfTsyZ<#C~nQR}KJU`idf4KsG*}?$1!a%vA0J)+-x#A%C(qQ?r5c%>@`N}XLQm6`7 zs18@Ck5+7mR%(b*YD?DcPS>4~r9UxSe`>D5j6$PXMMiT<>&pIsU4&haW#79pFQCvw zPZ!4!iOaeE>_UeXc%1Kge!urp;coPY|J$z$6kXqaW#8d#4wC}C1l@ibEYOx$y7>HY zZ2t5Ijtx?VtG=|~-LaS9rWJS7)2@yy+!hcc{+J`O0{4=9XoTHT0U7Cj9>VSO3-u W5rd~0DVuG@4apG^YfJjOUgZ&o4DuSZ1=Q+;nlJ>5>Z5C6#7NtIU>Ho3E%fUtMRh zzR_|+v*ngHt8MMp+uLn+?cLVzeDWyJ#Y`nZe!##en|#&+$eZBl;us0l!pS~FGwcX5~p!r>VTeo?0