aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking/signal_api.lua
diff options
context:
space:
mode:
authororwell <orwell@bleipb.de>2024-05-23 00:58:24 +0200
committerorwell <orwell@bleipb.de>2024-05-23 00:58:24 +0200
commit6fd845baec0f5aa8b7cdee1adf8d05061a643242 (patch)
treef1bd25e0d5d0a5dbd7947a43d670c6f1377534c4 /advtrains_interlocking/signal_api.lua
parent852da6bcaeeb8c39ce73639ef64f10ebc5b127b0 (diff)
downloadadvtrains-6fd845baec0f5aa8b7cdee1adf8d05061a643242.tar.gz
advtrains-6fd845baec0f5aa8b7cdee1adf8d05061a643242.tar.bz2
advtrains-6fd845baec0f5aa8b7cdee1adf8d05061a643242.zip
Connect the ropes, start on making the UI work
Diffstat (limited to 'advtrains_interlocking/signal_api.lua')
-rw-r--r--advtrains_interlocking/signal_api.lua220
1 files changed, 43 insertions, 177 deletions
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index d27a045..5216594 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -5,9 +5,15 @@ local F = advtrains.formspec
local signal = {}
signal.MASP_HALT = {
- name = "halt",
- description = "HALT",
- halt = true,
+ name = nil,
+ speed = nil,
+ remote = nil,
+}
+
+signal.MASP_FREE = {
+ name = "_free",
+ speed = -1,
+ remote = nil,
}
signal.ASPI_HALT = {
@@ -50,11 +56,12 @@ Note that once apply_aspect returns, there is no need for advtrains anymore to q
When the signal, for any reason, wants to change its aspect by itself *without* going through the signal API then
it should update the aspect info cache by calling advtrains.interlocking.signal.update_aspect_info(pos)
-Note that the apply_aspect function MUST accept the following main aspect, even if it is not defined in the main_aspects table:
-{ name = "halt", halt = true }
-It should cause the signal to show its most restrictive aspect. Typically it is a halt aspect, but e.g. for distant-only
+Apply_aspect may also receive nil as the main aspect. It usually means that the signal is not assigned to anything particular,
+and it should cause the signal to show its most restrictive aspect. Typically it is a halt aspect, but e.g. for distant-only
signals this would be "expect stop".
+Main aspect names starting with underscore (e.g. "_default") are reserved and must not be used!
+
== Aspect Info ==
The actual signal aspect in the already-known format. This is what the trains use to determine halt/proceed and speed.
asp = {
@@ -152,7 +159,7 @@ end
-- - Storing the main aspect and dst pos for this signal permanently (until next change)
-- - Assigning the distant signal for this signal
-- - Calling apply_aspect() in the signal's node definition to make the signal show the aspect
--- - Calling apply_aspect() again whenever the distant signal changes its aspect
+-- - Calling apply_aspect() again whenever the remote signal changes its aspect
-- - Notifying this signal's distant signals about changes to this signal (unless skip_dst_notify is specified)
function signal.set_aspect(pos, main_asp_name, main_asp_speed, rem_pos, skip_dst_notify)
local main_pts = advtrains.encode_pos(pos)
@@ -252,10 +259,7 @@ function signal.get_aspect(pos)
end
local function cache_mainaspects(ndefat)
- ndefat.main_aspects_lookup = {
- -- always define halt aspect
- halt = signal.MASP_HALT
- }
+ ndefat.main_aspects_lookup = {}
for _,ma in ipairs(ndefat.main_aspects) do
ndefat.main_aspects_lookup[ma.name] = ma
end
@@ -264,7 +268,7 @@ end
function signal.get_aspect_internal(pos, aspt)
if not aspt then
-- oh, no main aspect, nevermind
- return nil, aspt.remote, nil
+ return nil, nil, nil
end
atdebug("get_aspect_internal",pos,aspt)
-- look aspect in nodedef
@@ -277,6 +281,10 @@ function signal.get_aspect_internal(pos, aspt)
cache_mainaspects(ndefat)
end
local masp = ndefat.main_aspects_lookup[aspt.name]
+ -- special handling for the default free aspect ("_free")
+ if aspt.name == "_free" then
+ masp = ndefat.main_aspects[1]
+ end
if not masp then
atwarn(pos,"invalid main aspect",aspt.name,"valid are",ndefat.main_aspects_lookup)
return nil, aspt.remote, node, ndef
@@ -355,10 +363,30 @@ end
function signal.update_route_aspect(tcbs, skip_dst_notify)
if tcbs.signal then
local asp = tcbs.aspect or signal.MASP_HALT
- signal.set_aspect(tcbs.signal, asp, skip_dst_notify)
+ signal.set_aspect(tcbs.signal, asp.name, asp.speed, asp.remote, skip_dst_notify)
end
end
+-- Returns how capable the signal is with regards to aspect setting
+-- 0: not a signal at all
+-- 1: signal has get_aspect_info() but the aspect is not variable (e.g. a sign)
+-- 2: signal has apply_aspect() but does not have main aspects (e.g. a pure distant signal)
+-- 3: Full capabilities, signal has main aspects and can be used as main/shunt signal (can be start/endpoint of a route)
+function signal.get_signal_cap_level(pos)
+ local node = advtrains.ndb.get_node_or_nil(pos)
+ local ndef = node and minetest.registered_nodes[node.name]
+ local ndefat = ndef and ndef.advtrains
+ if ndefat and ndefat.get_aspect_info then
+ if ndefat.apply_aspect then
+ if ndefat.main_aspects then
+ return 3
+ end
+ return 2
+ end
+ return 1
+ end
+ return 0
+end
----------------
@@ -366,7 +394,7 @@ function signal.can_dig(pos)
return not advtrains.interlocking.db.get_sigd_for_signal(pos)
end
-function advtrains.interlocking.signal_after_dig(pos)
+function signal.after_dig(pos)
-- TODO clear influence point
advtrains.interlocking.signal.clear_aspect(pos)
end
@@ -374,169 +402,7 @@ end
function signal.on_rightclick(pos, node, player, itemstack, pointed_thing)
local pname = player:get_player_name()
local control = player:get_player_control()
- if control.aux1 then
- advtrains.interlocking.show_ip_form(pos, pname)
- return
- end
- advtrains.interlocking.show_signal_form(pos, node, pname)
-end
-
-function advtrains.interlocking.show_signal_form(pos, node, pname)
- local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos)
- if sigd then
- advtrains.interlocking.show_signalling_form(sigd, pname)
- else
- local ndef = minetest.registered_nodes[node.name]
- if ndef.advtrains and ndef.advtrains.set_aspect then
- -- permit to set aspect manually
- local function callback(pname, aspect)
- signal.set_aspect(pos, aspect)
- end
- local isasp = advtrains.interlocking.signal_get_aspect(pos, node)
-
- advtrains.interlocking.show_signal_aspect_selector(
- pname,
- ndef.advtrains.supported_aspects,
- pos, callback,
- isasp)
- else
- --static signal - only IP
- advtrains.interlocking.show_ip_form(pos, pname)
- end
- end
-end
-
-local players_assign_ip = {}
-
-local function ipmarker(ipos, connid)
- local node_ok, conns, rhe = advtrains.get_rail_info_at(ipos, advtrains.all_tracktypes)
- if not node_ok then return end
- local yaw = advtrains.dir_to_angle(conns[connid].c)
-
- -- using tcbmarker here
- local obj = minetest.add_entity(vector.add(ipos, {x=0, y=0.2, z=0}), "advtrains_interlocking:tcbmarker")
- if not obj then return end
- obj:set_yaw(yaw)
- obj:set_properties({
- textures = { "at_il_signal_ip.png" },
- })
-end
-
-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 ipform, pts, connid = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 0.5, 7)
- local form = {
- "formspec_version[4]",
- "size[8,2.25]",
- ipform,
- }
- 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
+ advtrains.interlocking.show_signal_form(pos, node, pname, control.aux1)
end
-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
- 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
- advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields)
- advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields)
- end
-end)
-
--- inits the signal IP assignment process
-function signal.init_ip_assign(pos, pname)
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- --remove old IP
- --advtrains.interlocking.db.clear_ip_by_signalpos(pos)
- minetest.chat_send_player(pname, "Configuring Signal: Please look in train's driving direction and punch rail to set influence point.")
-
- players_assign_ip[pname] = pos
-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
- -- IP assignment
- local signalpos = players_assign_ip[pname]
- if signalpos then
- if vector.distance(pos, signalpos)<=50 then
- local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
- if node_ok and #conns == 2 then
-
- local yaw = player:get_look_horizontal()
- local plconnid = advtrains.yawToClosestConn(yaw, conns)
-
- -- add assignment if not already present.
- local pts = advtrains.roundfloorpts(pos)
- if not advtrains.interlocking.db.get_ip_signal_asp(pts, plconnid) then
- advtrains.interlocking.db.set_ip_signal(pts, plconnid, signalpos)
- ipmarker(pos, plconnid)
- minetest.chat_send_player(pname, "Configuring Signal: Successfully set influence point")
- else
- minetest.chat_send_player(pname, "Configuring Signal: Influence point of another signal is already present!")
- end
- else
- minetest.chat_send_player(pname, "Configuring Signal: This is not a normal two-connection rail! Aborted.")
- end
- else
- minetest.chat_send_player(pname, "Configuring Signal: Node is too far away. Aborted.")
- end
- players_assign_ip[pname] = nil
- end
-end)
-
-
advtrains.interlocking.signal = signal