aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--advtrains/atc.lua30
-rw-r--r--advtrains/init.lua1
-rw-r--r--advtrains/path.lua2
-rw-r--r--advtrains/trainhud.lua37
-rw-r--r--advtrains/trainlogic.lua95
-rw-r--r--advtrains_interlocking/database.lua2
-rw-r--r--advtrains_interlocking/init.lua5
-rw-r--r--advtrains_interlocking/lzb.lua194
-rw-r--r--advtrains_interlocking/train_sections.lua (renamed from advtrains_interlocking/train_related.lua)0
-rw-r--r--advtrains_luaautomation/atc_rail.lua6
10 files changed, 315 insertions, 57 deletions
diff --git a/advtrains/atc.lua b/advtrains/atc.lua
index 22de4ca..b00849d 100644
--- a/advtrains/atc.lua
+++ b/advtrains/atc.lua
@@ -20,10 +20,11 @@ end
--contents: {command="...", arrowconn=0-15 where arrow points}
--general
-function atc.train_set_command(train_id, command, arrow)
- atc.train_reset_command(train_id)
- advtrains.trains[train_id].atc_arrow = arrow
- advtrains.trains[train_id].atc_command = command
+function atc.train_set_command(train, command, arrow)
+ atc.train_reset_command(train)
+ train.atc_delay = 0
+ train.atc_arrow = arrow
+ train.atc_command = command
end
function atc.send_command(pos, par_tid)
@@ -49,7 +50,7 @@ function atc.send_command(pos, par_tid)
atwarn("ATC rail at", pos, ": Rail not on train's path! Can't determine arrow direction. Assuming +!")
end
- atc.train_set_command(train_id, atc.controllers[pts].command, iconnid==1)
+ atc.train_set_command(train, atc.controllers[pts].command, iconnid==1)
atprint("Sending ATC Command to", train_id, ":", atc.controllers[pts].command, "iconnid=",iconnid)
return true
@@ -66,12 +67,13 @@ function atc.send_command(pos, par_tid)
return false
end
-function atc.train_reset_command(train_id)
- advtrains.trains[train_id].atc_command=nil
- advtrains.trains[train_id].atc_delay=0
- advtrains.trains[train_id].atc_brake_target=nil
- advtrains.trains[train_id].atc_wait_finish=nil
- advtrains.trains[train_id].atc_arrow=nil
+function atc.train_reset_command(train)
+ train.atc_command=nil
+ train.atc_delay=nil
+ train.atc_brake_target=nil
+ train.atc_wait_finish=nil
+ train.atc_arrow=nil
+ train.tarvelocity=nil
end
--nodes
@@ -179,7 +181,7 @@ local matchptn={
train.tarvelocity = 0
elseif train.velocity>tonumber(match) then
train.atc_brake_target=tonumber(match)
- if train.tarvelocity>train.atc_brake_target then
+ if not train.tarvelocity or train.tarvelocity>train.atc_brake_target then
train.tarvelocity=train.atc_brake_target
end
end
@@ -258,7 +260,7 @@ function atc.execute_atc_command(id, train)
while nest>=0 do
if pos>#rest then
atwarn(sid(id), attrans("ATC command syntax error: I statement not closed: @1",command))
- atc.train_reset_command(id)
+ atc.train_reset_command(train)
return
end
local char=string.sub(rest, pos, pos)
@@ -301,7 +303,7 @@ function atc.execute_atc_command(id, train)
end
end
atwarn(sid(id), attrans("ATC command parse error: Unknown command: @1", command))
- atc.train_reset_command(id)
+ atc.train_reset_command(train)
end
diff --git a/advtrains/init.lua b/advtrains/init.lua
index 46a73d4..c1f280d 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -45,6 +45,7 @@ function advtrains.pcall(fun)
atwarn(debug.traceback())
if advtrains.atprint_context_tid then
advtrains.path_print(advtrains.trains[advtrains.atprint_context_tid], atdebug)
+ atwarn(advtrains.trains[advtrains.atprint_context_tid].debug)
end
end)
if not succ then
diff --git a/advtrains/path.lua b/advtrains/path.lua
index 19b4e78..5c3db94 100644
--- a/advtrains/path.lua
+++ b/advtrains/path.lua
@@ -260,7 +260,7 @@ function advtrains.path_get_index_by_offset(train, index, offset)
--atdebug("pibo: 2 off=",off,"idx=",idx)
-- then walk the path forward until we would overshoot
while off - train.path_dist[idx] >= 0 do
- idx = idx - 1
+ idx = idx + 1
advtrains.path_get_adjacent(train, idx)
if not train.path_dist[idx] then
for i=-5,5 do
diff --git a/advtrains/trainhud.lua b/advtrains/trainhud.lua
index 60ef5d1..f326427 100644
--- a/advtrains/trainhud.lua
+++ b/advtrains/trainhud.lua
@@ -44,19 +44,19 @@ function advtrains.on_control_change(pc, train, flip)
else
local act=false
if pc.up then
- train.lever=4
+ train.ctrl.user=4
act=true
end
if pc.jump then
- train.lever = 1
+ train.ctrl.user = 1
act=true
end
if pc.down then
if train.velocity>0 then
if pc.jump then
- train.lever = 0
+ train.ctrl.user = 0
else
- train.lever = 2
+ train.ctrl.user = 2
end
act=true
else
@@ -77,7 +77,9 @@ function advtrains.on_control_change(pc, train, flip)
train.door_open = 1
end
end
- train.active_control = act
+ if not act then
+ train.ctrl.user = nil
+ end
if pc.aux1 then
--horn
end
@@ -161,9 +163,7 @@ function advtrains.hud_train_format(train, flip)
local max=train.max_speed or 10
local vel=advtrains.abs_ceil(train.velocity)
- local tvel=advtrains.abs_ceil(train.tarvelocity)
local vel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.velocity))
- local tvel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.tarvelocity))
local levers = "B - o +"
local tlev=train.lever
@@ -174,11 +174,28 @@ function advtrains.hud_train_format(train, flip)
if tlev == 3 then levers = "B - >o< +" end
if tlev == 4 then levers = "B - o >+<" end
- local topLine, firstLine, secondLine
+ local topLine, firstLine
+
+ local secondLine
+ if train.tarvelocity then
+ local b=" "
+ local tvel=advtrains.abs_ceil(train.tarvelocity)
+ local tvel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.tarvelocity))
+ if train.atc_brake_target then
+ b="-B-"
+ end
+ secondLine="ATC"..b..": |"..string.rep("+", tvel)..string.rep("_", max-tvel).."> "..tvel_kmh.." km/h"
+ elseif train.atc_delay then
+ secondLine = "ATC waiting "..advtrains.abs_ceil(train.atc_delay).."s"
+ else
+ secondLine = "Manual operation"
+ end
+ if train.ctrl.lzb then
+ secondLine = "-!- Safety override -!-"
+ end
topLine=" ["..mletter[fct].."] {"..levers.."} "..doorstr[(train.door_open or 0) * fct]
firstLine=attrans("Speed:").." |"..string.rep("+", vel)..string.rep("_", max-vel).."> "..vel_kmh.." km/h"
- secondLine=attrans("Target:").." |"..string.rep("+", tvel)..string.rep("_", max-tvel).."> "..tvel_kmh.." km/h"
- return topLine.."\n"..firstLine.."\n"..secondLine
+ return (train.debug or "").."\n"..topLine.."\n"..firstLine.."\n"..secondLine
end
diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua
index 861c042..f26f7da 100644
--- a/advtrains/trainlogic.lua
+++ b/advtrains/trainlogic.lua
@@ -181,6 +181,13 @@ local function assertdef(tbl, var, def)
end
end
+function advtrains.get_acceleration(train, lever)
+ local acc_all = t_accel_all[lever]
+ local acc_eng = t_accel_eng[lever]
+ local nwagons = #train.trainparts
+ local acc = acc_all + (acc_eng*train.locomotives_in_train)/nwagons
+ return acc
+end
-- Small local util function to recalculate train's end index
local function recalc_end_index(train)
@@ -219,9 +226,10 @@ function advtrains.train_ensure_init(id, train)
if train.no_step then return end
assertdef(train, "velocity", 0)
- assertdef(train, "tarvelocity", 0)
+ --assertdef(train, "tarvelocity", 0)
assertdef(train, "acceleration", 0)
assertdef(train, "id", id)
+ assertdef(train, "ctrl", {})
if not train.drives_on or not train.max_speed then
@@ -275,11 +283,10 @@ function advtrains.train_step_b(id, train, dtime)
--- 3. handle velocity influences ---
local train_moves=(train.velocity~=0)
- local tarvel_cap
+ local tarvel_cap = train.speed_restriction
if train.recently_collided_with_env then
tarvel_cap=0
- train.active_control=false
if not train_moves then
train.recently_collided_with_env=nil--reset status when stopped
end
@@ -307,11 +314,24 @@ function advtrains.train_step_b(id, train, dtime)
tarvel_cap=1
end
+ -- Driving control rework:
+ --[[
+ Items are only defined when something is controlling them.
+ In order of precedence.
+ train.ctrl = {
+ lzb = restrictive override from LZB
+ user = User input from driverstand
+ atc = ATC command override (determined here)
+ }
+ The code here determines the precedence and writes the final control into train.lever
+ ]]
+
--interpret ATC command and apply auto-lever control when not actively controlled
local trainvelocity = train.velocity
- if not train.lever then train.lever=3 end
- if train.active_control then
- advtrains.atc.train_reset_command(id)
+
+
+ if train.ctrl.user then
+ advtrains.atc.train_reset_command(train)
else
local braketar = train.atc_brake_target
local emerg = false -- atc_brake_target==-1 means emergency brake (BB command)
@@ -323,8 +343,11 @@ function advtrains.train_step_b(id, train, dtime)
train.atc_brake_target=nil
braketar = nil
end
+ if train.tarvelocity and train.velocity==train.tarvelocity then
+ train.tarvelocity = nil
+ end
if train.atc_wait_finish then
- if not train.atc_brake_target and train.velocity==train.tarvelocity then
+ if not train.atc_brake_target and not train.tarvelocity then
train.atc_wait_finish=nil
end
end
@@ -334,42 +357,62 @@ function advtrains.train_step_b(id, train, dtime)
else
train.atc_delay=train.atc_delay-dtime
end
+ elseif train.atc_delay then
+ train.atc_delay = nil
end
- train.lever = 3
- if train.tarvelocity>trainvelocity then train.lever=4 end
- if train.tarvelocity<trainvelocity then
+ train.ctrl.atc = nil
+ if train.tarvelocity and train.tarvelocity>trainvelocity then
+ train.ctrl.atc=4
+ end
+ if train.tarvelocity and train.tarvelocity<trainvelocity then
if (braketar and braketar<trainvelocity) then
if emerg then
- train.lever = 0
+ train.ctrl.atc = 0
else
- train.lever=1
+ train.ctrl.atc=1
end
else
- train.lever=2
+ train.ctrl.atc=2
end
end
end
- if tarvel_cap and tarvel_cap<train.tarvelocity then
+ if tarvel_cap and train.tarvelocity and tarvel_cap<train.tarvelocity then
train.tarvelocity=tarvel_cap
end
- local tmp_lever = train.lever
+
+ local tmp_lever
+
+ for _, lev in pairs(train.ctrl) do
+ -- use the most restrictive of all control overrides
+ tmp_lever = math.min(tmp_lever or 4, lev)
+ end
+
+ if not tmp_lever then
+ -- if there was no control at all, default to 3
+ tmp_lever = 3
+ end
+
if tarvel_cap and trainvelocity>tarvel_cap then
tmp_lever = 0
end
+ train.lever = tmp_lever
+
--- 3a. actually calculate new velocity ---
if tmp_lever~=3 then
- local acc_all = t_accel_all[tmp_lever]
- local acc_eng = t_accel_eng[tmp_lever]
- local nwagons = #train.trainparts
- local accel = acc_all + (acc_eng*train.locomotives_in_train)/nwagons
+ local accel = advtrains.get_acceleration(train, tmp_lever)
local vdiff = accel*dtime
- if not train.active_control then
+
+ -- ATC control exception: don't cross tarvelocity if
+ -- atc provided a target_vel
+ if train.tarvelocity then
local tvdiff = train.tarvelocity - trainvelocity
- if math.abs(vdiff) > math.abs(tvdiff) then
+ if tvdiff~=0 and math.abs(vdiff) > math.abs(tvdiff) then
--applying this change would cross tarvelocity
+ --atdebug("In Tvdiff condition, clipping",vdiff,"to",tvdiff)
+ --atdebug("vel=",trainvelocity,"tvel=",train.tarvelocity)
vdiff=tvdiff
end
end
@@ -385,9 +428,9 @@ function advtrains.train_step_b(id, train, dtime)
end
train.acceleration=vdiff
train.velocity=train.velocity+vdiff
- if train.active_control then
- train.tarvelocity = train.velocity
- end
+ --if train.ctrl.user then
+ -- train.tarvelocity = train.velocity
+ --end
else
train.acceleration = 0
end
@@ -443,7 +486,7 @@ if train.no_step or train.wait_for_path then return end
if not collided and advtrains.occ.check_collision(testpos, id) then
--collides
train.velocity = 0
- train.tarvelocity = 0
+ advtrains.atc.train_reset_command(train)
collided = true
end
--- 8b damage players ---
@@ -622,7 +665,7 @@ function advtrains.create_new_train_at(pos, connid, ioff, trainparts)
t.last_connid=connid
t.last_frac=ioff
- t.tarvelocity=0
+ --t.tarvelocity=0
t.velocity=0
t.trainparts=trainparts
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index 030a5e0..af90880 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -485,7 +485,7 @@ function ildb.get_ip_signal_asp(pts, connid)
ildb.clear_ip_signal(pts, connid)
return nil
end
- return asp
+ return asp, p
end
return nil
end
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index 19501b6..d6625eb 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -8,9 +8,12 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELI
dofile(modpath.."database.lua")
dofile(modpath.."signal_api.lua")
dofile(modpath.."demosignals.lua")
-dofile(modpath.."train_related.lua")
+dofile(modpath.."train_sections.lua")
dofile(modpath.."route_prog.lua")
dofile(modpath.."routesetting.lua")
dofile(modpath.."tcb_ts_ui.lua")
+dofile(modpath.."lzb.lua")
+
+
minetest.register_privilege("interlocking", {description = "Can set up track sections, routes and signals.", give_to_singleplayer = true})
diff --git a/advtrains_interlocking/lzb.lua b/advtrains_interlocking/lzb.lua
new file mode 100644
index 0000000..c9e40ab
--- /dev/null
+++ b/advtrains_interlocking/lzb.lua
@@ -0,0 +1,194 @@
+-- lzb.lua
+-- Enforced and/or automatic train override control, obeying signals
+
+--[[
+Documentation of train.lzb table
+train.lzb = {
+ trav = Current index that the traverser has advanced so far
+ travsht = boolean indicating whether the train will be a shunt move at "trav"
+ travspd = speed restriction at end of traverser
+ travwspd = warning speed res.
+ oncoming = table containing oncoming signals, in order of appearance on the path
+ {
+ pos = position of the signal (not the IP!)
+ idx = where this is on the path
+ spd = speed allowed to pass (determined dynamically)
+ }
+}
+each step, for every item in "oncoming", we need to determine the location to start braking (+ some safety margin)
+and, if we passed this point for at least one of the items, initiate brake.
+When speed has dropped below, say 3, decrease the margin to zero, so that trains actually stop at the signal IP.
+The spd variable and travsht need to be updated on every aspect change. it's probably best to reset everything when any aspect changes
+
+The traverser stops at signals that result in spd==0, because changes beyond there are likely.
+]]
+
+local il = advtrains.interlocking
+
+local BRAKE_SPACE = 10
+local AWARE_ZONE = 50
+
+local ADD_STAND = 2
+local ADD_SLOW = 1
+local ADD_FAST = 10
+
+local SHUNT_SPEED_MAX = 4
+
+local function look_ahead(id, train)
+
+ local acc = advtrains.get_acceleration(train, 1)
+ local vel = train.velocity
+ local brakedst = -(vel*vel) / (2*acc)
+
+ local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + BRAKE_SPACE)
+ --local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE)
+
+ local lzb = train.lzb
+ local trav = lzb.trav
+ local travspd = lzb.travspd
+ local travwspd = lzb.travwspd
+ local lspd
+
+ train.debug = lspd
+
+ while trav <= brake_i and (not lspd or lspd>0) do
+ trav = trav + 1
+ local pos = advtrains.path_get(train, trav)
+ local pts = advtrains.roundfloorpts(pos)
+ local cn = train.path_cn[trav]
+ -- check offtrack
+ if trav > train.path_trk_f then
+ lspd = 0
+ table.insert(lzb.oncoming, {
+ idx = trav-1,
+ spd = 0,
+ })
+ else
+ -- check for signal
+ local asp, spos = il.db.get_ip_signal_asp(pts, cn)
+ --atdebug("trav: ",pos, cn, asp, spos, "travsht=", lzb.travsht)
+ if asp then
+ local nspd = 0
+ --interpreting aspect and determining speed to proceed
+ if lzb.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
+ lzb.travsht = false
+ end
+ else
+ --train move
+ if asp.main.free then
+ nspd = asp.main.speed
+ elseif asp.shunt.free then
+ nspd = SHUNT_SPEED_MAX
+ lzb.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
+
+ table.insert(lzb.oncoming, {
+ pos = spos,
+ idx = trav,
+ spd = lspd,
+ })
+ -- TODO register aspect change callback!
+ end
+ end
+ end
+
+ lzb.trav = trav
+ lzb.travspd = travspd
+ lzb.travwspd = travwspd
+
+end
+
+--[[
+Distance needed to accelerate from v0 to v1 with constant acceleration a:
+
+ v1 - v0 a / v1 - v0 \ 2
+s = v0 * ------- + - * | ------- |
+ a 2 \ a /
+]]
+
+local function apply_control(id, train)
+ local lzb = train.lzb
+
+ local i = 1
+ while i<#lzb.oncoming do
+ if lzb.oncoming[i].idx < train.index then
+ train.speed_restriction = lzb.oncoming[i].spd
+ table.remove(lzb.oncoming, i)
+ else
+ i = i + 1
+ end
+ end
+
+ for i, it in ipairs(lzb.oncoming) do
+ local a = advtrains.get_acceleration(train, 1) --should be negative
+ local v0 = train.velocity
+ local v1 = it.spd
+ if v1 and v1 <= v0 then
+ local f = (v1-v0) / a
+ local s = v0*f + a*f*f/2
+
+ local st = s + ADD_SLOW
+ if v0 > 3 then
+ st = s + ADD_FAST
+ end
+ if v0<=0 then
+ st = s + ADD_STAND
+ end
+
+ local i = advtrains.path_get_index_by_offset(train, it.idx, -st)
+
+ --train.debug = dump({v0f=v0*f, aff=a*f*f,v0=v0, v1=v1, f=f, a=a, s=s, st=st, i=i, idx=train.index})
+ if i <= train.index then
+ -- Gotcha! Braking...
+ train.ctrl.lzb = 1
+ --train.debug = train.debug .. "BRAKE!!!"
+ return
+ end
+ end
+ end
+ train.ctrl.lzb = nil
+end
+
+
+advtrains.te_register_on_new_path(function(id, train)
+ train.lzb = {
+ trav = atfloor(train.index),
+ travsht = train.is_shunt,
+ oncoming = {}
+ }
+ train.ctrl.lzb = nil
+ look_ahead(id, train)
+end)
+
+advtrains.te_register_on_update(function(id, train)
+ look_ahead(id, train)
+ apply_control(id, train)
+end)
diff --git a/advtrains_interlocking/train_related.lua b/advtrains_interlocking/train_sections.lua
index 8bc9716..8bc9716 100644
--- a/advtrains_interlocking/train_related.lua
+++ b/advtrains_interlocking/train_sections.lua
diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua
index d001d88..1fab620 100644
--- a/advtrains_luaautomation/atc_rail.lua
+++ b/advtrains_luaautomation/atc_rail.lua
@@ -50,9 +50,7 @@ function r.fire_event(pos, evtdata)
atc_send = function(cmd)
if not train_id then return false end
assertt(cmd, "string")
- advtrains.atc.train_reset_command(train_id)
- train.atc_command=cmd
- train.atc_arrow=atc_arrow
+ advtrains.atc.train_set_command(train, cmd, atc_arrow)
return true
end,
set_line = function(line)
@@ -62,7 +60,7 @@ function r.fire_event(pos, evtdata)
atc_reset = function(cmd)
if not train_id then return false end
assertt(cmd, "string")
- advtrains.atc.train_reset_command(train_id)
+ advtrains.atc.train_reset_command(train)
return true
end,
atc_arrow = atc_arrow,