Begin major rework of track registration system

This commit is contained in:
orwell96 2023-09-04 19:34:47 +02:00
parent 7ca8ac8d00
commit 950d6f640c
17 changed files with 2469 additions and 2176 deletions

View File

@ -18,8 +18,6 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
# Wagon prototype properties
{
... all regular luaentity properties (mesh, textures, collisionbox a.s.o)...
drives_on = {default=true},
^- used to define the tracktypes (see below) that wagon can drive on. The tracktype identifiers are given as keys, similar to privileges)
max_speed = 10,
^- optional, default 10: defines the maximum speed this wagon can drive. The maximum speed of a train is determined by the wagon with the lowest max_speed value.
seats = {

View File

@ -21,7 +21,7 @@ minetest.register_tool("advtrains:copytool", {
local node=minetest.get_node_or_nil(pointed_thing.under)
if not node then atprint("[advtrains]Ignore at placer position") return itemstack end
local nodename=node.name
if(not advtrains.is_track_and_drives_on(nodename, {default=true})) then
if(not advtrains.is_track(nodename)) then
atprint("no track here, not placing.")
return itemstack
end

View File

@ -294,7 +294,7 @@ end
-- Going from the rail at pos (does not need to be rounded) along connection with id conn_idx, if there is a matching rail, return it and the matching connid
-- returns: <adjacent pos>, <conn index of adjacent>, <my conn index>, <railheight of adjacent>
-- parameter this_conns_p is connection table of this rail and is optional, is determined by get_rail_info_at if not provided.
function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_on)
function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx)
local this_pos = advtrains.round_vector_floor_y(this_posnr)
local this_conns = this_conns_p
local _
@ -318,11 +318,11 @@ function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_
adj_pos.y = adj_pos.y + 1
end
local nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos, drives_on)
local nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos)
if not nextnode_ok then
adj_pos.y = adj_pos.y - 1
conn_y = conn_y + 1
nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos, drives_on)
nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos)
if not nextnode_ok then
return nil
end

View File

@ -268,17 +268,17 @@ end
--false if it's not a rail or the train does not drive on this rail, but it is loaded or
--nil if the node is neither loaded nor in trackdb
--the distraction between false and nil will be needed only in special cases.(train initpos)
function advtrains.get_rail_info_at(pos, drives_on)
function advtrains.get_rail_info_at(pos)
local rdp=advtrains.round_vector_floor_y(pos)
local node=ndb.get_node_or_nil(rdp)
if not node then return end
local nodename=node.name
if(not advtrains.is_track_and_drives_on(nodename, drives_on)) then
if(not advtrains.is_track(nodename)) then
return false
end
local conns, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2)
local conns, railheight = advtrains.get_track_connections(node.name, node.param2)
return true, conns, railheight
end

751
advtrains/oldtracks.lua Normal file
View File

@ -0,0 +1,751 @@
--advtrains by orwell96, see readme.txt
--dev-time settings:
--EDIT HERE
--If the old non-model rails on straight tracks should be replaced by the new...
--false: no
--true: yes
advtrains.register_replacement_lbms=false
--[[TracksDefinition
nodename_prefix
texture_prefix
description
common={}
straight={}
straight45={}
curve={}
curve45={}
lswitchst={}
lswitchst45={}
rswitchst={}
rswitchst45={}
lswitchcr={}
lswitchcr45={}
rswitchcr={}
rswitchcr45={}
vert1={
--you'll probably want to override mesh here
}
vert2={
--you'll probably want to override mesh here
}
]]--
advtrains.all_tracktypes={}
--definition preparation
local function conns(c1, c2, r1, r2) return {{c=c1, y=r1}, {c=c2, y=r2}} end
local function conns3(c1, c2, c3, r1, r2, r3) return {{c=c1, y=r1}, {c=c2, y=r2}, {c=c3, y=r3}} end
advtrains.ap={}
advtrains.ap.t_30deg_flat={
regstep=1,
variant={
st={
conns = conns(0,8),
desc = "straight",
tpdouble = true,
tpsingle = true,
trackworker = "cr",
},
cr={
conns = conns(0,7),
desc = "curve",
tpdouble = true,
trackworker = "swlst",
},
swlst={
conns = conns3(0,8,7),
desc = "left switch (straight)",
trackworker = "swrst",
switchalt = "cr",
switchmc = "on",
switchst = "st",
switchprefix = "swl",
},
swlcr={
conns = conns3(0,7,8),
desc = "left switch (curve)",
trackworker = "swrcr",
switchalt = "st",
switchmc = "off",
switchst = "cr",
switchprefix = "swl",
},
swrst={
conns = conns3(0,8,9),
desc = "right switch (straight)",
trackworker = "st",
switchalt = "cr",
switchmc = "on",
switchst = "st",
switchprefix = "swr",
},
swrcr={
conns = conns3(0,9,8),
desc = "right switch (curve)",
trackworker = "st",
switchalt = "st",
switchmc = "off",
switchst = "cr",
switchprefix = "swr",
},
},
regtp=true,
tpdefault="st",
trackworker={
["swrcr"]="st",
["swrst"]="st",
["cr"]="swlst",
["swlcr"]="swrcr",
["swlst"]="swrst",
},
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_yturnout={
regstep=1,
variant={
l={
conns = conns3(0,7,9),
desc = "Y-turnout (left)",
switchalt = "r",
switchmc = "off",
switchst = "l",
switchprefix = "",
},
r={
conns = conns3(0,9,7),
desc = "Y-turnout (right)",
switchalt = "l",
switchmc = "on",
switchst = "r",
switchprefix = "",
}
},
regtp=true,
tpdefault="l",
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_s3way={
regstep=1,
variant={
l={
conns = { {c=0}, {c=7}, {c=8}, {c=9}, {c=0} },
desc = "3-way turnout (left)",
switchalt = "s",
switchst="l",
switchprefix = "",
},
s={
conns = { {c=0}, {c=8}, {c=7}, {c=9}, {c=0} },
desc = "3-way turnout (straight)",
switchalt ="r",
switchst = "s",
switchprefix = "",
},
r={
conns = { {c=0}, {c=9}, {c=8}, {c=7}, {c=0} },
desc = "3-way turnout (right)",
switchalt = "l",
switchst="r",
switchprefix = "",
}
},
regtp=true,
tpdefault="l",
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_30deg_slope={
regstep=1,
variant={
vst1={conns = conns(8,0,0,0.5), rail_y = 0.25, desc = "steep uphill 1/2", slope=true},
vst2={conns = conns(8,0,0.5,1), rail_y = 0.75, desc = "steep uphill 2/2", slope=true},
vst31={conns = conns(8,0,0,0.33), rail_y = 0.16, desc = "uphill 1/3", slope=true},
vst32={conns = conns(8,0,0.33,0.66), rail_y = 0.5, desc = "uphill 2/3", slope=true},
vst33={conns = conns(8,0,0.66,1), rail_y = 0.83, desc = "uphill 3/3", slope=true},
},
regsp=true,
slopeplacer={
[2]={"vst1", "vst2"},
[3]={"vst31", "vst32", "vst33"},
max=3,--highest entry
},
slopeplacer_45={
[2]={"vst1_45", "vst2_45"},
max=2,
},
rotation={"", "_30", "_45", "_60"},
trackworker={},
increativeinv={},
}
advtrains.ap.t_30deg_straightonly={
regstep=1,
variant={
st={
conns = conns(0,8),
desc = "straight",
tpdouble = true,
tpsingle = true,
trackworker = "st",
},
},
regtp=true,
tpdefault="st",
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_30deg_straightonly_noplacer={
regstep=1,
variant={
st={
conns = conns(0,8),
desc = "straight",
tpdouble = true,
tpsingle = true,
trackworker = "st",
},
},
tpdefault="st",
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_45deg={
regstep=2,
variant={
st={
conns = conns(0,8),
desc = "straight",
tpdouble = true,
tpsingle = true,
trackworker = "cr",
},
cr={
conns = conns(0,6),
desc = "curve",
tpdouble = true,
trackworker = "swlst",
},
swlst={
conns = conns3(0,8,6),
desc = "left switch (straight)",
trackworker = "swrst",
switchalt = "cr",
switchmc = "on",
switchst = "st",
},
swlcr={
conns = conns3(0,6,8),
desc = "left switch (curve)",
trackworker = "swrcr",
switchalt = "st",
switchmc = "off",
switchst = "cr",
},
swrst={
conns = conns3(0,8,10),
desc = "right switch (straight)",
trackworker = "st",
switchalt = "cr",
switchmc = "on",
switchst = "st",
},
swrcr={
conns = conns3(0,10,8),
desc = "right switch (curve)",
trackworker = "st",
switchalt = "st",
switchmc = "off",
switchst = "cr",
},
},
regtp=true,
tpdefault="st",
trackworker={
["swrcr"]="st",
["swrst"]="st",
["cr"]="swlst",
["swlcr"]="swrcr",
["swlst"]="swrst",
},
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_perpcrossing={
regstep = 1,
variant={
st={
conns = { {c=0}, {c=8}, {c=4}, {c=12} },
desc = "perpendicular crossing",
tpdouble = true,
tpsingle = true,
trackworker = "st",
},
},
regtp=true,
tpdefault="st",
rotation={"", "_30", "_45", "_60"},
}
advtrains.ap.t_90plusx_crossing={
regstep = 1,
variant={
["30l"]={
conns = { {c=0}, {c=8}, {c=1}, {c=9} },
desc = "30/90 degree crossing (left)",
tpdouble = true,
tpsingle = true,
trackworker = "45l"
},
["45l"]={
conns = { {c=0}, {c=8}, {c=2}, {c=10} },
desc = "45/90 degree crossing (left)",
tpdouble = true,
tpsingle = true,
trackworker = "60l",
},
["60l"]={
conns = { {c=0}, {c=8}, {c=3}, {c=11}},
desc = "60/90 degree crossing (left)",
tpdouble = true,
tpsingle = true,
trackworker = "60r",
},
["60r"]={
conns = { {c=0}, {c=8}, {c=5}, {c=13} },
desc = "60/90 degree crossing (right)",
tpdouble = true,
tpsingle = true,
trackworker = "45r"
},
["45r"]={
conns = { {c=0}, {c=8}, {c=6}, {c=14} },
desc = "45/90 degree crossing (right)",
tpdouble = true,
tpsingle = true,
trackworker = "30r",
},
["30r"]={
conns = { {c=0}, {c=8}, {c=7}, {c=15}},
desc = "30/90 degree crossing (right)",
tpdouble = true,
tpsingle = true,
trackworker = "30l",
},
},
regtp=true,
tpdefault="30l",
rotation={""},
trackworker = {
["30l"] = "45l",
["45l"] = "60l",
["60l"] = "60r",
["60r"] = "45r",
["45r"] = "30r",
["30r"] = "30l",
}
}
advtrains.ap.t_diagonalcrossing = {
regstep=1,
variant={
["30l45r"]={
conns = {{c=1}, {c=9}, {c=6}, {c=14}},
desc = "30left-45right diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="60l30l",
},
["60l30l"]={
conns = {{c=3}, {c=11}, {c=1}, {c=9}},
desc = "30left-60right diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="60l45r"
},
["60l45r"]={
conns = {{c=3}, {c=11}, {c=6}, {c=14}},
desc = "60left-45right diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="60l60r"
},
["60l60r"]={
conns = {{c=3}, {c=11}, {c=5}, {c=13}},
desc = "60left-60right diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="60r45l",
},
--If 60l60r had a mirror image, it would be here, but it's symmetric.
-- 60l60r is also equivalent to 30l30r but rotated 90 degrees.
["60r45l"]={
conns = {{c=5}, {c=13}, {c=2}, {c=10}},
desc = "60right-45left diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="60r30r",
},
["60r30r"]={
conns = {{c=5}, {c=13}, {c=7}, {c=15}},
desc = "60right-30right diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="30r45l",
},
["30r45l"]={
conns = {{c=7}, {c=15}, {c=2}, {c=10}},
desc = "30right-45left diagonal crossing",
tpdouble=true,
tpsingle=true,
trackworker="30l45r",
},
},
regtp=true,
tpdefault="30l45r",
rotation={""},
trackworker = {
["30l45r"] = "60l30l",
["60l30l"] = "60l45r",
["60l45r"] = "60l60r",
["60l60r"] = "60r45l",
["60r45l"] = "60r30r",
["60r30r"] = "30r45l",
["30r45l"] = "30l45r",
}
}
advtrains.trackpresets = advtrains.ap
--definition format: ([] optional)
--[[{
nodename_prefix
texture_prefix
[shared_texture]
models_prefix
models_suffix (with dot)
[shared_model]
formats={
st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2
(each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all)
}
common={} change something on common rail appearance
}
[18.12.17] Note on new connection system:
In order to support real rail crossing nodes and finally make the trackplacer respect switches, I changed the connection system.
There can be a variable number of connections available. These are specified as tuples {c=<connection>, y=<rely>}
The table "at_conns" consists of {<conn1>, <conn2>...}
the "at_rail_y" property holds the value that was previously called "railheight"
Depending on the number of connections:
2 conns: regular rail
3 conns: switch:
- when train passes in at conn1, will move out of conn2
- when train passes in at conn2 or conn3, will move out of conn1
4 conns: cross (or cross switch, depending on arrangement of conns):
- conn1 <> conn2
- conn3 <> conn4
]]
-- Notify the user if digging the rail is not allowed
local function can_dig_callback(pos, player)
local ok, reason = advtrains.can_dig_or_modify_track(pos)
if not ok and player then
minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason)
end
return ok
end
function advtrains.register_tracks(tracktype, def, preset)
advtrains.trackplacer.register_tracktype(def.nodename_prefix, preset.tpdefault)
if preset.regtp then
advtrains.trackplacer.register_track_placer(def.nodename_prefix, def.texture_prefix, def.description, def)
end
if preset.regsp then
advtrains.slope.register_placer(def, preset)
end
for suffix, var in pairs(preset.variant) do
for rotid, rotation in ipairs(preset.rotation) do
if not def.formats[suffix] or def.formats[suffix][rotid] then
local img_suffix = suffix..rotation
local ndef = advtrains.merge_tables({
description=def.description.."("..(var.desc or "any")..rotation..")",
drawtype = "mesh",
paramtype="light",
paramtype2="facedir",
walkable = false,
selection_box = {
type = "fixed",
fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2},
},
mesh = def.shared_model or (def.models_prefix.."_"..img_suffix..def.models_suffix),
tiles = {def.shared_texture or (def.texture_prefix.."_"..img_suffix..".png"), def.second_texture},
groups = {
attached_node = advtrains.IGNORE_WORLD and 0 or 1,
advtrains_track=1,
["advtrains_track_"..tracktype]=1,
save_in_at_nodedb=1,
dig_immediate=2,
not_in_creative_inventory=1,
not_blocking_trains=1,
},
can_dig = can_dig_callback,
after_dig_node=function(pos)
advtrains.ndb.update(pos)
end,
after_place_node=function(pos)
advtrains.ndb.update(pos)
end,
at_nnpref = def.nodename_prefix,
at_suffix = suffix,
at_rotation = rotation,
at_rail_y = var.rail_y
}, def.common or {})
if preset.regtp then
ndef.drop = def.nodename_prefix.."_placer"
end
if preset.regsp and var.slope then
ndef.drop = def.nodename_prefix.."_slopeplacer"
end
--connections
ndef.at_conns = advtrains.rotate_conn_by(var.conns, (rotid-1)*preset.regstep)
local ndef_avt_table
if var.switchalt and var.switchst then
local switchfunc=function(pos, node, newstate)
newstate = newstate or var.switchalt -- support for 3 (or more) state switches
-- this code is only called from the internal setstate function, which
-- ensures that it is safe to switch the turnout
if newstate~=var.switchst then
advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..(var.switchprefix or "")..newstate..rotation, param2=node.param2})
advtrains.invalidate_all_paths(pos)
end
end
ndef.on_rightclick = function(pos, node, player)
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.setstate(pos, nil, node)
advtrains.log("Switch", player:get_player_name(), pos)
end
end
if var.switchmc then
ndef.mesecons = {effector = {
["action_"..var.switchmc] = function(pos, node)
advtrains.setstate(pos, nil, node)
end,
rules=advtrains.meseconrules
}}
end
ndef_avt_table = {
getstate = var.switchst,
setstate = switchfunc,
}
end
local adef={}
if def.get_additional_definiton then
adef=def.get_additional_definiton(def, preset, suffix, rotation)
end
ndef = advtrains.merge_tables(ndef, adef)
-- insert getstate/setstate functions after merging the additional definitions
if ndef_avt_table then
ndef.advtrains = advtrains.merge_tables(ndef.advtrains or {}, ndef_avt_table)
end
minetest.register_node(":"..def.nodename_prefix.."_"..suffix..rotation, ndef)
--trackplacer
if preset.regtp then
local tpconns = {conn1=ndef.at_conns[1].c, conn2=ndef.at_conns[2].c}
if var.tpdouble then
advtrains.trackplacer.add_double_conn(def.nodename_prefix, suffix, rotation, tpconns)
end
if var.tpsingle then
advtrains.trackplacer.add_single_conn(def.nodename_prefix, suffix, rotation, tpconns)
end
end
advtrains.trackplacer.add_worked(def.nodename_prefix, suffix, rotation, var.trackworker)
end
end
end
advtrains.all_tracktypes[tracktype]=true
end
function advtrains.is_track_and_drives_on(nodename, drives_on_p)
local drives_on = drives_on_p
if not drives_on then drives_on = advtrains.all_tracktypes end
local hasentry = false
for _,_ in pairs(drives_on) do
hasentry=true
end
if not hasentry then drives_on = advtrains.all_tracktypes end
if not minetest.registered_nodes[nodename] then
return false
end
local nodedef=minetest.registered_nodes[nodename]
for k,v in pairs(drives_on) do
if nodedef.groups["advtrains_track_"..k] then
return true
end
end
return false
end
function advtrains.get_track_connections(name, param2)
local nodedef=minetest.registered_nodes[name]
if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end
local noderot=param2
if not param2 then noderot=0 end
if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end
local tracktype
for k,_ in pairs(nodedef.groups) do
local tt=string.match(k, "^advtrains_track_(.+)$")
if tt then
tracktype=tt
end
end
return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype
end
-- Function called when a track is about to be dug or modified by the trackworker
-- Returns either true (ok) or false,"translated string describing reason why it isn't allowed"
function advtrains.can_dig_or_modify_track(pos)
if advtrains.get_train_at_pos(pos) then
return false, attrans("Position is occupied by a train.")
end
-- interlocking: tcb, signal IP a.s.o.
if advtrains.interlocking then
-- TCB?
if advtrains.interlocking.db.get_tcb(pos) then
return false, attrans("There's a Track Circuit Break here.")
end
-- signal ip?
if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter
return false, attrans("There's a Signal Influence Point here.")
end
end
return true
end
-- slope placer. Defined in register_tracks.
--crafted with rail and gravel
local sl={}
function sl.register_placer(def, preset)
minetest.register_craftitem(":"..def.nodename_prefix.."_slopeplacer",{
description = attrans("@1 Slope", def.description),
inventory_image = def.texture_prefix.."_slopeplacer.png",
wield_image = def.texture_prefix.."_slopeplacer.png",
groups={},
on_place = sl.create_slopeplacer_on_place(def, preset)
})
end
--(itemstack, placer, pointed_thing)
function sl.create_slopeplacer_on_place(def, preset)
return function(istack, player, pt)
if not pt.type=="node" then
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node"))
return istack
end
local pos=pt.above
if not pos then
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node"))
return istack
end
local node=minetest.get_node(pos)
if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to then
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: space occupied!"))
return istack
end
if not advtrains.check_track_protection(pos, player:get_player_name()) then
minetest.record_protection_violation(pos, player:get_player_name())
return istack
end
--determine player orientation (only horizontal component)
--get_look_horizontal may not be available
local yaw=player.get_look_horizontal and player:get_look_horizontal() or (player:get_look_yaw() - math.pi/2)
--rounding unit vectors is a nice way for selecting 1 of 8 directions since sin(30°) is 0.5.
local dirvec={x=math.floor(math.sin(-yaw)+0.5), y=0, z=math.floor(math.cos(-yaw)+0.5)}
--translate to direction to look up inside the preset table
local param2, rot45=({
[-1]={
[-1]=2,
[0]=3,
[1]=3,
},
[0]={
[-1]=2,
[1]=0,
},
[1]={
[-1]=1,
[0]=1,
[1]=0,
},
})[dirvec.x][dirvec.z], dirvec.x~=0 and dirvec.z~=0
local lookup=preset.slopeplacer
if rot45 then lookup=preset.slopeplacer_45 end
--go unitvector forward and look how far the next node is
local step=1
while step<=lookup.max do
local node=minetest.get_node(vector.add(pos, dirvec))
--next node solid?
if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to or advtrains.is_protected(pos, player:get_player_name()) then
--do slopes of this distance exist?
if lookup[step] then
if minetest.settings:get_bool("creative_mode") or istack:get_count()>=step then
--start placing
local placenodes=lookup[step]
while step>0 do
minetest.set_node(pos, {name=def.nodename_prefix.."_"..placenodes[step], param2=param2})
if not minetest.settings:get_bool("creative_mode") then
istack:take_item()
end
step=step-1
pos=vector.subtract(pos, dirvec)
end
else
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: Not enough slope items left (@1 required)", step))
end
else
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: There's no slope of length @1",step))
end
return istack
end
step=step+1
pos=vector.add(pos, dirvec)
end
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: no supporting node at upper end."))
return itemstack
end
end
advtrains.slope=sl
--END code, BEGIN definition
--definition format: ([] optional)
--[[{
nodename_prefix
texture_prefix
[shared_texture]
models_prefix
models_suffix (with dot)
[shared_model]
formats={
st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2
(each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all)
}
common={} change something on common rail appearance
}]]

View File

@ -1,9 +1,5 @@
-- passive.lua
-- API to passive components, as described in passive_api.txt of advtrains_luaautomation
-- This has been moved to the advtrains core in turn with the interlocking system,
-- to prevent a dependency on luaautomation.
local deprecation_warned = {}
-- Rework for advtrains 2.5: The passive API now uses the reworked node_state system. Please see the comment in tracks.lua
function advtrains.getstate(parpos, pnode)
local pos
@ -19,20 +15,8 @@ function advtrains.getstate(parpos, pnode)
local node=pnode or advtrains.ndb.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
local st
if ndef and ndef.advtrains and ndef.advtrains.getstate then
st=ndef.advtrains.getstate
elseif ndef and ndef.luaautomation and ndef.luaautomation.getstate then
if not deprecation_warned[node.name] then
minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!")
end
st=ndef.luaautomation.getstate
else
return nil
end
if type(st)=="function" then
return st(pos, node)
else
return st
if ndef and ndef.advtrains then
return ndef.advtrains.node_state
end
end
@ -45,31 +29,46 @@ function advtrains.setstate(parpos, newstate, pnode)
end
if type(pos)~="table" or (not pos.x or not pos.y or not pos.z) then
debug.sethook()
error("Invalid position supplied to getstate")
error("Invalid position supplied to setstate")
end
local node=pnode or advtrains.ndb.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
local st
if ndef and ndef.advtrains and ndef.advtrains.setstate then
st=ndef.advtrains.setstate
elseif ndef and ndef.luaautomation and ndef.luaautomation.setstate then
if not deprecation_warned[node.name] then
minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!")
end
st=ndef.luaautomation.setstate
else
return nil
if not ndef or not ndef.advtrains then
return false, "missing_node_def"
end
local old_state = ndef.advtrains.node_state
if old_state == newstate then
-- nothing needs to be done
return true
end
if not ndef.advtrains.node_state_map then
return false, "missing_node_state_map"
end
local new_node_name = ndef.advtrains.node_state_map[newstate]
if not new_node_name then
return false, "no_such_state"
end
-- prevent state switching when route lock or train is present
if advtrains.get_train_at_pos(pos) then
return false
return false, "train_here"
end
if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.pos_to_string(pos)) then
return false
return false, "route_lock_here"
end
st(pos, node, newstate)
-- perform the switch
local new_node = {name = new_node_name, param2 = node.param2}
advtrains.ndb.swap_node(pos, new_node)
-- if callback is present, call it
if ndef.advtrains.node_on_switch_state then
ndef.advtrains.node_on_switch_state(pos, new_node, old_state, newstate)
end
return true
end
@ -86,12 +85,7 @@ function advtrains.is_passive(parpos, pnode)
end
local node=pnode or advtrains.ndb.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
if ndef and ndef.advtrains and ndef.advtrains.getstate then
return true
elseif ndef and ndef.luaautomation and ndef.luaautomation.getstate then
if not deprecation_warned[node.name] then
minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!")
end
if ndef and ndef.advtrains and ndef.advtrains.node_state_map then
return true
else
return false
@ -102,20 +96,10 @@ end
function advtrains.set_fallback_state(pos, pnode)
local node=pnode or advtrains.ndb.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
local st
if ndef and ndef.advtrains and ndef.advtrains.setstate
and ndef.advtrains.fallback_state then
if advtrains.get_train_at_pos(pos) then
return false
end
if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.pos_to_string(pos)) then
return false
end
ndef.advtrains.setstate(pos, node, ndef.advtrains.fallback_state)
return true
if not ndef or not ndef.advtrains or not ndef.advtrains.node_fallback_state then
return false, "no_fallback_state"
end
return advtrains.setstate(pos, ndef.advtrains.node_fallback_state, node)
end

View File

@ -33,13 +33,12 @@
-- If you need to proceed along the path by a specific actual distance, it does NOT work to simply add it to the index. You should use the path_get_index_by_offset() function.
-- creates the path data structure, reconstructing the train from a position and a connid
-- Important! train.drives_on must exist while calling this method
-- returns: true - successful
-- nil - node not yet available/unloaded, please wait
-- false - node definitely gone, remove train
function advtrains.path_create(train, pos, connid, rel_index)
local posr = advtrains.round_vector_floor_y(pos)
local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, train.drives_on)
local node_ok, conns, rhe = advtrains.get_rail_info_at(pos)
if not node_ok then
return node_ok
end
@ -211,7 +210,7 @@ function advtrains.path_get(train, index)
if pef == train.path_trk_f then
node_ok, this_conns = advtrains.get_rail_info_at(pos)
if not node_ok then error("For train "..train.id..": Path item "..pef.." on-track but not a valid node!") end
adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on)
adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid)
end
pef = pef + 1
if adj_pos then
@ -250,7 +249,7 @@ function advtrains.path_get(train, index)
if peb == train.path_trk_b then
node_ok, this_conns = advtrains.get_rail_info_at(pos)
if not node_ok then error("For train "..train.id..": Path item "..peb.." on-track but not a valid node!") end
adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on)
adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid)
end
peb = peb - 1
if adj_pos then

View File

@ -40,9 +40,6 @@ local suppasp = {
for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", als="green"}}) do
advtrains.trackplacer.register_tracktype("advtrains:retrosignal", "")
advtrains.trackplacer.register_tracktype("advtrains:signal", "")
for rotid, rotation in ipairs({"", "_30", "_45", "_60"}) do
local crea=1
if rotid==1 and r=="off" then crea=0 end
@ -108,8 +105,8 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
},
can_dig = can_dig_func,
after_dig_node = after_dig_func,
--TODO add rotation using trackworker
})
advtrains.trackplacer.add_worked("advtrains:retrosignal", r, rotation, nil)
minetest.register_node("advtrains:signal_"..r..rotation, {
drawtype = "mesh",
@ -179,8 +176,8 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
},
can_dig = can_dig_func,
after_dig_node = after_dig_func,
--TODO add rotation using trackworker
})
advtrains.trackplacer.add_worked("advtrains:signal", r, rotation, nil)
end
local crea=1

View File

@ -3,311 +3,204 @@
--all new trackplacer code
local tp={
tracks={}
groups={}
}
function tp.register_tracktype(nnprefix, n_suffix)
if tp.tracks[nnprefix] then return end--due to the separate registration of slopes and flats for the same nnpref, definition would be overridden here. just don't.
tp.tracks[nnprefix]={
default=n_suffix,
single_conn={},
single_conn_1={},
single_conn_2={},
double_conn={},
double_conn_1={},
double_conn_2={},
--keys:conn1_conn2 (example:1_4)
--values:{name=x, param2=x}
twcycle={},
twrotate={},--indexed by suffix, list, tells order of rotations
modify={},
}
end
function tp.add_double_conn(nnprefix, suffix, rotation, conns)
local nodename=nnprefix.."_"..suffix..rotation
for i=0,3 do
tp.tracks[nnprefix].double_conn[((conns.conn1+4*i)%16).."_"..((conns.conn2+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].double_conn[((conns.conn2+4*i)%16).."_"..((conns.conn1+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].double_conn_1[((conns.conn1+4*i)%16).."_"..((conns.conn2+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].double_conn_2[((conns.conn2+4*i)%16).."_"..((conns.conn1+4*i)%16)]={name=nodename, param2=i}
end
tp.tracks[nnprefix].modify[nodename]=true
end
function tp.add_single_conn(nnprefix, suffix, rotation, conns)
local nodename=nnprefix.."_"..suffix..rotation
for i=0,3 do
tp.tracks[nnprefix].single_conn[((conns.conn1+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].single_conn[((conns.conn2+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].single_conn_1[((conns.conn1+4*i)%16)]={name=nodename, param2=i}
tp.tracks[nnprefix].single_conn_2[((conns.conn2+4*i)%16)]={name=nodename, param2=i}
end
tp.tracks[nnprefix].modify[nodename]=true
--[[ New in version 2.5:
The track placer no longer uses hacky nodename pattern matching.
The base criterion for rotating or matching tracks is the common "ndef.advtrains.track_place_group" property.
Only rails where this field is set are considered for replacement. Other rails can still be considered for connection.
Replacement ("bending") of rails can only happen within their respective track place group. Only two-conn rails are allowed in the trackplacer.
The track registration functions register the candidates for any given track_place_group in two separate collections:
- double: tracks that can be used to connect both ends of the rail
- single: tracks that will be used to connect conn1 when only a single end is to be connected
When track placing is requested, the calling code just supplies the track_place_group to be placed.
]]--
local function rotate(conn, rot)
return (conn + rot) % 16
end
function tp.add_worked(nnprefix, suffix, rotation, cycle_follows)
tp.tracks[nnprefix].twcycle[suffix]=cycle_follows
if not tp.tracks[nnprefix].twrotate[suffix] then tp.tracks[nnprefix].twrotate[suffix]={} end
table.insert(tp.tracks[nnprefix].twrotate[suffix], rotation)
end
--[[
rewrite algorithm.
selection criteria: these will never be changed or even selected:
- tracks being already connected on both sides
- tracks that are already connected on one side but are not bendable to the desired position
the following situations can occur:
1. there are two more than two rails around
1.1 there is one or more subset(s) that can be directly connected
-> choose the first possibility
2.2 not
-> choose the first one and orient straight
2. there's exactly 1 rail around
-> choose and orient straight
3. there's no rail around
-> set straight
]]
local function istrackandbc(pos_p, conn)
local tpos = pos_p
local cnode=minetest.get_node(advtrains.dirCoordSet(tpos, conn.c))
if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then
local cconns=advtrains.get_track_connections(cnode.name, cnode.param2)
return advtrains.conn_matches_to(conn, cconns)
end
--try the same 1 node below
tpos = {x=tpos.x, y=tpos.y-1, z=tpos.z}
cnode=minetest.get_node(advtrains.dirCoordSet(tpos, conn.c))
if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then
local cconns=advtrains.get_track_connections(cnode.name, cnode.param2)
return advtrains.conn_matches_to(conn, cconns)
end
return false
end
function tp.find_already_connected(pos)
local dnode=minetest.get_node(pos)
local dconns=advtrains.get_track_connections(dnode.name, dnode.param2)
local found_conn
for connid, conn in ipairs(dconns) do
if istrackandbc(pos, conn) then
if found_conn then --we found one in previous iteration
return true, true --signal that it's connected
else
found_conn = conn.c
end
end
end
return found_conn
end
function tp.rail_and_can_be_bent(originpos, conn)
local pos=advtrains.dirCoordSet(originpos, conn)
local newdir=(conn+8)%16
local node=minetest.get_node(pos)
if not advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then
return false
end
local ndef=minetest.registered_nodes[node.name]
local nnpref = ndef and ndef.at_nnpref
if not nnpref then return false end
local tr=tp.tracks[nnpref]
if not tr then return false end
if not tr.modify[node.name] then
--we actually can use this rail, but only if it already points to the desired direction.
if advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then
local cconns=advtrains.get_track_connections(node.name, node.param2)
return advtrains.conn_matches_to(conn, cconns)
end
end
-- If the rail is not allowed to be modified, also only use if already in desired direction
if not advtrains.can_dig_or_modify_track(pos) then
local cconns=advtrains.get_track_connections(node.name, node.param2)
return advtrains.conn_matches_to(conn, cconns)
end
--rail at other end?
local adj1, adj2=tp.find_already_connected(pos)
if adj1 and adj2 then
return false--dont destroy existing track
elseif adj1 and not adj2 then
if tr.double_conn[adj1.."_"..newdir] then
return true--if exists, connect new rail and old end
end
return false
else
if tr.single_conn[newdir] then--just rotate old rail to right orientation
return true
end
return false
end
end
function tp.bend_rail(originpos, conn)
local pos=advtrains.dirCoordSet(originpos, conn)
local newdir=advtrains.oppd(conn)
local node=minetest.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
local nnpref = ndef and ndef.at_nnpref
if not nnpref then return false end
local tr=tp.tracks[nnpref]
if not tr then return false end
--is rail already connected? no need to bend.
local conns=advtrains.get_track_connections(node.name, node.param2)
if advtrains.conn_matches_to(conn, conns) then
return
end
--rail at other end?
local adj1, adj2=tp.find_already_connected(pos)
if adj1 and adj2 then
return false--dont destroy existing track
elseif adj1 and not adj2 then
if tr.double_conn[adj1.."_"..newdir] then
advtrains.ndb.swap_node(pos, tr.double_conn[adj1.."_"..newdir])
return true--if exists, connect new rail and old end
end
return false
else
if tr.single_conn[newdir] then--just rotate old rail to right orientation
advtrains.ndb.swap_node(pos, tr.single_conn[newdir])
return true
end
return false
end
end
function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing, yaw)
--1. find all rails that are likely to be connected
local tr=tp.tracks[nnpref]
local p_rails={}
local p_railpos={}
for i=0,15 do
if tp.rail_and_can_be_bent(pos, i, nnpref) then
p_rails[#p_rails+1]=i
p_railpos[i] = pos
else
local upos = {x=pos.x, y=pos.y-1, z=pos.z}
if tp.rail_and_can_be_bent(upos, i, nnpref) then
p_rails[#p_rails+1]=i
p_railpos[i] = upos
end
end
-- Register a track node as candidate
-- tpg: the track place group to register the candidates for
-- name, ndef: the node name and node definition table to register
-- as_single: whether the rail should be considered as candidate for one-endpoint connection
-- Typically only set for the straight rail variants
-- as_double: whether the rail should be considered as candidate for two-endpoint connection
-- Typically set for straights and curves
function tp.register_candidate(tpg, name, ndef, as_single, as_double)
--get or create TP group
if not tp.groups[tpg] then
tp.groups[tpg] = {double = {}, single1 = {}, single2 = {}, default = {name = name, param2 = 0} }
-- note: this causes the first candidate to ever be registered to be the default (which is typically what you want)
end
local g = tp.groups[tpg]
-- try double_conn
if #p_rails > 1 then
--iterate subsets
for k1, conn1 in ipairs(p_rails) do
for k2, conn2 in ipairs(p_rails) do
if k1~=k2 then
local dconn1 = tr.double_conn_1
local dconn2 = tr.double_conn_2
if not (advtrains.yawToDirection(yaw, conn1, conn2) == conn1) then
dconn1 = tr.double_conn_2
dconn2 = tr.double_conn_1
end
-- Checks are made this way round so that dconn1 has priority (this will make arrows of atc rails
-- point in the right direction)
local using
if (dconn2[conn1.."_"..conn2]) then
using = dconn2[conn1.."_"..conn2]
end
if (dconn1[conn1.."_"..conn2]) then
using = dconn1[conn1.."_"..conn2]
end
if using then
-- has found a fitting rail in either direction
-- if not, continue loop
tp.bend_rail(p_railpos[conn1], conn1, nnpref)
tp.bend_rail(p_railpos[conn2], conn2, nnpref)
advtrains.ndb.swap_node(pos, using)
local nname=using.name
if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then
minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing)
end
return
-- get conns
assert(#ndef.at_conns == 2)
local c1, c2 = ndef.at_conns[1].c, ndef.at_conns[2].c
local is_symmetrical = (rotate(c1, 8) == c2)
-- store all possible rotations (param2 values)
for i=0,3 do
if as_double then
g.double[rotate(c1,i*4).."_"..rotate(c2,i*4)] = {name=name, param2=i}
if not is_symmmetrical then
g.double[rotate(c2,i*4).."_"..rotate(c1,i*4)] = {name=name, param2=i}
-- if the track is unsymmetric (e.g. a curve), we may require the "wrong" orientation to fill a gap.
end
end
if as_single then
g.single1[rotate(c1,i*4)] = {name=name, param2=i}
g.single2[rotate(c2,i*4)] = {name=name, param2=i}
end
end
end
local function check_or_bend_rail(origin, dir, pname, commit)
local pos = advtrains.pos_add_dir(origin, dir)
local back_dir = advtrains.oppd(dir);
local node_ok, conns = advtrains.get_rail_info_at(pos)
if not node_ok then
-- try the node one level below
pos.y = pos.y - 1
node_ok, conns = advtrains.get_rail_info_at(pos)
end
if not node_ok then
return false
end
-- if one conn of the node here already points towards us, nothing to do
for connid, conn in ipairs(conns) do
if back_dir == conn.c then
return true
end
end
-- can we bend the node here?
local node = advtrains.ndb.get_node(pos)
local ndef = minetest.registered_nodes[node.name]
if not ndef or not ndef.advtrains or not ndef.advtrains.track_place_group then
return false
end
-- now the track must be two-conn, else it wouldn't be allowed to have track_place_group set.
assert(#conns == 2)
-- Is player and game allowed to do this?
if not advtrains.can_dig_or_modify_track(pos) then
return false
end
if not advtrains.check_track_protection(pos, pname) then
return false
end
-- we confirmed that track can be modified. Does there exist a suitable connection candidate?
-- check if there are any unbound ends
local bound_connids = {}
for connid, conn in ipairs(conns) do
local adj_pos, adj_connid = advtrains.get_adjacent_rail(pos, conns, connid)
if adj_pos then
bound_connids[#bound_connids+1] = connid
end
end
-- depending on the nummber of ends, decide
if #bound_connids == 2 then
-- rail is within a fixed track, do not break up
return false
end
-- obtain the group table
local g = tp.groups[ndef.advtrains.track_place_group]
if #bound_connids == 1 then
-- we can attempt double
local bound_dir = conns[bound_connids[1]].c
if g.double[back_dir.."_"..bound_dir] then
if commit then
advtrains.ndb.swap_node(pos, g.double[back_dir.."_"..bound_dir])
end
return true
end
else
-- rail is entirely unbound, we can attempt single1
if g.single1[back_dir] then
if commit then
advtrains.ndb.swap_node(pos, g.single1[back_dir])
end
return true
end
end
end
local function track_place_node(pos, node, ndef)
advtrains.ndb.swap_node(pos, node)
local ndef = minetest.registered_nodes[node.name]
if ndef and ndef.after_place_node then
ndef.after_place_node(pos)
end
end
-- Main API function to place a track. Replaces the older "placetrack"
-- This function will attempt to place a track of the specified track placing group at the specified position, connecting it
-- with neighboring rails. Neighboring rails can themselves be replaced ("bent") within their own track place group,
-- if the player is permitted to do this.
-- Order of preference is:
-- Connect two track ends if possible
-- Connect one track end if any rail is near
-- Place the default track if no tracks are near
-- The function returns true on success.
function tp.place_track(pos, tpg, pname, yaw)
-- 1. collect neighboring tracks and whether they can be connected
local cand = {}
for i=0,15 do
if check_or_bend_rail(pos, i, pname) then
cand[#cand+1] = i
end
end
-- obtain the group table
local g = tp.groups[tpg]
-- 2. try all possible two-endpoint connections
for k1, conn1 in ipairs(cand) do
for k2, conn2 in ipairs(cand) do
if k1~=k2 then
-- order of conn1/conn2: prefer conn2 being in the direction of the player facing.
-- the combination the other way round will be run through in a later loop iteration
if advtrains.yawToDirection(yaw, conn1, conn2) == conn2 then
-- does there exist a suitable double-connection rail?
local node = g.double[conn1.."_"..conn2]
if node then
check_or_bend_rail(pos, conn1, pname, true)
check_or_bend_rail(pos, conn2, pname, true)
track_place_node(pos, node) -- calls after_place_node implicitly
return true
end
end
end
end
end
-- try single_conn
if #p_rails > 0 then
for ix, p_rail in ipairs(p_rails) do
local sconn1 = tr.single_conn_1
local sconn2 = tr.single_conn_2
if not (advtrains.yawToDirection(yaw, p_rail, (p_rail+8)%16) == p_rail) then
sconn1 = tr.single_conn_2
sconn2 = tr.single_conn_1
end
if sconn1[p_rail] then
local using = sconn1[p_rail]
tp.bend_rail(p_railpos[p_rail], p_rail, nnpref)
advtrains.ndb.swap_node(pos, using)
local nname=using.name
if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then
minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing)
end
return
end
if sconn2[p_rail] then
local using = sconn2[p_rail]
tp.bend_rail(p_railpos[p_rail], p_rail, nnpref)
advtrains.ndb.swap_node(pos, using)
local nname=using.name
if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then
minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing)
end
return
end
-- 3. try all possible one_endpoint connections
for k1, conn1 in ipairs(cand) do
-- select single1 or single2? depending on yaw
local single
if advtrains.yawToDirection(yaw, conn1, advtrains.oppd(conn1)) == conn1 then
single = g.single1
else
single = g.single2
end
local node = single[conn1]
if node then
check_or_bend_rail(pos, conn1, pname, true)
track_place_node(pos, node) -- calls after_place_node implicitly
return true
end
end
--use default
minetest.set_node(pos, {name=nnpref.."_"..tr.default})
if minetest.registered_nodes[nnpref.."_"..tr.default] and minetest.registered_nodes[nnpref.."_"..tr.default].after_place_node then
minetest.registered_nodes[nnpref.."_"..tr.default].after_place_node(pos, placer, itemstack, pointed_thing)
end
-- 4. if nothing worked, set the default
local node = g.default
track_place_node(pos, node) -- calls after_place_node implicitly
return true
end
function tp.register_track_placer(nnprefix, imgprefix, dispname, def)
minetest.register_craftitem(":"..nnprefix.."_placer",{
description = dispname,
inventory_image = imgprefix.."_placer.png",
wield_image = imgprefix.."_placer.png",
groups={advtrains_trackplacer=1, digtron_on_place=1},
liquids_pointable = def.liquids_pointable,
on_place = function(itemstack, placer, pointed_thing)
local name = placer:get_player_name()
if not name then
return itemstack, false
end
if pointed_thing.type=="node" then
local pos=pointed_thing.above
local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0})
if not advtrains.check_track_protection(pos, name) then
return itemstack, false
end
if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then
local s
if def.suitable_substrate then
s = def.suitable_substrate(upos)
else
s = minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable
end
if s then
-- minetest.chat_send_all(nnprefix)
local yaw = placer:get_look_horizontal()
tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing, yaw)
if not advtrains.is_creative(name) then
itemstack:take_item()
end
end
end
end
return itemstack, true
end,
})
end
-- TRACK WORKER --
minetest.register_craftitem("advtrains:trackworker",{
description = attrans("Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc."),
@ -316,116 +209,93 @@ minetest.register_craftitem("advtrains:trackworker",{
wield_image = "advtrains_trackworker.png",
stack_max = 1,
on_place = function(itemstack, placer, pointed_thing)
local name = placer:get_player_name()
if not name then
local name = placer:get_player_name()
if not name then
return
end
local has_aux1_down = placer:get_player_control().aux1
if pointed_thing.type=="node" then
local pos=pointed_thing.under
if not advtrains.check_track_protection(pos, name) then
return
end
local has_aux1_down = placer:get_player_control().aux1
if pointed_thing.type=="node" then
local pos=pointed_thing.under
if not advtrains.check_track_protection(pos, name) then
return
end
local node=minetest.get_node(pos)
local node=minetest.get_node(pos)
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
--atdebug(node.name.."\npattern recognizes:"..nnprefix.." / "..suffix.." / "..rotation)
--atdebug("nntab: ",tp.tracks[nnprefix])
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
rotation = ""
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
return
-- New since 2.5: only the fields in the node definition are considered, no more hacky pattern matching on the nodename
local ndef = minetest.registered_nodes[node.name]
if not ndef.advtrains or not ndef.advtrains.trackworker_next_rot then
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
return
end
-- check if the node is modify-protected
if advtrains.is_track(node.name) then
-- is a track, we can query
local can_modify, reason = advtrains.can_dig_or_modify_track(pos)
if not can_modify then
local str = attrans("This track can not be rotated!")
if reason then
str = str .. " " .. reason
end
end
-- check if the node is modify-protected
if advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then
-- is a track, we can query
local can_modify, reason = advtrains.can_dig_or_modify_track(pos)
if not can_modify then
local str = attrans("This track can not be rotated!")
if reason then
str = str .. " " .. reason
end
minetest.chat_send_player(placer:get_player_name(), str)
return
end
end
if has_aux1_down then
--feature: flip the node by 180°
--i've always wanted this!
advtrains.ndb.swap_node(pos, {name=node.name, param2=(node.param2+2)%4})
minetest.chat_send_player(placer:get_player_name(), str)
return
end
local modext=tp.tracks[nnprefix].twrotate[suffix]
if rotation==modext[#modext] then --increase param2
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4})
return
else
local modpos
for k,v in pairs(modext) do
if v==rotation then modpos=k end
end
if not modpos then
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
return
end
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})
end
end
if has_aux1_down then
--feature: flip the node by 180°
--i've always wanted this!
advtrains.ndb.swap_node(pos, {name=node.name, param2=(node.param2+2)%4})
return
end
local new_node = {name = ndef.advtrains.trackworker_next_rot, param2 = node.param2}
if ndef.advtrains.trackworker_rot_incr_param2 then
new_node.param2 = ((node.param2 + 1) % 4)
end
advtrains.ndb.swap_node(pos, new_node)
end
end,
on_use=function(itemstack, user, pointed_thing)
local name = user:get_player_name()
if not name then
return
local name = user:get_player_name()
if not name then
return
end
if pointed_thing.type=="node" then
local pos=pointed_thing.under
local node=minetest.get_node(pos)
if not advtrains.check_track_protection(pos, name) then
return
end
if pointed_thing.type=="node" then
local pos=pointed_thing.under
local node=minetest.get_node(pos)
if not advtrains.check_track_protection(pos, name) then
return
end
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
if advtrains.get_train_at_pos(pos) then return end
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
--atdebug(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
rotation = ""
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
minetest.chat_send_player(user:get_player_name(), attrans("This node can't be changed using the trackworker!"))
return
end
end
-- check if the node is modify-protected
if advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then
-- is a track, we can query
local can_modify, reason = advtrains.can_dig_or_modify_track(pos)
if not can_modify then
local str = attrans("This track can not be changed!")
if reason then
str = str .. " " .. reason
end
minetest.chat_send_player(user:get_player_name(), str)
return
-- New since 2.5: only the fields in the node definition are considered, no more hacky pattern matching on the nodename
local ndef = minetest.registered_nodes[node.name]
if not ndef.advtrains or not ndef.advtrains.trackworker_next_var then
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be changed using the trackworker!"))
return
end
-- check if the node is modify-protected
if advtrains.is_track(node.name) then
-- is a track, we can query
local can_modify, reason = advtrains.can_dig_or_modify_track(pos)
if not can_modify then
local str = attrans("This track can not be rotated!")
if reason then
str = str .. " " .. reason
end
minetest.chat_send_player(placer:get_player_name(), str)
return
end
local nextsuffix=tp.tracks[nnprefix].twcycle[suffix]
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2})
else
atprint(name, dump(tp.tracks))
end
local new_node = {name = ndef.advtrains.trackworker_next_var, param2 = node.param2}
advtrains.ndb.swap_node(pos, new_node)
end
end,
})

File diff suppressed because it is too large Load Diff

View File

@ -283,7 +283,7 @@ function advtrains.train_ensure_init(id, train)
assertdef(train, "id", id)
if not train.drives_on or not train.max_speed then
if not train.max_speed then
--atprint("in ensure_init: missing properties, updating!")
advtrains.update_trainpart_properties(id)
end
@ -1034,10 +1034,9 @@ end
-- Note: safe_decouple_wagon() has been moved to wagons.lua
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed (and more)
function advtrains.update_trainpart_properties(train_id, invert_flipstate)
local train=advtrains.trains[train_id]
train.drives_on=advtrains.merge_tables(advtrains.all_tracktypes)
--FIX: deep-copy the table!!!
train.max_speed=20
train.extent_h = 0;
@ -1079,13 +1078,6 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate)
end
rel_pos=rel_pos+wagon.wagon_span
if wagon.drives_on then
for k,_ in pairs(train.drives_on) do
if not wagon.drives_on[k] then
train.drives_on[k]=nil
end
end
end
train.max_speed=math.min(train.max_speed, wagon.max_speed)
train.extent_h = math.max(train.extent_h, wagon.extent_h or 1);
end

View File

@ -1367,7 +1367,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
local node=minetest.get_node_or_nil(pointed_thing.under)
if not node then atprint("[advtrains]Ignore at placer position") return itemstack end
local nodename=node.name
if(not advtrains.is_track_and_drives_on(nodename, prototype.drives_on)) then
if(not advtrains.is_track(nodename)) then
atprint("no track here, not placing.")
return itemstack
end
@ -1382,7 +1382,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
local yaw = placer:get_look_horizontal()
local plconnid = advtrains.yawToClosestConn(yaw, tconns)
local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, prototype.drives_on)
local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid)
if not prevpos then
minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!")
return
@ -1407,7 +1407,6 @@ advtrains.register_wagon("advtrains:wagon_placeholder", {
collisionbox = {-0.3,-0.3,-0.3, 0.3,0.3,0.3},
visual_size = {x=0.7, y=0.7},
initial_sprite_basepos = {x=0, y=0},
drives_on = advtrains.all_tracktypes,
max_speed = 5,
seats = {
},

View File

@ -24,7 +24,9 @@ dofile(modpath.."tool.lua")
dofile(modpath.."approach.lua")
dofile(modpath.."ars.lua")
dofile(modpath.."tsr_rail.lua")
--TODO reenable tsr rail
--dofile(modpath.."tsr_rail.lua")
minetest.register_privilege("interlocking", {description = "Can set up track sections, routes and signals.", give_to_singleplayer = true})

View File

@ -20,7 +20,9 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELI
dofile(modpath.."railwaytime.lua")
dofile(modpath.."scheduler.lua")
dofile(modpath.."stoprail.lua")
--TODO reenable stop rail
--dofile(modpath.."stoprail.lua")
function advtrains.lines.load(data)

View File

@ -113,15 +113,6 @@ local suppasp_ra = {
}
}
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:hs")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:ra")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf7")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3v")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:mast")
for _, rtab in ipairs({
{rot = "0", sbox = {-1/8, -1/2, -1/2, 1/8, 1/2, -1/4}, ici=true},
{rot = "30", sbox = {-3/8, -1/2, -1/2, -1/8, 1/2, -1/4},},
@ -201,7 +192,7 @@ for _, rtab in ipairs({
after_dig_node = advtrains.interlocking.signal_after_dig,
})
-- rotatable by trackworker
advtrains.trackplacer.add_worked("advtrains_signals_ks:hs", typ, "_"..rot)
--TODO add rotation using trackworker
end
@ -246,7 +237,7 @@ for _, rtab in ipairs({
after_dig_node = advtrains.interlocking.signal_after_dig,
})
-- rotatable by trackworker
advtrains.trackplacer.add_worked("advtrains_signals_ks:ra", typ, "_"..rot)
--TODO add rotation using trackworker
end
-- Schilder:
@ -283,7 +274,7 @@ for _, rtab in ipairs({
after_dig_node = advtrains.interlocking.signal_after_dig,
})
-- rotatable by trackworker
advtrains.trackplacer.add_worked("advtrains_signals_ks:"..prefix, typ, "_"..rot, nxt)
--TODO add rotation using trackworker
end
for typ, prts in pairs {
@ -378,7 +369,7 @@ for _, rtab in ipairs({
t.drop = "advtrains_signals_ks:zs3_off_0"
t.selection_box.fixed[1][5] = 0
minetest.register_node("advtrains_signals_ks:zs3_"..typ.."_"..rot, t)
advtrains.trackplacer.add_worked("advtrains_signals_ks:zs3", typ, "_"..rot)
--TODO add rotation using trackworker
-- Zs 3v
local t = table.copy(def)
@ -387,7 +378,7 @@ for _, rtab in ipairs({
t.drop = "advtrains_signals_ks:zs3v_off_0"
t.tiles[3] = t.tiles[3] .. "^[multiply:yellow"
minetest.register_node("advtrains_signals_ks:zs3v_"..typ.."_"..rot, t)
advtrains.trackplacer.add_worked("advtrains_signals_ks:zs3v", typ, "_"..rot)
--TODO add rotation using trackworker
end
minetest.register_node("advtrains_signals_ks:mast_mast_"..rot, {
@ -412,7 +403,7 @@ for _, rtab in ipairs({
},
drop = "advtrains_signals_ks:mast_mast_0",
})
advtrains.trackplacer.add_worked("advtrains_signals_ks:mast","mast", "_"..rot)
--TODO add rotation using trackworker
end
-- Crafting

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,937 @@
-- Default tracks for advtrains
-- (c) orwell96 and contributors
local default_boxen = {
["st"] = {
[""] = {
selection_box = {
type = "fixed",
fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2},
}
},
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500},
{0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000},
{-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000}
}
}
},
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
},
["cr"] = {
[""] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.5000, 0.6875, -0.3750, 0.5000},
{-0.3750, -0.5000, -1.000, 1.000, -0.3750, 0.000}
}
}
},
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.5000, 0.7500, -0.3750, 0.8750},
{-0.3750, -0.5000, 0.8750, 0.2500, -0.3750, 1.188},
{0.7500, -0.5000, 0.2500, 1.063, -0.3750, 0.8750}
}
}
},
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.125, 0.5000, -0.3750, 0.6875},
{-0.8750, -0.5000, -0.9375, -0.5000, -0.3750, 0.06250},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.8125, -0.5000, -0.5000, 1.188, -0.3750, 0.5000},
{-0.1875, -0.5000, 0.5000, 0.8750, -0.3125, 0.8750},
{-0.2500, -0.5000, -0.9375, 0.3125, -0.3125, -0.5000}
}
}
},
},
["swlst"] = {
[""] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000},
{-0.3125, -0.5000, -1.000, 0.9375, -0.3125, -0.06250}
}
}
},
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500},
{0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000},
{-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000}
}
}
},
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.1875, 0.5000, -0.3750, 0.8750},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-0.8750, -0.5000, -0.8125, -0.5000, -0.3750, 0.5000}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
},
["swrst"] = {
[""] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000},
{-0.8125, -0.5000, -1.000, 0.4375, -0.3125, -0.06250}
}
}
},
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500},
{0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000},
{-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000}
}
}
},
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.1875, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-0.5000, -0.5000, 0.5000, 0.5000, -0.3750, 0.8750},
{-0.8125, -0.5000, -0.8750, 0.5000, -0.3750, -0.5000}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
},
}
default_boxen["swlcr"] = default_boxen["swlst"]
default_boxen["swrcr"] = default_boxen["swrst"]
--flat
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack",
texture_prefix="advtrains_dtrack",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("Track"),
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
if default_boxen[suffix] ~= nil and default_boxen[suffix][rotation] ~= nil then
return default_boxen[suffix][rotation]
else
return {}
end
end,
}, advtrains.ap.t_30deg_flat)
minetest.register_craft({
output = 'advtrains:dtrack_placer 50',
recipe = {
{'default:steel_ingot', 'group:stick', 'default:steel_ingot'},
{'default:steel_ingot', 'group:stick', 'default:steel_ingot'},
{'default:steel_ingot', 'group:stick', 'default:steel_ingot'},
},
})
local y3_boxen = {
[""] = {
selection_box = {
type = "fixed",
fixed = {
{-0.8750, -0.5000, -1.125, 0.8750, -0.3750, 0.4375}
}
}
},
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625},
{0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000},
}
}
},
--UX FIXME: - 3way - have to place straight route before l and r or the
--nodebox overlaps too much and can't place the straight track node.
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.1250, 0.5000, -0.3750, 0.8750},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-1.1250, -0.5000, -0.9375, -0.5000, -0.3750, 0.5000}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
--{-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000},
{-0.875, -0.5000, -0.5, 1.0, -0.3750, 0.5},
--{-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625},
{-0.4375, -0.5000, -0.8750, 0.5625, -0.3750, -0.5000},
--{0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000},
{-0.2500, -0.5000, -0.2500, 1.0000, -0.3750, 0.8125},
}
}
},
}
local function y3_turnouts_addef(def, preset, suffix, rotation)
return y3_boxen[rotation] or {}
end
-- y-turnout
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_sy",
texture_prefix="advtrains_dtrack_sy",
models_prefix="advtrains_dtrack_sy",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("Y-turnout"),
formats = {},
get_additional_definiton = y3_turnouts_addef,
}, advtrains.ap.t_yturnout)
minetest.register_craft({
output = 'advtrains:dtrack_sy_placer 2',
recipe = {
{'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'},
{'', 'advtrains:dtrack_placer', ''},
{'', 'advtrains:dtrack_placer', ''},
},
})
--3-way turnout
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_s3",
texture_prefix="advtrains_dtrack_s3",
models_prefix="advtrains_dtrack_s3",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("3-way turnout"),
formats = {},
get_additional_definiton = y3_turnouts_addef,
}, advtrains.ap.t_s3way)
minetest.register_craft({
output = 'advtrains:dtrack_s3_placer 1',
recipe = {
{'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'},
{'', 'advtrains:dtrack_placer', ''},
{'', '', ''},
},
})
-- Diamond Crossings
local perp_boxen = {
[""] = {}, --default size
["_30"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000}
}
}
},
["_45"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.8125, -0.5000, -0.8125, 0.8125, -0.3750, 0.8125}
}
}
},
["_60"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000}
}
}
},
}
-- perpendicular
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_xing",
texture_prefix="advtrains_dtrack_xing",
models_prefix="advtrains_dtrack_xing",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("Perpendicular Diamond Crossing Track"),
formats = {},
get_additional_definiton = function(def, preset, suffix, rotation)
return perp_boxen[rotation] or {}
end
}, advtrains.ap.t_perpcrossing)
minetest.register_craft({
output = 'advtrains:dtrack_xing_placer 3',
recipe = {
{'', 'advtrains:dtrack_placer', ''},
{'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'},
{'', 'advtrains:dtrack_placer', ''}
}
})
local ninety_plus_boxen = {
["30l"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500},
{0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000},
{-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000}
}
}
},
["30r"] = {
selection_box = {
type = "fixed",
fixed = {
{0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000},
{0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500},
{-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000},
{0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000}
}
}
},
["45l"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000}
}
}
},
["45r"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750},
{0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000},
{-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000}
}
}
},
["60l"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
["60r"] = {
selection_box = {
type = "fixed",
fixed = {
{1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000},
{1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000},
{0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750},
{1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875}
}
}
},
}
-- 90plusx
-- When you face east and param2=0, then this set of rails has a rail at 90
-- degrees to the viewer, plus another rail crossing at 30, 45 or 60 degrees.
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_xing90plusx",
texture_prefix="advtrains_dtrack_xing4590",
models_prefix="advtrains_dtrack_xing90plusx",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("90+Angle Diamond Crossing Track"),
formats = {},
get_additional_definiton = function(def, preset, suffix, rotation)
return ninety_plus_boxen[suffix] or {}
end,
}, advtrains.ap.t_90plusx_crossing)
minetest.register_craft({
output = 'advtrains:dtrack_xing90plusx_placer 2',
recipe = {
{'advtrains:dtrack_placer', '', ''},
{'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'},
{'', '', 'advtrains:dtrack_placer'}
}
})
-- Deprecate any rails using the old name scheme
minetest.register_lbm({
label = "Upgrade legacy 4590 rails",
name = "advtrains_train_track:replace_legacy_4590",
nodenames = {"advtrains:dtrack_xing4590_st"},
run_at_every_load = true,
action = function(pos, node)
minetest.log("actionPos!: " .. pos.x .. "," .. pos.y .. "," .. pos.z)
minetest.log("node!: " .. node.name .. "," .. node.param1 .. "," .. node.param2)
advtrains.ndb.swap_node(pos,
{
name="advtrains:dtrack_xing90plusx_45l",
param1=node.param1,
param2=node.param2,
})
end
})
-- This will replace any items left in the inventory
minetest.register_alias("advtrains:dtrack_xing4590_placer", "advtrains:dtrack_xing90plusx_placer")
local diagonal_boxen = {
["30r45l"] = {
selection_box = {
type = "fixed",
fixed = {
{0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000},
{0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500},
{-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000},
{0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000}
}
}
},
["60l30l"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
["60l60r"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000}
}
}
},
["60r30r"] = {
selection_box = {
type = "fixed",
fixed = {
{1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000},
{1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000},
{0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750},
{1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875}
}
}
},
["30l45r"] = {
selection_box = {
type = "fixed",
fixed = {
{-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000},
{-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500},
{0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000},
{-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000}
}
}
},
["60l45r"] = {
selection_box = {
type = "fixed",
fixed = {
{-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000},
{-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000},
{-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750},
{-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875}
}
}
},
["60r45l"] = {
selection_box = {
type = "fixed",
fixed = {
{1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000},
{1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000},
{0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750},
{1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875}
}
}
},
}
-- Diagonal
-- This set of rail crossings is named based on the angle of each intersecting
-- direction when facing east and param2=0. Rails with l/r swapped are mirror
-- images. For example, 30r45l is the mirror image of 30l45r.
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_xingdiag",
texture_prefix="advtrains_dtrack_xingdiag",
models_prefix="advtrains_dtrack_xingdiag",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
description=attrans("Diagonal Diamond Crossing Track"),
formats = {},
get_additional_definiton = function(def, preset, suffix, rotation)
return diagonal_boxen[suffix] or {}
end,
}, advtrains.ap.t_diagonalcrossing)
minetest.register_craft({
output = 'advtrains:dtrack_xingdiag_placer 2',
recipe = {
{'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'},
{'', 'advtrains:dtrack_placer', ''},
{'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'}
}
})
---- Not included: very shallow crossings like (30/60)+45.
---- At an angle of only 18.4 degrees, the models would not
---- translate well to a block game.
-- END crossings
--slopes
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack",
texture_prefix="advtrains_dtrack",
models_prefix="advtrains_dtrack",
models_suffix=".obj",
shared_texture="advtrains_dtrack_shared.png",
second_texture="default_gravel.png",
description=attrans("Track"),
formats={vst1={true, false, true}, vst2={true, false, true}, vst31={true}, vst32={true}, vst33={true}},
}, advtrains.ap.t_30deg_slope)
minetest.register_craft({
type = "shapeless",
output = 'advtrains:dtrack_slopeplacer 2',
recipe = {
"advtrains:dtrack_placer",
"advtrains:dtrack_placer",
"default:gravel",
},
})
--bumpers
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_bumper",
texture_prefix="advtrains_dtrack_bumper",
models_prefix="advtrains_dtrack_bumper",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_rail.png",
--bumpers still use the old texture until the models are redone.
description=attrans("Bumper"),
formats={},
}, advtrains.ap.t_30deg_straightonly)
minetest.register_craft({
output = 'advtrains:dtrack_bumper_placer 2',
recipe = {
{'group:wood', 'dye:red'},
{'default:steel_ingot', 'default:steel_ingot'},
{'advtrains:dtrack_placer', 'advtrains:dtrack_placer'},
},
})
--legacy bumpers
for _,rot in ipairs({"", "_30", "_45", "_60"}) do
minetest.register_alias("advtrains:dtrack_bumper"..rot, "advtrains:dtrack_bumper_st"..rot)
end
-- atc track
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_atc",
texture_prefix="advtrains_dtrack_atc",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_atc.png",
description=attrans("ATC controller"),
formats={},
get_additional_definiton = advtrains.atc_function
}, advtrains.trackpresets.t_30deg_straightonly)
-- Tracks for loading and unloading trains
-- Copyright (C) 2017 Gabriel Pérez-Cerezo <gabriel@gpcf.eu>
local function get_far_node(pos)
local node = minetest.get_node(pos)
if node.name == "ignore" then
minetest.get_voxel_manip():read_from_map(pos, pos)
node = minetest.get_node(pos)
end
return node
end
local function show_fc_formspec(pos,player)
local pname = player:get_player_name()
if minetest.is_protected(pos,pname) then
minetest.chat_send_player(pname, "Position is protected!")
return
end
local meta = minetest.get_meta(pos)
local fc = meta:get_string("fc") or ""
local form = 'formspec_version[4]'..
'size[10,5]'..
'label[0.5,0.4;Advtrains Loading/Unloading Track]'..
'label[0.5,1.1;Set the code to match against the wagon\'s freight code]'..
'label[0.5,1.6;A blank field matches all wagons (default)]'..
'label[0.5,2.1;Use code # to disable the track section]'..
'field[0.5,3;5.5,1;fc;FC;'..minetest.formspec_escape(fc)..']'..
'button[6.5,3;3,1;save;Submit]'
minetest.show_formspec(pname, "at_load_unload_"..advtrains.encode_pos(pos), form)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local pname = player:get_player_name()
local pe = string.match(formname, "^at_load_unload_(............)$")
local pos = advtrains.decode_pos(pe)
if pos then
if minetest.is_protected(pos, pname) then
minetest.chat_send_player(pname, "Position is protected!")
return
end
if fields.save then
minetest.get_meta(pos):set_string("fc",tostring(fields.fc))
minetest.chat_send_player(pname,"Freight code set: "..tostring(fields.fc))
show_fc_formspec(pos,player)
end
end
end)
local function train_load(pos, train_id, unload)
local train=advtrains.trains[train_id]
local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
if not string.match(below.name, "chest") then
atprint("this is not a chest! at "..minetest.pos_to_string(pos))
return
end
local node_fc = minetest.get_meta(pos):get_string("fc") or ""
if node_fc == "#" then
--track section is disabled
return
end
local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
if inv and train.velocity < 2 then
for k, v in ipairs(train.trainparts) do
local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v})
if i and i:get_list("box") then
local wagon_data = advtrains.wagons[v]
local wagon_fc
if wagon_data.fc then
if not wagon_data.fcind then wagon_data.fcind = 1 end
wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
end
if node_fc == "" or wagon_fc == node_fc then
if not unload then
for _, item in ipairs(inv:get_list("main")) do
if i:get_list("box") and i:room_for_item("box", item) then
i:add_item("box", item)
inv:remove_item("main", item)
end
end
else
for _, item in ipairs(i:get_list("box")) do
if inv:get_list("main") and inv:room_for_item("main", item) then
i:remove_item("box", item)
inv:add_item("main", item)
end
end
end
end
end
end
end
end
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_unload",
texture_prefix="advtrains_dtrack_unload",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_unload.png",
description=attrans("Unloading Track"),
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
after_dig_node=function(pos)
advtrains.invalidate_all_paths()
advtrains.ndb.clear(pos)
end,
on_rightclick = function(pos, node, player)
show_fc_formspec(pos, player)
end,
advtrains = {
on_train_enter = function(pos, train_id)
train_load(pos, train_id, true)
end,
},
}
end
}, advtrains.trackpresets.t_30deg_straightonly)
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_load",
texture_prefix="advtrains_dtrack_load",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_load.png",
description=attrans("Loading Track"),
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
after_dig_node=function(pos)
advtrains.invalidate_all_paths()
advtrains.ndb.clear(pos)
end,
on_rightclick = function(pos, node, player)
show_fc_formspec(pos, player)
end,
advtrains = {
on_train_enter = function(pos, train_id)
train_load(pos, train_id, false)
end,
},
}
end
}, advtrains.trackpresets.t_30deg_straightonly)
-- mod-dependent crafts
local loader_core = "default:mese_crystal" --fallback
if minetest.get_modpath("basic_materials") then
loader_core = "basic_materials:ic"
elseif minetest.get_modpath("technic") then
loader_core = "technic:control_logic_unit"
end
--print("Loader Core: "..loader_core)
minetest.register_craft({
type="shapeless",
output = 'advtrains:dtrack_load_placer',
recipe = {
"advtrains:dtrack_placer",
loader_core,
"default:chest"
},
})
loader_core = nil --nil the crafting variable
--craft between load/unload tracks
minetest.register_craft({
type="shapeless",
output = 'advtrains:dtrack_unload_placer',
recipe = {
"advtrains:dtrack_load_placer",
},
})
minetest.register_craft({
type="shapeless",
output = 'advtrains:dtrack_load_placer',
recipe = {
"advtrains:dtrack_unload_placer",
},
})
if mesecon then
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_detector_off",
texture_prefix="advtrains_dtrack_detector",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_detector_off.png",
description=attrans("Detector Rail"),
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
mesecons = {
receptor = {
state = mesecon.state.off,
rules = advtrains.meseconrules
}
},
advtrains = {
on_updated_from_nodedb = function(pos, node)
mesecon.receptor_off(pos, advtrains.meseconrules)
end,
on_train_enter=function(pos, train_id)
advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_on".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2})
if advtrains.is_node_loaded(pos) then
mesecon.receptor_on(pos, advtrains.meseconrules)
end
end
}
}
end
}, advtrains.ap.t_30deg_straightonly)
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_detector_on",
texture_prefix="advtrains_dtrack",
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_detector_on.png",
description="Detector(on)(you hacker you)",
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
mesecons = {
receptor = {
state = mesecon.state.on,
rules = advtrains.meseconrules
}
},
advtrains = {
on_updated_from_nodedb = function(pos, node)
mesecon.receptor_on(pos, advtrains.meseconrules)
end,
on_train_leave=function(pos, train_id)
advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_off".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2})
if advtrains.is_node_loaded(pos) then
mesecon.receptor_off(pos, advtrains.meseconrules)
end
end
}
}
end
}, advtrains.ap.t_30deg_straightonly_noplacer)
minetest.register_craft({
type="shapeless",
output = 'advtrains:dtrack_detector_off_placer',
recipe = {
"advtrains:dtrack_placer",
"mesecons:wire_00000000_off"
},
})
end
--TODO legacy
--I know lbms are better for this purpose
for name,rep in pairs({swl_st="swlst", swr_st="swrst", swl_cr="swlcr", swr_cr="swrcr", }) do
minetest.register_abm({
-- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_"..name},
interval = 1.0, -- Operation interval in seconds
chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep, param2=node.param2}) end,
})
minetest.register_abm({
-- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_"..name.."_45"},
interval = 1.0, -- Operation interval in seconds
chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep.."_45", param2=node.param2}) end,
})
end
if advtrains.register_replacement_lbms then
minetest.register_lbm({
name = "advtrains:ramp_replacement_1",
-- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_vert1"},
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst1", param2=(node.param2+2)%4}) end,
})
minetest.register_lbm({
name = "advtrains:ramp_replacement_1",
-- -- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_vert2"},
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst2", param2=(node.param2+2)%4}) end,
})
minetest.register_abm({
name = "advtrains:st_rep_1",
-- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_st"},
interval=1,
chance=1,
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st", param2=node.param2}) end,
})
minetest.register_lbm({
name = "advtrains:st_rep_1",
-- -- In the following two fields, also group:groupname will work.
nodenames = {"advtrains:track_st_45"},
action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st_45", param2=node.param2}) end,
})
end