Huge rewrite

Add sounds
Change Y acceleration to -2.5
Add partwise compatibility for MTG-registered rails
This commit is contained in:
SmallJoker 2016-11-22 20:32:17 +01:00
parent 74d8b8f931
commit cf9b82de37
8 changed files with 402 additions and 361 deletions

View File

@ -1,6 +1,7 @@
Minetest mod: boost_cart Minetest mod: boost_cart
========================== ==========================
Based on (and fully compatible with) the mod "carts" by PilzAdam Based on (and fully compatible with) the mod "carts" by PilzAdam
Also compatible with the carts mod in the subgame "minetest_game".
Target: Run smoothly as possible even on laggy server Target: Run smoothly as possible even on laggy server
@ -16,7 +17,7 @@ Target: Run smoothly as possible even on laggy server
License for everything License for everything
------------------------ ------------------------
CC-0 CC-0, if not specified otherwise below
Authors Authors
@ -36,6 +37,10 @@ kddekadenz
cart_side.png cart_side.png
cart_top.png cart_top.png
klankbeeld (CC-BY 3.0)
http://freesound.org/people/klankbeeld/sounds/174042/
cart_rail.*.ogg
numberZero numberZero
carts_rail_dtc.png carts_rail_dtc.png
carts_rail_dtc_on.png carts_rail_dtc_on.png

380
cart_entity.lua Normal file
View File

@ -0,0 +1,380 @@
local HAVE_MESECONS_ENABLED = minetest.global_exists("mesecon")
function boost_cart:on_rail_step(pos)
-- Play rail sound
if self.sound_counter <= 0 then
minetest.sound_play("cart_rail", {
pos = pos,
max_hear_distance = 40,
gain = 0.5
})
self.sound_counter = math.random(4, 15)
end
self.sound_counter = self.sound_counter - 1
if HAVE_MESECONS_ENABLED then
boost_cart:signal_detector_rail(pos)
end
end
local cart_entity = {
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,
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,
sound_counter = 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
boost_cart:manage_attachment(clicker, nil)
elseif not self.driver then
self.driver = player_name
boost_cart:manage_attachment(clicker, self.object)
end
end
function cart_entity:on_activate(staticdata, dtime_s)
self.object:set_armor_groups({immortal=1})
self.sound_counter = math.random(4, 15)
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 cart_entity:get_staticdata()
return minetest.serialize({
railtype = self.railtype,
old_dir = self.old_dir
})
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 = boost_cart: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
-- 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)
boost_cart:manage_attachment(player, nil)
end
for _, obj_ in pairs(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) > boost_cart.punch_speed_max then
return
end
end
local punch_dir = boost_cart:velocity_to_dir(puncher:get_look_dir())
punch_dir.y = 0
local cart_dir = boost_cart: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.punched = true
end
function cart_entity: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
local pos = self.object:getpos()
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
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 = boost_cart: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 = boost_cart: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 = boost_cart: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
-- Direction change detected
if not vector.equals(dir, self.old_dir) then
vel = vector.multiply(dir, math.abs(vel.x + vel.z))
update.vel = true
if dir.y ~= self.old_dir.y then
pos = vector.round(pos)
update.pos = true
end
end
-- Center on the rail
if dir.z ~= 0 and math.floor(pos.x + 0.5) ~= pos.x then
pos.x = math.floor(pos.x + 0.5)
update.pos = true
end
if dir.x ~= 0 and math.floor(pos.z + 0.5) ~= pos.z then
pos.z = math.floor(pos.z + 0.5)
update.pos = true
end
-- Calculate current cart acceleration
local acc = nil
local acc_meta = minetest.get_meta(pos):get_string("cart_acceleration")
if acc_meta == "halt" then
-- Stop rail
vel = {x=0, y=0, z=0}
acc = false
pos = vector.round(pos)
update.pos = true
update.vel = true
mod_found = true
end
if acc == nil then
-- Meta speed modifier
local speed_mod = tonumber(acc_meta)
if speed_mod and speed_mod ~= 0 then
-- Try to make it similar to the original carts mod
acc = speed_mod * 10
end
end
if acc == nil and boost_cart.mtg_compat then
-- MTG Cart API adaption
local rail_node = minetest.get_node(vector.round(pos))
local railparam = carts.railparams[rail_node.name]
if railparam and railparam.acceleration then
acc = railparam.acceleration
end
end
if acc == nil then
-- Handbrake
if ctrl and ctrl.down then
acc = -2
else
acc = -0.4
end
end
-- Slow down or speed up, depending on Y direction
if acc then
acc = acc + dir.y * -2.5
else
acc = 0
end
if self.old_dir.y ~= 1 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
boost_cart.on_rail_step(self, vector.round(pos))
-- Limits
local max_vel = boost_cart.speed_max
for _,v in pairs({"x","y","z"}) do
if math.abs(vel[v]) > max_vel then
vel[v] = boost_cart:get_sign(vel[v]) * max_vel
new_acc[v] = 0
update.vel = true
end
end
self.object:setacceleration(new_acc)
self.old_pos = pos
if not vector.equals(dir, {x=0, y=0, z=0}) then
self.old_dir = dir
end
self.old_switch = switch_keys
if self.punched then
-- Collect dropped items
for _, obj_ in pairs(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
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
update = nil
end
minetest.register_entity(":carts:cart", cart_entity)
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, "carts:cart")
elseif boost_cart:is_rail(pointed_thing.above) then
minetest.add_entity(pointed_thing.above, "carts:cart")
else
return
end
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"},
},
})

View File

@ -1,3 +1,4 @@
default default
mesecons? mesecons?
moreores? moreores?
carts?

353
init.lua
View File

@ -13,354 +13,23 @@ if not boost_cart.modpath then
"See also: http://dev.minetest.net/Installing_Mods") "See also: http://dev.minetest.net/Installing_Mods")
end end
dofile(boost_cart.modpath.."/functions.lua")
dofile(boost_cart.modpath.."/rails.lua")
local HAVE_MESECONS_ENABLED = minetest.global_exists("mesecon")
if HAVE_MESECONS_ENABLED then
dofile(boost_cart.modpath.."/detector.lua")
end
-- Support for non-default games -- Support for non-default games
if not default.player_attached then if not default.player_attached then
default.player_attached = {} default.player_attached = {}
end end
boost_cart.cart = { dofile(boost_cart.modpath.."/functions.lua")
physical = false, dofile(boost_cart.modpath.."/rails.lua")
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, if minetest.global_exists("mesecon") then
punched = false, -- used to re-send velocity and position dofile(boost_cart.modpath.."/detector.lua")
velocity = {x=0, y=0, z=0}, -- only used on punch --else
old_dir = {x=1, y=0, z=0}, -- random value to start the cart on punch -- minetest.register_alias("carts:powerrail", "boost_cart:detectorrail")
old_pos = nil, -- minetest.register_alias("carts:powerrail", "boost_cart:detectorrail_on")
old_switch = 0,
railtype = nil,
attached_items = {}
}
function boost_cart.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
boost_cart:manage_attachment(clicker, nil)
elseif not self.driver then
self.driver = player_name
boost_cart:manage_attachment(clicker, self.object)
end
end end
function boost_cart.cart:on_activate(staticdata, dtime_s) boost_cart.mtg_compat = minetest.global_exists("carts") and carts.pathfinder
self.object:set_armor_groups({immortal=1}) if boost_cart.mtg_compat then
if string.sub(staticdata, 1, string.len("return")) ~= "return" then minetest.log("action", "[boost_cart] Overwriting definitions of similar carts mod")
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 end
dofile(boost_cart.modpath.."/cart_entity.lua")
function boost_cart.cart:get_staticdata()
return minetest.serialize({
railtype = self.railtype,
old_dir = self.old_dir
})
end
function boost_cart.cart: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 = boost_cart: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
-- 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)
boost_cart: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) > boost_cart.punch_speed_max then
return
end
end
local punch_dir = boost_cart:velocity_to_dir(puncher:get_look_dir())
punch_dir.y = 0
local cart_dir = boost_cart: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.punched = true
end
function boost_cart.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
local pos = self.object:getpos()
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
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 = boost_cart: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 = boost_cart: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 = boost_cart: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
-- Direction change detected
if not vector.equals(dir, self.old_dir) then
vel = vector.multiply(dir, math.abs(vel.x + vel.z))
update.vel = true
if dir.y ~= self.old_dir.y then
pos = vector.round(pos)
update.pos = true
end
end
-- Center on the rail
if dir.z ~= 0 and math.floor(pos.x + 0.5) ~= pos.x then
pos.x = math.floor(pos.x + 0.5)
update.pos = true
end
if dir.x ~= 0 and math.floor(pos.z + 0.5) ~= pos.z then
pos.z = math.floor(pos.z + 0.5)
update.pos = true
end
-- Slow down or speed up..
local acc = dir.y * -1.8
local speed_mod_string = minetest.get_meta(pos):get_string("cart_acceleration")
local speed_mod = tonumber(speed_mod_string)
if speed_mod_string == "halt" then
vel = {x=0, y=0, z=0}
acc = 0
pos = vector.round(pos)
update.pos = true
update.vel = true
elseif speed_mod and speed_mod ~= 0 then
-- Try to make it similar to the original carts mod
acc = acc + (speed_mod * 10)
else
-- Handbrake
if ctrl and ctrl.down then
acc = acc - 1.6
else
acc = acc - 0.4
end
end
if self.old_dir.y ~= 1 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 HAVE_MESECONS_ENABLED then
boost_cart:signal_detector_rail(vector.round(pos))
end
-- Limits
local max_vel = boost_cart.speed_max
for _,v in ipairs({"x","y","z"}) do
if math.abs(vel[v]) > max_vel then
vel[v] = boost_cart: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
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
update = nil
end
minetest.register_entity(":carts:cart", boost_cart.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, "carts:cart")
elseif boost_cart:is_rail(pointed_thing.above) then
minetest.add_entity(pointed_thing.above, "carts:cart")
else
return
end
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"},
},
})

View File

@ -1,21 +1,10 @@
minetest.register_node(":default:rail", { boost_cart:register_rail(":default:rail", {
description = "Rail", description = "Rail",
drawtype = "raillike",
tiles = { tiles = {
"default_rail.png", "default_rail_curved.png", "default_rail.png", "default_rail_curved.png",
"default_rail_t_junction.png", "default_rail_crossing.png" "default_rail_t_junction.png", "default_rail_crossing.png"
}, },
inventory_image = "default_rail.png", groups = boost_cart:get_rail_groups()
wield_image = "default_rail.png",
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},
},
groups = boost_cart:get_rail_groups(),
}) })
if minetest.get_modpath("moreores") then if minetest.get_modpath("moreores") then
@ -28,7 +17,7 @@ else
"carts_rail_cp.png", "carts_rail_curved_cp.png", "carts_rail_cp.png", "carts_rail_curved_cp.png",
"carts_rail_t_junction_cp.png", "carts_rail_crossing_cp.png" "carts_rail_t_junction_cp.png", "carts_rail_crossing_cp.png"
}, },
groups = boost_cart:get_rail_groups(), groups = boost_cart:get_rail_groups()
}) })
minetest.register_craft({ minetest.register_craft({
@ -62,7 +51,6 @@ boost_cart:register_rail(":carts:powerrail", {
action_on = function(pos, node) action_on = function(pos, node)
boost_cart:boost_rail(pos, 0.5) boost_cart:boost_rail(pos, 0.5)
end, end,
action_off = function(pos, node) action_off = function(pos, node)
minetest.get_meta(pos):set_string("cart_acceleration", "0") minetest.get_meta(pos):set_string("cart_acceleration", "0")
end, end,
@ -98,7 +86,6 @@ boost_cart:register_rail(":carts:brakerail", {
action_on = function(pos, node) action_on = function(pos, node)
minetest.get_meta(pos):set_string("cart_acceleration", "-0.3") minetest.get_meta(pos):set_string("cart_acceleration", "-0.3")
end, end,
action_off = function(pos, node) action_off = function(pos, node)
minetest.get_meta(pos):set_string("cart_acceleration", "0") minetest.get_meta(pos):set_string("cart_acceleration", "0")
end, end,
@ -134,7 +121,6 @@ boost_cart:register_rail("boost_cart:startstoprail", {
action_on = function(pos, node) action_on = function(pos, node)
boost_cart:boost_rail(pos, 0.5) boost_cart:boost_rail(pos, 0.5)
end, end,
action_off = function(pos, node) action_off = function(pos, node)
minetest.get_meta(pos):set_string("cart_acceleration", "halt") minetest.get_meta(pos):set_string("cart_acceleration", "halt")
end, end,

BIN
sounds/cart_rail.1.ogg Normal file

Binary file not shown.

BIN
sounds/cart_rail.2.ogg Normal file

Binary file not shown.

BIN
sounds/cart_rail.3.ogg Normal file

Binary file not shown.