2016-05-29 20:27:30 +02:00
--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.
2016-08-21 21:46:16 +02:00
local print = function ( t , ... ) minetest.log ( " action " , table.concat ( { t , ... } , " " ) ) minetest.chat_send_all ( table.concat ( { t , ... } , " " ) ) end
2016-08-22 22:41:09 +02:00
--all new trackplacer code
local tp = {
tracks = { }
}
2016-05-29 20:27:30 +02:00
2016-08-22 22:41:09 +02:00
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 = { }
}
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 }
end
tp.tracks [ nnprefix ] . modify [ nodename ] = true
end
function tp . add_single_conn ( nnprefix , suffix , rotation , conns )
local nodename = nnprefix .. " _ " .. suffix .. rotation
2016-05-29 20:27:30 +02:00
for i = 0 , 3 do
2016-08-22 22:41:09 +02:00
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 }
2016-05-29 20:27:30 +02:00
end
2016-08-22 22:41:09 +02:00
tp.tracks [ nnprefix ] . modify [ nodename ] = true
2016-05-29 20:27:30 +02:00
end
2016-08-22 22:41:09 +02:00
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
2016-08-29 21:53:41 +02:00
--[[
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
] ]
2016-08-22 22:41:09 +02:00
function tp . find_already_connected ( pos ) --TODO vertical calculations(check node below)
local function istrackandbc ( pos , conn )
local cnode = minetest.get_node ( advtrains.dirCoordSet ( pos , conn ) )
local bconn = ( conn + 8 ) % 16
if advtrains.is_track_and_drives_on ( cnode.name , advtrains.all_tracktypes ) then
local cconn1 , cconn2 = advtrains.get_track_connections ( cnode.name , cnode.param2 )
return cconn1 == bconn or cconn2 == bconn
end
return false
end
2016-08-29 21:53:41 +02:00
local dnode = minetest.get_node ( pos )
local dconn1 , dconn2 = advtrains.get_track_connections ( dnode.name , dnode.param2 )
local t = { [ true ] = " true " , [ false ] = " false " }
if istrackandbc ( pos , dconn1 ) and istrackandbc ( pos , dconn2 ) then return dconn1 , dconn2
elseif istrackandbc ( pos , dconn1 ) then return dconn1
elseif istrackandbc ( pos , dconn2 ) then return dconn2
2016-08-22 22:41:09 +02:00
end
2016-08-29 21:53:41 +02:00
return nil
2016-08-22 22:41:09 +02:00
end
2016-08-29 21:53:41 +02:00
function tp . rail_and_can_be_bent ( originpos , conn , nnpref )
local pos = advtrains.dirCoordSet ( originpos , conn )
local newdir = ( conn + 8 ) % 16
local node = minetest.get_node ( pos )
2016-08-22 22:41:09 +02:00
local tr = tp.tracks [ nnpref ]
2016-08-29 21:53:41 +02:00
if not advtrains.is_track_and_drives_on ( node.name , advtrains.all_tracktypes ) then
return false
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
2016-05-29 20:27:30 +02:00
end
2016-08-29 21:53:41 +02:00
return false
else
if tr.single_conn [ newdir ] then --just rotate old rail to right orientation
return true
2016-05-29 20:27:30 +02:00
end
2016-08-29 21:53:41 +02:00
return false
2016-08-22 22:41:09 +02:00
end
end
2016-08-29 21:53:41 +02:00
function tp . bend_rail ( originpos , conn , nnpref )
local pos = advtrains.dirCoordSet ( originpos , conn )
local newdir = ( conn + 8 ) % 16
2016-08-22 22:41:09 +02:00
local node = minetest.get_node ( pos )
2016-08-29 21:53:41 +02:00
local tr = tp.tracks [ nnpref ]
--is rail already connected? no need to bend.
2016-08-22 22:41:09 +02:00
local conn1 , conn2 = advtrains.get_track_connections ( node.name , node.param2 )
if newdir == conn1 or newdir == conn2 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
minetest.set_node ( pos , tr.double_conn [ adj1 .. " _ " .. newdir ] )
return true --if exists, connect new rail and old end
2016-05-29 20:27:30 +02:00
end
2016-08-22 22:41:09 +02:00
return false
else
if tr.single_conn [ newdir ] then --just rotate old rail to right orientation
minetest.set_node ( pos , tr.single_conn [ newdir ] )
return true
2016-05-29 20:27:30 +02:00
end
2016-08-22 22:41:09 +02:00
return false
2016-05-29 20:27:30 +02:00
end
end
2016-08-29 21:53:41 +02:00
function tp . placetrack ( pos , nnpref )
--1. find all rails that are likely to be connected
local tr = tp.tracks [ nnpref ]
local p_rails = { }
for i = 0 , 15 do
if tp.rail_and_can_be_bent ( pos , i , nnpref ) then
p_rails [ # p_rails + 1 ] = i
end
end
if # p_rails == 0 then
minetest.set_node ( pos , { name = nnpref .. " _ " .. tr.default } )
elseif # p_rails == 1 then
tp.bend_rail ( pos , p_rails [ 1 ] , nnpref )
minetest.set_node ( pos , tr.single_conn [ p_rails [ 1 ] ] )
else
--iterate subsets
for k1 , conn1 in ipairs ( p_rails ) do
for k2 , conn2 in ipairs ( p_rails ) do
if k1 ~= k2 then
if ( 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 ] )
return
end
end
end
end
2016-08-30 10:20:43 +02:00
--not found
tp.bend_rail ( pos , p_rails [ 1 ] , nnpref )
minetest.set_node ( pos , tr.single_conn [ p_rails [ 1 ] ] )
2016-08-29 21:53:41 +02:00
end
end
2016-05-29 20:27:30 +02:00
2016-08-22 22:41:09 +02:00
function tp . register_track_placer ( nnprefix , imgprefix , dispname )
2016-05-29 20:27:30 +02:00
minetest.register_craftitem ( nnprefix .. " _placer " , {
description = dispname ,
inventory_image = imgprefix .. " _placer.png " ,
wield_image = imgprefix .. " _placer.png " ,
2016-08-28 20:59:54 +02:00
groups = { } ,
2016-05-29 20:27:30 +02:00
on_place = function ( itemstack , placer , pointed_thing )
if pointed_thing.type == " node " then
local pos = pointed_thing.above
2016-08-30 10:20:43 +02:00
local upos = pointed_thing.under
if 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
2016-08-22 22:41:09 +02:00
tp.placetrack ( pos , nnprefix )
2016-06-09 21:06:39 +02:00
if not minetest.setting_getbool ( " creative_mode " ) then
itemstack : take_item ( )
end
2016-05-29 20:27:30 +02:00
end
end
return itemstack
end ,
} )
end
minetest.register_craftitem ( " advtrains:trackworker " , {
description = " Track Worker Tool \n \n Left-click: change rail type (straight/curve/switch) \n Right-click: rotate rail " ,
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 )
if pointed_thing.type == " node " then
local pos = pointed_thing.under
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
if advtrains.is_train_at_pos ( pos ) then return end
2016-08-22 22:41:09 +02:00
local nnprefix , suffix , rotation = string.match ( node.name , " ^([^_]+)_([^_]+)(_?.*)$ " )
2016-08-21 21:46:16 +02:00
--print(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
2016-08-22 22:41:09 +02:00
if not tp.tracks [ nnprefix ] or not tp.tracks [ nnprefix ] . twrotate [ suffix ] then
print ( " [advtrains]railtype not workable by trackworker " )
2016-08-21 21:46:16 +02:00
return
end
2016-08-22 22:41:09 +02:00
local modext = tp.tracks [ nnprefix ] . twrotate [ suffix ]
2016-08-21 21:46:16 +02:00
if rotation == modext [ # modext ] then --increase param2
2016-08-22 22:41:09 +02:00
minetest.set_node ( pos , { name = nnprefix .. " _ " .. suffix .. modext [ 1 ] , param2 = ( node.param2 + 1 ) % 4 } )
2016-05-29 20:27:30 +02:00
return
else
2016-08-21 21:46:16 +02:00
local modpos
for k , v in pairs ( modext ) do if v == rotation then modpos = k end end
if not modpos then
2016-05-29 20:27:30 +02:00
print ( " [advtrains]rail not workable by trackworker " )
return
end
2016-08-22 22:41:09 +02:00
minetest.set_node ( pos , { name = nnprefix .. " _ " .. suffix .. modext [ modpos + 1 ] , param2 = node.param2 } )
2016-05-29 20:27:30 +02:00
end
2016-08-21 21:46:16 +02:00
advtrains.invalidate_all_paths ( )
2016-05-29 20:27:30 +02:00
end
end ,
on_use = function ( itemstack , user , pointed_thing )
if pointed_thing.type == " node " then
local pos = pointed_thing.under
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
if advtrains.is_train_at_pos ( pos ) then return end
2016-08-22 22:41:09 +02:00
local nnprefix , suffix , rotation = string.match ( node.name , " ^([^_]+)_([^_]+)(_?.*)$ " )
2016-05-29 20:27:30 +02:00
2016-08-22 22:41:09 +02:00
if not tp.tracks [ nnprefix ] or not tp.tracks [ nnprefix ] . twcycle [ suffix ] then
print ( " [advtrains]railtype not workable by trackworker " )
2016-05-29 20:27:30 +02:00
return
end
2016-08-22 22:41:09 +02:00
local nextsuffix = tp.tracks [ nnprefix ] . twcycle [ suffix ]
minetest.set_node ( pos , { name = nnprefix .. " _ " .. nextsuffix .. rotation , param2 = node.param2 } )
2016-05-29 20:27:30 +02:00
--invalidate trains
2016-08-21 21:46:16 +02:00
advtrains.invalidate_all_paths ( )
2016-05-29 20:27:30 +02:00
end
end ,
2016-06-09 21:06:39 +02:00
} )
2016-08-22 22:41:09 +02:00
--putting into right place
advtrains.trackplacer = tp