diff --git a/game_api.txt b/game_api.txt
index 80272a6..e85898f 100644
--- a/game_api.txt
+++ b/game_api.txt
@@ -650,3 +650,25 @@ Trees
 
  * `default.grow_new_snowy_pine_tree(pos)`
   * Grows a new design snowy pine tree at pos
+
+Carts
+-----
+
+	carts.register_rail(
+		"mycarts:myrail", -- Rail name
+		nodedef,          -- standard nodedef
+		railparams        -- rail parameter struct (optional)
+	)
+
+	railparams = {
+		on_step(obj, dtime), -- Event handler called when
+		                     -- cart is on rail
+		acceleration, -- integer acceleration factor (negative
+		              -- values to brake)
+	}
+
+	The event handler is called after all default calculations
+	are made, so the custom on_step handler can override things
+	like speed, acceleration, player attachment. The handler will
+	likely be called many times per second, so the function needs
+	to make sure that the event is handled properly.
diff --git a/mods/carts/README.txt b/mods/carts/README.txt
new file mode 100644
index 0000000..0cfaea2
--- /dev/null
+++ b/mods/carts/README.txt
@@ -0,0 +1,20 @@
+Carts (formerly boost_cart)
+==========================
+
+Cleaned up for merge based almost entirely on SmallJoker's boost_cart
+mod (github.com/smalljoker/boost_cart).
+
+That in turn was based on (and fully compatible with) the mod "carts"
+by PilzAdam
+
+The model was redone, but based on github.com/stujones11/railcart, CC-0
+
+Cart Textures are based on original work from PixelBOX (WTFPL).
+
+
+Features
+----------
+- A fast cart for your railway or roller coaster (up to 7 m/s!)
+- Boost and brake rails
+- Rail junction switching with the 'right-left' walking keys
+- Handbrake with the 'back' key
diff --git a/mods/carts/depends.txt b/mods/carts/depends.txt
new file mode 100644
index 0000000..4ad96d5
--- /dev/null
+++ b/mods/carts/depends.txt
@@ -0,0 +1 @@
+default
diff --git a/mods/carts/functions.lua b/mods/carts/functions.lua
new file mode 100644
index 0000000..f255fef
--- /dev/null
+++ b/mods/carts/functions.lua
@@ -0,0 +1,221 @@
+function carts:get_sign(z)
+	if z == 0 then
+		return 0
+	else
+		return z / math.abs(z)
+	end
+end
+
+function carts:manage_attachment(player, obj)
+	if not player then
+		return
+	end
+	local status = obj ~= nil
+	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
+		player:set_detach()
+		player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
+	end
+end
+
+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 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
+
+	-- Front
+	dir.y = 0
+	cur = vector.add(pos, dir)
+	if carts:is_rail(cur, railtype) then
+		return dir
+	end
+	-- Up
+	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 carts:is_rail(cur, railtype) then
+		return dir
+	end
+	return nil
+end
+
+function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
+	local pos = vector.round(pos_)
+	local cur
+	local left_check, right_check = true, true
+
+	-- Check left and right
+	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
+		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
+	end
+
+	-- Normal
+	cur = carts:check_front_up_down(pos, dir, true, railtype)
+	if cur then
+		return cur
+	end
+
+	-- 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
+
+	-- 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
+
+	-- 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:register_rail(name, def, railparams)
+	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},
+		},
+		sounds = default.node_sound_metal_defaults()
+	}
+	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
+
+	if railparams then
+		carts.railparams[name] = table.copy(railparams)
+	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/mods/carts/init.lua b/mods/carts/init.lua
new file mode 100644
index 0000000..7cfee74
--- /dev/null
+++ b/mods/carts/init.lua
@@ -0,0 +1,403 @@
+
+carts = {}
+carts.modpath = minetest.get_modpath("carts")
+carts.railparams = {}
+
+-- Maximal speed of the cart in m/s (min = -1)
+carts.speed_max = 7
+-- Set to -1 to disable punching the cart from inside (min = -1)
+carts.punch_speed_max = 5
+
+
+dofile(carts.modpath.."/functions.lua")
+dofile(carts.modpath.."/rails.lua")
+
+-- Support for non-default games
+if not default.player_attached then
+	default.player_attached = {}
+end
+
+local cart_entity = {
+	physical = false, -- otherwise going uphill breaks
+	collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
+	visual = "mesh",
+	mesh = "carts_cart.b3d",
+	visual_size = {x=1, y=1},
+	textures = {"carts_cart.png"},
+
+	driver = nil,
+	punched = false, -- used to re-send velocity and position
+	velocity = {x=0, y=0, z=0}, -- only used on punch
+	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 cart_entity: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
+		carts:manage_attachment(clicker, nil)
+	elseif not self.driver then
+		self.driver = player_name
+		carts:manage_attachment(clicker, self.object)
+	end
+end
+
+function cart_entity:on_activate(staticdata, dtime_s)
+	self.object:set_armor_groups({immortal=1})
+	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
+	if data.old_vel then
+		self.old_vel = data.old_vel
+	end
+end
+
+function cart_entity:get_staticdata()
+	return minetest.serialize({
+		railtype = self.railtype,
+		old_dir = self.old_dir,
+		old_vel = self.old_vel
+	})
+end
+
+function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
+	local pos = self.object:getpos()
+	if not self.railtype then
+		local node = minetest.get_node(pos).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.punched = true
+		return
+	end
+
+	if puncher:get_player_control().sneak then
+		if self.sound_handle then
+			minetest.sound_stop(self.sound_handle)
+		end
+		-- 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)
+			carts:manage_attachment(player, nil)
+		end
+		for _,obj_ in ipairs(self.attached_items) do
+			if obj_ then
+				obj_:set_detach()
+			end
+		end
+
+		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.object:getvelocity()
+	if puncher:get_player_name() == self.driver then
+		if math.abs(vel.x + vel.z) > carts.punch_speed_max then
+			return
+		end
+	end
+
+	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 = 2 * (time_from_last_punch / punch_interval)
+
+	self.velocity = vector.multiply(cart_dir, f)
+	self.old_dir = cart_dir
+	self.punched = true
+end
+
+local function rail_on_step_event(handler, obj, dtime)
+	if handler then
+		handler(obj, dtime)
+	end
+end
+
+-- sound refresh interval = 1.0sec
+local function rail_sound(self, dtime)
+	if not self.sound_ttl then
+		self.sound_ttl = 1.0
+		return
+	elseif self.sound_ttl > 0 then
+		self.sound_ttl = self.sound_ttl - dtime
+		return
+	end
+	self.sound_ttl = 1.0
+	if self.sound_handle then
+		local handle = self.sound_handle
+		self.sound_handle = nil
+		minetest.after(0.2, minetest.sound_stop, handle)
+	end
+	local vel = self.object:getvelocity()
+	local speed = vector.length(vel)
+	if speed > 0 then
+		self.sound_handle = minetest.sound_play(
+			"carts_cart_moving", {
+			object = self.object,
+			gain = (speed / carts.speed_max) / 2,
+			loop = true,
+		})
+	end
+end
+
+local function rail_on_step(self, dtime)
+	local pos = self.object:getpos()
+	local node = minetest.get_node(pos)
+	local railparams = carts.railparams[node.name] or {}
+
+	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
+
+	-- stop cart if velocity vector flips
+	if self.old_vel and (((self.old_vel.x * vel.x) < 0) or
+			((self.old_vel.z * vel.z) < 0)) and
+			(self.old_vel.y == 0) then
+		self.old_dir = {x = 0, y = 0, z = 0}
+		self.old_vel = {x = 0, y = 0, z = 0}
+		self.velocity = {x = 0, y = 0, z = 0}
+		self.old_pos = pos
+		self.object:setvelocity(vector.new())
+		self.object:setacceleration(vector.new())
+		rail_on_step_event(railparams.on_step, self, dtime)
+		return
+	end
+	self.old_vel = vector.new(vel)
+
+	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) then
+			-- Do not check one node multiple times
+			rail_on_step_event(railparams.on_step, self, dtime)
+			return
+		end
+	end
+
+	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 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
+		)
+
+		if not found_path then
+			-- No rail found: reset back to the expected position
+			pos = vector.new(self.old_pos)
+			update.pos = true
+		end
+	end
+
+	local cart_dir = carts:velocity_to_dir(vel)
+
+	-- dir:         New moving direction of the cart
+	-- switch_keys: Currently pressed L/R key, used to ignore the key on the next rail node
+	local dir, switch_keys = carts:get_rail_direction(
+		pos, cart_dir, ctrl, self.old_switch, self.railtype
+	)
+
+	local new_acc = {x=0, y=0, z=0}
+	if vector.equals(dir, {x=0, y=0, z=0}) then
+		vel = {x=0, y=0, z=0}
+		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)
+			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)
+			update.pos = true
+		end
+		-- Up, down?
+		if dir.y ~= self.old_dir.y then
+			vel.y = dir.y * math.abs(vel.x + vel.z)
+			pos = vector.round(pos)
+			update.pos = true
+		end
+
+		-- Slow down or speed up..
+		local acc = dir.y * -4.0
+
+		-- no need to check for railparams == nil since we always make it exist.
+		local speed_mod = railparams.acceleration
+		if speed_mod and speed_mod ~= 0 then
+			-- Try to make it similar to the original carts mod
+			acc = acc + speed_mod
+		else
+			-- Handbrake
+			if ctrl and ctrl.down then
+				acc = acc - 1.6
+			else
+				acc = acc - 0.4
+			end
+		end
+
+		new_acc = vector.multiply(dir, acc)
+	end
+
+	-- Limits
+	local max_vel = carts.speed_max
+	for _,v in ipairs({"x","y","z"}) do
+		if math.abs(vel[v]) > max_vel then
+			vel[v] = carts:get_sign(vel[v]) * max_vel
+			new_acc[v] = 0
+			update.vel = true
+		end
+	end
+
+	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 = switch_keys
+
+	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
+	end
+
+	if not (update.vel or update.pos) then
+		rail_on_step_event(railparams.on_step, self, dtime)
+		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
+		anim = {x=1, y=1}
+	elseif dir.y == 1 then
+		anim = {x=2, y=2}
+	end
+	self.object:set_animation(anim, 1, 0)
+
+	self.object:setvelocity(vel)
+	if update.pos then
+		self.object:setpos(pos)
+	end
+
+	-- call event handler
+	rail_on_step_event(railparams.on_step, self, dtime)
+end
+
+function cart_entity:on_step(dtime)
+	rail_on_step(self, dtime)
+	rail_sound(self, dtime)
+end
+
+minetest.register_entity("carts:cart", cart_entity)
+
+minetest.register_craftitem("carts:cart", {
+	description = "Cart (Sneak+Click to pick up)",
+	inventory_image = minetest.inventorycube("carts_cart_top.png", "carts_cart_side.png", "carts_cart_side.png"),
+	wield_image = "carts_cart_side.png",
+	on_place = function(itemstack, placer, pointed_thing)
+		if not pointed_thing.type == "node" then
+			return
+		end
+		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
+
+		minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
+			{pos = pointed_thing.above})
+
+		if not minetest.setting_getbool("creative_mode") then
+			itemstack:take_item()
+		end
+		return itemstack
+	end,
+})
+
+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/mods/carts/license.txt b/mods/carts/license.txt
new file mode 100644
index 0000000..6c5beb4
--- /dev/null
+++ b/mods/carts/license.txt
@@ -0,0 +1,54 @@
+
+License of source code
+----------------------
+
+The MIT License (MIT)
+Copyright (C) 2012-2016 PilzAdam
+Copyright (C) 2014-2016 SmallJoker
+Copyright (C) 2012-2016 Various Minetest developers and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+For more details:
+https://opensource.org/licenses/MIT
+
+
+Licenses of media
+-----------------
+
+CC-0, see: https://creativecommons.org/share-your-work/public-domain/cc0/, except
+if other license is mentioned.
+
+
+Authors
+---------
+Originally from PixelBOX (Gambit):
+	carts_cart_side.png
+	carts_cart_top.png
+	carts_cart_front.png*
+	carts_cart.png*
+
+sofar + stujones11:
+	carts_cart.b3d and carts_cart.blend
+
+hexafraction, modified by sofar
+	carts_rail_*.png
+
+http://www.freesound.org/people/YleArkisto/sounds/253159/ - YleArkisto - CC-BY-3.0
+	carts_cart_moving.*.ogg
diff --git a/mods/carts/models/carts_cart.b3d b/mods/carts/models/carts_cart.b3d
new file mode 100644
index 0000000..4e7eba3
Binary files /dev/null and b/mods/carts/models/carts_cart.b3d differ
diff --git a/mods/carts/models/carts_cart.blend b/mods/carts/models/carts_cart.blend
new file mode 100644
index 0000000..7d2515e
Binary files /dev/null and b/mods/carts/models/carts_cart.blend differ
diff --git a/mods/carts/rails.lua b/mods/carts/rails.lua
new file mode 100644
index 0000000..f929e84
--- /dev/null
+++ b/mods/carts/rails.lua
@@ -0,0 +1,58 @@
+carts:register_rail("carts:rail", {
+	description = "Rail",
+	tiles = {
+		"carts_rail_straight.png", "carts_rail_curved.png",
+		"carts_rail_t_junction.png", "carts_rail_crossing.png"
+	},
+	inventory_image = "carts_rail_straight.png",
+	wield_image = "carts_rail_straight.png",
+	groups = carts:get_rail_groups(),
+}, {})
+
+minetest.register_craft({
+	output = "carts:rail 16",
+	recipe = {
+		{"default:steel_ingot", "", "default:steel_ingot"},
+		{"default:steel_ingot", "group:stick", "default:steel_ingot"},
+		{"default:steel_ingot", "", "default:steel_ingot"},
+	}
+})
+
+minetest.register_alias("default:rail", "carts:rail")
+
+carts:register_rail("carts:powerrail", {
+	description = "Powered rail",
+	tiles = {
+		"carts_rail_straight_pwr.png", "carts_rail_curved_pwr.png",
+		"carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"
+	},
+	groups = carts:get_rail_groups(),
+}, {acceleration = 4})
+
+minetest.register_craft({
+	output = "carts:powerrail 8",
+	recipe = {
+		{"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"},
+		{"default:steel_ingot", "group:stick", "default:steel_ingot"},
+		{"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"},
+	}
+})
+
+carts:register_rail("carts:brakerail", {
+	description = "Brake rail",
+	tiles = {
+		"carts_rail_straight_brk.png", "carts_rail_curved_brk.png",
+		"carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png"
+	},
+	groups = carts:get_rail_groups(),
+}, {acceleration = -3})
+
+
+minetest.register_craft({
+	output = "carts:brakerail 8",
+	recipe = {
+		{"default:steel_ingot", "default:coal_lump", "default:steel_ingot"},
+		{"default:steel_ingot", "group:stick", "default:steel_ingot"},
+		{"default:steel_ingot", "default:coal_lump", "default:steel_ingot"},
+	}
+})
diff --git a/mods/carts/sounds/carts_cart_moving.1.ogg b/mods/carts/sounds/carts_cart_moving.1.ogg
new file mode 100644
index 0000000..869e765
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.1.ogg differ
diff --git a/mods/carts/sounds/carts_cart_moving.2.ogg b/mods/carts/sounds/carts_cart_moving.2.ogg
new file mode 100644
index 0000000..b4cc508
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.2.ogg differ
diff --git a/mods/carts/sounds/carts_cart_moving.3.ogg b/mods/carts/sounds/carts_cart_moving.3.ogg
new file mode 100644
index 0000000..e19a782
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.3.ogg differ
diff --git a/mods/carts/textures/carts_cart.png b/mods/carts/textures/carts_cart.png
new file mode 100644
index 0000000..965347c
Binary files /dev/null and b/mods/carts/textures/carts_cart.png differ
diff --git a/mods/carts/textures/carts_cart_front.png b/mods/carts/textures/carts_cart_front.png
new file mode 100644
index 0000000..b85696f
Binary files /dev/null and b/mods/carts/textures/carts_cart_front.png differ
diff --git a/mods/carts/textures/carts_cart_side.png b/mods/carts/textures/carts_cart_side.png
new file mode 100644
index 0000000..4362d6b
Binary files /dev/null and b/mods/carts/textures/carts_cart_side.png differ
diff --git a/mods/carts/textures/carts_cart_top.png b/mods/carts/textures/carts_cart_top.png
new file mode 100644
index 0000000..5f775ff
Binary files /dev/null and b/mods/carts/textures/carts_cart_top.png differ
diff --git a/mods/carts/textures/carts_rail_crossing.png b/mods/carts/textures/carts_rail_crossing.png
new file mode 100644
index 0000000..e10f3b1
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing.png differ
diff --git a/mods/carts/textures/carts_rail_crossing_brk.png b/mods/carts/textures/carts_rail_crossing_brk.png
new file mode 100644
index 0000000..0bf455e
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_brk.png differ
diff --git a/mods/carts/textures/carts_rail_crossing_pwr.png b/mods/carts/textures/carts_rail_crossing_pwr.png
new file mode 100644
index 0000000..d763d50
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_curved.png b/mods/carts/textures/carts_rail_curved.png
new file mode 100644
index 0000000..b320f0d
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved.png differ
diff --git a/mods/carts/textures/carts_rail_curved_brk.png b/mods/carts/textures/carts_rail_curved_brk.png
new file mode 100644
index 0000000..ca40723
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_brk.png differ
diff --git a/mods/carts/textures/carts_rail_curved_pwr.png b/mods/carts/textures/carts_rail_curved_pwr.png
new file mode 100644
index 0000000..781bbd0
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_straight.png b/mods/carts/textures/carts_rail_straight.png
new file mode 100644
index 0000000..30dcafe
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight.png differ
diff --git a/mods/carts/textures/carts_rail_straight_brk.png b/mods/carts/textures/carts_rail_straight_brk.png
new file mode 100644
index 0000000..0c69052
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight_brk.png differ
diff --git a/mods/carts/textures/carts_rail_straight_pwr.png b/mods/carts/textures/carts_rail_straight_pwr.png
new file mode 100644
index 0000000..e067ff1
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction.png b/mods/carts/textures/carts_rail_t_junction.png
new file mode 100644
index 0000000..8b1b946
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction_brk.png b/mods/carts/textures/carts_rail_t_junction_brk.png
new file mode 100644
index 0000000..6b4f6fa
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_brk.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction_pwr.png b/mods/carts/textures/carts_rail_t_junction_pwr.png
new file mode 100644
index 0000000..dd0eede
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_pwr.png differ
diff --git a/mods/default/aliases.lua b/mods/default/aliases.lua
index 1259ac0..6db3fc8 100644
--- a/mods/default/aliases.lua
+++ b/mods/default/aliases.lua
@@ -22,7 +22,7 @@ minetest.register_alias("papyrus", "default:papyrus")
 minetest.register_alias("bookshelf", "default:bookshelf")
 minetest.register_alias("glass", "default:glass")
 minetest.register_alias("wooden_fence", "default:fence_wood")
-minetest.register_alias("rail", "default:rail")
+minetest.register_alias("rail", "carts:rail")
 minetest.register_alias("ladder", "default:ladder_wood")
 minetest.register_alias("wood", "default:wood")
 minetest.register_alias("mese", "default:mese")
diff --git a/mods/default/crafting.lua b/mods/default/crafting.lua
index fe9862a..23f233f 100644
--- a/mods/default/crafting.lua
+++ b/mods/default/crafting.lua
@@ -352,15 +352,6 @@ minetest.register_craft({
 	}
 })
 
-minetest.register_craft({
-	output = 'default:rail 24',
-	recipe = {
-		{'default:steel_ingot', '', 'default:steel_ingot'},
-		{'default:steel_ingot', 'group:stick', 'default:steel_ingot'},
-		{'default:steel_ingot', '', 'default:steel_ingot'},
-	}
-})
-
 minetest.register_craft({
 	output = 'default:chest',
 	recipe = {
diff --git a/mods/default/nodes.lua b/mods/default/nodes.lua
index dba84da..e514a48 100644
--- a/mods/default/nodes.lua
+++ b/mods/default/nodes.lua
@@ -181,8 +181,6 @@ default:fence_aspen_wood
 default:glass
 default:obsidian_glass
 
-default:rail
-
 default:brick
 
 default:meselamp
@@ -2058,27 +2056,6 @@ minetest.register_node("default:obsidian_glass", {
 })
 
 
-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"},
-	inventory_image = "default_rail.png",
-	wield_image = "default_rail.png",
-	paramtype = "light",
-	sunlight_propagates = true,
-	walkable = false,
-	is_ground_content = false,
-	selection_box = {
-		type = "fixed",
-                -- but how to specify the dimensions for curved and sideways rails?
-                fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
-	},
-	groups = {dig_immediate = 2, attached_node = 1,
-		connect_to_raillike = minetest.raillike_group("rail")},
-})
-
-
 minetest.register_node("default:brick", {
 	description = "Brick Block",
 	paramtype2 = "facedir",
diff --git a/mods/default/textures/default_rail.png b/mods/default/textures/default_rail.png
deleted file mode 100644
index 26fed02..0000000
Binary files a/mods/default/textures/default_rail.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_crossing.png b/mods/default/textures/default_rail_crossing.png
deleted file mode 100644
index ba66e01..0000000
Binary files a/mods/default/textures/default_rail_crossing.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_curved.png b/mods/default/textures/default_rail_curved.png
deleted file mode 100644
index 9084ac2..0000000
Binary files a/mods/default/textures/default_rail_curved.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_t_junction.png b/mods/default/textures/default_rail_t_junction.png
deleted file mode 100644
index 486c416..0000000
Binary files a/mods/default/textures/default_rail_t_junction.png and /dev/null differ