aboutsummaryrefslogtreecommitdiff
path: root/advtrains/tracks.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/tracks.lua')
-rw-r--r--advtrains/tracks.lua935
1 files changed, 210 insertions, 725 deletions
diff --git a/advtrains/tracks.lua b/advtrains/tracks.lua
index 3acde74..dba0d7a 100644
--- a/advtrains/tracks.lua
+++ b/advtrains/tracks.lua
@@ -1,484 +1,128 @@
---advtrains by orwell96, see readme.txt
+-- tracks.lua
+-- rewritten with advtrains 2.5 according to new track registration system
---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
+Tracks in advtrains are defined by the node definition. They must have at least 2 connections, but can have any number.
+Switchable nodes (turnouts, single/double-slip switches) are implemented by having a separate node (node name) for each of the possible states.
-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 = "",
- }
+ minetest.register_node(nodename, {
+ ... usual node definition ...
+ groups = {
+ advtrains_track = 1,
+ advtrains_track_<tracktype>=1
+ ^- these groups tell that the node is a track
+ not_blocking_trains=1,
+ ^- this group tells that the node should not block trains although it's walkable.
},
- 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 = "",
+
+ at_rail_y = 0,
+ ^- Height of this rail node (the y position of a wagon that stands centered on this rail)
+ at_conns = {
+ [1] = { c=0..15, y=0..1 },
+ [2] = { c=0..15, y=0..1 },
+ ( [3] = { c=0..15, y=0..1 }, )
+ ( [4] = { c=0..15, y=0..1 }, )
+ ( ... )
+ }
+ ^- Connections of this rail. There are two general cases:
+ a) SIMPLE TRACK - the track has exactly 2 connections, and does not feature a turnout, crossing or other contraption
+ For simple tracks, except for the at_conns table no further setup needs to be specified. A train entering on conn 1 will go out at conn 2 and vice versa.
+ A track with only one connection defined is not permitted.
+ b) COMPOUND TRACK - the track has more than 2 connections
+ This will be used for turnouts and crossings. Tracks with more than 2 conns MUST define 'at_conn_map'.
+ Switchable nodes, whose state can be changed (e.g. turnouts) MUST define a 'state_map' within the advtrains table as well.
+ This differs from the behavior up until 2.4.2, where the conn mapping was fixed.
+ ^- Connection definition:
+ - c is the direction of the connection (0-16). For the mapping to world directions see helpers.lua.
+ - Connections will be auto-rotated with param2 of the node (horizontal, param2 values 0-3 only)
+ - y is the height of the connection (rail will only connect when this matches)
+ ^- The index of a connection inside the conns table (1, 2, 3, ...) is referred throughout advtrains code as 'connid'
+ ^- IMPORTANT: For switchable nodes (any kind of turnout), it is crucial that for all of the node's variants the at_conns table stays the same. See below.
+
+ at_conn_map = {
+ [1] = 2,
+ [2] = 1,
+ [3] = 1,
+ }
+ ^- Connection map of this rail. It specifies when a train enters the track on connid X, on which connid it will leave
+ This field MUST be specified when the number of connections in at_conns is greater than 2
+ This field may, and obviously will, vary between nodes for switchable nodes.
+
+ can_dig = advtrains.track_can_dig_callback
+ after_dig_node = advtrains.track_update_callback
+ after_place_node = advtrains.track_update_callback
+ ^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code
+
+ on_rightclick = advtrains.state_node_on_rightclick_callback
+ ^- Must be added if the node is a turnout and if it should be switched by right-click. It will cause the turnout to be switched to next_state.
+
+ advtrains = {
+ on_train_enter=function(pos, train_id, train, index) end
+ ^- called when a train enters the rail
+ on_train_leave=function(pos, train_id, train, index) end
+ ^- called when a train leaves the rail
+
+ -- The following function is only in effect when interlocking is enabled:
+ on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata)
+ ^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time)
+ ^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail.
+ ^- has_entered: when true, the train is already standing on this node with its front tip, and the enter callback has already been called.
+ Possibly, some actions need not to be taken in this case. Only set if it's the very first node the train is standing on.
+ ^- lzbdata should be ignored and nothing should be assigned to it
+
+ -- The following information is required if the node is a turnout (e.g. can be switched into different positions)
+ node_state = "st"
+ ^- The name of the state this node represents
+ ^- Conventions for this field are as follows:
+ - Two-way straight/turn switches: 'st'=straight branch, 'cr'=diverting/turn branch
+ - 3-way turnouts, Y-turnouts: 'l'=left branch, 's'=straight branch, 'r'=right branch
+
+ node_next_state = "cr"
+ ^- The name of the state that the turnout should be switched to when it is right-clicked
+
+ node_fallback_state = "st"
+ ^- The name of the state that the turnout should "fall back" to when it is released
+ Only used by the interlocking system, when a route on the node is released it is switched back to this state.
+
+ node_state_map = {
+ ["st"] = "<node name of the st variant>",
+ ["cr"] = "<node name of the cr variant>",
+ ... etc ...
}
- },
- 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},
- vst41={conns = conns(8,0,0,1/4), rail_y = 1/4 - 1/8, desc = "uphill 1/4", slope=true},
- vst42={conns = conns(8,0,1/4,2/4), rail_y = 2/4 - 1/8, desc = "uphill 2/4", slope=true},
- vst43={conns = conns(8,0,2/4,3/4), rail_y = 3/4 - 1/8, desc = "uphill 3/4", slope=true},
- vst44={conns = conns(8,0,3/4,1), rail_y = 1 - 1/8, desc = "uphill 4/4", slope=true},
- vst51={conns = conns(8,0,0,1/5), rail_y = 1/5 - 1/10, desc = "uphill 1/5", slope=true},
- vst52={conns = conns(8,0,1/5,2/5), rail_y = 2/5 - 1/10, desc = "uphill 2/5", slope=true},
- vst53={conns = conns(8,0,2/5,3/5), rail_y = 3/5 - 1/10, desc = "uphill 3/5", slope=true},
- vst54={conns = conns(8,0,3/5,4/5), rail_y = 4/5 - 1/10, desc = "uphill 4/5", slope=true},
- vst55={conns = conns(8,0,4/5,1), rail_y = 5/5 - 1/10, desc = "uphill 5/5", slope=true},
- vst61={conns = conns(8,0,0,1/6), rail_y = 1/6 - 1/12, desc = "uphill 1/6", slope=true},
- vst62={conns = conns(8,0,1/6,2/6), rail_y = 2/6 - 1/12, desc = "uphill 2/6", slope=true},
- vst63={conns = conns(8,0,2/6,3/6), rail_y = 3/6 - 1/12, desc = "uphill 3/6", slope=true},
- vst64={conns = conns(8,0,3/6,4/6), rail_y = 4/6 - 1/12, desc = "uphill 4/6", slope=true},
- vst65={conns = conns(8,0,4/6,5/6), rail_y = 5/6 - 1/12, desc = "uphill 5/6", slope=true},
- vst66={conns = conns(8,0,5/6,1), rail_y = 6/6 - 1/12, desc = "uphill 6/6", slope=true},
- vst71={conns = conns(8,0,0,1/7), rail_y = 1/7 - 1/14, desc = "uphill 1/7", slope=true},
- vst72={conns = conns(8,0,1/7,2/7), rail_y = 2/7 - 1/14, desc = "uphill 2/7", slope=true},
- vst73={conns = conns(8,0,2/7,3/7), rail_y = 3/7 - 1/14, desc = "uphill 3/7", slope=true},
- vst74={conns = conns(8,0,3/7,4/7), rail_y = 4/7 - 1/14, desc = "uphill 4/7", slope=true},
- vst75={conns = conns(8,0,4/7,5/7), rail_y = 5/7 - 1/14, desc = "uphill 5/7", slope=true},
- vst76={conns = conns(8,0,5/7,6/7), rail_y = 6/7 - 1/14, desc = "uphill 6/7", slope=true},
- vst77={conns = conns(8,0,6/7,1), rail_y = 7/7 - 1/14, desc = "uphill 7/7", slope=true},
- vst81={conns = conns(8,0,0,1/8), rail_y = 1/8 - 1/16, desc = "uphill 1/8", slope=true},
- vst82={conns = conns(8,0,1/8,2/8), rail_y = 2/8 - 1/16, desc = "uphill 2/8", slope=true},
- vst83={conns = conns(8,0,2/8,3/8), rail_y = 3/8 - 1/16, desc = "uphill 3/8", slope=true},
- vst84={conns = conns(8,0,3/8,4/8), rail_y = 4/8 - 1/16, desc = "uphill 4/8", slope=true},
- vst85={conns = conns(8,0,4/8,5/8), rail_y = 5/8 - 1/16, desc = "uphill 5/8", slope=true},
- vst86={conns = conns(8,0,5/8,6/8), rail_y = 6/8 - 1/16, desc = "uphill 6/8", slope=true},
- vst87={conns = conns(8,0,6/8,7/8), rail_y = 7/8 - 1/16, desc = "uphill 7/8", slope=true},
- vst88={conns = conns(8,0,7/8,1), rail_y = 8/8 - 1/16, desc = "uphill 8/8", slope=true},
- },
- regsp=true,
- slopeplacer={
- [2]={"vst1", "vst2"},
- [3]={"vst31", "vst32", "vst33"},
- [4]={"vst41", "vst42", "vst43", "vst44"},
- [5]={"vst51", "vst52", "vst53", "vst54", "vst55"},
- [6]={"vst61", "vst62", "vst63", "vst64", "vst65", "vst66"},
- [7]={"vst71", "vst72", "vst73", "vst74", "vst75", "vst76", "vst77"},
- [8]={"vst81", "vst82", "vst83", "vst84", "vst85", "vst86", "vst87", "vst88"},
- max=8,--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",
+ ^- Map of state name to the appropriate node name that should be set by advtrains when a switch is requested
+ Note that for all of those nodes, the at_conns table must be identical (however the conn_map will vary)
+
+ node_on_switch_state = function(pos, node, oldstate, newstate)
+ ^- Called when the node state is switched by advtrains, after the node replacement has commenced.
+
+ Turnout switching can happen programmatically via advtrains.setstate(pos, state), via user right_click or via the interlocking system.
+ In no other situation is it permissible to exchange track nodes in-place, unless both at_conns and at_conn_map stay identical.
+
+ Note that the fields node_state, node_next_state and node_state_map completely replace the getstate/setstate functions.
+ There must be a one-to-one mapping between states and node names and no function can be defined for state switching.
+ This principle enables the seamless working of the interlocking autorouter and reduces failure points.
+ The node_state_* system can also be used as drop-in replacement for the passive-API-enabled nodes (andrews-cross, mesecon_switch etc.)
+ The advtrains API functions advtrains.getstate() and advtrains.setstate() remain the programmatic access points, but will now utilize the new state system.
+
+
+ trackworker_next_rot = <nodename of next rotation step>,
+ ^- if set, right-click with trackworker will set this node
+ trackworker_rot_incr_param2 = true
+ ^- if set, trackworker will increase node param2 on rightclick
+
+ trackworker_next_var = <nodename of next variant>
+ ^- if set, left-click with trackworker will set this node
}
-}
-
-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
+-- This file provides some utilities to register tracks, but tries to not get into the way too much
---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)
+function advtrains.track_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)
@@ -486,148 +130,113 @@ local function can_dig_callback(pos, player)
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/2, -1/2, 1/2, -1/2+1/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},
- use_texture_alpha = "clip",
+function advtrains.track_update_callback(pos)
+ advtrains.ndb.update(pos)
+end
- 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
+function advtrains.state_node_on_rightclick_callback(pos, node, player)
+ if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
+ local ndef = minetest.registered_nodes[node.name]
+ if ndef and ndef.advtrains and ndef.advtrains.node_next_state then
+ advtrains.setstate(pos, ndef.advtrains.node_next_state, node)
+ advtrains.log("Switch", player:get_player_name(), pos)
+ end
+ end
+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
+-- advtrains.register_node_4rot(name, nodedef)
+-- Registers four rotations for the node defined by nodedef (0°, 30°, 45° and 60°; the 4 90°-steps are already handled by the param2, resulting in 16 directions total).
+-- You must provide the definition for the base node, and certain fields are altered automatically for the 3 additional rotations:
+-- name: appends the suffix "_30", "_45" or "_60"
+-- description: appends the rotation (human-readable) in parenthesis
+-- tiles_prefix: if defined, "tiles" field will be set as prefix..rotationExtension..".png"
+-- mesh_prefix, mesh_suffix: if defined, "mesh" field will be set as prefix..rotationExtension..suffix
+-- at_conns: are rotated according to the node rotation
+-- node_state_map, trackworker_next_var: appends the suffix appropriately.
+-- groups: applies save_in_at_nodedb and not_blocking_trains groups if not already present
+-- The nodes are registered in the trackworker to be rotated with right-click.
+-- definition_mangling_function is an optional parameter. For each of the 4 rotations, it gets passed the modified node definition and may perform final modifications to it.
+-- signature: function definition_mangling_function(name, nodedef, rotationIndex, rotationSuffix)
+-- Example usage: define the setstate function of turnouts (if that is not done via the "automatic" way of state_node_map)
+local rotations = {
+ {i = 0, s = "", h = " (0)", n = "_30"},
+ {i = 1, s = "_30", h = " (30)", n = "_45"},
+ {i = 2, s = "_45", h = " (45)", n = "_60"},
+ {i = 3, s = "_60", h = " (60)", n = ""},
+}
+function advtrains.register_node_4rot(ori_name, ori_ndef, definition_mangling_function)
+ for _, rot in ipairs(rotations) do
+ local ndef = table.copy(ori_ndef)
+ if ori_ndef.advtrains then
+ -- make sure advtrains table is deep-copied because we may need to replace node_state_map
+ ndef.advtrains = table.copy(ori_ndef.advtrains)
+ else
+ ndef.advtrains = {} -- we need the table later for trackworker
+ end
+ -- Perform the name mangling
+ local suffix = rot.s
+ local name = ori_name..suffix
+ ndef.description = ori_ndef.description .. rot.h
+ if ori_ndef.tiles_prefix then
+ ndef.tiles = { ori_ndef.tiles_prefix .. suffix .. ".png" }
+ end
+ if ori_ndef.mesh_prefix then
+ ndef.mesh = ori_ndef.mesh_prefix .. suffix .. ori_ndef.mesh_suffix
+ end
+ -- rotate connections
+ if ori_ndef.at_conns then
+ ndef.at_conns = advtrains.rotate_conn_by(ori_ndef.at_conns, rot.i)
+ end
+ -- update node state map if present
+ if ori_ndef.advtrains then
+ if ori_ndef.advtrains.node_state_map then
+ local new_nsm = {}
+ for state, nname in pairs(ori_ndef.advtrains.node_state_map) do
+ new_nsm[state] = nname .. suffix
end
- advtrains.trackplacer.add_worked(def.nodename_prefix, suffix, rotation, var.trackworker)
+ ndef.advtrains.node_state_map = new_nsm
end
+ if ori_ndef.advtrains.trackworker_next_var then
+ ndef.advtrains.trackworker_next_var = ori_ndef.advtrains.trackworker_next_var .. suffix
+ end
+ -- apply trackworker rot field
+ ndef.advtrains.trackworker_next_rot = ori_name .. rot.n
+ ndef.advtrains.trackworker_rot_incr_param2 = (rot.n=="")
+ end
+ -- apply groups
+ ndef.groups.save_in_at_nodedb = 1
+ ndef.groups.not_blocking_trains = 1
+
+ -- give the definition mangling function an option to do some adjustments
+ if definition_mangling_function then
+ definition_mangling_function(name, ndef, rot.i, suffix)
+ end
+
+ -- register node
+ minetest.register_node(":"..name, ndef)
+
+ -- if this has the track_place_group set, register as a candidate for the track_place_group
+ if ndef.advtrains.track_place_group then
+ advtrains.trackplacer.register_candidate(ndef.advtrains.track_place_group, name, ndef, ndef.advtrains.track_place_single, true)
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
-
+-- track-related helper functions
+
+function advtrains.is_track(nodename)
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
+ if nodedef and nodedef.groups.advtrains_track then
+ return true
end
return false
end
+-- returns the connection tables of the track with given node details
+-- returns: conns table, railheight, conn_map table
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
@@ -635,18 +244,16 @@ function advtrains.get_track_connections(name, 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
+ if not nodedef.at_conns then
+ return nil
end
- return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype
+ --atdebug("Track connections of ",name,param2,":",nodedef.at_conns)
+ return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), nodedef.at_conn_map
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"
+-- Impl Note: possibly duplicate code in "self contained TCB" - see interlocking/tcb_ts_ui.lua!
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.")
@@ -664,125 +271,3 @@ function advtrains.can_dig_or_modify_track(pos)
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),
- liquids_pointable = def.liquids_pointable,
- })
-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.is_creative_enabled(player:get_player_name()) 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.is_creative_enabled(player:get_player_name()) 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 istack
- 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
-}]]
-
-
-
-
-
-
-
-
-