--trackplacer.lua--holds code for the track-placing system. the default 'track' item will be a craftitem that places rails as needed. this will neither place or change switches nor place vertical rails.--all new trackplacer codelocal tp={
tracks={}}function tp.register_tracktype(nnprefix, n_suffix)
tp.tracks[nnprefix]={
default=n_suffix,
single_conn={},
double_conn={},--keys:conn1_conn2 (example:1_4)--values:{name=x, param2=x}
twcycle={},
twrotate={},--indexed by suffix, list, tells order of rotations
modify={}}endfunction tp.add_double_conn(nnprefix, suffix, rotation, conns)local nodename=nnprefix.."_"..suffix..rotation
for i=0,3do
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}end
tp.tracks[nnprefix].modify[nodename]=trueendfunction tp.add_single_conn(nnprefix, suffix, rotation, conns)local nodename=nnprefix.."_"..suffix..rotation
for i=0,3do
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}end
tp.tracks[nnprefix].modify[nodename]=trueendfunction 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]={}endtable.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]]function tp.find_already_connected(pos)--TODO vertical calculations(check node below)local functionistrackandbc(pos, conn)local cnode=minetest.get_node(advtrains.dirCoordSet(pos, conn))local bconn=(conn+8)%16if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes)thenlocal cconn1, cconn2=advtrains.get_track_connections(cnode.name, cnode.param2)return cconn1==bconn or cconn2==bconn
endreturn falseendlocal dnode=minetest.get_node(pos)local dconn1, dconn2=advtrains.get_track_connections(dnode.name, dnode.param2)local t={[true]="true", [false]="false"}ifistrackandbc(pos, dconn1)andistrackandbc(pos, dconn2)then return dconn1, dconn2
elseifistrackandbc(pos, dconn1)then return dconn1
elseifistrackandbc(pos, dconn2)then return dconn2
endreturn nilendfunction tp.rail_and_can_be_bent(originpos, conn, nnpref)local pos=advtrains.dirCoordSet(originpos, conn)local newdir=(conn+8)%16local node=minetest.get_node(pos)local tr=tp.tracks[nnpref]if not advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes)thenreturn falseend--rail at other end?local adj1, adj2=tp.find_already_connected(pos)if adj1 and adj2 thenreturn false--dont destroy existing trackelseif adj1 and not adj2 thenif tr.double_conn[adj1.."_"..newdir]thenreturn true--if exists, connect new rail and old endendreturn falseelseif tr.single_conn[newdir]then--just rotate old rail to right orientationreturn trueendreturn falseendendfunction tp.bend_rail(originpos, conn, nnpref)local pos=advtrains.dirCoordSet(originpos, conn)local newdir=(conn+8)%16local node=minetest.get_node(pos)local tr=tp.tracks[nnpref]--is rail already connected? no need to bend.local conn1, conn2=advtrains.get_track_connections(node.name, node.param2)if newdir==conn1 or newdir==conn2 thenreturnend--rail at other end?local adj1, adj2=tp.find_already_connected(pos)if adj1 and adj2 thenreturn false--dont destroy existing trackelseif adj1 and not adj2 thenif tr.double_conn[adj1.."_"..newdir]then
minetest.set_node(pos, tr.double_conn[adj1.."_"..newdir])return true--if exists, connect new rail and old endendreturn falseelseif tr.single_conn[newdir]then--just rotate old rail to right orientation
minetest.set_node(pos, tr.single_conn[newdir])return trueendreturn falseendendfunction tp.placetrack(pos, nnpref)--1. find all rails that are likely to be connectedlocal tr=tp.tracks[nnpref]local p_rails={}for i=0,15doif tp.rail_and_can_be_bent(pos, i, nnpref)then
p_rails[#p_rails+1]=i
endendif#p_rails==0then
minetest.set_node(pos, {name=nnpref.."_"..tr.default})elseif#p_rails==1then
tp.bend_rail(pos, p_rails[1], nnpref)
minetest.set_node(pos, tr.single_conn[p_rails[1]])else--iterate subsetsfor k1, conn1 inipairs(p_rails)dofor k2, conn2 inipairs(p_rails)doif k1~=k2 thenif(tr.double_conn[conn1.."_"..conn2])then
tp.bend_rail(pos, conn1, nnpref)
tp.bend_rail(pos, conn2, nnpref)
minetest.set_node(pos, tr.double_conn[conn1.."_"..conn2])returnendendendend--not found
tp.bend_rail(pos, p_rails[1], nnpref)
minetest.set_node(pos, tr.single_conn[p_rails[1]])endendfunction tp.register_track_placer(nnprefix, imgprefix, dispname)
minetest.register_craftitem(nnprefix.."_placer",{
description = dispname,
inventory_image = imgprefix.."_placer.png",
wield_image = imgprefix.."_placer.png",
groups={},
on_place =function(itemstack, placer, pointed_thing)local name = placer:get_player_name()if not name thenreturn itemstack
endif pointed_thing.type=="node"thenlocal pos=pointed_thing.above
local upos=pointed_thing.under
if minetest.is_protected(pos,name)and minetest.is_protected(upos,name)thenreturn itemstack
endif minetest.registered_nodes[minetest.get_node(pos).name]and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to
and minetest.registered_nodes[minetest.get_node(upos).name]and minetest.registered_nodes[minetest.get_node(upos).name].walkable then
tp.placetrack(pos, nnprefix)if not minetest.setting_getbool("creative_mode")then
itemstack:take_item()endendendreturn itemstack
end,})end
minetest.register_craftitem("advtrains:trackworker",{
description ="Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc.",
groups = {cracky=1},-- key=name, value=rating; rating=1..3.
inventory_image ="advtrains_trackworker.png",
wield_image ="advtrains_trackworker.png",
stack_max =1,
on_place =function(itemstack, placer, pointed_thing)local name = placer:get_player_name()if not name thenreturnendif pointed_thing.type=="node"thenlocal pos=pointed_thing.under
if minetest.is_protected(pos, name)thenreturnendlocal node=minetest.get_node(pos)--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return endif advtrains.is_train_at_pos(pos)then return endlocal nnprefix, suffix, rotation=string.match(node.name,"^(.+)_([^_]+)(_[^_]+)$")--print(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)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(),"This node can't be rotated using the trackworker!")returnendendlocal modext=tp.tracks[nnprefix].twrotate[suffix]if rotation==modext[#modext]then--increase param2
minetest.set_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4})returnelselocal modpos
for k,v inpairs(modext)do if v==rotation then modpos=k end endif not modpos then
minetest.chat_send_player(placer:get_player_name(),"This node can't be rotated using the trackworker!")returnend
minetest.set_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})end
advtrains.invalidate_all_paths()endend,
on_use=function(itemstack, user, pointed_thing)local name = user:get_player_name()if not name thenreturnendif pointed_thing.type=="node"thenlocal pos=pointed_thing.under
local node=minetest.get_node(pos)if minetest.is_protected(pos, name)thenreturnend--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return endif advtrains.is_train_at_pos(pos)then return endlocal nnprefix, suffix, rotation=string.match(node.name,"^(.+)_([^_]+)(_[^_]+)$")--print(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(),"This node can't be changed using the trackworker!")returnendendlocal nextsuffix=tp.tracks[nnprefix].twcycle[suffix]
minetest.set_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2})--invalidate trains
advtrains.invalidate_all_paths()elseprint(name,dump(tp.tracks))endend,})--putting into right place
advtrains.trackplacer=tp