diff options
Diffstat (limited to 'advtrains_interlocking/tcb_ts_ui.lua')
-rwxr-xr-x | advtrains_interlocking/tcb_ts_ui.lua | 292 |
1 files changed, 127 insertions, 165 deletions
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 264834c..e7ff685 100755 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -2,6 +2,7 @@ local players_assign_tcb = {} local players_assign_signal = {} +local players_assign_xlink = {} local players_link_ts = {} local ildb = advtrains.interlocking.db @@ -14,6 +15,7 @@ local lntrans = { "A", "B" } local function sigd_to_string(sigd) return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s] end +advtrains.interlocking.sigd_to_string = sigd_to_string minetest.register_node("advtrains_interlocking:tcb_node", { drawtype = "mesh", @@ -88,12 +90,8 @@ minetest.register_node("advtrains_interlocking:tcb_node", { local tcb = ildb.get_tcb(tcbpos) if not tcb then return true end for connid=1,2 do - if tcb[connid].ts_id or tcb[connid].signal then - minetest.chat_send_player(pname, "Can't remove TCB: Both sides must have no track section and no signal assigned!") - return false - end - if not ildb.may_modify_tcbs(tcb[connid]) then - minetest.chat_send_player(pname, "Can't remove TCB: Side "..connid.." forbids modification (shouldn't happen).") + if tcb[connid].signal then + minetest.chat_send_player(pname, "Can't remove TCB: Both sides must have no signal assigned!") return false end end @@ -102,18 +100,11 @@ minetest.register_node("advtrains_interlocking:tcb_node", { end, after_dig_node = function(pos, oldnode, oldmetadata, player) if not oldmetadata or not oldmetadata.fields then return end + local pname = player:get_player_name() local tcbpts = oldmetadata.fields.tcb_pos if tcbpts and tcbpts ~= "" then local tcbpos = minetest.string_to_pos(tcbpts) - local success = ildb.remove_tcb(tcbpos) - if success and player then - minetest.chat_send_player(player:get_player_name(), "TCB has been removed.") - else - minetest.chat_send_player(player:get_player_name(), "Failed to remove TCB!") - minetest.set_node(pos, oldnode) - local meta = minetest.get_meta(pos) - meta:set_string("tcb_pos", minetest.pos_to_string(tcbpos)) - end + ildb.remove_tcb_at(tcbpos, pname) end end, }) @@ -167,19 +158,18 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) if vector.distance(pos, tcbnpos)<=20 then local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) if node_ok and #conns == 2 then - local ok = ildb.create_tcb(pos) - - if not ok then - minetest.chat_send_player(pname, "Configuring TCB: TCB already exists at this position! It has now been re-assigned.") + -- if there is already a tcb here, reassign it + if ildb.get_tcb(pos) then + 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 - - ildb.sync_tcb_neighbors(pos, 1) - ildb.sync_tcb_neighbors(pos, 2) - + local meta = minetest.get_meta(tcbnpos) meta:set_string("tcb_pos", minetest.pos_to_string(pos)) 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 @@ -196,13 +186,10 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2 if is_signal then local ndef = minetest.registered_nodes[node.name] - if ndef and ndef.advtrains and ndef.advtrains.set_aspect then + if ndef and ndef.advtrains and ndef.advtrains.apply_aspect then local tcbs = ildb.get_tcbs(sigd) if tcbs then tcbs.signal = pos - if not tcbs.signal_name then - tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p) - end if not tcbs.routes then tcbs.routes = {} end @@ -227,29 +214,37 @@ end) -- TCB Form -local function mktcbformspec(tcbs, btnpref, offset, pname) +local function mktcbformspec(pos, side, tcbs, offset, pname) local form = "" + 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}) + -- Note: repair operations may have been triggered by this if tcbs.ts_id then ts = ildb.get_ts(tcbs.ts_id) end if ts then - form = form.."label[0.5,"..offset..";Side "..btnpref..": "..minetest.formspec_escape(ts.name).."]" + 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]" - if ildb.may_modify_tcbs(tcbs) then - -- Note: the security check to prohibit those actions is located in database.lua in the corresponding functions. - form = form.."button[0.5,"..(offset+1.5)..";2.5,1;"..btnpref.."_update;Update near TCBs]" - form = form.."button[3 ,"..(offset+1.5)..";2.5,1;"..btnpref.."_remove;Remove from section]" - end else tcbs.ts_id = nil 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]" - --if tcbs.section_free then - --form = form.."button[0.5,"..(offset+1.5)..";5,1;"..btnpref.."_setlocked;Section is free]" - --else - --form = form.."button[0.5,"..(offset+1.5)..";5,1;"..btnpref.."_setfree;Section is blocked]" - --end + end + -- xlink + if tcbs.xlink then + form = form.."label[0.5,"..(offset+1.5)..";Link:"..ildb.sigd_to_string(tcbs.xlink).."]" + 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;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)..";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;Signalling]" @@ -269,8 +264,8 @@ function advtrains.interlocking.show_tcb_form(pos, pname) if not tcb then return end 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", 5, pname) + form = form .. mktcbformspec(pos, 1, tcb[1], 1, pname) + form = form .. mktcbformspec(pos, 2, tcb[2], 5, pname) minetest.show_formspec(pname, "at_il_tcbconfig_"..minetest.pos_to_string(pos), form) advtrains.interlocking.show_tcb_marker(pos) @@ -297,13 +292,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local tcb = ildb.get_tcb(pos) if not tcb then return end local f_gotots = {fields.A_gotots, fields.B_gotots} - local f_update = {fields.A_update, fields.B_update} - local f_remove = {fields.A_remove, fields.B_remove} 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} + local f_xlinkadd = {fields.A_xlinkadd, fields.B_xlinkadd} + local f_xlinkdel = {fields.A_xlinkdel, fields.B_xlinkdel} + local f_xlinklink = {fields.A_xlinklink, fields.B_xlinklink} + local f_xlinkabrt = {fields.A_xlinkabrt, fields.B_xlinkabrt} for connid=1,2 do local tcbs = tcb[connid] @@ -312,28 +307,33 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) advtrains.interlocking.show_ts_form(tcbs.ts_id, pname) return end - if f_update[connid] then - ildb.sync_tcb_neighbors(pos, connid) - end - if f_remove[connid] then - ildb.remove_from_interlocking({p=pos, s=connid}) - end else if f_makeil[connid] then - -- try sinc_tcb_neighbors first - ildb.sync_tcb_neighbors(pos, connid) - -- if that didn't work, create new section if not tcbs.ts_id then - ildb.create_ts({p=pos, s=connid}) - ildb.sync_tcb_neighbors(pos, connid) + ildb.create_ts_from_tcbs({p=pos, s=connid}) end end - -- non-interlocked - if f_setfree[connid] then - tcbs.section_free = true + end + if tcbs.xlink then + if f_xlinkdel[connid] then + ildb.remove_tcb_xlink({p=pos, s=connid}) end - if f_setlocked[connid] then - tcbs.section_free = nil + else + local osigd = players_assign_xlink[pname] + if osigd then + if f_xlinklink[connid] then + ildb.add_tcb_xlink({p=pos, s=connid}, osigd) + players_assign_xlink[pname] = nil + elseif f_xlinkabrt[connid] then + players_assign_xlink[pname] = nil + end + else + if f_xlinkadd[connid] then + players_assign_xlink[pname] = {p=pos, s=connid} + 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 @@ -357,10 +357,7 @@ end) -- TS Formspec --- textlist selection temporary storage -local ts_pselidx = {} - -function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) +function advtrains.interlocking.show_ts_form(ts_id, pname) if not minetest.check_player_privs(pname, "interlocking") then minetest.chat_send_player(pname, "Insufficient privileges to use this!") return @@ -369,7 +366,7 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) if not ts_id then return end local form = "size[10,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).."]" + 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 @@ -382,26 +379,8 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) form = form.."textlist[0.5,3;5,3;tcblist;"..table.concat(strtab, ",").."]" if ildb.may_modify_ts(ts) then - - if players_link_ts[pname] then - local other_id = players_link_ts[pname] - local other_ts = ildb.get_ts(other_id) - if other_ts then - if ildb.may_modify_ts(other_ts) then - form = form.."button[5.5,3;3.5,1;mklink;Join with "..minetest.formspec_escape(other_ts.name).."]" - form = form.."button[9 ,3;0.5,1;cancellink;X]" - end - end - else - form = form.."button[5.5,3;4,1;link;Join into other section]" - hint = 1 - end - form = form.."button[5.5,4;4,1;dissolve;Dissolve Section]" + form = form.."button[5.5,4;4,1;remove;Remove Section]" form = form.."tooltip[dissolve;This will remove the track section and set all its end points to End Of Interlocking]" - if sel_tcb then - form = form.."button[5.5,5;4,1;del_tcb;Unlink selected TCB]" - hint = 2 - end else hint=3 end @@ -420,17 +399,12 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) end form = form.."button[5.5,7;4,1;reset;Reset section state]" - - if hint == 1 then - form = form.."label[0.5,0.75;Use the 'Join' button to designate rail crosses and link not listed far-away TCBs]" - elseif hint == 2 then - form = form.."label[0.5,0.75;Unlinking a TCB will set it to non-interlocked mode.]" - elseif hint == 3 then + + if hint == 3 then 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 - ts_pselidx[pname]=sel_tcb minetest.show_formspec(pname, "at_il_tsconfig_"..ts_id, form) end @@ -442,45 +416,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) return end -- independent of the formspec, clear this whenever some formspec event happens - local tpsi = ts_pselidx[pname] - ts_pselidx[pname] = nil local ts_id = string.match(formname, "^at_il_tsconfig_(.+)$") if ts_id and not fields.quit then local ts = ildb.get_ts(ts_id) if not ts then return end - local sel_tcb - if fields.tcblist then - local tev = minetest.explode_textlist_event(fields.tcblist) - sel_tcb = tev.index - ts_pselidx[pname] = sel_tcb - elseif tpsi then - sel_tcb = tpsi - end - if ildb.may_modify_ts(ts) then - if players_link_ts[pname] then - if fields.cancellink then - players_link_ts[pname] = nil - elseif fields.mklink then - ildb.link_track_sections(players_link_ts[pname], ts_id) - players_link_ts[pname] = nil - end - end - - if fields.del_tcb and sel_tcb and sel_tcb > 0 and sel_tcb <= #ts.tc_breaks then - if not ildb.remove_from_interlocking(ts.tc_breaks[sel_tcb]) then - minetest.chat_send_player(pname, "Please unassign signal first!") - end - sel_tcb = nil - end - - if fields.link then - players_link_ts[pname] = ts_id - end - if fields.dissolve then - ildb.dissolve_ts(ts_id) + if fields.remove then + ildb.remove_ts(ts_id) minetest.close_formspec(pname, formname) return end @@ -489,7 +433,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if fields.setname then ts.name = fields.name if ts.name == "" then - ts.name = "Section "..ts_id + ts.name = nil end end @@ -520,7 +464,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) ts.route = nil for _, sigd in ipairs(ts.tc_breaks) do local tcbs = ildb.get_tcbs(sigd) - advtrains.interlocking.update_signal_aspect(tcbs) + advtrains.interlocking.signal.update_route_aspect(tcbs) end minetest.chat_send_player(pname, "Reset track section "..ts_id.."!") end @@ -573,7 +517,7 @@ function advtrains.interlocking.show_tcb_marker(pos) ts = ildb.get_ts(tcbs.ts_id) end if ts then - itex[connid] = ts.name + itex[connid] = ts.name or tcbs.ts_id or "???" else itex[connid] = "--EOI--" end @@ -594,6 +538,36 @@ function advtrains.interlocking.show_tcb_marker(pos) markerent[pts] = obj end +function advtrains.interlocking.remove_tcb_marker(pos) + local pts = advtrains.roundfloorpts(pos) + if markerent[pts] then + markerent[pts]:remove() + end + markerent[pts] = nil +end + +local ts_showparticles_callback = function(pos, connid, bconnid) + minetest.add_particle({ + pos = pos, + velocity = {x=0, y=0, z=0}, + acceleration = {x=0, y=0, z=0}, + expirationtime = 10, + size = 7, + vertical = true, + texture = "at_il_ts_highlight_particle.png", + glow = 6, + }) +end + +-- Spawns particles to highlight the clicked track section +-- TODO: Adapt behavior to not dumb-walk anymore +function advtrains.interlocking.highlight_track_section(pos) + local all_tcbs = ildb.get_all_tcbs_adjacent(pos, nil, ts_showparticles_callback) + for _,sigd in ipairs(all_tcbs) do + advtrains.interlocking.show_tcb_marker(sigd.p) + end +end + -- Signalling formspec - set routes a.s.o -- textlist selection temporary storage @@ -610,11 +584,10 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle local tcbs = ildb.get_tcbs(sigd) if not tcbs.signal then return end - if not tcbs.signal_name then tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p) end if not tcbs.routes then tcbs.routes = {} end - local form = "size[7,10]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).."]" + 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 @@ -648,6 +621,9 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle local strtab = {} for idx, route in ipairs(tcbs.routes) do local clr = "" + if route.smartroute_generated then + clr = "#FFFF55" + end if route.ars then clr = "#FF5555" if route.ars.default then @@ -679,14 +655,10 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle end end if hasprivs then - form = form.."button[0.5,8;2.5,1;newroute;New Route]" - form = form.."button[ 3,8;2.5,1;unassign;Unassign Signal]" - form = form.."button[ 3,9;2.5,1;influp;Influence Point]" - end - if tcbs.ars_disabled then - form = form.."button[0.5,9;2.5,1;arsenable;Enable ARS]" - else - form = form.."button[0.5,9;2.5,1;arsdisable;Disable ARS]" + 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 elseif sigd_equal(tcbs.route_origin, sigd) then -- something has gone wrong: tcbs.routeset should have been set... @@ -704,14 +676,14 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle -- always a good idea to update the signal aspect if not called_from_form_update then -- FIX prevent a callback loop - advtrains.interlocking.update_signal_aspect(tcbs) + advtrains.interlocking.signal.update_route_aspect(tcbs) end end function advtrains.interlocking.update_player_forms(sigd) for pname, tsigd in pairs(p_open_sig_form) do if advtrains.interlocking.sigd_equal(sigd, tsigd) then - advtrains.interlocking.show_signalling_form(sigd, pname, nil) + advtrains.interlocking.show_signalling_form(sigd, pname, nil, true) end end end @@ -755,7 +727,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) sel_rte = tpsi end if fields.setname and fields.name and hasprivs then - tcbs.signal_name = fields.name + if fields.name == "" then + tcbs.signal_name = nil -- do not save a signal name if it isnt used (equivalent to track sections) + else + tcbs.signal_name = fields.name + end end if tcbs.routeset and fields.cancelroute then if tcbs.routes[tcbs.routeset] and tcbs.routes[tcbs.routeset].ars then @@ -771,6 +747,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) tcbs.ars_ignore_next = nil return end + if fields.smartroute and hasprivs then + advtrains.interlocking.smartroute.init(pname, sigd) + minetest.close_formspec(pname, formname) + tcbs.ars_ignore_next = nil + return + end if sel_rte and tcbs.routes[sel_rte] then if fields.setroute then ilrs.update_route(sigd, tcbs, sel_rte) @@ -789,32 +771,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end - if fields.unassign and hasprivs then - -- unassigning the signal from the tcbs - -- only when no route is set. - -- Routes and name remain saved, in case the player wants to reassign a new signal - if not tcbs.routeset then - local signal_pos = tcbs.signal - ildb.set_sigd_for_signal(signal_pos, nil) - tcbs.signal = nil - tcbs.aspect = nil - minetest.close_formspec(pname, formname) - minetest.chat_send_player(pname, "Signal has been unassigned. Name and routes are kept for reuse.") - return - else - minetest.chat_send_player(pname, "Please cancel route first!") - end - end - if fields.influp and hasprivs then - advtrains.interlocking.show_ip_form(tcbs.signal, pname) - return + if fields.ars then + tcbs.ars_disabled = not minetest.is_yes(fields.ars) end - if tcbs.ars_disabled and fields.arsenable then - tcbs.ars_disabled = nil - end - if not tcbs.ars_disabled and fields.arsdisable then - tcbs.ars_disabled = true + if fields.dstarstrig then + tcbs.no_dst_ars_trig = not minetest.is_yes(fields.dstarstrig) end if fields.auto then |