aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking
diff options
context:
space:
mode:
authororwell <orwell@bleipb.de>2025-05-27 21:03:14 +0200
committerorwell <orwell@bleipb.de>2025-05-27 21:03:14 +0200
commit8506dd2825b715293138976a5ad1fa11a46206a7 (patch)
tree1f48c1dc03c3bbc6ed6762bd04d10e543a3a580c /advtrains_interlocking
parent2a9891577c1b00068cc4ec858c7dc6c5196f0a2b (diff)
parentadc01a0bba29b40278e45c50caa954c435374f7b (diff)
downloadadvtrains-8506dd2825b715293138976a5ad1fa11a46206a7.tar.gz
advtrains-8506dd2825b715293138976a5ad1fa11a46206a7.tar.bz2
advtrains-8506dd2825b715293138976a5ad1fa11a46206a7.zip
Merge branch 'master' into cesky-hvozd
Throw away most of the changes in everything except line_automation. Merge line_automation changes between CH and master
Diffstat (limited to 'advtrains_interlocking')
-rw-r--r--advtrains_interlocking/ars.lua296
-rw-r--r--advtrains_interlocking/database.lua10
-rw-r--r--advtrains_interlocking/init.lua4
-rw-r--r--advtrains_interlocking/route_prog.lua96
-rw-r--r--advtrains_interlocking/route_ui.lua58
-rw-r--r--advtrains_interlocking/routesetting.lua85
-rw-r--r--advtrains_interlocking/signal_api.lua2
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua42
-rw-r--r--advtrains_interlocking/smartroute.lua41
-rw-r--r--advtrains_interlocking/tcb_ts_ui.lua266
-rw-r--r--advtrains_interlocking/tool.lua31
11 files changed, 581 insertions, 350 deletions
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 de6f2e8..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
@@ -760,7 +761,7 @@ function ildb.update_rs_cache(ts_id)
--atdebug("== Running update_rs_cache for ",ts_id)
-- start on every of the TS's TCBs, walk the track forward and store locks along the way
for start_tcbi, start_tcbs in ipairs(ts.tc_breaks) do
- local start_pkey = advtrains.encode_pos(start_tcbs.p)
+ start_pkey = advtrains.encode_pos(start_tcbs.p)
rscache[start_pkey] = {}
--atdebug("Starting for ",start_tcbi, start_tcbs)
local locks_found = {}
@@ -770,7 +771,7 @@ function ildb.update_rs_cache(ts_id)
-- now result_table contains found route locks. Match them with the other TCBs we have in this section
for end_tcbi, end_tcbs in ipairs(ts.tc_breaks) do
if end_tcbi ~= start_tcbi then
- local end_pkey = advtrains.encode_pos(end_tcbs.p)
+ end_pkey = advtrains.encode_pos(end_tcbs.p)
if result_table[end_pkey] then
--atdebug("Set RSCache entry",end_pkey.."-"..end_pkey,"=",result_table[end_pkey])
local lockstab = result_table[end_pkey]
@@ -941,7 +942,6 @@ function ildb.remove_ts(ts_id)
if not ts then
error("remove_ts: "..ts_id.." doesn't exist")
end
- local i = 1
while ts.tc_breaks[i] do
-- get TCBS
local sigd = ts.tc_breaks[i]
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index e11ffa2..ee08c30 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -1,5 +1,5 @@
--- Advtrains interlocking system
--- See database.lua for a detailed explanation
+--- Advtrains interlocking system.
+-- @module advtrains.interlocking
advtrains.interlocking = {}
diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua
index 76dad28..81aa133 100644
--- a/advtrains_interlocking/route_prog.lua
+++ b/advtrains_interlocking/route_prog.lua
@@ -29,19 +29,17 @@ end
local markerent = {}
minetest.register_entity("advtrains_interlocking:routemarker", {
- initial_properties = {
- visual = "mesh",
- mesh = "trackplane.b3d",
- textures = {"at_il_route_set.png"},
- collisionbox = {-1,-0.5,-1, 1,-0.4,1},
- visual_size = {x=10, y=10},
- static_save = false,
- },
+ visual = "mesh",
+ mesh = "trackplane.b3d",
+ textures = {"at_il_route_set.png"},
+ collisionbox = {-1,-0.5,-1, 1,-0.4,1},
+ visual_size = {x=10, y=10},
on_punch = function(self)
self.object:remove()
end,
get_staticdata = function() return "STATIC" end,
on_activate = function(self, sdata) if sdata=="STATIC" then self.object:remove() end end,
+ static_save = false,
})
@@ -125,11 +123,11 @@ the distant signal aspect is determined as DANGER.
]]--
local function chat(pname, message)
- minetest.chat_send_player(pname, "[Programování cesty] "..message)
+ minetest.chat_send_player(pname, "[Route programming] "..message)
end
local function clear_lock(locks, pname, pts)
locks[pts] = nil
- chat(pname, pts.." již není ovlivněn/a, když je tato cesta nastavena.")
+ chat(pname, pts.." is no longer affected when this route is set.")
end
local function otherside(s)
@@ -176,8 +174,11 @@ function advtrains.interlocking.visualize_route(origin, route, context, tmp_lcks
end
-- display locks
for pts, state in pairs(v.locks) do
- local pos = assert(advtrains.decode_pos(pts))
- routesprite(context, pos, "fix"..k..pts, "at_il_route_lock.png", "Zajištěna ve stavu '"..state.."' po cestě "..route.name.." dokud není úsek #"..k.." uvolněn.")
+ local pos = minetest.string_to_pos(pts)
+ if not pos then
+ pos = advtrains.decode_pos(pts)
+ end
+ routesprite(context, pos, "fix"..k..pts, "at_il_route_lock.png", "Fixed in state '"..state.."' by route "..route.name.." until segment #"..k.." is freed.")
end
end
@@ -204,7 +205,7 @@ function advtrains.interlocking.visualize_route(origin, route, context, tmp_lcks
-- display locks set by player
for pts, state in pairs(tmp_lcks) do
local pos = advtrains.decode_pos(pts)
- routesprite(context, pos, "fixp"..pts, "at_il_route_lock_edit.png", "Zajištěna ve stavu '"..state.."' cestou "..route.name.." (levý klik pro uvolnění)",
+ routesprite(context, pos, "fixp"..pts, "at_il_route_lock_edit.png", "Fixed in state '"..state.."' by route "..route.name.." (punch to unfix)",
function() clear_lock(tmp_lcks, pname, pts) end)
end
end
@@ -215,7 +216,7 @@ local player_rte_prog = {}
function advtrains.interlocking.init_route_prog(pname, sigd, default_route)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local rp = {
@@ -239,7 +240,7 @@ function advtrains.interlocking.init_route_prog(pname, sigd, default_route)
end
player_rte_prog[pname] = rp
advtrains.interlocking.visualize_route(sigd, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
- minetest.chat_send_player(pname, "Režim programování cesty je aktivní. Klikejte levým tlačítkem na TCB pro přidání úseků a na výhybky pro jejich uzamčení.")
+ minetest.chat_send_player(pname, "Route programming mode active. Punch TCBs to add route segments, punch turnouts to lock them.")
end
local function get_last_route_item(origin, route)
@@ -252,32 +253,33 @@ end
local function do_advance_route(pname, rp, sigd, tsref)
table.insert(rp.route, {next = sigd, locks = rp.tmp_lcks})
rp.tmp_lcks = {}
- chat(pname, "Úsek '"..(tsref and (tsref.name or "") or "--konec zab.--").."' přidán na cestu.")
+ chat(pname, "Added track section '"..(tsref and (tsref.name or "") or "--EOI--").."' to the route.")
end
local function finishrpform(pname)
local rp = player_rte_prog[pname]
if not rp then return end
- local form = "size[7,6]label[0.5,0.5;Dokončit programování cesty]"
+ local form = "size[7,6]label[0.5,0.5;Finish programming route]"
local terminal = get_last_route_item(rp.origin, rp.route)
if terminal then
local term_tcbs = advtrains.interlocking.db.get_tcbs(terminal)
if term_tcbs.signal then
- form = form .. "label[0.5,1.5;Cesta končí na signalizaci:]"
- form = form .. "label[0.5,2 ;"..term_tcbs.signal_name.."]"
+ local signalname = (term_tcbs.signal_name or "") .. sigd_to_string(terminal)
+ form = form .. "label[0.5,1.5;Route ends at signal:]"
+ form = form .. "label[0.5,2 ;"..signalname.."]"
else
- form = form .. "label[0.5,1.5;VAROVÁNÍ: Cesta nekončí na signalizaci.]"
- form = form .. "label[0.5,2 ;Cesty většinou končí na signlizacích.]"
- form = form .. "label[0.5,2.5;Nejste-li si jistý/á, zrušte programování!]"
+ form = form .. "label[0.5,1.5;WARNING: Route does not end at a signal.]"
+ form = form .. "label[0.5,2 ;Routes should in most cases end at signals.]"
+ form = form .. "label[0.5,2.5;Cancel if you are unsure!]"
end
else
- form = form .. "label[0.5,1.5;Cesta vede do]"
- form = form .. "label[0.5,2 ;nezabezpečené oblasti]"
+ form = form .. "label[0.5,1.5;Route leads into]"
+ form = form .. "label[0.5,2 ;non-interlocked area]"
end
- form = form.."field[0.8,3.5;5.2,1;name;Zadejte název cesty;]"
- form = form.."button_exit[0.5,4.5; 5,1;save;Uložit cestu]"
+ form = form.."field[0.8,3.5;5.2,1;name;Enter Route Name;]"
+ form = form.."button_exit[0.5,4.5; 5,1;save;Save Route]"
minetest.show_formspec(pname, "at_il_routepf", form)
@@ -325,7 +327,7 @@ local function check_advance_valid(tcbpos, rp)
local adv_tcbs = advtrains.interlocking.db.get_tcbs(this_sigd)
local next_tsid = adv_tcbs.ts_id
local can_over, over_ts, next_tc_bs = false, nil, nil
- local cannotover_rsn = "Rozbíhavý úsek (>2 TCB)"
+ local cannotover_rsn = "Next section is diverging (>2 TCBs)"
if next_tsid then
-- you may not advance over EOI. While this is technically possible,
-- in practise this just enters an unnecessary extra empty route item.
@@ -333,7 +335,7 @@ local function check_advance_valid(tcbpos, rp)
next_tc_bs = over_ts.tc_breaks
can_over = #next_tc_bs <= 2
else
- cannotover_rsn = "Konec zabezpečené oblasti"
+ cannotover_rsn = "End of interlocking"
end
local over_sigd = nil
@@ -375,29 +377,29 @@ local function show_routing_form(pname, tcbpos, message)
-- show nothing at all
-- In all cases, Discard and Backtrack buttons needed.
- local form = "size[7,9.5]label[0.5,0.5;Pokračovat/ukončit cestu]"
+ local form = "size[7,9.5]label[0.5,0.5;Advance/Complete Route]"
if message then
form = form .. "label[0.5,1;"..message.."]"
end
if advance_valid and not is_endpoint then
- form = form.. "label[0.5,1.8;Pokračovat s cestou do dalšího úseku]"
+ form = form.. "label[0.5,1.8;Advance to next route section]"
form = form.."image_button[0.5,2.2; 5,1;at_il_routep_advance.png;advance;]"
form = form.. "label[0.5,3.5;-------------------------]"
else
- form = form.. "label[0.5,2.3;Tato TCB není vhodná]"
- form = form.. "label[0.5,2.8;pro pokračování cesty.]"
+ form = form.. "label[0.5,2.3;This TCB is not suitable as]"
+ form = form.. "label[0.5,2.8;route continuation.]"
end
if advance_valid or is_endpoint then
- form = form.. "label[0.5,3.8;Ukonči cestu ZDE]"
+ form = form.. "label[0.5,3.8;Finish route HERE]"
form = form.."image_button[0.5, 4.2; 5,1;at_il_routep_end_here.png;endhere;]"
if can_over then
- form = form.. "label[0.5,5.3;Ukončit cestu na konci NÁSLEDUJÍCÍHO úseku]"
+ form = form.. "label[0.5,5.3;Finish route at end of NEXT section]"
form = form.."image_button[0.5,5.7; 5,1;at_il_routep_end_over.png;endover;]"
else
- form = form.. "label[0.5,5.3;Pokračování do následujícího úseku]"
- form = form.. "label[0.5,5.8;zde není možné.]"
+ form = form.. "label[0.5,5.3;Advancing over next section is]"
+ form = form.. "label[0.5,5.8;impossible at this place.]"
if cannotover_rsn then
form = form.. "label[0.5,6.3;"..cannotover_rsn.."]"
end
@@ -406,9 +408,9 @@ local function show_routing_form(pname, tcbpos, message)
form = form.. "label[0.5,7;-------------------------]"
if #rp.route > 0 then
- form = form.."button[0.5,7.4; 5,1;retract;Zpět o jeden úsek]"
+ form = form.."button[0.5,7.4; 5,1;retract;Step back one section]"
end
- form = form.."button[0.5,8.4; 5,1;cancel;Zrušit programování cesty]"
+ form = form.."button[0.5,8.4; 5,1;cancel;Cancel route programming]"
minetest.show_formspec(pname, "at_il_rprog_"..minetest.pos_to_string(tcbpos), form)
end
@@ -419,7 +421,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local tcbpts = string.match(formname, "^at_il_rprog_([^_]+)$")
local tcbpos
if tcbpts then
- tcbpos = assert(minetest.string_to_pos(tcbpts))
+ tcbpos = minetest.string_to_pos(tcbpts)
end
if tcbpos then
-- RPROG form
@@ -459,12 +461,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
rp.tmp_locks = rp.route[#rp.route].locks
rp.route[#rp.route] = nil
- chat(pname, "Úsek cesty "..(#rp.route+1).." odstraněn.")
+ chat(pname, "Route section "..(#rp.route+1).." removed.")
end
if fields.cancel then
player_rte_prog[pname] = nil
advtrains.interlocking.clear_visu_context("prog_"..pname)
- chat(pname, "Cesta zahozena.")
+ chat(pname, "Route discarded.")
minetest.close_formspec(pname, formname)
return
end
@@ -485,13 +487,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local rp = player_rte_prog[pname]
if rp then
if #rp.route <= 0 then
- chat(pname, "Bez cíle nemohu naprogramovat cestu.")
+ chat(pname, "Cannot program route without a target")
return
end
local tcbs = advtrains.interlocking.db.get_tcbs(rp.origin)
if not tcbs then
- chat(pname, "Původní TCB se během programování ztratilo. Zkuste cestu naprogramovat znovu.")
+ chat(pname, "The origin TCB has become unknown during programming. Try again.")
return
end
@@ -505,7 +507,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
advtrains.interlocking.clear_visu_context("prog_"..pname)
player_rte_prog[pname] = nil
- chat(pname, "Cesta úspěšně naprogramována.")
+ chat(pname, "Successfully programmed route.")
advtrains.interlocking.show_route_edit_form(pname, rp.origin, #tcbs.routes)
return
@@ -528,10 +530,10 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
local meta = minetest.get_meta(pos)
local tcbpts = meta:get_string("tcb_pos")
if tcbpts == "" then
- chat(pname, "Tato TCB není nastavena, nejprve k ní musíte přiřadit kolej")
+ chat(pname, "This TCB is unconfigured, you first need to assign it to a rail")
return
end
- local tcbpos = assert(minetest.string_to_pos(tcbpts))
+ local tcbpos = minetest.string_to_pos(tcbpts)
-- show formspec
@@ -551,7 +553,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
else
local state = advtrains.getstate(pos)
rp.tmp_lcks[pts] = state
- chat(pname, pts.." je držena ve stavu "..state.." , když je tato cesta nastavena a uvolněna.")
+ chat(pname, pts.." is held in "..state.." position when this route is set and freed ")
end
advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
return
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua
index baaa957..3c7bd64 100644
--- a/advtrains_interlocking/route_ui.lua
+++ b/advtrains_interlocking/route_ui.lua
@@ -17,7 +17,7 @@ local sel_rpartcache = {}
function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
@@ -26,9 +26,9 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local route = tcbs.routes[routeid]
if not route then return end
- local form = "size[9,11]label[0.5,0.2;Přehled cesty]"
- form = form.."field[0.8,1.2;6.5,1;name;Název cesty;"..minetest.formspec_escape(route.name).."]"
- form = form.."button[7.0,0.9;1.5,1;setname;Nastavit]"
+ local form = "size[9,11]label[0.5,0.2;Route overview]"
+ form = form.."field[0.8,1.2;6.5,1;name;Route name;"..minetest.formspec_escape(route.name).."]"
+ form = form.."button[7.0,0.9;1.5,1;setname;Set]"
-- construct textlist for route information
local tab = {}
@@ -37,7 +37,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
tab[#tab+1] = minetest.formspec_escape(string.gsub(t, ",", " "))
tabref[#tab] = { [rty] = true, param = rpara, seg = rseg, idx = #tab }
end
- itab(1, "("..(tcbs.signal_name or "+")..") Cesta #"..routeid, "signal", sigd)
+ itab(1, "("..(tcbs.signal_name or "+")..") Route #"..routeid, "signal", sigd)
-- this code is partially copy-pasted from routesetting.lua
-- we start at the tc designated by signal
@@ -47,12 +47,12 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- itab("-!- Na "..sigd_to_string(c_sigd).." nejsou žádné TCB. Prosím, přenastavte cestu!")
+ itab(i, "-!- No TCBS at "..sigd_to_string(c_sigd)..". Please reconfigure route!", "err", nil)
break
end
c_ts_id = c_tcbs.ts_id
if not c_ts_id then
- itab("-!- S "..sigd_to_string(c_sigd).." nesousedí žádný traťový úsek. Prosím přenastavte cestu!")
+ itab(i, "-!- No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!", "err", nil)
break
end
c_ts = ildb.get_ts(c_ts_id)
@@ -62,15 +62,15 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local signame = "-"
if c_tcbs and c_tcbs.signal then signame = c_tcbs.signal_name or "o" end
itab(i, ""..i.." "..sigd_to_string(c_sigd).." ("..signame..")", "signal", c_sigd)
- itab(i, "= "..(c_ts and c_ts.name or c_ts_id).." ="..(c_rseg.call_on and " [pov.]" or ""), "section", c_ts_id)
+ itab(i, "= "..(c_ts and c_ts.name or c_ts_id).." ="..(c_rseg.call_on and " [CO]" or ""), "section", c_ts_id)
if c_rseg.locks then
for pts, state in pairs(c_rseg.locks) do
local pos = advtrains.decode_pos(pts)
- itab(i, "Zámek "..core.pos_to_string(pos).." -> "..state, "lock", pos)
+ itab(i, "L "..pts.." -> "..state, "lock", pos)
if not advtrains.is_passive(pos) then
- itab("-!- Na "..core.pos_to_string(pos).." není žádná pasivní komponenta. Prosím, přenastavte cestu!")
+ itab(i, "-!- No passive component at "..pts..". Please reconfigure route!", "err", nil)
break
end
end
@@ -80,7 +80,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
if nvar then
local re_tcbs = ildb.get_tcbs({p = nvar.p, s = (nvar.s==1) and 2 or 1})
if not re_tcbs or not re_tcbs.ts_id or re_tcbs.ts_id~=c_ts_id then
- itab(i, "-!- Na "..sigd_to_string(c_sigd)..".neodpovídají začátek a konec úseku!", "err", nil)
+ itab(i, "-!- At "..sigd_to_string(c_sigd)..".Section Start and End do not match!", "err", nil)
break
end
end
@@ -92,13 +92,13 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local e_tcbs = ildb.get_tcbs(c_sigd)
local signame = "-"
if e_tcbs and e_tcbs.signal then signame = e_tcbs.signal_name or "o" end
- itab(i, "K "..sigd_to_string(c_sigd).." ("..signame..")", "end", c_sigd)
+ itab(i, "E "..sigd_to_string(c_sigd).." ("..signame..")", "end", c_sigd)
else
- itab(i, "K (žádný)", "end", nil)
+ itab(i, "E (none)", "end", nil)
end
if not sel_rpartidx then sel_rpartidx = 1 end
- form = form.."textlist[0.5,2;4.5,3.9;routelog;"..table.concat(tab, ",")..";"..(sel_rpartidx or 1)..";false]"
+ form = form.."textlist[0.5,2;3.5,3.9;routelog;"..table.concat(tab, ",")..";"..(sel_rpartidx or 1)..";false]"
-- to the right of rtelog, controls are displayed for the thing in focus
-- What is in focus is determined by the parameter sel_rpartidx
@@ -113,10 +113,10 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
-- main aspect list
local signalpos = s_tcbs and s_tcbs.signal
if signalpos and rseg then
- form = form..F.label(5.5, 2, "Signál:")
+ form = form..F.label(4.5, 2, "Signal Aspect:")
local ndef = signalpos and advtrains.ndb.get_ndef(signalpos)
if ndef and ndef.advtrains and ndef.advtrains.main_aspects then
- local entries = { "<výchozí>" }
+ local entries = { "<Default Aspect>" }
local sel = 1
for i, mae in ipairs(ndef.advtrains.main_aspects) do
entries[i+1] = mae.description
@@ -124,7 +124,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
sel = i+1
end
end
- form = form..F.dropdown(5.5, 3.0, 4, "sa_main_aspect", entries, sel, true)
+ form = form..F.dropdown(4.5, 3.0, 4, "sa_main_aspect", entries, sel, true)
end
-- checkbox for assign distant signal
local assign_dst = rseg.assign_dst
@@ -133,21 +133,21 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
-- defaults to false for the very first signal and true for all others (= minimal user configuration overhead)
-- Note: on save, the value will be fixed at either false or true
end
- form = form..string.format("checkbox[5.5,4.0;sa_distant;Ohlásit předzvěst;%s]", assign_dst)
+ form = form..string.format("checkbox[4.5,4.0;sa_distant;Announce distant signal;%s]", assign_dst)
else
- form = form..F.label(5.5, 2, "Tato TCB nemá žádné návěstidlo")
+ form = form..F.label(4.5, 2, "No Signal at this TCB")
end
elseif sel_rpart and sel_rpart.section then
local rseg = route[sel_rpart.seg]
if rseg then
- form = form..F.label(5.5, 2, "Volby:")
+ form = form..F.label(4.5, 2, "Section Options:")
-- checkbox for call-on
- form = form..string.format("checkbox[5.5,4.0;se_callon;Povolit (úsek může být obsazen);%s]", rseg.call_on)
+ form = form..string.format("checkbox[4.5,4.0;se_callon;Call-on (section may be occupied);%s]", rseg.call_on)
end
elseif sel_rpart and sel_rpart.err then
- form = form.."textarea[5.5,2.5;4,4;errorta;Chyba:;"..tab[sel_rpartidx].."]"
+ form = form.."textarea[4.5,2.5;4,4;errorta;Error:;"..tab[sel_rpartidx].."]"
else
- form = form..F.label(5.5, 2, "<< Vyberte část cesty pro nastavení voleb")
+ form = form..F.label(4.5, 2, "<< Select a route part to edit options")
end
form = form.."button[0.5,6;1,1;prev;<<<]"
@@ -158,15 +158,15 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
--if route.smartroute_generated or route.default_autoworking then
-- form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]"
--end
- form = form.."button[5.5,6;3,1;delete;Smazat cestu]"
- form = form.."button[0.5,7;3,1;back;Zpět na návěstidlo]"
- form = form.."button[3.5,7;2,1;clone;Klonovat cestu]"
- form = form.."button[5.5,7;3,1;newfrom;Nová z cesty]"
+ form = form.."button[5.5,6;3,1;delete;Delete Route]"
+ form = form.."button[0.5,7;3,1;back;Back to signal]"
+ form = form.."button[3.5,7;2,1;clone;Clone Route]"
+ form = form.."button[5.5,7;3,1;newfrom;New From Route]"
--atdebug(route.ars)
form = form.."style[ars;font=mono]"
- form = form.."textarea[0.8,8.3;5,3;ars;ARS pravidla;"..atil.ars_to_text(route.ars).."]"
- form = form.."button[5.5,8.23;3,1;savears;Uložit ARS pravidla]"
+ form = form.."textarea[0.8,8.3;5,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]"
+ form = form.."button[5.5,8.23;3,1;savears;Save ARS List]"
local formname = "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid
minetest.show_formspec(pname, formname, form)
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_api.lua b/advtrains_interlocking/signal_api.lua
index 7d718a4..f624f7a 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -303,7 +303,7 @@ function signal.get_aspect_internal(pos, aspt)
-- look up node and nodedef
local node = advtrains.ndb.get_node_or_nil(pos)
local ndef = node and minetest.registered_nodes[node.name]
- if not aspt or not ndef then
+ if not aspt then
-- oh, no main aspect, nevermind
return signal.MASP_HALT, nil, node, ndef
end
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
index 818f6d6..49e7d8b 100644
--- a/advtrains_interlocking/signal_aspect_ui.lua
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -38,14 +38,14 @@ function advtrains.interlocking.make_ip_formspec_component(pos, x, y, w)
local ipos = minetest.string_to_pos(pts)
ipmarker(ipos, connid)
return table.concat {
- F.S_label(x, y, "Bod účinku nastaven na @1.", string.format("%s/%s", pts, connid)),
- F.S_button_exit(x, y+0.5, w/2-0.125, "ip_set", "Změnit"),
- F.S_button_exit(x+w/2+0.125, y+0.5, w/2-0.125, "ip_clear", "Odebrat bod účinku"),
+ F.S_label(x, y, "Influence point is set at @1.", string.format("%s/%s", pts, connid)),
+ F.S_button_exit(x, y+0.5, w/2-0.125, "ip_set", "Modify"),
+ F.S_button_exit(x+w/2+0.125, y+0.5, w/2-0.125, "ip_clear", "Clear"),
}
else
return table.concat {
- F.S_label(x, y, "Bod účinku není nastaven."),
- F.S_button_exit(x, y+0.5, w, "ip_set", "Nastavit bod účinku"),
+ F.S_label(x, y, "Influence point is not set."),
+ F.S_button_exit(x, y+0.5, w, "ip_set", "Set influence point"),
}
end
end
@@ -83,10 +83,10 @@ function advtrains.interlocking.show_ip_sa_form(pos, pname)
-- Create Signal aspect formspec elements
local ndef = advtrains.ndb.get_ndef(pos)
if ndef and ndef.advtrains then
- form[#form+1] = F.label(0.5, 2, "signál:")
+ form[#form+1] = F.label(0.5, 2, "Signal Aspect:")
-- main aspect list
if ndef.advtrains.main_aspects then
- local entries = { "<žádný>" }
+ local entries = { "<none>" }
local sel = 1
for i, mae in ipairs(ndef.advtrains.main_aspects) do
entries[i+1] = mae.description
@@ -98,9 +98,9 @@ function advtrains.interlocking.show_ip_sa_form(pos, pname)
end
-- distant signal assign (is shown either when main_aspect is not none, or when pure distant signal)
if rpos then
- form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_undistant", "odpojit od: " .. minetest.pos_to_string(rpos))
+ form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_undistant", "Dst: " .. minetest.pos_to_string(rpos))
elseif (ma and not ma.halt) or not ndef.advtrains.main_aspects then
- form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_distant", "<přiřadit předzvěst>")
+ form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_distant", "<assign distant>")
end
end
@@ -165,12 +165,12 @@ end)
-- inits the signal IP assignment process
function advtrains.interlocking.init_ip_assign(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
--remove old IP
--advtrains.interlocking.db.clear_ip_by_signalpos(pos)
- minetest.chat_send_player(pname, attrans("Configuring Signal: Please look in train's driving direction and punch rail to set influence point."))
+ minetest.chat_send_player(pname, "Configuring Signal: Please look in train's driving direction and punch rail to set influence point.")
players_assign_ip[pname] = pos
end
@@ -178,10 +178,10 @@ end
-- inits the distant signal assignment process
function advtrains.interlocking.init_distant_assign(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
- minetest.chat_send_player(pname, attrans("Set distant signal: Punch the main signal to assign!"))
+ minetest.chat_send_player(pname, "Set distant signal: Punch the main signal to assign!")
players_assign_distant[pname] = pos
end
@@ -203,7 +203,7 @@ local function try_auto_assign_to_tcb(signalpos, pos, connid, pname)
advtrains.interlocking.db.assign_signal_to_tcbs(signalpos, sigd)
-- use auto-naming
advtrains.interlocking.add_autoname_to_tcbs(tcb[aconnid], pname)
- minetest.chat_send_player(pname, attrans("Assigned signal to the TCB at @1", core.pos_to_string(apos)))
+ minetest.chat_send_player(pname, "Assigned signal to the TCB at "..core.pos_to_string(apos))
advtrains.interlocking.show_tcb_marker(apos)
advtrains.interlocking.show_signalling_form(sigd, pname)
end
@@ -215,7 +215,7 @@ local function try_auto_assign_to_tcb(signalpos, pos, connid, pname)
local mainsig = advtrains.interlocking.db.get_ip_signal(pts, aconnid)
if mainsig and advtrains.interlocking.signal.get_signal_cap_level(mainsig) >= 3 then
advtrains.interlocking.signal.set_aspect(signalpos, "_default", mainsig)
- minetest.chat_send_player(pname, attrans("Assigned distant signal to the main signal at @1", core.pos_to_string(mainsig)))
+ minetest.chat_send_player(pname, "Assigned distant signal to the main signal at "..core.pos_to_string(mainsig))
return
end
end
@@ -245,19 +245,21 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if not advtrains.interlocking.db.get_ip_signal_asp(pts, plconnid) then
advtrains.interlocking.db.set_ip_signal(pts, plconnid, signalpos)
ipmarker(pos, plconnid)
- minetest.chat_send_player(pname, attrans("Configuring Signal: Successfully set influence point"))
+ 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
- minetest.chat_send_player(pname, attrans("Configuring Signal: Influence point of another signal is already present!"))
+ minetest.chat_send_player(pname, "Configuring Signal: Influence point of another signal is already present!")
end
else
- minetest.chat_send_player(pname, attrans("Configuring Signal: This is not a normal two-connection rail! Aborted."))
+ minetest.chat_send_player(pname, "Configuring Signal: This is not a normal two-connection rail! Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring Signal: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring Signal: Node is too far away. Aborted.")
end
players_assign_ip[pname] = nil
end
diff --git a/advtrains_interlocking/smartroute.lua b/advtrains_interlocking/smartroute.lua
index d57a0c8..76c7814 100644
--- a/advtrains_interlocking/smartroute.lua
+++ b/advtrains_interlocking/smartroute.lua
@@ -52,7 +52,7 @@ local RTE_MAX_SECS = 16
-- find_more_than: search is aborted only if more than the specified number of routes are found
function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
local found_routes = {}
- local restart_tcbs = { {sigd = sigd, tcbseq = {} } }
+ local restart_tcbs = { {sigd = sigd, tcbseq = {}, secseq = {} } }
local last_len = 0
while true do
-- take first entry out of restart_tcbs (due to the way it is inserted the first entry will always be the one with the lowest length
@@ -94,7 +94,9 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
local nsigd = {p=end_sigd.p, s = end_sigd.s==1 and 2 or 1} -- invert to other side
-- record nsigd in the tcbseq
local ntcbseq = table.copy(cur_restart.tcbseq)
+ local nsecseq = table.copy(cur_restart.secseq)
ntcbseq[#ntcbseq+1] = nsigd
+ nsecseq[#nsecseq+1] = c_ts.name or c_ts_id
local shall_continue = true
-- check if that sigd is a route target
local tcbs = ildb.get_tcbs(nsigd)
@@ -109,6 +111,7 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
-- record the found route in the results
found_routes[#found_routes+1] = {
tcbseq = ntcbseq,
+ secseq = nsecseq,
shunt_route = not is_mainsignal,
name = tcbs.signal_name or atil.sigd_to_string(nsigd)
}
@@ -122,7 +125,7 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
end
-- unless overridden, insert the next restart point
if shall_continue then
- restart_tcbs[#restart_tcbs+1] = {sigd = nsigd, tcbseq = ntcbseq }
+ restart_tcbs[#restart_tcbs+1] = {sigd = nsigd, tcbseq = ntcbseq, secseq = nsecseq }
end
end
end
@@ -140,10 +143,10 @@ local players_smartroute_actions = {}
function sr.propose_next(pname, sigd, find_more_than, searching_shunt)
local tcbs = ildb.get_tcbs(sigd)
if not tcbs or not tcbs.routes then
- minetest.chat_send_player(pname, "Hledání cesty: Zde neexistují hranice úseků ani cesty!")
+ minetest.chat_send_player(pname, "Smartroute: TCBS or routes don't exist here!")
return
elseif not tcbs.ts_id then
- minetest.chat_send_player(pname, "Hledání cesty: Kupředu není žádný úsek!")
+ minetest.chat_send_player(pname, "Smartroute: No track section directly ahead!")
return
end
-- Step 1: search for routes using the current settings
@@ -155,14 +158,22 @@ function sr.propose_next(pname, sigd, find_more_than, searching_shunt)
found_routes = found_routes
}
-- step 3: build form
- local form = "size[5,5]label[0,0;Hledání cesty: "..#found_routes.." cest nalezeno]"
+ local form = "size[8,5]label[0,0;Route search: "..#found_routes.." found]"
local tab = {}
for idx, froute in ipairs(found_routes) do
- tab[idx] = minetest.formspec_escape(froute.name.." (Délka="..#froute.tcbseq..")")
+ local secfl = table.copy(froute.secseq)
+ table.remove(secfl, 1) -- remove first and last, because it will always be the same
+ secfl[#secfl]=nil
+ local viatext = ""
+ if next(secfl) then
+ froute.via = table.concat(secfl, ", ")
+ viatext = " (via "..froute.via..")"
+ end
+ tab[idx] = minetest.formspec_escape(froute.name..viatext)
end
- form=form.."textlist[0.5,1;4,3;rtelist;"..table.concat(tab, ",").."]"
- form=form.."button[0.5,4;2,1;continue;Hledat dál]"
- form=form.."button[2.5,4;2,1;apply;Použít]"
+ form=form.."textlist[0.5,1;7,3;rtelist;"..table.concat(tab, ",").."]"
+ form=form.."button[0.5,4;2,1;continue;Search further]"
+ form=form.."button[2.5,4;2,1;apply;Apply]"
minetest.show_formspec(pname, "at_il_smartroute_propose", form)
end
@@ -207,11 +218,19 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
local new_frte = {}
+ local endOnce = {}
+ local endTwice = {}
for _,froute in ipairs(found_routes) do
local endpoint = froute.tcbseq[#froute.tcbseq]
local endstr = advtrains.interlocking.sigd_to_string(endpoint)
if not ex_endpts[endstr] then
new_frte[#new_frte+1] = froute
+ -- record duplicate targets in froute
+ if endOnce[froute.name] then
+ endTwice[froute.name] = true
+ else
+ endOnce[froute.name] = true
+ end
else
--atdebug("(Smartroute) Throwing away",froute.name,"because endpoint",endstr,"already reached by route",ex_endpts[endstr])
end
@@ -220,6 +239,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- All remaining routes will be applied to the signal
local sel_rte = #tcbs.routes+1
for idx, froute in ipairs(new_frte) do
+ if endTwice[froute.name] then
+ -- append via text to deduplicate name
+ froute.name = froute.name .. " (via "..(froute.via or "direct")..")"
+ end
tcbs.routes[#tcbs.routes+1] = build_route_from_foundroute(froute)
end
-- if only one route present and it is newly created (there was no route before, thus sel_rte==1), make default
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index a3c4fba..0be943a 100644
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -30,7 +30,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
},
mesh = "at_il_tcb_node.obj",
tiles = {"at_il_tcb_node.png"},
- description=attrans("Track Circuit Break"),
+ description="Track Circuit Break",
sunlight_propagates=true,
groups = {
cracky=3,
@@ -40,12 +40,12 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
},
after_place_node = function(pos, node, player)
local meta = minetest.get_meta(pos)
- meta:set_string("infotext", attrans("Unconfigured Track Circuit Break, right-click to assign."))
+ meta:set_string("infotext", "Unconfigured Track Circuit Break, right-click to assign.")
end,
on_rightclick = function(pos, node, player)
local pname = player:get_player_name()
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
@@ -57,11 +57,11 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
if tcb then
advtrains.interlocking.show_tcb_form(tcbpos, pname)
else
- minetest.chat_send_player(pname, attrans("This TCB has been removed. Please dig marker."))
+ minetest.chat_send_player(pname, "This TCB has been removed. Please dig marker.")
end
else
--unconfigured
- minetest.chat_send_player(pname, attrans("Configuring TCB: Please punch the rail you want to assign this TCB to."))
+ minetest.chat_send_player(pname, "Configuring TCB: Please punch the rail you want to assign this TCB to.")
players_assign_tcb[pname] = pos
end
@@ -85,7 +85,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
local tcbpts = meta:get_string("tcb_pos")
if tcbpts ~= "" then
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local tcbpos = minetest.string_to_pos(tcbpts)
@@ -93,7 +93,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
if not tcb then return true end
for connid=1,2 do
if tcb[connid].signal then
- minetest.chat_send_player(pname, attrans("Can't remove TCB: Both sides must have no signal assigned!"))
+ minetest.chat_send_player(pname, "Can't remove TCB: Both sides must have no signal assigned!")
return false
end
end
@@ -162,21 +162,21 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if node_ok and #conns == 2 then
-- if there is already a tcb here, reassign it
if ildb.get_tcb(pos) then
- minetest.chat_send_player(pname, attrans("Configuring TCB: Already existed at this position, it is now linked to this TCB marker"))
+ minetest.chat_send_player(pname, "Configuring TCB: Already existed at this position, it is now linked to this TCB marker")
else
ildb.create_tcb_at(pos, pname)
end
local meta = minetest.get_meta(tcbnpos)
meta:set_string("tcb_pos", minetest.pos_to_string(pos))
- meta:set_string("infotext", attrans("TCB assigned to @1", minetest.pos_to_string(pos)))
- minetest.chat_send_player(pname, attrans("Configuring TCB: Successfully configured TCB"))
+ meta:set_string("infotext", "TCB assigned to "..minetest.pos_to_string(pos))
+ minetest.chat_send_player(pname, "Configuring TCB: Successfully configured TCB")
advtrains.interlocking.show_tcb_marker(pos)
else
minetest.chat_send_player(pname, "Configuring TCB: This is not a normal two-connection rail! Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.")
end
players_assign_tcb[pname] = nil
end
@@ -194,19 +194,19 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
ildb.assign_signal_to_tcbs(pos, sigd)
-- use auto-naming
advtrains.interlocking.add_autoname_to_tcbs(tcbs, pname)
- minetest.chat_send_player(pname, "Konfigurace TCB: Návěstidlo úspěšně přiřazeno.")
+ minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.")
advtrains.interlocking.show_ip_form(pos, pname, true)
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Internal error, TCBS doesn't exist. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Cannot use static signals for routesetting. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Cannot use static signals for routesetting. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Not a compatible signal. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Not a compatible signal. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.")
end
players_assign_signal[pname] = nil
end
@@ -222,11 +222,11 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
minetest.chat_send_player(pname, minetest.pos_to_string(pos).." locks in state "..state)
ts.fixed_locks[pts] = state
else
- minetest.chat_send_player(pname, "Chyba: traťová sekce se změnila, ruším operaci!")
+ minetest.chat_send_player(pname, "Error: TS modified, abort!")
players_assign_fixedlocks[pname] = nil
end
else
- minetest.chat_send_player(pname, "Ruční přidání zámků dokončeno!")
+ minetest.chat_send_player(pname, "Setting fixed locks finished!")
players_assign_fixedlocks[pname] = nil
ildb.update_rs_cache(ts_id)
advtrains.interlocking.show_ts_form(ts_id, pname)
@@ -247,12 +247,12 @@ function advtrains.interlocking.self_tcb_make_after_place_callback(fail_silently
local pname = player:get_player_name()
if not minetest.check_player_privs(pname, "interlocking") then
if not fail_silently_on_noprivs then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
end
return
end
if ildb.get_tcb(pos) then
- minetest.chat_send_player(pname, attrans("TCB already existed at this position, now linked to this node"))
+ minetest.chat_send_player(pname, "TCB already existed at this position, now linked to this node")
else
ildb.create_tcb_at(pos, pname)
end
@@ -261,7 +261,7 @@ function advtrains.interlocking.self_tcb_make_after_place_callback(fail_silently
local tcbs = ildb.get_tcbs(sigd)
-- make sure signal doesn't already exist
if tcbs.signal then
- minetest.chat_send_player(pname, attrans("Signal on B side already assigned!"))
+ minetest.chat_send_player(pname, "Signal on B side already assigned!")
return
end
ildb.assign_signal_to_tcbs(pos, sigd)
@@ -281,7 +281,7 @@ function advtrains.interlocking.self_tcb_make_can_dig_callback(is_signal)
local pname = player and player:get_player_name() or ""
-- need to duplicate logic of the regular "can_dig_or_modify_track()" function in core/tracks.lua
if advtrains.get_train_at_pos(pos) then
- minetest.chat_send_player(pname, attrans("Can't remove track, a train is here!"))
+ minetest.chat_send_player(pname, "Can't remove track, a train is here!")
return false
end
-- end of standard checks
@@ -371,17 +371,10 @@ end
-- TCB Form
-local sidecolorA = minetest.get_color_escape_sequence("#f40000")
-local sidecolorB = minetest.get_color_escape_sequence("#068b00")
-
local function mktcbformspec(pos, side, tcbs, offset, pname)
local form = ""
- local btncolor, btnpref, ts
- if side == 1 then
- btncolor, btnpref = sidecolorA, "A"
- else
- btncolor, btnpref = sidecolorB, "B"
- end
+ local btnpref = side==1 and "A" or "B"
+ local ts
-- ensure that mapping and xlink are up to date
ildb.tcbs_ensure_ts_ref_exists({p=pos, s=side, tcbs=tcbs})
ildb.validate_tcb_xlink({p=pos, s=side, tcbs=tcbs})
@@ -390,12 +383,12 @@ local function mktcbformspec(pos, side, tcbs, offset, pname)
ts = ildb.get_ts(tcbs.ts_id)
end
if ts then
- form = form.."label[0.5,"..offset..";"..btncolor..attrans("Side "..btnpref)..": "..minetest.formspec_escape(ts.name or tcbs.ts_id).."]"
- form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;"..attrans("Show track section").."]"
+ form = form.."label[0.5,"..offset..";Side "..btnpref..": "..minetest.formspec_escape(ts.name or tcbs.ts_id).."]"
+ form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;Show track section]"
else
tcbs.ts_id = nil
- form = form.."label[0.5,"..offset..";"..btncolor..attrans("Side "..btnpref)..": "..attrans("End of interlocking").."]"
- form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_makeil;"..attrans("Create Interlocked Track Section").."]"
+ form = form.."label[0.5,"..offset..";Side "..btnpref..": ".."End of interlocking]"
+ form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_makeil;Create Interlocked Track Section]"
end
-- xlink
if tcbs.xlink then
@@ -403,17 +396,17 @@ local function mktcbformspec(pos, side, tcbs, offset, pname)
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkdel;X]"
else
if players_assign_xlink[pname] then
- form = form.."button[0.5,"..(offset+1.5)..";4,1;"..btnpref.."_xlinklink;"..attrans("Link @1", ildb.sigd_to_string(players_assign_xlink[pname])).."]"
+ form = form.."button[0.5,"..(offset+1.5)..";4,1;"..btnpref.."_xlinklink;Link "..ildb.sigd_to_string(players_assign_xlink[pname]).."]"
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkabrt;X]"
else
- form = form.."label[0.5,"..(offset+1.5)..";"..attrans("No Link").."]"
+ form = form.."label[0.5,"..(offset+1.5)..";No Link]"
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkadd;+]"
end
end
if tcbs.signal then
- form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_sigdia;"..attrans("Signalling").."]"
+ form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_sigdia;Signalling]"
else
- form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_asnsig;"..attrans("Assign a signal").."]"
+ form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_asnsig;Assign a signal]"
end
return form
end
@@ -421,13 +414,13 @@ end
function advtrains.interlocking.show_tcb_form(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local tcb = ildb.get_tcb(pos)
if not tcb then return end
- local form = "size[6,9] label[0.5,0.5;"..attrans("Track Circuit Break Configuration").."]"
+ local form = "size[6,9] label[0.5,0.5;Track Circuit Break Configuration]"
form = form .. mktcbformspec(pos, 1, tcb[1], 1, pname)
form = form .. mktcbformspec(pos, 2, tcb[2], 5, pname)
@@ -494,14 +487,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
else
if f_xlinkadd[connid] then
players_assign_xlink[pname] = {p=pos, s=connid}
- minetest.chat_send_player(pname, attrans("TCB Link: Select linked TCB now!"))
+ minetest.chat_send_player(pname, "TCB Link: Select linked TCB now!")
minetest.close_formspec(pname, formname)
return -- to not reopen form
end
end
end
if f_asnsig[connid] and not tcbs.signal then
- minetest.chat_send_player(pname, attrans("Configuring TCB: Please punch the signal to assign."))
+ minetest.chat_send_player(pname, "Configuring TCB: Please punch the signal to assign.")
players_assign_signal[pname] = {p=pos, s=connid}
minetest.close_formspec(pname, formname)
return
@@ -523,15 +516,15 @@ end)
function advtrains.interlocking.show_ts_form(ts_id, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local ts = ildb.get_ts(ts_id)
if not ts_id then return end
- local form = "size[10,10]label[0.5,0.5;"..attrans("Track Section Detail - @1", ts_id).."]"
- form = form.."field[0.8,2;5.2,1;name;"..attrans("Section name")..";"..minetest.formspec_escape(ts.name or "").."]"
- form = form.."button[5.5,1.7;1,1;setname;"..attrans("Set").."]"
+ local form = "size[10.5,10]label[0.5,0.5;Track Section Detail - "..ts_id.."]"
+ form = form.."field[0.8,2;5.2,1;name;Section name;"..minetest.formspec_escape(ts.name or "").."]"
+ form = form.."button[5.5,1.7;1,1;setname;Set]"
local hint
local strtab = {}
@@ -540,7 +533,7 @@ function advtrains.interlocking.show_ts_form(ts_id, pname)
advtrains.interlocking.show_tcb_marker(sigd.p)
end
- form = form.."label[0.5,2.5;"..attrans("Boundary TCBs")..":]"
+ form = form.."label[0.5,2.5;Boundary TCBs:]"
form = form.."textlist[0.5,3;4,3;tcblist;"..table.concat(strtab, ",").."]"
-- additional route locks (e.g. for level crossings)
@@ -552,36 +545,36 @@ function advtrains.interlocking.show_ts_form(ts_id, pname)
minetest.pos_to_string(advtrains.decode_pos(pts)).." = "..state)
end
end
- form = form.."label[5.5,2.5;"..attrans("Fixed route locks (e.g. level crossings)")..":]"
+ form = form.."label[5.5,2.5;Fixed route locks (e.g. level crossings):]"
form = form.."textlist[5.5,3;4,3;fixedlocks;"..table.concat(strtab, ",").."]"
if ildb.may_modify_ts(ts) then
- form = form.."button[5.5,6;2,1;flk_add;"..attrans("Add locks").."]"
- form = form.."button[7.5,6;2,1;flk_clear;"..attrans("Clear locks").."]"
+ form = form.."button[5.5,6;2,1;flk_add;Add locks]"
+ form = form.."button[7.5,6;2,1;flk_clear;Clear locks]"
- form = form.."button[5.5,8;4,1;remove;"..attrans("Remove Section").."]"
- form = form.."tooltip[remove;"..attrans("This will remove the track section and set all its end points to End Of Interlocking").."]"
+ form = form.."button[5.5,8;4,1;remove;Remove Section]"
+ form = form.."tooltip[remove;This will remove the track section and set all its end points to End Of Interlocking]"
else
hint=3
end
if ts.route then
- form = form.."label[0.5,6.1;"..attrans("Route is set: @1", ts.route.rsn).."]"
+ form = form.."label[0.5,6.1;Route is set: "..ts.route.rsn.."]"
elseif ts.route_post then
- form = form.."label[0.5,6.1;"..attrans("Section holds @1 route locks.", #(ts.route_post.lcks or {})).."]"
+ form = form.."label[0.5,6.1;Section holds "..#(ts.route_post.lcks or {}).." route locks.]"
end
-- occupying trains
if ts.trains and #ts.trains>0 then
- form = form.."label[0.5,7.1;"..attrans("Trains on this section:").."]"
+ form = form.."label[0.5,7.1;Trains on this section:]"
form = form.."textlist[0.5,7.7;3,2;trnlist;"..table.concat(ts.trains, ",").."]"
else
- form = form.."label[0.5,7.1;"..attrans("No trains on this section.").."]"
+ form = form.."label[0.5,7.1;No trains on this section.]"
end
- form = form.."button[5.5,7;4,1;reset;"..attrans("Reset section state").."]"
+ form = form.."button[5.5,7;4,1;reset;Reset section state]"
if hint == 3 then
- form = form.."label[0.5,0.75;"..attrans("You cannot modify track sections when a route is set or a train is on the section.").."]"
+ form = form.."label[0.5,0.75;You cannot modify track sections when a route is set or a train is on the section.]"
--form = form.."label[0.5,1;Trying to unlink a TCB directly connected to this track will not work.]"
end
@@ -622,7 +615,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
ts.fixed_locks = {}
end
players_assign_fixedlocks[pname] = ts_id
- minetest.chat_send_player(pname, attrans("Punch components to add fixed locks. (punch anything else = end)"))
+ minetest.chat_send_player(pname, "Punch components to add fixed locks. (punch anything else = end)")
minetest.close_formspec(pname, formname)
return
elseif fields.flk_clear then
@@ -632,15 +625,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.reset then
-- User requested resetting the section
-- Show him what this means...
- local form = "size[7,5]label[0.5,0.5;"..attrans("Reset track section").."]"
- form = form.."label[0.5,1;"..attrans("This will clear the list of trains\nand the routesetting status of this section.\nAre you sure?").."]"
- form = form.."button_exit[0.5,2.5; 5,1;reset;"..attrans("Yes").."]"
- form = form.."button_exit[0.5,3.5; 5,1;cancel;"..attrans("Cancel").."]"
+ local form = "size[7,5]label[0.5,0.5;Reset track section]"
+ form = form.."label[0.5,1;This will clear the list of trains\nand the routesetting status of this section.\nAre you sure?]"
+ form = form.."button_exit[0.5,2.5; 5,1;reset;Yes]"
+ form = form.."button_exit[0.5,3.5; 5,1;cancel;Cancel]"
minetest.show_formspec(pname, "at_il_tsreset_"..ts_id, form)
return
end
- advtrains.interlocking.show_ts_form(ts_id, pname)
+ advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
return
end
@@ -658,7 +651,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local tcbs = ildb.get_tcbs(sigd)
advtrains.interlocking.signal.update_route_aspect(tcbs)
end
- minetest.chat_send_player(pname, attrans("Reset track section @1!", ts_id))
+ minetest.chat_send_player(pname, "Reset track section "..ts_id.."!")
end
end)
@@ -668,14 +661,11 @@ end)
local markerent = {}
minetest.register_entity("advtrains_interlocking:tcbmarker", {
- initial_properties = {
- visual = "mesh",
- mesh = "trackplane.b3d",
- textures = {"at_il_tcb_marker.png"},
- collisionbox = {-1,-0.5,-1, 1,-0.4,1},
- visual_size = {x=10, y=10},
- static_save = false,
- },
+ visual = "mesh",
+ mesh = "trackplane.b3d",
+ textures = {"at_il_tcb_marker.png"},
+ collisionbox = {-1,-0.5,-1, 1,-0.4,1},
+ visual_size = {x=10, y=10},
on_punch = function(self)
self.object:remove()
end,
@@ -686,6 +676,7 @@ minetest.register_entity("advtrains_interlocking:tcbmarker", {
end,
get_staticdata = function() return "STATIC" end,
on_activate = function(self, sdata) if sdata=="STATIC" then self.object:remove() end end,
+ static_save = false,
})
function advtrains.interlocking.remove_tcb_marker_pts(pts)
@@ -713,7 +704,7 @@ function advtrains.interlocking.show_tcb_marker(pos)
if ts then
itex[connid] = ts.name or tcbs.ts_id or "???"
else
- itex[connid] = "--kon.zab.ob.--"
+ itex[connid] = "--EOI--"
end
end
@@ -773,11 +764,11 @@ function advtrains.interlocking.check_route_valid(route, sigd)
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- return false, attrans("No TCBS at @1", sigd_to_string(c_sigd))
+ return false, "No TCBS at "..sigd_to_string(c_sigd)
end
c_ts_id = c_tcbs.ts_id
if not c_ts_id then
- return false, attrans("No track section adjacent to @1", sigd_to_string(c_sigd))
+ return false, "No track section adjacent to "..sigd_to_string(c_sigd)
end
c_ts = ildb.get_ts(c_ts_id)
@@ -787,7 +778,7 @@ function advtrains.interlocking.check_route_valid(route, sigd)
for pts, state in pairs(c_rseg.locks) do
local pos = advtrains.decode_pos(pts)
if not advtrains.is_passive(pos) then
- return false, attrans("No passive component for lock at @1", pts)
+ return false, "No passive component for lock at "..pts
end
end
end
@@ -796,7 +787,7 @@ function advtrains.interlocking.check_route_valid(route, sigd)
if nvar then
local re_tcbs = ildb.get_tcbs({p = nvar.p, s = (nvar.s==1) and 2 or 1})
if not re_tcbs or not re_tcbs.ts_id or re_tcbs.ts_id~=c_ts_id then
- return false, attrans("TCB at @1 has different section than previous TCB.", minetest.pos_to_string(nvar.p))
+ return false, "TCB at "..minetest.pos_to_string(nvar.p).." has different section than previous TCB."
end
end
-- advance
@@ -805,11 +796,11 @@ function advtrains.interlocking.check_route_valid(route, sigd)
end
-- check end TCB
if not c_sigd then
- return false, attrans("Final TCBS unset (legacy-style buffer route)")
+ return false, "Final TCBS unset (legacy-style buffer route)"
end
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- return false, attrans("Final TCBS missing at @1", sigd_to_string(c_sigd))
+ return false, "Final TCBS missing at "..sigd_to_string(c_sigd)
end
return true, nil, c_sigd
end
@@ -823,7 +814,7 @@ local p_open_sig_form = {}
function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, called_from_form_update)
if not minetest.check_player_privs(pname, "train_operator") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local hasprivs = minetest.check_player_privs(pname, "interlocking")
@@ -831,38 +822,52 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
if not tcbs.signal then return end
if not tcbs.routes then tcbs.routes = {} end
- if not tcbs.signal_name then tcbs.signal_name = minetest.pos_to_string(sigd.p) end
-
- local form = "size[7,10]label[0.5,0.5;"..attrans("Signal at @1", minetest.pos_to_string(sigd.p)).."]"
- form = form.."field[0.8,1.5;5.2,1;name;"..attrans("Signal name")..";"..minetest.formspec_escape(tcbs.signal_name).."]"
- form = form.."button[5.5,1.2;1,1;setname;"..attrans("Set").."]"
+
+ local form = "size[7,10.25]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
+ form = form.."field[0.8,1.5;5.2,1;name;Signal name;"..minetest.formspec_escape(tcbs.signal_name or "").."]"
+ 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;"..attrans("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;"..attrans("Route has been set.").."]"
+ form = form.."label[0.5,3.5;Route has been set.]"
else
- form = form.."label[0.5,3.5;"..attrans("Waiting for route to be set...").."]"
+ form = form.."label[0.5,3.5;Waiting for route to be set...]"
if tcbs.route_rsn then
form = form.."label[0.5,4;"..minetest.formspec_escape(tcbs.route_rsn).."]"
end
end
if not tcbs.route_auto then
- form = form.."button[0.5,7; 5,1;auto;"..attrans("Enable Automatic Working").."]"
+ form = form.."button[0.5,7; 5,1;auto;Enable Automatic Working]"
else
- form = form.."label[0.5,7 ;"..attrans("Automatic Working is active.").."]"
- form = form.."label[0.5,7.3;"..attrans("Route is re-set when a train passed.").."]"
- form = form.."button[0.5,7.7; 5,1;noauto;"..attrans("Disable Automatic Working").."]"
+ form = form.."label[0.5,7 ;Automatic Working is active.]"
+ form = form.."label[0.5,7.3;Route is re-set when a train passed.]"
+ form = form.."button[0.5,7.7; 5,1;noauto;Disable Automatic Working]"
end
- form = form.."button[0.5,6; 5,1;cancelroute;"..attrans("Cancel Route").."]"
+ form = form.."button[0.5,6; 5,1;cancelroute;Cancel Route]"
else
if not tcbs.route_origin then
if #tcbs.routes > 0 then
@@ -883,35 +888,35 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
end
strtab[#strtab+1] = clr .. minetest.formspec_escape(rname)
end
- form = form.."label[0.5,2.5;"..attrans("Routes:").."]"
+ form = form.."label[0.5,2.5;Routes:]"
form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",")
if sel_rte then
form = form .. ";" .. sel_rte .."]"
- form = form.."button[0.5,6; 5,1;setroute;"..attrans("Set Route").."]"
- form = form.."button[0.5,7;2,1;dsproute;"..attrans("Show").."]"
+ form = form.."button[0.5,6; 5,1;setroute;Set Route]"
+ form = form.."button[0.5,7;2,1;dsproute;Show]"
if hasprivs then
- form = form.."button[5.5,3.3;1,0.3;setarsdefault;Vých]tooltip[setarsdefault;"..attrans("Set ARS default route").."]"
- form = form.."button[3.5,7;2,1;editroute;"..attrans("Edit").."]"
+ form = form.."button[5.5,3.3;1,0.3;setarsdefault;D]tooltip[setarsdefault;Set ARS default route]"
+ form = form.."button[3.5,7;2,1;editroute;Edit]"
if sel_rte > 1 then
form = form .. "button[5.5,4;1,0.3;moveup;↑]"
end
if sel_rte < #strtab then
form = form .. "button[5.5,4.7;1,0.3;movedown;↓]"
end
- form = form.."button[5.5,5.4;1,0.3;delroute;X]tooltip[delroute;"..attrans("Delete this route").."]"
+ form = form.."button[5.5,5.4;1,0.3;delroute;X]tooltip[delroute;Delete this route]"
end
else
form = form .. "]"
if tcbs.ars_disabled then
- form = form.."label[0.5,6 ;"..attrans("NOTE: ARS is disabled.").."]"
- form = form.."label[0.5,6.5;"..attrans("Routes are not automatically set.").."]"
+ form = form.."label[0.5,6 ;NOTE: ARS is disabled.]"
+ form = form.."label[0.5,6.5;Routes are not automatically set.]"
end
end
if hasprivs then
- form = form.."button[0.5,8;2.5,1;smartroute;"..attrans("Smart Route").."]"
- form = form.."button[ 3,8;2.5,1;newroute;"..attrans("New (Manual)").."]"
- form = form..string.format("checkbox[0.5,8.75;ars;"..attrans("Automatic routesetting")..";%s]", not tcbs.ars_disabled)
- form = form..string.format("checkbox[0.5,9.25;dstarstrig;"..attrans("Distant signal triggers ARS")..";%s]", not tcbs.no_dst_ars_trig)
+ form = form.."button[0.5,8;2.5,1;smartroute;Smart Route]"
+ form = form.."button[ 3,8;2.5,1;newroute;New (Manual)]"
+ form = form..string.format("checkbox[0.5,8.75;ars;Automatic routesetting;%s]", not tcbs.ars_disabled)
+ form = form..string.format("checkbox[0.5,9.25;dstarstrig;Distant signal triggers ARS;%s]", not tcbs.no_dst_ars_trig)
end
else
-- no route is active, and no route is so far defined
@@ -919,29 +924,29 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
local caps = advtrains.interlocking.signal.get_signal_cap_level(tcbs.signal)
if caps >= 4 then
-- offer user the "block signal mode"
- form = form.."label[0.5,2.5;"..attrans("No routes are yet defined.").."]"
+ form = form.."label[0.5,2.5;No routes are yet defined.]"
if hasprivs then
- form = form.."button[0.5,4;2.5,1;smartroute;"..attrans("Smart Route").."]"
- form = form.."button[ 3,4;2.5,1;newroute;"..attrans("New (Manual)").."]"
+ form = form.."button[0.5,4;2.5,1;smartroute;Smart Route]"
+ form = form.."button[ 3,4;2.5,1;newroute;New (Manual)]"
end
elseif caps >= 3 then
-- it's a buffer!
- form = form.."label[0.5,2.5;Tento signál vždy ukazuje červenou.\n"
- .."Vlakové cesty odsud nemohou být nastaveny.]"
+ form = form.."label[0.5,2.5;This is an always-halt signal (e.g. a buffer)\n"
+ .."No routes can be set from here.]"
else
-- signal caps say it cannot be route start/end
- form = form.."label[0.5,2.5;Toto je vzdálená předzvěst.\n"
- .."Aktuálně tudy není nastavena vlaková cesta.]"
+ form = form.."label[0.5,2.5;This is a pure distant signal\n"
+ .."No route is currently set through.]"
end
end
elseif sigd_equal(tcbs.route_origin, sigd) then
-- something has gone wrong: tcbs.routeset should have been set...
- form = form.."label[0.5,2.5;"..attrans("Inconsistent state: route_origin is same TCBS but no route set. Try again.").."]"
+ form = form.."label[0.5,2.5;Inconsistent state: route_origin is same TCBS but no route set. Try again.]"
ilrs.cancel_route_from(sigd)
else
- form = form.."label[0.5,2.5;"..attrans("Route is set over this signal by:").."\n"..sigd_to_string(tcbs.route_origin).."]"
- form = form.."label[0.5,4;"..attrans("Wait for this route to be cancelled in order to do anything here.").."]"
+ form = form.."label[0.5,2.5;Route is set over this signal by:\n"..sigd_to_string(tcbs.route_origin).."]"
+ form = form.."label[0.5,4;Wait for this route to be cancelled in order to do anything here.]"
end
end
sig_pselidx[pname] = sel_rte
@@ -1010,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
@@ -1035,7 +1038,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.dsproute then
local t = os.clock()
advtrains.interlocking.visualize_route(sigd, tcbs.routes[sel_rte], "disp_"..t)
- minetest.after(60, function() advtrains.interlocking.clear_visu_context("disp_"..t) end)
+ minetest.after(10, function() advtrains.interlocking.clear_visu_context("disp_"..t) end)
end
if fields.editroute and hasprivs then
advtrains.interlocking.show_route_edit_form(pname, sigd, sel_rte)
@@ -1064,7 +1067,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
if fields.delroute and hasprivs then
if tcbs.routes[sel_rte] and tcbs.routes[sel_rte].ars then
- minetest.chat_send_player(pname, attrans("Cannot delete route which has ARS rules, please review and then delete through edit dialog!"))
+ minetest.chat_send_player(pname, "Cannot delete route which has ARS rules, please review and then delete through edit dialog!")
else
table.remove(tcbs.routes,sel_rte)
end
@@ -1074,13 +1077,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.ars then
tcbs.ars_disabled = not minetest.is_yes(fields.ars)
- local action
- if tcbs.ars_disabled then
- action = "disabled"
- else
- action = "enabled"
- end
- core.log("action", pname.." "..action.." ARS at "..pts)
end
if fields.dstarstrig then
diff --git a/advtrains_interlocking/tool.lua b/advtrains_interlocking/tool.lua
index c8f8521..5ceae04 100644
--- a/advtrains_interlocking/tool.lua
+++ b/advtrains_interlocking/tool.lua
@@ -5,17 +5,17 @@ local ilrs = advtrains.interlocking.route
local function node_right_click(pos, pname, player)
if advtrains.is_passive(pos) then
- local form = "size[7,5]label[0.5,0.5;Průzkumník zámků]"
+ local form = "size[7,5]label[0.5,0.5;Route lock inspector]"
local pts = advtrains.encode_pos(pos)
local rtl = ilrs.has_route_lock(pts)
if rtl then
- form = form.."label[0.5,1;Právě uzamčeno:\n"..rtl.."]"
- form = form.."button_exit[0.5,3.5; 5,1;clear;Odemknout vše]"
+ form = form.."label[0.5,1;Route locks currently put:\n"..rtl.."]"
+ form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]"
else
- form = form.."label[0.5,1;Nic není uzamčeno]"
- form = form.."button_exit[0.5,3.5; 5,1;emplace;Uzamknout ručně]"
+ form = form.."label[0.5,1;No route locks set]"
+ form = form.."button_exit[0.5,3.5; 5,1;emplace;Emplace manual lock]"
end
minetest.show_formspec(pname, "at_il_rtool_"..pts, form)
@@ -25,7 +25,7 @@ local function node_right_click(pos, pname, player)
-- If not a turnout, check the track section and show a form
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
if not node_ok then
- minetest.chat_send_player(pname, "Tento blok není kolej!")
+ minetest.chat_send_player(pname, "Node is not a track!")
return
end
if advtrains.interlocking.db.get_tcb(pos) then
@@ -37,14 +37,14 @@ local function node_right_click(pos, pname, player)
if ts_id then
advtrains.interlocking.show_ts_form(ts_id, pname)
else
- minetest.chat_send_player(pname, "Zde není zabezpečený traťový úsek!")
+ minetest.chat_send_player(pname, "No track section at this location!")
end
end
local function node_left_click(pos, pname, player)
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
if not node_ok then
- minetest.chat_send_player(pname, "Tento blok není kolej!")
+ minetest.chat_send_player(pname, "Node is not a track!")
return
end
@@ -62,14 +62,13 @@ local function node_left_click(pos, pname, player)
advtrains.interlocking.db.update_rs_cache(ts_id)
advtrains.interlocking.highlight_track_section(pos)
else
- minetest.chat_send_player(pname, "Zde není zabezpečený traťový úsek!")
+ minetest.chat_send_player(pname, "No track section at this location!")
end
end
minetest.register_craftitem("advtrains_interlocking:tool",{
- description = "ovladač traťového zabezpečení",
- _ch_help = "levý klik: zvýraznit traťový úsek\npravý klik: prozkoumat/zkontrolovat zámky nebo zobrazit informace o traťovém úseku",
+ description = "Interlocking tool\nPunch: Highlight track section\nPlace: check route locks/show track section info",
groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
inventory_image = "at_il_tool.png",
wield_image = "at_il_tool.png",
@@ -80,7 +79,7 @@ minetest.register_craftitem("advtrains_interlocking:tool",{
return
end
if not minetest.check_player_privs(pname, {interlocking=true}) then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
if pointed_thing.type=="node" then
@@ -120,8 +119,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
ilrs.remove_route_locks(pts)
end
if fields.emplace then
- ilrs.add_manual_route_lock(pts, attrans("Manual lock (@1)", pname))
+ ilrs.add_manual_route_lock(pts, "Manual lock ("..pname..")")
end
end
end
end)
+
+minetest.register_craft({
+ output = "advtrains_interlocking:tool",
+ type = "shapeless",
+ recipe = {"dye:green","advtrains:trackworker", "advtrains_interlocking:tcb_node"}
+}) \ No newline at end of file