summaryrefslogtreecommitdiff
path: root/advtrains_interlocking
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains_interlocking')
-rw-r--r--advtrains_interlocking/approach.lua113
-rw-r--r--advtrains_interlocking/ars.lua155
-rw-r--r--advtrains_interlocking/database.lua599
-rw-r--r--advtrains_interlocking/demosignals.lua111
-rw-r--r--advtrains_interlocking/depends.txt2
-rw-r--r--advtrains_interlocking/init.lua30
-rw-r--r--advtrains_interlocking/models/at_il_tcb_node.obj248
-rw-r--r--advtrains_interlocking/route_prog.lua548
-rw-r--r--advtrains_interlocking/route_ui.lua152
-rw-r--r--advtrains_interlocking/routesetting.lua357
-rw-r--r--advtrains_interlocking/settingtypes.txt4
-rw-r--r--advtrains_interlocking/signal_api.lua546
-rw-r--r--advtrains_interlocking/tcb_ts_ui.lua789
-rw-r--r--advtrains_interlocking/textures/advtrains_dtrack_npr_placer.pngbin1238 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/advtrains_dtrack_shared_npr.pngbin3176 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_route_end.pngbin451 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_route_lock.pngbin534 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_route_lock_edit.pngbin533 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_route_set.pngbin398 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_route_start.pngbin380 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_routep_advance.pngbin304 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_routep_end_here.pngbin243 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_routep_end_over.pngbin281 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_routep_end_over_last.pngbin277 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_signal_asp_danger.pngbin247 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_signal_asp_free.pngbin245 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_signal_asp_slow.pngbin245 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_signal_ip.pngbin285 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_signal_off.pngbin236 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_tcb_marker.pngbin308 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_tcb_node.pngbin279 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_tool.pngbin337 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_turnout_cr_l.pngbin314 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_turnout_cr_r.pngbin298 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_turnout_free.pngbin367 -> 0 bytes
-rw-r--r--advtrains_interlocking/textures/at_il_turnout_st.pngbin229 -> 0 bytes
-rw-r--r--advtrains_interlocking/tool.lua66
-rw-r--r--advtrains_interlocking/train_sections.lua199
-rw-r--r--advtrains_interlocking/tsr_rail.lua56
39 files changed, 0 insertions, 3975 deletions
diff --git a/advtrains_interlocking/approach.lua b/advtrains_interlocking/approach.lua
deleted file mode 100644
index 8e90b5a..0000000
--- a/advtrains_interlocking/approach.lua
+++ /dev/null
@@ -1,113 +0,0 @@
--- Interlocking counterpart of LZB, which has been moved into the core...
--- Registers LZB callback for signal management.
-
---[[
-usage of lzbdata:
-{
- travsht = boolean indicating whether the train will be a shunt move at "trav"
- travspd = speed restriction at end of traverser
- travwspd = warning speed res.t
-}
-]]
-
-local SHUNT_SPEED_MAX = advtrains.SHUNT_SPEED_MAX
-
-local il = advtrains.interlocking
-
-local function get_over_function(speed, shunt)
- return function(pos, id, train, index, speed, lzbdata)
- if speed == 0 and minetest.settings:get_bool("at_il_force_lzb_halt") then
- atwarn(id,"overrun LZB 0 restriction (red signal) ",pos)
- -- Set train 1 index backward. Hope this does not lead to bugs...
- train.index = index - 0.5
- train.velocity = 0
- train.ctrl.lzb = 0
- minetest.after(0, advtrains.invalidate_path, id)
- else
- train.speed_restriction = speed
- train.is_shunt = shunt
- end
- end
-end
-
-advtrains.tnc_register_on_approach(function(pos, id, train, index, lzbdata)
-
- --atdebug(id,"IL ApprC",pos,index,lzbdata)
- --train.debug = advtrains.print_concat_table({train.is_shunt,"|",index,"|",lzbdata})
-
- local pts = advtrains.roundfloorpts(pos)
- local cn = train.path_cn[index]
- local travsht = lzbdata.travsht
-
- if travsht==nil then
- travsht = train.is_shunt
- end
-
- local travspd = lzbdata.travspd
- local travwspd = lzbdata.travwspd
-
- -- check for signal
- local asp, spos = il.db.get_ip_signal_asp(pts, cn)
-
- -- do ARS if needed
- if spos then
- --atdebug(id,"IL Spos (ARS)",spos,asp)
- local sigd = il.db.get_sigd_for_signal(spos)
- if sigd then
- il.ars_check(sigd, train)
- end
- end
- --atdebug("trav: ",pos, cn, asp, spos, "travsht=", lzb.travsht)
- local lspd
- if asp then
- --atdebug(id,"IL Signal",spos,asp)
- local nspd = 0
- --interpreting aspect and determining speed to proceed
- if travsht then
- --shunt move
- if asp.shunt.free then
- nspd = SHUNT_SPEED_MAX
- elseif asp.shunt.proceed_as_main and asp.main.free then
- nspd = asp.main.speed
- travsht = false
- end
- else
- --train move
- if asp.main.free then
- nspd = asp.main.speed
- elseif asp.shunt.free then
- nspd = SHUNT_SPEED_MAX
- travsht = true
- end
- end
- -- nspd can now be: 1. !=0: new speed restriction, 2. =0: stop here or 3. nil: keep travspd
- if nspd then
- if nspd == -1 then
- travspd = nil
- else
- travspd = nspd
- end
- end
-
- local nwspd = asp.info.w_speed
- if nwspd then
- if nwspd == -1 then
- travwspd = nil
- else
- travwspd = nwspd
- end
- end
- --atdebug("ns,wns,ts,wts", nspd, nwspd, travspd, travwspd)
- lspd = travspd
- if travwspd and (not lspd or lspd>travwspd) then
- lspd = travwspd
- end
-
- local udata = {signal_pos = spos}
- local callback = get_over_function(lspd, travsht)
- advtrains.lzb_add_checkpoint(train, index, lspd, callback, udata)
- end
- lzbdata.travsht = travsht
- lzbdata.travspd = travspd
- lzbdata.travwspd = travwspd
-end)
diff --git a/advtrains_interlocking/ars.lua b/advtrains_interlocking/ars.lua
deleted file mode 100644
index 434ae2c..0000000
--- a/advtrains_interlocking/ars.lua
+++ /dev/null
@@ -1,155 +0,0 @@
--- ars.lua
--- automatic routesetting
-
---[[
- The "ARS table" and its effects:
- Every route has (or can have) an associated ARS table. This can either be
- ars = { [n] = {ln="<line>"}/{rc="<routingcode>"}/{c="<a comment>"} }
- a list of rules involving either line or routingcode matchers (or comments, those are ignored)
- The first matching rule determines the route to set.
- - or -
- ars = {default = true}
- this means that all trains that no other rule matches on should use this route
-
- Compound ("and") conjunctions are not supported (--TODO should they?)
-
- For editing, those tables are transformed into lines in a text area:
- {ln=...} -> LN ...
- {rc=...} -> RC ...
- {c=...} -> #...
- {default=true} -> *
- See also route_ui.lua
-]]
-
-local il = advtrains.interlocking
-
--- The ARS data are saved in a table format, but are entered in text format. Utility functions to transform between both.
-function il.ars_to_text(arstab)
- if not arstab then
- return ""
- end
-
- local txt = {}
-
- for i, arsent in ipairs(arstab) do
- local n = ""
- if arsent.n then
- n = "!"
- end
- if arsent.ln then
- txt[#txt+1] = n.."LN "..arsent.ln
- elseif arsent.rc then
- txt[#txt+1] = n.."RC "..arsent.rc
- elseif arsent.c then
- txt[#txt+1] = "#"..arsent.c
- end
- end
-
- if arstab.default then
- return "*\n" .. table.concat(txt, "\n")
- end
- return table.concat(txt, "\n")
-end
-
-function il.text_to_ars(t)
- if t=="" then
- return nil
- elseif t=="*" then
- return {default=true}
- end
- local arstab = {}
- for line in string.gmatch(t, "[^\r\n]+") do
- if line=="*" then
- arstab.default = true
- else
- local c, v = string.match(line, "^(...?)%s(.*)$")
- if c and v then
- local n = nil
- if string.sub(c,1,1) == "!" then
- n = true
- c = string.sub(c,2)
- end
- local tt=string.upper(c)
- if tt=="LN" then
- arstab[#arstab+1] = {ln=v, n=n}
- elseif tt=="RC" then
- arstab[#arstab+1] = {rc=v, n=n}
- end
- else
- local ct = string.match(line, "^#(.*)$")
- if ct then arstab[#arstab+1] = {c = ct} end
- end
- end
- end
- return arstab
-end
-
-local function find_rtematch(routes, train)
- local default
- for rteid, route in ipairs(routes) do
- if route.ars then
- if route.ars.default then
- default = rteid
- else
- if il.ars_check_rule_match(route.ars, train) then
- return rteid
- end
- end
- end
- end
- return default
-end
-
--- Checks whether ARS rule explicitly matches. This does not take into account the "default" field, since a wider context is required for this.
--- Returns the rule number that matched, or nil if nothing matched
-function il.ars_check_rule_match(ars, train)
- if not ars then
- return nil
- end
- local line = train.line
- local routingcode = train.routingcode
- for arskey, arsent in ipairs(ars) do
- --atdebug(arsent, line, routingcode)
- if arsent.n then
- -- rule is inverse...
- if arsent.ln and (not line or arsent.ln ~= line) then
- return arskey
- elseif arsent.rc and (not routingcode or not string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true)) then
- return arskey
- end
- return nil
- end
-
- if arsent.ln and line and arsent.ln == line then
- return arskey
- elseif arsent.rc and routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true) then
- return arskey
- end
- end
- return nil
-end
-
-function advtrains.interlocking.ars_check(sigd, train)
- local tcbs = il.db.get_tcbs(sigd)
- if not tcbs or not tcbs.routes then return end
-
- if tcbs.ars_disabled then
- -- No-ARS mode of signal.
- -- ignore...
- return
- end
-
- if tcbs.routeset then
- -- ARS is not in effect when a route is already set
- -- just "punch" routesetting, just in case callback got lost.
- minetest.after(0, il.route.update_route, sigd, tcbs, nil, nil)
- return
- end
-
- local rteid = find_rtematch(tcbs.routes, train)
- if rteid then
- --delay routesetting, it should not occur inside train step
- -- using after here is OK because that gets called on every path recalculation
- minetest.after(0, il.route.update_route, sigd, tcbs, rteid, nil)
- end
-end
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
deleted file mode 100644
index e2c9edc..0000000
--- a/advtrains_interlocking/database.lua
+++ /dev/null
@@ -1,599 +0,0 @@
--- interlocking/database.lua
--- saving the location of TCB's, their neighbors and their state
---[[
-
-== THIS COMMENT IS PARTIALLY INCORRECT AND OUTDATED! ==
-
-The interlocking system is based on track circuits.
-Track circuit breaks must be manually set by the user. Signals must be assigned to track circuit breaks and to a direction(connid).
-To simplify the whole system, there is no overlap.
-== Trains ==
-Trains always occupy certain track circuits. These are shown red in the signalbox view (TRAIN occupation entry).
-== Database storage ==
-The things that are actually saved are the Track Circuit Breaks. Each TCB holds a list of the TCBs that are adjacent in each direction.
-TC occupation/state is then saved inside each (TCB,Direction) and held in sync across all TCBs adjacent to this one. If something should not be in sync,
-all entries are merged to perform the most restrictive setup.
-== Traverser function ==
-To determine and update the list of neighboring TCBs, we need a traverser function.
-It will start at one TCB in a specified direction (connid) and use get_adjacent_rail to crawl along the track. When encountering a turnout or a crossing,
-it needs to branch(call itself recursively) to find all required TCBs. Those found TCBs are then saved in a list as tuples (TCB,Dir)
-In the last step, they exchange their neighbors.
-== TC states ==
-A track circuit does not have a state as such, but has more or less a list of "reservations"
-type can be one of these:
-TRAIN See Trains obove
-ROUTE Route set from a signal, but no train has yet passed that signal.
-Not implemented (see note by reversible): OWNED - former ROUTE segments that a train has begun passing (train_id assigned)
- - Space behind a train up to the next signal, when a TC is set as REVERSIBLE
-Certain TCs can be marked as "allow call-on".
-== Route setting: ==
-Routes are set from a signal (the entry signal) to another signal facing the same direction (the exit signal)
-Remember that signals are assigned to a TCB and a connid.
-Whenever this is done, the following track circuits are set "reserved" by the train by saving the entry signal's ID:
-- all TCs on the direct way of the route - set as ROUTE
-Route setting fails whenever any TC that we want to set ROUTE to is already set ROUTE or TRAIN from another signal (except call-on, see below)
-Apart from this, we need to set turnouts
-- Turnouts on the track are set held as ROUTE
-- Turnouts that purpose as flank protection are set held as FLANK (NOTE: left as an idea for later, because it's not clear how to do this properly without an engineer)
-Note: In SimSig, it is possible to set a route into an still occupied section on the victoria line sim. (at the depot exit at seven sisters), although
- there are still segments set ahead of the first train passing, remaining from another route.
- Because our system will be able to remember "requested routes" and set them automatically once ready, this is not necessary here.
-== Call-On/Multiple Trains ==
-It will be necessary to join and split trains using call-on routes. A call-on route may be set when:
-- there are no ROUTE reservations
-- there are TRAIN reservations only inside TCs that have "allow call-on" set
-== TC Properties ==
-Note: Reversible property will not be implemented, assuming everything as non-rev.
-This is sufficient to cover all use cases, and is done this way in reality.
- REVERSIBLE - Whether trains are allowed to reverse while on track circuit
- This property is supposed to be set for station tracks, where there is a signal at each end, and for sidings.
- It should in no case be set for TCs covering turnouts, or for main running lines.
- When a TC is not set as reversible, the OWNED status is cleared from the TC right after the train left it,
- to allow other trains to pass it.
- If it is set reversible, interlocking will keep the OWNED state behind the train up to the next signal, clearing it
- as soon as the train passes another signal or enters a non-reversible section.
-CALL_ON_ALLOWED - Whether this TC being blocked (TRAIN or ROUTE) does not prevent shunt routes being set through this TC
-== More notes ==
-- It may not be possible to switch turnouts when their TC has any state entry
-
-== Route releasing (TORR) ==
-A train passing through a route happens as follows:
-Route set from entry to exit signal
-Train passes entry signal and enters first TC past the signal
--> Route from signal cleared (TCs remain locked)
--> ROUTE status of first TC past signal cleared
-Train continues along the route.
-Whenever train leaves a TC
--> Clearing any routes set from this TC outward recursively - see "Reversing problem"
-Whenever train enters a TC
--> Clear route status from the just entered TC
-Note that this prohibits by design that the train clears the route ahead of it.
-== Reversing Problem ==
-Encountered at the Royston simulation in SimSig. It is solved there by imposing a time limit on the set route. Call-on routes can somehow be set anyway.
-Imagine this setup: (T=Train, R=Route, >=in_dir TCB)
- O-| Royston P2 |-O
-T->---|->RRR-|->RRR-|--
-Train T enters from the left, the route is set to the right signal. But train is supposed to reverse here and stops this way:
- O-| Royston P2 |-O
-------|-TTTT-|->RRR-|--
-The "Route" on the right is still set. Imposing a timeout here is a thing only professional engineers can determine, not an algorithm.
- O-| Royston P2 |-O
-<-T---|------|->RRR-|--
-The train has left again, while route on the right is still set.
-So, we have to clear the set route when the train has left the left TC.
-This does not conflict with call-on routes, because both station tracks are set as "allow call-on"
-Because none of the routes extends past any non-call-on sections, call-on route would be allowed here, even though the route
-is locked in opposite direction at the time of routesetting.
-Another case of this:
---TTT/--|->RRR--
-The / here is a non-interlocked turnout (to a non-frequently used siding). For some reason, there is no exit node there,
-so the route is set to the signal at the right end. The train is taking the exit to the siding and frees the TC, without ever
-having touched the right TC.
-]]--
-
-local TRAVERSER_LIMIT = 1000
-
-
-local ildb = {}
-
-local track_circuit_breaks = {}
-local track_sections = {}
-
--- Assignment of signals to TCBs
-local signal_assignments = {}
-
--- track+direction -> signal position
-local influence_points = {}
-
-advtrains.interlocking.npr_rails = {}
-
-
-function ildb.load(data)
- if not data then return end
- if data.tcbs then
- track_circuit_breaks = data.tcbs
- end
- if data.ts then
- track_sections = data.ts
- end
- if data.signalass then
- signal_assignments = data.signalass
- end
- if data.rs_locks then
- advtrains.interlocking.route.rte_locks = data.rs_locks
- end
- if data.rs_callbacks then
- advtrains.interlocking.route.rte_callbacks = data.rs_callbacks
- end
- if data.influence_points then
- influence_points = data.influence_points
- end
- if data.npr_rails then
- advtrains.interlocking.npr_rails = data.npr_rails
- end
-end
-
-function ildb.save()
- return {
- tcbs = track_circuit_breaks,
- ts=track_sections,
- signalass = signal_assignments,
- rs_locks = advtrains.interlocking.route.rte_locks,
- rs_callbacks = advtrains.interlocking.route.rte_callbacks,
- influence_points = influence_points,
- npr_rails = advtrains.interlocking.npr_rails,
- }
-end
-
---
---[[
-TCB data structure
-{
-[1] = { -- Variant: with adjacent TCs.
- ts_id = <id> -- ID of the assigned track section
- signal = <pos> -- optional: when set, routes can be set from this tcb/direction and signal
- -- aspect will be set accordingly.
- routeset = <index in routes> -- Route set from this signal. This is the entry that is cleared once
- -- train has passed the signal. (which will set the aspect to "danger" again)
- route_committed = <boolean> -- When setting/requesting a route, routetar will be set accordingly,
- -- 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 = <asp> -- The aspect the signal should show. If this is nil, should show the most restrictive aspect (red)
- signal_name = <string> -- The human-readable name of the signal, only for documenting purposes
- routes = { <route definition> } -- a collection of routes from this signal
- route_auto = <boolean> -- When set, we will automatically re-set the route (designated by routeset)
-},
-[2] = { -- Variant: end of track-circuited area (initial state of TC)
- ts_id = nil, -- this is the indication for end_of_interlocking
- section_free = <boolean>, --this can be set by an exit node via mesecons or atlatc,
- -- or from the tc formspec.
-}
-}
-
-Track section
-[id] = {
- name = "Some human-readable name"
- tc_breaks = { <signal specifier>,... } -- Bounding TC's (signal specifiers)
- -- Can be direct ends (auto-detected), conflicting routes or TCBs that are too far away from each other
- route = {
- origin = <signal>, -- route origin
- entry = <sigd>, -- supposed train entry point
- rsn = <string>,
- first = <bool>
- }
- route_post = {
- locks = {[n] = <pts>}
- next = <sigd>
- }
- -- Set whenever a route has been set through this TC. It saves the origin tcb id and side
- -- (=the origin signal). rsn is some description to be shown to the user
- -- first says whether to clear the routesetting status from the origin signal.
- -- locks contains the positions where locks are held by this ts.
- -- 'route' is cleared when train enters the section, while 'route_post' cleared when train leaves section.
- trains = {<id>, ...} -- Set whenever a train (or more) reside in this TC
-}
-
-
-Signal specifier (sigd) (a pair of TCB/Side):
-{p = <pos>, s = <1/2>}
-
-Signal Assignments: reverse lookup of signals assigned to TCBs
-signal_assignments = {
-[<signal pts>] = <sigd>
-}
-]]
-
-
---
-function ildb.create_tcb(pos)
- local new_tcb = {
- [1] = {},
- [2] = {},
- }
- local pts = advtrains.roundfloorpts(pos)
- if not track_circuit_breaks[pts] then
- track_circuit_breaks[pts] = new_tcb
- return true
- else
- return false
- end
-end
-
-function ildb.get_tcb(pos)
- local pts = advtrains.roundfloorpts(pos)
- return track_circuit_breaks[pts]
-end
-
-function ildb.get_tcbs(sigd)
- local tcb = ildb.get_tcb(sigd.p)
- if not tcb then return nil end
- return tcb[sigd.s]
-end
-
-
-function ildb.create_ts(sigd)
- local tcbs = ildb.get_tcbs(sigd)
- local id = advtrains.random_id()
-
- while track_sections[id] do
- id = advtrains.random_id()
- end
-
- track_sections[id] = {
- name = "Section "..id,
- tc_breaks = { sigd }
- }
- tcbs.ts_id = id
-end
-
-function ildb.get_ts(id)
- return track_sections[id]
-end
-
-
-
--- various helper functions handling sigd's
-local sigd_equal = advtrains.interlocking.sigd_equal
-local function insert_sigd_nodouble(list, sigd)
- for idx, cmp in pairs(list) do
- if sigd_equal(sigd, cmp) then
- return
- end
- end
- table.insert(list, sigd)
-end
-
-
--- This function will actually handle the node that is in connid direction from the node at pos
--- so, this needs the conns of the node at pos, since these are already calculated
-local function traverser(found_tcbs, pos, conns, connid, count, brk_when_found_n)
- local adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, conns, connid, advtrains.all_tracktypes)
- if not adj_pos then
- --atdebug("Traverser found end-of-track at",pos, connid)
- return
- end
- -- look whether there is a TCB here
- if #next_conns == 2 then --if not, don't even try!
- local tcb = ildb.get_tcb(adj_pos)
- if tcb then
- -- done with this branch
- --atdebug("Traverser found tcb at",adj_pos, adj_connid)
- insert_sigd_nodouble(found_tcbs, {p=adj_pos, s=adj_connid})
- return
- end
- end
- -- recursion abort condition
- if count > TRAVERSER_LIMIT then
- --atdebug("Traverser hit counter at",adj_pos, adj_connid)
- return true
- end
- -- continue traversing
- local counter_hit = false
- for nconnid, nconn in ipairs(next_conns) do
- if adj_connid ~= nconnid then
- counter_hit = counter_hit or traverser(found_tcbs, adj_pos, next_conns, nconnid, count + 1, brk_when_found_n)
- if brk_when_found_n and #found_tcbs>=brk_when_found_n then
- break
- end
- end
- end
- return counter_hit
-end
-
-
-
--- Merges the TS with merge_id into root_id and then deletes merge_id
-local function merge_ts(root_id, merge_id)
- local rts = ildb.get_ts(root_id)
- local mts = ildb.get_ts(merge_id)
- if not mts then return end -- This may be the case when sync_tcb_neighbors
- -- inserts the same id twice. do nothing.
-
- if not ildb.may_modify_ts(rts) then return false end
- if not ildb.may_modify_ts(mts) then return false end
-
- -- cobble together the list of TCBs
- for _, msigd in ipairs(mts.tc_breaks) do
- local tcbs = ildb.get_tcbs(msigd)
- if tcbs then
- insert_sigd_nodouble(rts.tc_breaks, msigd)
- tcbs.ts_id = root_id
- end
- advtrains.interlocking.show_tcb_marker(msigd.p)
- end
- -- done
- track_sections[merge_id] = nil
-end
-
-local lntrans = { "A", "B" }
-local function sigd_to_string(sigd)
- return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
-end
-
--- Check for near TCBs and connect to their TS if they have one, and syncs their data.
-function ildb.sync_tcb_neighbors(pos, connid)
- local found_tcbs = { {p = pos, s = connid} }
- local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
- if not node_ok then
- atwarn("update_tcb_neighbors but node is NOK: "..minetest.pos_to_string(pos))
- return
- end
-
- --atdebug("Traversing from ",pos, connid)
- local counter_hit = traverser(found_tcbs, pos, conns, connid, 0)
-
- local ts_id
- local list_eoi = {}
- local list_ok = {}
- local list_mismatch = {}
- local ts_to_merge = {}
-
- for idx, sigd in pairs(found_tcbs) do
- local tcbs = ildb.get_tcbs(sigd)
- if not tcbs.ts_id then
- --atdebug("Sync: put",sigd_to_string(sigd),"into list_eoi")
- table.insert(list_eoi, sigd)
- elseif not ts_id and tcbs.ts_id then
- if not ildb.get_ts(tcbs.ts_id) then
- atwarn("Track section database is inconsistent, there's no TS with ID=",tcbs.ts_id)
- tcbs.ts_id = nil
- table.insert(list_eoi, sigd)
- else
- --atdebug("Sync: put",sigd_to_string(sigd),"into list_ok")
- ts_id = tcbs.ts_id
- table.insert(list_ok, sigd)
- end
- elseif ts_id and tcbs.ts_id and tcbs.ts_id ~= ts_id then
- atwarn("Track section database is inconsistent, sections share track!")
- atwarn("Merging",tcbs.ts_id,"into",ts_id,".")
- table.insert(list_mismatch, sigd)
- table.insert(ts_to_merge, tcbs.ts_id)
- end
- end
- if ts_id then
- local ts = ildb.get_ts(ts_id)
- for _, sigd in ipairs(list_eoi) do
- local tcbs = ildb.get_tcbs(sigd)
- tcbs.ts_id = ts_id
- table.insert(ts.tc_breaks, sigd)
- advtrains.interlocking.show_tcb_marker(sigd.p)
- end
- for _, mts in ipairs(ts_to_merge) do
- merge_ts(ts_id, mts)
- end
- end
-end
-
-function ildb.link_track_sections(merge_id, root_id)
- if merge_id == root_id then
- return
- end
- merge_ts(root_id, merge_id)
-end
-
-function ildb.remove_from_interlocking(sigd)
- local tcbs = ildb.get_tcbs(sigd)
- if not ildb.may_modify_tcbs(tcbs) then return false end
-
- if tcbs.ts_id then
- local tsid = tcbs.ts_id
- local ts = ildb.get_ts(tsid)
- if not ts then
- tcbs.ts_id = nil
- return true
- end
-
- -- remove entry from the list
- local idx = 1
- while idx <= #ts.tc_breaks do
- local cmp = ts.tc_breaks[idx]
- if sigd_equal(sigd, cmp) then
- table.remove(ts.tc_breaks, idx)
- else
- idx = idx + 1
- end
- end
- tcbs.ts_id = nil
-
- --ildb.sync_tcb_neighbors(sigd.p, sigd.s)
-
- if #ts.tc_breaks == 0 then
- track_sections[tsid] = nil
- end
- end
- advtrains.interlocking.show_tcb_marker(sigd.p)
- if tcbs.signal then
- return false
- end
- return true
-end
-
-function ildb.remove_tcb(pos)
- local pts = advtrains.roundfloorpts(pos)
- if not track_circuit_breaks[pts] then return end
- for connid=1,2 do
- if not ildb.remove_from_interlocking({p=pos, s=connid}) then
- return false
- end
- end
- track_circuit_breaks[pts] = nil
- return true
-end
-
-function ildb.dissolve_ts(ts_id)
- local ts = ildb.get_ts(ts_id)
- if not ildb.may_modify_ts(ts) then return false end
- local tcbr = advtrains.merge_tables(ts.tc_breaks)
- for _,sigd in ipairs(tcbr) do
- ildb.remove_from_interlocking(sigd)
- end
- -- Note: ts gets removed in the moment of the removal of the last TCB.
- return true
-end
-
--- Returns true if it is allowed to modify any property of a track section, such as
--- - removing TCBs
--- - merging and dissolving sections
--- As of now the action will be denied if a route is set or if a train is in the section.
-function ildb.may_modify_ts(ts)
- if ts.route or ts.route_post or (ts.trains and #ts.trains>0) then
- return false
- end
- return true
-end
-
-
-function ildb.may_modify_tcbs(tcbs)
- if tcbs.ts_id then
- local ts = ildb.get_ts(tcbs.ts_id)
- if ts and not ildb.may_modify_ts(ts) then
- return false
- end
- end
- return true
-end
-
--- Utilize the traverser to find the track section at the specified position
--- Returns:
--- ts_id, origin - the first found ts and the sigd of the found tcb
--- nil - there were no TCBs in TRAVERSER_MAX range of the position
--- false - the first found TCB stated End-Of-Interlocking, or track ends were reached
-function ildb.get_ts_at_pos(pos)
- local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
- if not node_ok then
- error("get_ts_at_pos but node is NOK: "..minetest.pos_to_string(pos))
- end
- local limit_hit = false
- local found_tcbs = {}
- for connid, conn in ipairs(conns) do -- Note: a breadth-first-search would be better for performance
- limit_hit = limit_hit or traverser(found_tcbs, pos, conns, connid, 0, 1)
- if #found_tcbs >= 1 then
- local tcbs = ildb.get_tcbs(found_tcbs[1])
- local ts
- if tcbs.ts_id then
- return tcbs.ts_id, found_tcbs[1]
- else
- return false
- end
- end
- end
- if limit_hit then
- -- there was at least one limit hit
- return nil
- else
- -- all traverser ends were track ends
- return false
- end
-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)
- local sigd = signal_assignments[pts]
- if sigd then
- if not ildb.get_tcbs(sigd) then
- signal_assignments[pts] = nil
- return nil
- end
- return sigd
- end
- return nil
-end
-function ildb.set_sigd_for_signal(pos, sigd)
- local pts = advtrains.roundfloorpts(pos)
- signal_assignments[pts] = sigd
-end
-
--- checks if there's any influence point set to this position
-function ildb.is_ip_at(pos)
- local pts = advtrains.roundfloorpts(pos)
- if influence_points[pts] then
- return true
- end
- return false
-end
-
--- checks if a signal is influencing here
-function ildb.get_ip_signal(pts, connid)
- if influence_points[pts] then
- return influence_points[pts][connid]
- end
-end
-
--- Tries to get aspect to obey here, if there
--- is a signal ip at this location
--- auto-clears invalid assignments
-function ildb.get_ip_signal_asp(pts, connid)
- local p = ildb.get_ip_signal(pts, connid)
- if p then
- local asp = advtrains.interlocking.signal_get_aspect(p)
- if not asp then
- atlog("Clearing orphaned signal influence point", pts, "/", connid)
- ildb.clear_ip_signal(pts, connid)
- return nil
- end
- return asp, p
- end
- return nil
-end
-
--- set signal assignment.
-function ildb.set_ip_signal(pts, connid, spos)
- ildb.clear_ip_by_signalpos(spos)
- if not influence_points[pts] then
- influence_points[pts] = {}
- end
- influence_points[pts][connid] = spos
-end
--- clear signal assignment.
-function ildb.clear_ip_signal(pts, connid)
- influence_points[pts][connid] = nil
- for _,_ in pairs(influence_points[pts]) do
- return
- end
- influence_points[pts] = nil
-end
-
-function ildb.get_ip_by_signalpos(spos)
- for pts,tab in pairs(influence_points) do
- for connid,pos in pairs(tab) do
- if vector.equals(pos, spos) then
- return pts, connid
- end
- end
- end
-end
--- clear signal assignment given the signal position
-function ildb.clear_ip_by_signalpos(spos)
- local pts, connid = ildb.get_ip_by_signalpos(spos)
- if pts then ildb.clear_ip_signal(pts, connid) end
-end
-
-
-advtrains.interlocking.db = ildb
-
-
-
-
diff --git a/advtrains_interlocking/demosignals.lua b/advtrains_interlocking/demosignals.lua
deleted file mode 100644
index ab7a8b6..0000000
--- a/advtrains_interlocking/demosignals.lua
+++ /dev/null
@@ -1,111 +0,0 @@
--- 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.
-
-
-local setaspect = function(pos, node, asp)
- if not asp.main.free then
- advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_danger"})
- else
- if asp.dst.free and asp.main.speed == -1 then
- advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_free"})
- else
- advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_slow"})
- end
- end
- local meta = minetest.get_meta(pos)
- if meta then
- meta:set_string("infotext", minetest.serialize(asp))
- end
-end
-
-local suppasp = {
- main = {
- free = nil,
- speed = {6, -1},
- },
- dst = {
- free = nil,
- speed = nil,
- },
- shunt = {
- free = false,
- proceed_as_main = true,
- },
- info = {
- call_on = false,
- dead_end = false,
- w_speed = nil,
- }
-}
-
-minetest.register_node("advtrains_interlocking:ds_danger", {
- description = "Demo signal at Danger",
- tiles = {"at_il_signal_asp_danger.png"},
- groups = {
- cracky = 3,
- advtrains_signal = 2,
- save_in_at_nodedb = 1,
- },
- sounds = default.node_sound_stone_defaults(),
- advtrains = {
- set_aspect = setaspect,
- supported_aspects = suppasp,
- get_aspect = function(pos, node)
- return advtrains.interlocking.DANGER
- end,
- },
- on_rightclick = advtrains.interlocking.signal_rc_handler,
- can_dig = advtrains.interlocking.signal_can_dig,
-})
-minetest.register_node("advtrains_interlocking:ds_free", {
- description = "Demo signal at Free",
- tiles = {"at_il_signal_asp_free.png"},
- groups = {
- cracky = 3,
- advtrains_signal = 2,
- save_in_at_nodedb = 1,
- },
- sounds = default.node_sound_stone_defaults(),
- advtrains = {
- set_aspect = setaspect,
- supported_aspects = suppasp,
- get_aspect = function(pos, node)
- return {
- main = {
- free = true,
- speed = -1,
- }
- }
- end,
- },
- on_rightclick = advtrains.interlocking.signal_rc_handler,
- can_dig = advtrains.interlocking.signal_can_dig,
-})
-minetest.register_node("advtrains_interlocking:ds_slow", {
- description = "Demo signal at Slow",
- tiles = {"at_il_signal_asp_slow.png"},
- groups = {
- cracky = 3,
- advtrains_signal = 2,
- save_in_at_nodedb = 1,
- },
- sounds = default.node_sound_stone_defaults(),
- advtrains = {
- set_aspect = setaspect,
- supported_aspects = suppasp,
- get_aspect = function(pos, node)
- return {
- main = {
- free = true,
- speed = 6,
- }
- }
- end,
- },
- on_rightclick = advtrains.interlocking.signal_rc_handler,
- can_dig = advtrains.interlocking.signal_can_dig,
-})
-
diff --git a/advtrains_interlocking/depends.txt b/advtrains_interlocking/depends.txt
deleted file mode 100644
index fdf6b17..0000000
--- a/advtrains_interlocking/depends.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-advtrains
-advtrains_train_track? \ No newline at end of file
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
deleted file mode 100644
index a2f5882..0000000
--- a/advtrains_interlocking/init.lua
+++ /dev/null
@@ -1,30 +0,0 @@
--- Advtrains interlocking system
--- See database.lua for a detailed explanation
-
-advtrains.interlocking = {}
-
-advtrains.SHUNT_SPEED_MAX = 6
-
-function advtrains.interlocking.sigd_equal(sigd, cmp)
- return vector.equals(sigd.p, cmp.p) and sigd.s==cmp.s
-end
-
-
-local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELIM
-
-dofile(modpath.."database.lua")
-dofile(modpath.."signal_api.lua")
-dofile(modpath.."demosignals.lua")
-dofile(modpath.."train_sections.lua")
-dofile(modpath.."route_prog.lua")
-dofile(modpath.."routesetting.lua")
-dofile(modpath.."tcb_ts_ui.lua")
-dofile(modpath.."route_ui.lua")
-dofile(modpath.."tool.lua")
-
-dofile(modpath.."approach.lua")
-dofile(modpath.."ars.lua")
-dofile(modpath.."tsr_rail.lua")
-
-
-minetest.register_privilege("interlocking", {description = "Can set up track sections, routes and signals.", give_to_singleplayer = true})
diff --git a/advtrains_interlocking/models/at_il_tcb_node.obj b/advtrains_interlocking/models/at_il_tcb_node.obj
deleted file mode 100644
index bb6aab5..0000000
--- a/advtrains_interlocking/models/at_il_tcb_node.obj
+++ /dev/null
@@ -1,248 +0,0 @@
-# Blender v2.76 (sub 0) OBJ File: ''
-# www.blender.org
-mtllib at_il_tcb_node.mtl
-o Cube
-v 0.038370 -0.500000 -0.038370
-v 0.038370 -0.500000 0.038370
-v -0.038370 -0.500000 0.038370
-v -0.038370 -0.500000 -0.038370
-v 0.038370 0.098086 -0.038370
-v 0.038370 0.098086 0.038370
-v -0.038370 0.098086 0.038370
-v -0.038370 0.098086 -0.038370
-v -0.182395 0.065479 0.099357
-v -0.182395 0.182395 0.099357
-v -0.182395 0.065479 -0.171034
-v -0.182395 0.182395 -0.171034
-v 0.182395 0.065479 0.099357
-v 0.182395 0.182395 0.099357
-v 0.182395 0.065479 -0.171034
-v 0.182395 0.182395 -0.171034
-v -0.112374 0.070035 -0.139406
-v -0.112374 -0.500000 -0.139406
-v 0.112189 -0.500000 -0.139406
-v 0.112189 0.070035 -0.139406
-v 0.122883 -0.500000 -0.137278
-v 0.122883 0.070035 -0.137278
-v 0.131950 -0.500000 -0.131220
-v 0.131950 0.070035 -0.131220
-v 0.138008 -0.500000 -0.122154
-v 0.138008 0.070035 -0.122154
-v 0.140135 -0.500000 -0.111459
-v 0.140135 0.070035 -0.111459
-v 0.138008 -0.500000 -0.100765
-v 0.138008 0.070035 -0.100765
-v 0.131950 -0.500000 -0.091698
-v 0.131950 0.070035 -0.091698
-v 0.122883 -0.500000 -0.085640
-v 0.122883 0.070035 -0.085640
-v 0.112189 -0.500000 -0.083513
-v 0.112189 0.070035 -0.083513
-v 0.101494 -0.500000 -0.085640
-v 0.101494 0.070035 -0.085640
-v 0.092428 -0.500000 -0.091698
-v 0.092428 0.070035 -0.091698
-v 0.086370 -0.500000 -0.100765
-v 0.086370 0.070035 -0.100765
-v 0.084242 -0.500000 -0.111459
-v 0.084242 0.070035 -0.111459
-v 0.086370 -0.500000 -0.122154
-v 0.086370 0.070035 -0.122154
-v 0.092428 -0.500000 -0.131220
-v 0.092428 0.070035 -0.131220
-v 0.101494 -0.500000 -0.137278
-v 0.101494 0.070035 -0.137278
-v -0.101679 -0.500000 -0.137278
-v -0.101679 0.070035 -0.137278
-v -0.092613 -0.500000 -0.131220
-v -0.092613 0.070035 -0.131220
-v -0.086555 -0.500000 -0.122154
-v -0.086555 0.070035 -0.122154
-v -0.084428 -0.500000 -0.111459
-v -0.084428 0.070035 -0.111459
-v -0.086555 -0.500000 -0.100765
-v -0.086555 0.070035 -0.100765
-v -0.092613 -0.500000 -0.091698
-v -0.092613 0.070035 -0.091698
-v -0.101679 -0.500000 -0.085640
-v -0.101679 0.070035 -0.085640
-v -0.112374 -0.500000 -0.083513
-v -0.112374 0.070035 -0.083513
-v -0.123069 -0.500000 -0.085640
-v -0.123069 0.070035 -0.085640
-v -0.132135 -0.500000 -0.091698
-v -0.132135 0.070035 -0.091698
-v -0.138193 -0.500000 -0.100765
-v -0.138193 0.070035 -0.100765
-v -0.140320 -0.500000 -0.111459
-v -0.140320 0.070035 -0.111459
-v -0.138193 -0.500000 -0.122154
-v -0.138193 0.070035 -0.122154
-v -0.132135 -0.500000 -0.131220
-v -0.132135 0.070035 -0.131220
-v -0.123069 -0.500000 -0.137278
-v -0.123069 0.070035 -0.137278
-vt 0.876073 0.266665
-vt 0.876073 0.977812
-vt 0.784827 0.977812
-vt 0.784827 0.266665
-vt 0.693582 0.977812
-vt 0.693582 0.266665
-vt 0.602336 0.977812
-vt 0.602336 0.266665
-vt 0.967319 0.266665
-vt 0.967319 0.977812
-vt 0.147929 0.032040
-vt 0.469434 0.032040
-vt 0.469434 0.171057
-vt 0.147929 0.171057
-vt 0.903184 0.032040
-vt 0.903184 0.171057
-vt 0.147929 0.032751
-vt 0.469434 0.032751
-vt 0.469434 0.171768
-vt 0.147929 0.171768
-vt 0.903184 0.032751
-vt 0.903183 0.171768
-vt 0.263807 0.270252
-vt 0.585312 0.270252
-vt 0.585312 0.704001
-vt 0.263807 0.704001
-vt 0.584297 0.703059
-vt 0.262792 0.703059
-vt 0.262793 0.269309
-vt 0.584297 0.269309
-vt 0.108472 0.980897
-vt 0.108473 0.303114
-vt 0.121438 0.303114
-vt 0.121438 0.980897
-vt 0.081877 0.980125
-vt 0.081879 0.302342
-vt 0.094844 0.302342
-vt 0.094843 0.980125
-vt 0.095507 0.980897
-vt 0.095508 0.303114
-vt 0.107809 0.302342
-vt 0.107808 0.980125
-vt 0.082541 0.980897
-vt 0.082543 0.303114
-vt 0.120774 0.302342
-vt 0.120774 0.980125
-vt 0.069575 0.980897
-vt 0.069577 0.303114
-vt 0.133739 0.302342
-vt 0.133740 0.980125
-vt 0.056609 0.980897
-vt 0.056612 0.303114
-vt 0.146705 0.302342
-vt 0.146706 0.980125
-vt 0.043643 0.980897
-vt 0.043647 0.303114
-vt 0.159670 0.302342
-vt 0.159672 0.980125
-vt 0.030677 0.980897
-vt 0.030682 0.303113
-vt 0.172635 0.302342
-vt 0.172638 0.980125
-vt 0.017711 0.980897
-vt 0.017717 0.303113
-vt 0.185600 0.302342
-vt 0.185604 0.980125
-vt 0.212200 0.980896
-vt 0.212195 0.303113
-vt 0.225160 0.303113
-vt 0.225166 0.980896
-vt 0.198565 0.302342
-vt 0.198570 0.980125
-vt 0.199234 0.980897
-vt 0.199230 0.303114
-vt 0.211531 0.302342
-vt 0.211536 0.980125
-vt 0.186268 0.980897
-vt 0.186264 0.303114
-vt 0.224496 0.302342
-vt 0.224502 0.980125
-vt 0.173302 0.980897
-vt 0.173299 0.303114
-vt 0.017047 0.980125
-vt 0.017052 0.302342
-vt 0.030018 0.302342
-vt 0.030013 0.980125
-vt 0.134403 0.303114
-vt 0.134404 0.980897
-vt 0.160336 0.980897
-vt 0.160334 0.303114
-vt 0.042983 0.302342
-vt 0.042979 0.980125
-vt 0.147369 0.303114
-vt 0.147370 0.980897
-vt 0.055948 0.302342
-vt 0.055945 0.980125
-vt 0.068911 0.980125
-vt 0.068913 0.302342
-vn 1.000000 0.000000 0.000000
-vn -0.000000 -0.000000 1.000000
-vn -1.000000 -0.000000 -0.000000
-vn 0.000000 0.000000 -1.000000
-vn 0.000000 -1.000000 0.000000
-vn 0.000000 1.000000 0.000000
-vn -0.831500 0.000000 -0.555600
-vn 0.195100 0.000000 -0.980800
-vn -0.980800 0.000000 -0.195100
-vn 0.555600 0.000000 -0.831500
-vn -0.980800 0.000000 0.195100
-vn 0.831500 0.000000 -0.555600
-vn -0.831500 0.000000 0.555600
-vn 0.980800 0.000000 -0.195100
-vn -0.555600 0.000000 0.831500
-vn 0.980800 0.000000 0.195100
-vn -0.195100 0.000000 0.980800
-vn 0.831500 0.000000 0.555600
-vn 0.195100 0.000000 0.980800
-vn 0.555600 0.000000 0.831500
-vn -0.555600 0.000000 -0.831500
-vn -0.195100 0.000000 -0.980800
-usemtl Material
-s off
-f 1/1/1 5/2/1 6/3/1 2/4/1
-f 2/4/2 6/3/2 7/5/2 3/6/2
-f 3/6/3 7/5/3 8/7/3 4/8/3
-f 5/2/4 1/1/4 4/9/4 8/10/4
-f 10/11/3 12/12/3 11/13/3 9/14/3
-f 12/12/4 16/15/4 15/16/4 11/13/4
-f 16/17/1 14/18/1 13/19/1 15/20/1
-f 14/18/2 10/21/2 9/22/2 13/19/2
-f 9/23/5 11/24/5 15/25/5 13/26/5
-f 14/27/6 16/28/6 12/29/6 10/30/6
-f 75/31/7 76/32/7 78/33/7 77/34/7
-f 19/35/8 20/36/8 22/37/8 21/38/8
-f 73/39/9 74/40/9 76/32/9 75/31/9
-f 21/38/10 22/37/10 24/41/10 23/42/10
-f 71/43/11 72/44/11 74/40/11 73/39/11
-f 23/42/12 24/41/12 26/45/12 25/46/12
-f 69/47/13 70/48/13 72/44/13 71/43/13
-f 25/46/14 26/45/14 28/49/14 27/50/14
-f 67/51/15 68/52/15 70/48/15 69/47/15
-f 27/50/16 28/49/16 30/53/16 29/54/16
-f 65/55/17 66/56/17 68/52/17 67/51/17
-f 29/54/18 30/53/18 32/57/18 31/58/18
-f 63/59/19 64/60/19 66/56/19 65/55/19
-f 31/58/20 32/57/20 34/61/20 33/62/20
-f 61/63/20 62/64/20 64/60/20 63/59/20
-f 33/62/19 34/61/19 36/65/19 35/66/19
-f 59/67/18 60/68/18 62/69/18 61/70/18
-f 35/66/17 36/65/17 38/71/17 37/72/17
-f 57/73/16 58/74/16 60/68/16 59/67/16
-f 37/72/15 38/71/15 40/75/15 39/76/15
-f 55/77/14 56/78/14 58/74/14 57/73/14
-f 39/76/13 40/75/13 42/79/13 41/80/13
-f 53/81/12 54/82/12 56/78/12 55/77/12
-f 41/83/11 42/84/11 44/85/11 43/86/11
-f 77/34/21 78/33/21 80/87/21 79/88/21
-f 51/89/10 52/90/10 54/82/10 53/81/10
-f 43/86/9 44/85/9 46/91/9 45/92/9
-f 79/88/22 80/87/22 17/93/22 18/94/22
-f 18/94/8 17/93/8 52/90/8 51/89/8
-f 45/92/7 46/91/7 48/95/7 47/96/7
-f 49/97/22 50/98/22 20/36/22 19/35/22
-f 47/96/21 48/95/21 50/98/21 49/97/21
diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua
deleted file mode 100644
index eadfd93..0000000
--- a/advtrains_interlocking/route_prog.lua
+++ /dev/null
@@ -1,548 +0,0 @@
--- 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 <route name>'.
- 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)
- if self.callback then
- self.callback()
- end
- 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, callback)
- 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},
- })
-
- if callback then
- obj:get_luaentity().callback = callback
- end
-
- markerent[context][key] = obj
-end
-
---[[
-Route definition:
-route = {
- name = <string>
- [n] = {
- next = <sigd>, -- of the next (note: next) TCB on the route
- locks = {<pts> = "state"} -- route locks of this route segment
- }
- terminal =
-}
-The first item in the TCB path (namely i=0) is always the start signal of this route,
-so this is left out.
-All subsequent entries, starting from 1, contain:
-- all route locks of the segment on TS between the (i-1). and the i. TCB
-- the next TCB signal describer in proceeding direction of the route.
-'Terminal' once again repeats the "next" entry of the last route segment.
-It is needed for distant signal aspect determination. If it is not set,
-the distant signal aspect is determined as DANGER.
-]]--
-
-local function chat(pname, message)
- minetest.chat_send_player(pname, "[Route programming] "..message)
-end
-local function clear_lock(locks, pname, pts)
- locks[pts] = nil
- chat(pname, pts.." is no longer affected when this route is set.")
-end
-
-local function otherside(s)
- if s==1 then return 2 else return 1 end
-end
-
-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_<player> or vis_<pts> for later visualizations
--- last 2 parameters are only to be used in the context of route programming!
-function advtrains.interlocking.visualize_route(origin, route, context, tmp_lcks, pname)
- advtrains.interlocking.clear_visu_context(context)
-
- local oyaw = 0
- local onode_ok, oconns, orhe = advtrains.get_rail_info_at(origin.p, advtrains.all_tracktypes)
- if onode_ok then
- oyaw = advtrains.dir_to_angle(oconns[origin.s].c)
- end
- routemarker(context, origin.p, "rte_origin", "at_il_route_start.png", oyaw, route.name)
-
- local c_sigd = origin
- for k,v in ipairs(route) do
- c_sigd = v.next
- -- display route path
- -- Final "next" marker can be EOI, thus undefined. This is legitimate.
- if c_sigd then
- local yaw = 0
- local node_ok, conns, rhe = advtrains.get_rail_info_at(c_sigd.p, advtrains.all_tracktypes)
- if node_ok then
- yaw = advtrains.dir_to_angle(conns[c_sigd.s].c)
- end
- local img = "at_il_route_set.png"
- if k==#route and not tmp_lcks then
- img = "at_il_route_end.png"
- end
- routemarker(context, c_sigd.p, "rte"..k, img, yaw, route.name.." #"..k)
- end
- -- display locks
- for pts, state in pairs(v.locks) do
- local pos = minetest.string_to_pos(pts)
- routesprite(context, pos, "fix"..k..pts, "at_il_route_lock.png", "Fixed in state '"..state.."' by route "..route.name.." until segment #"..k.." is freed.")
- end
- end
-
- -- The presence of tmp_lcks tells us that we are displaying during route programming.
- if tmp_lcks then
- -- display route end markers at appropriate places (check next TS, if it exists)
- local terminal = c_sigd
- if terminal then
- local term_tcbs = advtrains.interlocking.db.get_tcbs(terminal)
- if term_tcbs.ts_id then
- local over_ts = advtrains.interlocking.db.get_ts(term_tcbs.ts_id)
- for i, sigd in ipairs(over_ts.tc_breaks) do
- if not vector.equals(sigd.p, terminal.p) then
- 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[otherside(sigd.s)].c)
- end
- routemarker(context, sigd.p, "rteterm"..i, "at_il_route_end.png", yaw, route.name.." Terminal "..i)
- end
- end
- end
- end
- -- display locks set by player
- for pts, state in pairs(tmp_lcks) do
- local pos = minetest.string_to_pos(pts)
- routesprite(context, pos, "fixp"..pts, "at_il_route_lock_edit.png", "Fixed in state '"..state.."' by route "..route.name.." (punch to unfix)",
- function() clear_lock(tmp_lcks, pname, pts) end)
- end
- end
-end
-
-
-local player_rte_prog = {}
-
-function advtrains.interlocking.init_route_prog(pname, sigd)
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- player_rte_prog[pname] = {
- origin = sigd,
- route = {
- name = "PROG["..pname.."]",
- },
- tmp_lcks = {},
- }
- advtrains.interlocking.visualize_route(sigd, player_rte_prog[pname].route, "prog_"..pname, player_rte_prog[pname].tmp_lcks, pname)
- 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 == 0 then
- return origin
- end
- return route[#route].next
-end
-
-local function do_advance_route(pname, rp, sigd, tsname)
- table.insert(rp.route, {next = sigd, locks = rp.tmp_lcks})
- rp.tmp_lcks = {}
- chat(pname, "Added track section '"..tsname.."' to the route.")
-end
-
-local function finishrpform(pname)
- local rp = player_rte_prog[pname]
- if not rp then return end
-
- local form = "size[7,6]label[0.5,0.5;Finish programming route]"
- local terminal = get_last_route_item(rp.origin, rp.route)
- if terminal then
- local term_tcbs = advtrains.interlocking.db.get_tcbs(terminal)
-
- if term_tcbs.signal then
- form = form .. "label[0.5,1.5;Route ends at signal:]"
- form = form .. "label[0.5,2 ;"..term_tcbs.signal_name.."]"
- else
- form = form .. "label[0.5,1.5;WARNING: Route does not end at a signal.]"
- form = form .. "label[0.5,2 ;Routes should in most cases end at signals.]"
- form = form .. "label[0.5,2.5;Cancel if you are unsure!]"
- end
- else
- form = form .. "label[0.5,1.5;Route leads into]"
- form = form .. "label[0.5,2 ;non-interlocked area]"
- end
- form = form.."field[0.8,3.5;5.2,1;name;Enter Route Name;]"
- form = form.."button_exit[0.5,4.5; 5,1;save;Save Route]"
-
-
- minetest.show_formspec(pname, "at_il_routepf", form)
-end
-
-
-local function check_advance_valid(tcbpos, rp)
- -- track circuit break, try to advance route over it
- local lri = get_last_route_item(rp.origin, rp.route)
- if not lri then
- return false, false
- end
-
- local is_endpoint = false
-
- local this_sigd, this_ts, adv_side
-
- if vector.equals(lri.p, tcbpos) then
- -- If the player just punched the last TCB again, it's of course possible to
- -- finish the route here (although it can't be advanced by here.
- -- Fun fact: you can now program routes that end exactly where they begin :)
- is_endpoint = true
- this_sigd = lri
- else
- -- else, we need to check whether this TS actually borders
- local start_tcbs = advtrains.interlocking.db.get_tcbs(lri)
- if not start_tcbs.ts_id then
- return false, false
- end
-
- this_ts = advtrains.interlocking.db.get_ts(start_tcbs.ts_id)
- for _,sigd in ipairs(this_ts.tc_breaks) do
- if vector.equals(sigd.p, tcbpos) then
- adv_side = otherside(sigd.s)
- end
- end
- if not adv_side then
- -- this TCB is not bordering to the section
- return false, false
- end
- this_sigd = {p=tcbpos, s=adv_side}
- end
-
- -- check whether the ts at the other end is capable of "end over"
- local adv_tcbs = advtrains.interlocking.db.get_tcbs(this_sigd)
- local next_tsid = adv_tcbs.ts_id
- local can_over, over_ts, next_tc_bs = false, nil, nil
- local cannotover_rsn = "Next section is diverging (>2 TCBs)"
- if next_tsid then
- -- you may not advance over EOI. While this is technically possible,
- -- in practise this just enters an unnecessary extra empty route item.
- over_ts = advtrains.interlocking.db.get_ts(adv_tcbs.ts_id)
- next_tc_bs = over_ts.tc_breaks
- can_over = #next_tc_bs <= 2
- else
- cannotover_rsn = "End of interlocking"
- end
-
- local over_sigd = nil
- if can_over then
- if next_tc_bs and #next_tc_bs == 2 then
- local sdt
- if vector.equals(next_tc_bs[1].p, tcbpos) then
- sdt = next_tc_bs[2]
- end
- if vector.equals(next_tc_bs[2].p, tcbpos) then
- sdt = next_tc_bs[1]
- end
- if not sdt then
- error("Inconsistency: "..dump(next_ts))
- end
- -- swap TCB direction
- over_sigd = {p = sdt.p, s = otherside(sdt.s) }
- end
- end
-
- return is_endpoint, true, this_sigd, this_ts, can_over, over_ts, over_sigd, cannotover_rsn
-end
-
-local function show_routing_form(pname, tcbpos, message)
-
- local rp = player_rte_prog[pname]
-
- if not rp then return end
-
- local is_endpoint, advance_valid, this_sigd, this_ts, can_over, over_ts, over_sigd, cannotover_rsn = check_advance_valid(tcbpos, rp)
-
- -- at this place, advance_valid shows whether the current route can be advanced
- -- over this TCB.
- -- If it can:
- -- Advance over (continue programming)
- -- End here
- -- Advance and end (only <=2 TCBs, terminal signal needs to be known)
- -- if not:
- -- show nothing at all
- -- In all cases, Discard and Backtrack buttons needed.
-
- local form = "size[7,9.5]label[0.5,0.5;Advance/Complete Route]"
- if message then
- form = form .. "label[0.5,1;"..message.."]"
- end
-
- if advance_valid and not is_endpoint then
- form = form.. "label[0.5,1.8;Advance to next route section]"
- form = form.."image_button[0.5,2.2; 5,1;at_il_routep_advance.png;advance;]"
-
- form = form.. "label[0.5,3.5;-------------------------]"
- else
- form = form.. "label[0.5,2.3;This TCB is not suitable as]"
- form = form.. "label[0.5,2.8;route continuation.]"
- end
- if advance_valid or is_endpoint then
- form = form.. "label[0.5,3.8;Finish route HERE]"
- form = form.."image_button[0.5, 4.2; 5,1;at_il_routep_end_here.png;endhere;]"
- if can_over then
- form = form.. "label[0.5,5.3;Finish route at end of NEXT section]"
- form = form.."image_button[0.5,5.7; 5,1;at_il_routep_end_over.png;endover;]"
- else
- form = form.. "label[0.5,5.3;Advancing over next section is]"
- form = form.. "label[0.5,5.8;impossible at this place.]"
- if cannotover_rsn then
- form = form.. "label[0.5,6.3;"..cannotover_rsn.."]"
- end
- end
- end
-
- form = form.. "label[0.5,7;-------------------------]"
- if #rp.route > 0 then
- form = form.."button[0.5,7.4; 5,1;retract;Step back one section]"
- end
- form = form.."button[0.5,8.4; 5,1;cancel;Cancel route programming]"
-
- minetest.show_formspec(pname, "at_il_rprog_"..minetest.pos_to_string(tcbpos), form)
-end
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
-
- local tcbpts = string.match(formname, "^at_il_rprog_([^_]+)$")
- local tcbpos
- if tcbpts then
- tcbpos = minetest.string_to_pos(tcbpts)
- end
- if tcbpos then
- -- RPROG form
- local rp = player_rte_prog[pname]
- if not rp then
- minetest.close_formspec(pname, formname)
- return
- end
-
- local is_endpoint, advance_valid, this_sigd, this_ts, can_over, over_ts, over_sigd = check_advance_valid(tcbpos, rp)
-
- if advance_valid then
- if fields.advance then
- -- advance route
- if not is_endpoint then
- do_advance_route(pname, rp, this_sigd, this_ts.name)
- end
- end
- if fields.endhere then
- if not is_endpoint then
- do_advance_route(pname, rp, this_sigd, this_ts.name)
- end
- finishrpform(pname)
- end
- if can_over and fields.endover then
- if not is_endpoint then
- do_advance_route(pname, rp, this_sigd, this_ts.name)
- end
- do_advance_route(pname, rp, over_sigd, over_ts and over_ts.name or "--EOI--")
- finishrpform(pname)
- end
- end
- if fields.retract then
- if #rp.route <= 0 then
- minetest.close_formspec(pname, formname)
- return
- end
- rp.tmp_locks = rp.route[#rp.route].locks
- rp.route[#rp.route] = nil
- chat(pname, "Route section "..(#rp.route+1).." removed.")
- end
- if fields.cancel then
- player_rte_prog[pname] = nil
- advtrains.interlocking.clear_visu_context("prog_"..pname)
- chat(pname, "Route discarded.")
- minetest.close_formspec(pname, formname)
- return
- end
-
- advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
- minetest.close_formspec(pname, formname)
- return
- end
-
- if formname == "at_il_routepf" then
- if not fields.save or not fields.name then return end
- if fields.name == "" then
- -- show form again
- finishrpform(pname)
- return
- end
-
- local rp = player_rte_prog[pname]
- if rp then
- if #rp.route <= 0 then
- chat(pname, "Cannot program route without a target")
- return
- end
-
- local tcbs = advtrains.interlocking.db.get_tcbs(rp.origin)
- if not tcbs then
- chat(pname, "The origin TCB has become unknown during programming. Try again.")
- return
- end
-
- local terminal = get_last_route_item(rp.origin, rp.route)
- rp.route.terminal = terminal
- rp.route.name = fields.name
-
- table.insert(tcbs.routes, rp.route)
-
- advtrains.interlocking.clear_visu_context("prog_"..pname)
- player_rte_prog[pname] = nil
- chat(pname, "Successfully programmed route.")
-
- advtrains.interlocking.show_route_edit_form(pname, rp.origin, #tcbs.routes)
- return
- end
- end
-end)
-
-
--- Central route programming punch callback
-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 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)
-
- -- show formspec
-
- show_routing_form(pname, tcbpos)
-
- advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
-
- return
- end
- if advtrains.is_passive(pos) then
- local pts = advtrains.roundfloorpts(pos)
- if rp.tmp_lcks[pts] then
- clear_lock(rp.tmp_lcks, pname, pts)
- else
- local state = advtrains.getstate(pos)
- rp.tmp_lcks[pts] = state
- chat(pname, pts.." is held in "..state.." position when this route is set and freed ")
- end
- advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
- return
- end
-
- end
-end)
-
-
---TODO on route setting
--- routes should end at signals. complete route setting by punching a signal, and command as exceptional route completion
--- Create simpler way to advance a route to the next tcb/signal on simple sections without turnouts
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua
deleted file mode 100644
index 71fed09..0000000
--- a/advtrains_interlocking/route_ui.lua
+++ /dev/null
@@ -1,152 +0,0 @@
--- route_ui.lua
--- User interface for showing and editing routes
-
-local atil = advtrains.interlocking
-local ildb = atil.db
-
--- TODO duplicate
-local lntrans = { "A", "B" }
-local function sigd_to_string(sigd)
- return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
-end
-
-
-
-function atil.show_route_edit_form(pname, sigd, routeid)
-
- if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
-
- local tcbs = atil.db.get_tcbs(sigd)
- if not tcbs then return end
- local route = tcbs.routes[routeid]
- if not route then return end
-
- local form = "size[9,10]label[0.5,0.2;Route overview]"
- form = form.."field[0.8,1.2;5.2,1;name;Route name;"..minetest.formspec_escape(route.name).."]"
- form = form.."button[5.5,0.9;1,1;setname;Set]"
-
- -- construct textlist for route information
- local tab = {}
- local function itab(t)
- tab[#tab+1] = minetest.formspec_escape(string.gsub(t, ",", " "))
- end
- itab("TCB "..sigd_to_string(sigd).." ("..tcbs.signal_name..") Route #"..routeid)
-
- -- this code is partially copy-pasted from routesetting.lua
- -- we start at the tc designated by signal
- local c_sigd = sigd
- local i = 1
- local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp
- while c_sigd and i<=#route do
- c_tcbs = ildb.get_tcbs(c_sigd)
- if not c_tcbs then
- itab("-!- No TCBS at "..sigd_to_string(c_sigd)..". Please reconfigure route!")
- break
- end
- c_ts_id = c_tcbs.ts_id
- if not c_ts_id then
- itab("-!- No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!")
- break
- end
- c_ts = ildb.get_ts(c_ts_id)
-
- c_rseg = route[i]
- c_lckp = {}
-
- itab(""..i.." Entry "..sigd_to_string(c_sigd).." -> Sec. "..(c_ts and c_ts.name or "-").." -> Exit "..(c_rseg.next and sigd_to_string(c_rseg.next) or "END"))
-
- if c_rseg.locks then
- for pts, state in pairs(c_rseg.locks) do
-
- local pos = minetest.string_to_pos(pts)
- itab(" Lock: "..pts.." -> "..state)
- if not advtrains.is_passive(pos) then
- itab("-!- No passive component at "..pts..". Please reconfigure route!")
- break
- end
- end
- end
- -- advance
- c_sigd = c_rseg.next
- i = i + 1
- end
- if c_sigd then
- local e_tcbs = ildb.get_tcbs(c_sigd)
- itab("Route end: "..sigd_to_string(c_sigd).." ("..(e_tcbs and e_tcbs.signal_name or "-")..")")
- else
- itab("Route ends on dead-end")
- end
-
- form = form.."textlist[0.5,2;7,4;rtelog;"..table.concat(tab, ",").."]"
-
- form = form.."button[0.5,6;2,1;back;<<< Back to signal]"
- form = form.."button[3.5,6;2,1;aspect;Signal Aspect]"
- form = form.."button[5.5,6;2,1;delete;Delete Route]"
-
- --atdebug(route.ars)
- form = form.."textarea[1,7.3;5.2,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]"
- form = form.."button[6,7.7;1,1;savears;Save]"
-
- minetest.show_formspec(pname, "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid, form)
-
-end
-
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
- return
- end
-
- local pts, connids, routeids = string.match(formname, "^at_il_routeedit_([^_]+)_(%d)_(%d+)$")
- local pos, connid, routeid
- if pts then
- pos = minetest.string_to_pos(pts)
- connid = tonumber(connids)
- routeid = tonumber(routeids)
- if not connid or connid<1 or connid>2 then return end
- if not routeid then return end
- end
- if pos and connid and routeid and not fields.quit then
- local sigd = {p=pos, s=connid}
- local tcbs = ildb.get_tcbs(sigd)
- if not tcbs then return end
- local route = tcbs.routes[routeid]
- if not route then return end
-
- if fields.setname and fields.name then
- route.name = fields.name
- end
-
- if fields.aspect then
- local suppasp = advtrains.interlocking.signal_get_supported_aspects(tcbs.signal)
-
- local callback = function(pname, asp)
- route.aspect = asp
- advtrains.interlocking.show_route_edit_form(pname, sigd, routeid)
- end
-
- advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, route.aspect)
- return
- end
- if fields.delete then
- -- if something set the route in the meantime, make sure this doesn't break.
- atil.route.update_route(sigd, tcbs, nil, true)
- table.remove(tcbs.routes, routeid)
- advtrains.interlocking.show_signalling_form(sigd, pname)
- end
-
- if fields.ars and fields.savears then
- route.ars = atil.text_to_ars(fields.ars)
- --atdebug(route.ars)
- end
-
- if fields.back then
- advtrains.interlocking.show_signalling_form(sigd, pname)
- end
-
- end
-end)
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua
deleted file mode 100644
index 575b053..0000000
--- a/advtrains_interlocking/routesetting.lua
+++ /dev/null
@@ -1,357 +0,0 @@
--- Setting and clearing routes
-
--- TODO duplicate
-local lntrans = { "A", "B" }
-local function sigd_to_string(sigd)
- return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
-end
-
-local asp_generic_free = {
- main = {
- free = true,
- speed = -1,
- },
- shunt = {
- free = false,
- },
- dst = {
- free = true,
- speed = -1,
- },
- info = {}
-}
-
-local ildb = advtrains.interlocking.db
-local ilrs = {}
-
-local sigd_equal = advtrains.interlocking.sigd_equal
-
--- table containing locked points
--- also manual locks (maintenance a.s.o.) are recorded here
--- [pts] = {
--- [n] = { [by = <ts_id>], rsn = <human-readable text>, [origin = <sigd>] }
--- }
-ilrs.rte_locks = {}
-ilrs.rte_callbacks = {
- ts = {},
- lck = {}
-}
-
-
--- main route setting. First checks if everything can be set as designated,
--- then (if "try" is not set) actually sets it
--- returns:
--- true - route can be/was successfully set
--- false, message, cbts, cblk - something went wrong, what is contained in the message.
--- cbts: the ts id of the conflicting ts, cblk: the pts of the conflicting component
-function ilrs.set_route(signal, route, try)
- if not try then
- local tsuc, trsn, cbts, cblk = ilrs.set_route(signal, route, true)
- if not tsuc then
- return false, trsn, cbts, cblk
- end
- end
-
-
- -- we start at the tc designated by signal
- local c_sigd = signal
- local first = true
- local i = 1
- local rtename = route.name
- local signalname = ildb.get_tcbs(signal).signal_name
- local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp
- while c_sigd and i<=#route do
- c_tcbs = ildb.get_tcbs(c_sigd)
- if not c_tcbs then
- if not try then atwarn("Did not find TCBS",c_sigd,"while setting route",rtename,"of",signal) end
- return false, "No TCB found at "..sigd_to_string(c_sigd)..". Please reconfigure route!"
- end
- c_ts_id = c_tcbs.ts_id
- if not c_ts_id then
- if not try then atwarn("Encountered End-Of-Interlocking while setting route",rtename,"of",signal) end
- return false, "No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!"
- end
- c_ts = ildb.get_ts(c_ts_id)
- c_rseg = route[i]
- c_lckp = {}
-
- if c_ts.route then
- if not try then atwarn("Encountered ts lock during a real run of routesetting routine, at ts=",c_ts_id,"while setting route",rtename,"of",signal) end
- return false, "Section '"..c_ts.name.."' already has route set from "..sigd_to_string(c_ts.route.origin)..":\n"..c_ts.route.rsn, c_ts_id, nil
- end
- if c_ts.trains and #c_ts.trains>0 then
- if not try then atwarn("Encountered ts occupied during a real run of routesetting routine, at ts=",c_ts_id,"while setting route",rtename,"of",signal) end
- return false, "Section '"..c_ts.name.."' is occupied!", c_ts_id, nil
- end
-
- for pts, state in pairs(c_rseg.locks) do
- local confl = ilrs.has_route_lock(pts, state)
-
- local pos = minetest.string_to_pos(pts)
- if advtrains.is_passive(pos) then
- local cstate = advtrains.getstate(pos)
- if cstate ~= state then
- local confl = ilrs.has_route_lock(pts)
- if confl then
- if not try then atwarn("Encountered route lock while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end
- return false, "Lock conflict at "..pts..", Held locked by:\n"..confl, nil, pts
- elseif not try then
- advtrains.setstate(pos, state)
- end
- end
- if not try then
- ilrs.add_route_lock(pts, c_ts_id, "Route '"..rtename.."' from signal '"..signalname.."'", signal)
- c_lckp[#c_lckp+1] = pts
- end
- else
- if not try then atwarn("Encountered route lock misconfiguration (no passive component) while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end
- return false, "No passive component at "..pts..". Please reconfigure route!"
- end
- end
- -- reserve ts and write locks
- if not try then
- local nvar = c_rseg.next
- if not route[i+1] then
- -- We shouldn't use the "next" value of the final route segment, because this can lead to accidental route-cancelling of already set routes from another signal.
- nvar = nil
- end
- c_ts.route = {
- origin = signal,
- entry = c_sigd,
- rsn = "Route '"..rtename.."' from signal '"..signalname.."', segment #"..i,
- first = first,
- }
- c_ts.route_post = {
- locks = c_lckp,
- next = nvar,
- }
- if c_tcbs.signal then
- c_tcbs.route_committed = true
- c_tcbs.aspect = route.aspect or asp_generic_free
- c_tcbs.route_origin = signal
- advtrains.interlocking.update_signal_aspect(c_tcbs)
- end
- end
- -- advance
- first = nil
- c_sigd = c_rseg.next
- i = i + 1
- end
-
- return true
-end
-
--- Checks whether there is a route lock that prohibits setting the component
--- to the wanted state. returns string with reasons on conflict
-function ilrs.has_route_lock(pts)
- -- look this up
- local e = ilrs.rte_locks[pts]
- if not e then return nil
- elseif #e==0 then
- ilrs.rte_locks[pts] = nil
- return nil
- end
- local txts = {}
- for _, ent in ipairs(e) do
- txts[#txts+1] = ent.rsn
- end
- return table.concat(txts, "\n")
-end
-
--- adds route lock for position
-function ilrs.add_route_lock(pts, ts, rsn, origin)
- ilrs.free_route_locks_indiv(pts, ts, true)
- local elm = {by=ts, rsn=rsn, origin=origin}
- if not ilrs.rte_locks[pts] then
- ilrs.rte_locks[pts] = { elm }
- else
- table.insert(ilrs.rte_locks[pts], elm)
- end
-end
-
--- adds route lock for position
-function ilrs.add_manual_route_lock(pts, rsn)
- local elm = {rsn=rsn}
- if not ilrs.rte_locks[pts] then
- ilrs.rte_locks[pts] = { elm }
- else
- table.insert(ilrs.rte_locks[pts], elm)
- end
-end
-
--- frees route locking for all points (components) that were set by this ts
-function ilrs.free_route_locks(ts, lcks, nocallbacks)
- for _,pts in pairs(lcks) do
- ilrs.free_route_locks_indiv(pts, ts, nocallbacks)
- end
-end
-
-function ilrs.free_route_locks_indiv(pts, ts, nocallbacks)
- local e = ilrs.rte_locks[pts]
- if not e then return nil
- elseif #e==0 then
- ilrs.rte_locks[pts] = nil
- return nil
- end
- local i = 1
- while i <= #e do
- if e[i].by == ts then
- --atdebug("free_route_locks_indiv",pts,"clearing entry",e[i].by,e[i].rsn)
- table.remove(e,i)
- else
- i = i + 1
- end
- end
- -- This must be delayed, because this code is executed in-between a train step
- -- TODO use luaautomation timers?
- if not nocallbacks then
- minetest.after(0, ilrs.update_waiting, "lck", pts)
- minetest.after(0.5, advtrains.set_fallback_state, minetest.string_to_pos(pts))
- end
-end
--- frees all route locks, even manual ones set with the tool, at a specific position
-function ilrs.remove_route_locks(pts, nocallbacks)
- ilrs.rte_locks[pts] = nil
- -- This must be delayed, because this code is executed in-between a train step
- -- TODO use luaautomation timers?
- if not nocallbacks then
- minetest.after(0, ilrs.update_waiting, "lck", pts)
- end
-end
-
-
--- starting from the designated sigd, clears all subsequent route and route_post
--- information from the track sections.
--- note that this does not clear the routesetting status from the entry signal,
--- only from the ts's
-function ilrs.cancel_route_from(sigd)
- -- we start at the tc designated by signal
- local c_sigd = sigd
- local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp
- while c_sigd do
- --atdebug("cancel_route_from: at sigd",c_sigd)
- c_tcbs = ildb.get_tcbs(c_sigd)
- if not c_tcbs then
- atwarn("Failed to cancel route, no TCBS at",c_sigd)
- return false
- end
-
- --atdebug("cancelling",c_ts.route.rsn)
- -- clear signal aspect and routesetting state
- c_tcbs.route_committed = nil
- c_tcbs.aspect = nil
- c_tcbs.routeset = nil
- c_tcbs.route_auto = nil
- c_tcbs.route_origin = nil
-
- advtrains.interlocking.update_signal_aspect(c_tcbs)
-
- c_ts_id = c_tcbs.ts_id
- if not c_tcbs then
- atwarn("Failed to cancel route, end of interlocking at",c_sigd)
- return false
- end
- c_ts = ildb.get_ts(c_ts_id)
-
- if not c_ts
- or not c_ts.route
- or not sigd_equal(c_ts.route.entry, c_sigd) then
- --atdebug("cancel_route_from: abort (eoi/no route):")
- return false
- end
-
- c_ts.route = nil
-
- if c_ts.route_post then
- advtrains.interlocking.route.free_route_locks(c_ts_id, c_ts.route_post.locks)
- c_sigd = c_ts.route_post.next
- else
- c_sigd = nil
- end
- c_ts.route_post = nil
- minetest.after(0, advtrains.interlocking.route.update_waiting, "ts", c_ts_id)
- end
- --atdebug("cancel_route_from: done (no final sigd)")
- return true
-end
-
--- TCBS Routesetting helper: generic update function for
--- route setting
--- Call this function to set and cancel routes!
--- sigd, tcbs: self-explanatory
--- newrte: If a new route should be set, the route index of it (in tcbs.routes). nil otherwise
--- cancel: true in combination with newrte=nil causes cancellation of the current route.
-function ilrs.update_route(sigd, tcbs, newrte, cancel)
- --atdebug("Update_Route for",sigd,tcbs.signal_name)
- local has_changed_aspect = false
- if tcbs.route_origin and not sigd_equal(tcbs.route_origin, sigd) then
- --atdebug("Signal not in control, held by",tcbs.signal_name)
- return
- end
- if (newrte and tcbs.routeset and tcbs.routeset ~= newrte) or cancel then
- if tcbs.route_committed then
- --atdebug("Cancelling:",tcbs.routeset)
- advtrains.interlocking.route.cancel_route_from(sigd)
- end
- tcbs.route_committed = nil
- tcbs.aspect = nil
- has_changed_aspect = true
- tcbs.routeset = nil
- tcbs.route_auto = nil
- tcbs.route_rsn = nil
- end
- if newrte or tcbs.routeset then
- if tcbs.route_committed then
- return
- end
- if newrte then tcbs.routeset = newrte end
- --atdebug("Setting:",tcbs.routeset)
- local succ, rsn, cbts, cblk = ilrs.set_route(sigd, tcbs.routes[tcbs.routeset])
- if not succ then
- tcbs.route_rsn = rsn
- --atdebug("Routesetting failed:",rsn)
- -- add cbts or cblk to callback table
- if cbts then
- --atdebug("cbts =",cbts)
- if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end
- advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal)
- end
- if cblk then
- --atdebug("cblk =",cblk)
- if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end
- advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal)
- end
- else
- --atdebug("Committed Route:",tcbs.routeset)
- has_changed_aspect = true
- end
- end
- if has_changed_aspect then
- -- FIX: prevent an minetest.after() loop caused by update_signal_aspect dispatching path invalidation, which in turn calls ARS again
- advtrains.interlocking.update_signal_aspect(tcbs)
- end
- advtrains.interlocking.update_player_forms(sigd)
-end
-
--- Try to re-set routes that conflicted with this point
--- sys can be one of "ts" and "lck"
--- key is then ts_id or pts respectively
-function ilrs.update_waiting(sys, key)
- --atdebug("update_waiting:",sys,".",key)
- local t = ilrs.rte_callbacks[sys][key]
- ilrs.rte_callbacks[sys][key] = nil
- if t then
- for _,sigd in ipairs(t) do
- --atdebug("Updating", sigd)
- -- While these are run, the table we cleared before may be populated again, which is in our interest.
- -- (that's the reason we needed to copy it)
- local tcbs = ildb.get_tcbs(sigd)
- if tcbs then
- ilrs.update_route(sigd, tcbs)
- end
- end
- end
-end
-
-advtrains.interlocking.route = ilrs
-
diff --git a/advtrains_interlocking/settingtypes.txt b/advtrains_interlocking/settingtypes.txt
deleted file mode 100644
index f1c22b0..0000000
--- a/advtrains_interlocking/settingtypes.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# Stop trains forcibly in front of signal when about to run over an LZB 0 restriction, instead of setting emergency halt for manual resolving
-# This prevents the need to manually restart trains that overran red signals, but is unrealistic.
-# This is a workaround to circumvent system breakages due to bugs in LZB braking curves
-at_il_force_lzb_halt (Force LZB Halt) bool true
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
deleted file mode 100644
index 9729195..0000000
--- a/advtrains_interlocking/signal_api.lua
+++ /dev/null
@@ -1,546 +0,0 @@
--- Signal API implementation
-
-
---[[
-Signal aspect table:
-asp = {
- main = {
- free = <boolean>,
- speed = <int km/h>,
- },
- shunt = {
- free = <boolean>,
- -- Whether train may proceed as shunt move, on sight
- -- main aspect takes precedence over this
- proceed_as_main = <boolean>,
- -- If an approaching train is a shunt move and "main.free" is set,
- -- the train may proceed as a train move under the "main" aspect
- -- If this is not set, shunt moves are NOT allowed to switch to
- -- a train move, and must stop even if "main.free" is set.
- -- This is intended to be used for "Halt for shunt moves" signs.
- }
- dst = {
- free = <boolean>,
- speed = <int km/h>,
- }
- info = {
- call_on = <boolean>, -- Call-on route, expect train in track ahead (not implemented yet)
- dead_end = <boolean>, -- Route ends on a dead end (e.g. bumper) (not implemented yet)
- w_speed = <integer>,
- -- "Warning speed restriction". Supposed for short-term speed
- -- restrictions which always override any other restrictions
- -- imposed by "speed" fields, until lifted by a value of -1
- -- (Example: german Langsamfahrstellen-Signale)
- }
-}
--- For "speed" and "w_speed" fields, a value of -1 means that the
--- restriction is lifted. If they are omitted, the value imposed at
--- the last aspect received remains valid.
--- The "dst" subtable can be completely omitted when no explicit dst
--- aspect should be signalled to the train. In this case, the last
--- signalled dst aspect remains valid.
-
-== How signals actually work in here ==
-Each signal (in the advtrains universe) is some node that has at least the
-following things:
-- An "influence point" that is set somewhere on a rail
-- An aspect which trains that pass the "influence point" have to obey
-
-There can be static and dynamic signals. Static signals are, roughly
-spoken, signs, while dynamic signals are "real" signals which can display
-different things.
-
-The node definition of a signal node should contain those fields:
-groups = {
- advtrains_signal = 2,
- save_in_at_nodedb = 1,
-}
-advtrains = {
- set_aspect = function(pos, node, asp)
- -- This function gets called whenever the signal should display
- -- a new or changed signal aspect. It is not required that
- -- the signal actually displays the exact same aspect, since
- -- some signals can not do this by design.
- -- Example: pure shunt signals can not display a "main" aspect
- -- and have no effect on train moves, so they will only ever
- -- honor the shunt.free field for their aspect.
- -- In turn, it is not guaranteed that the aspect will fulfill the
- -- criteria put down in supported_aspects.
- -- If set_aspect is present, supported_aspects should also be declared.
-
- -- The aspect passed in here can always be queried using the
- -- advtrains.interlocking.signal_get_supposed_aspect(pos) function.
- -- It is always DANGER when the signal is not used as route signal.
-
- -- For static signals, this function should be completely omitted
- -- If this function is omitted, it won't be possible to use
- -- route setting on this signal.
- end,
- supported_aspects = {
- -- A table which tells which different types of aspects this signal
- -- is able to display. It is used to construct the "aspect editing"
- -- formspec for route programming (and others) It should always be
- -- present alongside with set_aspect. If this is not specified but
- -- set_aspect is, the user will be allowed to select any aspect.
- -- Any of the fields marked with <boolean/nil> support 3 types of values:
- nil: if this signal can switch between free/blocked
- false: always shows "blocked", unchangable
- true: always shows "free", unchangable
- -- Any of the "speed" fields should contain a list of possible values
- -- to be set as restriction. If omitted, this signal should never
- -- set the corresponding "speed" field in the aspect, which means
- -- that the previous speed limit stays valid
- -- If your signal can only display a single speed (may it be -1),
- -- always enclose that single value into a list. (such as {-1})
- main = {
- free = <boolean/nil>,
- speed = {<speed1>, ..., <speedn>} or nil,
- },
- dst = {
- free = <boolean/nil>,
- speed = {<speed1>, ..., <speedn>} or nil,
- },
- shunt = {
- free = <boolean/nil>,
- },
- info = {
- call_on = <boolean/nil>,
- dead_end = <boolean/nil>,
- w_speed = {<speed1>, ..., <speedn>} or nil,
- }
-
- },
- get_aspect = function(pos, node)
- -- This function gets called by the train safety system. It
- should return the aspect that this signal actually displays,
- not preferably the input of set_aspect.
- -- For regular, full-featured light signals, they will probably
- honor all entries in the original aspect, however, e.g.
- simple shunt signals always return main.free=true regardless of
- the set_aspect input because they can not signal "Halt" to
- train moves.
- -- advtrains.interlocking.DANGER contains a default "all-danger" aspect.
- -- If your signal does not cover certain sub-tables of the aspect,
- the following reasonable defaults are automatically assumed:
- main = {
- free = true,
- }
- dst = {
- free = true,
- }
- shunt = {
- free = false,
- proceed_as_main = false,
- }
- end,
-}
-on_rightclick = advtrains.interlocking.signal_rc_handler
-can_dig = advtrains.interlocking.signal_can_dig
-after_dig_node = advtrains.interlocking.signal_after_dig
-
-(If you need to specify custom can_dig or after_dig_node callbacks,
-please call those functions anyway!)
-
-Important note: If your signal should support external ways to set its
-aspect (e.g. via mesecons), there are some things that need to be considered:
-- advtrains.interlocking.signal_get_supposed_aspect(pos) won't respect this
-- Whenever you change the signal aspect, and that aspect change
-did not happen through a call to
-advtrains.interlocking.signal_set_aspect(pos, asp), you are
-*required* to call this function:
-advtrains.interlocking.signal_on_aspect_changed(pos)
-in order to notify trains about the aspect change.
-This function will query get_aspect to retrieve the new aspect.
-
-]]--
-
-local DANGER = {
- main = {
- free = false,
- speed = 0,
- },
- shunt = {
- free = false,
- },
- dst = {
- free = false,
- speed = 0,
- },
- info = {}
-}
-advtrains.interlocking.DANGER = DANGER
-
-local function fillout_aspect(asp)
- if not asp.main then
- asp.main = {
- free = true,
- }
- elseif type(asp.main) ~= "table" then
- asp.main = {
- free = asp.main~=0,
- speed = asp.main,
- }
- end
- if not asp.dst then
- asp.dst = {
- free = true,
- }
- end
- if not asp.shunt then
- asp.shunt = {
- free = false,
- proceed_as_main = false,
- }
- elseif type(asp.shunt) ~= "table" then
- asp.shunt = {
- free = asp.shunt,
- proceed_as_main = asp.proceed_as_main,
- }
- end
- if not asp.info then
- asp.info = {}
- end
-end
-
-function advtrains.interlocking.update_signal_aspect(tcbs)
- if tcbs.signal then
- local asp = tcbs.aspect or DANGER
- advtrains.interlocking.signal_set_aspect(tcbs.signal, asp)
- end
-end
-
-function advtrains.interlocking.signal_can_dig(pos)
- return not advtrains.interlocking.db.get_sigd_for_signal(pos)
-end
-
-function advtrains.interlocking.signal_after_dig(pos)
- -- clear influence point
- advtrains.interlocking.db.clear_ip_by_signalpos(pos)
-end
-
-function advtrains.interlocking.signal_set_aspect(pos, asp)
- fillout_aspect(asp)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
- ndef.advtrains.set_aspect(pos, node, asp)
- advtrains.interlocking.signal_on_aspect_changed(pos)
- end
-end
-
--- should be called when aspect has changed on this signal.
-function advtrains.interlocking.signal_on_aspect_changed(pos)
- local ipts, iconn = advtrains.interlocking.db.get_ip_by_signalpos(pos)
- if not ipts then return end
- local ipos = minetest.string_to_pos(ipts)
-
- local tns = advtrains.occ.get_trains_over(ipos)
- for id, sidx in pairs(tns) do
--- local train = advtrains.trains[id]
- --if train.index <= sidx then
- minetest.after(0, advtrains.invalidate_path, id)
- --end
- end
-end
-
-function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing)
- local pname = player:get_player_name()
- 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
- minetest.show_formspec(pname, "at_il_sigasp_"..minetest.pos_to_string(pos), "field[aspect;Set Aspect ('A' to assign IP);D0D0D]")
- else
- --static signal - only IP
- advtrains.interlocking.show_ip_form(pos, pname)
- end
- 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_sigasp_(.+)$")
- local pos
- if pts then pos = minetest.string_to_pos(pts) end
- if pos and fields.aspect then
- if fields.aspect == "A" then
- advtrains.interlocking.show_ip_form(pos, pname)
- return
- end
- local mfs, msps, dfs, dsps, shs = string.match(fields.aspect, "^([FD])([-0-9]+)([FD])([-0-9]+)([FD])$")
- local asp = {
- main = {
- free = mfs=="F",
- speed = tonumber(msps),
- },
- shunt = {
- free = shs=="F",
- },
- dst = {
- free = dfs=="F",
- speed = tonumber(dsps),
- },
- info = {
- call_on = false, -- Call-on route, expect train in track ahead
- dead_end = false, -- Route ends on a dead end (e.g. bumper)
- }
- }
- 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_supposed_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
-
--- Returns the actual aspect of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_aspect(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.get_aspect then
- local asp = ndef.advtrains.get_aspect(pos, node)
- if not asp then asp = DANGER end
- fillout_aspect(asp)
- return asp
- end
- return nil
-end
-
--- Returns the "supported_aspects" of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_supported_aspects(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.supported_aspects then
- local asp = ndef.advtrains.supported_aspects
- return asp
- end
- return nil
-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
-
--- shows small info form for signal IP state/assignment
--- 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,5]label[0.5,0.5;Signal at "..minetest.pos_to_string(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]"
- 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,3.5; 5,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)
- end
-end
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
- return
- end
- local pts = string.match(formname, "^at_il_ipassign_([^_]+)$")
- 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
- end
-end)
-
--- inits the signal IP assignment process
-function advtrains.interlocking.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)
-
-
---== aspect selector ==--
-
-local players_aspsel = {}
-
---[[
-suppasp: "supported_aspects" table
-purpose: form title string
-callback: func(pname, aspect) called on form submit
-]]
-function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, p_isasp)
- local suppasp = p_suppasp or {
- main = {}, dst = {}, shunt = {}, info = {},
- }
- local purpose = p_purpose or ""
- local isasp = p_isasp and fillout_aspect(p_isasp)
-
- local form = "size[7,5]label[0.5,0.5;Select Signal Aspect:]"
- form = form.."label[0.5,1;"..purpose.."]"
-
- form = form.."label[0.5,1.5;== Main Signal ==]"
- if suppasp.main.free == nil then
- local st = 2
- if isasp and not isasp.main.free then st=1 end
- form = form.."dropdown[0.5,2;2;main_free;danger,free;"..st.."]"
- end
- if suppasp.main.speed then
- local selid = 1
- if isasp and isasp.main.speed then
- for idx, spv in ipairs(suppasp.main.speed) do
- if spv == isasp.main.speed then
- selid = idx
- break
- end
- end
- end
- form = form.."label[2.3,1;Speed:]"
- form = form.."dropdown[3,2;2;main_speed;"..table.concat(suppasp.main.speed, ",")..";"..selid.."]"
- end
-
- form = form.."label[0.5,3;== Shunting ==]"
- if suppasp.shunt.free == nil then
- local st = 1
- if isasp and isasp.shunt.free then st=2 end
- form = form.."dropdown[0.5,3.5;2;shunt_free;---,allowed;"..st.."]"
- end
-
- form = form.."button_exit[0.5,4.5; 5,1;save;OK]"
-
- 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)
-end
-
-local function usebool(sup, val, free)
- if sup == nil then
- return val==free
- else
- return sup
- end
-end
-local function usespeed(sup, val)
- if sup then
- return tonumber(val)
- else
- return nil
- end
-end
-
--- TODO use non-hacky way to parse outputs
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- local psl = players_aspsel[pname]
- if psl then
- if formname == "at_il_sigaspdia_"..psl.token then
- if fields.save then
- local asp = {
- main = {
- free = usebool(psl.suppasp.main.free, fields.main_free, "free"),
- speed = usespeed(psl.suppasp.main.speed, fields.main_speed),
- },
- dst = {
- free = true, speed = -1,
- },
- shunt = {
- free = usebool(psl.suppasp.shunt.free, fields.shunt_free, "allowed"),
- },
- info = {}
- }
- psl.callback(pname, asp)
- end
- else
- players_aspsel[pname] = nil
- end
- end
-
-end)
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
deleted file mode 100644
index da318a7..0000000
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ /dev/null
@@ -1,789 +0,0 @@
--- Track Circuit Breaks and Track Sections - Player interaction
-
-local players_assign_tcb = {}
-local players_assign_signal = {}
-local players_link_ts = {}
-
-local ildb = advtrains.interlocking.db
-local ilrs = advtrains.interlocking.route
-
-local sigd_equal = advtrains.interlocking.sigd_equal
-
-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 = false,
- 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,
- at_il_track_circuit_break = 1,
- },
- 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 pname = player:get_player_name()
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
-
- 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 = ildb.get_tcb(tcbpos)
- if tcb then
- advtrains.interlocking.show_tcb_form(tcbpos, pname)
- else
- minetest.chat_send_player(pname, "This TCB has been removed. Please dig marker.")
- end
- else
- --unconfigured
- 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)
- if player == nil then return false end
-
- local pname = player:get_player_name()
-
- -- 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
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- local tcbpos = minetest.string_to_pos(tcbpts)
- 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).")
- 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 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
- end
- 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
- -- TCB assignment
- 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 = 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.")
- 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")
- 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
-
- -- 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 ndef = minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.set_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
- ildb.set_sigd_for_signal(pos, sigd)
- minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.")
- advtrains.interlocking.show_ip_form(pos, pname, true)
- else
- minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.")
- end
- else
- minetest.chat_send_player(pname, "Configuring TCB: Cannot use static signals for routesetting. 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_signal[pname] = nil
- end
-end)
-
--- TCB Form
-
-local function mktcbformspec(tcbs, btnpref, offset, pname)
- local form = ""
- local ts
- 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.."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
- 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
-
-
-function advtrains.interlocking.show_tcb_form(pos, pname)
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- local tcb = ildb.get_tcb(pos)
- 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)
-
- 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()
- if not minetest.check_player_privs(pname, "interlocking") then
- return
- end
- 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 = 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}
-
- 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
- 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)
- end
- end
- -- non-interlocked
- if f_setfree[connid] then
- tcbs.section_free = true
- end
- if f_setlocked[connid] then
- 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
-
-end)
-
-
-
--- TS Formspec
-
--- textlist selection temporary storage
-local ts_pselidx = {}
-
-function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
- if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- local ts = ildb.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;"..minetest.formspec_escape(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 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.."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
-
- if ts.route then
- form = form.."label[0.5,6.1;Route is set: "..ts.route.rsn.."]"
- elseif ts.route_post then
- form = form.."label[0.5,6.1;Section holds "..#(ts.route_post.lcks or {}).." route locks.]"
- end
- -- occupying trains
- if ts.trains and #ts.trains>0 then
- form = form.."label[0.5,7.1;Trains on this section:]"
- form = form.."textlist[0.5,7.7;3,2;trnlist;"..table.concat(ts.trains, ",").."]"
- else
- form = form.."label[0.5,7.1;No trains on this section.]"
- 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
- 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
-
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, "interlocking") then
- 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)
- minetest.close_formspec(pname, formname)
- return
- end
- end
-
- if fields.setname then
- ts.name = fields.name
- if ts.name == "" then
- ts.name = "Section "..ts_id
- end
- end
-
- if fields.reset then
- -- User requested resetting the section
- -- Show him what this means...
- local form = "size[7,5]label[0.5,0.5;Reset track section]"
- form = form.."label[0.5,1;This will clear the list of trains\nand the routesetting status of this section.\nAre you sure?]"
- form = form.."button_exit[0.5,2.5; 5,1;reset;Yes]"
- form = form.."button_exit[0.5,3.5; 5,1;cancel;Cancel]"
- minetest.show_formspec(pname, "at_il_tsreset_"..ts_id, form)
- return
- end
-
- advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
- return
- end
-
- ts_id = string.match(formname, "^at_il_tsreset_(.+)$")
- if ts_id and fields.reset then
- local ts = ildb.get_ts(ts_id)
- if not ts then return end
- ts.trains = {}
- if ts.route_post then
- advtrains.interlocking.route.free_route_locks(ts_id, ts.route_post.locks)
- end
- ts.route_post = nil
- ts.route = nil
- for _, sigd in ipairs(ts.tc_breaks) do
- local tcbs = ildb.get_tcbs(sigd)
- advtrains.interlocking.update_signal_aspect(tcbs)
- end
- minetest.chat_send_player(pname, "Reset track section "..ts_id.."!")
- 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)
- --atdebug("showing tcb marker",pos)
- local tcb = ildb.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 = ildb.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
-
--- Signalling formspec - set routes a.s.o
-
--- textlist selection temporary storage
-local sig_pselidx = {}
--- Players having a signalling form open
-local p_open_sig_form = {}
-
-function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte)
- if not minetest.check_player_privs(pname, "train_operator") then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- local hasprivs = minetest.check_player_privs(pname, "interlocking")
- 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).."]"
- form = form.."button[5.5,1.2;1,1;setname;Set]"
-
- if tcbs.routeset then
- local rte = tcbs.routes[tcbs.routeset]
- if not rte then
- atwarn("Unknown route set from signal!")
- tcbs.routeset = nil
- return
- end
- form = form.."label[0.5,2.5;A route is requested from this signal:]"
- form = form.."label[0.5,3.0;"..minetest.formspec_escape(rte.name).."]"
- if tcbs.route_committed then
- form = form.."label[0.5,3.5;Route has been set.]"
- else
- form = form.."label[0.5,3.5;Waiting for route to be set...]"
- if tcbs.route_rsn then
- form = form.."label[0.5,4;"..minetest.formspec_escape(tcbs.route_rsn).."]"
- end
- end
- if not tcbs.route_auto then
- form = form.."button[0.5,7; 5,1;auto;Enable Automatic Working]"
- else
- form = form.."label[0.5,7 ;Automatic Working is active.]"
- form = form.."label[0.5,7.3;Route is re-set when a train passed.]"
- form = form.."button[0.5,7.7; 5,1;noauto;Disable Automatic Working]"
- end
-
- form = form.."button[0.5,6; 5,1;cancelroute;Cancel Route]"
- else
- if not tcbs.route_origin then
- local strtab = {}
- for idx, route in ipairs(tcbs.routes) do
- local clr = ""
- if route.ars then
- clr = "#FF5555"
- if route.ars.default then
- clr = "#55FF55"
- end
- end
- strtab[#strtab+1] = clr .. minetest.formspec_escape(route.name)
- end
- form = form.."label[0.5,2.5;Routes:]"
- form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",").."]"
- if sel_rte then
- form = form.."button[0.5,6; 5,1;setroute;Set Route]"
- form = form.."button[0.5,7;2,1;dsproute;Show]"
- if hasprivs then
- form = form.."button[3.5,7;2,1;editroute;Edit]"
- end
- else
- if tcbs.ars_disabled then
- form = form.."label[0.5,6 ;NOTE: ARS is disabled.]"
- form = form.."label[0.5,6.5;Routes are not automatically set.]"
- 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]"
- end
- elseif sigd_equal(tcbs.route_origin, sigd) then
- -- something has gone wrong: tcbs.routeset should have been set...
- form = form.."label[0.5,2.5;Inconsistent state: route_origin is same TCBS but no route set. Try again.]"
- ilrs.cancel_route_from(sigd)
- else
- form = form.."label[0.5,2.5;Route is set over this signal by:\n"..sigd_to_string(tcbs.route_origin).."]"
- form = form.."label[0.5,4;Wait for this route to be cancelled in order to do anything here.]"
- end
- end
- sig_pselidx[pname] = sel_rte
- minetest.show_formspec(pname, "at_il_signalling_"..minetest.pos_to_string(sigd.p).."_"..sigd.s, form)
- p_open_sig_form[pname] = sigd
-
- -- always a good idea to update the signal aspect
- advtrains.interlocking.update_signal_aspect(tcbs)
-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)
- end
- end
-end
-
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, "train_operator") then
- return
- end
- local hasprivs = minetest.check_player_privs(pname, "interlocking")
-
- -- independent of the formspec, clear this whenever some formspec event happens
- local tpsi = sig_pselidx[pname]
- sig_pselidx[pname] = nil
- p_open_sig_form[pname] = nil
-
- local pts, connids = string.match(formname, "^at_il_signalling_([^_]+)_(%d)$")
- 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
- local sigd = {p=pos, s=connid}
- local tcbs = ildb.get_tcbs(sigd)
- if not tcbs then return end
-
- local sel_rte
- if fields.rtelist then
- local tev = minetest.explode_textlist_event(fields.rtelist)
- sel_rte = tev.index
- elseif tpsi then
- sel_rte = tpsi
- end
- if fields.setname and fields.name and hasprivs then
- tcbs.signal_name = fields.name
- end
- if tcbs.routeset and fields.cancelroute then
- if tcbs.routes[tcbs.routeset] and tcbs.routes[tcbs.routeset].ars then
- tcbs.ars_disabled = true
- end
- -- if route committed, cancel route ts info
- ilrs.update_route(sigd, tcbs, nil, true)
- end
- if not tcbs.routeset then
- if fields.newroute and hasprivs then
- advtrains.interlocking.init_route_prog(pname, sigd)
- minetest.close_formspec(pname, formname)
- return
- end
- if sel_rte and tcbs.routes[sel_rte] then
- if fields.setroute then
- ilrs.update_route(sigd, tcbs, sel_rte)
- end
- if fields.dsproute then
- local t = os.clock()
- advtrains.interlocking.visualize_route(sigd, tcbs.routes[sel_rte], "disp_"..t)
- minetest.after(10, function() advtrains.interlocking.clear_visu_context("disp_"..t) end)
- end
- if fields.editroute and hasprivs then
- advtrains.interlocking.show_route_edit_form(pname, sigd, sel_rte)
- --local rte = tcbs.routes[sel_rte]
- --minetest.show_formspec(pname, formname.."_renroute_"..sel_rte, "field[name;Enter new route name;"..rte.name.."]")
- return
- end
- 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
- 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
- end
-
- if fields.auto then
- tcbs.route_auto = true
- end
- if fields.noauto then
- tcbs.route_auto = false
- end
-
- advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte)
- return
- end
-
-
- if not hasprivs then return end
- -- rename route
- local rind, rte_id
- pts, connids, rind = string.match(formname, "^at_il_signalling_([^_]+)_(%d)_renroute_(%d+)$")
- if pts then
- pos = minetest.string_to_pos(pts)
- connid = tonumber(connids)
- rte_id = tonumber(rind)
- if not connid or connid<1 or connid>2 then return end
- end
- if pos and connid and rind and fields.name then
- local sigd = {p=pos, s=connid}
- local tcbs = ildb.get_tcbs(sigd)
- if tcbs.routes[rte_id] then
- tcbs.routes[rte_id].name = fields.name
- advtrains.interlocking.show_signalling_form(sigd, pname)
- end
- end
-end)
diff --git a/advtrains_interlocking/textures/advtrains_dtrack_npr_placer.png b/advtrains_interlocking/textures/advtrains_dtrack_npr_placer.png
deleted file mode 100644
index 0d1c769..0000000
--- a/advtrains_interlocking/textures/advtrains_dtrack_npr_placer.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/advtrains_dtrack_shared_npr.png b/advtrains_interlocking/textures/advtrains_dtrack_shared_npr.png
deleted file mode 100644
index 0116c27..0000000
--- a/advtrains_interlocking/textures/advtrains_dtrack_shared_npr.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_route_end.png b/advtrains_interlocking/textures/at_il_route_end.png
deleted file mode 100644
index 1433f0c..0000000
--- a/advtrains_interlocking/textures/at_il_route_end.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_route_lock.png b/advtrains_interlocking/textures/at_il_route_lock.png
deleted file mode 100644
index 6a5269b..0000000
--- a/advtrains_interlocking/textures/at_il_route_lock.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_route_lock_edit.png b/advtrains_interlocking/textures/at_il_route_lock_edit.png
deleted file mode 100644
index df5f923..0000000
--- a/advtrains_interlocking/textures/at_il_route_lock_edit.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_route_set.png b/advtrains_interlocking/textures/at_il_route_set.png
deleted file mode 100644
index 3531420..0000000
--- a/advtrains_interlocking/textures/at_il_route_set.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_route_start.png b/advtrains_interlocking/textures/at_il_route_start.png
deleted file mode 100644
index dcb5160..0000000
--- a/advtrains_interlocking/textures/at_il_route_start.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_routep_advance.png b/advtrains_interlocking/textures/at_il_routep_advance.png
deleted file mode 100644
index d971e85..0000000
--- a/advtrains_interlocking/textures/at_il_routep_advance.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_routep_end_here.png b/advtrains_interlocking/textures/at_il_routep_end_here.png
deleted file mode 100644
index 9dd3088..0000000
--- a/advtrains_interlocking/textures/at_il_routep_end_here.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_routep_end_over.png b/advtrains_interlocking/textures/at_il_routep_end_over.png
deleted file mode 100644
index e03198b..0000000
--- a/advtrains_interlocking/textures/at_il_routep_end_over.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_routep_end_over_last.png b/advtrains_interlocking/textures/at_il_routep_end_over_last.png
deleted file mode 100644
index f4fb1aa..0000000
--- a/advtrains_interlocking/textures/at_il_routep_end_over_last.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_signal_asp_danger.png b/advtrains_interlocking/textures/at_il_signal_asp_danger.png
deleted file mode 100644
index fca786d..0000000
--- a/advtrains_interlocking/textures/at_il_signal_asp_danger.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_signal_asp_free.png b/advtrains_interlocking/textures/at_il_signal_asp_free.png
deleted file mode 100644
index e9d6e9c..0000000
--- a/advtrains_interlocking/textures/at_il_signal_asp_free.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_signal_asp_slow.png b/advtrains_interlocking/textures/at_il_signal_asp_slow.png
deleted file mode 100644
index 9242bb3..0000000
--- a/advtrains_interlocking/textures/at_il_signal_asp_slow.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_signal_ip.png b/advtrains_interlocking/textures/at_il_signal_ip.png
deleted file mode 100644
index bf1618a..0000000
--- a/advtrains_interlocking/textures/at_il_signal_ip.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_signal_off.png b/advtrains_interlocking/textures/at_il_signal_off.png
deleted file mode 100644
index f9b1f79..0000000
--- a/advtrains_interlocking/textures/at_il_signal_off.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_tcb_marker.png b/advtrains_interlocking/textures/at_il_tcb_marker.png
deleted file mode 100644
index 3efc38a..0000000
--- a/advtrains_interlocking/textures/at_il_tcb_marker.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_tcb_node.png b/advtrains_interlocking/textures/at_il_tcb_node.png
deleted file mode 100644
index d5f615f..0000000
--- a/advtrains_interlocking/textures/at_il_tcb_node.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_tool.png b/advtrains_interlocking/textures/at_il_tool.png
deleted file mode 100644
index f6ce1cc..0000000
--- a/advtrains_interlocking/textures/at_il_tool.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_turnout_cr_l.png b/advtrains_interlocking/textures/at_il_turnout_cr_l.png
deleted file mode 100644
index fb79e3d..0000000
--- a/advtrains_interlocking/textures/at_il_turnout_cr_l.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_turnout_cr_r.png b/advtrains_interlocking/textures/at_il_turnout_cr_r.png
deleted file mode 100644
index e04dfbd..0000000
--- a/advtrains_interlocking/textures/at_il_turnout_cr_r.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_turnout_free.png b/advtrains_interlocking/textures/at_il_turnout_free.png
deleted file mode 100644
index 5c83193..0000000
--- a/advtrains_interlocking/textures/at_il_turnout_free.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/textures/at_il_turnout_st.png b/advtrains_interlocking/textures/at_il_turnout_st.png
deleted file mode 100644
index 50d5ad5..0000000
--- a/advtrains_interlocking/textures/at_il_turnout_st.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_interlocking/tool.lua b/advtrains_interlocking/tool.lua
deleted file mode 100644
index 5d38b3a..0000000
--- a/advtrains_interlocking/tool.lua
+++ /dev/null
@@ -1,66 +0,0 @@
--- tool.lua
--- Interlocking tool
-
-local ilrs = advtrains.interlocking.route
-
-minetest.register_craftitem("advtrains_interlocking:tool",{
- description = "Interlocking tool\nright-click turnouts to inspect route locks",
- groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
- inventory_image = "at_il_tool.png",
- wield_image = "at_il_tool.png",
- stack_max = 1,
- on_place = function(itemstack, placer, pointed_thing)
- local pname = placer:get_player_name()
- if not pname then
- return
- end
- if not minetest.check_player_privs(pname, {interlocking=true}) then
- minetest.chat_send_player(pname, "Insufficient privileges to use this!")
- return
- end
- if pointed_thing.type=="node" then
- local pos=pointed_thing.under
- if advtrains.is_passive(pos) then
- local form = "size[7,5]label[0.5,0.5;Route lock inspector]"
- local pts = minetest.pos_to_string(pos)
-
- local rtl = ilrs.has_route_lock(pts)
-
- if rtl then
- form = form.."label[0.5,1;Route locks currently put:\n"..rtl.."]"
- form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]"
- else
- form = form.."label[0.5,1;No route locks set]"
- form = form.."button_exit[0.5,3.5; 5,1;emplace;Emplace manual lock]"
- end
-
- minetest.show_formspec(pname, "at_il_rtool_"..pts, form)
- else
- minetest.chat_send_player(pname, "Cannot use this here.")
- return
- end
- end
- end,
-})
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, "interlocking") then
- return
- end
- local pos
- local pts = string.match(formname, "^at_il_rtool_(.+)$")
- if pts then
- pos = minetest.string_to_pos(pts)
- end
- if pos then
- if advtrains.is_passive(pos) then
- if fields.clear then
- ilrs.remove_route_locks(pts)
- end
- if fields.emplace then
- ilrs.add_manual_route_lock(pts, "Manual lock ("..pname..")")
- end
- end
- end
-end)
diff --git a/advtrains_interlocking/train_sections.lua b/advtrains_interlocking/train_sections.lua
deleted file mode 100644
index 757f36a..0000000
--- a/advtrains_interlocking/train_sections.lua
+++ /dev/null
@@ -1,199 +0,0 @@
--- train_related.lua
--- Occupation of track sections - mainly implementation of train callbacks
-
---[[
-Track section occupation is saved as follows
-
-In train:
-train.il_sections = {
- [n] = {ts_id = <...> (origin = <sigd>)}
-}
--- "origin" is the TCB (signal describer) the train initially entered this section
-
-In track section
-ts.trains = {
- [n] = <train_id>
-}
-
-When any inconsistency is detected, we will assume the most restrictive setup.
-It will be possible to indicate a section "free" via the GUI.
-]]
-
-local ildb = advtrains.interlocking.db
-
-local sigd_equal = advtrains.interlocking.sigd_equal
-
-local function itexist(tbl, com)
- for _,item in ipairs(tbl) do
- if (item==com) then
- return true
- end
- end
- return false
-end
-local function itkexist(tbl, ikey, com)
- for _,item in ipairs(tbl) do
- if item[ikey] == com then
- return true
- end
- end
- return false
-end
-
-local function itremove(tbl, com)
- local i=1
- while i <= #tbl do
- if tbl[i] == com then
- table.remove(tbl, i)
- else
- i = i + 1
- end
- end
-end
-local function itkremove(tbl, ikey, com)
- local i=1
- while i <= #tbl do
- if tbl[i][ikey] == com then
- table.remove(tbl, i)
- else
- i = i + 1
- end
- end
-end
-
-local function setsection(tid, train, ts_id, ts, sigd)
- -- train
- if not train.il_sections then train.il_sections = {} end
- if not itkexist(train.il_sections, "ts_id", ts_id) then
- table.insert(train.il_sections, {ts_id = ts_id, origin = sigd})
- end
-
- -- ts
- if not ts.trains then ts.trains = {} end
- if not itexist(ts.trains, tid) then
- table.insert(ts.trains, tid)
- end
-
- -- routes
- local tcbs = advtrains.interlocking.db.get_tcbs(sigd)
-
- -- route setting - clear route state
- if ts.route then
- --atdebug(tid,"enters",ts_id,"examining Routestate",ts.route)
- if not sigd_equal(ts.route.entry, sigd) then
- -- Train entered not from the route. Locate origin and cancel route!
- atwarn("Train",tid,"hit route",ts.route.rsn,"!")
- advtrains.interlocking.route.cancel_route_from(ts.route.origin)
- atwarn("Route was cancelled.")
- else
- -- train entered route regularily. Reset route and signal
- tcbs.route_committed = nil
- tcbs.route_comitted = nil -- TODO compatibility cleanup
- tcbs.aspect = nil
- tcbs.route_origin = nil
- advtrains.interlocking.update_signal_aspect(tcbs)
- if tcbs.signal and sigd_equal(ts.route.entry, ts.route.origin) then
- if tcbs.route_auto and tcbs.routeset then
- --atdebug("Resetting route (",ts.route.origin,")")
- advtrains.interlocking.route.update_route(ts.route.origin, tcbs)
- else
- tcbs.routeset = nil
- end
- end
- end
- ts.route = nil
- end
- if tcbs.signal then
- advtrains.interlocking.route.update_route(sigd, tcbs)
- end
-end
-
-local function freesection(tid, train, ts_id, ts)
- -- train
- if not train.il_sections then train.il_sections = {} end
- itkremove(train.il_sections, "ts_id", ts_id)
-
- -- ts
- if not ts.trains then ts.trains = {} end
- itremove(ts.trains, tid)
-
- if ts.route_post then
- advtrains.interlocking.route.free_route_locks(ts_id, ts.route_post.locks)
- if ts.route_post.next then
- --this does nothing when the train went the right way, because
- -- "route" info is already cleared.
- advtrains.interlocking.route.cancel_route_from(ts.route_post.next)
- end
- ts.route_post = nil
- end
- -- This must be delayed, because this code is executed in-between a train step
- -- TODO use luaautomation timers?
- minetest.after(0, advtrains.interlocking.route.update_waiting, "ts", ts_id)
-end
-
-
--- This is regular operation
--- The train is on a track and drives back and forth
-
--- This sets the section for both directions, to be failsafe
-advtrains.tnc_register_on_enter(function(pos, id, train, index)
- local tcb = ildb.get_tcb(pos)
- if tcb then
- for connid=1,2 do
- local ts = tcb[connid].ts_id and ildb.get_ts(tcb[connid].ts_id)
- if ts then
- setsection(id, train, tcb[connid].ts_id, ts, {p=pos, s=connid})
- end
- end
- end
-end)
-
-
--- this time, of course, only clear the backside (cp connid)
-advtrains.tnc_register_on_leave(function(pos, id, train, index)
- local tcb = ildb.get_tcb(pos)
- if tcb and train.path_cp[index] then
- local connid = train.path_cp[index]
- local ts = tcb[connid].ts_id and ildb.get_ts(tcb[connid].ts_id)
- if ts then
- freesection(id, train, tcb[connid].ts_id, ts)
- end
- end
-end)
-
--- those callbacks are needed to account for created and removed trains (also regarding coupling)
-
-advtrains.te_register_on_create(function(id, train)
- -- let's see what track sections we find here
- local index = atround(train.index)
- local pos = advtrains.path_get(train, index)
- local ts_id, origin = ildb.get_ts_at_pos(pos)
- if ts_id then
- local ts = ildb.get_ts(ts_id)
- if ts then
- setsection(id, train, ts_id, ts, origin)
- else
- atwarn("ILDB corruption: TCB",origin," has invalid TS reference")
- end
- -- Make train a shunt move
- train.is_shunt = true
- elseif ts_id==nil then
- atlog("Train",id,": Unable to determine whether to block a track section!")
- else
- --atdebug("Train",id,": Outside of interlocked area!")
- end
-end)
-
-advtrains.te_register_on_remove(function(id, train)
- if train.il_sections then
- for idx, item in ipairs(train.il_sections) do
-
- local ts = item.ts_id and ildb.get_ts(item.ts_id)
-
- if ts and ts.trains then
- itremove(ts.trains, id)
- end
- end
- train.il_sections = nil
- end
-end)
diff --git a/advtrains_interlocking/tsr_rail.lua b/advtrains_interlocking/tsr_rail.lua
deleted file mode 100644
index a500c8f..0000000
--- a/advtrains_interlocking/tsr_rail.lua
+++ /dev/null
@@ -1,56 +0,0 @@
--- tsr_rail.lua
--- Point speed restriction rails
--- Simple rail whose only purpose is to place a TSR on the position, as a temporary solution until the timetable system covers everything.
--- This code resembles the code in lines/stoprail.lua
-
-local function updateform(pos)
- local meta = minetest.get_meta(pos)
- local pe = advtrains.encode_pos(pos)
- local npr = advtrains.interlocking.npr_rails[pe] or 2
-
- meta:set_string("infotext", "Point speed restriction: "..npr)
- meta:set_string("formspec", "field[npr;Set point speed restriction:;"..npr.."]")
-end
-
-
-local adefunc = function(def, preset, suffix, rotation)
- return {
- after_place_node=function(pos)
- updateform(pos)
- end,
- after_dig_node=function(pos)
- local pe = advtrains.encode_pos(pos)
- advtrains.interlocking.npr_rails[pe] = nil
- end,
- on_receive_fields = function(pos, formname, fields, player)
- if fields.npr then
- local pe = advtrains.encode_pos(pos)
- advtrains.interlocking.npr_rails[pe] = tonumber(fields.npr)
- updateform(pos)
- end
- end,
- advtrains = {
- on_train_approach = function(pos,train_id, train, index)
- if train.path_cn[index] == 1 then
- local pe = advtrains.encode_pos(pos)
- local npr = advtrains.interlocking.npr_rails[pe] or 2
- advtrains.lzb_add_checkpoint(train, index, npr, nil)
- end
- end,
- },
- }
-end
-
-
-if minetest.get_modpath("advtrains_train_track") ~= nil then
- advtrains.register_tracks("default", {
- nodename_prefix="advtrains_interlocking:dtrack_npr",
- texture_prefix="advtrains_dtrack_npr",
- models_prefix="advtrains_dtrack",
- models_suffix=".b3d",
- shared_texture="advtrains_dtrack_shared_npr.png",
- description="Point Speed Restriction Rail",
- formats={},
- get_additional_definiton = adefunc,
- }, advtrains.trackpresets.t_30deg_straightonly)
-end \ No newline at end of file