From 98c37108762c6d7c9f1d691b84f49bfa65b81b28 Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Sat, 11 Jun 2022 18:07:00 +0200 Subject: Implement primitive distant signaling --- advtrains_interlocking/distant_ui.lua | 76 +++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 advtrains_interlocking/distant_ui.lua (limited to 'advtrains_interlocking/distant_ui.lua') diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua new file mode 100644 index 0000000..4ec2255 --- /dev/null +++ b/advtrains_interlocking/distant_ui.lua @@ -0,0 +1,76 @@ +local F = advtrains.formspec +local D = advtrains.distant +local I = advtrains.interlocking + +function advtrains.interlocking.show_distant_signal_form(pos, pname) + local form = {"size[7,7]"} + form[#form+1] = advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 3) + local main, set_by = D.get_main(pos) + if main then + local pts_main = minetest.pos_to_string(main) + form[#form+1] = F.S_label(0.5, 0.5, "This signal is a distant signal of @1.", pts_main) + if set_by == "manual" then + form[#form+1] = F.S_label(0.5, 1, "The assignment is made manually.") + elseif set_by == "routesetting" then + form[#form+1] = F.S_label(0.5, 1, "The assignment is made by the routesetting system.") + end + else + form[#form+1] = F.S_label(0.5, 0.5, "This signal is not assigned to a main signal.") + form[#form+1] = F.S_label(0.5, 1, "The distant aspect of the signal is not used.") + end + if set_by ~= nil then + form[#form+1] = F.S_button_exit(0.5, 1.5, 3, 1, "unassign_dst", "Unassign") + form[#form+1] = F.S_button_exit(3.5, 1.5, 3, 1, "assign_dst", "Reassign") + else + form[#form+1] = F.S_button_exit(0.5, 1.5, 6, 1, "assign_dst", "Assign") + end + minetest.show_formspec(pname, "advtrains:distant_" .. minetest.pos_to_string(pos), table.concat(form)) +end + +local signal_pos = {} +local function init_signal_assignment(pname, pos) + if not minetest.check_player_privs(pname, "interlocking") then + minetest.chat_send_player(pname, attrans("This operation is not allowed without the @1 privilege.", "interlocking")) + return + end + signal_pos[pname] = pos + minetest.chat_send_player(pname, attrans("Please punch the signal to use as the main signal.")) +end + +minetest.register_on_punchnode(function(pos, node, player, pointed_thing) + local pname = player:get_player_name() + if not minetest.check_player_privs(pname, "interlocking") then + return + end + local spos = signal_pos[pname] + if not spos then + return + end + signal_pos[pname] = nil + local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2 + if not is_signal then + minetest.chat_send_player(pname, attrans("Incompatible signal.")) + return + end + minetest.chat_send_player(pname, attrans("Successfully assigned signal.")) + D.assign(pos, spos, "manual") +end) + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local pname = player:get_player_name() + local pos = minetest.string_to_pos(string.match(formname, "^advtrains:distant_(.+)$") or "") + if not pos then + return + end + if not minetest.check_player_privs(pname, "interlocking") then + return + end + if advtrains.interlocking.handle_signal_formspec_tabheader_fields(pname, fields) then + return true + end + if fields.unassign_dst then + D.unassign_dst(pos) + elseif fields.assign_dst then + init_signal_assignment(pname, pos) + end +end) -- cgit v1.2.3 From 34405b8431b7c758988b56cc09d21d6de74b727b Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Sat, 13 Aug 2022 21:16:15 +0200 Subject: Allow assigning distant signals from the main signal --- advtrains/formspec.lua | 27 +++++++++++++++++ advtrains_interlocking/distant_ui.lua | 55 +++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 2 deletions(-) (limited to 'advtrains_interlocking/distant_ui.lua') diff --git a/advtrains/formspec.lua b/advtrains/formspec.lua index 20dab59..58968da 100644 --- a/advtrains/formspec.lua +++ b/advtrains/formspec.lua @@ -32,6 +32,21 @@ local function f_dropdown(x, y, w, id, entries, sel, indexed) indexed and ";true" or "") end +local function f_image_button(x, y, w, h, texture, id, label, noclip, drawborder, pressed) + local st = {string.format("%f,%f;%f,%f;%s;%s;%s", x, y, w, h, fsescape(texture), fsescape(id), fsescape(label))} + if pressed then + st[#st+1] = tostring(noclip or false) + st[#st+1] = tostring(drawborder or false) + st[#st+1] = fsescape(pressed) + end + return sformat("image_button[%s]", table.concat(st, ";")) +end + +local function f_image_button_exit(x, y, w, h, texture, id, label) + local st = {string.format("%f,%f;%f,%f;%s;%s;%s", x, y, w, h, fsescape(texture), fsescape(id), fsescape(label))} + return sformat("image_button_exit[%s]", table.concat(st, ";")) +end + local function f_label(x, y, text) return sformat("label[%f,%f;%s]", x, y, fsescape(text)) end @@ -61,13 +76,25 @@ local function f_tabheader(x, y, w, h, id, entries, sel, transparent, border) return string.format("tabheader[%s]", table.concat(st, ";")) end +local function f_textlist(x, y, w, h, id, entries, sel, transparent) + local st = {string.format("%f,%f;%f,%f;%s;%s", x, y, w, h, id, make_list(entries))} + if sel then + st[#st+1] = tostring(sel) + st[#st+1] = tostring(transparent or false) + end + return string.format("textlist[%s]", table.concat(st, ";")) +end + return { button = f_button, S_button = S_button, button_exit = f_button_exit, S_button_exit = S_button_exit, dropdown = f_dropdown, + image_button = f_image_button, + image_button_exit = f_image_button_exit, label = f_label, S_label = S_label, tabheader = f_tabheader, + textlist = f_textlist, } diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua index 4ec2255..e1e14b7 100644 --- a/advtrains_interlocking/distant_ui.lua +++ b/advtrains_interlocking/distant_ui.lua @@ -24,6 +24,16 @@ function advtrains.interlocking.show_distant_signal_form(pos, pname) else form[#form+1] = F.S_button_exit(0.5, 1.5, 6, 1, "assign_dst", "Assign") end + + local dsts = D.get_dst(pos) + local dstlist = {} + for pos, _ in pairs(dsts) do + dstlist[#dstlist+1] = minetest.pos_to_string(advtrains.decode_pos(pos)) + end + form[#form+1] = F.S_label(0.5, 2.5, "This signal has the following distant signals:") + form[#form+1] = F.textlist(0.5, 3, 4.5, 3.5, "dstlist", dstlist) + form[#form+1] = F.image_button_exit(5.5, 3.5, 1, 1, "cdb_add.png", "dst_add", "") + form[#form+1] = F.image_button_exit(5.5, 5, 1, 1, "cdb_clear.png", "dst_del", "") minetest.show_formspec(pname, "advtrains:distant_" .. minetest.pos_to_string(pos), table.concat(form)) end @@ -37,25 +47,46 @@ local function init_signal_assignment(pname, pos) minetest.chat_send_player(pname, attrans("Please punch the signal to use as the main signal.")) end +local distant_pos = {} +local function init_distant_assignment(pname, pos) + if not minetest.check_player_privs(pname, "interlocking") then + minetest.send_chat_player(pname, attrans("This operation is now allowed without the @1 privilege.", "interlocking")) + return + end + distant_pos[pname] = pos + minetest.chat_send_player(pname, attrans("Please punch the signal to use as the distant signal.")) +end + minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local pname = player:get_player_name() if not minetest.check_player_privs(pname, "interlocking") then return end local spos = signal_pos[pname] + local distant = false if not spos then - return + spos = distant_pos[pname] + if not spos then + return + end + distant = true end signal_pos[pname] = nil + distant_pos[pname] = nil local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2 if not is_signal then minetest.chat_send_player(pname, attrans("Incompatible signal.")) return end minetest.chat_send_player(pname, attrans("Successfully assigned signal.")) - D.assign(pos, spos, "manual") + if distant then + D.assign(spos, pos, "manual") + else + D.assign(pos, spos, "manual") + end end) +local dstsel = {} minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() local pos = minetest.string_to_pos(string.match(formname, "^advtrains:distant_(.+)$") or "") @@ -72,5 +103,25 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) D.unassign_dst(pos) elseif fields.assign_dst then init_signal_assignment(pname, pos) + elseif fields.dst_add then + init_distant_assignment(pname, pos) + elseif fields.dstlist then + dstsel[pname] = minetest.explode_textlist_event(fields.dstlist).index + elseif fields.dst_del then + local selid = dstsel[pname] + if selid then + local dsts = D.get_dst(pos) + local pos + for p, _ in pairs(dsts) do + selid = selid-1 + if selid <= 0 then + pos = p + break + end + end + if pos then + D.unassign_dst(advtrains.decode_pos(pos)) + end + end end end) -- cgit v1.2.3 From 67efae9c9ad6f93aaa418d512c4ae1817eed6d24 Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Sun, 18 Dec 2022 11:01:26 +0100 Subject: Adjust signal aspect formspecs to be of similar size --- advtrains/formspec.lua | 10 +++++ advtrains_interlocking/distant_ui.lua | 8 ++-- advtrains_interlocking/signal_api.lua | 14 ++++--- advtrains_interlocking/signal_aspect_ui.lua | 57 +++++++++++++++-------------- 4 files changed, 53 insertions(+), 36 deletions(-) (limited to 'advtrains_interlocking/distant_ui.lua') diff --git a/advtrains/formspec.lua b/advtrains/formspec.lua index 58968da..743d3f3 100644 --- a/advtrains/formspec.lua +++ b/advtrains/formspec.lua @@ -17,6 +17,14 @@ local function S_button(x, y, w, h, id, ...) return f_button(x, y, w, h, id, attrans(...)) end +local function f_checkbox(x, y, name, selected, label) + return sformat("checkbox[%f,%f;%s;%s;%s]", x, y, name, label, selected and "true" or "false") +end + +local function S_checkbox(x, y, name, selected, ...) + return f_checkbox(x, y, name, selected, attrans(...)) +end + local function f_button_exit(x, y, w, h, id, text) return sformat("button_exit[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text) end @@ -88,6 +96,8 @@ end return { button = f_button, S_button = S_button, + checkbox = f_checkbox, + S_checkbox = S_checkbox, button_exit = f_button_exit, S_button_exit = S_button_exit, dropdown = f_dropdown, diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua index e1e14b7..a7ff406 100644 --- a/advtrains_interlocking/distant_ui.lua +++ b/advtrains_interlocking/distant_ui.lua @@ -3,7 +3,7 @@ local D = advtrains.distant local I = advtrains.interlocking function advtrains.interlocking.show_distant_signal_form(pos, pname) - local form = {"size[7,7]"} + local form = {"size[7,6.5]"} form[#form+1] = advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 3) local main, set_by = D.get_main(pos) if main then @@ -31,9 +31,9 @@ function advtrains.interlocking.show_distant_signal_form(pos, pname) dstlist[#dstlist+1] = minetest.pos_to_string(advtrains.decode_pos(pos)) end form[#form+1] = F.S_label(0.5, 2.5, "This signal has the following distant signals:") - form[#form+1] = F.textlist(0.5, 3, 4.5, 3.5, "dstlist", dstlist) - form[#form+1] = F.image_button_exit(5.5, 3.5, 1, 1, "cdb_add.png", "dst_add", "") - form[#form+1] = F.image_button_exit(5.5, 5, 1, 1, "cdb_clear.png", "dst_del", "") + form[#form+1] = F.textlist(0.5, 3, 4.5, 3, "dstlist", dstlist) + form[#form+1] = F.image_button_exit(5.5, 3.25, 1, 1, "cdb_add.png", "dst_add", "") + form[#form+1] = F.image_button_exit(5.5, 4.75, 1, 1, "cdb_clear.png", "dst_del", "") minetest.show_formspec(pname, "advtrains:distant_" .. minetest.pos_to_string(pos), table.concat(form)) end diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index 54202f0..8bb92bf 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -137,14 +137,18 @@ function advtrains.interlocking.show_ip_form(pos, pname, only_notset) if not minetest.check_player_privs(pname, "interlocking") then return end - local form = "size[7,5]label[0.5,0.5;Signal at "..minetest.pos_to_string(pos).."]" - form = form .. advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 2) + local form = "size[7,6.5]label[0.5,0.5;Signal at "..minetest.pos_to_string(pos).."]" + local node = advtrains.ndb.get_node(pos) + local ndef = minetest.registered_nodes[node.name] or {} + if ndef.advtrains and ndef.advtrains.set_aspect then + form = form .. advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 2) + end advtrains.interlocking.db.check_for_duplicate_ip(pos) local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos) if pts then form = form.."label[0.5,1.5;Influence point is set at "..pts.."/"..connid.."]" - form = form.."button_exit[0.5,2.5; 5,1;set;Move]" - form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]" + form = form.."button_exit[0.5,4.25; 6,1;set;Move]" + form = form.."button_exit[0.5,5.25; 6,1;clear;Clear]" local ipos = minetest.string_to_pos(pts) ipmarker(ipos, connid) else @@ -152,7 +156,7 @@ function advtrains.interlocking.show_ip_form(pos, pname, only_notset) form = form.."label[0.5,2.0;It is recommended to set an influence point.]" form = form.."label[0.5,2.5;This is the point where trains will obey the signal.]" - form = form.."button_exit[0.5,3.5; 5,1;set;Set]" + form = form.."button_exit[0.5,5.25; 6,1;set;Set]" end if not only_notset or not pts then minetest.show_formspec(pname, "at_il_ipassign_"..minetest.pos_to_string(pos), form) diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua index ccedb01..6de21e6 100644 --- a/advtrains_interlocking/signal_aspect_ui.lua +++ b/advtrains_interlocking/signal_aspect_ui.lua @@ -52,16 +52,8 @@ local function describe_supported_aspects_t1(suppasp, isasp) t.main_current = selid if suppasp.shunt == nil then - selid = 1 - if isasp and isasp.shunt then - selid = 2 - end - entries = { - describe_t1_shunt_aspect(false), - describe_t1_shunt_aspect(true), - } - t.shunt = entries - t.shunt_current = selid + t.shunt = true + t.shunt_current = isasp and isasp.shunt end entries = {} @@ -83,8 +75,12 @@ local signal_tabheader_map = {} local function make_signal_formspec_tabheader(pname, pos, width, selid) signal_tabheader_map[pname] = pos + local firstlabel = attrans("Signal aspect") + if advtrains.interlocking.db.get_sigd_for_signal(pos) then + firstlabel = attrans("Routesetting") + end local options = { - attrans("Signal aspect"), + firstlabel, attrans("Influence point"), attrans("Distant signalling"), } @@ -112,7 +108,7 @@ advtrains.interlocking.make_signal_formspec_tabheader = make_signal_formspec_tab advtrains.interlocking.handle_signal_formspec_tabheader_fields = handle_signal_formspec_tabheader_fields local function make_signal_aspect_selector_t1(suppasp, purpose, isasp) - local form = {"size[7,7.25]"} + local form = {"size[7,6.5]"} local t = describe_supported_aspects_t1(suppasp, isasp) if type(purpose) == "table" then form[#form+1] = make_signal_formspec_tabheader(purpose.pname, purpose.pos, 7, 1) @@ -124,22 +120,21 @@ local function make_signal_aspect_selector_t1(suppasp, purpose, isasp) form[#form+1] = F.S_label(0.5, 1.5, "Main aspect") form[#form+1] = F.dropdown(0.5, 2, 6, "main", t.main, t.main_current, true) - form[#form+1] = F.S_label(0.5, 3, "Shunt aspect") + form[#form+1] = F.S_label(0.5, 3, "Distant aspect") + form[#form+1] = F.dropdown(0.5, 3.5, 6, "dst", t.dst, t.dst_current, true) + if t.shunt then - form[#form+1] = F.dropdown(0.5, 3.5, 6, "shunt_free", t.shunt, t.shunt_current, true) + form[#form+1] = F.S_checkbox(0.5, 4.25, "shunt", t.shunt_current, "Allow shunting") else - form[#form+1] = F.S_label(0.5, 3.5, "The shunt aspect cannot be changed") + form[#form+1] = F.S_label(0.5, 4.5, "The shunt aspect cannot be changed.") end - form[#form+1] = F.S_label(0.5, 4.5, "Distant aspect") - form[#form+1] = F.dropdown(0.5, 5, 6, "dst", t.dst, t.dst_current, true) - - form[#form+1] = F.S_button_exit(0.5, 6, 6, 1, "save", "Save signal aspect") + form[#form+1] = F.S_button_exit(0.5, 5.25, 6, 1, "save", "Save signal aspect") return table.concat(form) end local function make_signal_aspect_selector_t2(suppasp, purpose, isasp) - local form = {"size[7,4]"} + local form = {"size[7,6.5]"} local def = advtrains.interlocking.aspects.get_type2_definition(suppasp.group) if not def then return nil @@ -159,8 +154,13 @@ local function make_signal_aspect_selector_t2(suppasp, purpose, isasp) end entries[idx] = spv.label end - form[#form+1] = F.dropdown(0.5, 1.5, 6, "asp", entries, selid, true) - form[#form+1] = F.S_button_exit(0.5, 2.5, 6, 1, "save", "Save signal aspect") + form[#form+1] = F.S_label(0.5, 1.5, "Signal group: @1", def.label) + form[#form+1] = F.dropdown(0.5, 2, 6, "asp", entries, selid, true) + form[#form+1] = F.S_label(0.5, 3, "Aspect in effect:") + form[#form+1] = F.label(0.5, 3.5, describe_t1_main_aspect(isasp.main)) + form[#form+1] = F.label(0.5, 4, describe_t1_distant_aspect(isasp.dst)) + form[#form+1] = F.label(0.5, 4.5, describe_t1_shunt_aspect(isasp.shunt)) + form[#form+1] = F.S_button_exit(0.5, 5.25, 6, 1, "save", "Save signal aspect") return table.concat(form) end @@ -205,7 +205,7 @@ local function usebool(sup, val, free) end end -local function get_aspect_from_formspec_t1(suppasp, fields) +local function get_aspect_from_formspec_t1(suppasp, fields, psl) local maini = tonumber(fields.main) if not maini then return end local dsti = tonumber(fields.dst) @@ -213,12 +213,12 @@ local function get_aspect_from_formspec_t1(suppasp, fields) return { main = suppasp.main[maini], dst = suppasp.dst[dsti], - shunt = usebool(suppasp.shunt, fields.shunt_free, "2"), + shunt = usebool(suppasp.shunt, psl.shunt, "true"), info = {}, } end -local function get_aspect_from_formspec_t2(suppasp, fields) +local function get_aspect_from_formspec_t2(suppasp, fields, psl) local asp = advtrains.interlocking.aspects.type2_to_type1(suppasp, tonumber(fields.asp)) return asp end @@ -232,12 +232,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if handle_signal_formspec_tabheader_fields(pname, fields) then return true end + if fields.shunt then + psl.shunt = fields.shunt + end if fields.save then local asp if suppasp.type == 2 then - asp = get_aspect_from_formspec_t2(suppasp, fields) + asp = get_aspect_from_formspec_t2(suppasp, fields, psl) else - asp = get_aspect_from_formspec_t1(suppasp, fields) + asp = get_aspect_from_formspec_t1(suppasp, fields, psl) end if asp then psl.callback(pname, asp) -- cgit v1.2.3 From 2d072cdc67ec3018eaba36b7c79c2b19e574a94d Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Fri, 6 Jan 2023 14:45:03 +0100 Subject: Rework formspecs; add description to JP signal group --- advtrains/formspec.lua | 47 +++--- advtrains_interlocking/distant_ui.lua | 76 ++++----- advtrains_interlocking/signal_api.lua | 75 +++++---- advtrains_interlocking/signal_aspect_ui.lua | 232 +++++++++++++++++----------- advtrains_interlocking/tcb_ts_ui.lua | 5 - advtrains_signals_japan/init.lua | 1 + 6 files changed, 252 insertions(+), 184 deletions(-) (limited to 'advtrains_interlocking/distant_ui.lua') diff --git a/advtrains/formspec.lua b/advtrains/formspec.lua index 743d3f3..8894354 100644 --- a/advtrains/formspec.lua +++ b/advtrains/formspec.lua @@ -9,32 +9,28 @@ local function make_list(entries) return table.concat(t, ",") end -local function f_button(x, y, w, h, id, text) - return sformat("button[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text) +local function S_wrapper(f, i0) + return function(...) + local args = {...} + args[i0] = attrans(unpack(args,i0)) + return f(unpack(args,1,i0)) + end end -local function S_button(x, y, w, h, id, ...) - return f_button(x, y, w, h, id, attrans(...)) +local function f_button(x, y, w, id, text) + return sformat("button[%f,%f;%f,0.75;%s;%s]", x, y, w, id, text) end local function f_checkbox(x, y, name, selected, label) - return sformat("checkbox[%f,%f;%s;%s;%s]", x, y, name, label, selected and "true" or "false") -end - -local function S_checkbox(x, y, name, selected, ...) - return f_checkbox(x, y, name, selected, attrans(...)) + return sformat("checkbox[%f,%f;%s;%s;%s]", x, y+0.25, name, label, selected and "true" or "false") end -local function f_button_exit(x, y, w, h, id, text) - return sformat("button_exit[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text) -end - -local function S_button_exit(x, y, w, h, id, ...) - return f_button_exit(x, y, w, h, id, attrans(...)) +local function f_button_exit(x, y, w, id, text) + return sformat("button_exit[%f,%f;%f,0.75;%s;%s]", x, y, w, id, text) end local function f_dropdown(x, y, w, id, entries, sel, indexed) - return sformat("dropdown[%f,%f;%f;%s;%s;%d%s]", + return sformat("dropdown[%f,%f;%f,0.75;%s;%s;%d%s]", x, y, w, id, make_list(entries), sel or 1, indexed and ";true" or "") @@ -56,11 +52,15 @@ local function f_image_button_exit(x, y, w, h, texture, id, label) end local function f_label(x, y, text) - return sformat("label[%f,%f;%s]", x, y, fsescape(text)) + return sformat("label[%f,%f;%s]", x, y+0.25, fsescape(text)) +end + +local function f_field_aux(x, y, w, id, default) + return sformat("field[%f,%f;%f,0.75;%s;;%s]", x, y, w, id, default) end -local function S_label(x, y, ...) - return f_label(x, y, attrans(...)) +local function f_field(x, y, w, id, label, default) + return f_label(x, y-0.5, label) .. f_field_aux(x, y, w, id, default) end local function f_tabheader(x, y, w, h, id, entries, sel, transparent, border) @@ -95,16 +95,17 @@ end return { button = f_button, - S_button = S_button, + S_button = S_wrapper(f_button, 5), checkbox = f_checkbox, - S_checkbox = S_checkbox, + S_checkbox = S_wrapper(f_checkbox, 5), button_exit = f_button_exit, - S_button_exit = S_button_exit, + S_button_exit = S_wrapper(f_button_exit, 5), dropdown = f_dropdown, + field = f_field, image_button = f_image_button, image_button_exit = f_image_button_exit, label = f_label, - S_label = S_label, + S_label = S_wrapper(f_label, 3), tabheader = f_tabheader, textlist = f_textlist, } diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua index a7ff406..0907684 100644 --- a/advtrains_interlocking/distant_ui.lua +++ b/advtrains_interlocking/distant_ui.lua @@ -2,39 +2,52 @@ local F = advtrains.formspec local D = advtrains.distant local I = advtrains.interlocking -function advtrains.interlocking.show_distant_signal_form(pos, pname) - local form = {"size[7,6.5]"} - form[#form+1] = advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 3) +function I.make_short_dst_formspec_component(pos, x, y, w) local main, set_by = D.get_main(pos) if main then local pts_main = minetest.pos_to_string(main) - form[#form+1] = F.S_label(0.5, 0.5, "This signal is a distant signal of @1.", pts_main) + local desc = attrans("The assignment is made with an unknown method.") if set_by == "manual" then - form[#form+1] = F.S_label(0.5, 1, "The assignment is made manually.") + desc = attrans("The assignment is made manually.") elseif set_by == "routesetting" then - form[#form+1] = F.S_label(0.5, 1, "The assignment is made by the routesetting system.") + desc = attrans("The assignment is made by the routesetting system.") end + return table.concat { + F.S_label(x, y, "This signal is a distant signal of @1.", pts_main), + F.label(x, y+0.5, desc), + F.S_button_exit(x, y+1, w/2-0.125, "dst_assign", "Reassign"), + F.S_button_exit(x+w/2+0.125, y+1, w/2-0.125, "dst_unassign", "Unassign"), + } else - form[#form+1] = F.S_label(0.5, 0.5, "This signal is not assigned to a main signal.") - form[#form+1] = F.S_label(0.5, 1, "The distant aspect of the signal is not used.") - end - if set_by ~= nil then - form[#form+1] = F.S_button_exit(0.5, 1.5, 3, 1, "unassign_dst", "Unassign") - form[#form+1] = F.S_button_exit(3.5, 1.5, 3, 1, "assign_dst", "Reassign") - else - form[#form+1] = F.S_button_exit(0.5, 1.5, 6, 1, "assign_dst", "Assign") + return table.concat { + F.S_label(x, y, "This signal is not assigned to a main signal."), + F.S_label(x, y+0.5, "The distant aspect of the signal is not used."), + F.S_button_exit(x, y+1, w, "dst_assign", "Assign") + } end +end - local dsts = D.get_dst(pos) +function I.make_dst_list_formspec_component(pos, x, y, w, h) + local ymid = y+0.25+h/2 local dstlist = {} - for pos, _ in pairs(dsts) do - dstlist[#dstlist+1] = minetest.pos_to_string(advtrains.decode_pos(pos)) + for pos, _ in pairs(D.get_dst(pos)) do + table.insert(dstlist, minetest.pos_to_string(advtrains.decode_pos(pos))) end - form[#form+1] = F.S_label(0.5, 2.5, "This signal has the following distant signals:") - form[#form+1] = F.textlist(0.5, 3, 4.5, 3, "dstlist", dstlist) - form[#form+1] = F.image_button_exit(5.5, 3.25, 1, 1, "cdb_add.png", "dst_add", "") - form[#form+1] = F.image_button_exit(5.5, 4.75, 1, 1, "cdb_clear.png", "dst_del", "") - minetest.show_formspec(pname, "advtrains:distant_" .. minetest.pos_to_string(pos), table.concat(form)) + return table.concat { + F.S_label(x, y, "Distant signals:"), + F.textlist(x, y+0.5, w-1, h-0.5, "dstlist", dstlist), + F.image_button_exit(x+w-0.75, ymid-0.875, 0.75, 0.75, "cdb_add.png", "dst_add", ""), + F.image_button_exit(x+w-0.75, ymid+0.125, 0.75, 0.75, "cdb_clear.png", "dst_del", ""), + } +end + +function I.make_dst_formspec_component(pos, x, y, w, h) + return I.make_short_dst_formspec_component(pos, x, y, w, h) + .. I.make_dst_list_formspec_component(pos, x, y+2, w, h-2) +end + +function I.show_distant_signal_form(pos, pname) + return I.show_ip_form(pos, pname) end local signal_pos = {} @@ -87,21 +100,14 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) end) local dstsel = {} -minetest.register_on_player_receive_fields(function(player, formname, fields) - local pname = player:get_player_name() - local pos = minetest.string_to_pos(string.match(formname, "^advtrains:distant_(.+)$") or "") - if not pos then - return - end - if not minetest.check_player_privs(pname, "interlocking") then + +function advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields) + if not (pos and minetest.check_player_privs(pname, "interlocking")) then return end - if advtrains.interlocking.handle_signal_formspec_tabheader_fields(pname, fields) then - return true - end - if fields.unassign_dst then + if fields.dst_unassign then D.unassign_dst(pos) - elseif fields.assign_dst then + elseif fields.dst_assign then init_signal_assignment(pname, pos) elseif fields.dst_add then init_distant_assignment(pname, pos) @@ -124,4 +130,4 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end end -end) +end diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index 8bb92bf..cd408d7 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -1,5 +1,7 @@ -- Signal API implementation +local F = advtrains.formspec + local DANGER = { main = 0, shunt = false, @@ -131,57 +133,68 @@ local function ipmarker(ipos, connid) }) end --- shows small info form for signal IP state/assignment +function advtrains.interlocking.make_ip_formspec_component(pos, x, y, w) + advtrains.interlocking.db.check_for_duplicate_ip(pos) + local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos) + if pts then + return table.concat { + 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"), + }, pts, connid + else + return table.concat { + 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 + +-- shows small info form for signal properties +-- This function is named show_ip_form because it was originally only intended +-- for assigning/changing the influence point. -- only_notset: show only if it is not set yet (used by signal tcb assignment) function advtrains.interlocking.show_ip_form(pos, pname, only_notset) if not minetest.check_player_privs(pname, "interlocking") then return end - local form = "size[7,6.5]label[0.5,0.5;Signal at "..minetest.pos_to_string(pos).."]" - local node = advtrains.ndb.get_node(pos) - local ndef = minetest.registered_nodes[node.name] or {} - if ndef.advtrains and ndef.advtrains.set_aspect then - form = form .. advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 2) - end - advtrains.interlocking.db.check_for_duplicate_ip(pos) - local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos) + local ipform, pts, connid = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 0.5, 7) + local form = table.concat { + "formspec_version[4]", + "size[8,6.75]", + ipform, + advtrains.interlocking.make_dst_formspec_component(pos, 0.5, 2, 7, 4.25), + } if pts then - form = form.."label[0.5,1.5;Influence point is set at "..pts.."/"..connid.."]" - form = form.."button_exit[0.5,4.25; 6,1;set;Move]" - form = form.."button_exit[0.5,5.25; 6,1;clear;Clear]" local ipos = minetest.string_to_pos(pts) ipmarker(ipos, connid) - else - form = form.."label[0.5,1.5;Influence point is not set.]" - form = form.."label[0.5,2.0;It is recommended to set an influence point.]" - form = form.."label[0.5,2.5;This is the point where trains will obey the signal.]" - - form = form.."button_exit[0.5,5.25; 6,1;set;Set]" end if not only_notset or not pts then - minetest.show_formspec(pname, "at_il_ipassign_"..minetest.pos_to_string(pos), form) + minetest.show_formspec(pname, "at_il_propassign_"..minetest.pos_to_string(pos), form) end end -minetest.register_on_player_receive_fields(function(player, formname, fields) - local pname = player:get_player_name() - if advtrains.interlocking.handle_signal_formspec_tabheader_fields(pname, fields) then - return true - end - if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then +function advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields) + if not (pos and minetest.check_player_privs(pname, {train_operator=true, interlocking=true})) then return end - local pts = string.match(formname, "^at_il_ipassign_([^_]+)$") + if fields.ip_set then + advtrains.interlocking.signal_init_ip_assign(pos, pname) + elseif fields.ip_clear then + advtrains.interlocking.db.clear_ip_by_signalpos(pos) + end +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local pname = player:get_player_name() + local pts = string.match(formname, "^at_il_propassign_([^_]+)$") local pos if pts then pos = minetest.string_to_pos(pts) end if pos then - if fields.set then - advtrains.interlocking.signal_init_ip_assign(pos, pname) - elseif fields.clear then - advtrains.interlocking.db.clear_ip_by_signalpos(pos) - end + advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields) + advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields) end end) diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua index 6de21e6..ddab793 100644 --- a/advtrains_interlocking/signal_aspect_ui.lua +++ b/advtrains_interlocking/signal_aspect_ui.lua @@ -37,6 +37,20 @@ advtrains.interlocking.describe_t1_main_aspect = describe_t1_main_aspect advtrains.interlocking.describe_t1_shunt_aspect = describe_t1_shunt_aspect advtrains.interlocking.describe_t1_distant_aspect = describe_t1_distant_aspect +local function dsel(p, q, x, y) + if p == nil then + if q then + return x + else + return y + end + elseif p then + return x + else + return y + end +end + local function describe_supported_aspects_t1(suppasp, isasp) local t = {} @@ -50,11 +64,22 @@ local function describe_supported_aspects_t1(suppasp, isasp) end t.main = entries t.main_current = selid + t.main_string = tostring(isasp.main) + if t.main == nil then + t.main_string = "" + end - if suppasp.shunt == nil then - t.shunt = true - t.shunt_current = isasp and isasp.shunt + t.shunt = { + attrans("No shunting"), + attrans("Shunting allowed"), + attrans("Proceed as main"), + } + + t.shunt_current = dsel(suppasp.shunt, isasp.shunt, 2, 1) + if dsel(suppasp.proceed_as_main, isasp.proceed_as_main, t.shunt_current == 1) then + t.shunt_current = 3 end + t.shunt_const = suppasp.shunt ~= nil entries = {} selid = 1 @@ -71,96 +96,98 @@ end advtrains.interlocking.describe_supported_aspects_t1 = describe_supported_aspects_t1 -local signal_tabheader_map = {} - -local function make_signal_formspec_tabheader(pname, pos, width, selid) - signal_tabheader_map[pname] = pos - local firstlabel = attrans("Signal aspect") - if advtrains.interlocking.db.get_sigd_for_signal(pos) then - firstlabel = attrans("Routesetting") - end - local options = { - firstlabel, - attrans("Influence point"), - attrans("Distant signalling"), - } - return F.tabheader(0, 0, nil, nil, "signal_tab", options, selid) -end - -local function handle_signal_formspec_tabheader_fields(pname, fields) - local n = tonumber(fields.signal_tab) - local pos = signal_tabheader_map[pname] - if not (n and pos) then - return false - end - if n == 1 then - local node = advtrains.ndb.get_node(pos) - advtrains.interlocking.show_signal_form(pos, node, pname) - elseif n == 2 then - advtrains.interlocking.show_ip_form(pos, pname) - elseif n == 3 then - advtrains.interlocking.show_distant_signal_form(pos, pname) - end - return true -end - -advtrains.interlocking.make_signal_formspec_tabheader = make_signal_formspec_tabheader -advtrains.interlocking.handle_signal_formspec_tabheader_fields = handle_signal_formspec_tabheader_fields - local function make_signal_aspect_selector_t1(suppasp, purpose, isasp) - local form = {"size[7,6.5]"} local t = describe_supported_aspects_t1(suppasp, isasp) + local formmode = 1 + + local pos if type(purpose) == "table" then - form[#form+1] = make_signal_formspec_tabheader(purpose.pname, purpose.pos, 7, 1) - purpose = "" + formmode = 2 + pos = purpose.pos end - form[#form+1] = F.S_label(0.5, 0.5, "Select signal aspect") - form[#form+1] = F.label(0.5, 1, purpose) - form[#form+1] = F.S_label(0.5, 1.5, "Main aspect") - form[#form+1] = F.dropdown(0.5, 2, 6, "main", t.main, t.main_current, true) + local form = { + "formspec_version[4]", + string.format("size[8,%f]", ({5.75, 9.25})[formmode]), + F.S_label(0.5, 0.5, "Select signal aspect"), + } + if formmode == 1 then + form[#form+1] = F.label(0.5, 1, purpose) + else + form[#form+1] = F.S_label(0.5, 1, "Signal at @1", minetest.pos_to_string(pos)) + end - form[#form+1] = F.S_label(0.5, 3, "Distant aspect") - form[#form+1] = F.dropdown(0.5, 3.5, 6, "dst", t.dst, t.dst_current, true) + form[#form+1] = F.S_label(0.5, 1.5, "Main aspect") + if formmode == 1 then + form[#form+1] = F.field(0.5, 2, 7, "asp_mainval", "", t.main_string) + else + form[#form+1] = F.dropdown(0.5, 2, 7, "asp_mainsel", t.main, t.main_current, true) + end - if t.shunt then - form[#form+1] = F.S_checkbox(0.5, 4.25, "shunt", t.shunt_current, "Allow shunting") + form[#form+1] = F.S_label(0.5, 3, "Shunt aspect") + if formmode == 2 and t.shunt_const then + form[#form+1] = F.label(0.5, 3.5, t.shunt[t.shunt_current]) + form[#form+1] = F.S_label(0.5, 4, "The shunt aspect cannot be changed.") else - form[#form+1] = F.S_label(0.5, 4.5, "The shunt aspect cannot be changed.") + form[#form+1] = F.dropdown(0.5, 3.5, 7, "asp_shunt", t.shunt, t.shunt_current, true) + end + + form[#form+1] = F.S_button_exit(0.5, 4.5, 7, "asp_save", "Save signal aspect") + + if formmode == 2 then + form[#form+1] = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 5.5, 7) + form[#form+1] = advtrains.interlocking.make_short_dst_formspec_component(pos, 0.5, 7, 7) end - form[#form+1] = F.S_button_exit(0.5, 5.25, 6, 1, "save", "Save signal aspect") return table.concat(form) end local function make_signal_aspect_selector_t2(suppasp, purpose, isasp) - local form = {"size[7,6.5]"} local def = advtrains.interlocking.aspects.get_type2_definition(suppasp.group) if not def then return nil end + local formmode = 1 + + local pos if type(purpose) == "table" then - form[#form+1] = make_signal_formspec_tabheader(purpose.pname, purpose.pos, 7, 1) - purpose = "" + formmode = 2 + pos = purpose.pos + end + local form = { + "formspec_version[4]", + string.format("size[8,%f]", ({4.25, 10.25})[formmode]), + F.S_label(0.5, 0.5, "Select signal aspect") + } + if formmode == 1 then + form[#form+1] = F.label(0.5, 1, purpose) + else + form[#form+1] = F.S_label(0.5, 1, "Signal at @1", minetest.pos_to_string(pos)) end - form[#form+1] = F.S_label(0.5, 0.5, "Select signal aspect") - form[#form+1] = F.label(0.5, 1, purpose) local entries = {} - local selid = 1 - for idx, spv in ipairs(def.main) do - if isasp and isasp.type2name == spv.name then - selid = idx + local selid = #def.main + if isasp then + if isasp.type2name ~= def.main[selid].name then + selid = 1 end - entries[idx] = spv.label end + if selid > 1 then + selid = 2 + end + local entries = { + def.main[1].label, + def.main[#def.main].label, + } form[#form+1] = F.S_label(0.5, 1.5, "Signal group: @1", def.label) - form[#form+1] = F.dropdown(0.5, 2, 6, "asp", entries, selid, true) - form[#form+1] = F.S_label(0.5, 3, "Aspect in effect:") - form[#form+1] = F.label(0.5, 3.5, describe_t1_main_aspect(isasp.main)) - form[#form+1] = F.label(0.5, 4, describe_t1_distant_aspect(isasp.dst)) - form[#form+1] = F.label(0.5, 4.5, describe_t1_shunt_aspect(isasp.shunt)) - form[#form+1] = F.S_button_exit(0.5, 5.25, 6, 1, "save", "Save signal aspect") + form[#form+1] = F.dropdown(0.5, 2, 7, "asp_sel", entries, selid, true) + form[#form+1] = F.S_button_exit(0.5, 3, 7, "asp_save", "Save signal aspect") + + if formmode == 2 then + form[#form+1] = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 4, 7) + form[#form+1] = advtrains.interlocking.make_dst_formspec_component(pos, 0.5, 5.5, 7, 4.25) + end + return table.concat(form) end @@ -188,13 +215,14 @@ function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_ local token = advtrains.random_id() minetest.show_formspec(pname, "at_il_sigaspdia_"..token, form) - --minetest.after(1, function() - players_aspsel[pname] = { - suppasp = suppasp, - callback = callback, - token = token, - } - --end) + minetest.after(0, function() + players_aspsel[pname] = { + purpose = purpose, + suppasp = suppasp, + callback = callback, + token = token, + } + end) end local function usebool(sup, val, free) @@ -206,20 +234,45 @@ local function usebool(sup, val, free) end local function get_aspect_from_formspec_t1(suppasp, fields, psl) - local maini = tonumber(fields.main) - if not maini then return end - local dsti = tonumber(fields.dst) - if not dsti then return end + local maini = tonumber(fields.asp_mainsel) + local main = suppasp.main[maini] + if not maini then + local mainval = fields.asp_mainval + if mainval == "-1" then + main = -1 + elseif string.match(mainval, "^%d+$") then + main = tonumber(mainval) + else + main = nil + end + end + local shunti = tonumber(fields.asp_shunt) + local shunt = suppasp.shunt + if shunt == nil then + shunt = shunti == 2 + end + local proceed_as_main = suppasp.proceed_as_main + if proceed_as_main == nil then + proceed_as_main = shunti == 3 + end return { - main = suppasp.main[maini], - dst = suppasp.dst[dsti], - shunt = usebool(suppasp.shunt, psl.shunt, "true"), + main = main, + shunt = shunt, + proceed_as_main = proceed_as_main, info = {}, } end local function get_aspect_from_formspec_t2(suppasp, fields, psl) - local asp = advtrains.interlocking.aspects.type2_to_type1(suppasp, tonumber(fields.asp)) + local sel = tonumber(fields.asp_sel) + local def = advtrains.interlocking.aspects.get_type2_definition(suppasp.group) + if not (sel and def) then + return + end + if sel ~= 1 then + sel = #def.main + end + local asp = advtrains.interlocking.aspects.type2_to_type1(suppasp, sel) return asp end @@ -229,13 +282,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if psl then if formname == "at_il_sigaspdia_"..psl.token then local suppasp = psl.suppasp - if handle_signal_formspec_tabheader_fields(pname, fields) then - return true - end - if fields.shunt then - psl.shunt = fields.shunt - end - if fields.save then + if fields.asp_save then local asp if suppasp.type == 2 then asp = get_aspect_from_formspec_t2(suppasp, fields, psl) @@ -246,6 +293,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) psl.callback(pname, asp) end end + if type(psl.purpose) == "table" then + local pos = psl.purpose.pos + advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields) + advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields) + end else players_aspsel[pname] = nil end diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 3898d73..9aea18c 100755 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -614,7 +614,6 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle if not tcbs.routes then tcbs.routes = {} end local form = "size[7,10.25]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]" - form = form .. advtrains.interlocking.make_signal_formspec_tabheader(pname, tcbs.signal, 7, 1) form = form.."field[0.8,1.5;5.2,1;name;Signal name;"..minetest.formspec_escape(tcbs.signal_name).."]" form = form.."button[5.5,1.2;1,1;setname;Set]" @@ -708,10 +707,6 @@ end minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() - if string.find(formname, "^at_il_signalling_") - and advtrains.interlocking.handle_signal_formspec_tabheader_fields(pname, fields) then - return true - end if not minetest.check_player_privs(pname, "train_operator") then return end diff --git a/advtrains_signals_japan/init.lua b/advtrains_signals_japan/init.lua index a28478f..fe74259 100644 --- a/advtrains_signals_japan/init.lua +++ b/advtrains_signals_japan/init.lua @@ -294,6 +294,7 @@ local function process_signal(name, sigdata, isrpt) local type2def = {} type2def.name = typename type2def.main = {} + type2def.label = S(string.format("Japanese signal (type %s)", string.upper(name))) local def = {} local tx = {} def.typename = typename -- cgit v1.2.3 From d443d8e07af89665a6bb3d87af91f43f08a6c47e Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Fri, 6 Jan 2023 18:23:15 +0100 Subject: Distant signaling: avoid signal signs --- advtrains_interlocking/distant.lua | 21 +++++++++++++++++++++ advtrains_interlocking/distant_ui.lua | 10 +++++++++- advtrains_interlocking/signal_api.lua | 10 +++++++--- advtrains_interlocking/signal_aspect_accessors.lua | 2 +- .../spec/basic_signalling_spec.lua | 17 ++++++++++++++++- 5 files changed, 54 insertions(+), 6 deletions(-) (limited to 'advtrains_interlocking/distant_ui.lua') diff --git a/advtrains_interlocking/distant.lua b/advtrains_interlocking/distant.lua index 726c2b3..4175875 100644 --- a/advtrains_interlocking/distant.lua +++ b/advtrains_interlocking/distant.lua @@ -85,6 +85,23 @@ local function unassign_all(pos, force) unassign_dst(pos, force) end +--- Check whether a signal is "appropriate" for the distant signal system. +-- Currently, a signal is considered appropriate if its signal aspect can be set. +-- @function appropriate_signal +-- @param pos The position of the signal +local function appropriate_signal(pos) + local node = advtrains.ndb.get_node(pos) + local ndef = minetest.registered_nodes[node.name] or {} + if not ndef then + return false + end + local atdef = ndef.advtrains + if not atdef then + return false + end + return atdef.supported_aspects and atdef.set_aspect and true +end + --- Assign a distant signal to a main signal. -- @function assign -- @param main The position of the main signal. @@ -92,6 +109,9 @@ end -- @param[opt="manual"] by The method of assignment. -- @param[opt=false] skip_update Whether to skip callbacks. local function assign(main, dst, by, skip_update) + if not (appropriate_signal(main) and appropriate_signal(dst)) then + return + end local pts_main = pts(main) local pts_dst = pts(dst) local t = db_distant[pts_main] @@ -177,4 +197,5 @@ advtrains.distant = { update_main = update_main, update_dst = update_dst, update_signal = update_signal, + appropriate_signal = appropriate_signal, } diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua index 0907684..bb66dc4 100644 --- a/advtrains_interlocking/distant_ui.lua +++ b/advtrains_interlocking/distant_ui.lua @@ -56,6 +56,10 @@ local function init_signal_assignment(pname, pos) minetest.chat_send_player(pname, attrans("This operation is not allowed without the @1 privilege.", "interlocking")) return end + if not D.appropriate_signal(pos) then + minetest.chat_send_player(pname, attrans("Incompatible signal.")) + return + end signal_pos[pname] = pos minetest.chat_send_player(pname, attrans("Please punch the signal to use as the main signal.")) end @@ -66,6 +70,10 @@ local function init_distant_assignment(pname, pos) minetest.send_chat_player(pname, attrans("This operation is now allowed without the @1 privilege.", "interlocking")) return end + if not D.appropriate_signal(pos) then + minetest.chat_send_player(pname, attrans("Incompatible signal.")) + return + end distant_pos[pname] = pos minetest.chat_send_player(pname, attrans("Please punch the signal to use as the distant signal.")) end @@ -87,7 +95,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) signal_pos[pname] = nil distant_pos[pname] = nil local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2 - if not is_signal then + if not (is_signal and D.appropriate_signal(pos)) then minetest.chat_send_player(pname, attrans("Incompatible signal.")) return end diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index cd408d7..1b4a21c 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -159,16 +159,20 @@ function advtrains.interlocking.show_ip_form(pos, pname, only_notset) return end local ipform, pts, connid = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 0.5, 7) - local form = table.concat { + local form = { "formspec_version[4]", - "size[8,6.75]", + "size[8,2.25]", ipform, - advtrains.interlocking.make_dst_formspec_component(pos, 0.5, 2, 7, 4.25), } if pts then local ipos = minetest.string_to_pos(pts) ipmarker(ipos, connid) end + if advtrains.distant.appropriate_signal(pos) then + form[#form+1] = advtrains.interlocking.make_dst_formspec_component(pos, 0.5, 2, 7, 4.25) + form[2] = "size[8,6.75]" + end + form = table.concat(form) if not only_notset or not pts then minetest.show_formspec(pname, "at_il_propassign_"..minetest.pos_to_string(pos), form) end diff --git a/advtrains_interlocking/signal_aspect_accessors.lua b/advtrains_interlocking/signal_aspect_accessors.lua index e55814e..e419515 100644 --- a/advtrains_interlocking/signal_aspect_accessors.lua +++ b/advtrains_interlocking/signal_aspect_accessors.lua @@ -144,7 +144,7 @@ local function get_real_aspect(pos) if ndef.advtrains and ndef.advtrains.get_aspect then local asp = ndef.advtrains.get_aspect(pos, node) or I.DANGER local suppasp = get_supported_aspects(pos) - if suppasp.type == 2 then + if suppasp and suppasp.type == 2 then asp = A.type2_to_type1(suppasp, asp) end return adjust_aspect(pos, asp) diff --git a/advtrains_interlocking/spec/basic_signalling_spec.lua b/advtrains_interlocking/spec/basic_signalling_spec.lua index 720b274..cce0f15 100644 --- a/advtrains_interlocking/spec/basic_signalling_spec.lua +++ b/advtrains_interlocking/spec/basic_signalling_spec.lua @@ -23,6 +23,12 @@ sourcefile("signal_api") sourcefile("signal_aspect_accessors") fixture("../../demosignals") +minetest.register_node("advtrains_interlocking:signal_sign", { + advtrains = { + get_aspcet = function() return {main = 19} end + } +}) + local D = advtrains.distant local I = advtrains.interlocking @@ -32,7 +38,7 @@ local stub_aspect_t1 = { danger = {main = 0, shunt = false}, } local stub_pos_t1 = {} -for i = 1, 3 do +for i = 1, 4 do stub_pos_t1[i] = {x = 1, y = 0, z = i} end @@ -40,6 +46,7 @@ world.layout { {stub_pos_t1[1], "advtrains_interlocking:ds_danger"}, {stub_pos_t1[2], "advtrains_interlocking:ds_slow"}, {stub_pos_t1[3], "advtrains_interlocking:ds_free"}, + {stub_pos_t1[4], "advtrains_interlocking:signal_sign"}, } describe("API for supposed signal aspects", function() @@ -84,4 +91,12 @@ describe("Distant signaling", function() assert.same({}, {D.get_main(stub_pos_t1[3])}) assert.same(stub_aspect_t1.free, I.signal_get_aspect(stub_pos_t1[3])) end) + it("should reject signal signs", function() + D.assign(stub_pos_t1[1], stub_pos_t1[4]) + assert.same({}, D.get_dst(stub_pos_t1[1])) + assert.same({}, {D.get_main(stub_pos_t1[4])}) + D.assign(stub_pos_t1[4], stub_pos_t1[1]) + assert.same({}, D.get_dst(stub_pos_t1[4])) + assert.same({}, {D.get_main(stub_pos_t1[1])}) + end) end) -- cgit v1.2.3