forked from VoxeLibre/VoxeLibre
490 lines
14 KiB
Lua
490 lines
14 KiB
Lua
local modname = minetest.get_current_modname()
|
|
local modpath = minetest.get_modpath(modname)
|
|
local mod = mcl_minecarts
|
|
local S = minetest.get_translator(modname)
|
|
mod.RAIL_GROUPS = {
|
|
STANDARD = 1,
|
|
CURVES = 2,
|
|
}
|
|
|
|
-- Inport functions and constants from elsewhere
|
|
local table_merge = mcl_util.table_merge
|
|
local check_connection_rules = mod.check_connection_rules
|
|
local update_rail_connections = mod.update_rail_connections
|
|
local minetest_fourdir_to_dir = minetest.fourdir_to_dir
|
|
local minetest_dir_to_fourdir = minetest.dir_to_fourdir
|
|
local vector_offset = vector.offset
|
|
local vector_equals = vector.equals
|
|
local north = mod.north
|
|
local south = mod.south
|
|
local east = mod.east
|
|
local west = mod.west
|
|
|
|
--- Rail direction Handleres
|
|
local function rail_dir_straight(pos, dir, node)
|
|
dir = vector.new(dir)
|
|
dir.y = 0
|
|
|
|
if node.param2 == 0 or node.param2 == 2 then
|
|
if vector_equals(dir, north) then
|
|
return north
|
|
else
|
|
return south
|
|
end
|
|
else
|
|
if vector_equals(dir,east) then
|
|
return east
|
|
else
|
|
return west
|
|
end
|
|
end
|
|
end
|
|
local function rail_dir_sloped(pos, dir, node)
|
|
local uphill = minetest_fourdir_to_dir(node.param2)
|
|
local downhill = minetest_fourdir_to_dir((node.param2+2)%4)
|
|
local up_uphill = vector_offset(uphill,0,1,0)
|
|
|
|
if vector_equals(dir, uphill) or vector_equals(dir, up_uphill) then
|
|
return up_uphill
|
|
else
|
|
return downhill
|
|
end
|
|
end
|
|
-- Fourdir to cardinal direction
|
|
-- 0 = north
|
|
-- 1 = east
|
|
-- 2 = south
|
|
-- 3 = west
|
|
|
|
-- This takes a table `dirs` that has one element for each cardinal direction
|
|
-- and which specifies the direction for a cart to continue in when entering
|
|
-- a rail node in the direction of the cardinal. This function takes node
|
|
-- rotations into account.
|
|
local function rail_dir_from_table(pos, dir, node, dirs)
|
|
dir = vector.new(dir)
|
|
dir.y = 0
|
|
local dir_fourdir = (minetest_dir_to_fourdir(dir) - node.param2 + 4) % 4
|
|
local new_fourdir = (dirs[dir_fourdir] + node.param2) % 4
|
|
return minetest_fourdir_to_dir(new_fourdir)
|
|
end
|
|
|
|
local CURVE_RAIL_DIRS = { [0] = 1, 1, 2, 2, }
|
|
local function rail_dir_curve(pos, dir, node)
|
|
return rail_dir_from_table(pos, dir, node, CURVE_RAIL_DIRS)
|
|
end
|
|
local function rail_dir_tee_off(pos, dir, node)
|
|
return rail_dir_from_table(pos, dir, node, CURVE_RAIL_DIRS)
|
|
end
|
|
|
|
local TEE_RAIL_ON_DIRS = { [0] = 0, 1, 1, 0 }
|
|
local function rail_dir_tee_on(pos, dir, node)
|
|
return rail_dir_from_table(pos, dir, node, TEE_RAIL_ON_DIRS)
|
|
end
|
|
|
|
local function rail_dir_cross(pos, dir, node)
|
|
dir = vector.new(dir)
|
|
dir.y = 0
|
|
|
|
-- Always continue in the same direction. No direction changes allowed
|
|
return dir
|
|
end
|
|
|
|
-- 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
|
|
local BASE_DEF = {
|
|
drawtype = "mesh",
|
|
mesh = "flat_track.obj",
|
|
paramtype = "light",
|
|
paramtype2 = "4dir",
|
|
stack_max = 64,
|
|
sounds = mcl_sounds.node_sound_metal_defaults(),
|
|
is_ground_content = true,
|
|
paramtype = "light",
|
|
use_texture_alpha = "clip",
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = { -8/16, -8/16, -8/16, 8/16, -7/16, 8/15 }
|
|
},
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
|
},
|
|
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
|
|
},
|
|
description = S("New Rail"), -- Temporary name to make debugging easier
|
|
_tt_help = S("Track for minecarts"),
|
|
_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."),
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
local node = minetest.get_node(pointed_thing.under)
|
|
local node_name = node.name
|
|
|
|
-- Don't allow placing rail above rail
|
|
if minetest.get_item_group(node_name,"rail") ~= 0 then
|
|
return itemstack
|
|
end
|
|
|
|
-- Handle right-clicking nodes with right-click handlers
|
|
if placer and not placer:get_player_control().sneak then
|
|
local node_def = minetest.registered_nodes[node_name] or {}
|
|
local on_rightclick = node_def and node_def.on_rightclick
|
|
if on_rightclick then
|
|
return on_rightclick(pointed_thing.under, node, placer, itemstack, pointed_thing) or itemstack
|
|
end
|
|
end
|
|
|
|
-- Place the rail
|
|
return minetest.item_place_node(itemstack, placer, pointed_thing)
|
|
end,
|
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
|
update_rail_connections(pos)
|
|
end,
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_straight,
|
|
},
|
|
_mcl_blast_resistance = 0.7,
|
|
_mcl_hardness = 0.7,
|
|
}
|
|
|
|
local SLOPED_RAIL_DEF = table.copy(BASE_DEF)
|
|
table_merge(SLOPED_RAIL_DEF,{
|
|
drawtype = "mesh",
|
|
mesh = "sloped_track.obj",
|
|
groups = {
|
|
rail_slope = 1,
|
|
not_in_creative_inventory = 1,
|
|
},
|
|
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 }
|
|
}
|
|
},
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_sloped,
|
|
},
|
|
})
|
|
|
|
function mod.register_rail(itemstring, ndef)
|
|
assert(ndef.tiles)
|
|
|
|
-- Extract out the craft recipe
|
|
local craft = ndef.craft
|
|
ndef.craft = nil
|
|
|
|
-- 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))
|
|
|
|
-- Make registrations
|
|
minetest.register_node(itemstring, ndef)
|
|
if craft then minetest.register_craft(craft) end
|
|
end
|
|
|
|
local function make_mesecons(base_name, suffix, base_mesecons)
|
|
if not base_mesecons then
|
|
if suffix == "_tee_off" or suffix == "_tee_on" then
|
|
base_mesecons = {}
|
|
else
|
|
return
|
|
end
|
|
end
|
|
|
|
local mesecons = table.copy(base_mesecons)
|
|
|
|
if suffix == "_tee_off" then
|
|
mesecons.effector = base_mesecons.effector and table.copy(base_mesecons.effector) or {}
|
|
|
|
local old_action_on = base_mesecons.effector and base_mesecons.effector.action_on
|
|
mesecons.effector.action_on = function(pos, node)
|
|
if old_action_on then old_action_on(pos, node) end
|
|
|
|
node.name = base_name.."_tee_on"
|
|
minetest.set_node(pos, node)
|
|
end
|
|
mesecons.effector.rules = mesecons.effector.rules or mesecon.rules.alldirs
|
|
elseif suffix == "_tee_on" then
|
|
mesecons.effector = base_mesecons.effector and table.copy(base_mesecons.effector) or {}
|
|
|
|
local old_action_off = base_mesecons.effector and base_mesecons.effector.action_off
|
|
mesecons.effector.action_off = function(pos, node)
|
|
if old_action_off then old_action_off(pos, node) end
|
|
|
|
node.name = base_name.."_tee_off"
|
|
minetest.set_node(pos, node)
|
|
end
|
|
mesecons.effector.rules = mesecons.effector.rules or mesecon.rules.alldirs
|
|
end
|
|
|
|
if mesecons.conductor then
|
|
mesecons.conductor = table.copy(base_mesecons.conductor)
|
|
|
|
if mesecons.conductor.onstate then
|
|
mesecons.conductor.onstate = base_mesecons.conductor.onstate..suffix
|
|
end
|
|
if base_mesecons.conductor.offstate then
|
|
mesecons.conductor.offstate = base_mesecons.conductor.offstate..suffix
|
|
end
|
|
end
|
|
|
|
return mesecons
|
|
end
|
|
|
|
|
|
function mod.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] },
|
|
drop = base_name,
|
|
groups = {
|
|
rail = mod.RAIL_GROUPS.STANDARD,
|
|
},
|
|
_mcl_minecarts = {
|
|
base_name = base_name,
|
|
can_slope = true,
|
|
},
|
|
}
|
|
table_merge(base_def, add); table_merge(sloped_def, add)
|
|
table_merge(base_def, def); table_merge(sloped_def, def)
|
|
|
|
-- Register the base node
|
|
mod.register_rail(base_name, base_def)
|
|
base_def.craft = nil; sloped_def.craft = nil
|
|
table_merge(base_def,{
|
|
_mcl_minecarts = {
|
|
railtype = "straight",
|
|
suffix = "",
|
|
},
|
|
})
|
|
|
|
-- Sloped variant
|
|
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(sloped_def),{
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_sloped,
|
|
suffix = "_sloped",
|
|
},
|
|
mesecons = make_mesecons(base_name, "_sloped", def.mesecons),
|
|
tiles = { tiles[1] },
|
|
_mcl_minecarts = {
|
|
railtype = "sloped",
|
|
},
|
|
}))
|
|
end
|
|
|
|
function mod.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 = {
|
|
_mcl_minecarts = { base_name = base_name },
|
|
groups = {
|
|
rail = mod.RAIL_GROUPS.CURVES
|
|
},
|
|
drop = base_name,
|
|
}
|
|
table_merge(base_def, add); table_merge(sloped_def, add)
|
|
table_merge(base_def, def); table_merge(sloped_def, def)
|
|
|
|
-- 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,
|
|
suffix = "",
|
|
},
|
|
}))
|
|
|
|
-- Update for other variants
|
|
base_def.craft = nil
|
|
table_merge(base_def, {
|
|
groups = {
|
|
not_in_creative_inventory = 1
|
|
}
|
|
})
|
|
|
|
-- 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",
|
|
suffix = "_corner",
|
|
},
|
|
mesecons = make_mesecons(base_name, "_corner", def.mesecons),
|
|
}))
|
|
|
|
-- Tee variants
|
|
mod.register_rail(base_name.."_tee_off", table_merge(table.copy(base_def),{
|
|
tiles = { tiles[3] },
|
|
mesecons = make_mesecons(base_name, "_tee_off", def.mesecons),
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_tee_off,
|
|
railtype = "tee",
|
|
suffix = "_tee_off",
|
|
},
|
|
}))
|
|
mod.register_rail(base_name.."_tee_on", table_merge(table.copy(base_def),{
|
|
tiles = { tiles[4] },
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_tee_on,
|
|
railtype = "tee",
|
|
suffix = "_tee_on",
|
|
},
|
|
mesecons = make_mesecons(base_name, "_tee_on", def.mesecons),
|
|
}))
|
|
|
|
-- Sloped variant
|
|
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(sloped_def),{
|
|
description = S("Sloped Rail"), -- Temporary name to make debugging easier
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_sloped,
|
|
railtype = "tee",
|
|
suffix = "_sloped",
|
|
},
|
|
mesecons = make_mesecons(base_name, "_sloped", def.mesecons),
|
|
tiles = { tiles[1] },
|
|
}))
|
|
|
|
-- Cross variant
|
|
mod.register_rail(base_name.."_cross", table_merge(table.copy(base_def),{
|
|
tiles = { tiles[5] },
|
|
_mcl_minecarts = {
|
|
get_next_dir = rail_dir_cross,
|
|
railtype = "cross",
|
|
suffix = "_cross",
|
|
},
|
|
mesecons = make_mesecons(base_name, "_cross", def.mesecons),
|
|
}))
|
|
end
|
|
|
|
function mod.register_rail_sloped(itemstring, def)
|
|
assert(def.tiles)
|
|
|
|
-- Build the node definition
|
|
local ndef = table.copy(SLOPED_RAIL_DEF)
|
|
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
|
|
|
|
--print("registering sloped rail "..itemstring.." with definition: "..dump(ndef))
|
|
|
|
-- Make registrations
|
|
minetest.register_node(itemstring, ndef)
|
|
end
|
|
|
|
-- Redstone rules
|
|
mod.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},
|
|
{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}}
|
|
|
|
dofile(modpath.."/rails/normal.lua")
|
|
dofile(modpath.."/rails/activator.lua")
|
|
dofile(modpath.."/rails/detector.lua")
|
|
dofile(modpath.."/rails/powered.lua")
|
|
|
|
-- Aliases
|
|
if minetest.get_modpath("doc") then
|
|
doc.add_entry_alias("nodes", "mcl_minecarts:golden_rail", "nodes", "mcl_minecarts:golden_rail_on")
|
|
end
|
|
|
|
local CURVY_RAILS_MAP = {
|
|
["mcl_minecarts:rail"] = "mcl_minecarts:rail_v2",
|
|
}
|
|
local function convert_legacy_curvy_rails(pos, node)
|
|
node.name = CURVY_RAILS_MAP[node.name]
|
|
if node.name then
|
|
minetest.swap_node(pos, node)
|
|
mod.update_rail_connections(pos, { legacy = true, ignore_neighbor_connections = true })
|
|
end
|
|
end
|
|
for old,new in pairs(CURVY_RAILS_MAP) do
|
|
local new_def = minetest.registered_nodes[new]
|
|
minetest.register_node(old, {
|
|
drawtype = "raillike",
|
|
inventory_image = new_def.inventory_image,
|
|
groups = { rail = 1, legacy = 1 },
|
|
tiles = { new_def.tiles[1], new_def.tiles[1], new_def.tiles[1], new_def.tiles[1] },
|
|
_vl_legacy_convert_node = convert_legacy_curvy_rails
|
|
})
|
|
vl_legacy.register_item_conversion(old, new)
|
|
end
|
|
local STRAIGHT_RAILS_MAP ={
|
|
["mcl_minecarts:golden_rail"] = "mcl_minecarts:golden_rail_v2",
|
|
["mcl_minecarts:golden_rail_on"] = "mcl_minecarts:golden_rail_v2_on",
|
|
["mcl_minecarts:activator_rail"] = "mcl_minecarts:activator_rail_v2",
|
|
["mcl_minecarts:activator_rail_on"] = "mcl_minecarts:activator_rail_v2_on",
|
|
["mcl_minecarts:detector_rail"] = "mcl_minecarts:detector_rail_v2",
|
|
["mcl_minecarts:detector_rail_on"] = "mcl_minecarts:detector_rail_v2_on",
|
|
}
|
|
local function convert_legacy_straight_rail(pos, node)
|
|
node.name = STRAIGHT_RAILS_MAP[node.name]
|
|
if node.name then
|
|
local connections = mod.get_rail_connections(pos, { legacy = true, ignore_neighbor_connections = true })
|
|
if not mod.HORIZONTAL_STANDARD_RULES[connections] then
|
|
-- Drop an immortal object at this location
|
|
local item_entity = minetest.add_item(pos, ItemStack(node.name))
|
|
if item_entity then
|
|
item_entity:get_luaentity()._immortal = true
|
|
end
|
|
|
|
-- This is a configuration that doesn't exist in the new rail
|
|
-- Replace with a standard rail
|
|
node.name = "mcl_minecarts:rail_v2"
|
|
end
|
|
minetest.swap_node(pos, node)
|
|
mod.update_rail_connections(pos, { legacy = true, ignore_neighbor_connections = true })
|
|
end
|
|
end
|
|
for old,new in pairs(STRAIGHT_RAILS_MAP) do
|
|
local new_def = minetest.registered_nodes[new]
|
|
minetest.register_node(old, {
|
|
drawtype = "raillike",
|
|
inventory_image = new_def.inventory_image,
|
|
groups = { rail = 1, legacy = 1 },
|
|
tiles = { new_def.tiles[1], new_def.tiles[1], new_def.tiles[1], new_def.tiles[1] },
|
|
_vl_legacy_convert_node = convert_legacy_straight_rail,
|
|
})
|
|
vl_legacy.register_item_conversion(old, new)
|
|
end
|
|
|