From 031aab4633f6f140a2ffda4f00b6e0d743cf681a Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 4 Jul 2018 17:48:33 +0200 Subject: Signal assignment and route programming procedure --- advtrains/nodedb.lua | 5 +- advtrains_interlocking/database.lua | 26 +- advtrains_interlocking/demosignals.lua | 9 +- advtrains_interlocking/init.lua | 1 + advtrains_interlocking/route_prog.lua | 323 +++++++++++++++++++++ advtrains_interlocking/signal_api.lua | 35 ++- advtrains_interlocking/tcb_ts_ui.lua | 94 +++++- .../textures/at_il_route_end.png | Bin 0 -> 451 bytes .../textures/at_il_route_lock.png | Bin 0 -> 382 bytes .../textures/at_il_route_set.png | Bin 0 -> 398 bytes .../textures/at_il_route_start.png | Bin 0 -> 380 bytes .../textures/at_il_turnout_cr_l.png | Bin 0 -> 314 bytes .../textures/at_il_turnout_cr_r.png | Bin 0 -> 298 bytes .../textures/at_il_turnout_free.png | Bin 0 -> 367 bytes .../textures/at_il_turnout_st.png | Bin 0 -> 229 bytes 15 files changed, 476 insertions(+), 17 deletions(-) create mode 100644 advtrains_interlocking/route_prog.lua create mode 100644 advtrains_interlocking/textures/at_il_route_end.png create mode 100644 advtrains_interlocking/textures/at_il_route_lock.png create mode 100644 advtrains_interlocking/textures/at_il_route_set.png create mode 100644 advtrains_interlocking/textures/at_il_route_start.png create mode 100644 advtrains_interlocking/textures/at_il_turnout_cr_l.png create mode 100644 advtrains_interlocking/textures/at_il_turnout_cr_r.png create mode 100644 advtrains_interlocking/textures/at_il_turnout_free.png create mode 100644 advtrains_interlocking/textures/at_il_turnout_st.png diff --git a/advtrains/nodedb.lua b/advtrains/nodedb.lua index 7433042..edb3329 100644 --- a/advtrains/nodedb.lua +++ b/advtrains/nodedb.lua @@ -133,7 +133,9 @@ end function ndb.swap_node(pos, node, no_inval) - minetest.swap_node(pos, node) + if minetest.get_node_or_nil(pos) then + minetest.swap_node(pos, node) + end ndb.update(pos, node) end @@ -294,6 +296,5 @@ minetest.register_chatcommand("at_sync_ndb", return true, text end) end, - privs = {train_operator=true}, -- Require the "privs" privilege to run }) diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua index f4a6871..6c6047f 100644 --- a/advtrains_interlocking/database.lua +++ b/advtrains_interlocking/database.lua @@ -95,6 +95,8 @@ local ildb = {} local track_circuit_breaks = {} local track_sections = {} +local signal_assignments = {} + function ildb.load(data) if not data then return end if data.tcbs then @@ -103,10 +105,13 @@ function ildb.load(data) if data.ts then track_sections = data.ts end + if data.signalass then + signal_assignments = data.signalass + end end function ildb.save() - return {tcbs = track_circuit_breaks, ts=track_sections} + return {tcbs = track_circuit_breaks, ts=track_sections, signalass = signal_assignments} end -- @@ -123,6 +128,7 @@ TCB data structure -- 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 + aspect = -- The aspect the signal should show. If this is nil, should show the most restrictive aspect (red) }, [2] = { -- Variant: end of track-circuited area (initial state of TC) ts_id = nil, -- this is the indication for end_of_interlocking @@ -145,6 +151,11 @@ Track section Signal specifier (sigd) (a pair of TCB/Side): {p = , s = <1/2>} + +Signal Assignments: reverse lookup of signals assigned to TCBs +signal_assignments = { +[] = +} ]] @@ -406,6 +417,19 @@ function ildb.get_ts_at_pos(pos) return nil end + +-- returns the sigd the signal at pos belongs to, if this is known +function ildb.get_sigd_for_signal(pos) + local pts = advtrains.roundfloorpts(pos) + return signal_assignments[pts] +end +function ildb.set_sigd_for_signal(pos, sigd) + local pts = advtrains.roundfloorpts(pos) + signal_assignments[pts] = sigd +end + + + advtrains.interlocking.db = ildb diff --git a/advtrains_interlocking/demosignals.lua b/advtrains_interlocking/demosignals.lua index 8320afb..d5d5c4f 100644 --- a/advtrains_interlocking/demosignals.lua +++ b/advtrains_interlocking/demosignals.lua @@ -1,13 +1,16 @@ -- Demonstration signals -- Those can display the 3 main aspects of Ks signals +-- Note that the group value of advtrains_signal is 2, which means "step 2 of signal capabilities" +-- advtrains_signal=1 is meant for signals that do not implement set_aspect. + minetest.register_node("advtrains_interlocking:ds_danger", { description = "Demo signal at Danger", tiles = {"at_il_signal_asp_danger.png"}, groups = { cracky = 3, - advtrains_signal = 1, + advtrains_signal = 2, save_in_at_nodedb = 1, }, sounds = default.node_sound_stone_defaults(), @@ -35,7 +38,7 @@ minetest.register_node("advtrains_interlocking:ds_free", { tiles = {"at_il_signal_asp_free.png"}, groups = { cracky = 3, - advtrains_signal = 1, + advtrains_signal = 2, save_in_at_nodedb = 1, }, sounds = default.node_sound_stone_defaults(), @@ -63,7 +66,7 @@ minetest.register_node("advtrains_interlocking:ds_slow", { tiles = {"at_il_signal_asp_slow.png"}, groups = { cracky = 3, - advtrains_signal = 1, + advtrains_signal = 2, save_in_at_nodedb = 1, }, sounds = default.node_sound_stone_defaults(), diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua index a7138f8..05665e3 100644 --- a/advtrains_interlocking/init.lua +++ b/advtrains_interlocking/init.lua @@ -10,3 +10,4 @@ dofile(modpath.."tcb_ts_ui.lua") dofile(modpath.."signal_api.lua") dofile(modpath.."demosignals.lua") dofile(modpath.."train_related.lua") +dofile(modpath.."route_prog.lua") diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua new file mode 100644 index 0000000..72f72ca --- /dev/null +++ b/advtrains_interlocking/route_prog.lua @@ -0,0 +1,323 @@ +-- Route programming system + +--[[ +Progamming routes: +1. Select "program new route" in the signalling dialog +-> route_start marker will appear to designate route-program mode +2. Do those actions in any order: +A. punch a TCB marker node to proceed route along this TCB. This will only work if + this is actually a TCB bordering the current TS, and will place a + route_set marker and shift to the next TS +B. right-click a turnout to switch it (no impact to route programming +C. punch a turnout (or some other passive component) to fix its state (toggle) + for the route. A sprite telling "Route Fix" will show that fact. +3. To complete route setting, use the chat command '/at_program_route '. + The last punched TCB will get a 'route end' marker + The end of a route should be at another signal facing the same direction as the entrance signal, + however this is not enforced and left up to the signal engineer (the programmer) + +The route visualization will also be used to visualize routes after they have been programmed. +]]-- + + +-- table with objectRefs +local markerent = {} + +minetest.register_entity("advtrains_interlocking:routemarker", { + 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, +}) + + +-- Spawn or update a route marker entity +-- pos: position where this is going to be +-- key: something unique to determine which entity to remove if this was set before +-- img: texture +local function routemarker(context, pos, key, img, yaw, itex) + if not markerent[context] then + markerent[context] = {} + end + if markerent[context][key] then + markerent[context][key]:remove() + end + + local obj = minetest.add_entity(vector.add(pos, {x=0, y=0.3, z=0}), "advtrains_interlocking:routemarker") + if not obj then return end + obj:set_yaw(yaw) + obj:set_properties({ + infotext = itex, + textures = {img}, + }) + + markerent[context][key] = obj +end + +minetest.register_entity("advtrains_interlocking:routesprite", { + visual = "sprite", + textures = {"at_il_turnout_free.png"}, + collisionbox = {-0.2,-0.2,-0.2, 0.2,0.2,0.2}, + visual_size = {x=1, y=1}, + 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, +}) + + +-- Spawn or update a route sprite entity +-- pos: position where this is going to be +-- key: something unique to determine which entity to remove if this was set before +-- img: texture +local function routesprite(context, pos, key, img, itex) + if not markerent[context] then + markerent[context] = {} + end + if markerent[context][key] then + markerent[context][key]:remove() + end + + local obj = minetest.add_entity(vector.add(pos, {x=0, y=0, z=0}), "advtrains_interlocking:routesprite") + if not obj then return end + obj:set_properties({ + infotext = itex, + textures = {img}, + }) + + markerent[context][key] = obj +end + +--[[ +Route definition: +route = { + name = + tcbpath = { + [n] = + } + pcfix = { + [] = "state" + } +} +The first item in the TCB path is always the start signal of this route, +so this is left out. + + +]]-- + +function advtrains.interlocking.clear_visu_context(context) + if not markerent[context] then return end + for key, obj in pairs(markerent[context]) do + obj:remove() + end + markerent[context] = nil +end + +-- visualize route. 'context' is a string that identifies the context of this visualization +-- e.g. prog_ or vis for later visualizations +function advtrains.interlocking.visualize_route(origin, route, context) + advtrains.interlocking.clear_visu_context(context) + for k,sigd in ipairs(route.tcbpath) do + local yaw = 0 + local node_ok, conns, rhe = advtrains.get_rail_info_at(sigd.p, advtrains.all_tracktypes) + if node_ok then + yaw = advtrains.dir_to_angle(conns[sigd.s].c) + end + local img = "at_il_route_set.png" + if k == #route.tcbpath then img = "at_il_route_end.png" end + routemarker(context, sigd.p, "rte"..k, img, yaw, route.name.." #"..k) + end + for pts, state in pairs(route.pcfix) do + local pos = minetest.string_to_pos(pts) + routesprite(context, pos, "fix"..pts, "at_il_route_lock.png", "Fixed in state '"..state.."' by route "..route.name) + end +end + + +local player_rte_prog = {} + +function advtrains.interlocking.init_route_prog(pname, sigd) + player_rte_prog[pname] = { + origin = sigd, + route = { + name = "PROG["..pname.."]", + tcbpath = {}, + pcfix = {}, + } + } + 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) + if #route.tcbpath == 0 then + return origin + end + return route.tcbpath[#route.tcbpath] +end + +local function chat(pname, message) + minetest.chat_send_player(pname, "[Route programming] "..message) +end +local function otherside(s) + if s==1 then return 2 else return 1 end +end + +-- Central route programming punch callback +minetest.register_on_punchnode(function(pos, node, player, pointed_thing) + local pname = player:get_player_name() + local rp = player_rte_prog[pname] + if rp then + -- determine what the punched node is + if minetest.get_item_group(node.name, "at_il_track_circuit_break") >= 1 then + -- get position of the assigned tcb + local meta = minetest.get_meta(pos) + local tcbpts = meta:get_string("tcb_pos") + if tcbpts == "" then + chat(pname, "This TCB is unconfigured, you first need to assign it to a rail") + return + end + local tcbpos = minetest.string_to_pos(tcbpts) + + -- track circuit break, try to advance route over it + local lri = get_last_route_item(rp.origin, rp.route) + if vector.equals(lri.p, tcbpos) then + chat(pname, "You cannot continue the route to where you came from!") + return + end + + local start_tcbs = advtrains.interlocking.db.get_tcbs(lri) + if not start_tcbs.ts_id then + chat(pname, "The previous TCB was End of Interlocking. Please complete route programming using '/at_rp_set '") + return + end + + local ts = advtrains.interlocking.db.get_ts(start_tcbs.ts_id) + if not ts then atwarn("Internal error, ts inexistant for id!") return end + local found = nil + for _,sigd in ipairs(ts.tc_breaks) do + if vector.equals(sigd.p, tcbpos) then + found = otherside(sigd.s) + end + end + if not found then + chat(pname, "Previous and this TCB belong to different track sections!") + return + end + -- everything worked, just add the other side to the list + table.insert(rp.route.tcbpath, {p = tcbpos, s = found}) + chat(pname, "Added track section '"..ts.name.."' to the route (revert with /at_rp_back)") + advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname) + return + end + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.luaautomation and ndef.luaautomation.getstate then + local pts = advtrains.roundfloorpts(pos) + if rp.route.pcfix[pts] then + rp.route.pcfix[pts] = nil + chat(pname, pts.." is no longer affected when this route is set.") + else + local state = ndef.luaautomation.getstate + if type(state)=="function" then + state = state(pos, node) + end + rp.route.pcfix[pts] = state + chat(pname, pts.." is held in "..state.." position when this route is set.") + end + advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname) + return + end + + end +end) + +minetest.register_chatcommand("at_rp_set", + { + params = "", -- Short parameter description + description = "Completes route programming procedure", -- Full description + privs = {}, -- TODO + func = function(pname, param) + return advtrains.pcall(function() + if param=="" then + return false, "Missing name parameter!" + end + local rp = player_rte_prog[pname] + if rp then + if #rp.route.tcbpath <= 0 then + return false, "Cannot program route without a target" + end + rp.route.name = param + -- TODO save that route somewhere in origin + atdebug("ROUTE RESULT:",rp) + advtrains.interlocking.clear_visu_context("prog_"..pname) + return true, "Successfully programmed route" + end + return false, "You were not programming a route!" + end) + end, + }) + +minetest.register_chatcommand("at_rp_back", + { + params = "", -- Short parameter description + description = "Remove last route segment", -- Full description + privs = {}, -- Require the "privs" privilege to run + func = function(pname, param) + return advtrains.pcall(function() + local rp = player_rte_prog[pname] + if rp then + if #rp.route.tcbpath <= 0 then + return false, "Cannot backtrack when there are no route elements" + end + rp.route.tcbpath[#rp.route.tcbpath] = nil + advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname) + return true, "Route section "..(#rp.route.tcbpath+1).." removed." + end + return false, "You were not programming a route!" + end) + end, + }) +minetest.register_chatcommand("at_rp_mark", + { + params = "", -- Short parameter description + description = "Re-set route programming markers", -- Full description + privs = {}, -- TODO + func = function(pname, param) + return advtrains.pcall(function() + local rp = player_rte_prog[pname] + if rp then + advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname) + return true, "Redrawn route markers" + end + return false, "You were not programming a route!" + end) + end, + }) +minetest.register_chatcommand("at_rp_discard", + { + params = "", -- Short parameter description + description = "Discards the currently programmed route", -- Full description + privs = {}, -- Require the "privs" privilege to run + func = function(pname, param) + return advtrains.pcall(function() + player_rte_prog[pname] = nil + advtrains.interlocking.clear_visu_context("prog_"..pname) + return true, "Route discarded" + end) + end, + }) + + +--TODO on route setting +-- locked turnouts need to somehow know the TS they're associated to, which isn't possible with the current route programming and saving method +-- unify luaautomation get/setstate interface to the core +-- privileges for route programming +-- for now, that locking aspect will be ignored and turnouts just set when route gets commited. diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index e072273..17799ae 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -33,6 +33,21 @@ on_rightclick = advtrains.interlocking.signal_rc_handler ]]-- +local DANGER = { + main = { + free = false, + speed = 0, + }, + shunt = { + free = false, + }, + dst = { + free = false, + speed = 0, + }, + info = {} +} + function advtrains.interlocking.signal_set_aspect(pos, asp) local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] @@ -43,7 +58,13 @@ end function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing) local pname = player:get_player_name() - minetest.show_formspec(pname, "at_il_sigasp_"..minetest.pos_to_string(pos), "field[aspect;Set Aspect (F/D)Speed(F/D)Speed(F/D);D0D0D]") + local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) + if sigd then + advtrains.interlocking.show_signalling_form(sigd, pname) + else + -- permit to set aspect manually + minetest.show_formspec(pname, "at_il_sigasp_"..minetest.pos_to_string(pos), "field[aspect;Set Aspect (F/D)Speed(F/D)Speed(F/D);D0D0D]") + end end minetest.register_on_player_receive_fields(function(player, formname, fields) @@ -73,3 +94,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) advtrains.interlocking.signal_set_aspect(pos, asp) end end) + +-- Returns the aspect the signal at pos is supposed to show +function advtrains.interlocking.signal_get_aspect(pos) + local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) + if sigd then + local tcbs = advtrains.interlocking.db.get_tcbs(sigd) + if tcbs.aspect then + return tcbs.aspect + end + end + return DANGER; +end diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 0ebe767..454e2c4 100644 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -1,6 +1,7 @@ -- Track Circuit Breaks and Track Sections - Player interaction local players_assign_tcb = {} +local players_assign_signal = {} local players_link_ts = {} local lntrans = { "A", "B" } @@ -26,6 +27,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", { cracky=3, not_blocking_trains=1, --save_in_at_nodedb=2, + at_il_track_circuit_break = 1, }, after_place_node = function(pos, node, player) local meta = minetest.get_meta(pos) @@ -46,14 +48,14 @@ minetest.register_node("advtrains_interlocking:tcb_node", { players_assign_tcb[pname] = pos end end, - on_punch = function(pos, node, player) - local meta = minetest.get_meta(pos) - local tcbpts = meta:get_string("tcb_pos") - if tcbpts ~= "" then - local tcbpos = minetest.string_to_pos(tcbpts) - advtrains.interlocking.show_tcb_marker(tcbpos) - end - end, + --on_punch = function(pos, node, player) + -- local meta = minetest.get_meta(pos) + -- local tcbpts = meta:get_string("tcb_pos") + -- if tcbpts ~= "" then + -- local tcbpos = minetest.string_to_pos(tcbpts) + -- advtrains.interlocking.show_tcb_marker(tcbpos) + -- end + --end, can_dig = function(pos, player) -- Those markers can only be dug when all adjacent TS's are set -- as EOI. @@ -83,6 +85,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", { minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local pname = player:get_player_name() + -- TCB assignment local tcbnpos = players_assign_tcb[pname] if tcbnpos then if vector.distance(pos, tcbnpos)<=20 then @@ -109,6 +112,29 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) end players_assign_tcb[pname] = nil end + + -- Signal assignment + local sigd = players_assign_signal[pname] + if sigd then + if vector.distance(pos, sigd.p)<=50 then + local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2 + if is_signal then + local tcbs = advtrains.interlocking.db.get_tcbs(sigd) + if tcbs then + tcbs.signal = pos + advtrains.interlocking.db.set_sigd_for_signal(pos, sigd) + minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.") + else + minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.") + end + else + minetest.chat_send_player(pname, "Configuring TCB: Not a compatible signal. Aborted.") + end + else + minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.") + end + players_assign_tcb[pname] = nil + end end) @@ -135,6 +161,11 @@ local function mktcbformspec(tcbs, btnpref, offset, pname) form = form.."button[0.5,"..(offset+1.5)..";5,1;"..btnpref.."_setfree;Section is blocked]" end end + if tcbs.signal then + 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;Assign a signal]" + end return form end @@ -143,9 +174,9 @@ function advtrains.interlocking.show_tcb_form(pos, pname) local tcb = advtrains.interlocking.db.get_tcb(pos) if not tcb then return end - local form = "size[6,7] label[0.5,0.5;Track Circuit Break Configuration]" + local form = "size[6,9] label[0.5,0.5;Track Circuit Break Configuration]" form = form .. mktcbformspec(tcb[1], "A", 1, pname) - form = form .. mktcbformspec(tcb[2], "B", 4, pname) + form = form .. mktcbformspec(tcb[2], "B", 5, pname) minetest.show_formspec(pname, "at_il_tcbconfig_"..minetest.pos_to_string(pos), form) advtrains.interlocking.show_tcb_marker(pos) @@ -174,6 +205,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local f_makeil = {fields.A_makeil, fields.B_makeil} local f_setlocked = {fields.A_setlocked, fields.B_setlocked} local f_setfree = {fields.A_setfree, fields.B_setfree} + local f_asnsig = {fields.A_asnsig, fields.B_asnsig} + local f_sigdia = {fields.A_sigdia, fields.B_sigdia} for connid=1,2 do local tcbs = tcb[connid] @@ -201,6 +234,17 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) tcbs.section_free = nil end end + if f_asnsig[connid] and not tcbs.signal then + 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 + end + if f_sigdia[connid] and tcbs.signal then + advtrains.interlocking.show_signalling_form({p=pos, s=connid}, pname) + return + end + end advtrains.interlocking.show_tcb_form(pos, pname) end @@ -373,3 +417,33 @@ function advtrains.interlocking.show_tcb_marker(pos) markerent[pts] = obj end + +-- Signalling formspec - set routes a.s.o + +function advtrains.interlocking.show_signalling_form(sigd, pname) + local form = "size[10,10]label[0.5,0.5;Track Section Detail - ]" + form = form.."field[0.8,2;5.2,1;name;Section name;]" + form = form.."button[5.5,1.7;1,1;setname;Set]" + + --minetest.show_formspec(pname, "at_il_signalling_"..sigd.p.."_"..sigd.s, form) + --TODO this is temporary + advtrains.interlocking.init_route_prog(pname, sigd) +end + + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local pname = player:get_player_name() + local pts, connids = string.match(formname, "^at_il_signalling_([^_]+)_(%d)$") + local pts = string.match(formname, "^at_il_tcbconfig_(.+)$") + local pos, connid + if pts then + pos = minetest.string_to_pos(pts) + connid = tonumber(connids) + if not connid or connid<1 or connid>2 then return end + end + if pos and connid and not fields.quit then + + advtrains.interlocking.show_signalling_form(ts_id, pname, sel_tcb) + end + +end) diff --git a/advtrains_interlocking/textures/at_il_route_end.png b/advtrains_interlocking/textures/at_il_route_end.png new file mode 100644 index 0000000..1433f0c Binary files /dev/null and b/advtrains_interlocking/textures/at_il_route_end.png differ diff --git a/advtrains_interlocking/textures/at_il_route_lock.png b/advtrains_interlocking/textures/at_il_route_lock.png new file mode 100644 index 0000000..57eba71 Binary files /dev/null and b/advtrains_interlocking/textures/at_il_route_lock.png differ diff --git a/advtrains_interlocking/textures/at_il_route_set.png b/advtrains_interlocking/textures/at_il_route_set.png new file mode 100644 index 0000000..3531420 Binary files /dev/null and b/advtrains_interlocking/textures/at_il_route_set.png differ diff --git a/advtrains_interlocking/textures/at_il_route_start.png b/advtrains_interlocking/textures/at_il_route_start.png new file mode 100644 index 0000000..dcb5160 Binary files /dev/null and b/advtrains_interlocking/textures/at_il_route_start.png differ diff --git a/advtrains_interlocking/textures/at_il_turnout_cr_l.png b/advtrains_interlocking/textures/at_il_turnout_cr_l.png new file mode 100644 index 0000000..fb79e3d Binary files /dev/null and b/advtrains_interlocking/textures/at_il_turnout_cr_l.png differ diff --git a/advtrains_interlocking/textures/at_il_turnout_cr_r.png b/advtrains_interlocking/textures/at_il_turnout_cr_r.png new file mode 100644 index 0000000..e04dfbd Binary files /dev/null and b/advtrains_interlocking/textures/at_il_turnout_cr_r.png differ diff --git a/advtrains_interlocking/textures/at_il_turnout_free.png b/advtrains_interlocking/textures/at_il_turnout_free.png new file mode 100644 index 0000000..5c83193 Binary files /dev/null and b/advtrains_interlocking/textures/at_il_turnout_free.png differ diff --git a/advtrains_interlocking/textures/at_il_turnout_st.png b/advtrains_interlocking/textures/at_il_turnout_st.png new file mode 100644 index 0000000..50d5ad5 Binary files /dev/null and b/advtrains_interlocking/textures/at_il_turnout_st.png differ -- cgit v1.2.3