VoxeLibre/mods/ENTITIES/mcl_minecarts/rails.lua

598 lines
19 KiB
Lua
Raw Normal View History

2024-03-28 08:11:59 +01:00
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local mod = mcl_minecarts
mod.RAIL_GROUPS = {
STANDARD = 1,
CURVES = 2,
}
2024-03-28 08:11:59 +01:00
local S = minetest.get_translator(modname)
2024-03-31 12:21:07 +02:00
local table_merge = mcl_util.table_merge
local check_connection_rules = mod.check_connection_rules
local update_rail_connections = mod.update_rail_connections
local north = mod.north
local south = mod.south
local east = mod.east
local west = mod.west
-- Setup shared text
local railuse = S(
"Place them on the ground to build your railway, the rails will automatically connect to each other and will"..
" turn into curves, T-junctions, crossings and slopes as needed."
)
mod.text = mod.text or {}
mod.text.railuse = railuse
2024-03-28 08:11:59 +01:00
local function drop_railcarts(pos)
-- Scan for minecarts in this pos and force them to execute their "floating" check.
-- Normally, this will make them drop.
local objs = minetest.get_objects_inside_radius(pos, 1)
for o=1, #objs do
local le = objs[o]:get_luaentity()
if le then
-- All entities in this mod are minecarts, so this works
if string.sub(le.name, 1, 14) == "mcl_minecarts:" then
le._last_float_check = mcl_minecarts.check_float_time
end
end
end
end
local RAIL_DEFAULTS = {
is_ground_content = true,
paramtype = "light",
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
stack_max = 64,
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 0.7,
_mcl_hardness = 0.7,
after_destruct = drop_railcarts,
}
local RAIL_DEFAULT_GROUPS = {
handy=1, pickaxey=1,
attached_node=1,
rail=1,
connect_to_raillike=minetest.raillike_group("rail"),
dig_by_water=0,destroy_by_lava_flow=0,
transport=1
}
2017-08-28 23:40:47 +02:00
-- Template rail function
2021-05-25 12:52:25 +02:00
local function register_rail(itemstring, tiles, def_extras, creative)
2024-03-28 08:11:59 +01:00
local groups = table.copy(RAIL_DEFAULT_GROUPS)
2017-08-28 23:40:47 +02:00
if creative == false then
groups.not_in_creative_inventory = 1
end
local ndef = {
drawtype = "raillike",
tiles = tiles,
inventory_image = tiles[1],
wield_image = tiles[1],
groups = groups,
}
2024-03-28 08:11:59 +01:00
table_merge(ndef, RAIL_DEFAULTS)
ndef.walkable = false -- Old behavior
table_merge(ndef, def_extras)
2017-08-28 23:40:47 +02:00
minetest.register_node(itemstring, ndef)
end
-- Now get the translator after we have finished using S for other things
mod.text = mod.text or {}
mod.text.railuse = railuse
2024-03-31 12:21:07 +02:00
local BASE_DEF = {
description = S("New Rail"), -- Temporary name to make debugging easier
_tt_help = S("Track for minecarts"),
2024-03-31 12:21:07 +02:00
_doc_items_usagehelp = railuse,
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction."),
after_place_node = function(pos, placer, itemstack, pointed_thing)
update_rail_connections(pos, true)
end,
2024-03-31 12:21:07 +02:00
drawtype = "nodebox",
groups = RAIL_DEFAULT_GROUPS,
2024-03-31 12:21:07 +02:00
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, -7/16, 8/15}
}
},
paramtype = "light",
paramtype2 = "4dir",
2024-03-31 12:21:07 +02:00
}
table_merge(BASE_DEF, RAIL_DEFAULTS) -- Merge together old rail values
local SLOPED_RAIL_DEF = table.copy(BASE_DEF)
table_merge(SLOPED_RAIL_DEF,{
drawtype = "mesh",
mesh = "sloped_track.obj",
collision_box = {
type = "fixed",
fixed = {
{ -0.5, -0.5, -0.5, 0.5, 0.0, 0.5 },
{ -0.5, 0.0, 0.0, 0.5, 0.5, 0.5 }
}
},
selection_box = {
type = "fixed",
fixed = {
{ -0.5, -0.5, -0.5, 0.5, 0.0, 0.5 },
{ -0.5, 0.0, 0.0, 0.5, 0.5, 0.5 }
}
}
})
local function register_rail_v2(itemstring, ndef)
assert(ndef.tiles)
2024-03-28 08:11:59 +01:00
-- Extract out the craft recipe
local craft = ndef.craft
ndef.craft = nil
2024-03-28 08:11:59 +01:00
-- Add sensible defaults
if not ndef.inventory_image then ndef.inventory_image = ndef.tiles[1] end
if not ndef.wield_image then ndef.wield_image = ndef.tiles[1] end
print("registering rail "..itemstring.." with definition: "..dump(ndef))
2024-03-28 08:11:59 +01:00
-- Make registrations
minetest.register_node(itemstring, ndef)
if craft then minetest.register_craft(craft) end
2024-03-28 08:11:59 +01:00
end
mod.register_rail = register_rail_v2
2024-03-31 12:21:07 +02:00
local function rail_dir_straight(pos, dir, node)
local function inside(pos,dir,node)
if node.param2 == 0 or node.param2 == 2 then
if vector.equals(dir, north) then
return north
else
return south
end
2024-03-31 12:21:07 +02:00
else
if vector.equals(dir,east) then
return east
else
return west
end
2024-03-31 12:21:07 +02:00
end
end
local raw_dir = inside(pos, dir, node)
-- Handle reversing if there is a solid block in the next position
-- Only do this for straight tracks
local next_pos = vector.add(pos, raw_dir)
local next_node = minetest.get_node(next_pos)
local node_def = minetest.registered_nodes[next_node.name]
if node_def and node_def.groups and ( node_def.groups.solid or node_def.groups.stair ) then
-- Reverse the direction without giving -0 members
return vector.direction(next_pos, pos)
2024-03-31 12:21:07 +02:00
else
return raw_dir
2024-03-31 12:21:07 +02:00
end
end
local function rail_dir_curve(pos, dir, node)
if node.param2 == 0 then
-- South and East
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return east end
if vector.equals(dir, west) then return south end
if vector.equals(dir, east) then return east end
elseif node.param2 == 1 then
-- South and West
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return west end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return south end
elseif node.param2 == 2 then
-- North and West
if vector.equals(dir, south) then return west end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return north end
elseif node.param2 == 3 then
-- North and East
if vector.equals(dir, south) then return east end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return north end
if vector.equals(dir, east) then return east end
end
end
local function rail_dir_tee(pos, dir, node)
-- TODO: implement
return north
end
2024-03-31 12:21:07 +02:00
local function rail_dir_cross(pos, dir, node)
-- Always continue in the same direction. No direction changes allowed
return dir
end
2024-03-31 12:41:00 +02:00
local function register_straight_rail(base_name, tiles, def)
def = def or {}
local base_def = table.copy(BASE_DEF)
local sloped_def = table.copy(SLOPED_RAIL_DEF)
local add = {
tiles = { tiles[1] },
2024-03-31 12:41:00 +02:00
drop = base_name,
groups = {
rail = mod.RAIL_GROUPS.STANDARD,
},
_mcl_minecarts = {
base_name = base_name,
get_next_dir = rail_dir_straight,
can_slope = true,
},
}
table_merge(base_def, add); table_merge(sloped_def, add)
table_merge(base_def, def); table_merge(sloped_def, def)
2024-03-31 12:41:00 +02:00
-- Register the base node
mod.register_rail(base_name, base_def)
base_def.craft = nil; sloped_def.craft = nil
table_merge(base_def,{
groups = {
not_in_creative_inventory = 1,
},
_mcl_minecarts = {
railtype = "straight",
},
})
-- Sloped variant
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(base_def),{
description = S("Sloped Rail"), -- Temporary name to make debugging easier
2024-03-31 12:41:00 +02:00
_mcl_minecarts = {
get_next_dir = rail_dir_cross,
},
tiles = { tiles[1] },
_mcl_minecarts = {
railtype = "sloped",
},
2024-03-31 12:41:00 +02:00
}))
end
mod.register_straight_rail = register_straight_rail
2024-03-31 12:21:07 +02:00
local function register_curves_rail(base_name, tiles, def)
def = def or {}
local base_def = table.copy(BASE_DEF)
local sloped_def = table.copy(SLOPED_RAIL_DEF)
local add = {
2024-03-31 12:21:07 +02:00
_mcl_minecarts = { base_name = base_name },
groups = {
rail = mod.RAIL_GROUPS.CURVES
},
2024-03-31 12:21:07 +02:00
drop = base_name,
}
table_merge(base_def, add); table_merge(sloped_def, add)
table_merge(base_def, def); table_merge(sloped_def, def)
2024-03-31 12:21:07 +02:00
-- Register the base node
mod.register_rail(base_name, table_merge(table.copy(base_def),{
tiles = { tiles[1] },
_mcl_minecarts = {
get_next_dir = rail_dir_straight,
railtype = "straight",
can_slope = true,
},
2024-03-31 12:21:07 +02:00
}))
-- Update for other variants
base_def.craft = nil
table_merge(base_def, {
groups = {
not_in_creative_inventory = 1
}
})
2024-03-31 12:21:07 +02:00
-- Corner variants
mod.register_rail(base_name.."_corner", table_merge(table.copy(base_def),{
tiles = { tiles[2] },
_mcl_minecarts = {
get_next_dir = rail_dir_curve,
railtype = "corner",
2024-03-31 12:21:07 +02:00
},
}))
-- Tee variants
mod.register_rail(base_name.."_tee_off", table_merge(table.copy(base_def),{
tiles = { tiles[3] },
groups = {
not_in_creative_inventory = 1,
},
mesecons = {
effector = {
action_on = function(pos, node)
local new_node = {name = base_name.."_tee_on", param2 = node.param2}
minetest.swap_node(pos, new_node)
end,
rules = mesecon.rules.alldirs,
}
},
_mcl_minecarts = {
railtype = "corner",
},
2024-03-31 12:21:07 +02:00
}))
mod.register_rail(base_name.."_tee_on", table_merge(table.copy(base_def),{
tiles = { tiles[4] },
_mcl_minecarts = {
get_next_dir = rail_dir_tee,
railtype = "tee",
2024-03-31 12:21:07 +02:00
},
mesecons = {
effector = {
action_off = function(pos, node)
local new_node = {name = base_name.."_tee_off", param2 = node.param2}
minetest.swap_node(pos, new_node)
end,
rules = mesecon.rules.alldirs,
}
}
}))
-- Sloped variant
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(sloped_def),{
2024-03-31 12:21:07 +02:00
description = S("Sloped Rail"), -- Temporary name to make debugging easier
_mcl_minecarts = {
get_next_dir = rail_dir_cross,
railtype = "tee",
2024-03-31 12:21:07 +02:00
},
tiles = { tiles[1] },
}))
-- Cross variant
mod.register_rail(base_name.."_cross", table_merge(table.copy(base_def),{
tiles = { tiles[5] },
_mcl_minecarts = {
railtype = "cross",
},
2024-03-31 12:21:07 +02:00
}))
end
mod.register_curves_rail = register_curves_rail
2024-03-29 20:53:13 +01:00
local function register_rail_sloped(itemstring, def)
assert(def.tiles)
-- Build rail groups
local groups = table.copy(RAIL_DEFAULT_GROUPS)
if def.groups then table_merge(groups, def.groups) end
def.groups = groups
-- Build the node definition
2024-03-31 12:21:07 +02:00
local ndef = table.copy(SLOPED_RAIL_DEF)
2024-03-29 20:53:13 +01:00
table_merge(ndef, def)
-- Add sensible defaults
if not ndef.inventory_image then ndef.inventory_image = ndef.tiles[1] end
if not ndef.wield_image then ndef.wield_image = ndef.tiles[1] end
2024-03-31 12:21:07 +02:00
--print("registering sloped rail "..itemstring.." with definition: "..dump(ndef))
2024-03-29 20:53:13 +01:00
-- Make registrations
minetest.register_node(itemstring, ndef)
if craft then minetest.register_craft(craft) end
end
mod.register_rail_sloped = register_rail_sloped
2018-01-22 17:33:06 +01:00
-- Redstone rules
local rail_rules_long =
{{x=-1, y= 0, z= 0, spread=true},
{x= 1, y= 0, z= 0, spread=true},
{x= 0, y=-1, z= 0, spread=true},
2018-01-22 17:33:06 +01:00
{x= 0, y= 1, z= 0, spread=true},
{x= 0, y= 0, z=-1, spread=true},
{x= 0, y= 0, z= 1, spread=true},
{x= 1, y= 1, z= 0},
{x= 1, y=-1, z= 0},
{x=-1, y= 1, z= 0},
{x=-1, y=-1, z= 0},
{x= 0, y= 1, z= 1},
{x= 0, y=-1, z= 1},
{x= 0, y= 1, z=-1},
{x= 0, y=-1, z=-1}}
local rail_rules_short = mesecon.rules.pplate
2017-02-16 20:15:43 +01:00
-- Normal rail
2024-03-31 12:21:07 +02:00
mod.register_curves_rail("mcl_minecarts:rail_v2", {
"default_rail.png",
"default_rail_curved.png",
"default_rail_t_junction.png",
"default_rail_t_junction_on.png",
"default_rail_crossing.png"
},{
2024-03-31 12:41:00 +02:00
description = S("Rail"),
_tt_help = S("Track for minecarts"),
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction."),
_doc_items_usagehelp = railuse,
2024-03-31 12:21:07 +02:00
craft = {
output = "mcl_minecarts:rail_v2 16",
recipe = {
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mcl_core:stick", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"},
}
},
})
2024-03-31 12:41:00 +02:00
register_rail("mcl_minecarts:rail", {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"}, {}, false ) -- deprecated
2017-08-28 23:40:47 +02:00
-- Powered rail (off = brake mode)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:golden_rail_v2",{ "mcl_minecarts_rail_golden.png" },{
description = S("Powered Rail"),
_tt_help = S("Track for minecarts").."\n"..S("Speed up when powered, slow down when not powered"),
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts."),
_doc_items_usagehelp = railuse .. "\n" .. S("Without redstone power, the rail will brake minecarts. To make this rail accelerate"..
" minecarts, power it with redstone power."),
_doc_items_create_entry = false,
_rail_acceleration = -3,
_max_acceleration_velocity = 8,
mesecons = {
conductor = {
state = mesecon.state.off,
offstate = "mcl_minecarts:golden_rail_v2",
onstate = "mcl_minecarts:golden_rail_v2_on",
rules = rail_rules_long,
2017-08-28 23:40:47 +02:00
},
2024-03-31 12:41:00 +02:00
},
drop = "mcl_minecarts:golden_rail_v2",
craft = {
output = "mcl_minecarts:golden_rail_v2 6",
recipe = {
{"mcl_core:gold_ingot", "", "mcl_core:gold_ingot"},
{"mcl_core:gold_ingot", "mcl_core:stick", "mcl_core:gold_ingot"},
{"mcl_core:gold_ingot", "mesecons:redstone", "mcl_core:gold_ingot"},
}
2017-08-28 23:40:47 +02:00
}
2024-03-31 12:41:00 +02:00
})
register_rail("mcl_minecarts:golden_rail", {"mcl_minecarts_rail_golden.png", "mcl_minecarts_rail_golden_curved.png", "mcl_minecarts_rail_golden_t_junction.png", "mcl_minecarts_rail_golden_crossing.png"}, {}, false ) -- deprecated
2017-08-28 23:40:47 +02:00
-- Powered rail (on = acceleration mode)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:golden_rail_v2_on",{ "mcl_minecarts_rail_golden_powered.png" },{
_doc_items_create_entry = false,
_rail_acceleration = 4,
_max_acceleration_velocity = 8,
groups = {
not_in_creative_inventory = 1,
},
mesecons = {
conductor = {
state = mesecon.state.on,
offstate = "mcl_minecarts:golden_rail_v2",
onstate = "mcl_minecarts:golden_rail_v2_on",
rules = rail_rules_long,
2017-08-28 23:40:47 +02:00
},
2017-02-16 20:15:43 +01:00
},
2024-03-31 12:41:00 +02:00
drop = "mcl_minecarts:golden_rail_v2",
})
register_rail("mcl_minecarts:golden_rail_on", {"mcl_minecarts_rail_golden_powered.png", "mcl_minecarts_rail_golden_curved_powered.png", "mcl_minecarts_rail_golden_t_junction_powered.png", "mcl_minecarts_rail_golden_crossing_powered.png"}, { }, false ) -- deprecated
2017-08-28 23:40:47 +02:00
-- Activator rail (off)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:activator_rail_v2", {"mcl_minecarts_rail_activator.png"},{
description = S("Activator Rail"),
_tt_help = S("Track for minecarts").."\n"..S("Activates minecarts when powered"),
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts."),
_doc_items_usagehelp = railuse .. "\n" .. S("To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail."),
mesecons = {
conductor = {
state = mesecon.state.off,
offstate = "mcl_minecarts:activator_rail_v2",
onstate = "mcl_minecarts:activator_rail_v2_on",
rules = rail_rules_long,
},
2024-03-31 12:41:00 +02:00
},
craft = {
output = "mcl_minecarts:activator_rail_v2 6",
recipe = {
{"mcl_core:iron_ingot", "mcl_core:stick", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mesecons_torch:mesecon_torch_on", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mcl_core:stick", "mcl_core:iron_ingot"},
}
},
})
register_rail("mcl_minecarts:activator_rail", {"mcl_minecarts_rail_activator.png", "mcl_minecarts_rail_activator_curved.png", "mcl_minecarts_rail_activator_t_junction.png", "mcl_minecarts_rail_activator_crossing.png"}, {} ) -- deprecated
-- Activator rail (on)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:activator_rail_v2_on", {"mcl_minecarts_rail_activator_powered.png"},{
_doc_items_create_entry = false,
groups = {
not_in_creative_inventory = 1,
},
mesecons = {
conductor = {
state = mesecon.state.on,
offstate = "mcl_minecarts:activator_rail_v2",
onstate = "mcl_minecarts:activator_rail_v2_on",
rules = rail_rules_long,
},
effector = {
-- Activate minecarts
action_on = function(pos, node)
local pos2 = { x = pos.x, y =pos.y + 1, z = pos.z }
local objs = minetest.get_objects_inside_radius(pos2, 1)
for _, o in pairs(objs) do
local l = o:get_luaentity()
if l and string.sub(l.name, 1, 14) == "mcl_minecarts:" and l.on_activate_by_rail then
l:on_activate_by_rail()
2020-01-30 22:05:18 +01:00
end
2024-03-31 12:41:00 +02:00
end
end,
},
2024-03-31 12:41:00 +02:00
},
2024-03-31 12:41:00 +02:00
_mcl_minecarts_on_enter = function(pos, cart)
if cart.on_activate_by_rail then
cart:on_activate_by_rail()
end
end,
drop = "mcl_minecarts:activator_rail_v2",
})
register_rail("mcl_minecarts:activator_rail_on", {"mcl_minecarts_rail_activator_powered.png", "mcl_minecarts_rail_activator_curved_powered.png", "mcl_minecarts_rail_activator_t_junction_powered.png", "mcl_minecarts_rail_activator_crossing_powered.png"}, { }, false ) -- deprecated
-- Detector rail (off)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:detector_rail_v2",{"mcl_minecarts_rail_detector.png"},{
description = S("Detector Rail"),
_tt_help = S("Track for minecarts").."\n"..S("Emits redstone power when a minecart is detected"),
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms."),
_doc_items_usagehelp = railuse .. "\n" .. S("To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail."),
mesecons = {
receptor = {
state = mesecon.state.off,
rules = rail_rules_short,
},
2024-03-31 12:41:00 +02:00
},
_mcl_minecarts_on_enter = function(pos, cart)
local node = minetest.get_node(pos)
2024-03-31 12:41:00 +02:00
local newnode = {
name = "mcl_minecarts:detector_rail_v2_on",
param2 = node.param2
}
minetest.swap_node( pos, newnode )
mesecon.receptor_on(pos)
end,
craft = {
output = "mcl_minecarts:detector_rail_v2 6",
recipe = {
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mesecons_pressureplates:pressure_plate_stone_off", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mesecons:redstone", "mcl_core:iron_ingot"},
}
}
2024-03-31 12:41:00 +02:00
})
register_rail("mcl_minecarts:detector_rail", {"mcl_minecarts_rail_detector.png", "mcl_minecarts_rail_detector_curved.png", "mcl_minecarts_rail_detector_t_junction.png", "mcl_minecarts_rail_detector_crossing.png"}, {} ) -- deprecated
-- Detector rail (on)
2024-03-31 12:41:00 +02:00
mod.register_straight_rail("mcl_minecarts:detector_rail_v2_on",{"mcl_minecarts_rail_detector_powered.png"},{
groups = {
not_in_creative_inventory = 1,
},
_doc_items_create_entry = false,
mesecons = {
receptor = {
state = mesecon.state.on,
rules = rail_rules_short,
},
},
2024-03-31 12:41:00 +02:00
_mcl_minecarts_on_leave = function(pos, cart)
local node = minetest.get_node(pos)
2024-03-31 12:41:00 +02:00
local newnode = {
name = "mcl_minecarts:detector_rail",
param2 = node.param2
}
minetest.swap_node( pos, newnode )
mesecon.receptor_off(pos)
end,
drop = "mcl_minecarts:detector_rail_v2",
})
2024-03-31 12:41:00 +02:00
register_rail("mcl_minecarts:detector_rail_on", {"mcl_minecarts_rail_detector_powered.png", "mcl_minecarts_rail_detector_curved_powered.png", "mcl_minecarts_rail_detector_t_junction_powered.png", "mcl_minecarts_rail_detector_crossing_powered.png"}, { }, false ) -- deprecated
2017-08-28 23:40:47 +02:00
-- Aliases
if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", "mcl_minecarts:golden_rail", "nodes", "mcl_minecarts:golden_rail_on")
end