aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--advtrains/track_reg_helper.lua8
-rw-r--r--advtrains_interlocking/ars.lua296
-rw-r--r--advtrains_interlocking/database.lua5
-rw-r--r--advtrains_interlocking/routesetting.lua85
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua4
-rwxr-xr-xadvtrains_interlocking/tcb_ts_ui.lua33
-rw-r--r--advtrains_line_automation/stoprail.lua7
-rw-r--r--advtrains_luaautomation/atc_rail.lua7
-rw-r--r--advtrains_signals_japan/init.lua17
9 files changed, 350 insertions, 112 deletions
diff --git a/advtrains/track_reg_helper.lua b/advtrains/track_reg_helper.lua
index 31741d6..e2f71e8 100644
--- a/advtrains/track_reg_helper.lua
+++ b/advtrains/track_reg_helper.lua
@@ -484,6 +484,11 @@ local function append_statemap_suffix(state_map, nnpref, rot)
return t
end
+function advtrains.default_suitable_substrate(upos)
+ return core.registered_nodes[core.get_node(upos).name]
+ and core.registered_nodes[core.get_node(upos).name].walkable
+end
+
function advtrains.register_tracks(tracktype, def, preset)
if not preset.v25_format then
error("advtrains.register_tracks(): A track preset for pre-v2.5 is used with advtrains 2.5+. Mod probably defines own track preset instead of using it from the advtrains.ap table! Please check track mod compatibility!")
@@ -509,8 +514,7 @@ function advtrains.register_tracks(tracktype, def, preset)
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 = minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable
- if s then
+ if (def.suitable_substrate and def.suitable_substrate or advtrains.default_suitable_substrate)(upos) then
-- minetest.chat_send_all(nnprefix)
local yaw = placer:get_look_horizontal()
advtrains.trackplacer.place_track(pos, nnprefix, name, yaw)
diff --git a/advtrains_interlocking/ars.lua b/advtrains_interlocking/ars.lua
index eb10497..5182cd3 100644
--- a/advtrains_interlocking/ars.lua
+++ b/advtrains_interlocking/ars.lua
@@ -3,26 +3,89 @@
--[[
The "ARS table" and its effects:
- Every route has (or can have) an associated ARS table. This can either be
- ars = { [n] = {ln="<line>"}/{rc="<routingcode>"}/{c="<a comment>"} }
- a list of rules involving either line or routingcode matchers (or comments, those are ignored)
- The first matching rule determines the route to set.
- - or -
- ars = {default = true}
- this means that all trains that no other rule matches on should use this route
+ Every route has (or can have) an associated ARS table:
+ ars = {
+ [n] = {
+ ln = "<line>" -- either line
+ rc = "<routingcode>" -- or routingcode
+ n = true/false -- true = logical not (matches everything that does not have this line/rc)
+ conj = { -- and conjunction, optional. This must be true in addition to the main rule
+ ln=... / rc=... / n=... -- like toplevel
+ conj=... -- can be nested
+ -- note that conj cannot have prio, in inherits the prio from main rule
+ }
+ prio = <num> -- optional, a priority number. If set, enables "multi-ARS" where train can wait for multiple routes at once
+ -- or
+ c="<a comment>"
+ }
+ default = true -- Route is the default route for trains
+ default_prio -- optional, priority for multi-ars with default route
+ default_conj = {...} -- optional, conditions (conjunction) that need to be fulfilled for this to be considered default route
+ }
- Compound ("and") conjunctions are not supported (--TODO should they?)
+ In case a train matches the ARS rules of multiple routes, precedence is as follows:
+ 1. train matches rules without priority in one or more routes -> first matching route is unconditionally set
+ 2. train matches rules with priority in one or more routes -> all of the matching routes are set (multi-ars)
+ in the order given by priority, first available route is set
+ 3. route is default=true, default_prio=nil and train matches default_conj (if present) -> first default route is set
+ 4. one or more routes are default=true, with default_prio set,and train matches default_conj (if present)
+ -> all of the matching routes are set (multi-ars) in the order given by priority, first available route is set
For editing, those tables are transformed into lines in a text area:
{ln=...} -> LN ...
{rc=...} -> RC ...
{c=...} -> #...
{default=true} -> *
- See also route_ui.lua
+ n -> ! (e.g. ln=..., n=true -> !LN ...)
+ prio -> <num> (e.g. ln=..., prio=1 -> 1 LN ...)
+
+ conj -> goes on the next line, with an & prepended, e.g.:
+ {ln="S1", conj={rc="Left"}} ->
+ LN S1
+ & RC Left
+
+ Example combining everything:
+ ars = {
+ [1] = {
+ ln = "S1"
+ n = true
+ prio = 4
+ conj = {
+ rc = "R4"
+ }
+ }
+ default = true
+ default_prio = 2
+ default_conj = {
+ rc = "R5"
+ n = true
+ }
+ } ->
+ 4 !LN S1
+ & RC R4
+ 2 *
+ & !RC R5
+
]]
local il = advtrains.interlocking
+
+local function conj_to_text(conj, txt)
+ while conj do
+ n = ""
+ if conj.n then
+ n = "!"
+ end
+ if conj.ln then
+ txt[#txt+1] = "& "..n.."LN "..conj.ln
+ elseif conj.rc then
+ txt[#txt+1] = "& "..n.."RC "..conj.rc
+ end
+ conj = conj.conj
+ end
+end
+
-- The ARS data are saved in a table format, but are entered in text format. Utility functions to transform between both.
function il.ars_to_text(arstab)
if not arstab then
@@ -32,103 +95,213 @@ function il.ars_to_text(arstab)
local txt = {}
for i, arsent in ipairs(arstab) do
+ local prio = ""
+ if arsent.prio then
+ prio = arsent.prio.." "
+ end
local n = ""
if arsent.n then
n = "!"
end
if arsent.ln then
- txt[#txt+1] = n.."LN "..arsent.ln
+ txt[#txt+1] = prio..n.."LN "..arsent.ln
elseif arsent.rc then
- txt[#txt+1] = n.."RC "..arsent.rc
+ txt[#txt+1] = prio..n.."RC "..arsent.rc
elseif arsent.c then
txt[#txt+1] = "#"..arsent.c
end
+ conj_to_text(arsent.conj, txt)
end
if arstab.default then
- return "*\n" .. table.concat(txt, "\n")
+ local prio = ""
+ if arstab.default_prio then
+ prio = arstab.default_prio.." "
+ end
+ txt[#txt+1] = prio.."*"
+ conj_to_text(arstab.default_conj, txt)
end
return table.concat(txt, "\n")
end
+local function parse_ruleexp(line)
+ local excl, key, val = string.match(line, "^%s*(!?)%s*([RL][CN])%s+(.+)%s*$")
+ if key == "RC" then
+ return {rc=val, n=(excl=="!")}
+ elseif key == "LN" then
+ return {ln=val, n=(excl=="!")}
+ end
+end
+
function il.text_to_ars(t)
if not string.match(t, "%S+") then
return nil
- elseif t=="*" then
- return {default=true}
end
local arstab = {}
+ local previtem
for line in string.gmatch(t, "[^\r\n]+") do
- if line=="*" then
- arstab.default = true
+ -- a) comment
+ local ct = string.match(line, "^#(.*)$")
+ if ct then
+ arstab[#arstab+1] = {c = ct}
+ previtem = nil
else
- local c, v = string.match(line, "^(...?)%s(.*)$")
- if c and v then
- local n = nil
- if string.sub(c,1,1) == "!" then
- n = true
- c = string.sub(c,2)
- end
- local tt=string.upper(c)
- if tt=="LN" then
- arstab[#arstab+1] = {ln=v, n=n}
- elseif tt=="RC" then
- arstab[#arstab+1] = {rc=v, n=n}
+ -- b) Conjunction to the previous item
+ local conline = string.match(line, "^%s*&(.+)$")
+ if conline then
+ local conj = parse_ruleexp(conline)
+ if conj and previtem==true then
+ -- previtem was default
+ arstab.default_conj = conj
+ previtem = conj
+ elseif conj and previtem then
+ previtem.conj = conj
+ previtem = conj
+ else
+ -- dont know what to do with line, put as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
end
else
- local ct = string.match(line, "^#(.*)$")
- if ct then arstab[#arstab+1] = {c = ct} end
+ -- c) Normal rule spec
+ local prio, ruleline = string.match(line, "^%s*([0-9]*)%s*(.+)%s*$")
+ if ruleline == "*" then
+ -- ruleline is the asterisk, this is default
+ arstab.default = true
+ arstab.default_prio = tonumber(prio) -- evals to nil if not given
+ previtem = true -- marks that previtem was asterisk
+ elseif ruleline then
+ -- ruleline is present, parse it
+ local rule = parse_ruleexp(ruleline)
+ if not rule then
+ -- dont know what to do with line, put as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
+ else
+ rule.prio = tonumber(prio) -- evals to nil if not given
+ arstab[#arstab+1] = rule
+ previtem = rule
+ end
+ else
+ -- d) nothing else works, save line as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
+ end
end
end
end
return arstab
end
-local function find_rtematch(routes, train)
- local default
- for rteid, route in ipairs(routes) do
- if route.ars then
- if route.ars.default then
- default = rteid
- else
- if il.ars_check_rule_match(route.ars, train) then
- return rteid
- end
- end
+
+local function match_arsent(arsent, train)
+ local rule_matches = false
+ if arsent.ln then
+ local line = train.line
+ rule_matches = line and arsent.ln == line
+ if arsent.n then rule_matches = not rule_matches end
+ elseif arsent.rc then
+ local routingcode = train.routingcode
+ rule_matches = routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true)
+ if arsent.n then rule_matches = not rule_matches end
+ end
+ if rule_matches then
+ -- if the entry has a conjunction, go on checking
+ if arsent.conj then
+ return match_arsent(arsent.conj, train)
+ else
+ return true
end
+ else
+ return false
end
- return default
end
--- Checks whether ARS rule explicitly matches. This does not take into account the "default" field, since a wider context is required for this.
--- Returns the rule number that matched, or nil if nothing matched
+-- Given an ARS rule table, check whether any of the clauses in it match the train.
+-- Returns: match_specific, match_default
+-- match_specific: One of the clauses explicitly matched (if this is non-false, match_default is not checked and always given false)
+-- match_default: The default clause (*) matched (as well as any conjunctions attached to the default clause)
+-- both of these can be either true (unconditional match), a number (priority for multi-ars) or false
function il.ars_check_rule_match(ars, train)
if not ars then
- return nil
+ return nil, nil
end
- local line = train.line
- local routingcode = train.routingcode
for arskey, arsent in ipairs(ars) do
- --atdebug(arsent, line, routingcode)
- if arsent.n then
- -- rule is inverse...
- if arsent.ln and (not line or arsent.ln ~= line) then
- return arskey
- elseif arsent.rc and (not routingcode or not string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true)) then
- return arskey
- end
- return nil
+ local rule_matches = match_arsent(arsent, train)
+ if rule_matches then
+ return (arsent.prio or true), nil
end
-
- if arsent.ln and line and arsent.ln == line then
- return arskey
- elseif arsent.rc and routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true) then
- return arskey
+ end
+ if ars.default then
+ local def_matches = true
+ if ars.default_conj then
+ def_matches = match_arsent(ars.default_conj, train)
end
+ if def_matches then
+ return false, (ars.default_prio or true)
+ end
+ end
+ return false,false
+end
+
+local function sort_priority(sprio)
+ -- insertion sort
+ local order = {}
+ local oprio = {}
+ for rteid, prio in pairs(sprio) do
+ local inspos = 1
+ while order[inspos] do
+ if oprio[inspos] > prio then
+ -- next item has higher priority number (= less urgent), insert before it
+ break
+ elseif oprio[inspos] == prio and order[inspos] > rteid then
+ -- next item has same priority as current and a higher routeid, insert before it
+ break
+ end
+ inspos = inspos + 1
end
+ table.insert(order, inspos, rteid)
+ table.insert(oprio, inspos, prio)
+ end
+ --atdebug("sort_priority",sprio,"result",order,oprio)
+ if #order == 1 then
+ return order[1] -- only one route, table doesnt make sense
+ end
+ return order
+end
+
+local function find_rtematch(routes, train)
+ local sprio = {}
+ local default = nil
+ local dprio = {}
+ for rteid, route in ipairs(routes) do
+ if route.ars then
+ local mspec, mdefault = il.ars_check_rule_match(route.ars, train)
+ --atdebug("route",rteid,"ars",route.ars,"gives", mspec, mdefault)
+ if mspec == true then
+ return rteid
+ elseif mspec then
+ sprio[rteid] = mspec
+ end
+ if mdefault == true then
+ if not default then default = rteid end
+ elseif mdefault then
+ dprio[rteid] = mdefault
+ end
+ end
+ end
+ if next(sprio) then
+ return sort_priority(sprio)
+ elseif default then
+ return default
+ elseif next(dprio) then
+ return sort_priority(dprio)
+ else
return nil
+ end
end
+
function advtrains.interlocking.ars_check(signalpos, train, trig_from_dst)
-- check for distant signal
-- this whole check must be delayed until after the route setting has taken place,
@@ -169,6 +342,7 @@ function advtrains.interlocking.ars_check(signalpos, train, trig_from_dst)
local rteid = find_rtematch(tcbs.routes, train)
if rteid then
+ --atdebug("Ars setting ",rteid)
--delay routesetting, it should not occur inside train step
-- using after here is OK because that gets called on every path recalculation
minetest.after(0, il.route.update_route, sigd, tcbs, rteid, nil)
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index 844d350..5e35dba 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -214,10 +214,11 @@ TCB data structure
-- aspect will be set accordingly.
routeset = <index in routes> -- Route set from this signal. This is the entry that is cleared once
-- train has passed the signal. (which will set the aspect to "danger" again)
- route_committed = <boolean> -- When setting/requesting a route, routetar will be set accordingly,
+ -- routeset may be a table (e.g. {1,2}) while the route is not committed yet, indicating a wait for multiple routes at once (Multi-ARS)
+ route_committed = <boolean> -- When setting/requesting a route, routeset will be set accordingly,
-- while the signal still displays danger and nothing is written to the TCs
-- As soon as the route can actually be set, all relevant TCs and turnouts are set and this field
- -- is set true, clearing the signal
+ -- is set true, clearing the signal (when this is true, routeset is never a table)
aspect = <asp> -- The aspect the signal should show. If this is nil, should show the most restrictive aspect (red)
signal_name = <string> -- The human-readable name of the signal, only for documenting purposes
routes = { <route definition> } -- a collection of routes from this signal
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua
index 1065cad..9901d23 100644
--- a/advtrains_interlocking/routesetting.lua
+++ b/advtrains_interlocking/routesetting.lua
@@ -363,7 +363,7 @@ end
-- route setting
-- Call this function to set and cancel routes!
-- sigd, tcbs: self-explanatory
--- newrte: If a new route should be set, the route index of it (in tcbs.routes). nil otherwise
+-- newrte: If a new route should be set, the route index of it (in tcbs.routes). Can also be a table (multi-ars). nil otherwise
-- cancel: true in combination with newrte=nil causes cancellation of the current route.
function ilrs.update_route(sigd, tcbs, newrte, cancel)
--atdebug("Update_Route for",sigd,tcbs.signal_name)
@@ -390,37 +390,66 @@ function ilrs.update_route(sigd, tcbs, newrte, cancel)
if tcbs.route_committed then
return
end
- if newrte then tcbs.routeset = newrte end
+ if newrte then
+ if type(newrte)=="table" and not next(newrte) then
+ error("update_route got multi-ARS with empty table, this is not allowed")
+ end
+ tcbs.routeset = newrte
+ else
+ if type(tcbs.routeset)=="table" and not next(tcbs.routeset) then
+ -- just unset, don't error
+ atwarn(sigd, "had multi-ARS route set with empty list! Cancelled!")
+ tcbs.routeset = nil
+ return
+ end
+ end
--atdebug("Setting:",tcbs.routeset)
- local succ, rsn, cbts, cblk
- local route = tcbs.routes[tcbs.routeset]
- if route then
- succ, rsn, cbts, cblk = ilrs.set_route(sigd, route)
+ -- check: single-ars or multi-ars?
+ local multi_rte
+ if type(tcbs.routeset) == "table" then
+ multi_rte = tcbs.routeset
else
- succ = false
- rsn = attrans("Route state changed.")
+ multi_rte = {tcbs.routeset}
end
- if not succ then
- tcbs.route_rsn = rsn
- --atdebug("Routesetting failed:",rsn)
- -- add cbts or cblk to callback table
- if cbts then
- --atdebug("cbts =",cbts)
- if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end
- advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal)
- end
- if cblk then
- --atdebug("cblk =",cblk)
- if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end
- advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal)
+ for multi_idx, rteid in ipairs(multi_rte) do
+ local succ, rsn, cbts, cblk
+ local route = tcbs.routes[rteid]
+ if route then
+ succ, rsn, cbts, cblk = ilrs.set_route(sigd, route)
+ else
+ succ = false
+ rsn = attrans("Route with index @1 not found", rteid)
end
- else
- --atdebug("Committed Route:",tcbs.routeset)
- -- set_route now sets the signal aspects
- --has_changed_aspect = true
- -- route success. apply default_autoworking flag if requested
- if route.default_autoworking then
- tcbs.route_auto = true --FIX 2025-01-08: never set it to false if it was true!
+ if not succ then
+ if multi_idx==1 then
+ tcbs.route_rsn = rsn
+ else
+ tcbs.route_rsn = (tcbs.route_rsn or "").."\n"..rsn
+ end
+ --atdebug("Routesetting",rteid,"failed:",rsn,"(multi-idx",multi_idx,")")
+ -- add cbts or cblk to callback table
+ if cbts then
+ --atdebug("cbts =",cbts)
+ if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end
+ advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal)
+ end
+ if cblk then
+ --atdebug("cblk =",cblk)
+ if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end
+ advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal)
+ end
+ else
+ --atdebug("Committed Route:",rteid,"(multi-idx",multi_idx,")")
+ -- replace multi_route by single actually committed route
+ tcbs.routeset = rteid
+ -- set_route now sets the signal aspects
+ --has_changed_aspect = true
+ -- route success. apply default_autoworking flag if requested
+ if route.default_autoworking then
+ tcbs.route_auto = true --FIX 2025-01-08: never set it to false if it was true!
+ end
+ -- break out of the for loop, dont try any more routes
+ break
end
end
end
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
index 98a332a..49e7d8b 100644
--- a/advtrains_interlocking/signal_aspect_ui.lua
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -247,7 +247,9 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
ipmarker(pos, plconnid)
minetest.chat_send_player(pname, "Configuring Signal: Successfully set influence point")
-- Try to find a TCB ahead and auto assign this signal there
- if advtrains.interlocking.signal.get_signal_cap_level(signalpos) >= 2 then
+ local pc = player:get_player_control()
+ local no_auto_assign = pc.aux1
+ if not no_auto_assign and advtrains.interlocking.signal.get_signal_cap_level(signalpos) >= 2 then
try_auto_assign_to_tcb(signalpos, pos, plconnid, pname)
end
else
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index 814a11a..0be943a 100755
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -828,14 +828,29 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
form = form.."button[5.5,1.2;1,1;setname;Set]"
if tcbs.routeset then
- local rte = tcbs.routes[tcbs.routeset]
- if not rte then
- atwarn("Unknown route set from signal!")
- tcbs.routeset = nil
- return
+ if type(tcbs.routeset)=="table" then
+ local rtenames = {}
+ for midx,rteid in ipairs(tcbs.routeset) do
+ local rte = tcbs.routes[rteid]
+ if not rte then
+ atwarn("Unknown route set from signal!")
+ tcbs.routeset = nil
+ return
+ end
+ rtenames[midx] = rte.name
+ end
+ form = form.."label[0.5,2.5;Multiple routes are requested (first available is set):]"
+ form = form.."label[0.5,3.0;"..minetest.formspec_escape(table.concat(rtenames,", ")).."]"
+ else
+ local rte = tcbs.routes[tcbs.routeset]
+ if not rte then
+ atwarn("Unknown route set from signal!")
+ tcbs.routeset = nil
+ return
+ end
+ form = form.."label[0.5,2.5;A route is requested from this signal:]"
+ form = form.."label[0.5,3.0;"..minetest.formspec_escape(rte.name).."]"
end
- form = form.."label[0.5,2.5;A route is requested from this signal:]"
- form = form.."label[0.5,3.0;"..minetest.formspec_escape(rte.name).."]"
if tcbs.route_committed then
form = form.."label[0.5,3.5;Route has been set.]"
else
@@ -1000,9 +1015,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
if tcbs.routeset and fields.cancelroute then
- if tcbs.routes[tcbs.routeset] and tcbs.routes[tcbs.routeset].ars then
- tcbs.ars_ignore_next = true
- end
+ tcbs.ars_ignore_next = true
-- if route committed, cancel route ts info
ilrs.update_route(sigd, tcbs, nil, true)
end
diff --git a/advtrains_line_automation/stoprail.lua b/advtrains_line_automation/stoprail.lua
index 89f4a09..aa8dfdd 100644
--- a/advtrains_line_automation/stoprail.lua
+++ b/advtrains_line_automation/stoprail.lua
@@ -24,7 +24,8 @@ local function updatemeta(pos)
end
local door_dropdown = {L=1, R=2, C=3}
-local door_dropdown_rev = {Right="R", Left="L", Closed="C"}
+--local door_dropdown_rev = {Right="R", Left="L", Closed="C"} -- Code review : why are the value in an order different than the one in the dropdown box ?
+local door_dropdown_code = {"L", "R", "C"} -- switch to numerical index of selection : for conversion of the numerical index in the opening side selection dropdown box to the internal codification
local function show_stoprailform(pos, player)
local pe = advtrains.encode_pos(pos)
@@ -60,7 +61,7 @@ local function show_stoprailform(pos, player)
form = form.."field[4.30,2.0;1.75,1;track;"..S("Track")..";"..minetest.formspec_escape(stdata.track).."]"
form = form.."field[6.05,2.0;1.75,1;wait;"..S("Stop Time")..";"..stdata.wait.."]"
form = form.."label[0.5,2.6;"..S("Door Side").."]"
- form = form.."dropdown[0.51,3.0;2;doors;"..S("Left")..","..S("Right")..","..S("Closed")..";"..door_dropdown[stdata.doors].."]"
+ form = form.."dropdown[0.51,3.0;2;doors;"..S("Left")..","..S("Right")..","..S("Closed")..";"..door_dropdown[stdata.doors]..";true]" -- switch to numerical index of the selection
form = form.."checkbox[3.00,2.4;reverse;"..S("Reverse train")..";"..(stdata.reverse and "true" or "false").."]"
form = form.."checkbox[3.00,2.8;kick;"..S("Kick out passengers")..";"..(stdata.kick and "true" or "false").."]"
form = form.."checkbox[3.00,3.2;waitsig;"..S("Wait for signal to clear")..";"..(stdata.waitsig and "true" or "false").."]"
@@ -120,7 +121,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- dropdowns
if fields.doors then
- stdata.doors = door_dropdown_rev[fields.doors] or "C"
+ stdata.doors = door_dropdown_code[tonumber(fields.doors)] or "C" -- switch to numerical index of selection; attention : fields.doors is string typed, needed to be converted to an integer typed index in door_dropdown_code table
end
if fields.track then
diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua
index dd26f51..c98f62b 100644
--- a/advtrains_luaautomation/atc_rail.lua
+++ b/advtrains_luaautomation/atc_rail.lua
@@ -62,7 +62,7 @@ function r.fire_event(pos, evtdata, appr_internal)
local new_id = advtrains.split_train_at_index(train, index)
if new_id then
minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
- return true
+ return new_id
end
return false
end,
@@ -73,7 +73,7 @@ function r.fire_event(pos, evtdata, appr_internal)
if new_id then
minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
end
- return fc or ""
+ return (fc or ""), new_id
end,
split_off_locomotive = function(cmd, len)
assertt(cmd, "string")
@@ -81,7 +81,8 @@ function r.fire_event(pos, evtdata, appr_internal)
local new_id, fc = advtrains.split_train_at_fc(train, true, len)
if new_id then
minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
- end
+ end
+ return (fc or ""), new_id
end,
train_length = function ()
if not train_id then return false end
diff --git a/advtrains_signals_japan/init.lua b/advtrains_signals_japan/init.lua
index 1140b6b..728a91f 100644
--- a/advtrains_signals_japan/init.lua
+++ b/advtrains_signals_japan/init.lua
@@ -15,6 +15,19 @@ local light_distant = light_purple
local light_off = signal_face_texture
do
+ local model_dir = core.get_modpath("advtrains_signals_japan") .. DIR_DELIM .. "models"
+ local function add_model(name, content)
+ local fn = "advtrains_signals_japan_" .. name
+ if core.features.dynamic_add_media_startup then
+ core.dynamic_add_media {
+ filename = fn,
+ filedata = content,
+ }
+ else
+ core.mkdir(model_dir)
+ core.safe_file_write(model_dir .. DIR_DELIM .. fn, content)
+ end
+ end
local model_path_prefix = table.concat({minetest.get_modpath("advtrains_signals_japan"), "models", "advtrains_signals_japan_"}, DIR_DELIM)
local function vertex(x, y, z)
@@ -122,7 +135,7 @@ do
pole_vertices = table.concat(pole_vertices, "\n")
pole_objdef = table.concat(pole_objdef, "\n")
pole_uv = table.concat(pole_uv, "\n")
- minetest.safe_file_write(model_path_prefix .. "pole.obj", table.concat({pole_vertices, pole_uv, pole_objdef}, "\n"))
+ add_model("pole.obj", table.concat({pole_vertices, pole_uv, pole_objdef}, "\n"))
-- generate signals
for lightcount = 5, 6 do
@@ -231,7 +244,7 @@ do
face_vertices = table.concat(face_vertices, "\n")
face_uv = table.concat(face_uv, "\n")
face_objdef = table.concat(face_objdef, "\n")
- minetest.safe_file_write(model_path_prefix .. lightcount .. "_" .. rotname .. ".obj", table.concat({
+ add_model(lightcount .. "_" .. rotname .. ".obj", table.concat({
pole_vertices,
face_vertices,
table.concat(light_vertices, "\n"),