aboutsummaryrefslogtreecommitdiff
path: root/advtrains_signals_ks
diff options
context:
space:
mode:
authorywang <yw05@forksworld.de>2021-05-30 12:16:09 +0200
committerywang <yw05@forksworld.de>2021-11-05 20:28:38 +0100
commit22994705235dfcdfbdc9966a9ba037d657188b5a (patch)
tree72006d8f6e2569de30b97526ab129d1ce85588dc /advtrains_signals_ks
parent8793c8bd48eb37f7807f9f1df942ed7226b934e8 (diff)
downloadadvtrains-22994705235dfcdfbdc9966a9ba037d657188b5a.tar.gz
advtrains-22994705235dfcdfbdc9966a9ba037d657188b5a.tar.bz2
advtrains-22994705235dfcdfbdc9966a9ba037d657188b5a.zip
round speed limit if needed
Diffstat (limited to 'advtrains_signals_ks')
-rwxr-xr-xadvtrains_signals_ks/init.lua15
1 files changed, 8 insertions, 7 deletions
diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua
index a1f056c..3a2f4d0 100755
--- a/advtrains_signals_ks/init.lua
+++ b/advtrains_signals_ks/init.lua
@@ -4,15 +4,17 @@
-- 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 supported_speed_limits = {
- [4] = true, [6] = true, [8] = true, [12] = true, [16] = true
-}
+local function asp_to_zs3type(asp)
+ local n = tonumber(asp)
+ if not n or n < 4 then return "off" end
+ if n < 8 then return 2*math.floor(n/2) end
+ return math.min(16,4*math.floor(n/4))
+end
local function setzs3(msp, lim, rot)
local pos = {x = msp.x, y = msp.y+1, z = msp.z}
local node = advtrains.ndb.get_node(pos)
- local asp = lim
- if not asp or not supported_speed_limits[lim] then asp = "off" end
+ local asp = asp_to_zs3type(lim)
if node.name:find("^advtrains_signals_ks:zs3_") then
advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:zs3_"..asp.."_"..rot, param2 = node.param2})
end
@@ -31,8 +33,7 @@ end
local function setzs3v(msp, lim, rot)
local pos = {x = msp.x, y = msp.y-1, z = msp.z}
local node = advtrains.ndb.get_node(pos)
- local asp = lim
- if not asp or not supported_speed_limits[lim] then asp = "off" end
+ local asp = asp_to_zs3type(lim)
if node.name:find("^advtrains_signals_ks:zs3v_") then
advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:zs3v_"..asp.."_"..rot, param2 = node.param2})
end
>194 195 196 197 198 199 200 201 202 203 204 205 206
-- 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
			if tcbs.signal then
				local spos = tcbs.signal
				local _, setter = advtrains.distant.get_main(spos)
				if setter == "routesetting" then
					advtrains.distant.unassign_dst(spos, true)
				end
			end
			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)