advtrains/advtrains_interlocking/tcb_ts_ui.lua

376 lines
11 KiB
Lua
Raw Normal View History

-- Track Circuit Breaks and Track Sections - Player interaction
local players_assign_tcb = {}
local players_link_ts = {}
local lntrans = { "A", "B" }
local function sigd_to_string(sigd)
return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
end
minetest.register_node("advtrains_interlocking:tcb_node", {
drawtype = "mesh",
paramtype="light",
paramtype2="facedir",
walkable = true,
selection_box = {
type = "fixed",
fixed = {-1/6, -1/2, -1/6, 1/6, 1/4, 1/6},
},
mesh = "at_il_tcb_node.obj",
tiles = {"at_il_tcb_node.png"},
description="Track Circuit Break",
sunlight_propagates=true,
groups = {
cracky=3,
not_blocking_trains=1,
--save_in_at_nodedb=2,
},
after_place_node = function(pos, node, player)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Unconfigured Track Circuit Break, right-click to assign.")
end,
on_rightclick = function(pos, node, player)
local meta = minetest.get_meta(pos)
local tcbpts = meta:get_string("tcb_pos")
local pname = player:get_player_name()
if tcbpts ~= "" then
local tcbpos = minetest.string_to_pos(tcbpts)
advtrains.interlocking.show_tcb_form(tcbpos, pname)
else
--unconfigured
--TODO security
minetest.chat_send_player(pname, "Configuring TCB: Please punch the rail you want to assign this TCB to.")
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,
can_dig = function(pos, player)
-- Those markers can only be dug when all adjacent TS's are set
-- as EOI.
local meta = minetest.get_meta(pos)
local tcbpts = meta:get_string("tcb_pos")
if tcbpts ~= "" then
local tcbpos = minetest.string_to_pos(tcbpts)
local tcb = advtrains.interlocking.db.get_tcb(tcbpos)
if not tcb then return true end
for connid=1,2 do
if tcb[connid].ts_id then
return false
end
end
end
return true
end,
after_dig_node = function(pos, oldnode, oldmetadata, player)
if not oldmetadata or not oldmetadata.fields then return end
local tcbpts = oldmetadata.fields.tcb_pos
if tcbpts ~= "" then
local tcbpos = minetest.string_to_pos(tcbpts)
advtrains.interlocking.db.remove_tcb(tcbpos)
end
end,
})
minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
local pname = player:get_player_name()
local tcbnpos = players_assign_tcb[pname]
if tcbnpos then
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 = advtrains.interlocking.db.create_tcb(pos)
if not ok then
minetest.chat_send_player(pname, "Configuring TCB: TCB already exists at this position. Aborted.")
end
advtrains.interlocking.db.sync_tcb_neighbors(pos, 1)
advtrains.interlocking.db.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")
else
minetest.chat_send_player(pname, "Configuring TCB: This is not a normal two-connection rail! Aborted.")
end
else
minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.")
end
players_assign_tcb[pname] = nil
end
end)
-- TCB Form
local function mktcbformspec(tcbs, btnpref, offset, pname)
local form = ""
local ts
if tcbs.ts_id then
ts = advtrains.interlocking.db.get_ts(tcbs.ts_id)
end
if ts then
form = form.."label[0.5,"..offset..";Side "..btnpref..": "..ts.name.."]"
form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;Show track section]"
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]"
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
return form
end
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]"
form = form .. mktcbformspec(tcb[1], "A", 1, pname)
form = form .. mktcbformspec(tcb[2], "B", 4, pname)
minetest.show_formspec(pname, "at_il_tcbconfig_"..minetest.pos_to_string(pos), form)
advtrains.interlocking.show_tcb_marker(pos)
end
--helper: length of nil table is 0
local function nlen(t)
if not t then return 0 end
return #t
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local pname = player:get_player_name()
local pts = string.match(formname, "^at_il_tcbconfig_(.+)$")
local pos
if pts then
pos = minetest.string_to_pos(pts)
end
if pos and not fields.quit then
local tcb = advtrains.interlocking.db.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}
for connid=1,2 do
local tcbs = tcb[connid]
if tcbs.ts_id then
if f_gotots[connid] then
advtrains.interlocking.show_ts_form(tcbs.ts_id, pname)
return
end
if f_update[connid] then
advtrains.interlocking.db.sync_tcb_neighbors(pos, connid)
end
if f_remove[connid] then
advtrains.interlocking.db.remove_from_interlocking({p=pos, s=connid})
end
else
if f_makeil[connid] then
advtrains.interlocking.db.create_ts({p=pos, s=connid})
advtrains.interlocking.db.sync_tcb_neighbors(pos, connid)
end
-- non-interlocked
if f_setfree[connid] then
tcbs.section_free = true
end
if f_setlocked[connid] then
tcbs.section_free = nil
end
end
end
advtrains.interlocking.show_tcb_form(pos, pname)
end
end)
-- TS Formspec
function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
local ts = advtrains.interlocking.db.get_ts(ts_id)
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;"..ts.name.."]"
form = form.."button[5.5,1.7;1,1;setname;Set]"
local hint
local strtab = {}
for idx, sigd in ipairs(ts.tc_breaks) do
strtab[#strtab+1] = minetest.formspec_escape(sigd_to_string(sigd))
advtrains.interlocking.show_tcb_marker(sigd.p)
end
form = form.."textlist[0.5,3;5,3;tcblist;"..table.concat(strtab, ",").."]"
if players_link_ts[pname] then
local other_id = players_link_ts[pname]
local other_ts = advtrains.interlocking.db.get_ts(other_id)
if other_ts then
form = form.."button[5.5,3;3.5,1;mklink;Join with "..other_ts.name.."]"
form = form.."button[9 ,3;0.5,1;cancellink;X]"
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.."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
2018-06-29 16:16:55 +02:00
-- occupying trains
if ts.trains and #ts.trains>0 then
form = form.."label[0.5,6.1;Trains on this section:]"
form = form.."textlist[0.5,6.7;3,2;trnlist;"..table.concat(ts.trains, ",").."]"
else
form = form.."label[0.5,6.1;No trains on this section.]"
end
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.]"
--form = form.."label[0.5,1;Trying to unlink a TCB directly connected to this track will not work.]"
end
minetest.show_formspec(pname, "at_il_tsconfig_"..ts_id, form)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local pname = player:get_player_name()
local ts_id = string.match(formname, "^at_il_tsconfig_(.+)$")
if ts_id and not fields.quit then
local ts = advtrains.interlocking.db.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
end
if players_link_ts[pname] then
if fields.cancellink then
players_link_ts[pname] = nil
elseif fields.mklink then
advtrains.interlocking.db.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
advtrains.interlocking.db.remove_from_interlocking(ts.tc_breaks[sel_tcb])
end
if fields.link then
players_link_ts[pname] = ts_id
end
if fields.dissolve then
advtrains.interlocking.db.dissolve_ts(ts_id)
minetest.close_formspec(pname, formname)
return
end
if fields.setname then
ts.name = fields.name
if ts.name == "" then
ts.name = "Section "..ts_id
end
end
advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
end
end)
-- TCB marker entities
-- table with objectRefs
local markerent = {}
minetest.register_entity("advtrains_interlocking:tcbmarker", {
visual = "mesh",
mesh = "trackplane.b3d",
textures = {"at_il_tcb_marker.png"},
collisionbox = {-1,-0.5,-1, 1,-0.4,1},
visual_size = {x=10, y=10},
on_punch = function(self)
self.object:remove()
end,
on_rightclick = function(self, player)
if self.tcbpos and player then
advtrains.interlocking.show_tcb_form(self.tcbpos, player:get_player_name())
end
end,
get_staticdata = function() return "STATIC" end,
on_activate = function(self, sdata) if sdata=="STATIC" then self.object:remove() end end,
static_save = false,
})
function advtrains.interlocking.show_tcb_marker(pos)
2018-06-29 16:16:55 +02:00
--atdebug("showing tcb marker",pos)
local tcb = advtrains.interlocking.db.get_tcb(pos)
if not tcb then return end
local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
if not node_ok then return end
local yaw = advtrains.conn_angle_median(conns[2].c, conns[1].c)
local itex = {}
for connid=1,2 do
local tcbs = tcb[connid]
local ts
if tcbs.ts_id then
ts = advtrains.interlocking.db.get_ts(tcbs.ts_id)
end
if ts then
itex[connid] = ts.name
else
itex[connid] = "--EOI--"
end
end
local pts = advtrains.roundfloorpts(pos)
if markerent[pts] then
markerent[pts]:remove()
end
local obj = minetest.add_entity(pos, "advtrains_interlocking:tcbmarker")
if not obj then return end
obj:set_yaw(yaw)
obj:set_properties({
infotext = "A = "..itex[1].."\nB = "..itex[2]
})
local le = obj:get_luaentity()
if le then le.tcbpos = pos end
markerent[pts] = obj
end