diff options
author | orwell <orwell@bleipb.de> | 2025-05-27 21:03:14 +0200 |
---|---|---|
committer | orwell <orwell@bleipb.de> | 2025-05-27 21:03:14 +0200 |
commit | 8506dd2825b715293138976a5ad1fa11a46206a7 (patch) | |
tree | 1f48c1dc03c3bbc6ed6762bd04d10e543a3a580c /advtrains_interlocking | |
parent | 2a9891577c1b00068cc4ec858c7dc6c5196f0a2b (diff) | |
parent | adc01a0bba29b40278e45c50caa954c435374f7b (diff) | |
download | advtrains-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.lua | 296 | ||||
-rw-r--r-- | advtrains_interlocking/database.lua | 10 | ||||
-rw-r--r-- | advtrains_interlocking/init.lua | 4 | ||||
-rw-r--r-- | advtrains_interlocking/route_prog.lua | 96 | ||||
-rw-r--r-- | advtrains_interlocking/route_ui.lua | 58 | ||||
-rw-r--r-- | advtrains_interlocking/routesetting.lua | 85 | ||||
-rw-r--r-- | advtrains_interlocking/signal_api.lua | 2 | ||||
-rw-r--r-- | advtrains_interlocking/signal_aspect_ui.lua | 42 | ||||
-rw-r--r-- | advtrains_interlocking/smartroute.lua | 41 | ||||
-rw-r--r-- | advtrains_interlocking/tcb_ts_ui.lua | 266 | ||||
-rw-r--r-- | advtrains_interlocking/tool.lua | 31 |
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 |