1
0
mirror of https://github.com/metrostroi-repo/MetrostroiAddon.git synced 2026-05-02 00:42:29 +00:00
Files
MetrostroiAddon/lua/metrostroi/sv_centralisation.lua
g_brzhezinskiy 1d05caf866 init
2021-01-02 12:51:45 +03:00

315 lines
14 KiB
Lua

local function GetOccupation(tbl)
if not tbl then return end
for sID,signame in ipairs(tbl) do
if signame[1] == "@" then
local trigger = Metrostroi.ARMGet(signame:sub(2,-1), "trigger")
--if not trigger then print(signame) end
if not trigger or trigger.ARMTriggered then
return true
end
elseif signame ~= "" then
local signal = Metrostroi.ARMGet(signame, "signal")
if not signal or signal.OccupiedBy and signal.OccupiedBy ~= signal then
return true
end
end
end
return false
end
function Metrostroi.CentralisationPrepareRoute(station,route)
if not Metrostroi.ARMTable[station].routes then Metrostroi.ARMTable[station].routes = {} end
local Routes = Metrostroi.ARMTable[station].routes
local stationT = Metrostroi.ARMConfigGenerated[station]
if not Routes[route] then
local segments = route.route
for i,segm in pairs(segments) do
if segm.inroute then
RunConsoleCommand("say",Format("Station %d. Error building route %s, because there is already another route",station,route))
return false
end
if route.ignores and (not route.ignores or not route.ignores[i]) and segm.occupied then
RunConsoleCommand("say",Format("Station %d. Error building route %s. Route occupied!",station,route))
return false
end
end
if route.checks then
for i,segm in pairs(route.checks) do
if segm.inroute then
RunConsoleCommand("say",Format("Station %d. Error building route %s, because there is already another route on protective segments",station,route))
return false
end
if route.ignores and (not route.ignores or not route.ignores[i]) and segm.occupied then
RunConsoleCommand("say",Format("Station %d. Error building route %s. Protective segments occupied!",station,route))
return false
end
end
end
for _,segm in pairs(segments) do
segm.inroute = true
end
Routes[route] = table.insert(Routes,route)
RunConsoleCommand("say",Format("Station %d. Added route %s with ID:%d",station,route,Routes[route]))
return true
end
end
local function CentralistationCalculateFreeBS(segm,dir,sigconf,pSeg,rccount)
if pSeg then
local signal = dir and segm.signal2 or not dir and segm.signal1
if signal then
local ent = signal.ent
if not ent then return 1 end
local conf = sigconf[ent.Name]
--return (ent.FreeBSARM or ent.FreeBS or 0)+(conf and conf.bs or 1),ent
return (ent.FreeBSARM or ent.FreeBS or 0)+rccount,ent
end
end
rccount = (rccount or 0) + 1
if not segm or segm.occupied then
return rccount
end
local alt,main = false,true
if segm.switch then
local switch = Metrostroi.ARMGet(segm.switch, "switch")
main = switch and switch.MainTrack and not switch.AlternateTrack
alt = switch and not switch.MainTrack and switch.AlternateTrack
if not alt and not main then return 0 end
end
if pSeg and segm.next_a and (segm.next_a == pSeg and not alt or segm.next_m == pSeg and not main) then return 0 end
local segmM,segmA = segm.next_m,segm.next_a
local segmP = segm.prev
local mainM = segmM and (dir and segmM.x > segm.x or not dir and segmM.x < segm.x)
local mainP = segmP and (dir and segmP.x > segm.x or not dir and segmP.x < segm.x)
if mainM then
local next
if alt and segmA then next = segmA end
if main and segmM then next = segmM end
return CentralistationCalculateFreeBS(next,dir,sigconf,segm,rccount)
end
if segmP and mainP then
return CentralistationCalculateFreeBS(segmP,dir,sigconf,segm,rccount)
end
end
local function CentralisationSolveSignalLogic(signal,signalE,signalDir,station,segm)
if not signalE then return end
if station.signals and station.signals[signal] then
local sigconf = station.signals[signal]
signalE.ControllerLogic = station
local target,codes = "",""
local alt = false
local occupied = segm.occupied
if segm.switch then
local switch = Metrostroi.ARMGet(segm.switch, "switch")
local main = switch and switch.MainTrack and not switch.AlternateTrack
alt = switch and not switch.MainTrack and switch.AlternateTrack
if not alt and not main then occupied = true end
end
if alt then
--occupied = occupied or segm.next_a and GetOccupation(segm.next_a)
else
--occupied = occupied or segm.next_m and GetOccupation(segm.next_m)
end
local route = sigconf.route
local free,nextSignal = CentralistationCalculateFreeBS(segm,signalDir,station.signals)
--print(free,signalE,signalE.Name)
local dir = route and route.dir
if route and dir ~= signalDir then
print(signalE.Name,dir ,signalDir)
route = nil
occupied = true
end
if sigconf.Mode == 1 then
if occupied then
target = sigconf.R
codes = "2"
elseif route then
if nextSignal then
local colors = nextSignal.Colors or ""
local segments = route[2]
--print(route)
local start = false
local specialS = sigconf.routes and sigconf.routes[route[1].name]
if free < (sigconf.bs or 1) then
target = sigconf.RY or sigconf.R
elseif route.mode == 3 then
target = sigconf.W
elseif colors:find("[rR]+") and colors:find("[yY]+") then
target = sigconf.Y or sigconf.YG or sigconf.RY or sigconf.R
elseif colors:find("[rR]+") then
target = sigconf.Y or sigconf.RY or sigconf.R
elseif colors:find("[ygYG]+[ygYG]+") or colors:find("[gwGW]+") then
target = sigconf.G or sigconf.YG or sigconf.Y or sigconf.RY or sigconf.R
elseif colors:find("[yY]+") then
target = sigconf.YG or sigconf.G or sigconf.Y or sigconf.RY or sigconf.R
else
target = sigconf.R
end
elseif route.mode == 3 then
target = sigconf.W
else
target = sigconf.R
end
else
if free and free < 1 then
target = sigconf.R or sigconf.RY or ""
else
target = sigconf.RY or sigconf.R
end
codes = "0"
end
signalE.Red = target==sigconf.R or target==sigconf.RY
signalE.AutoEnabled = signalE.AutoEnabled
else
end
local sig = ""
for i=1,#target do
local id = tonumber(target[i])
if not id then continue end
if #sig < id then sig = sig..string.rep("0",id-#sig) end
sig = string.SetChar(sig,tonumber(target[i]),target[i+1]=="b" and "2" or "1")
end
signalE.Sig = sig
signalE.FreeBSARM = occupied and 0 or free
signalE.FreeBS = math.ceil(signalE.FreeBSARM or 0)
--print(occupied,free,signalE.FreeBS)
--print(signalE.Colors,target,signalE.Sig)
end
end
local function CentralisationSolveRoutesLogic(stationID,station)
local Routes = Metrostroi.ARMTable[stationID].routes
local HasPrepared = true
for k,route in ipairs(Routes) do
local segments = route.route
local directions = route.directions
if route.prepared then
--HasPrepared = true
local done,occupiedN,halfroute = true--,100
for segmID,segm in ipairs(segments) do
if segm.occupied then
if not occupiedN or occupiedN < segmID then occupiedN = segmID end
end
if segm.route then done = false end
if not segm.route then halfroute = true end
end
if occupiedN then
for segmID,segm in ipairs(segments) do
if segmID > occupiedN then break end
if segm.route == route then
segm.route = false
segm.inroute = false
local signal = route[3] and segm.signal2 or not route[3] and segm.signal1
local sig = Metrostroi.ARMGet(signal and signal.name, "signal")
end
end
end
if done or halfroute and not occupiedN then
for _,segm in ipairs(segments) do
segm.inroute = false
segm.route = false
end
for i,signame in pairs(route.signals) do
if not station.signals[signame] then continue end
station.signals[signame].route = nil
end
RunConsoleCommand("say",Format("Station %d. Route %s(%d) has destroyed",stationID,route,Routes[route]))
table.remove(Routes,Routes[route])
Routes[route] = nil
for i,v in pairs(Routes) do Routes[v] = i end
route.prepared = false
end
else
local Prepared = true
--Check for occupation
for i,segm in ipairs(segments) do
if route.ignores and not route.ignores[i] and segm.occupied then Prepared = false break end
if segm.route then Prepared = false break end
end
--If there is no occupation - check and prepare switches
if Prepared then
for segmID,segm in ipairs(segments) do
if not segm.switch then continue end
local switch = Metrostroi.ARMGet(segm.switch, "switch")
if not switch then continue end
local dir = directions[segmID]
local main = switch and switch.MainTrack and not switch.AlternateTrack
local alt = switch and not switch.MainTrack and switch.AlternateTrack
--print(route[3],switch,dir)
if dir and main or not dir and alt or (not main and not alt) then
switch:SwitchTo(dir and "alt" or "main")
Prepared = false
print("Move",segmID,segm.switch,switch,dir and "alt" or "main")
end
if not main and not alt then Prepared = false end
end
end
if Prepared then
for k,segm in ipairs(segments) do
segm.route = route
local signal = route[3] and segm.signal2 or not route[3] and segm.signal1
local sig = Metrostroi.ARMGet(signal and signal.name, "signal")
end
for i,signame in pairs(route.signals) do
if not station.signals[signame] then continue end
station.signals[signame].route = route
end
route.prepared = true
RunConsoleCommand("say",Format("Station %d. Route %s(%d) has assembled",stationID,route,Routes[route]))
end
end
end
return HasPrepared
end
function Metrostroi.Centralisation()
if not Metrostroi.ARMConfigGenerated then return end
for stationID,station in pairs(Metrostroi.ARMConfigGenerated) do
--Route logic
local HasPrepared = CentralisationSolveRoutesLogic(stationID,station)
for name, signal in pairs(station.signals) do
if signal.sig then
local ent = Metrostroi.ARMGet(name, "signal")
signal.sig.ent = ent
CentralisationSolveSignalLogic(name,ent,signal.sig.dir,station,signal.segm)
end
end
for segmID, segm in ipairs(station) do
segm.occupied = segm._occup or GetOccupation(segm.occup) or GetOccupation(segm.occupAlt)
if true then
if segm.switch then
local switch = Metrostroi.ARMGet(segm.switch, "switch")
local main = switch and switch.MainTrack and not switch.AlternateTrack
local alt = switch and not switch.MainTrack and switch.AlternateTrack
if switch and not segm.route and not segm.inroute and not segm.occupied and (alt or not main and not alt) then
switch:SwitchTo("main")
print("Reset",segm.switch,switch,segmID,segm.route)
end
end
--[[ if segm.signal1 then
local ent = Metrostroi.ARMGet(segm.signal1.name, "signal")
segm.signal1.ent = ent
CentralisationSolveSignalLogic(segm.signal1.name,ent,false,station,segm)
end
if segm.signal2 then
local ent = Metrostroi.ARMGet(segm.signal2.name, "signal")
segm.signal2.ent = ent
CentralisationSolveSignalLogic(segm.signal2.name,ent,true,station,segm)
end--]]
--[[ if segm.route and not HasPrepared then
segm.route = false
segm.inroute = false
end--]]
end
end
end
end
timer.Create("metrostroi_centralisation",0.1,0,Metrostroi.Centralisation)